尝试以交互方式编写程序,该程序可以将来自命令行的输入作为表达式或诸如-的属性
irb : 3+2
Should evaluate to => 5
Attribute
irb : abc = 1
=> 1
irb : jkl(or def) = 1
=> 1
irb : abc + def
=> 2
此外,一旦用户输入空白行,就应该进行评估。
我的努力:我创建了一个attr_accessor方法,该方法遍历传递给它的* secret数组,并在每个attr上调用define_method,为每个属性创建一个实例变量getter和setter。
部分代码有效: 我在评估表达式和返回字符串值方面取得了成功。
irb:3 + 2 应该计算为=> 5
irb:是 =>正确
但是仍然坚持评估属性分配,并且无法将这些值动态存储在我的交互式irb中。低于预期结果不起作用: 属性
irb:abc = 1
=> 1
irb:def = 1
=> 1
irb:abc + def
=> 2
注意-我不想使用“ require'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
实际结果:除表达式和简单字符串外,所有其他输入的输出均为“无效表达式”。
答案 0 :(得分:0)
我相信,我已经部分解决了上述问题。现在,我可以将属性的值存储在哈希图中。我尝试通过键访问这些值,因此可以轻松存储和显示分配值,例如:
rb : x = 1
=> 1
or
rb : y = 1
但是我编写的用于评估“ x + y”的代码部分试图将其分区到运算符上,然后访问每个属性的值。 我在标有注释#faulty的代码行中做错了。由于我得到了输出 => xy
分区后我无法访问键值。 有人可以仅就这段代码提出建议吗?
解决方案:
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