=begin
Please do not edit this page. ((<"File a new ticket"|URL:http://bugs.ruby-lang.org/projects/ruby-trunk/issues/new>)) instead.

= Refinements Specification

== Abstract

This documentation describes the specification of Refinements, which provide local class extensions.

== Rationale

Monkey patching is a powerful feature of Ruby.
However, it affects globally in a program. Therefore, a monkey patch might break code which doesn't expect the extended behavior, and multiple monkey patches for the same class might cause conflicts.
To solve these problems, Refinements provide a way to extend classes locally.

== Terms and definitions

: refinement
A class extension which can be activated only in a certain scope.
A refinement is an anonymous module, and is defined under another module, which is used as a namespace for a set of refinements.
: refine
To extend a class by refinements.
: refined class
An attribute of a refinement, which represents a class to be extended by the refinement.
: refine block
A refine block is a block given to Module#refine.
: defined refinement table
A table which holds refinements defined in a module. Keys are classes to be refined, and values are refinements.
: main
The object referred by self in toplevel. main is a direct instance of Object, and has singleton methods.
: implementation-defined
Behavior that possibly differs between implementations, but is defined for every implementation
: unspecified
Behavior that possibly differs between implementations, and is not necessarily defined for every implementation

== Overview

A refinement is defined in a module as follows:

class C
def foo
puts "C#foo"
end
end

module M
refine C do
def foo
puts "C#foo in M"
end
end
end

refine is not a keyword, but a method defined in Module.
refine takes a class to be extended as the only argument, and takes a block, in which self is replaced with an anonymous module called a refinement.

A refinement is activated in a certain scope by main.using as follows:

using M
x = C.new
c.foo #=> C#foo in M

In a scope where a refinement is activated, when a method is invoked on an instance of the refined class, the methods defined in the refinement is searched before methods of the refined class.

== Defining refinements

A refinement is defined in a module by Module#refine. Multiple refinements can be defined in a single module.

=== Module#refine(klass, &block)

Visibility: private

Behavior:

Module#refine defines a refinement under the receiver as follows:

(1) If (({klass})) is not an instance of Class, raise a TypeError.
(2) Lookup (({klass})) in the defined refinement table of the receiver.
(3) If a refinement is found, let (({R})) be the refinement.
(4) Otherwise:
(1) Create an anonymous module with a special flag which denotes the module is a refinement,
and let (({R})) be the created anonymous module.
(2) Set the refined class of (({R})) to (({klass})).
(3) Add a pair whose key is (({klass})) and whose value is (({R})) to the defined refinement table of the receiver
(5) Yield block replacing self with (({R})) as module_eval does.
Refinements defined in the receiver shall be activated in (({block})) as specified in ((<"Scope of refinements activated in refine blocks">)).
However, if (({block})) is of a Proc, whether refinements are activated is implementation-defined.
(6) Return (({R})).

NOTE: In this specification, modules cannot be refined as described in Step 1 to avoid complexity of method lookup.

=== Class#refine

Class#refine shall be undefined as if the following Ruby program is evaluated.

class Class
undef refine
end

NOTE: In this specification, it doesn't make sense to provide Class#refine because class/module scope refinements are not available.

== Using refinements

Refinements are activated by main.using.

=== main.using(mod)

Visibility: private

Behavior:

(1) If using is called in a class/module definition or a method definition, raise a RuntimeError.
(2) If (({mod})) is not an instance of Module, or is an instance of Class, raise a TypeError.
(3) Activate refinements in the defined refinement table of (({mod})) in a certain scope as specified in ((<"Scope of refinements activated by main.using">)).
(4) Return the receiver.

== Scope of refinements

A refinement is activated in a certain scope.
The scope of a refinement is lexical in the sense that, when control is transferred outside the scope (e.g., by an invocation of a method defined outside the scope, by load/require, etc...), the refinement is deactivated.
In the body of a method defined in a scope where a refinement is activated, the refinement is activated even if the method is invoked outside the scope.

EXAMPLE 1: A refinement is deactivated when control is transferred outside the scope.

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 #=> C#foo in M
call_foo(x) #=> NoMethodError

EXAMPLE 2: A refinement is activated even if a method is invoked outside the scope.

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
muser = MUser.new
m
user.call_foo(x) #=> C#foo in M
x.foo #=> NoMethodError

=== Scope of refinements activated by main.using

The scope of a refinement activated by main.using is from the point just after main.using is invoked to the end of the file where main.using is invoked.
However, when main.using is invoked in a string given as the first argument of Kernel#eval, Kernel#instanceeval, or Module#moduleeval, the end of the scope is the end of the string.

main.using activates a refinement at runtime, and therefore a refinement is not activated if main.using is not evaluated.

EXAMPLE 1: using in a file

# not activated here
using M
# activated here
class Foo
# activated here
def foo
# activated here
end
# activated here
end
# activated here

EXAMPLE 2: using in eval

# not activated here
eval <<EOF
# not activated here
using M
# activated here
EOF
# not activated here

EXAMPLE 3: using not evaluated

# not activated here
if false
using M
end
# not activated here

=== Scope of refinements activated in refine blocks

In a block given to Module#refine, refinements in the defined refinement table of the receiver of Module#refine are activated.
The scope of refinements activated in a refine block is only in that block and refinements are deactivated outside the block.

When a method defined in a refine block is invoked, refinements defined in the receiver of Module#refine at the time when the method is invoked are activated.

EXAMPLE 1: Refinements are deactivated outside a refine block.

module StringRecursiveLength
refine String do
def recursivelength
if empty?
0
else
self[1..-1].recursive
length + 1
end
end
end
p "abc".recursive_length #=> NoMethodError
end

EXAMPLE 2: Refinements defined at the time when a method is invoked are activated.

module ToJSON
refine Integer do
def tojson; tos; 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 #=> "[{\"1\":2},{\"3\":4}]"

== Method lookup with refinements

=== Normal method lookup

A method is searched with refinements as follows:

(1) Let (({N})) be the name of the method to be invoked.
(2) Let (({S})) be the receiver.
(3) If (({S})) has a singleton class, let (({C})) be the singleton class. Otherwise, let (({C})) be the class of (({S})).
(4) If there exist refinements of (({C})) (i.e., the refined class of the refinements is (({C}))) which are activated in the current context, let (({RS})) be the refinements, and take the following steps for each refinement (({R})) in (({RS})) in the reverse order they are activated in the context:
(1) If (({R})) has prepended modules, let (({MS})) be the modules, and take the following step for each module (({M})) in (({MS})) in the reverse order they are prepended into (({R})).
(1) If a method with name (({N})) found in the method table of (({M})), return the method.
(2) If a method with name (({N})) found in the method table of (({R})), return the method.
(3) If (({R})) has included modules, let (({MS})) be the modules, and take the following step for each module (({M})) in (({MS})) in the reverse order they are included into (({R})).
(1) If a method with name (({N})) found in the method table of (({M})), return the method.
(5) If (({C})) has prepended modules, let (({MS})) be the modules, and take the following step for each module (({M})) in (({MS})) in the reverse order they are prepended into (({C})).
(1) If a method with name (({N})) found in the method table of (({M})), return the method.
(6) If a method with name (({N})) found in the method table of (({C})), return the method.
(7) If (({C})) has included modules, let (({MS})) be the modules, and take the following step for each module (({M})) in (({MS})) in the reverse order they are included into (({C})).
(1) If a method with name (({N})) found in the method table of (({M})), return the method.
(8) If (({C})) has a direct superclass, let (({C})) be the superclass, and go to Step 4.
(9) Otherwise, the method is not found.

NOTE: In this specification subclasses have priority over refinements. For example, even if the method / is defined in a refinement of Integer, (({1 / 2})) invokes the original Fixnum#/ because Fixnum is a subclass of Integer, and is searched before the refinement of Integer. However, if the method foo is defined in a refinement of Integer, (({1.foo})) invokes that method, because foo is not found in Fixnum, and is therefore searched in the refinement.

NOTE: The lookup order for a class C is: refinements of C (and their prepended and included modules) -> prepended modules of C -> C -> included modules of C -> the superclass of C.

=== super

When super is invoked, a method is search as follows:

(1) Let (({N})) be the name of the current method.
(2) Let (({C})) be the current class.
(3) If (({C})) has included modules, let (({MS})) be the modules, and take the following step for each module (({M})) in (({MS})) in the reverse order they are included into (({C})).
(1) If a method with name (({N})) found in the method table of (({M})), return the method.
(4) If (({C})) is a refinement, search the method (({N})) as specified in ((<"Normal method lookup">)) from Step 4, where (({C})) is the refined class of the refinement.
(7) If (({C})) has a direct superclass, search the method (({N})) as specified in ((<"Normal method lookup">)) from Step 4, where (({C})) is the superclass.
(8) Otherwise, the method is not found.

NOTE: In this specification, super in a method of a refinement (({R})) invokes the method in the refined class (({C})) of (({R})) even if there is another refinement for (({C})) which has been activated in the same context before (({R})).

== Indirect method accesses

Any indirect method access such as Kernel#send, Kernel#method, and Kernel#respond_to? shall not honor refinements in the caller context during method lookup.

NOTE: This behavior will be changed in the future.

=end