Module: Roby::Models::Task
Defined Under Namespace
Classes: AsPlanProxy, Template, TemplateEventGenerator
Constant Summary collapse
- @@exception_handler_id =
0
Constants included from Arguments
Arguments::NO_DEFAULT_ARGUMENT
Event Relations collapse
-
#causal_link(mappings) ⇒ Object
Establish model-level causal links between events of that task.
-
#forward(mappings) ⇒ Object
Establish model-level forwarding between events of that task.
-
#signal(mappings) ⇒ Object
Establish model-level signals between events of that task.
Class Method Summary collapse
-
.define_method_unless_present(m, name, &block) ⇒ Object
private
Helper method for #define_event_methods.
-
.model_attribute_list(name) ⇒ Object
Declares an attribute set which follows the task models inheritance hierarchy.
- .model_relation(name) ⇒ Object
Instance Method Summary collapse
-
#abstract ⇒ Object
Declare that this task model defines abstract tasks.
- #all_models ⇒ Object deprecated Deprecated.
-
#as_plan(**arguments) ⇒ Object
Default implementation of the #as_plan method.
- #can_merge?(target_model) ⇒ Boolean
-
#clear_model ⇒ Object
Clears all definitions saved in this model.
- #compute_terminal_events(events) ⇒ Object
-
#define_command_method(event_name, block) ⇒ Object
private
Define the method that will be used as command for the given event.
-
#define_event_methods(event_name) ⇒ Object
private
Define support methods for a task event.
- #discover_terminal_events(events, terminal_set, set, root) ⇒ Object
- #enum_events ⇒ Object
-
#event(event_name, options = {}, &block) ⇒ Hash<Symbol,TaskEvent>
The events defined by the task model.
-
#event_model(model_def) ⇒ Model<TaskEvent>
Accesses an event model.
-
#find_event_model(name) ⇒ Object
(also: #has_event?)
Find the event class for
event
, or nil ifevent
is not an event name for this model. -
#from(object) ⇒ Object
Helper method to define delayed arguments from related objects.
-
#from_state(state_object = State) ⇒ Object
Helper method to define delayed arguments from the State object.
- #fullfills?(models) ⇒ Boolean
- #instantiate_event_relations(template) ⇒ Object
-
#interruptible ⇒ Object
Declare that tasks of this model can be interrupted by calling the command of Task#failed_event.
- #invalidate_template ⇒ Object
-
#match(*args) ⇒ Object
Returns a TaskMatcher object that matches this task model.
-
#on(*event_names) {|context| ... } ⇒ Object
Adds an event handler for the given event model.
-
#on_exception(matcher) {|exception| ... } ⇒ Object
Defines an exception handler.
-
#poll(&block) ⇒ Object
Declares that the given block should be called at each execution cycle, when the task is running.
- #precondition(event, reason, &block) ⇒ Object
-
#provided_services ⇒ Object
Returns the lists of tags this model fullfills.
- #query(*args) ⇒ Object
-
#template ⇒ Object
The plan that is used to instantiate this task model.
-
#terminal_events ⇒ Object
Get the list of terminal events for this task model.
-
#terminates ⇒ Object
Declare that tasks of this model can finish by simply emitting stop, i.e.
- #to_coordination_task(_task_model) ⇒ Object
-
#to_execution_exception_matcher ⇒ Queries::ExecutionExceptionMatcher
An exception match object that matches exceptions originating from this task.
-
#update_terminal_flag ⇒ Object
private
Update the terminal flag for the event models that are defined in this task model.
-
#with_arguments(arguments = {}) ⇒ Object
If this class model has an ‘as_plan’, this specifies what arguments should be passed to as_plan.
Methods included from Arguments
#argument, #arguments, #default_argument, #meaningful_arguments
Class Method Details
.define_method_unless_present(m, name, &block) ⇒ Object
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.
Helper method for #define_event_methods
643 644 645 646 647 |
# File 'lib/roby/models/task.rb', line 643 def self.define_method_unless_present(m, name, &block) return if m.method_defined?(name) m.send(:define_method, name, &block) end |
.model_attribute_list(name) ⇒ Object
Declares an attribute set which follows the task models inheritance hierarchy. Define the corresponding enumeration methods as well.
For instance,
model_attribute_list 'signal'
defines the model-level signals, which can be accessed through
.each_signal(model)
.signals(model)
#each_signal(model)
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/roby/models/task.rb', line 271 def self.model_attribute_list(name) # :nodoc: class_eval <<~MODEL_ATTRIBUTE_ACCESSORS, __FILE__, __LINE__ + 1 inherited_attribute("#{name}_set", "#{name}_sets", map: true) { Hash.new { |h, k| h[k] = Set.new } } def each_#{name}(model) for obj in #{name}s(model) yield(obj) end self end def #{name}s(model) result = Set.new each_#{name}_set(model, false) do |set| result.merge set end result end def all_#{name}s if @all_#{name}s @all_#{name}s else result = Hash.new each_#{name}_set do |from, targets| result[from] ||= Set.new result[from].merge(targets) end @all_#{name}s = result end end MODEL_ATTRIBUTE_ACCESSORS end |
.model_relation(name) ⇒ Object
303 304 305 |
# File 'lib/roby/models/task.rb', line 303 def self.model_relation(name) model_attribute_list(name) end |
Instance Method Details
#abstract ⇒ Object
Declare that this task model defines abstract tasks. Abstract tasks can be used to represent an action, without specifically representing how this action should be done.
Instances of abstract task models are not executable, i.e. they cannot be started.
497 498 499 |
# File 'lib/roby/models/task.rb', line 497 def abstract @abstract = true end |
#all_models ⇒ Object
Use #each_submodel instead
239 240 241 |
# File 'lib/roby/models/task.rb', line 239 def all_models submodels end |
#as_plan(**arguments) ⇒ Object
Default implementation of the #as_plan method
The #as_plan method is used to use task models as representation of abstract actions. For instance, if an #as_plan method is available on a particular MoveTo task model, one can do
root.depends_on(MoveTo)
This default implementation looks for planning methods declared in the main Roby application planners that return the required task type or one of its subclasses. If one is found, it is using it to generate the action. Otherwise, it falls back to returning a new instance of this task model, unless the model is abstract in which case it raises ArgumentError.
It can be used with
class TaskModel < Roby::Task
end
root = Roby::Task.new
child = root.depends_on(TaskModel)
If arguments need to be given, the #with_arguments method should be used:
root = Roby::Task.new
child = root.depends_on(TaskModel.with_arguments(id: 200))
224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/roby/models/task.rb', line 224 def as_plan(**arguments) Roby.app.prepare_action(self, **arguments).first rescue Application::ActionResolutionError if abstract? raise Application::ActionResolutionError, "#{self} is abstract and no planning method exists "\ "that returns it" end new(**arguments) end |
#can_merge?(target_model) ⇒ Boolean
898 899 900 |
# File 'lib/roby/models/task.rb', line 898 def can_merge?(target_model) fullfills?(target_model) end |
#causal_link(mappings) ⇒ Object
Establish model-level causal links between events of that task. These signals will be established on all the instances of this task model (and its subclasses).
Causal links are used during event propagation to order the propagation properly. Establish a causal link when e.g. an event handler might call or emit on another of this task’s event
signal start: [:one, :two]
381 382 383 384 385 386 387 388 389 |
# File 'lib/roby/models/task.rb', line 381 def causal_link(mappings) mappings.each do |from, to| from = event_model(from).symbol causal_link_sets[from].merge( Array[*to].map { |ev| event_model(ev).symbol } ) end update_terminal_flag end |
#clear_model ⇒ Object
Clears all definitions saved in this model. This is to be used by the reloading code
245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/roby/models/task.rb', line 245 def clear_model class_eval do # Remove event models events.each_key do |ev_symbol| remove_const ev_symbol.to_s.camelcase(:upper) end [@events, @signal_sets, @forwarding_sets, @causal_link_sets, @arguments, @handler_sets, @precondition_sets].each do |set| set&.clear end end super end |
#compute_terminal_events(events) ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/roby/models/task.rb', line 154 def compute_terminal_events(events) success_events = [events[:success]].to_set failure_events = [events[:failed]].to_set terminal_events = [ events[:stop], events[:success], events[:failed] ].to_set event_set = events.values.to_set discover_terminal_events( event_set, terminal_events, success_events, events[:success] ) discover_terminal_events( event_set, terminal_events, failure_events, events[:failed] ) discover_terminal_events( event_set, terminal_events, nil, events[:stop] ) events.each_value do |ev| next unless ev.event_model.terminal? if !success_events.include?(ev) && !failure_events.include?(ev) terminal_events << ev end end [terminal_events, success_events, failure_events] end |
#define_command_method(event_name, block) ⇒ Object
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.
Define the method that will be used as command for the given event
610 611 612 613 614 615 616 617 |
# File 'lib/roby/models/task.rb', line 610 def define_command_method(event_name, block) check_arity(block, 1, strict: true) define_method("event_command_#{event_name}", &block) method = instance_method("event_command_#{event_name}") lambda do |dst_task, *event_context| method.bind(dst_task).call(*event_context) end end |
#define_event_methods(event_name) ⇒ Object
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.
Define support methods for a task event
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
# File 'lib/roby/models/task.rb', line 624 def define_event_methods(event_name) event_name = event_name.to_sym Task.define_method_unless_present(self, "#{event_name}_event") do @bound_events[event_name] || event(event_name) end Task.define_method_unless_present(self, "#{event_name}?") do (@bound_events[event_name] || event(event_name)).emitted? end Task.define_method_unless_present(self, "#{event_name}!") do |*context| (@bound_events[event_name] || event(event_name)).call(*context) end Task.define_method_unless_present(singleton_class, "#{event_name}_event") do find_event_model(event_name) end end |
#discover_terminal_events(events, terminal_set, set, root) ⇒ Object
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/roby/models/task.rb', line 135 def discover_terminal_events(events, terminal_set, set, root) stack = [root] until stack.empty? vertex = stack.shift [EventStructure::Signal, EventStructure::Forwarding] .each do |relation| vertex.parent_objects(relation).each do |parent| next unless events.include?(parent) next if parent[vertex, relation] next if terminal_set.include?(parent) terminal_set << parent set << parent if set stack << parent end end end end |
#enum_events ⇒ Object
701 702 703 704 705 706 |
# File 'lib/roby/models/task.rb', line 701 def enum_events Roby.warn_deprecated( "#enum_events is deprecated, use #each_event without a block instead" ) each_event end |
#event(event_name, options = {}, &block) ⇒ Hash<Symbol,TaskEvent>
The events defined by the task model
567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 |
# File 'lib/roby/models/task.rb', line 567 def event(event_name, = {}, &block) event_name = event_name.to_sym = ( , controlable: nil, command: nil, terminal: nil, model: find_event_model(event_name) || Roby::TaskEvent ) if .key?(:controlable) [:command] = [:controlable] elsif !.key?(:command) && block [:command] = define_command_method(event_name, block) end validate_event_definition_request(event_name, ) # Define the event class new_event = [:model].new_submodel( task_model: self, terminal: [:terminal], symbol: event_name, command: [:command] ) new_event.permanent_model = permanent_model? old_model = find_event_model(event_name) setup_terminal_handler = [:terminal] && new_event.symbol != :stop && (!old_model || !old_model.terminal?) events[new_event.symbol] = new_event forward(new_event => :stop) if setup_terminal_handler const_set(event_name.to_s.camelcase(:upper), new_event) define_event_methods(event_name) new_event end |
#event_model(model_def) ⇒ Model<TaskEvent>
Accesses an event model
This method gives access to this task’s event models. If given a name, it returns the corresponding event model. If given an event model, it verifies that the model is part of the events of self and returns it.
730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 |
# File 'lib/roby/models/task.rb', line 730 def event_model(model_def) if model_def.respond_to?(:to_sym) ev_model = find_event_model(model_def.to_sym) unless ev_model all_events = each_event.map { |name, _| name } unless ev_model raise ArgumentError, "#{model_def} is not an event of #{name}: "\ "#{all_events}" end end elsif model_def.respond_to?(:has_ancestor?) && model_def.has_ancestor?(Roby::TaskEvent) # Check that model_def is an event class for us ev_model = event_model(model_def.symbol) if ev_model != model_def raise ArgumentError, "the event model #{model_def} is not a model for "\ "#{name} (found #{ev_model} with the same name)" end else raise ArgumentError, "wanted either a symbol or an event class, got #{model_def}" end ev_model end |
#find_event_model(name) ⇒ Object Also known as: has_event?
Find the event class for event
, or nil if event
is not an event name for this model
716 717 718 |
# File 'lib/roby/models/task.rb', line 716 def find_event_model(name) find_event(name.to_sym) end |
#forward(mappings) ⇒ Object
Establish model-level forwarding between events of that task. These relations will be established on all the instances of this task model (and its subclasses).
Forwarding is used to cause the target event to be emitted when the source event is.
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/roby/models/task.rb', line 409 def forward(mappings) mappings.each do |from, to| from = event_model(from).symbol targets = Array[*to].map { |ev| event_model(ev).symbol } if event_model(from).terminal? non_terminal = targets.find_all do |name| !event_model(name).terminal? end unless non_terminal.empty? raise ArgumentError, "trying to establish a forwarding relation from "\ "the terminal event #{from} to the non-terminal "\ "event(s) #{targets}" end end forwarding_sets[from].merge targets end update_terminal_flag end |
#from(object) ⇒ Object
Helper method to define delayed arguments from related objects
437 438 439 440 441 442 443 |
# File 'lib/roby/models/task.rb', line 437 def from(object) if object.kind_of?(Symbol) Roby.from(nil).send(object) else Roby.from(object) end end |
#from_state(state_object = State) ⇒ Object
Helper method to define delayed arguments from the State object
449 450 451 |
# File 'lib/roby/models/task.rb', line 449 def from_state(state_object = State) Roby.from_state(state_object) end |
#fullfills?(models) ⇒ Boolean
882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 |
# File 'lib/roby/models/task.rb', line 882 def fullfills?(models) models = if models.respond_to?(:each) models.to_a else [models] end models.each do |m| m.each_fullfilled_model do |test_m| return false unless has_ancestor?(test_m) end end true end |
#instantiate_event_relations(template) ⇒ Object
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/roby/models/task.rb', line 63 def instantiate_event_relations(template) events = template.events_by_name all_signals.each do |generator, signalled_events| next if signalled_events.empty? generator = events[generator] signalled_events.each do |signalled| signalled = events[signalled] generator.signals signalled end end all_forwardings.each do |generator, signalled_events| next if signalled_events.empty? generator = events[generator] signalled_events.each do |signalled| signalled = events[signalled] generator.forward_to signalled end end all_causal_links.each do |generator, signalled_events| next if signalled_events.empty? generator = events[generator] signalled_events.each do |signalled| signalled = events[signalled] generator.add_causal_link signalled end end # Add a link from internal_event to stop if stop is controllable if events[:stop].controlable? events[:internal_error].signals events[:stop] end terminal_events, success_events, failure_events = compute_terminal_events(events) template.terminal_events = terminal_events template.success_events = success_events template.failure_events = failure_events start_event = events[:start] # WARN: the start event CAN be terminal: it can be a signal from # :start to a terminal event # # Create the precedence relations between 'normal' events and # the terminal events root_terminal_events = terminal_events.find_all do |ev| (ev != start_event) && ev.root?(Roby::EventStructure::Precedence) end events.each_value do |ev| next if ev == start_event next if terminal_events.include?(ev) if ev.root?(Roby::EventStructure::Precedence) start_event.add_precedence(ev) end if ev.leaf?(Roby::EventStructure::Precedence) root_terminal_events.each do |terminal| ev.add_precedence(terminal) end end end end |
#interruptible ⇒ Object
Declare that tasks of this model can be interrupted by calling the command of Task#failed_event
470 471 472 473 474 475 476 477 478 479 480 481 482 |
# File 'lib/roby/models/task.rb', line 470 def interruptible if !has_event?(:failed) || !event_model(:failed).controlable? raise ArgumentError, "failed is not controlable" end event(:stop) do |context| if starting? start_event.signals stop_event return end failed!(context) end end |
#invalidate_template ⇒ Object
42 43 44 |
# File 'lib/roby/models/task.rb', line 42 def invalidate_template @template = nil end |
#match(*args) ⇒ Object
Returns a TaskMatcher object that matches this task model
866 867 868 869 870 871 872 873 874 |
# File 'lib/roby/models/task.rb', line 866 def match(*args) matcher = Queries::TaskMatcher.new if args.empty? && self != Task matcher.which_fullfills(self) else matcher.which_fullfills(*args) end matcher end |
#on(*event_names) {|context| ... } ⇒ Object
Adds an event handler for the given event model. The block is going to be called whenever some events are emitted.
Unlike a block given to EventGenerator#on, the block is evaluated in the context of the task instance.
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 |
# File 'lib/roby/models/task.rb', line 773 def on(*event_names, &user_handler) raise ArgumentError, "#on called without a block" unless user_handler check_arity(user_handler, 1, strict: true) event_names.each do |from| from = event_model(from).symbol if user_handler method_name = "event_handler_#{from}_"\ "#{Object.address_from_id(user_handler.object_id).to_s(16)}" define_method(method_name, &user_handler) handler = ->(event) { event.task.send(method_name, event) } handler_sets[from] << EventGenerator::EventHandler.new(handler, false, false) end end end |
#on_exception(matcher) {|exception| ... } ⇒ Object
Defines an exception handler.
When propagating exceptions, ExecutionException goes up in the task hierarchy and calls matching handlers on the tasks it finds, and on their planning task. The first matching handler is called, and the exception propagation assumes that it handled the exception (i.e. won’t look for new handlers) unless it calls Task#pass_exception
843 844 845 846 847 848 849 850 851 |
# File 'lib/roby/models/task.rb', line 843 def on_exception(matcher, &handler) check_arity(handler, 1, strict: true) matcher = matcher.to_execution_exception_matcher id = (@@exception_handler_id += 1) define_method("exception_handler_#{id}", &handler) exception_handlers.unshift( [matcher, instance_method("exception_handler_#{id}")] ) end |
#poll(&block) ⇒ Object
Declares that the given block should be called at each execution cycle, when the task is running. Use it that way:
class MyTask < Roby::Task
poll do
... do something ...
end
end
If the given polling block raises an exception, the task will be terminated by emitting its failed
event.
813 814 815 816 817 |
# File 'lib/roby/models/task.rb', line 813 def poll(&block) raise ArgumentError, "no block given" unless block_given? define_method(:poll_handler, &block) end |
#precondition(event, reason, &block) ⇒ Object
792 793 794 795 |
# File 'lib/roby/models/task.rb', line 792 def precondition(event, reason, &block) event = event_model(event) precondition_sets[event.symbol] << [reason, block] end |
#provided_services ⇒ Object
Returns the lists of tags this model fullfills.
798 799 800 |
# File 'lib/roby/models/task.rb', line 798 def provided_services ancestors.find_all { |m| m.kind_of?(Models::TaskServiceModel) } end |
#query(*args) ⇒ Object
855 856 857 858 859 860 861 862 863 |
# File 'lib/roby/models/task.rb', line 855 def query(*args) q = Queries::Query.new if args.empty? && self != Task q.which_fullfills(self) else q.which_fullfills(*args) end q end |
#signal(mappings) ⇒ Object
Establish model-level signals between events of that task. These signals will be established on all the instances of this task model (and its subclasses).
Signals cause the target event(s) command to be called when the source event is emitted.
signal start: [:one, :two]
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 |
# File 'lib/roby/models/task.rb', line 339 def signal(mappings) mappings.each do |from, to| from = event_model(from) targets = Array[*to].map { |ev| event_model(ev) } if from.terminal? non_terminal = targets.find_all { |ev| !ev.terminal? } unless non_terminal.empty? raise ArgumentError, "trying to establish a signal from the terminal "\ "event #{from} to the non-terminal "\ "events #{non_terminal}" end end non_controlable = targets.find_all { |ev| !ev.controlable? } unless non_controlable.empty? raise ArgumentError, "trying to signal #{non_controlable.join(' ')} which "\ "is/are not controlable" end signal_sets[from.symbol].merge( targets.map(&:symbol) ) end update_terminal_flag end |
#template ⇒ Object
The plan that is used to instantiate this task model
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/roby/models/task.rb', line 47 def template return @template if @template template = Template.new each_event do |event_name, event_model| event = TemplateEventGenerator.new( event_model.controlable?, event_model, plan: template ) template.add(event) template.events_by_name[event_name] = event end instantiate_event_relations(template) @template = template end |
#terminal_events ⇒ Object
Get the list of terminal events for this task model
709 710 711 712 |
# File 'lib/roby/models/task.rb', line 709 def terminal_events each_event.find_all { |_, e| e.terminal? } .map { |_, e| e } end |
#terminates ⇒ Object
Declare that tasks of this model can finish by simply emitting stop, i.e. with no specific action.
461 462 463 464 |
# File 'lib/roby/models/task.rb', line 461 def terminates event :failed, command: true, terminal: true interruptible end |
#to_coordination_task(_task_model) ⇒ Object
902 903 904 |
# File 'lib/roby/models/task.rb', line 902 def to_coordination_task(_task_model) Roby::Coordination::Models::TaskFromAsPlan.new(self, self) end |
#to_execution_exception_matcher ⇒ Queries::ExecutionExceptionMatcher
Returns an exception match object that matches exceptions originating from this task.
878 879 880 |
# File 'lib/roby/models/task.rb', line 878 def to_execution_exception_matcher Queries::ExecutionExceptionMatcher.new.with_origin(self) end |
#update_terminal_flag ⇒ Object
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.
Update the terminal flag for the event models that are defined in this task model. The event is terminal if model-level signals (#signal) or forwards (#forward) lead to the emission of #stop_event
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 |
# File 'lib/roby/models/task.rb', line 507 def update_terminal_flag # :nodoc: events = each_event.map { |name, _| name } terminal_events = [:stop] events.delete(:stop) loop do old_size = terminal_events.size events.delete_if do |ev| signals_terminal = signals(ev).any? do |sig_ev| terminal_events.include?(sig_ev) end signals_terminal ||= forwardings(ev).any? do |sig_ev| terminal_events.include?(sig_ev) end if signals_terminal terminal_events << ev true end end break if old_size == terminal_events.size end terminal_events.each do |sym| if (ev = self.events[sym]) ev.terminal = true else ev = superclass.event_model(sym) unless ev.terminal? event sym, model: ev, terminal: true, command: (ev.method(:call) rescue nil) end end end end |
#with_arguments(arguments = {}) ⇒ Object
If this class model has an ‘as_plan’, this specifies what arguments should be passed to as_plan
185 186 187 188 189 190 191 192 193 |
# File 'lib/roby/models/task.rb', line 185 def with_arguments(arguments = {}) if respond_to?(:as_plan) AsPlanProxy.new(self, arguments) else raise NoMethodError, "#with_arguments is invalid on #self, as #self does not "\ "have an #as_plan method" end end |