Sandboxed Methods
Avoid conflicting method and variable names between modules.
What is this?
You should not write a module or a plugin like this.1 module Foo 2 def self.append_features(base) 3 base.__send__ :include, InstanceMethods 4 end 5 6 module InstanceMethods 7 def foo 8 # using internal methods 9 return ... 10 end 11 12 # internal_methods 13 def names 14 ... 15 end 16 end 17 end
Although this Foo module intends to give ‘foo’ class method to callers, unfortunately it also gives internal_methods and instance variables those are spin-off about ‘foo’ method.
We unconsciously prefer shorter names and tend to use well-conflictable method names such as ‘names’, ‘valid?’, ‘path’ for middle(internal) methods. Indeed it works sanely in your system, but how about outside of it?
SandboxedMethods helps you to offer methods you intend properly.
Usage
It is easy to use SandboxedMethods. There are only two points.
1) use “SandboxedMethods.give” rather than “extend” or “include” directly
This class method declares use of published method just like
"delegate" or "api stuff do so.
2) define methods as a sub class of SandboxedMethods
SandboxedMethods class offers a sandbox for executing methods.
Because all published methods are executed in the closed object,
the base object can't access other internal methods and variables.
Example
We can remove risks of the conflictions from above example by rewriting only two lines.1 module Foo 2 def self.append_features(base) 3 InstanceMethods.give(base, :foo) # 1) use 'give' class methods 4 end 5 6 class InstanceMethods < SandboxedMethods # 2) use SandboxedMethods class 7 def foo 8 # using internal methods 9 return ... 10 end 11 12 # internal_methods 13 def names 14 ... 15 end 16 end 17 end
Now we can create plugins as much as we want without taking care of conflictions about internal methods and variables!
Advanced
Q) How can I publish all methods defined in my module? A) If no methods are specified, it regards all methods as published.1 InstanceMethods.give(base)
Q) How can I publish methods as class methods? A) Use” option in “give” method.
1 InstanceMethods.give(base, :foo, :class=>true) 2 # It'd be better to rename "InstanceMethods" :)
1 class InstanceMethods < SandboxedMethods 2 def foo 3 array = objects # returns '@objects' in base object. 4 size = attributes.size # returns '@attributes' in base object.
1 class InstanceMethods < SandboxedMethods 2 def foo 3 var = self[:foo] # returns '@foo' in base object.
1 class InstanceMethods < SandboxedMethods 2 def foo 3 self.bar = 1 # means '@bar = 1' in base object. 4 self[:bar] = 1 # of course this works too. 5 bar = 1 # this is invalid cause it create a local variable.
1 class InstanceMethods < SandboxedMethods 2 def foo 3 base.class # returns '@foo' in base object.
1 class InstanceMethods < SandboxedMethods 2 def foo 3 base.class # returns '@foo' in base object.
1 class InstanceMethods < SandboxedMethods 2 def foo 3 base.__send__ :bar
- Repository Path: http://wota.jp/svn/rails/plugins/trunk/sandboxed_methods