На самом деле, если бы у вас не было этого комментария в середине строки, он бы просто работал:
method_a(@date > Date.today, {:param1 => 'value1', :param2 => 'value2'}) do; end
Кстати: если бы последний аргумент метода былхеш, вы можете опустить фигурные скобки, что делает его читаемым почти как аргументы в стиле Python:
method_a(@date > Date.today, :param1 => 'value1', :param2 => 'value2') do; end
Если вы используете Ruby 1.9 и у вас есть хеш, где ключи являются символами, выможно использовать новый альтернативный синтаксис хэша:
method_a(@date > Date.today, {param1: 'value1', param2: 'value2'}) do; end
Объединение двух действительно выглядит как аргументы ключевого слова:
method_a(@date > Date.today, param1: 'value1', param2: 'value2') do; end
В вашем method_a
вы могли бы значительноулучшить удобочитаемость, используя выражение охраны вместо большого гудящего выражения if
:
def method_a(condition, params={}, &block)
return method_b(params, &block) if condition
yield
end
Или наоборот, в зависимости от того, что вы считаете лучше:
def method_a(condition, params={}, &block)
return yield unless condition
method_b(params, &block)
end
Однако,это гигантский запах кода.Метод должен всегда делать одну вещь и только одну вещь. Каждый метод , который принимает логический аргумент, нарушает это правило, потому что по определению он в значительной степени делает две вещи: одну вещь, если условие истинно, и другую вещь, если условие ложно.
В исходном коде это явно очевидно, поскольку у вас есть гигантское выражение if
, окружающее весь метод, а код в двух ветвях полностью отличается.Это даже более очевидно, поскольку ветвь else
не только имеет совершенно другой код, чем ветка then
, но и полностью игнорирует аргументы, передаваемые в метод!Таким образом, метод не только ведет себя по-разному в зависимости от условия, он даже имеет различную сигнатуру !
То, что вы действительно хотите сделать, - это разделение метода на два метода.Пользователь method_a
должен знать в любом случае , каково различие между этими двумя случаями, и он должен сам поставить условное выражение.Вместо этого он мог просто вызвать правильный метод в первую очередь.Итак, я бы разделил method_a
на два:
def method_one(params={}, &block)
method_b(params, &block)
end
def method_two
yield
end
И клиент может решить, какой из них позвонить:
if @date > Date.today then
method_two(param1: 'value1', param2: 'value2')
else
method_one do
# something
end
end
Но, если вы внимательно посмотрите на method_one
,вы увидите, что все, что он делает, это просто передает свои неизмененные аргументы в method_b
.Таким образом, мы можем просто полностью избавиться от method_one
и получить от клиента прямой вызов method_b
.
То же самое касается method_two
: все, что он делает, это вызывает блок.Клиент мог бы с таким же успехом запустить код в первую очередь.
Итак, теперь код нашей библиотеки выглядит так:
# there is no spoon
Это верно!Там не осталось кода библиотеки!(За исключением method_b
, который не является частью вашего вопроса.)
И код клиента выглядит следующим образом:
if @date > Date.today then
method_b(param1: 'value1', param2: 'value2')
else
# something
end
Очень хороший пример метода, который нарушает это правило,* Module#instance_methods
в базовой библиотеке Ruby.Он сообщает вам все методы экземпляра, определенные в определенном модуле и классе, и принимает логический аргумент, который решает, будет ли этот список включать методы, унаследованные от суперклассов. Никто не может когда-либо запомнить, передать ли false
или true
. Noone .Джим Вейрих использует этот пример в своих беседах о хорошем дизайне и обычно спрашивает аудиторию, что является унаследованным случаем, а какой - непосредственным.Как правило, высокий процент ошибается.Иногда этот процент на хуже, чем просто подбрасывание монеты !
Если вы посмотрите на документацию , это очень запутанно.Я не могу никогда помнить, как обходится условное условие, мне всегда приходится искать это в документации.Что не очень полезно, потому что официальная документация , которая является частью фактического исходного кода YARV и MRI, тоже неверно !