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



237
238
239
240
241
242
# File 'lib/roby/coordination/task_script.rb', line 237

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.



13
14
15
# File 'lib/roby/coordination/task_script.rb', line 13

def definition_block
  @definition_block
end

Instance Method Details

#bind(task) ⇒ Object



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

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



163
164
165
166
167
# File 'lib/roby/coordination/task_script.rb', line 163

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



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

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



22
23
24
25
# File 'lib/roby/coordination/task_script.rb', line 22

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



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

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



178
179
180
181
182
# File 'lib/roby/coordination/task_script.rb', line 178

def poll_until(event, &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



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

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
        if !event
            raise ArgumentError, "#{model.root} has no event called #{symbol}"
        end
    end
    script_task, model_task = resolve_task(event.task)
    model_event  = model_task.find_event(event.symbol)
    script_event = instance_for(model_event)
    return script_event, model_event
end

#resolve_instructionsObject



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

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



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

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

    return script_task, model_task
end

#respond_to_missing?(m, include_private) ⇒ Boolean

Returns:

  • (Boolean)


230
231
232
233
234
235
# File 'lib/roby/coordination/task_script.rb', line 230

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



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

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



103
104
105
106
107
# File 'lib/roby/coordination/task_script.rb', line 103

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



223
224
225
226
227
228
# File 'lib/roby/coordination/task_script.rb', line 223

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



18
19
20
# File 'lib/roby/coordination/task_script.rb', line 18

def task
    root_task
end

#timeout(seconds, options = Hash.new, &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: Hash.new)

Options Hash (options):

  • :event (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



198
199
200
201
202
# File 'lib/roby/coordination/task_script.rb', line 198

def timeout(seconds, options = Hash.new, &block)
    timeout = timeout_start(seconds, options)
    parse(&block)
    timeout_stop(timeout)
end

#timeout_start(seconds, options = Hash.new) ⇒ Object

Start a timeout operation. Usually not used directly

See Also:



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

def timeout_start(seconds, options = Hash.new)
    options, timeout_options  = Kernel.filter_options options, emit: nil
    if event = options[:emit]
        script_event, 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:



218
219
220
# File 'lib/roby/coordination/task_script.rb', line 218

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

#transition!Object

Quit a #poll block



185
186
187
# File 'lib/roby/coordination/task_script.rb', line 185

def transition!
    root_task.poll_transition_event.emit
end

#wait(event, options = Hash.new) ⇒ 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: Hash.new)

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”



140
141
142
143
144
# File 'lib/roby/coordination/task_script.rb', line 140

def wait(event, options = Hash.new)
    event, model_event = resolve_event(event)
    model.wait(model_event, options)
    event
end

#wait_any(event, options = Hash.new) ⇒ Object

Deprecated.

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



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

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