试图交互方式编写一个程序,该程序可以从命令行中以表达式或属性为诸如 -
之类的属性irb : 3+2
Should evaluate to => 5
Attribute
irb : abc = 1
=> 1
irb : jkl(or def) = 1
=> 1
irb : abc + def
=> 2
也应在用户输入空白行后进行评估。
我的努力:我创建了一个方法attr_accessor,该方法通过 *秘密传递的数组来迭代,并在每个attr上调用define_method,为每个属性创建一个实例变量getter和setter。
代码工作的一部分:我成功地评估了表达式和返回字符串值。
irb:3 2应评估为=> 5
irb:是的=> true
,但仍然坚持对属性的分配评估,并且无法在我的交互式IRB中动态存储这些值。低于预期的结果不起作用:属性
irb:abc = 1
=> 1
irb:def = 1
=> 1
irb:ABC def
=> 2
注意 - 我不想使用"需要'irb'"或" require'pry'。
我的解决方案:
class Demo
def self.attr_accessor(*secret)
secret.each do |attr|
define_method(attr) { instance_variable_get("@#{attr}") }
define_method("#{attr}=") { |val| instance_variable_set("@#{attr}", val) }
end
get_binding
end
def self.method_new(input)
@object = attr_accessor(input)
end
def self.method(secret)
@object = Regexp.new(/A[d+-*/=. ]+z/).match(secret.to_s) ? eval(secret) : "Invalid expression"
get_binding
end
def self.simple_method(secret)
@object = secret
get_binding
end
def self.get_binding
binding
end
end
user_input = ''
until user_input == 'q' do
user_input = gets.chomp
if user_input =~ /^.*=.*$/
b2 = Demo.method_new(*user_input)
puts eval('@object', b2)
elsif user_input =~ /A[d+-*/=. ]+z/
b3 = Demo.method(user_input)
puts eval('@object', b3)
else
b4 = Demo.simple_method(user_input)
puts eval('@object', b4)
end
end
预期结果:
irb : 3+2
#note - each result evaluated after user enters blank line
Should evaluate to => 5
Attributes ---
irb : abc = 1
#note - each result evaluated after user enters blank line
=> 1
irb : def = 1
#note - each result evaluated after user enters blank line
=> 1
irb : abc + def( or jkl)
#note - each result evaluated after user enters blank line
=> 2
实际结果:除表达式和简单字符串外,所有其他输入的输出是"无效的表达式"。
我相信,我部分地解决了上述问题的解决方案。现在,我可以将属性值存储在哈希地图中。我尝试通过键访问这些值,因此可以轻松地存储和显示分配的值:
rb : x = 1
=> 1
or
rb : y = 1
但是,我为评估" X y"编写的代码部分试图将其划分在操作员上,然后访问每个属性的值。我在标有评论#faulty的代码行中做错了什么。因此,我的输出像=> x y
分区后我无法访问钥匙值。有人可以单独提供建议吗?
解决方案:
class Module
def initialize(args)
args.each do |key, value|
# the instance_variable_set method dynamically creates instance variables
# with the key as the name and value as the assigned value
instance_variable_set("@#{key}",value)
# define_singleton_method creates a getter method with the same name as the
# key and inside the block you define what it returns
define_singleton_method(key){ value }
#defining the setter method
define_singleton_method("#{key}=") do |val|
instance_variable_set("@#{key}", val)
end
end
end
end
class Demo
#var :bar
def self.eval_binary_expr(expr)
if expr =~ /^.*=.*$/
obj = Module.new(:name => expr)
@object1 = eval(obj.name)
get_binding
else
obj = Module.new(:name => expr)
l_operand, op, r_operand = (obj.name).partition(%r{[/*+-]}) #Faulty
if op.empty?
raise ArgumentError, "Invalid operation or no operation in expression: #{expr}"
end
case op
when '/'; then @object1 = (l_operand / r_operand); get_binding
when '*'; then @object1 = (l_operand * r_operand); get_binding
when '+'; then @object1 = (l_operand + r_operand); get_binding
when '-'; then @object1 = (l_operand - r_operand); get_binding
end
end
end
def self.method(secret)
@object2 = Regexp.new(/A[d+-*/=. ]+z/).match(secret.to_s) ? eval(secret) : "Invalid expression"
get_binding
end
def self.new_method(secret)
@object3 = secret
get_binding
end
def self.get_binding
binding
end
end
user_input = ''
until user_input == 'q' do
user_input = gets.chomp
if user_input =~ /A[w+-*/=. ]+z/
b2 = Demo.eval_binary_expr(user_input)
puts eval('@object1', b2)
elsif user_input =~ /A[d+-*/=. ]+z/
b3 = Demo.method(user_input)
puts eval('@object2', b3)
else
b4 = Demo.new_method(user_input)
puts eval('@object3', b4)
end
end