Class: Roby::Coordination::TaskScript

Inherits:
Base show all
Extended by:
Models::Script
Includes:
Script
Defined in:
lib/roby/coordination/task_script.rb

Overview

Implementation of a task script

The model-level accessors and API is described in Models::Script

Constant Summary

Constants included from Script

Script::DeadInstruction

Instance Attribute Summary collapse

Attributes included from Script

#current_instruction, #instructions

Attributes inherited from Base

#arguments, #instances, #parent

Instance Method Summary collapse

Methods included from Models::Script

add, call, instructions, terminal, terminal?

Methods included from Script

#dependency_options_for, #finished?, #jump_to, #prepare, #step

Methods inherited from Base

#attach_fault_response_tables_to, #bind_coordination_task_to_instance, #initialize, #instance_for, #model, #plan, #root_task

Constructor Details

This class inherits a constructor from Roby::Coordination::Base

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *args, &block) ⇒ Object



249
250
251
252
253
254
255
# File 'lib/roby/coordination/task_script.rb', line 249

def method_missing(m, *args, &block)
    if m =~ /_(?:event|child)$/
        instance_for(model.root).send(m, *args, &block)
    else
        super
    end
end

Instance Attribute Details

#definition_blockObject (readonly)

Returns the value of attribute definition_block.



15
16
17
# File 'lib/roby/coordination/task_script.rb', line 15

def definition_block
  @definition_block
end

Instance Method Details

#bind(task) ⇒ Object



29
30
31
32
33
34
35
# File 'lib/roby/coordination/task_script.rb', line 29

def bind(task)
    result_model = self.class.superclass.new_submodel(root: model.root.model)
    result = result_model.new(task)
    result.parse(&definition_block)
    result.prepare
    result
end

#emit(event) ⇒ Object

Emit the given event



172
173
174
175
176
# File 'lib/roby/coordination/task_script.rb', line 172

def emit(event)
    event, model_event = resolve_event(event)
    model.emit(model_event)
    event
end

#execute(task) ⇒ Object #execute({ ... }) ⇒ Object

Overloads:

  • #execute(task) ⇒ Object

    Deploy and start the given task, and wait for it to finish successfully

  • #execute({ ... }) ⇒ Object

    Execute the content of the given block once



117
118
119
120
121
122
123
124
125
126
# File 'lib/roby/coordination/task_script.rb', line 117

def execute(task = nil, &block)
    if task
        task, model_task = resolve_task(task)
        model.execute(model_task)
        task
    else
        model.instructions << BlockExecute.new(block)
        nil
    end
end

#parse(&block) ⇒ Object



24
25
26
27
# File 'lib/roby/coordination/task_script.rb', line 24

def parse(&block)
    @definition_block = block
    instance_eval(&block)
end

#poll(&block) ⇒ Object

Executes the provided block once per execution cycle

Call #transition! to quit the block



181
182
183
# File 'lib/roby/coordination/task_script.rb', line 181

def poll(&block)
    poll_until(poll_transition_event, &block)
end

#poll_until(event, &block) ⇒ Object

Execute the provided block once per execution cycle, until the given event is emitted

Raises:

  • (ArgumentError)


187
188
189
190
191
192
193
# File 'lib/roby/coordination/task_script.rb', line 187

def poll_until(event, &block)
    raise ArgumentError, "poll_until requires a block" unless block

    event, model_event = resolve_event(event)
    model.instructions << Script::Models::PollUntil.new(model_event, block)
    event
end

#resolve_event(event) ⇒ Object

Resolve the given event object into a Coordination::Event and a Coordination::Models::Event



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/roby/coordination/task_script.rb', line 81

def resolve_event(event)
    if event.respond_to?(:to_sym)
        symbol = event
        if root_task
            event = root_task.find_event(symbol)
        else
            event = model.root.find_event(symbol)
        end
        unless event
            raise ArgumentError, "#{model.root} has no event called #{symbol}"
        end
    end
    _, model_task = resolve_task(event.task)
    model_event = model_task.find_event(event.symbol)
    script_event = instance_for(model_event)
    [script_event, model_event]
end

#resolve_instructionsObject



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/roby/coordination/task_script.rb', line 37

def resolve_instructions
    super
    model.each_task do |model_task|
        script_task = instance_for(model_task)
        if script_task.respond_to?(:task) && !script_task.task # Not bound ? Check if the model can be instanciated
            task = model_task.instanciate(root_task.plan)
            bind_coordination_task_to_instance(script_task, task, on_replace: :copy)

            # Protect from scheduling until the start is executed
            #
            # #start_task will be called by the Start instruction
            root_task.start_event.add_causal_link(task.start_event)
        end
    end
    # Now, make the dependencies based on what we do / wait for with
    # the tasks. Namely, we look at Start (dependency options) and
    # Wait (success events)
    instructions.each do |ins|
        case ins
        when Coordination::Models::Script::Start
            task = ins.task.resolve
            root_task.depends_on task, ins.dependency_options
        end
    end
end

#resolve_task(task) ⇒ Object

Resolve the given event object into a Coordination::Task and a Coordination::Models::Task



65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/roby/coordination/task_script.rb', line 65

def resolve_task(task)
    if root_task && task.kind_of?(Roby::Task)
        root_task.plan.add(task)
        model_task = Coordination::Models::Task.new(task.model)
        script_task = instance_for(model_task)
        bind_coordination_task_to_instance(script_task, task, on_replace: :copy)
    else
        model_task = self.model.task(task)
        script_task = instance_for(model_task)
    end

    [script_task, model_task]
end

#respond_to_missing?(m, include_private) ⇒ Boolean

Returns:

  • (Boolean)


241
242
243
244
245
246
247
# File 'lib/roby/coordination/task_script.rb', line 241

def respond_to_missing?(m, include_private)
    if m =~ /_(?:event|child)$/
        instance_for(model.root).respond_to?(m)
    else
        super
    end
end

#sleep(seconds) ⇒ Object

Sleep for a given number of seconds

Parameters:

  • seconds (Float)

    the number of seconds to stop the script execution



166
167
168
169
# File 'lib/roby/coordination/task_script.rb', line 166

def sleep(seconds)
    task = start(Tasks::Timeout.new(delay: seconds), explicit_start: true)
    wait task.stop_event
end

#start(task, explicit_start: false, **dependency_options) ⇒ Object

Start the given task at that point in the script, and wait for it to emit its start event

Parameters:

  • task (Task)

    the task that should be started

  • dependency_options (Hash)

    options that should be passed to TaskStructure::Dependency::Extension#depends_on



105
106
107
108
109
# File 'lib/roby/coordination/task_script.rb', line 105

def start(task, explicit_start: false, **dependency_options)
    task, model_task = resolve_task(task)
    model.start(model_task, explicit_start: explicit_start, **dependency_options)
    task
end

#start_task(task, explicit_start: false) ⇒ Object

Used by Script



234
235
236
237
238
239
# File 'lib/roby/coordination/task_script.rb', line 234

def start_task(task, explicit_start: false)
    root_task.start_event.remove_causal_link(task.resolve.start_event)
    if explicit_start
        task.resolve.start_event.call
    end
end

#taskObject

Deprecated.

Use #root_task instead



20
21
22
# File 'lib/roby/coordination/task_script.rb', line 20

def task
    root_task
end

#timeout(seconds, options = {}, &block) ⇒ Object

Execute the script instructions given as block. If they take more than the specified number of seconds, either generate an error or emit an event (and quit the block)

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :emit (Event) — default: nil

    if set, the given event will be emitted when the timeout is reached. Otherwise, a Script::TimedOut exception is generated with the script’s supporting task as origin



209
210
211
212
213
# File 'lib/roby/coordination/task_script.rb', line 209

def timeout(seconds, options = {}, &block)
    timeout = timeout_start(seconds, options)
    parse(&block)
    timeout_stop(timeout)
end

#timeout_start(seconds, options = {}) ⇒ Object

Start a timeout operation. Usually not used directly

See Also:



218
219
220
221
222
223
224
# File 'lib/roby/coordination/task_script.rb', line 218

def timeout_start(seconds, options = {})
    options, timeout_options = Kernel.filter_options options, emit: nil
    if event = options[:emit]
        _, model_event = resolve_event(event)
    end
    model.timeout_start(seconds, timeout_options.merge(emit: model_event))
end

#timeout_stop(timeout) ⇒ Object

Stop a timeout operation. Usually not used directly

See Also:



229
230
231
# File 'lib/roby/coordination/task_script.rb', line 229

def timeout_stop(timeout)
    model.timeout_stop(timeout)
end

#transition!Object

Quit a #poll block



196
197
198
# File 'lib/roby/coordination/task_script.rb', line 196

def transition!
    root_task.poll_transition_event.emit
end

#wait(event, options = {}) ⇒ Object

Wait for an event to be emitted

Examples:

wait first_child.start_event

Waits until start event has been emitted. Will wait forever if
the start event has already been emitted

wait first_child.start_event, after: Time.at(0)

Waits for start event to be emitted. Will return immediately if
it has already been emitted.

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • after (Time, nil) — default: nil

    if set, only event emissions that happened after this value will make the script pass this instruction. The default of nil means “from the point of this instruction on”



142
143
144
145
146
# File 'lib/roby/coordination/task_script.rb', line 142

def wait(event, options = {})
    event, model_event = resolve_event(event)
    model.wait(model_event, **options)
    event
end

#wait_any(event, options = {}) ⇒ Object

Deprecated.

Use wait(event after: Time.at(0)) instead



158
159
160
# File 'lib/roby/coordination/task_script.rb', line 158

def wait_any(event, options = {})
    wait(event, options.merge(after: Time.at(0)))
end

#wait_untilObject

Waits until the given block returns true



149
150
151
152
153
# File 'lib/roby/coordination/task_script.rb', line 149

def wait_until
    poll do
        transition! if yield
    end
end