How can I create a basic "English calculator" in Ruby?

So, I am now training in Ruby on the excellent CodeWars website and have run into a problem that is slightly above my level, but feels that it can really help my coding development if I can look at the answer and push it a little to the brain. Type of transaction with a missing type of relationship.

The problem is how to build a Calc class to achieve the following results:

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

A class should deal only with one-bit inputs with zero-nine and with operators + - * /, and the format will always be a chain of three methods, as you see above (for example, the number operator number).

I would like to read some of your decisions, and if it bothers you, the thought processes that you went through solving this. Thank!

+3
source share
4 answers

Assuming the methods will not be used in an invalid way:

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
source

How about this?

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
+1
source

, :

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 reset .

+1

, #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

. , .

0

All Articles