Refinements был экспериментальным дополнением к версии 2.0, а затем изменен и сделан постоянным в версии 2.1. Это дает возможность избежать «исправления обезьян», предоставляя «способ расширить класс локально».Использование уточнений иерархически
я попытался применить Refinements
к this recent question которые я упростит таким образом:
a = [[1, "a"],
[2, "b"],
[3, "c"],
[4, "d"]]
b = [[1, "AA"],
[2, "B"],
[3, "C"],
[5, "D"]]
Элемент по смещению i
в a
соответствует элементу по смещению i
в b
если:
a[i].first == b[i].first
и
a[i].last.downcase == b[i].last.downcase
Другими словами, соответствие строк не зависит от случая.
Проблема заключается в определении количества элементов a
, соответствующих соответствующему элементу b
. Мы видим, что ответ два, элементы в смещениях 1
и 2
.
Один из способов сделать это обезьяны повязкой String#==:
class String
alias :dbl_eql :==
def ==(other)
downcase.dbl_eql(other.downcase)
end
end
a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } }
#=> 2
или вместо использования Refinements
:
module M
refine String do
alias :dbl_eql :==
def ==(other)
downcase.dbl_eql(other.downcase)
end
end
end
'a' == 'A'
#=> false (as expected)
a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } }
#=> 0 (as expected)
using M
'a' == 'A'
#=> true
a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } }
#=> 2
Однако, я хотел бы использовать Refinements
так:
using M
a.zip(b).count { |ae,be| ae == be }
#=> 0
но, как вы видите, это дает неправильный ответ. Это потому, что я вызываю Array#==, и уточнение не применяется в пределах Array
.
Я мог бы сделать это:
module N
refine Array do
def ==(other)
zip(other).all? do |ae,be|
case ae
when String
ae.downcase==be.downcase
else
ae==be
end
end
end
end
end
using N
a.zip(b).count { |ae,be| ae == be }
#=> 2
, но это не то, что я хочу. Я хочу сделать что-то вроде этого:
module N
refine Array do
using M
end
end
using N
a.zip(b).count { |ae,be| ae == be }
#=> 0
но ясно это не работает.
Мой вопрос: есть ли способ уточнить String
для использования в Array
, а затем уточнить Array
для использования в моем методе?
Это замечательно! Одна деталь: вы можете рассмотреть возможность замены '! Self.zip (other) .map {| x, y | x == y} .include? false' с 'zip (other) .all? {| x, y | x == y} '. (Напомним, что 'self' является получателем по умолчанию.) –
Ах, да, спасибо. Я приобрел плохую привычку использовать' self' везде, где он мог бы применяться. Это поможет мне вспомнить, имеет ли смысл использовать. Он выглядит намного лучше/читаем здесь без 'self' и используя' all? '. –
Многие рубисты используют 'self', когда это не нужно, потому что они считают, что его упущение может ввести в заблуждение читателя. Я не в этом лагере, но я не могу сказать, что они неправы. –