Skip to content

Commit d40b224

Browse files
committed
Add 25: "Meta Methodology"
1 parent fb57b8c commit d40b224

1 file changed

Lines changed: 145 additions & 0 deletions

File tree

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
---
2+
title: Meta Methodology
3+
date: 2015-05-25
4+
tags: core, meta
5+
---
6+
7+
Ruby **clutters** its objects a lot with methods for metaprogramming other methods:
8+
9+
ARTICLE
10+
11+
Class.instance_methods.grep /method/
12+
=> [:instance_methods, :public_instance_methods,
13+
:protected_instance_methods, :private_instance_methods,
14+
:method_defined?, :public_method_defined?,
15+
:private_method_defined?, :protected_method_defined?,
16+
:public_class_method, :private_class_method, :instance_method,
17+
:public_instance_method, :methods, :singleton_methods,
18+
:protected_methods, :private_methods, :public_methods,
19+
:method, :public_method, :singleton_method,
20+
:define_singleton_method]
21+
22+
Class.private_instance_methods.grep /method/
23+
=> [:method_added, :method_removed, :method_undefined,
24+
:remove_method, :undef_method, :alias_method, :define_method,
25+
:instance_methods_for, :__method__, :singleton_method_added,
26+
:singleton_method_removed, :singleton_method_undefined,
27+
:method_missing]
28+
29+
It's so many methods, because working with methods is a multi-dimensional problem:
30+
31+
- Where are the modules, in the current instance or if a class/module, in its instances?
32+
- Or in its [singleton class](http://www.devalot.com/articles/2008/09/ruby-singleton)?
33+
- What about the method visibility?
34+
- Should the inheritance chain be considered?
35+
36+
Let's put everything in some order:
37+
38+
## Method Lists
39+
40+
Methods returning method lists always take a boolean argument, which will prevent inheritance if set to `false`
41+
42+
Method | From | Target | Visibility
43+
------------------------------------------------------------------------------------------------------------------|-----------|----------------------|-------------------
44+
[Object#singleton_methods](http://ruby-doc.org/core-2.2.2/Object.html#method-i-singleton_methods) | instance | singleton | public + protected
45+
[Object#methods](http://ruby-doc.org/core-2.2.2/Object.html#method-i-methods) | instance | instance + singleton | public + protected
46+
[Object#public_methods](http://ruby-doc.org/core-2.2.2/Object.html#method-i-public_methods) | instance | instance + singleton | public
47+
[Object#protected_methods](http://ruby-doc.org/core-2.2.2/Object.html#method-i-protected_methods) | instance | instance + singleton | protected
48+
[Object#private_methods](http://ruby-doc.org/core-2.2.2/Object.html#method-i-private_methods) | instance | instance + singleton | private
49+
[Module#instance_methods](http://ruby-doc.org/core-2.2.2/Module.html#method-i-instance_methods) | class | instance | public + protected
50+
[Module#public_instance_methods](http://ruby-doc.org/core-2.2.2/Module.html#method-i-public_instance_methods) | class | instance | public
51+
[Module#proected_instance_methods](http://ruby-doc.org/core-2.2.2/Module.html#method-i-proected_instance_methods) | class | instance | proected
52+
[Module#private_instance_methods](http://ruby-doc.org/core-2.2.2/Module.html#method-i-private_instance_methods) | class | instance | private
53+
{:.table-38-15-20-X}
54+
55+
- There is no API for getting a list of private singleton methods
56+
57+
## Method Defined? Checks
58+
59+
Instead of listing all methods and checking if the resulting array contains a specific method, you can also directly check if a method is defined:
60+
61+
Method | From | Target | Visibilitiy
62+
--------------------------------------------------------------------------------------------------------------------|-------|----------|------------
63+
[Module#method_defined?](http://ruby-doc.org/core-2.2.2/Module.html#method-i-method_defined-3F) | class | instance | all
64+
[Module#public_method_defined?](http://ruby-doc.org/core-2.2.2/Module.html#method-i-public_method_defined-3F) | class | instance | public
65+
[Module#protected_method_defined?](http://ruby-doc.org/core-2.2.2/Module.html#method-i-protected_method_defined-3F) | class | instance | protected
66+
[Module#private_method_defined?](http://ruby-doc.org/core-2.2.2/Module.html#method-i-private_method_defined-3F) | class | instance | private
67+
{:.table-38-15-20-X}
68+
69+
- This is also the best way to get the visibility of a method
70+
- There is no direct way to check for singleton methods
71+
72+
## Method Getters
73+
74+
These methods will return method objects for further metaprogramming action:
75+
76+
Method | From | Target | Visibility | Returns
77+
------------------------------------------------------------------------------------------------------------|-----------|----------------------|------------|--------
78+
[Object#singleton_method](http://ruby-doc.org/core-2.2.2/Object.html#method-i-singleton_method) | instance | singleton | all | [Method](http://ruby-doc.org/core-2.2.2/Method.html)
79+
[Object#method](http://ruby-doc.org/core-2.2.2/Object.html#method-i-method) | instance | instance + singleton | all | [Method](http://ruby-doc.org/core-2.2.2/Method.html)
80+
[Object#public_method](http://ruby-doc.org/core-2.2.2/Object.html#method-i-public_method) | instance | instance + singleton | public | [Method](http://ruby-doc.org/core-2.2.2/Method.html)
81+
[Module#instance_method](http://ruby-doc.org/core-2.2.2/Module.html#method-i-instance_method) | class | instance | all | [UnboundMethod](http://ruby-doc.org/core-2.2.2/UnboundMethod.html)
82+
[Module#public_instance_method](http://ruby-doc.org/core-2.2.2/Module.html#method-i-public_instance_method) | class | instance | public | [UnboundMethod](http://ruby-doc.org/core-2.2.2/UnboundMethod.html)
83+
{:.table-34-15-20-14-X}
84+
85+
- There are no methods to explicitely get private methods
86+
87+
## Method Manipulation
88+
89+
These methods will actually modify your objects:
90+
91+
Method | From | Target | Visibility
92+
--------------------------------------------------------------------------------------------------------------|-----------|-----------|-----------
93+
[Object#define_singleton_method](http://ruby-doc.org/core-2.2.2/Object.html#method-i-define_singleton_method) | instance | singleton | public
94+
[Module#define_method](http://ruby-doc.org/core-2.2.2/Module.html#method-i-define_method) (private) | class | instance | public (see notes)
95+
[Module#remove_method](http://ruby-doc.org/core-2.2.2/Module.html#method-i-remove_method) (private) | class | instance | -
96+
[Module#undef_method](http://ruby-doc.org/core-2.2.2/Module.html#method-i-undef_method) (private) | class | instance | -
97+
[Module#alias_method](http://ruby-doc.org/core-2.2.2/Module.html#method-i-alias_method) (private) | class | instance | same
98+
{:.table-38-15-20-X}
99+
100+
- No direct way to define a non-public method, but `define_method` respects visibility modifiers
101+
- No direct way to define a non-public singleton method
102+
- `remove_method` only deletes the method from the current module, while `undef_method` also deletes it from all ancestors
103+
104+
## Method Hooks
105+
106+
Hook methods can be defined and will be called by the Ruby interpreter when the respective event happens:
107+
108+
Method | From | Target
109+
------------------------------------------------------------------------------------------------------------------------------|----------|-------
110+
[BasicObject#singleton_method_added](http://ruby-doc.org/core-2.2.2/BasicObject.html#method-i-singleton_method_added) | instance | singleton
111+
[BasicObject#singleton_method_undefined](http://ruby-doc.org/core-2.2.2/BasicObject.html#method-i-singleton_method_undefined) | instance | singleton
112+
[BasicObject#singleton_method_removed](http://ruby-doc.org/core-2.2.2/BasicObject.html#method-i-singleton_method_removed) | instance | singleton
113+
[Module#method_added](http://ruby-doc.org/core-2.2.2/Module.html#method-i-method_added) | class | instance
114+
[Module#method_undefined](http://ruby-doc.org/core-2.2.2/Module.html#method-i-method_undefined) | class | instance
115+
[Module#method_removed](http://ruby-doc.org/core-2.2.2/Module.html#method-i-method_removed) | class | instance
116+
[BasicObject#method_missing](http://ruby-doc.org/core-2.2.2/BasicObject.html#method-i-method_missing) | class | instance
117+
{:.table-38-15-20-X}
118+
119+
- As long as you haven't defined a hook, Ruby considers it as an empty private method
120+
121+
## Method Visibility Modifiers
122+
123+
Besides `public`, `protected`, and `private`, there are two additional methods with the sole purpose of changing a method's visibility:
124+
125+
Method | From | Target | Description
126+
--------------------------------------------------------------------------------------------------------|-------|-----------|------------
127+
[Module#public_class_method](http://ruby-doc.org/core-2.2.2/Module.html#method-i-public_class_method) | class | singleton | Makes a class's singleton method public
128+
[Module#private_class_method](http://ruby-doc.org/core-2.2.2/Module.html#method-i-private_class_method) | class | singleton | Makes a class's singleton method private
129+
{:.table-34-12-12-X}
130+
131+
## Current Method Name
132+
133+
There are two underscore-wrapped methods that return the current method's name:
134+
135+
Method | From | Returns
136+
--------------------------------------------------------------------------------------------------|----------|--------
137+
[Kernel#\_\_method\_\_](http://ruby-doc.org/core-2.2.2/Kernel.html#method-i-__method__) (private) | anywhere | Original method name
138+
[Kernel#\_\_callee\_\_](http://ruby-doc.org/core-2.2.2/Kernel.html#method-i-__callee__) (private) | anywhere | Aliased method name
139+
{:.table-35-20-X}
140+
141+
- Also see [Kernel#caller](http://ruby-doc.org/core-2.2.2/Kernel.html#method-i-caller) and [Kernel#caller_locations](http://ruby-doc.org/core-2.2.2/Kernel.html#method-i-caller_locations)
142+
143+
## A Better API for Metaprogramming Methods?
144+
145+
Metaprogramming in Ruby has evolved over time, but it might be a good idea to clean it up a little - A good example of how to clean up one of Ruby's other metaprogramming APIs is the [instance gem](https://github.com/rubyworks/instance/). It gives you a neat API for working with an object's state, like setting instance variables. Someone feels like building a similar gem for Ruby's Method APIs?

0 commit comments

Comments
 (0)