[前][次][番号順一覧][スレッド一覧]

ruby-changes:26861

From: drbrain <ko1@a...>
Date: Thu, 24 Jan 2013 09:45:47 +0900 (JST)
Subject: [ruby-changes:26861] drbrain:r38913 (trunk): * doc/syntax/refinements.rdoc: Added refinements document based on

drbrain	2013-01-24 09:40:49 +0900 (Thu, 24 Jan 2013)

  New Revision: 38913

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38913

  Log:
    * doc/syntax/refinements.rdoc:  Added refinements document based on
      the specification from the wiki.
    * doc/syntax.rdoc:  Added link to refinements document.

  Added files:
    trunk/doc/syntax/refinements.rdoc
  Modified files:
    trunk/ChangeLog
    trunk/doc/syntax.rdoc

Index: doc/syntax/refinements.rdoc
===================================================================
--- doc/syntax/refinements.rdoc	(revision 0)
+++ doc/syntax/refinements.rdoc	(revision 38913)
@@ -0,0 +1,240 @@ https://github.com/ruby/ruby/blob/trunk/doc/syntax/refinements.rdoc#L1
+= Refinements
+
+Due to Ruby's open classes you can redefine or add functionality to existing
+classes.  This is called a "monkey patch".  Unfortunately the scope of such
+changes is global.  All users of the monkey-patched class see the same
+changes.  This can cause unintended side-effects or breakage of programs.
+
+Refinements are designed to reduce the impact of monkey patching on other
+users of the monkey-patched class.  Refinements provide a way to extend a
+class locally.
+
+Refinements are an experimental feature in Ruby 2.0.  At the time of writing,
+refinements are expected to exist in future versions of Ruby but the
+specification of refinements may change.  You will receive a warning the first
+time you define or activate a refinement.
+
+Here is a basic refinement:
+
+  class C
+    def foo
+      puts "C#foo
+    end
+  end
+
+  module M
+    refine C do
+      def foo
+        puts "C#foo in M"
+      end
+    end
+  end
+
+First, a class +C+ is defined.  Next a refinement for +C+ is created using
+Module#refine.  Refinements only modify classes, not modules so the argument
+must be a class.
+
+Module#refine creates an anonymous module that contains the changes or
+refinements to the class (+C+ in the example).  +self+ in the refine block is
+this anonymous module similar to Module#module_eval.
+
+Activate the refinement with #using:
+
+  using M
+
+  x = C.new
+
+  c.foo # prints "C#foo in M"
+
+== Scope
+
+You may only activate refinements at top-level to the end of the file or in a
+string passed to Kernel#eval, Kernel#instance_eval or Kernel#module_eval until
+the end of the string.
+
+Refinements are lexical in scope.  When control is transferred outside the
+scope the refinement is deactivated.  This means that if you require or load a
+file or call a method that is defined outside the current scope the refinement
+will be deactivated:
+
+  class C
+  end
+
+  module M
+    refine C do
+      def foo
+        puts "C#foo in M"
+      end
+    end
+  end
+
+  def call_foo(x)
+    x.foo
+  end
+
+  using M
+
+  x = C.new
+  x.foo       # prints "C#foo in M"
+  call_foo(x) #=> raises NoMethodError
+
+If a method is defined in a scope where a refinement is active the refinement
+will be active when the method is called.  This example spans multiple files:
+
+c.rb:
+
+  class C
+  end
+
+m.rb:
+
+  require "c"
+
+  module M
+    refine C do
+      def foo
+        puts "C#foo in M"
+      end
+    end
+  end
+
+m_user.rb:
+
+  require "m"
+
+  using M
+
+  class MUser
+    def call_foo(x)
+      x.foo
+    end
+  end
+
+main.rb:
+
+  require "m_user"
+
+  x = C.new
+  m_user = MUser.new
+  m_user.call_foo(x) # prints "C#foo in M"
+  x.foo              #=> raises NoMethodError
+
+Since the refinement +M+ is active in <code>m_user.rb</code> where
+<code>MUser#call_foo</code> is defined it is also active when
+<code>main.rb</code> calls +call_foo+.
+
+Since #using is a method, refinements are only active when it is called.  Here
+are examples of where a refinement +M+ is and is not active.
+
+In a file:
+
+  # not activated here
+  using M
+  # activated here
+  class Foo
+    # activated here
+    def foo
+      # activated here
+    end
+    # activated here
+  end
+  # activated here
+
+In eval:
+
+  # not activated here
+  eval <<EOF
+    # not activated here
+    using M
+    # activated here
+  EOF
+  # not activated here
+
+When not evaluated:
+
+  # not activated here
+  if false
+    using M
+  end
+  # not activated here
+
+When defining multiple refinements in the same module, inside a refine block
+all refinements from the same module are active when a refined method is
+called:
+
+  module ToJSON
+    refine Integer do
+      def to_json
+        to_s
+      end
+    end
+
+    refine Array do
+      def to_json
+        "[" + map { |i| i.to_json }.join(",") + "]"
+      end
+    end
+
+    refine Hash do
+      def to_json
+        "{" + map { |k, v| k.to_s.dump + ":" + v.to_json }.join(",") + "}"
+      end
+    end
+  end
+
+  using ToJSON
+
+  p [{1=>2}, {3=>4}].to_json # prints "[{\"1\":2},{\"3\":4}]"
+
+== Method Lookup
+
+When looking up a method for a class +C+ Ruby checks:
+
+* If refinements are active for +C+, in the reverse order they were activated:
+  * The prepended modules from the refinement for +C+
+  * The refinement for +C+
+  * The included modules from the refinement for +C+
+* The prepended modules of +C+
+* +C+
+* The included modules of +C+
+
+If no method was found at any point this repeats with the superclass of +C+.
+
+Note that methods in a subclass have priority over refinements in a
+superclass.  For example, if the method <code>/</code> is defined in a
+refinement for Integer <code>1 / 2</code> invokes the original Fixnum#/
+because Fixnum is a subclass of Integer and is searched before the refinements
+for the superclass Integer.
+
+If a method +foo+ is defined on Integer in a refinement, <code>1.foo</code>
+invokes that method since +foo+ does not exist on Fixnum.
+
+== +super+
+
+When +super+ is invoked method lookup checks:
+
+* The included modules of the current class.  Note that the current class may
+  be a refinement.
+* If the current class is a refinement, the method lookup proceeds as in the
+  Method Lookup section above.
+* If the current class has a direct superclass, the method proceeds as in the
+  Method Lookup section above using the superclass.
+
+Note that +super+ in a method of a refinement invokes the method in the
+refined class even if there is another refinement which has been activated in
+the same context.
+
+== Indirect Method Calls
+
+When using indirect method access such as Kernel#send, Kernel#method or
+Kernel#respond_to? refinements are not honored for the caller context during
+method lookup.
+
+This behavior may be changed in the future.
+
+== Further Reading
+
+See http://bugs.ruby-lang.org/projects/ruby-trunk/wiki/RefinementsSpec for the
+current specification for implementing refinements.  The specification also
+contains more details.
+

Property changes on: doc/syntax/refinements.rdoc
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: doc/syntax.rdoc
===================================================================
--- doc/syntax.rdoc	(revision 38912)
+++ doc/syntax.rdoc	(revision 38913)
@@ -26,6 +26,9 @@ Exceptions[rdoc-ref:syntax/exceptions.rd https://github.com/ruby/ruby/blob/trunk/doc/syntax.rdoc#L26
 Precedence[rdoc-ref:syntax/precedence.rdoc] ::
   Precedence of ruby operators
 
+Refinements[rdoc-ref:syntax/refinements.rdoc] ::
+  Use and behavior of the experimental refinements feature
+
 Miscellaneous[rdoc-ref:syntax/miscellaneous.rdoc] ::
   +alias+, +undef+, +BEGIN+, +END+
 
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 38912)
+++ ChangeLog	(revision 38913)
@@ -1,3 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Thu Jan 24 09:40:13 2013  Eric Hodel  <drbrain@s...>
+
+	* doc/syntax/refinements.rdoc:  Added refinements document based on
+	  the specification from the wiki.
+	* doc/syntax.rdoc:  Added link to refinements document.
+
 Wed Jan 23 16:29:09 2013  Nobuyoshi Nakada  <nobu@r...>
 
 	* win32/win32.c (rb_w32_spawn, rb_w32_aspawn_flags): fix missing

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]