Class: OroGen::Loaders::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/orogen/loaders/base.rb

Overview

Definition of the base loader API

Direct Known Subclasses

Aggregate, Files, PkgConfig, ROS::Loader

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(root_loader = self) ⇒ Base

Returns a new instance of Base



50
51
52
53
54
55
56
57
58
# File 'lib/orogen/loaders/base.rb', line 50

def initialize(root_loader = self)
    @root_loader = root_loader || self
    if root_loader != self
        root_loader.added_child(self)
    end
    @typekit_load_callbacks = Array.new
    @project_load_callbacks = Array.new
    clear
end

Instance Attribute Details

#interface_typelistObject (readonly)

The list of types that can be used on an oroGen interface



20
21
22
# File 'lib/orogen/loaders/base.rb', line 20

def interface_typelist
  @interface_typelist
end

#loaded_deployment_modelsObject (readonly)

Set of deployment models that are known to us



14
15
16
# File 'lib/orogen/loaders/base.rb', line 14

def loaded_deployment_models
  @loaded_deployment_models
end

#loaded_projectsHash<String,Spec::Project> (readonly)

Set of projects loaded so far

Returns:



8
9
10
# File 'lib/orogen/loaders/base.rb', line 8

def loaded_projects
  @loaded_projects
end

#loaded_task_modelsObject (readonly)

Set of task models that are known to us



11
12
13
# File 'lib/orogen/loaders/base.rb', line 11

def loaded_task_models
  @loaded_task_models
end

#loaded_typekitsHash<String,Spec::Typekit> (readonly)

Set of typekits loaded so far

Returns:



28
29
30
# File 'lib/orogen/loaders/base.rb', line 28

def loaded_typekits
  @loaded_typekits
end

#project_load_callbacksArray<#call> (readonly)

Set of callbacks that are called whenever a new typekit gets loaded

Returns:

  • (Array<#call>)


48
49
50
# File 'lib/orogen/loaders/base.rb', line 48

def project_load_callbacks
  @project_load_callbacks
end

#registryObject (readonly)

The registry that includes types from all loaded typekits



17
18
19
# File 'lib/orogen/loaders/base.rb', line 17

def registry
  @registry
end

#root_loaderObject (readonly)

The loader that should be used to resolve dependencies



31
32
33
# File 'lib/orogen/loaders/base.rb', line 31

def root_loader
  @root_loader
end

#typekit_load_callbacksArray<#call> (readonly)

Set of callbacks that are called whenever a new typekit gets loaded

Returns:

  • (Array<#call>)


42
43
44
# File 'lib/orogen/loaders/base.rb', line 42

def typekit_load_callbacks
  @typekit_load_callbacks
end

#typekits_by_type_nameObject (readonly)

A mapping from type names to the typekits that define them



23
24
25
# File 'lib/orogen/loaders/base.rb', line 23

def typekits_by_type_name
  @typekits_by_type_name
end

Instance Method Details

#added_child(loader) ⇒ Object



70
71
# File 'lib/orogen/loaders/base.rb', line 70

def added_child(loader)
end

#clearObject



60
61
62
63
64
65
66
67
68
# File 'lib/orogen/loaders/base.rb', line 60

def clear
    @loaded_projects = Hash.new
    @loaded_typekits = Hash.new
    @loaded_task_models = Hash.new
    @loaded_deployment_models = Hash.new
    @typekits_by_type_name = Hash.new
    @registry = Typelib::Registry.new
    @interface_typelist = Set.new
end

#define_dummy_types=(value) ⇒ Boolean

Sets the behaviour of the type resolution on unknown types

Returns:

  • (Boolean)


36
# File 'lib/orogen/loaders/base.rb', line 36

attr_predicate :define_dummy_types?, true

#define_dummy_types?Boolean

Sets the behaviour of the type resolution on unknown types

Returns:

  • (Boolean)


36
# File 'lib/orogen/loaders/base.rb', line 36

attr_predicate :define_dummy_types?, true

#deployed_task_model_from_name(name, deployment_name = nil) ⇒ OroGen::Spec::TaskDeployment

Returns the deployed task model for the given name

Parameters:

  • name (String)

    the deployed task name

  • deployment_name (String) (defaults to: nil)

    () the name of the deployment in which the task is defined. It must be given only when more than one deployment defines a task with the requested name

Returns:

Raises:

  • (DeployedTaskModelNotFound)

    if no deployed tasks with that name exists

  • (DeployedTaskModelNotFound)

    if deployment_name was given, but the requested task is not defined in this deployment

  • (OroGen::AmbiguousName)

    if more than one task exists with that name. In that case, you will have to provide the deployment name explicitly using the second argument



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/orogen/loaders/base.rb', line 207

def deployed_task_model_from_name(name, deployment_name = nil)
    if deployment_name
        deployment = deployment_model_from_name(deployment_name)
    else
        deployment_names = find_deployments_from_deployed_task_name(name)
        if deployment_names.empty?
            raise DeployedTaskModelNotFound, "cannot find a deployed task called #{name}"
        elsif deployment_names.size > 1
            raise AmbiguousName, "more than one deployment defines a deployed task called #{name}: #{deployment_names.map(&:name).sort.join(", ")}"
        end
        deployment = deployment_model_from_name(deployment_names.first)
    end

    if !(task = deployment.find_task_by_name(name))
        if deployment_name
            raise DeployedTaskModelNotFound, "deployment #{deployment_name} does not have a task called #{name}"
        else
            raise InternalError, "deployment #{deployment_name} was supposed to have a task called #{name} but does not"
        end
    end
    task
end

#deployment_model_from_name(name) ⇒ OroGen::Spec::Deployment

Returns the deployment model for the given deployment name

Parameters:

  • name (String)

    the deployment name

Returns:

Raises:



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/orogen/loaders/base.rb', line 176

def deployment_model_from_name(name)
    if model = loaded_deployment_models[name]
        return model
    end

    project_name = find_project_from_deployment_name(name)
    if !project_name
        raise DeploymentModelNotFound, "there is no deployment called #{name} on #{self}"
    end

    project = project_model_from_name(project_name)
    deployment = project.deployers[name]
    if !deployment
        raise InternalError, "cannot find the deployment called #{name} in #{project.name}. Candidates were #{project.deployers.map(&:name).sort.join(", ")}"
    end
    deployment
end

#each_available_project_name {|project_name| ... } ⇒ Object

Enumerates the names of all available projects

Yield Parameters:

  • project_name (String)


545
546
547
548
# File 'lib/orogen/loaders/base.rb', line 545

def each_available_project_name
    return enum_for(__method__) if !block_given?
    nil
end

#find_deployments_from_deployed_task_name(name) ⇒ Set<String>

Returns the set of deployments that contain a certain task

Parameters:

  • name (String)

Returns:

  • (Set<String>)


539
540
# File 'lib/orogen/loaders/base.rb', line 539

def find_deployments_from_deployed_task_name(name)
end

#find_project_from_deployment_name(name) ⇒ String?

Returns the project that defines the given deployment

Parameters:

  • deployment_name (String)

    the deployment we are looking for

Returns:

  • (String, nil)


532
533
# File 'lib/orogen/loaders/base.rb', line 532

def find_project_from_deployment_name(name)
end

#find_task_library_from_task_model_name(name) ⇒ String?

Returns the task library name in which a task model is defined

Parameters:

  • model_name (String)

    the name of the task model to look for

Returns:

  • (String, nil)

Raises:

  • (NotImplementedError)


524
525
526
# File 'lib/orogen/loaders/base.rb', line 524

def find_task_library_from_task_model_name(name)
    raise NotImplementedError, "#{self.class} does not implement #find_task_library_from_task_model_name"
end

#has_loaded_project?(name) ⇒ Boolean

Returns:

  • (Boolean)


455
456
457
# File 'lib/orogen/loaders/base.rb', line 455

def has_loaded_project?(name)
    loaded_projects.has_key?(name)
end

#has_loaded_typekit?(name) ⇒ Boolean

Tests if a typekit with that name has been loaded

Parameters:

  • name (String)

    the typekit name

Returns:

  • (Boolean)


508
509
510
# File 'lib/orogen/loaders/base.rb', line 508

def has_loaded_typekit?(name)
    loaded_typekits.has_key?(name)
end

#has_project?(name) ⇒ Boolean

Tests if a project with that name exists

Parameters:

  • name (String)

    the project name

Returns:

  • (Boolean)


500
501
502
# File 'lib/orogen/loaders/base.rb', line 500

def has_project?(name)
    loaded_projects.has_key?(name)
end

#has_typekit?(name) ⇒ Boolean

Tests if a typekit with that name exists

Parameters:

  • name (String)

    the typekit name

Returns:

  • (Boolean)


516
517
518
# File 'lib/orogen/loaders/base.rb', line 516

def has_typekit?(name)
    loaded_typekits.has_key?(name)
end

#imported_typekits_for(typename, definition_typekits: true) ⇒ Set<Spec::Typekit>

Returns the typekit object that defines this type

Parameters:

  • options (Hash)

    a customizable set of options

Returns:

Raises:



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/orogen/loaders/base.rb', line 350

def imported_typekits_for(typename, definition_typekits: true)
    if typename.respond_to?(:name)
        typename = typename.name
    end
    if typekits = typekits_by_type_name[typename]
        if definition_typekits
            definition_typekits = typekits.find_all { |tk| tk.include?(typename) }
            if definition_typekits.empty?
                raise DefinitionTypekitNotFound, "typekits #{typekits.map(&:name).sort.join(", ")} have #{typename} in their registries, but it seems that they got it from another typekit and I cannot find it. definition_typekits is true, I raise"
            end
            return definition_typekits.to_set
        else
            return typekits
        end
    end
    raise DefinitionTypekitNotFound, "#{typename} is not defined by any typekits loaded so far"
end

#inspectObject



571
572
573
# File 'lib/orogen/loaders/base.rb', line 571

def inspect
    to_s
end

#interface_type?(typename) ⇒ Boolean

Tests whether the given type can be used on an interface

Parameters:

  • typename (#name, String)

    the type

Returns:

  • (Boolean)


386
387
388
389
# File 'lib/orogen/loaders/base.rb', line 386

def interface_type?(typename)
    typename = typename.name if typename.respond_to?(:name)
    interface_typelist.include?(typename)
end

#intermediate_type?(type) ⇒ Boolean

Tests whether the given type can be used on an interface

Returns:

  • (Boolean)
  • (Boolean)


395
396
397
398
# File 'lib/orogen/loaders/base.rb', line 395

def intermediate_type?(type)
    type = resolve_type(type)
    !type..get('orogen:intermediate_type_of').empty?
end

#intermediate_type_for(type) ⇒ Model<Typelib::Type>

Returns the intermediate type that is paired with the given type

Parameters:

  • type (#name, String)

    the type or type name

Returns:

  • (Model<Typelib::Type>)

    the type of the opaque, or the given type if it is not an intermediate type



416
417
418
419
420
# File 'lib/orogen/loaders/base.rb', line 416

def intermediate_type_for(type)
    type = resolve_type(type)
    intermediates = type..get('orogen:intermediate_type')
    registry.get(intermediates.first || type.name)
end

#m_type?(type) ⇒ Boolean

Returns whether this type is a m-type (intermediate type generated by oroGen)

Returns:

  • (Boolean)
  • (Boolean)


428
429
430
431
# File 'lib/orogen/loaders/base.rb', line 428

def m_type?(type)
    type = resolve_type(type)
    type..get('orogen:generated_type') == ['true']
end

#on_project_load(initial_events = true, &block) ⇒ Object

Registers a callback that should be called with newly registered projects

Parameters:

  • initial_events (Boolean) (defaults to: true)

    if true, the callbacks will be called instantly with the projects that have already been loaded



113
114
115
116
117
118
119
120
121
122
# File 'lib/orogen/loaders/base.rb', line 113

def on_project_load(initial_events = true, &block)
    project_load_callbacks << block
    if initial_events
        current_set = loaded_projects.values.dup
        current_set.each do |p|
            block.call(p)
        end
    end
    block
end

#on_typekit_load(initial_events = true, &block) ⇒ Object

Registers a callback that should be called with newly registered typekits

Parameters:

  • initial_events (Boolean) (defaults to: true)

    if true, the callbacks will be called instantly with the typekits that have already been loaded



309
310
311
312
313
314
315
316
317
# File 'lib/orogen/loaders/base.rb', line 309

def on_typekit_load(initial_events = true, &block)
    typekit_load_callbacks << block
    if initial_events
        current_set = loaded_typekits.values.dup
        current_set.each do |tk|
            block.call(tk)
        end
    end
end

#opaque_type_for(type) ⇒ Model<Typelib::Type>

Returns the opaque type that is paired with the given type

Parameters:

  • type (#name, String)

    the type or type name

Returns:

  • (Model<Typelib::Type>)

    the type of the opaque, or the given type if it is not an intermediate type



405
406
407
408
409
# File 'lib/orogen/loaders/base.rb', line 405

def opaque_type_for(type)
    type = resolve_type(type)
    opaques = type..get('orogen:intermediate_type_of')
    registry.get(opaques.first || type.name)
end

#project_model_from_name(name) ⇒ OroGen::Spec::Project

Returns the project model corresponding to the given name

Parameters:

  • the (String)

    project name

Returns:

Raises:



79
80
81
82
83
84
85
86
87
88
89
# File 'lib/orogen/loaders/base.rb', line 79

def project_model_from_name(name)
    if project = loaded_projects[name]
        return project
    end

    name = name.to_str

    text, path = project_model_text_from_name(name)
    OroGen.info "loading oroGen project #{name}"
    project_model_from_text(text, name: name, path: path)
end

#project_model_from_text(text, name: nil, path: nil) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/orogen/loaders/base.rb', line 91

def project_model_from_text(text, name: nil, path: nil)
    project = Spec::Project.new(root_loader)
    project.typekit =
        if has_typekit?(name)
            typekit_model_from_name(name)
        else
            Spec::Typekit.new(root_loader, name)
        end

    Loaders::Project.new(project).__eval__(path, text)
    if name && (project.name != name)
        raise ArgumentError, "got project #{project.name} while loading #{name}"
    end
    register_project_model(project)
    project
end

#project_model_text_from_name(name) ⇒ (String,String)

Returns the textual representation of a project model

Parameters:

  • the (String)

    project name

Returns:

  • ((String,String))

    the model as text, as well as a path to the model file (or nil if there is no such file)

Raises:



482
483
484
# File 'lib/orogen/loaders/base.rb', line 482

def project_model_text_from_name(name)
    raise NotImplementedError
end

#register_deployment_model(model) ⇒ void

This method returns an undefined value.

Registers a new deployment model

Parameters:



471
472
473
# File 'lib/orogen/loaders/base.rb', line 471

def register_deployment_model(model)
    loaded_deployment_models[model.name] = model
end

#register_project_model(project) ⇒ Object

Registers this project's subobjects



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
# File 'lib/orogen/loaders/base.rb', line 434

def register_project_model(project)
    if loaded_projects.has_key?(project.name)
        raise AlreadyRegistered, "there is already a project called #{project.name} registered on #{self}"
    end

    loaded_projects[project.name] = project
    if root_loader != self
        return root_loader.register_project_model(project)
    end

    project.tasks.each do |_, task_model|
        register_task_context_model(task_model)
    end
    project.deployers.each do |_, deployer_model|
        register_deployment_model(deployer_model)
    end
    project_load_callbacks.each do |callback|
        callback.call(project)
    end
end

#register_task_context_model(model) ⇒ void

This method returns an undefined value.

Registers a new task model

Parameters:



463
464
465
# File 'lib/orogen/loaders/base.rb', line 463

def register_task_context_model(model)
    loaded_task_models[model.name] = model
end

#register_type_model(type, interface = true) ⇒ Object



297
298
299
300
301
302
# File 'lib/orogen/loaders/base.rb', line 297

def register_type_model(type, interface = true)
    registry.merge type.registry.minimal(type.name)
    if interface
        interface_typelist << type.name
    end
end

#register_typekit_model(typekit) ⇒ Object

Registers information from this typekit

Callbacks registered by #on_typekit_load gets called with the new typekit as argument



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/orogen/loaders/base.rb', line 254

def register_typekit_model(typekit)
    if loaded_typekits.has_key?(typekit.name)
        raise AlreadyRegistered, "there is already a typekit called #{typekit.name} registered on #{self}"
    end

    loaded_typekits[typekit.name] = typekit
    if root_loader != self
        return root_loader.register_typekit_model(typekit)
    end

    registry.merge typekit.registry

    typekit.registry.each(with_aliases: false) do |type|
        self_type = registry.get(type.name)
        self_type..add('orogen:typekits', typekit.name)
        if typekit.include?(type.name)
            self_type..add('orogen:definition_typekits', typekit.name)
        end

        if type.contains_opaques?
            intermediate_type_name = typekit.intermediate_type_name_for(type)
            intermediate_type = registry.get(intermediate_type_name)
            self_type..add('orogen:intermediate_type',
                              intermediate_type_name)
            intermediate_type..add('orogen:intermediate_type_of',
                                           type.name)
            if !type.opaque?
                intermediate_type..set('orogen:generated_type',
                                               'true')
            end
        end
    end

    @interface_typelist |= typekit.interface_typelist
    typekit.registry.each(with_aliases: true) do |typename, _|
        typekits_by_type_name[typename] ||= Set.new
        typekits_by_type_name[typename] << typekit
    end
    typekit_load_callbacks.each do |callback|
        callback.call(typekit)
    end
end

#remove_project_load_callback(callback) ⇒ Object

Removes the given callback from the listeners to #on_project_load

Parameters:

  • callback (Object)

    the value returned by #on_project_load for the callback that should be removed



128
129
130
# File 'lib/orogen/loaders/base.rb', line 128

def remove_project_load_callback(callback)
    project_load_callbacks.delete(callback)
end

#resolve_interface_type(typename) ⇒ Object

Returns the type object for typename, validating that we can use it in a task interface, i.e. that it will be registered in the RTT's typeinfo system



371
372
373
374
375
376
377
378
379
380
# File 'lib/orogen/loaders/base.rb', line 371

def resolve_interface_type(typename)
    type = resolve_type(typename)
    if type < Typelib::ArrayType
        raise InvalidInterfaceType.new(type), "static arrays are not valid interface types. Use an array in a structure or a std::vector"
    elsif !interface_type?(type)
        typekits = imported_typekits_for(type.name)
        raise NotExportedType.new(type, typekits), "#{type.name}, defined in the #{typekits.map(&:name).join(", ")} typekits, is never exported"
    end
    type
end

#resolve_type(type, options = Hash.new) ⇒ Model<Typelib::Type>

Resolves a type object

Parameters:

  • type (#name, String)

    the type to be resolved

Returns:

Raises:

  • Typelib::NotFound if the type cannot be found



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/orogen/loaders/base.rb', line 325

def resolve_type(type, options = Hash.new)
    typename =
        if type.respond_to?(:name)
            type.name
        else type
        end
    registry.get(typename)
rescue Typelib::NotFound => e
    if define_dummy_types? || options[:define_dummy_type]
        type = registry.create_null(typename)
        register_type_model(type, interface: true)
        return type
    else raise e, "#{e.message} using #{self}", e.backtrace
    end
end

#task_library_model_from_name(name) ⇒ OroGen::Spec::Project

Returns the task library model corresponding to the given name

Parameters:

  • the (String)

    project name

Returns:

Raises:

  • (ProjectNotFound)

    if there is no task library with that name. This does including having a project with that name if the project defines no tasks.



138
139
140
141
142
143
144
# File 'lib/orogen/loaders/base.rb', line 138

def task_library_model_from_name(name)
    project = project_model_from_name(name)
    if project.self_tasks.empty?
        raise ProjectNotFound, "there is an oroGen project called #{name}, but it defines no tasks"
    end
    project
end

#task_model_from_name(name) ⇒ Spec::TaskContext

Returns the task model object corresponding to a model name

Parameters:

  • name (String)

    the task model name

Returns:

Raises:



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/orogen/loaders/base.rb', line 152

def task_model_from_name(name)
    if model = loaded_task_models[name]
        return model
    end

    tasklib_name = find_task_library_from_task_model_name(name)
    if !tasklib_name
        raise TaskModelNotFound, "no task model #{name} is registered"
    end

    tasklib = project_model_from_name(tasklib_name)
    result = tasklib.tasks[name]
    if !result
        raise InternalError, "while looking up model of #{name}: found project #{tasklib_name}, but this project does not actually have a task model called #{name}"
    end

    result
end

#typekit_model_from_name(name) ⇒ Spec::Typekit

Loads a typekit from its name

Parameters:

  • name (String)

    the typekit name

Returns:

Raises:



235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/orogen/loaders/base.rb', line 235

def typekit_model_from_name(name)
    if typekit = loaded_typekits[name]
        return typekit
    end

    registry_xml, typelist_txt = typekit_model_text_from_name(name)
    typekit = Spec::Typekit.from_raw_data(root_loader, name, registry_xml, typelist_txt)
    if typekit.name != name
        raise InternalError, "inconsistency: got typekit #{typekit.name} while loading #{name}"
    end

    register_typekit_model(typekit)
    typekit
end

#typekit_model_text_from_name(name) ⇒ (String,String)

Returns the textual representation of a typekit

Parameters:

  • the (String)

    typekit name

Returns:

  • ((String,String))

    the typekit registry as XML and the typekit's typelist

Raises:



492
493
494
# File 'lib/orogen/loaders/base.rb', line 492

def typekit_model_text_from_name(name)
    raise NotImplementedError
end

#typelib_type_for(t) ⇒ Object



550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
# File 'lib/orogen/loaders/base.rb', line 550

def typelib_type_for(t)
    if t.respond_to?(:name)
        return t if !t.contains_opaques?
        t = t.name
    end

    if registry.include?(t)
        type = registry.get(t)
        if type.contains_opaques?
            intermediate_type_for(type)
        elsif type.null?
            # 't' is an opaque type and there are no typelib marshallers
            # to convert it to something we can manipulate, raise
            raise Typelib::NotFound, "#{t} is a null type and there are no typelib marshallers registered in RTT to convert it to a typelib-compatible type"
        else type
        end
    else
        raise Typelib::NotFound, "#{t} cannot be found in the currently loaded registries"
    end
end