评估红宝​​石中args的简便方法

时间:2015-02-16 00:39:11

标签: ruby args

我目前在ruby程序中使用以下代码来评估传递给方法的变量长度参数。该程序正在运行,但我想知道是否有一个简短的方法来写这个。 应该在我的原始描述中更具体,尝试重写Array类的Inject方法(因此诙谐的名字......)

因此,它需要能够接受最多两个args,如果给出一个块,则最少为0。

  • array.inject(:+)
  • array.inject {| output,num |输出+数字}
  • array.inject(arg,:+)
  • array.inject(arg){| output,num |输出+数字}

要处理的最困难的案例是第一个和第四个,其中1个arg可以是Fixnum或Symbol。如上所述,代码可以工作,只是想找到整理它的方法。

class Array

  def enjict(*args)

    if args.length == 2 && args[0].is_a?(Fixnum) && args[1].is_a?(Symbol)
      start, symbol = args
    elsif args.length == 1
      raise ArgumentError unless args.first.is_a?(Symbol) || args.first.is_a?(Fixnum)
      symbol = args.first if args.first.is_a?(Symbol)
      start = args.first if args.first.is_a?(Fixnum)
    else
      raise ArgumentError unless block_given?
    end

    copiedArray = dup

    start = copiedArray.shift unless start

    if block_given?
      copiedArray.each { |num| start = yield(start, num) }
    else
      copiedArray.each { |num| start = start.send(symbol, num) }
    end
    start
  end
end

2 个答案:

答案 0 :(得分:2)

可悲的事实是:它很乱,你无能为力。几乎所有Ruby实现都实现Enumerable#inject具有对解释器内部的特权访问,包括对参数的内省。 MRI,YARV,MRuby在C中实现它,在Objective-C中使用MacRuby和RubyMotion,在Java中使用XRuby和JRuby,在C#中使用Ruby.NET和IronRuby,在RPython中使用Topaz,在PIR中使用Cardinal,等等。

这是Ruby代码根本无法使用的东西。

只有Rubinius实现了它in Ruby

您可以使用类似的技巧(ab)使用以下事实:可选参数的默认参数表达式可以是任意任意复杂的Ruby表达式,并且这些表达式的局部变量成为局部变量方法。这是判断参数是否通过的常用技巧:

def inject(initial=(no_initial = true; nil), sym=(no_sym = true; nil))
  sym, initial = initial, nil if !block_given && no_sym
  # and so on …
end

答案 1 :(得分:1)

从条件来看,如何将方法参数重构为:

def enjict(start, symbol, *options, &block)
  e = proc{ raise ArgumentError if options.length > 0 && !block_given? }
  e.call

  if start.is_a?(Fixnum) && symbol.is_a?(Symbol)
    # do something you want
  else
    e.call
  end
end