Короткий ручной способ оценки аргументов в ruby

В настоящее время я использую следующий код в программе ruby ​​для оценки аргументов переменной длины, которые передаются методу. Программа работает, однако мне интересно, есть ли короткий способ написать это. Мое первоначальное описание должно было быть более конкретным, пытаясь переписать метод Inject для класса Array (отсюда и остроумное название...)

Поэтому он должен иметь возможность принимать максимум два аргумента и минимум 0, если задан блок.

  • массив.inject(:+)
  • array.inject{ |выход, число| вывод + число }
  • array.inject(аргумент, :+)
  • array.inject(arg) { |выход, число| вывод + число }

Наиболее сложными для обработки являются первый и четвертый случаи, когда 1 аргумент может быть либо 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

person Phil Brockwell    schedule 16.02.2015    source источник
comment
Единственный способ, который я вижу, - это создание нескольких методов для разных аргументов.   -  person Ismael    schedule 16.02.2015
comment
Можете ли вы сделать короткую заметку о том, что вы пытаетесь сделать с помощью метода или о цели метода?   -  person Jikku Jose    schedule 16.02.2015
comment
start = copiedArray.shift выполняется, если start ранее не было присвоено значение. Это ваше намерение? Вы получите ошибку аргумента, если block_given => false и symbol ранее не были присвоены значения. Пожалуйста, объясни. copiedArray = dup предполагает, что этот код находится внутри класса. Есть ли что-то, что нам нужно знать об этом классе? В более общем случае было бы полезно понять, чего вы пытаетесь достичь. Я вижу способы почистить код, но нужна дополнительная информация.   -  person Cary Swoveland    schedule 16.02.2015
comment
Попытка переписать метод Inject; обновленный вопрос   -  person Phil Brockwell    schedule 16.02.2015


Ответы (2)


Печальная правда такова: это грязно, и вы ничего не можете с этим поделать. Почти все реализации Ruby реализуют Enumerable#inject с привилегированным доступом к внутренним компонентам интерпретатора, включая самоанализ аргументов. MRI, YARV, MRuby реализуют его на C, MacRuby и RubyMotion на Objective-C, XRuby и JRuby на Java, Ruby.NET и IronRuby на C#, Topaz на RPython, Cardinal на PIR и так далее.

Это то, что просто недоступно для кода Ruby.

Только Rubinius реализует его в 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
person Jörg W Mittag    schedule 16.02.2015

Судя по условиям, как насчет рефакторинга ваших аргументов метода:

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
person Finks    schedule 16.02.2015
comment
Это требует 2 или более аргументов, тогда как поведение, которое пытается воспроизвести OP, принимает 0, 1 или 2, но не более 2 аргументов. - person Jörg W Mittag; 16.02.2015