class SCPIsequence
Introduction¶ ↑
SCPIsequence
is essentially a container for an ordered sequence of SCPIsession
options (added via SCPIsequence.add) that may eventually be applied to an SCPIsession
in order (via SCPIsequence.execute
). In addition to SCPIsession
options, this class may also house a few additional parameters which provide various programming constructs: variables (with comprehensive substitution & ruby code execution), conditionals, & jumps. With these additions, the mrSCPI scripting language becomes Turing complete, and an SCPIsequence
can used to house full scripts.
Additional “options” for an SCPIsequence
¶ ↑
:eval
-
{VAR}={RUBY_CODE}
:var
-
{VAR}={VALUE}
:skip_if
-
{LHS}{=|!=|~|!~}{RHS}
:next_if
-
{LHS}{=|!=|~|!~}{RHS}
:stop
-
[MESSAGE]
–MESSAGE
is required when:stop
is given on the command line!
:print
-
[MESSAGE]
–MESSAGE
is required when:stop
is given on the command line!
:goto
-
{LABEL}
:lab
-
{LABEL}
Use¶ ↑
-
Create a new
SCPIsequence
object. -
Repeatedly call the
add
method to add options. -
When done adding options, call the
execute
method to run the sequence.
How mrSCPI uses SCPIsequence
¶ ↑
- For command line scripts
-
Command line arguments added to an
SCPIsequence
in order. Once all the arguments are processed, theexecute
method is called.
Public Class Methods
# File src/mrSCPI.rb, line 1030 def initialize (convertStrings=nil) # Store the instance to shorten lines referencing it @re = SCPIregexLibrary.instance # These are only passed to the session constructor @optsForNew = Set.new([:ip_address, :net_port, :net_protocol, :url]) # These are sequence options not session options @optsForSeq = Set.new([:skip_if, :next_if, :stop, :print, :goto, :lab, :var, :eval]) # How we convert strings to option values. @optValToStr = { :cmd => lambda { |x| x }, # Properties :delay_after_complete => lambda { |x| x.to_i }, :delay_before_first_read => lambda { |x| x.to_i }, :echo => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_macro_bin => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_macro_block => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_macro_ascii => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_macro_debug => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_macro_csv => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :good_std_eot => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :eol => lambda { |x| "\"#{x}\"".undump }, :eval => lambda { |x| md=x.match(@re.a(:mrs_assign)); [md[1], md[2]] }, :execute_on_cmd => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :exit_0 => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :exit_on_error => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :goto => lambda { |x| x }, :ip_address => lambda { |x| x }, # new properties :lab => lambda { |x| x }, :log_file => lambda { |x| x }, :name => lambda { |x| (x=='' ? nil : x) }, :net_port => lambda { |x| x.to_i }, :net_protocol => lambda { |x| x.sub(/^:/, '').to_sym }, :next_if => lambda { |x| md=x.match(@re.a(:mrs_branch)); [md[1], md[2], md[3]] }, :out_file => lambda { |x| x }, :print => lambda { |x| x }, :print_cmd => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :print_raw_result => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :print_result => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :read_buffer_size => lambda { |x| x.to_i }, :read_eot_sentinel => lambda { |x| ( ['', 'nil'].member?(x) ? nil : "\"#{x}\"".undump ) }, :read_max_bytes => lambda { |x| ( ['0', 'nil'].member?(x) ? nil : x.to_i ) }, :print_max_len => lambda { |x| ( ['0', 'nil'].member?(x) ? nil : x.to_i ) }, :print_debug => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :read_retry_delay => lambda { |x| x.to_i }, :read_timeout_first_byte => lambda { |x| x.to_i }, :read_timeout_next_byte => lambda { |x| x.to_i }, :result_squeeze => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_chomp => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_last_word => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_extract_block => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_split => lambda { |x| (x.nil? ? nil : x.sub(/^:/, '').to_sym) }, :result_split_arg => lambda { |x| "\"#{x}\"".undump }, :result_strip => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :result_type => lambda { |x| (x.match?(/^n/i) ? nil : x.sub(/^:/, '').to_sym) }, :scpi_prefix => lambda { |x| x }, :seq_verbose => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :skip_if => lambda { |x| md=x.match(@re.a(:mrs_branch)); [md[1], md[2], md[3]] }, :socket_close => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :socket_close_write => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :stop => lambda { |x| x }, :store_cmd => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :store_raw_results => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :store_results => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :store_named_in_var => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :store_last_in_ans => lambda { |x| !x.match?(@re.a(:o488_FALSEx)) }, :url => lambda { |x| x }, :var => lambda { |x| md=x.match?(@re.a(:mrs_assign)); [md[1], md[2]] }, :verbose => lambda { |x| x.to_i }, } @newOpts = Hash.new @seqOpts = Array.new @convertStringsP = convertStrings end
Public Instance Methods
Return true if property is valid, and nil if not – note :execute_on_cmd is not allowed
# File src/mrSCPI.rb, line 1104 def add (property, value) if @convertStringsP && (property.is_a?(String)) then property = property.sub(/^(--|:)/, '') property = property.to_sym end if (property != :execute_on_cmd) && @optValToStr.member?(property) then if @convertStringsP && (value.is_a?(String)) then value = @optValToStr[property].call(value.strip) end if @optsForNew.member?(property) then if @newOpts.member?(property) then PrintyPrintyBangBang.instance.logPrinter(2, "WARNING: Ignoring: #{property.inspect} => #{value.inspect}. Using value: #{@newOpts[property].inspect}", self) else @newOpts[property] = value end else @seqOpts.push([property, value]) end return true else return nil end end
Execute the sequence of stored parameters
# File src/mrSCPI.rb, line 1130 def execute () theSession = SCPIsession.new(@newOpts) theSession.set(:execute_on_cmd => true) labelIndex = Hash.new lookingForLab = nil skipStep = false currentLineNumber = 0 while currentLineNumber <= (@seqOpts.length-1) do (par, val) = @seqOpts[currentLineNumber] PrintyPrintyBangBang.instance.logPrinter(4, "DEBUG-4: LINE: #{currentLineNumber} : #{@seqOpts[currentLineNumber].inspect}", self) if skipStep then skipStep = false else if !(lookingForLab) || ((par == :lab) && (lookingForLab == val)) then if @optsForSeq.member?(par) then if (par == :skip_if) || (par == :next_if) then tmpLHS = theSession.expand(val[0]) tmpRHS = theSession.expand(val[2]) pred = ( val[1].match?("=") ? (tmpLHS == tmpRHS) : !!(tmpLHS.match?(tmpRHS)) ) pred = ( val[1].match?("!") ? !(pred) : pred ) skipStep = ((par == :skip_if) && pred) || ((par == :next_if) && !(pred)) elsif par == :stop then if !(val.empty?) then tmpMSG = theSession.expand(val) PrintyPrintyBangBang.instance.outPrinter(tmpMSG, newline=true) end break elsif par == :print then tmpMSG = theSession.expand(val) PrintyPrintyBangBang.instance.outPrinter(tmpMSG, newline=true) elsif par == :goto then if labelIndex.member?(val) then currentLineNumber = labelIndex[val] # Jump back else lookingForLab = val # Jump forward end next elsif par == :lab then lookingForLab = nil labelIndex[val] = currentLineNumber elsif (par == :var) || (par == :eval) then tmpVAL = theSession.expand(val[1]) if par == :eval then tmpVAL = eval(tmpVAL).to_s end theSession.variable(val[0], tmpVAL) end else tmpVal = (val.is_a?(String) ? theSession.expand(val) : val) theSession.set(par => tmpVal) end end end currentLineNumber += 1 end end