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

child_selection[R]

A name => SelectedChild mapping of the selection result during instanciate

Public Class Methods

new(options = Hash.new) click to toggle source
Calls superclass method Syskit::Component.new
# File lib/syskit/composition.rb, line 20
def initialize(options = Hash.new)
    @child_selection = Hash.new
    super
end

Public Instance Methods

conf(names) click to toggle source

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
find_required_composition_child_from_role(role, from_model = self.model) click to toggle source

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
port_by_name(name) click to toggle source

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
removing_child(child) click to toggle source

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

Calls superclass method
# 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
required_composition_child_from_role(role) click to toggle source

(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
resolve_port(port_name) click to toggle source
# 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
self_port_to_actual_port(exported_port) click to toggle source

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
self_port_to_orocos_port(exported_port) click to toggle source

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
to_instance_requirements() click to toggle source

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
update_requirements(new_requirements, keep_abstract: false) click to toggle source
Calls superclass method Syskit::Component#update_requirements
# 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
updated_sink(child, mappings) click to toggle source
Calls superclass method
# File lib/syskit/composition.rb, line 257
def updated_sink(child, mappings)
    super
    dataflow_change_handler(false, child, mappings)
end