Extracting redundant code and commonalizing it in a different way.
To extract redundant codes into a method to commonalize them is a usual strategy for OOP. It allows us to streamline our codes and modify at one stop even though the method is used at anywhere, anytimes.
I don't like when highly commonalized OOP structure disturbes me from quick tracing where such methods are defined. It's OOP's natural defect, I think. Once classes/modules are defined, it's inevitable that the classes/modules are inherited/included at anywhere we don't know.
In that way, inheritance/inclusion-based OOP resembles
goto programming; There's no clear reason why some classes/modules are inherited/included by another classes/modules. Even though there's some structural thought in your classes/modules design, such an excessively free inheritance/inclusion prevents us from grasping the whole code quickily.
This library provides a "method repository" in which you can add your methods to commonalize redundant codes here and there in your whole codes, which is just same as usual module usage. However, the methods you define in the "repository" will never be included automatically into other classes/modules unless not permitted explicitely.
This is the point; There's no chance the methods in the "repository" appear at somewhere the "repository" don't know. To commonalize redundancy is our intension, but we don't want the methods to be used where we don't know. The way this library provides solves the problem.
Imagine there's such a code below:
module Repository include MethodRepository insert :method1, in: %w[Foo Bar] do; end insert :method2, in: %w[Baz] do; end end class Foo; end class Bar; end class Baz; end class Qux; end
method1is declared it can be inserted in
method2is declared it can be inserted in only
- No method is declared it can be inserted in
Limit Extending/Including in a Lump
You can also limit extending/including in a lump, not designating classes using
insert method at method definitions, like below:
module Extendable include MethodRepository extendable_by 'Hoge' end module Includable include MethodRepository includable_by 'Hoge' end class Hoge; end class Fuga; end
In this way:
Hoge.extend(Extendable) Hoge.send(:include, Includable)
works as you see, however:
Fuga.extend(Extendable) Fuga.send(:include, Includable)
When the classes/objects are extended by
Foo.extend(Repository) Bar.extend(Repository) Baz.extend(Repository) Qux.extend(Repository)
foo = Foo.new; foo.extend(Repository) bar = Bar.new; bar.extend(Repository) baz = Baz.new; bar.extend(Repository) qux = Qux.new; qux.extend(Repository)
Only explicitely permitted methods are defined as singleton methods of each classes/objects. That results in:
Foo.respond_to?(:method1) #=> true Bar.respond_to?(:method1) #=> true Baz.respond_to?(:method1) #=> false Qux.respond_to?(:method1) #=> false Foo.respond_to?(:method2) #=> false Bar.respond_to?(:method2) #=> false Baz.respond_to?(:method2) #=> true Qux.respond_to?(:method2) #=> false
foo.respond_to?(:method1) #=> true bar.respond_to?(:method1) #=> true baz.respond_to?(:method1) #=> false qux.respond_to?(:method1) #=> false foo.respond_to?(:method2) #=> false bar.respond_to?(:method2) #=> false baz.respond_to?(:method2) #=> true qux.respond_to?(:method2) #=> false
The rule is also applicable to
Foo.send(:include, Repository) Bar.send(:include, Repository) Baz.send(:include, Repository) Qux.send(:include, Repository)
Foo.new.respond_to?(:method1) #=> true Bar.new.respond_to?(:method1) #=> true Baz.new.respond_to?(:method1) #=> false Qux.new.respond_to?(:method1) #=> false Foo.new.respond_to?(:method2) #=> false Bar.new.respond_to?(:method2) #=> false Baz.new.respond_to?(:method2) #=> true Qux.new.respond_to?(:method2) #=> false
In this case, the methods in
Repository are, of course, defined as instance methods of each classes, not singleton methods of each objects.
Add this line to your application's Gemfile:
And then execute:
Or install it yourself as:
$ gem install method_repository
- Fork it
- Create your feature branch (
git checkout -b my-new-feature)
- Commit your changes (
git commit -am 'Add some feature')
- Push to the branch (
git push origin my-new-feature)
- Create new Pull Request