我如何在Ruby中构建一个基本的“英语计算器”?

时间:2014-02-13 14:03:37

标签: ruby oop method-chaining

所以我目前正在使用Ruby在优秀的CodeWars网站上进行培训,并且遇到了一个比我的水平高一点的问题,但如果我能看一下这个问题,我觉得它真的可以帮助我编写代码。 /答案并将它推到我的大脑周围一点。一种缺失的链接类型交易。

问题是如何构建Calc类以实现以下结果:

class Calc
end

Calc.new.one.plus.two             # Should return 3
Calc.new.five.minus.six           # Should return -1
Calc.new.seven.times.two          # Should return 14
Calc.new.nine.divided_by.three    # Should return 3

该类只需要处理单个数字输入零 - 九和+ - * /运算符,并且格式将始终是如上所示的3种方法的链(即数字运算符号)。

我很乐意阅读您的一些解决方案,如果您感到烦恼,那么您在解决它时会遇到的思考过程。谢谢!

4 个答案:

答案 0 :(得分:1)

假设不会以无效的方式使用这些方法:

class Calc
  def self.operand name, v
    define_method(name) do
      @operator ? @operand.send(@operator, v) : (@operand = v; self)
    end
  end
  def self.operator name, v
    define_method(name) do
      @operator = v; self
    end
  end

  operand :one, 1
  operand :two, 2
  ...
  operator :plus, :+
  operator :minus, :-
  ...
end

答案 1 :(得分:1)

这个怎么样?

class Calc
  attr_accessor :result, :last_operator

  def initialize(result=0)
   @result = result
  end

  OPERATORS = {
    :plus => :+, :minus => :-, :times => :*, :divided_by => :/
  }

  OPERANDS = [ :zero, :one, :two, :three, :four, :five, :six, :seven, :eight, :nine, :ten, :eleven, :twelve ] 

  def method_missing(m, *args, &block)
    if OPERATORS.include?(m.to_sym)
      @last_operator = m.to_sym
      return self 
    elsif OPERANDS.include?(m.to_sym)
      if @last_operator.nil?
        @result = OPERANDS.index(m.to_sym)
        return self
      end
      @result = eval("#{@result} #{OPERATORS[@last_operator]} #{OPERANDS.index(m.to_sym)}")
      return @last_operator.nil? ? self : @result
    end

    super
  end
end


[20] pry(main)> Calc.new.three.times.seven
=> 21
[21] pry(main)> Calc.new.twelve.divided_by.two
=> 6

答案 2 :(得分:1)

不是最佳解决方案,但符合要求:

class Calc
  ENGLISH_TO_OP = Hash[%i{zero one two three four five six seven eight nine}
    .each_with_index.to_a].merge(plus: :+, minus: :-, times: :*, divided_by: :/)

  def method_missing(m)
    if s = ENGLISH_TO_OP[m]
      (@cmd ||= []) << s
      return @cmd[0].send(*@cmd[1..2]) if @cmd.size == 3
      self
    else
      super
    end
  end
end

允许:

2.1.0 :015 > Calc.new.seven.times.two
 => 14 
2.1.0 :016 > Calc.new.nine.divided_by.three
 => 3 
2.1.0 :017 > Calc.new.five.minus.six
 => -1 
2.1.0 :018 > Calc.new.one.plus.two
 => 3 

我不想写很多代码,所以method_missing必须要定义方法,即使它可能有问题,因此我倾向于避免它。哈希查找适用于指定的操作数和操作,each_with_index可以填充值。在条件中将查找值分配给s只是懒惰。最后,我可以在初始值设定项中初始化@cmd,但这样的代码更少,并且可以防止@cmd稍后通过其他方法重置为nil。

答案 3 :(得分:0)

以下是使用#method_missing的另一个技巧:

class Calc
    attr_reader :val
    def initialize
      # operand hash
      @hsh_num = {one: 1,two: 2, three: 3,four: 4,five: 5,six: 6}
      # operator hash
      @hsh_op = {plus: '+', minus: '-',times: '*',divided_by: '/'}
    end
    def method_missing(symbol)
      if @hsh_num[symbol]
        @val = @meth.is_a?(Method) ? @meth.call(@hsh_num[symbol]) : @hsh_num[symbol]
      end
      if @hsh_op[symbol]
        @meth = @val.method(@hsh_op[symbol])
      end
      self
    end
end

# I just added one more method val, to get the last output.
# a bit change I did.
Calc.new.one.plus.two.plus.two.val # => 3
Calc.new.five.minus.six.val # => -1

我没有为所有人实施它。但是,就你的情况而言,你可以从中得到一个想法。