如何在Ruby中正确链接自定义方法?

时间:2014-07-08 21:11:22

标签: ruby-on-rails ruby methods method-chaining

我正在尝试为以下两种方法执行链接方法。运行此代码后,我不断收到以下输出:

#<SimpleMath:0x007fc85898ab70>% 

我的问题是:Ruby中链接方法的正确方法是什么?

这是我的代码:

class SimpleMath


    def add(a,b=0)
        a + b
        return self
    end


    def subtract(a,b=0)
         a - b
        return self
    end

end
newNumber = SimpleMath.new()
print newNumber.add(2,3).add(2)

4 个答案:

答案 0 :(得分:12)

你正试图这样做吗?

class SimpleMath
  def initialize
    @result = 0
  end

  #1 add function
  def add(val)
    @result += val
    self
  end

  #2 Subtract function
  def subtract(val)
    @result -= val
    self
  end

  def to_s
    @result
  end
end

newNumber = SimpleMath.new
p newNumber.add(2).add(2).subtract(1)

对于任意数量的参数

class SimpleMath
  def initialize
    @result = 0
  end

  #1 add function
  def add(*val)
    @result += val.inject(&:+)
    self
  end

  #2 Subtract function
  def subtract(*val)
    @result -= val.inject(&:+)
    self
  end

  def to_s
    @result
  end
end

newNumber = SimpleMath.new
p newNumber.add(1, 1).add(1, 1, 1, 1).subtract(1)

答案 1 :(得分:6)

让我们定义您的班级SimpleMath的实例:

sm = SimpleMath.new #=> #<SimpleMath:0x000001020ca820>

这里要注意三件事:

  • sm是一个变量。在Ruby中,变量由小写字母表示,可选地用下划线分隔(例如,my_var)。
  • 虽然可以在()之后添加new,但new没有参数(又名&#34;参数&#34;),那就是&#39}可选的,通常不会。
  • 如果关键字return不存在,Ruby将返回该方法执行的最后一次计算。在这里,您通常会将最后一行写为self,并且会返回。唉,重要的是,返回self,无论有没有关键字return,都不是你想要的。

在IRB中尝试以下内容:

sm.add(2) #=> #<SimpleMath:0x000001020ca820>

毫无疑问,您希望这会返回2+0 #=> 2,而是返回self,正如您在上面看到的那样,sm#<SimpleMath:0x000001020ca820>

您只需删除以下行即可解决此问题:

return self

来自addsubtract

class SimpleMath
  def add(a,b=0)
    a + b
  end

  def subtract(a,b=0)
    a - b
  end
end

现在

sm = SimpleMath.new
sm.add(2) #=> 2

但是,如果我们尝试链接另一个add,我们还会遇到另一个问题:

sm.add(2).add(2,3) #=> NoMethodError: undefined method `add' for 2:Fixnum

此消息非常明确:Fixnum是一个实例的类2没有名为add的实例方法。这是因为您为课程SimpleMath定义了该课程,而不是Fixnum

当Ruby执行sm.add(2).add(3,4)时,它首先计算sm.add(2) #=> 2,这会将表达式缩减为2.add(3,4)。然后,它尝试将方法add(带有两个参数)发送到2,但发现类2.class #=> Fixnum没有实例方法add;因此例外。

我们可以通过为类Fixnum定义这些方法来纠正错误:

class Fixnum
  def add(a,b=0)
    a + b
  end

  def subtract(a,b=0)
    a - b
  end
end

您可以通过运行:

确认已将这些方法添加到Fixnum类中
Fixnum.instance_methods.sort

现在,另一个问题是:

sm = Fixnum.new #=> NoMethodError: undefined method `new' for Fixnum:Class

哦,我的,班级Fixnum没有new方法!这是因为Fixnum的实例是整数,无法创建。您可以轻松确认整数是Fixnum的实例:

72.class #=> Fixnum
-3.class #=> Fixnum

因此我们可以通过将add方法发送到任何 Fixnum实例来调用{<1}}方法:

72.add(2) #=> 2
-3.add(2) #=> 2

现在让我们尝试链接add操作:

72.add(2).add(3,4)       #=> 7
72.add(2000000).add(3,4) #=> 7

没有例外,但没有链接。解决这个问题的方法是再次改变方法:

class Fixnum
  def add(b=0)
    puts "in add, self = #{self}, b = #{b}"
    self + b
  end

  def subtract(b=0)
    puts "in subtract, self = #{self}, b = #{b}"
    self - b
  end
end

我已经在每个方法中添加了puts语句,以防需要更多调试。当代码正常运行时,我们会删除它们。我们来测试一下:

2.add(3)                    #=> 5
  in add, self = 2, b = 3
5.add                       #=> 5
  in add, self = 5, b = 0
5.add(7)                    #=> 12
  in add, self = 5, b = 7
2.add(3).add.add(7)         #=> 12
  in add, self = 2, b = 3
  in add, self = 5, b = 0
  in add, self = 5, b = 7

2.subtract(5)               #=> -3
  in subtract, self = 2, b = 5
-3.subtract                 #=> -3
  in subtract, self = -3, b = 0
2.subtract(5).subtract      #=> -3
  in subtract, self = 2, b = 5
  in subtract, self = -3, b = 0

2.add(3).subtract(5).add(7) #=>  7
  in add, self = 2, b = 3
  in subtract, self = 5, b = 5
  in add, self = 0, b = 7

成功!得到它?

答案 2 :(得分:1)

这个家伙(tjackiw.tumblr.com)使用这个作为面试问题,并提供了一个非常干净的方式,如何&amp;为什么正确的答案类似于以下内容:

class Interpreter

  def initialize(&block)
    instance_eval(&block)
  end

  def at(time)
    @time = time
    self
  end

  def when(date)
    @date = date
    self
  end

  def we(*people)
    @people = people
    self
  end

  def going(where)
    @where = where
    self
  end

  def output
    [@people.join(' and '), "are going", @where, @date, "at", @time].join(' ')
  end

end

答案 3 :(得分:1)

另一种方法是通过chainable_methods gem构建管道。

Described in the article

require 'chainable_methods'

module SimpleMath
  include ChainableMethods

  def add(a, b=0)
    a + b
  end

  def subtract(a, b=0)
    a - b    
  end
end

SimpleMath.
  chain_from(5).
  add(5).
  add(5).
  subtract(3).
  unwrap