Refinements było eksperymentalnym dodatkiem do wersji 2.0, a następnie zmodyfikowane i wprowadzone na stałe w wersji 2.1. Zapewnia to sposób na uniknięcie "łatania małp" poprzez zapewnienie "sposobu na rozszerzenie klasy lokalnie".Użycie opcji Zawężenie hierarchicznie
próbowałem zastosować Refinements
do this recent question które będę uprościć sposób:
a = [[1, "a"],
[2, "b"],
[3, "c"],
[4, "d"]]
b = [[1, "AA"],
[2, "B"],
[3, "C"],
[5, "D"]]
elementu o przesunięcie i
w a
pasuje do elementu w offsecie i
w b
jeżeli:
a[i].first == b[i].first
i
a[i].last.downcase == b[i].last.downcase
Innymi słowy, dopasowanie łańcuchów jest niezależne od wielkości liter.
Problem polega na określeniu liczby elementów a
pasujących do odpowiedniego elementu z b
. Widzimy, że odpowiedź jest dwa, elementy na offsetach 1
i 2
.
Jednym ze sposobów, aby to zrobić jest małpa plastra 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
lub zamiast wykorzystać 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
Jednak chciałbym skorzystać Refinements
tak:
using M
a.zip(b).count { |ae,be| ae == be }
#=> 0
ale, jak widzisz, daje to złą odpowiedź. To dlatego, że wywołuję Array#==, a udoskonalenie nie ma zastosowania w obrębie Array
.
mogę to zrobić:
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
ale to nie to, co chcę. Chcę zrobić coś takiego:
module N
refine Array do
using M
end
end
using N
a.zip(b).count { |ae,be| ae == be }
#=> 0
ale oczywiście to nie działa.
Moje pytanie: czy istnieje sposób na udoskonalenie String
do użytku w Array
, a następnie doprecyzowanie Array
do wykorzystania w mojej metodzie?
To świetnie! Jeden szczegół: możesz rozważyć zastąpienie '! Self.zip (other) .map {| x, y | x == y} .include? false' with 'zip (other) .all? {| x, y | x == y} '. (Przypomnijmy, że 'self' jest domyślnym odbiornikiem.) –
Ach, tak, dzięki - nabrałem złego nawyku używania" ja "wszędzie, gdzie mogłoby to mieć zastosowanie. To pomoże mi zapamiętać, czy warto korzystać z niego, czy nie. Wygląda o wiele ładniej/bardziej czytelnie, bez 'self' i używania' all? '. –
Wielu Rubyists używają "self", gdy nie jest potrzebne, ponieważ wierzą, że jego pominięcie może być mylące dla czytelnika. Nie jestem w tym obozie, ale nie mogę powiedzieć, że są w błędzie. –