=begin
common class for parsing switches in ruby
=end
class SwitchObj
attr_reader :type,
:default_value,
:code_block,
:comment
def initialize(type, variable, default_value, code_block, comment, args)
@variable = variable
@type = type
@default_value = default_value
@code_block = code_block
@comment = comment
@args = args
@required = args[:required]
@set = false
end
def usage
if type == TrueClass
# copy how cnsim does true false plusargs
if @default_value
string = “(-#{@variable})/-no_#{@variable} "
else
string = “-#{@variable}/(-no_#{@variable})”
end
else
string = “-#{@variable} <?> default "#{@default_value}".”
end
string += " # #{@comment}”
if @required
string += " (required)";
end
string += “\n”
return string
end
# return true is switch matches this plusarg
def find?(switch, value)
if switch.instance_of? Symbol
switch = switch.to_s
end
found = false
#print “input #{switch} plusarg #{@variable}\n”
if switch == @variable
found = self
end
return found
end
# set plusarg to a new value
def set!(env_obj, value)
@set = true
if type == Fixnum # convert param from String to Fixnum to match type
if value.instance_of? String
if value =~ /^0x/
value = value.hex
else
value = value.to_i
end
end
elsif type == Range
if value =~ /^\d+$/ # convert 10 to 10…10
value = value.to_i…value.to_i
else # convert “10…30” into range
value = value.split(‘…’).inject { |s,e| s.to_i…e.to_i }
end
end
#print “found range here val is #{value} type #{value.class}\n”
@code_block.call(env_obj, value)
end
def complain_need_to_be_set?
if @required && ! @set
return true
end
return false
end
end
THIS IS A GENERIC PLUSARG PARSER THAT CAN BE USED ANYWHEHRE!!!#############
=begin
here is an example of creating switches
:required => true means this switch is required
:default! => “comment” all remain args become the default value. you can add a code block to parse filter things yourself
class MySwitches < Switches
def self.init_all_variables
copy_super
create_variable TrueClass, :cnsim, nil, “follows cnsim format as closely as possible”, required: true
create_variable Fixnum, :insts , false, “X number of instructions per JSON obj. use this if memory footprint is large”
create_variable String, :avpl, nil, “input avplist”
end
init_all_variables
def initialize(args=Hash.new)
# process default args
default!(“plusargs”) do |current|
if current =~ /^+/ # plusargs are okay
return current
else
raise “unexpected plusargs #{current}”
end
end
current + “whatever” # show you can change args
super(args)
end
end
multiple ways to set args
1. plusargs
Switches(“-avplist file”)
2. hash
Switches(avplist: “file”)
on TrueClass (like debug) you can set and unset using the following
-debug
-no_debug
=end
class Switches
attr_reader :defaults # any parameter not part of switch are aggregated here.
# e.g generate_fasm …
########### CLASS METHODS ##############################
# can’t put the code below in helper because I need “self” to known it is class Switches
@@plusargs = Hash.new # contains a hash of hash
# first level hash is the object name
# second level hash is code block which sets the variable
# the reason we need first level is because all Env parser inherent from
# this class and we don’t want conflicts
# if we don’t do this than Switches will have all the plusargs of its children
@@plusargs[self.to_s] = Hash.new
def self.create_variable(type, variable, default_value, comment, args=Hash.new)
if ! @@plusargs[self.to_s]
raise “need to run copy_super before create_variable”
end
if ! variable.instance_of? Symbol
raise “create variable must be of Symbol. it is #{variable}, type #{variable.class}”
end
# make it class variable
variable_string = variable.to_s
variable_class = “@” + variable_string
# create setter like avplist!
# for getter create avplist and avplist? the “?” is better for Boolean
#print “all methods #{methods.join(”,“)}\n”
method_getter = (variable_string).to_sym
send :define_method , method_getter do
self.instance_variable_get(variable_class)
end
method_getter = (variable_string + “?”).to_sym
send :define_method , method_getter do
self.instance_variable_get(variable_class)
end
method_setter = (variable_string + “!”).to_sym
send :define_method, method_setter do |new_value|
self.instance_variable_set(variable_class, new_value)
end
setter_code_block = lambda do |env_obj, set_value|
#print “setting:self #{env_obj.class} variable #{variable_class} value #{set_value}\n”
env_obj.instance_variable_set(variable_class, set_value)
#print “after avplist is #{env_obj.avplist}\n”
end
@@plusargs[self.to_s][variable_string] = SwitchObj.new(type, variable_string, default_value, setter_code_block, comment, args)
end
def self.copy_super
# copy over all variables from parent class
if self.superclass != Object
self.superclass.copy_super
@@plusargs[self.to_s] = @@plusargs[self.superclass.to_s].clone
end
end
def initialize(args=Hash.new)
# so current object has all parent class methods
if ! @@plusargs[class_name]
raise “need to run copy_super first”
end
@@plusargs[class_name].each do |variable_string, plusarg|
variable_class = “@” + variable_string
#print “set #{variable_class} to #{plusarg.default_value}. type #{plusarg.default_value.class}\n”
self.instance_variable_set(variable_class, plusarg.default_value)
end
@defaults = []
@args = args
parse(args)
end
# for instance object to access @@plusargs
def class_name
self.class.to_s
end
# everything not a plusarg becomes this
def default!(comment, &block)
#print “accept default is true\n”
@accept_default = true
@default_comment = comment
if block_given?
@parse_default_block = block
end
end
def check_required_args
@@plusargs[class_name].each do |name, current_plusarg|
#print “check required args #{name}\n”;
if current_plusarg.complain_need_to_be_set?
puts “the args below is required\n#{current_plusarg.usage}”
exit
end
end
end
# can parse either
# String like “-avplist file”
# Hash like avplist: “file”
def parse(args)
usage if args.empty?
if args.instance_of? Array
#print “arg is #{args}\n”
current_plusarg = nil
args.each do |current_arg|
#print “current_arg is #{current_arg}\n”
if current_arg =~ /^\s*
/
e
l
s
i
f
c
u
r
r
e
n
t
a
r
g
=
/
−
(
§
+
)
/ elsifcurrent
a
rg= /
−
(§+)/ # switch
switch =
1
i
f
(
c
u
r
r
e
n
t
a
r
g
=
/
−
n
o
(
§
+
)
1 if(current
a
rg= /
−
no
(
§+)/) || (current_arg =~ /^-no-(\S+)$/) # boolean, support both -no_blah or -no-blah version
current_plusarg = find_plusarg($1, current_arg)
if current_plusarg.type == TrueClass
current_plusarg.set!(self, false)
current_plusarg = nil # finish
else
raise “unexpected switch #{current_arg}. must be Boolean it is #{current_plusarg.type}”
end
else
#print “trying to find switch #{switch}\n”
current_plusarg = find_plusarg(switch, current_arg)
if current_plusarg.type == TrueClass
current_plusarg.set!(self, true)
current_plusarg = nil # finish
else
current_plusarg = find_plusarg(switch, current_arg)
# need to still get the value
end
end
elsif current_plusarg # switch with parameter
#print “set current_arg #{current_arg}. class #{current_arg.class}. plusarg #{current_plusarg.class}\n”
current_plusarg.set!(self, current_arg)
current_plusarg = nil # finish switch with parameter
else
# just parameter without association to plusargs
#print “parsing #{current_arg} accept default is #{@accept_default}\n”
if @accept_default
if @parse_default_block
current_arg = @parse_default_block.call(current_arg)
end
@defaults.push current_arg
else
print “unexpected input #{current_arg}\n”
usage
end
end
end
elsif args.instance_of? Hash
args.each do |switch, value|
plusarg = find_plusargs(switch, switch)
plusarg.set(self, value)
end
else
raise “unexpected args class. arg is #{args}. type #{args.class}. must be String or Hash”
end
check_required_args
end
def find_plusarg(switch, orig_switch_string)
# foreach token (which is switch, check against @plusargs)
found_plusarg = false
@@plusargs[class_name].each do |name, current_plusarg|
found_plusarg = current_plusarg.find?(switch, orig_switch_string)
break if found_plusarg
end
#print “afterwards avplist is #{@avplist}\n”
if ! found_plusarg
print “can’t find switch #{orig_switch_string}\n”
usage
end
return found_plusarg
end
def usage
string = “”
@@plusargs[class_name].each do |name, current_plusarg|
string += current_plusarg.usage
end
if @accept_default
string += “ … ##{@default_comment}\n”
end
print “#{$0}\n”
print string
exit
end
# dump the original args for debug
def to_s
string = “”
if @rng
string += “seed: #{@rng.seed}\n”
end
string += "switch: " + @args.to_s
end
end
麻烦你为我详细解析这段代码,需要逐行解析,且我不太懂ruby语法因此除了代码解析你还需要顺便给我讲讲语法
最新发布