class Syskit::Composition
Compositions, i.e. grouping of components and/or other compositions that perform a given function.
Compositions are used to regroup components and/or other compositions in functional groups.
See the Models::Composition for class-level methods
Attributes
A name => SelectedChild mapping of the selection result during instanciate
Public Class Methods
# File lib/syskit/composition.rb, line 20 def initialize(options = Hash.new) @child_selection = Hash.new super end
Public Instance Methods
Returns the configuration definition for the given configuration(s)
Note that unlike ConfigurationManager, only one configuration can be selected (they cannot be overlaid on top of each other)
The returned value is a mapping from child names to the configurations that should be applied to them, i.e. for the 'narrow' configuration used as an example in #conf,
conf(['narrow'])
would return
'monitoring' => ['default', 'narrow_window'], 'sonar' => ['default', 'narrow_window']
# File lib/syskit/composition.rb, line 45 def conf(names) if names.size != 1 raise ArgumentError, "unlike with ConfigurationManager, only one configuration can be selected on compositions" end result = Hash.new found_something = false model.each_configuration(names.first.to_s, false) do |values| found_something = true result = values.merge(result) end if !found_something if names == ['default'] ConfigurationManager.info "required default configuration on composition #{task}, but #{task.model.short_name} has no registered default configurations" return result else raise ArgumentError, "#{self} has no declared configuration called #{names.join(", ")}" end end result end
Returns a child from its role, as the composition model tells we should see it
Generally speaking, if the composition model requires a data service, this service is going to be returned instead of the whole task
@return [Component,BoundDataService,nil]
# File lib/syskit/composition.rb, line 134 def find_required_composition_child_from_role(role, from_model = self.model) selected = child_selection[role] return if !selected # Check what the child is made of ... We might not have to # return a service task = find_child_from_role(role) return if !task target_child_model = from_model.find_child(role) if target_srv = target_child_model.service service_selections = [selected.service_selection] child_model = self.model.find_child(role) while !from_model.fullfills?(child_model.composition_model) service_selections.unshift child_model.overload_info.service_selection child_model = child_model.parent_model end selected_service_m = service_selections.inject(target_srv) do |srv, selections| if selected_srv = selections[srv.model] if task.model <= selected_srv.component_model selected_srv else selected_srv.as_real_model end else break srv end end return selected_service_m.bind(task).as(target_srv.model) else return task end end
Finds the corresponding syskit port @param [String] the name of the port that should be found @return [Syskit::Port] the actuar orocos port with the given name @raises [ArgumentError] if the port does not exist
# File lib/syskit/composition.rb, line 119 def port_by_name(name) if p = find_input_port(name) || find_output_port(name) p else raise ArgumentError, "#{self} has no port called #{name}, known ports are: #{each_port.map(&:name).sort.join(", ")}" end end
Hook called when one of the compositions' child has been removed
If self has exported ports, this broke some connections (the exported ports are not “internally connected” anymore) and as such the corresponding tasks should be added to modified_tasks
# File lib/syskit/composition.rb, line 228 def removing_child(child) super dataflow_graph = relation_graph_for(Flows::DataFlow) if dataflow_graph.has_edge?(child, self) # output ports, we only need to make sure that the dataflow # handlers are called dataflow_graph.remove_relation(child, self) end if dataflow_graph.has_edge?(self, child) # This one is harder, we need to explicitely add the sources # because none of the other triggers will work dataflow_graph.edge_info(self, child).each_key do |self_port_name, _| self_port = find_input_port(self_port_name) self_port.each_concrete_connection do |source_port| dataflow_graph.modified_tasks << source_port.component end end end end
(see #find_required_composition_child_from_role)
@return [Component,BoundDataService] @raise ArgumentError if the requested child does not exist
# File lib/syskit/composition.rb, line 168 def required_composition_child_from_role(role) selected = find_required_composition_child_from_role(role) if !selected raise ArgumentError, "#{role} does not seem to be a proper child of this composition" end selected end
# File lib/syskit/composition.rb, line 67 def resolve_port(port_name) export = model.find_exported_input(port_name) || model.find_exported_output(port_name) child_name = export.component_model.child_name if child = find_child_from_role(child_name) actual_port_name = child_selection[child_name].port_mappings[export.name] if child.respond_to?(:resolve_port) child.resolve_port(actual_port_name) else child.find_port(actual_port_name) end end end
Maps a port exported on this composition to the port that it represents on the actual task context
@param [Syskit::Port] exported_port the port to be mapped @return [Syskit::Port] the actual port. Its {Port#component}
attribute is guaranteed to be an instance of TaskContext
# File lib/syskit/composition.rb, line 86 def self_port_to_actual_port(exported_port) port_name = exported_port.name export = model.find_exported_input(port_name) || model.find_exported_output(port_name) child_name = export.component_model.child_name child = child_from_role(child_name) actual_port_name = child_selection[child_name].port_mappings[export.name] child.find_port(actual_port_name).to_actual_port end
Maps a port exported on this composition to the actual orocos port that it represents
@param [Syskit::Port] exported_port the port to be mapped @return [Orocos::Port] the actual port
# File lib/syskit/composition.rb, line 103 def self_port_to_orocos_port(exported_port) self_port_to_actual_port(exported_port).to_orocos_port end
Generates the InstanceRequirements
object that represents self best
@return [Syskit::InstanceRequirements]
# File lib/syskit/composition.rb, line 275 def to_instance_requirements req = super use_flags = Hash.new model.each_child do |child_name, _| use_flags[child_name] = required_composition_child_from_role(child_name).to_instance_requirements end req.use(use_flags) req end
# File lib/syskit/composition.rb, line 107 def update_requirements(new_requirements, keep_abstract: false) super new_requirements.dynamics.ports.each do |port_name, info| find_port(port_name).to_actual_port.component. requirements.dynamics.add_port_info(port_name, info) end end
# File lib/syskit/composition.rb, line 257 def updated_sink(child, mappings) super dataflow_change_handler(false, child, mappings) end