Istnieje całkiem dobra dokumentacja aktualnej implementacji udoskonaleń w ruby tutaj: http://ruby-doc.org//core-2.2.0/doc/syntax/refinements_rdoc.html, , ale są pewne dziwne przypadki narożne.Subtelności subtelności rubinu
Po pierwsze, include module
jest ortogonalna do using module
(jedna zawiera metodę instancji modułu, a druga aktywuje udoskonalenie). Ale jest też pewna sztuczka, aby zawrzeć sam moduł udoskonalania, zobacz Better way to turn a ruby class into a module than using refinements?.
def to_module(klass)
Module.new do
#note that we return the refinement module itself here
return refine(klass) {
yield if block_given?
}
end
end
class Base
def foo
"foo"
end
end
class Receiver
include to_module(Base) {
def foo
"refined " + super
end
}
end
Receiver.new.foo #=> "refined foo"
dziwo ten moduł dystynkcja nie może być używany z using
!
m=to_module(Base) {}
m.class #=> Module
using m
#=>TypeError: wrong argument type Class (expected Module)
Wykorzystanie tylko pracy w module otaczającym modułów udoskonalania. Po drugie, chciałem wykorzystać powyższy trik wydajności, aby móc przekazać Proc do udoskonalenia (nawet poprzez to, że akceptuje tylko blok), bez uciekania się do konwersji Proc z powrotem do źródła, jak w https://www.new-bamboo.co.uk/blog/2014/02/05/refinements-under-the-knife/. Ale używając yield
jak na przykład obejmować nie działa:
def ref_module1(klass)
Module.new do
refine(klass) {
yield
}
end
end
class Receiver1
using ref_module1(Base) {
def foo
"refined " + super
end
}
def bar
Base.new.foo
end
end
Receiver1.new.bar #=> NoMethodError: super: no superclass method `foo'
Widzimy, że Receiver1 nadal korzystać Bar foo, a nie sposób wyrafinowany. howewer możemy użyć module_eval
zamiast:
def ref_module2(klass,&b)
Module.new do
refine(klass) {
module_eval(&b)
}
end
end
class Receiver2
using ref_module2(Base) {
def foo
"refined " + super
end
}
def bar
Base.new.foo
end
end
Receiver2.new.bar #=> "refined foo"
ja nie bardzo rozumiem dlaczego module_eval
pracuje tutaj, a nie metodę yield
. Wewnątrz bloku udoskonalania, "default_definee" jest modułem udokładniania, więc module_eval
, który umieszcza "default_definee" na self
= "moduł udokładniania", nie powinien mieć na nie wpływu. I rzeczywiście w przykładzie "uwzględnij" na samym początku otrzymuję taki sam wynik, gdy używam module_eval
lub bezpośrednio yield
.
Czy ktoś może wyjaśnić to zachowanie?
Świetne pytanie. Mam nadzieję, że otrzymasz równie dobre odpowiedzi. –