Class: Syskit::Models::CompositionChild

Inherits:
InstanceRequirements show all
Defined in:
lib/syskit/models/composition_child.rb

Overview

Used by Composition to define its children. Values returned by Syskit::Models::Composition#find_child are instances of that class.

Instance Attribute Summary collapse

Attributes inherited from InstanceRequirements

#arguments, #base_model, #deployment_group, #deployment_hints, #dynamics, #model, #name, #required_host, #specialization_hints, #template

Instance Method Summary collapse

Methods inherited from InstanceRequirements

#abstract, #abstract?, #add_models, #add_port_period, #as, #as_plan, #as_real_model, #as_real_model!, #can_use_template=, #can_use_template?, #component_model, #component_model?, #composition_model?, #compute_template, #create_proxy_task, #do_copy, #each_child, #each_fullfilled_model, #each_input_port, #each_output_port, #each_port, #each_required_model, #each_required_service_model, #find_all_data_services_from_type, #find_child, #find_data_service, #find_data_service_from_type, #find_input_port, #find_output_port, #find_port, #find_port_dynamics, #find_through_method_missing, from_object, #fullfilled_model, #fullfills?, #has_child?, #has_data_service?, #has_port?, #has_template?, #has_through_method_missing?, #hash, #if_already_present, #instanciate, #instanciate_from_template, #invalidate_dependency_injection, #invalidate_template, #map_use_selections!, #merge, #narrow_model, #not_abstract, #on_server, #period, #placeholder_model, #plain?, #port_by_name, #post_instanciation_setup, #prefer_deployed_tasks, #prefer_specializations, #push_dependency_injection, #push_selections, #reset_deployment_selection, #resolve, #resolved_dependency_injection, #select_service, #selected_for, #self_port_to_component_port, #service, #simplest_model_representation, #specialize, #to_action, #to_action_model, #to_component_model, #to_coordination_task, #try_bind, #try_resolve, #unselect_service, #use, #use_conf, #use_configured_deployment, #use_deployment, #use_deployment_group, #with_arguments, #with_conf, #with_no_arguments

Constructor Details

#initialize(composition_model, child_name, models = Set.new, dependency_options = Hash.new, parent_model = nil) ⇒ CompositionChild

Returns a new instance of CompositionChild



28
29
30
31
32
33
34
# File 'lib/syskit/models/composition_child.rb', line 28

def initialize(composition_model, child_name, models = Set.new, dependency_options = Hash.new,
              parent_model = nil)
    @composition_model, @child_name = composition_model, child_name
    super(models)
    @dependency_options = Roby::TaskStructure::Dependency.validate_options(dependency_options)
    @parent_model = parent_model
end

Instance Attribute Details

#child_nameObject (readonly)

String

the name of this child on #composition_model



10
11
12
# File 'lib/syskit/models/composition_child.rb', line 10

def child_name
  @child_name
end

#composition_modelObject (readonly)

Models::Composition

the model of the composition this child is

part of



8
9
10
# File 'lib/syskit/models/composition_child.rb', line 8

def composition_model
  @composition_model
end

#dependency_optionsObject

The set of models that this child should fullfill. It is a Set which contains at most one Component model and any number of data service models



14
15
16
# File 'lib/syskit/models/composition_child.rb', line 14

def dependency_options
  @dependency_options
end

#parent_modelCompositionChild?

Returns the composition child model from which this model has been overloaded

Returns:

  • (CompositionChild, nil)

    the composition child model from which this model has been overloaded



22
23
24
# File 'lib/syskit/models/composition_child.rb', line 22

def parent_model
  @parent_model
end

Instance Method Details

#==(other) ⇒ Object

:nodoc:



240
241
242
243
244
# File 'lib/syskit/models/composition_child.rb', line 240

def ==(other) # :nodoc:
    other.class == self.class &&
        other.composition_model == composition_model &&
        other.child_name == child_name
end

#attach(composition_model) ⇒ Object



272
273
274
275
276
# File 'lib/syskit/models/composition_child.rb', line 272

def attach(composition_model)
    result = dup
    result.instance_variable_set :@composition_model, composition_model
    result
end

#bind(component) ⇒ Syskit::Component, Syskit::BoundDataService

Binds this child model to the component

Within Syskit, binding a model to an instance means returning a 'view' of the instance that is described by the model. For instance, if the child is defined by a service, the returned object will be a BoundDataService instance, which then allows to for instance resolve ports “as if” they were from the service itself.

Parameters:

Returns:

Raises:

  • if self cannot be bound to the component, usually because the component is not the “right” child from the composition



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/syskit/models/composition_child.rb', line 162

def bind(component)
    compositions = component.each_parent_task.
        find_all { |t| t.fullfills?(composition_model) }
    parent = compositions.
        find { |t| component == t.find_child_from_role(child_name) }

    unless parent
        if compositions.empty?
            raise ArgumentError, "cannot bind #{self} to #{component}: "\
                "it is not the child of any #{composition_model} composition"
        else
            raise ArgumentError, "cannot bind #{self} to #{component}: "\
                "it is the child of one or more #{composition_model} compositions, "\
                "but not with the role '#{child_name}'"
        end
    end

    resolve_and_bind_child(composition_model.bind(parent))
end

#connect_ports(other_component, connections) ⇒ Object



228
229
230
231
232
233
234
235
236
237
238
# File 'lib/syskit/models/composition_child.rb', line 228

def connect_ports(other_component, connections)
    if !other_component.respond_to?(:composition_model)
        raise ArgumentError, "cannot connect ports of #{self} to ports of #{other_component}: #{other_component} is not a composition child"
    elsif other_component.composition_model != composition_model
        raise ArgumentError, "cannot connect ports of #{self} to ports of #{other_component}: they are children of different composition models"
    end
    cmp_connections = composition_model.explicit_connections[[child_name, other_component.child_name]]
    connections.each do |port_pair, policy|
        cmp_connections[port_pair] = policy
    end
end

#connect_to(sink, policy = Hash.new) ⇒ Array<Port>

Automatically computes the connections between the output ports of self to the given port or component interface

Parameters:

  • the (Port, CompositionChild)

    sink side of the connection. If a Port is given, it has to be a port on a CompositionChild of the same composition than self

Returns:

  • (Array<Port>)

    the set of created connections



198
199
200
# File 'lib/syskit/models/composition_child.rb', line 198

def connect_to(sink, policy = Hash.new)
    Syskit.connect(self, sink, policy)
end

#connected?(source_port, sink_port) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Tests whether two ports are connected

This is a delegated call from Port#connected_to?. Always use the former unless you know what you are doing

Returns:

  • (Boolean)


215
216
217
218
219
220
221
222
223
224
225
# File 'lib/syskit/models/composition_child.rb', line 215

def connected?(source_port, sink_port)
    if !self_port?(source_port)
        raise ArgumentError, "source port #{source_port} in connected? is not a port of #{self}"
    elsif !composition_model.child_port?(sink_port)
        return false
    end

    cmp_connections = composition_model.
        explicit_connections[[child_name, sink_port.component_model.child_name]]
    cmp_connections.has_key?([source_port.name,sink_port.name])
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


48
49
50
51
# File 'lib/syskit/models/composition_child.rb', line 48

def eql?(other)
    other.respond_to?(:child_name) && other.child_name == child_name &&
        super
end

#freezeObject



42
43
44
45
46
# File 'lib/syskit/models/composition_child.rb', line 42

def freeze
    # Precompute memoized values, or we'll get a frozen error
    overload_info
    super
end

#initialize_copy(old) ⇒ Object



36
37
38
39
40
# File 'lib/syskit/models/composition_child.rb', line 36

def initialize_copy(old)
    super
    @dependency_options = old.dependency_options.dup
    @overload_info = nil
end

#optionalObject



187
188
189
# File 'lib/syskit/models/composition_child.rb', line 187

def optional
    @optional = true
end

#optional?Boolean

If set to true, the child is going to be removed automatically if no selection exists for it

Returns:

  • (Boolean)


26
# File 'lib/syskit/models/composition_child.rb', line 26

attr_predicate :optional?

#overload_infoObject

InstanceSelection

information needed to update the composition's

parent models about the child (mainly port mappings)



17
18
19
# File 'lib/syskit/models/composition_child.rb', line 17

def overload_info
    @overload_info ||= InstanceSelection.new(nil, self, @parent_model || InstanceRequirements.new)
end

#port_mappingsObject

The port mappings from this child's parent model to this model



183
184
185
# File 'lib/syskit/models/composition_child.rb', line 183

def port_mappings
    overload_info.port_mappings
end

#pretty_print(pp) ⇒ Object



260
261
262
263
264
265
# File 'lib/syskit/models/composition_child.rb', line 260

def pretty_print(pp)
    pp.text "child #{child_name} of type "
    super
    pp.breakable
    pp.text "of #{composition_model}"
end

#resolve_and_bind_child(task) ⇒ Roby::Task

Resolves the task instance that corresponds to self, using task as the root composition. The returned instance is bound to self.

Returns:

  • (Roby::Task)

Raises:

  • (ArgumentError)

    if task does not fullfill the required composition model, or if it does not have the required children

See Also:



140
141
142
143
144
145
146
# File 'lib/syskit/models/composition_child.rb', line 140

def resolve_and_bind_child(task)
    if resolved_task = try_resolve_and_bind_child(task)
        resolved_task
    else
        raise ArgumentError, "cannot find #{self} from #{task}"
    end
end

#resolve_and_bind_child_recursive(root) ⇒ Object

Resolves the task that corresponds to self starting the resolution at the given root

If #composition_model is not itself a CompositionChild, this is equivalent to #resolve_and_bind_child. Otherwise, it resolves the children one by one starting at the given root.

Returns:

Raises:

  • (ArgumentError)

    if the root is not suitable for the resolution (e.g. wrong model or missing children)



104
105
106
107
108
109
110
# File 'lib/syskit/models/composition_child.rb', line 104

def resolve_and_bind_child_recursive(root)
    if bound = try_resolve_and_bind_child_recursive(root)
        bound
    else
        raise ArgumentError, "cannot resolve #{self} from #{root}"
    end
end

#resolve_child(task) ⇒ Object

Deprecated.


68
69
70
71
72
# File 'lib/syskit/models/composition_child.rb', line 68

def resolve_child(task)
    Roby.warn_deprecated "#{__method__} is deprecated, "\
        "use #resolve_and_bind_child instead"
    resolve_and_bind_child(task)
end

#self_port?(port) ⇒ Boolean

Test whether the given port object is a port of self

Parameters:

Returns:

  • (Boolean)


205
206
207
# File 'lib/syskit/models/composition_child.rb', line 205

def self_port?(port)
    port.component_model == self
end

#short_nameObject



268
269
270
# File 'lib/syskit/models/composition_child.rb', line 268

def short_name
    "#{composition_model.short_name}.#{child_name}_child[#{model.short_name}]"
end

#stateObject



246
247
248
249
250
251
252
253
254
255
256
# File 'lib/syskit/models/composition_child.rb', line 246

def state
    if @state
        return @state
    elsif component_model = models.find { |c| c <= Component }
        @state = Roby::StateFieldModel.new(component_model.state)
        @state.__object = self
        return @state
    else
        raise ArgumentError, "cannot create a state model on elements that are only data services"
    end
end

#to_instance_requirementsObject



278
279
280
281
282
# File 'lib/syskit/models/composition_child.rb', line 278

def to_instance_requirements
    ir = InstanceRequirements.new
    ir.do_copy(self)
    ir
end

#to_sObject



258
# File 'lib/syskit/models/composition_child.rb', line 258

def to_s; "#{composition_model}.#{child_name}_child[#{super}]" end

#try_resolve_and_bind_child(composition) ⇒ nil, Object

Resolves the instance that matches self in the given composition

The method binds the instance to self with #bind. This means that the returned value offers the interface that InstanceRequirements#model expects, and not necessarily the one of the actual instance.

For instance, if self represents a data service, it will return the corresponding BoundDataService

Parameters:

  • composition (Syskit::Composition)

    the composition instance whose child we are trying to resolve

Returns:

  • (nil, Object)

    the bound children instance, or nil if it cannot be resolved



125
126
127
128
129
130
# File 'lib/syskit/models/composition_child.rb', line 125

def try_resolve_and_bind_child(composition)
    if bound = composition_model.try_bind(composition)
        bound.find_required_composition_child_from_role(
            child_name, composition_model)
    end
end

#try_resolve_and_bind_child_recursive(root) ⇒ nil, Object

Tries to resolve the task that corresponds to self starting the resolution at the given root

If #composition_model is not itself a CompositionChild, this is equivalent to #try_resolve_and_bind_child. Otherwise, it resolves the children one by one starting at the given root.

Returns:



82
83
84
85
86
87
88
89
90
91
92
# File 'lib/syskit/models/composition_child.rb', line 82

def try_resolve_and_bind_child_recursive(root)
    # Handle a composition child of a composition child
    if composition_model.respond_to?(:try_resolve_and_bind_child_recursive)
        resolved_parent = composition_model.
            try_resolve_and_bind_child_recursive(root)

        try_resolve_and_bind_child(resolved_parent) if resolved_parent
    else
        try_resolve_and_bind_child(root)
    end
end

#try_resolve_child(task) ⇒ Object

Deprecated.


54
55
56
57
58
# File 'lib/syskit/models/composition_child.rb', line 54

def try_resolve_child(task)
    Roby.warn_deprecated "#{__method__} is deprecated, use "\
        "CompositionChild#try_resolve_and_bind_child instead"
    try_resolve_and_bind_child(task)
end

#try_resolve_child_recursive(root) ⇒ Object

Deprecated.


61
62
63
64
65
# File 'lib/syskit/models/composition_child.rb', line 61

def try_resolve_child_recursive(root)
    Roby.warn_deprecated "#{__method__} is deprecated, use "\
        "CompositionChild#try_resolve_and_bind_child_recursive instead"
    try_resolve_and_bind_child_recursive(root)
end