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

时间:2019-08-02 23:38:38

标签: ruby 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方法,该方法遍历传递给它的* 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

实际结果:除表达式和简单字符串外,所有其他输入的输出均为“无效表达式”。

1 个答案:

答案 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