我们如何使用以下绑定方法复制IRB行为



试图交互方式编写一个程序,该程序可以从命令行中以表达式或属性为诸如 -

之类的属性
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

最新更新