Class: Command::BaseInterpreter

Inherits:
Object
  • Object
show all
Defined in:
lib/command-set/interpreter/base.rb

Overview

This is the base interpreter class. By itself it’ll raise a bunch of NoMethodErrors.

Interpreters manage the Subject object(s) and CommandSet and process input.

Subclasses of BaseInterpreter (like TextInterpreter, for instance, must implement #cook_input(raw) that converts raw input (of whatever form is appropriate to the interpreter) into CommandSetup objects. Other methods can be overridden - especially consider #get_formatter, and #prompt_user

Direct Known Subclasses

QuickInterpreter, TextInterpreter

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBaseInterpreter

Returns a new instance of BaseInterpreter.



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/command-set/interpreter/base.rb', line 19

def initialize
  @command_set=nil
  @sub_modes = []
  @behavior = {
    :screen_width => 76,
    :warn_no_undo => true
  }
  @out_io = $stdout
  @stop = false
  @subject = nil
  @logger = Logger.new($stderr)
  @logger.level=Logger::FATAL
  @undo_stack = UndoStack.new
  @commands_pending = []
  @pause_decks = Hash.new {|h,k| h[k]=[]}
end

Instance Attribute Details

#command_setObject

Returns the value of attribute command_set.



17
18
19
# File 'lib/command-set/interpreter/base.rb', line 17

def command_set
  @command_set
end

#loggerObject

Returns the value of attribute logger.



16
17
18
# File 'lib/command-set/interpreter/base.rb', line 16

def logger
  @logger
end

#out_ioObject

Returns the value of attribute out_io.



16
17
18
# File 'lib/command-set/interpreter/base.rb', line 16

def out_io
  @out_io
end

#sub_modesObject (readonly)

Returns the value of attribute sub_modes.



17
18
19
# File 'lib/command-set/interpreter/base.rb', line 17

def sub_modes
  @sub_modes
end

#subjectObject Also known as: subject_template

Returns the value of attribute subject.



17
18
19
# File 'lib/command-set/interpreter/base.rb', line 17

def subject
  @subject
end

Instance Method Details

#behavior(hash) ⇒ Object

Any options that the interpreter might have can be set by passing a hash to behavior to be merged with the defaults



67
68
69
# File 'lib/command-set/interpreter/base.rb', line 67

def behavior(hash)
  @behavior.merge!(hash)
end

#fill_subject {|template| ... } ⇒ Object

Yields:

  • (template)


59
60
61
62
63
# File 'lib/command-set/interpreter/base.rb', line 59

def fill_subject
  template = self.subject
  yield template
  self.subject=(template)
end

#get_formatterObject

Gets the final Results::Formatter object to output to. Override this if you won’t be reporting output to the standard output.



188
189
190
# File 'lib/command-set/interpreter/base.rb', line 188

def get_formatter
  return Results::TextFormatter.new(::Command::raw_stdout)
end

#get_formattersObject



192
193
194
# File 'lib/command-set/interpreter/base.rb', line 192

def get_formatters
  return [get_formatter]
end

#get_subjectObject



100
101
102
# File 'lib/command-set/interpreter/base.rb', line 100

def get_subject
  return Subject.new
end

#next_commandObject

Gets the next command in the queue - related to DSL::Action#chain. You’ll almost never want to override this method.



122
123
124
125
126
127
# File 'lib/command-set/interpreter/base.rb', line 122

def next_command
  setup = @commands_pending.shift
  setup.arg_hash = default_arg_hash.merge(setup.arg_hash)
  setup.set_nesting = current_nesting + setup.set_nesting
  return setup.command_instance(current_command_set, build_subject)
end

#pop_modeObject

The compliment to #push_mode. Removes the most recent command set.



86
87
88
89
# File 'lib/command-set/interpreter/base.rb', line 86

def pop_mode
  sub_modes.pop
  return nil
end

#prep_subject(subject) ⇒ Object

This method sets up the fields in the subject required by the interpreter.



106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/command-set/interpreter/base.rb', line 106

def prep_subject(subject)
  @command_set.add_requirements(subject)
  @command_set.add_defaults(subject)
  subject.required_fields(subject_requirements())
  subject.undo_stack = @undo_stack
  subject.command_set = @command_set
  subject.interpreter = self
  subject.interpreter_behavior = @behavior
  subject.chain_of_command = @commands_pending
  subject.pause_decks = @pause_decks
  subject.mode_stack = @sub_modes
  return subject
end

#process_input(raw_input) ⇒ Object

Process a single unit of input from the user. Relies on cook input to convert raw_input into a CommandSetup



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
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
182
183
184
# File 'lib/command-set/interpreter/base.rb', line 138

def process_input(raw_input)
  @commands_pending << cook_input(raw_input)

  presenter = Results::Presenter.new
  formatters = get_formatters
  formatters.each do |formatter|
    presenter.register_formatter(formatter)
  end
  collector = presenter.create_collector

  begin
    raise "Ack!  No OutputStandin in place!" unless $stdout.respond_to?(:add_dispatcher)
    $stdout.add_dispatcher(collector)
    until @commands_pending.empty?
      cmd = next_command
      unless cmd.class.executeable?
        raise CommandException, "incomplete command"
      end
      if ( @behavior[:warn_no_undo] and not cmd.undoable? )
        confirm = prompt_user("\"#{raw_input}\" cannot be undone.  Continue? ")
        if not ["yes", "y", "sure", "i suppose", "okay"].include? confirm.strip.downcase
          return
        end
      end
      begin
        execute(cmd, formatters, collector)
      rescue CommandException => ce
        ce.command = cmd
        raise
      rescue ResumeFrom => rf
        deck = rf.pause_deck
        @pause_decks[deck].push rf.setup
        raise unless ResumeFromOnlyThis === rf
      end
    end
  rescue ResumeFrom => rf
    @pause_decks[deck] += @commands_pending
  rescue CommandException => ce
    ce.raw_input = raw_input
    raise
  ensure
    $stdout.remove_dispatcher(collector)
  end
  presenter.done

  @commands_pending.clear
end

#prompt_user(message) ⇒ Object

Present message to the user, and get a response - usually yes or no. Non-interactive interpreters, or ones where that level of interaction is undesirable should not override this method, which returns “no”.



132
133
134
# File 'lib/command-set/interpreter/base.rb', line 132

def prompt_user(message)
   "no"
end

#push_mode(nesting) ⇒ Object

Puts a CommandSet ahead of the current one for processing. Useful for command

modes, like Cisco's IOS with configure modes, et al.


75
76
77
78
79
80
81
82
83
# File 'lib/command-set/interpreter/base.rb', line 75

def push_mode(nesting)
  mode = nesting.pop
  unless CommandSet === mode
    raise RuntimeError, "Sub-modes must be CommandSets!" 
  end

  sub_modes.push([mode, mode.most_recent_args, nesting])
  return nil
end

#subject_requirementsObject

If your interpreter needs extra fields in the subject, alter subject_requirements to return an array of those fields.



95
96
97
98
# File 'lib/command-set/interpreter/base.rb', line 95

def subject_requirements
  return [:undo_stack, :command_set, :interpreter, :interpreter_behavior, 
    :chain_of_command, :pause_decks, :mode_stack]
end