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

Use

How mrSCPI uses SCPIsequence

Public Class Methods

new(convertStrings=nil) click to toggle source
# 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

add(property, value) click to toggle source

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() click to toggle source

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