Изящный способ вводящих утку строк, символов и массивов?

Просто удалите эти переполнение: автоматический часть и близко внутреннее отделение правильно с закрывающим тэгом, тот путь это работает в IE6, IE7, Firefox 3 и Opera =>, вероятно, все браузеры.

5
задан Bryan Larsen 25 August 2009 в 19:36
поделиться

7 ответов

Как насчет того, чтобы рассматривать их все как массивы ? Поведение, которое вы хотите для String s, такое же, как для Array , содержащего только эту String :

def foo(obj, arg)
  [*arg].each { |method| obj.send(method) }
end

[* arg] работает, потому что оператор splat ( * ) превращает отдельный элемент в себя или массив во встроенный список его элементов.

Позже

Это в основном просто синтаксически улучшенная версия или ответ Арно , хотя есть небольшие различия, если вы передадите Array , содержащий другие Array .

Еще позже

Там дополнительная разница, связанная с возвращаемым значением foo . Если вы вызовете foo (bar,: baz) , вы можете быть удивлены, если получите обратно [baz] . Чтобы решить эту проблему, вы можете добавить Kestrel :

def foo(obj, arg)
  returning(arg) do |args|
    [*args].each { |method| obj.send(method) }
  end
end

, который всегда будет возвращать переданный arg . Или вы можете сделать return (obj) , чтобы вы могли связать вызовы с foo . Вам решать, какое поведение возвращаемого значения вы хотите.

6
ответ дан 13 December 2019 в 22:12
поделиться

Поскольку Array и String оба являются Enumerables , нет элегантного способа сказать «вещь, которая является Enumberable, но не String », по крайней мере, так, как обсуждается.

Я бы сделал тип утки для Enumerable ( Responds_to?: [] ), а затем использовал case , например так:

def foo(obj, arg)
  if arg.respond_to?(:[])
    case arg
    when String then obj.send(arg)
    else arg.each { |method_name| obj.send(method_name) }
    end
  end
end

или даже более чистый:

def foo(obj, arg)
  case arg
  when String then obj.send(arg)
  when Enumerable then arg.each { |method| obj.send(method) }
  else nil
  end
end
1
ответ дан 13 December 2019 в 22:12
поделиться

Используйте Marshal для сериализации ваших объектов перед их отправкой.

0
ответ дан 13 December 2019 в 22:12
поделиться

Допустим, ваша функция называется func

Я бы сделал массив из параметров с помощью

def func(param)
  a = Array.new
  a << param
  a.flatten!
  func_array(a)
end

. В итоге вы реализуете свою функцию func_array только для массивов

с помощью func (" привет, мир ") вы получите a.flatten! => ["привет, мир"] с func (["привет", "мир"]) вы получите a.flatten! => ["привет", "мир"]

1
ответ дан 13 December 2019 в 22:12
поделиться

Если вы не хотите использовать monkeypatch, просто перед отправкой переместите список в соответствующую строку. Если вы не против патчинга обезьян или наследования, но хотите сохранить ту же сигнатуру метода:

class ToBePatched
    alias_method :__old_takes_a_string, :takes_a_string

    #since the old method wanted only a string, check for a string and call the old method
    # otherwise do your business with the map on things that respond to a map.
    def takes_a_string( string_or_mappable )
        return __old_takes_a_string( string_or_mappable ) if String === string_or_mappable
        raise ArgumentError unless string_or_mappable.responds_to?( :map )
        # do whatever you wish to do
    end
end
0
ответ дан 13 December 2019 в 22:12
поделиться

Возможно, вопрос был недостаточно ясным, но ночной сон показал мне два чистых пути чтобы ответить на этот вопрос.

1: to_sym доступен для String и Symbol и должен быть доступен для всего, что крякает, как строка.

if arg.respond_to? :to_sym
    obj.send(arg, ...)
else
    # do array stuff
end

2: отправить throws TypeError при передаче массива.

begin
  obj.send(arg, ...)
rescue TypeError
  # do array stuff
end

Мне особенно нравится №2. Я очень сомневаюсь, что кто-либо из пользователей старого API ожидает, что TypeError будет вызван этим методом ...

to_sym доступен для String и Symbol и должен быть доступен для всего, что крякает, как строка.

if arg.respond_to? :to_sym
    obj.send(arg, ...)
else
    # do array stuff
end

2: send throws TypeError ] при передаче массива.

begin
  obj.send(arg, ...)
rescue TypeError
  # do array stuff
end

Мне особенно нравится №2. Я очень сомневаюсь, что кто-либо из пользователей старого API ожидает, что TypeError будет вызван этим методом ...

to_sym доступен для String и Symbol и должен быть доступен для всего, что крякает, как строка.

if arg.respond_to? :to_sym
    obj.send(arg, ...)
else
    # do array stuff
end

2: send throws TypeError ] при передаче массива.

begin
  obj.send(arg, ...)
rescue TypeError
  # do array stuff
end

Мне особенно нравится №2. Я очень сомневаюсь, что кто-либо из пользователей старого API ожидает, что TypeError будет вызван этим методом ...

0
ответ дан 13 December 2019 в 22:12
поделиться

Они также возникают время от времени, когда я кодирую. Вы могли бы подумать о переносе второго оператора using в другую функцию?

просто добавьте метод, обрабатывающий параметр типа массива. Это немного другое поведение, поэтому может иметь смысл дополнительный метод.

0
ответ дан 13 December 2019 в 22:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: