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" :)
Q) How can I access instance variables used in base object? A) Just write the name as method. (powered by method_missing)
1 class InstanceMethods < SandboxedMethods
2     def foo
3       array = objects         # returns '@objects' in base object.
4       size  = attributes.size # returns '@attributes' in base object.
Q) How can I access instance variables those names are used in internal methods? A) Use “self[name]” method.
1 class InstanceMethods < SandboxedMethods
2     def foo
3       var = self[:foo]  # returns '@foo' in base object.
Q) How can I write instance variables back to base object? A) Use “name=” or “[]=(name, val) method.
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.
Q) How can I access base object directly? A) Use “base” method without argument.
1 class InstanceMethods < SandboxedMethods
2     def foo
3       base.class  # returns '@foo' in base object.
Q) How can I access methods defined in base object? A) Use reference of base object by “base” method if it’s public.
1 class InstanceMethods < SandboxedMethods
2     def foo
3       base.class  # returns '@foo' in base object.
Q) How can I access non public methods defined in base object? A) Use “instance_eval” or “send” method to base object :)
1 class InstanceMethods < SandboxedMethods
2     def foo
3       base.__send__ :bar
This is too ugly. Any ideas?

Tags

You need to Login to tag this item.