File: C:/Ruby27-x64/share/ri/2.7.0/system/syntax/page-refinements_rdoc.ri
U:RDoc::TopLevel[ i I"syntax/refinements.rdoc:ETcRDoc::Parser::Simpleo:RDoc::Markup::Document:@parts[gS:RDoc::Markup::Heading:
leveli: textI"Refinements;To:RDoc::Markup::BlankLine o:RDoc::Markup::Paragraph;[ I"RDue to Ruby's open classes you can redefine or add functionality to existing ;TI"Qclasses. This is called a "monkey patch". Unfortunately the scope of such ;TI"Lchanges is global. All users of the monkey-patched class see the same ;TI"Nchanges. This can cause unintended side-effects or breakage of programs.;T@
o;
;[I"ORefinements are designed to reduce the impact of monkey patching on other ;TI"Ousers of the monkey-patched class. Refinements provide a way to extend a ;TI"Eclass locally. Refinements can modify both classes and modules.;T@
o;
;[I" Here is a basic refinement:;T@
o:RDoc::Markup::Verbatim;[I"
class C
;TI" def foo
;TI" puts "C#foo"
;TI" end
;TI" end
;TI"
;TI"module M
;TI" refine C do
;TI" def foo
;TI" puts "C#foo in M"
;TI"
end
;TI" end
;TI" end
;T:@format0o;
;[I"PFirst, a class +C+ is defined. Next a refinement for +C+ is created using ;TI"Module#refine.;T@
o;
;[I"LModule#refine creates an anonymous module that contains the changes or ;TI"Srefinements to the class (+C+ in the example). +self+ in the refine block is ;TI"9this anonymous module similar to Module#module_eval.;T@
o;
;[I")Activate the refinement with #using:;T@
o;;[
I"
using M
;TI"
;TI"c = C.new
;TI"
;TI"!c.foo # prints "C#foo in M"
;T;0S; ;
i;I"
Scope;T@
o;
;[ I"PYou may activate refinements at top-level, and inside classes and modules. ;TI"RYou may not activate refinements in method scope. Refinements are activated ;TI"Runtil the end of the current class or module definition, or until the end of ;TI"/the current file if used at the top-level.;T@
o;
;[I"QYou may activate refinements in a string passed to Kernel#eval. Refinements ;TI"1are active until the end of the eval string.;T@
o;
;[I"SRefinements are lexical in scope. Refinements are only active within a scope ;TI"Xafter the call to +using+. Any code before the +using+ statement will not have the ;TI"refinement activated.;T@
o;
;[I"SWhen control is transferred outside the scope, the refinement is deactivated. ;TI"TThis means that if you require or load a file or call a method that is defined ;TI"Boutside the current scope the refinement will be deactivated:;T@
o;;[I"
class C
;TI" end
;TI"
;TI"module M
;TI" refine C do
;TI" def foo
;TI" puts "C#foo in M"
;TI"
end
;TI" end
;TI" end
;TI"
;TI"def call_foo(x)
;TI"
x.foo
;TI" end
;TI"
;TI"
using M
;TI"
;TI"x = C.new
;TI"'x.foo # prints "C#foo in M"
;TI"*call_foo(x) #=> raises NoMethodError
;T;0o;
;[I"TIf a method is defined in a scope where a refinement is active, the refinement ;TI"Rwill be active when the method is called. This example spans multiple files:;T@
o;
;[I"
c.rb:;T@
o;;[I"
class C
;TI" end
;T;0o;
;[I"
m.rb:;T@
o;;[I"require "c"
;TI"
;TI"module M
;TI" refine C do
;TI" def foo
;TI" puts "C#foo in M"
;TI"
end
;TI" end
;TI" end
;T;0o;
;[I"m_user.rb:;T@
o;;[I"require "m"
;TI"
;TI"
using M
;TI"
;TI"class MUser
;TI" def call_foo(x)
;TI" x.foo
;TI" end
;TI" end
;T;0o;
;[I"
main.rb:;T@
o;;[I"require "m_user"
;TI"
;TI"x = C.new
;TI"m_user = MUser.new
;TI".m_user.call_foo(x) # prints "C#foo in M"
;TI"1x.foo #=> raises NoMethodError
;T;0o;
;[I"HSince the refinement +M+ is active in <code>m_user.rb</code> where ;TI"C<code>MUser#call_foo</code> is defined it is also active when ;TI"+<code>main.rb</code> calls +call_foo+.;T@
o;
;[I"TSince #using is a method, refinements are only active when it is called. Here ;TI"Aare examples of where a refinement +M+ is and is not active.;T@
o;
;[I"In a file:;T@
o;;[I"# not activated here
;TI"
using M
;TI"# activated here
;TI"class Foo
;TI" # activated here
;TI" def foo
;TI" # activated here
;TI" end
;TI" # activated here
;TI" end
;TI"# activated here
;T;0o;
;[I"In a class:;T@
o;;[I"# not activated here
;TI"class Foo
;TI" # not activated here
;TI" def foo
;TI" # not activated here
;TI" end
;TI" using M
;TI" # activated here
;TI" def bar
;TI" # activated here
;TI" end
;TI" # activated here
;TI" end
;TI"# not activated here
;T;0o;
;[I"UNote that the refinements in +M+ are *not* activated automatically if the class ;TI"+Foo+ is reopened later.;T@
o;
;[I"
In eval:;T@
o;;[I"# not activated here
;TI"eval <<EOF
;TI" # not activated here
;TI" using M
;TI" # activated here
;TI" EOF
;TI"# not activated here
;T;0o;
;[I"When not evaluated:;T@
o;;[
I"# not activated here
;TI"if false
;TI" using M
;TI" end
;TI"# not activated here
;T;0o;
;[I"\When defining multiple refinements in the same module inside multiple +refine+ blocks, ;TI"Kall refinements from the same module are active when a refined method ;TI"E(any of the +to_json+ methods from the example below) is called:;T@
o;;[I"module ToJSON
;TI" refine Integer do
;TI" def to_json
;TI" to_s
;TI"
end
;TI" end
;TI"
;TI" refine Array do
;TI" def to_json
;TI"7 "[" + map { |i| i.to_json }.join(",") + "]"
;TI"
end
;TI" end
;TI"
;TI" refine Hash do
;TI" def to_json
;TI"N "{" + map { |k, v| k.to_s.dump + ":" + v.to_json }.join(",") + "}"
;TI"
end
;TI" end
;TI" end
;TI"
;TI"using ToJSON
;TI"
;TI"Ap [{1=>2}, {3=>4}].to_json # prints "[{\"1\":2},{\"3\":4}]"
;T;0S; ;
i;I"Method Lookup;T@
o;
;[I"GWhen looking up a method for an instance of class +C+ Ruby checks:;T@
o:RDoc::Markup::List:
@type:BULLET:@items[ o:RDoc::Markup::ListItem:@label0;[o;
;[I"QIf refinements are active for +C+, in the reverse order they were activated:;To;;;;[o;;0;[o;
;[I"6The prepended modules from the refinement for +C+;To;;0;[o;
;[I"The refinement for +C+;To;;0;[o;
;[I"5The included modules from the refinement for +C+;To;;0;[o;
;[I"!The prepended modules of +C+;To;;0;[o;
;[I"+C+;To;;0;[o;
;[I" The included modules of +C+;T@
o;
;[I"QIf no method was found at any point this repeats with the superclass of +C+.;T@
o;
;[I"INote that methods in a subclass have priority over refinements in a ;TI"Lsuperclass. For example, if the method <code>/</code> is defined in a ;TI"Nrefinement for Numeric <code>1 / 2</code> invokes the original Integer#/ ;TI"Ubecause Integer is a subclass of Numeric and is searched before the refinements ;TI"Qfor the superclass Numeric. Since the method <code>/</code> is also present ;TI"Nin child +Integer+, the method lookup does not move up to the superclass.;T@
o;
;[I"ZHowever, if a method +foo+ is defined on Numeric in a refinement, <code>1.foo</code> ;TI"?invokes that method since +foo+ does not exist on Integer.;T@
S; ;
i;I"+super+;T@
o;
;[I"2When +super+ is invoked method lookup checks:;T@
o;;;;[o;;0;[o;
;[I"QThe included modules of the current class. Note that the current class may ;TI"be a refinement.;To;;0;[o;
;[I"PIf the current class is a refinement, the method lookup proceeds as in the ;TI"!Method Lookup section above.;To;;0;[o;
;[I"QIf the current class has a direct superclass, the method proceeds as in the ;TI"6Method Lookup section above using the superclass.;T@
o;
;[I"MNote that +super+ in a method of a refinement invokes the method in the ;TI"Srefined class even if there is another refinement which has been activated in ;TI"the same context.;T@
S; ;
i;I"Methods Introspection;T@
o;
;[I"jWhen using introspection methods such as Kernel#method or Kernel#methods refinements are not honored.;T@
o;
;[I"0This behavior may be changed in the future.;T@
S; ;
i;I"-Refinement inheritance by Module#include;T@
o;
;[I"PWhen a module X is included into a module Y, Y inherits refinements from X.;T@
o;
;[I"LFor example, C inherits refinements from A and B in the following code:;T@
o;;[I"module A
;TI" refine X do ... end
;TI" refine Y do ... end
;TI" end
;TI"module B
;TI" refine Z do ... end
;TI" end
;TI"module C
;TI" include A
;TI" include B
;TI" end
;TI"
;TI"
using C
;TI"2# Refinements in A and B are activated here.
;T;0o;
;[I"ORefinements in descendants have higher precedence than those of ancestors.;T@
S; ;
i;I"Further Reading;T@
o;
;[I"USee https://bugs.ruby-lang.org/projects/ruby-trunk/wiki/RefinementsSpec for the ;TI"Qcurrent specification for implementing refinements. The specification also ;TI"contains more details.;T:
@file@:0@omit_headings_from_table_of_contents_below0