Module: Command::DSL::Action
Overview
The methods available within the DSL::CommandDefinition#action method
The trickiest thing to realize about writing Commands is that a CommandSet is an object that contains several Command subclasses; Commad::setup creates a subclass, and so CommandSet#command does too. It’s when a command is invoked that it’s actually instantiated.
Also note that you can access the arguments of a command as read-only attributes, and you can write to and read from instance variables, which will be local to the invocation of the command. This is especially useful for undo and redo.
Instance Method Summary collapse
-
#action_thread(&block) ⇒ Object
For big jobs - splitting them into subthreads and such.
-
#chain(*args) ⇒ Object
It frequently makes sense to offer shortcut chains to the user, or even commands that can only be run as part of another command.
-
#chain_first(klass_or_path, args) ⇒ Object
Like #chain, but interjects the command being chained to the start of the queue, immediately after this command completes.
-
#defer(deck = nil) ⇒ Object
Stop here and return control to the user.
-
#dont_undo ⇒ Object
Some commands sometimes cause side effects.
- #fan_out(threads_at_a_time, array, &block) ⇒ Object
-
#pause(deck = nil) ⇒ Object
Stop here.
- #root ⇒ Object
-
#subject ⇒ Object
This is how you’ll access the Command::Subject object that’s the interface of every command to the program state.
-
#task(id) ⇒ Object
Allows for a command to be broken into pieces so that a resume can pick up within a command.
-
#undo(box) ⇒ Object
Not normally called from within an #action block, this provides the default behavior for an undo (raise an exception).
- #up(levels = 1) ⇒ Object
Methods included from Formatting
#begin_list, #end_list, #item, #list, #sub_collector
Instance Method Details
#action_thread(&block) ⇒ Object
For big jobs - splitting them into subthreads and such. But they need to be debugged, and IIRC there’s a deadlock condition
632 633 634 635 636 637 638 639 |
# File 'lib/command-set/dsl.rb', line 632 def action_thread(&block) collector = sub_collector return Thread.new do $stdout.set_thread_collector(collector) block.call $stdout.remove_thread_collector(collector) end end |
#chain(*args) ⇒ Object
It frequently makes sense to offer shortcut chains to the user, or even commands that can only be run as part of another command. Calling chain with either a command class or a command path allows will cause that command to be invoked before returning control to the user.
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 |
# File 'lib/command-set/dsl.rb', line 574 def chain(*args) anchor = CommandSet === args.first ? args.shift : self.parent setup = AnchoredCommandSetup.new(anchor) setup.arg_hash = Hash === args.last ? args.pop : {} if args.length == 1 args = args[0] case args when Array setup.terms = args when String setup.terms = [args] when Symbol setup.terms = [args.to_s] when Class setup.command_class = args else raise CommandException, "Can't chain #{args.inspect}" end else if args.find{|arg| not (String === arg or Symbol === arg)} raise CommandException, "Can't chain #{args.inspect}" else setup.terms = args.map{|arg| arg.to_s} end end subject.chain_of_command.push(setup) end |
#chain_first(klass_or_path, args) ⇒ Object
Like #chain, but interjects the command being chained to the start of the queue, immediately after this command completes.
606 607 608 609 610 611 |
# File 'lib/command-set/dsl.rb', line 606 def chain_first(klass_or_path, args) setup = CommandSetup.new setup.command = klass_or_path setup.args_hash = args subject.chain_of_command.unshift(setup) end |
#defer(deck = nil) ⇒ Object
Stop here and return control to the user. If several commands are chained (c.f. #chain) and the pause is subsequently resumed (StandardCommands::Resume) the rest of the chain (not this command) will be dropped.
548 549 550 |
# File 'lib/command-set/dsl.rb', line 548 def defer(deck = nil) raise ResumeFromOnlyThis, deck end |
#dont_undo ⇒ Object
Some commands sometimes cause side effects. When evaluating arguments, if you discover that undoing doesn’t make sense, and will be confusing to the user, call dont_undo, and the interpreter will ignore the call for purposes of undoing
524 525 526 527 |
# File 'lib/command-set/dsl.rb', line 524 def dont_undo @should_undo = false return nil end |
#fan_out(threads_at_a_time, array, &block) ⇒ Object
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 |
# File 'lib/command-set/dsl.rb', line 641 def fan_out(threads_at_a_time, array, &block) require 'thwait' array = array.to_a first_batch = (array[0...threads_at_a_time]||[]).map do |item| action_thread { block.call(item) } end rest = (array[threads_at_a_time..-1] || []) waiter = ThreadsWait.new(*first_batch) rest.each do |item| waiter.next_wait waiter.join_nowait(action_thread{block.call(item)}) end waiter.join end |
#pause(deck = nil) ⇒ Object
Stop here. Return control to the user. If several commands are chained (c.f. #chain) and the pause is subsequently resumed (StandardCommands::Resume) the whole chain will be resumed.
540 541 542 |
# File 'lib/command-set/dsl.rb', line 540 def pause(deck = nil) raise ResumeFrom, deck end |
#root ⇒ Object
617 618 619 |
# File 'lib/command-set/dsl.rb', line 617 def root return @nesting[0] end |
#subject ⇒ Object
This is how you’ll access the Command::Subject object that’s the interface of every command to the program state.
531 532 533 |
# File 'lib/command-set/dsl.rb', line 531 def subject @subject_image end |
#task(id) ⇒ Object
Allows for a command to be broken into pieces so that a resume can pick up within a command. The block will be executed normally, but if the command is resumed with a task id, all task blocks until that id will be skipped.
556 557 558 559 560 561 562 563 564 565 |
# File 'lib/command-set/dsl.rb', line 556 def task(id) #:yield: if not @resume_from.nil? if @resume_from == id @resume_from = nil end return end yield if block_given? @last_completed_task = id end |
#undo(box) ⇒ Object
Not normally called from within an #action block, this provides the default behavior for an undo (raise an exception)
625 626 627 |
# File 'lib/command-set/dsl.rb', line 625 def undo(box) raise CommandException, "#{@name} cannot be undone" end |
#up(levels = 1) ⇒ Object
613 614 615 |
# File 'lib/command-set/dsl.rb', line 613 def up(levels = 1) return @nesting[-(levels+1)] end |