method_repository 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +136 -0
- data/Rakefile +1 -0
- data/lib/method_repository.rb +47 -0
- data/lib/method_repository/version.rb +3 -0
- data/method_repository.gemspec +21 -0
- data/spec/lib/method_repository_spec.rb +98 -0
- data/spec/spec_helper.rb +5 -0
- metadata +74 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Kentaro Kuribayashi
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
# MethodRepository
|
2
|
+
|
3
|
+
Extracting redandunt code and commonalizing it in a different way.
|
4
|
+
|
5
|
+
## Problem
|
6
|
+
|
7
|
+
To extract redandunt 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.
|
8
|
+
|
9
|
+
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 classed/modules are defined, it's inevitable that the classes/modules are inherited/included at anywhere we don't know.
|
10
|
+
|
11
|
+
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 prevent them from grasping the whole code quickily.
|
12
|
+
|
13
|
+
## Solution
|
14
|
+
|
15
|
+
This library provides a "method repository" in which you can add your methods to commonalize redandunt 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.
|
16
|
+
|
17
|
+
This is the point; There's no chance the methods in the "repository" appear at somewhere the "repository" don't know. To commonalize redanduncy 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.
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Imagine there's such a code below:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
module Repository
|
25
|
+
include MethodRepository
|
26
|
+
|
27
|
+
insert :method1, in: %w[Foo Bar] do; end
|
28
|
+
insert :method2, in: %w[Baz] do; end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Foo; end
|
32
|
+
class Bar; end
|
33
|
+
class Baz; end
|
34
|
+
class Qux; end
|
35
|
+
```
|
36
|
+
|
37
|
+
* `method1` is declared it can be inserted in `Foo` and `Bar`
|
38
|
+
* `method2` is declared it can be inserted in only `Baz`
|
39
|
+
* No method is declared it can be inserted in `Qux`
|
40
|
+
|
41
|
+
### Extending
|
42
|
+
|
43
|
+
When the classes/objects are extended by `Repository` module:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
Foo.extend(Repository)
|
47
|
+
Bar.extend(Repository)
|
48
|
+
Baz.extend(Repository)
|
49
|
+
Qux.extend(Repository)
|
50
|
+
```
|
51
|
+
|
52
|
+
or
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
foo = Foo.new; foo.extend(Repository)
|
56
|
+
bar = Bar.new; bar.extend(Repository)
|
57
|
+
baz = Baz.new; bar.extend(Repository)
|
58
|
+
qux = Qux.new; qux.extend(Repository)
|
59
|
+
```
|
60
|
+
|
61
|
+
Only explicitely permitted methods are defined as singleton methods of each classes/objects. That results in:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
Foo.respond_to?(:method1)) #=> true
|
65
|
+
Bar.respond_to?(:method1)) #=> true
|
66
|
+
Baz.respond_to?(:method1)) #=> false
|
67
|
+
Qux.respond_to?(:method1)) #=> false
|
68
|
+
|
69
|
+
Foo.respond_to?(:method2)) #=> false
|
70
|
+
Bar.respond_to?(:method2)) #=> false
|
71
|
+
Baz.respond_to?(:method2)) #=> true
|
72
|
+
Qux.respond_to?(:method1)) #=> false
|
73
|
+
```
|
74
|
+
|
75
|
+
or
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
foo.respond_to?(:method1)) #=> true
|
79
|
+
bar.respond_to?(:method1)) #=> true
|
80
|
+
baz.respond_to?(:method1)) #=> false
|
81
|
+
qux.respond_to?(:method1)) #=> false
|
82
|
+
|
83
|
+
foo.respond_to?(:method2)) #=> false
|
84
|
+
bar.respond_to?(:method2)) #=> false
|
85
|
+
baz.respond_to?(:method2)) #=> true
|
86
|
+
qux.respond_to?(:method1)) #=> false
|
87
|
+
```
|
88
|
+
|
89
|
+
### Including
|
90
|
+
|
91
|
+
The rule is also applicable to `include`:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
Foo.send(:include, Repository)
|
95
|
+
Bar.send(:include, Repository)
|
96
|
+
Baz.send(:include, Repository)
|
97
|
+
Qux.send(:include, Repository)
|
98
|
+
```
|
99
|
+
|
100
|
+
Results in:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
Foo.new.respond_to?(:method1)) #=> true
|
104
|
+
Bar.new.respond_to?(:method1)) #=> true
|
105
|
+
Baz.new.respond_to?(:method1)) #=> false
|
106
|
+
Qux.new.respond_to?(:method1)) #=> false
|
107
|
+
|
108
|
+
Foo.new.respond_to?(:method2)) #=> false
|
109
|
+
Bar.new.respond_to?(:method2)) #=> false
|
110
|
+
Baz.new.respond_to?(:method2)) #=> true
|
111
|
+
Qux.new.respond_to?(:method1)) #=> false
|
112
|
+
```
|
113
|
+
|
114
|
+
In this case, the methods in `Repository` are, of course, defined as instance methods of each classes, not singleton methods of each objects.
|
115
|
+
|
116
|
+
## Installation
|
117
|
+
|
118
|
+
Add this line to your application's Gemfile:
|
119
|
+
|
120
|
+
gem 'inserts'
|
121
|
+
|
122
|
+
And then execute:
|
123
|
+
|
124
|
+
$ bundle
|
125
|
+
|
126
|
+
Or install it yourself as:
|
127
|
+
|
128
|
+
$ gem install inserts
|
129
|
+
|
130
|
+
## Contributing
|
131
|
+
|
132
|
+
1. Fork it
|
133
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
134
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
135
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
136
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "method_repository/version"
|
2
|
+
|
3
|
+
module MethodRepository
|
4
|
+
def self.included(base)
|
5
|
+
base.instance_variable_set(:@targets, {})
|
6
|
+
base.extend(ModuleMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ModuleMethods
|
10
|
+
def extended(base)
|
11
|
+
klass_name = base.class.to_s == 'Class' ? base.to_s : base.class.to_s
|
12
|
+
|
13
|
+
if (methods = @targets[klass_name])
|
14
|
+
singleton_class = class << base; self; end
|
15
|
+
singleton_class.class_eval do
|
16
|
+
methods.each do |method|
|
17
|
+
define_method method[:name], method[:block]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def included(base)
|
24
|
+
if (methods = @targets[base.to_s])
|
25
|
+
base.class_eval do
|
26
|
+
methods.each do |method|
|
27
|
+
define_method method[:name], method[:block]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def insert(name, klasses = {}, &block)
|
34
|
+
if !klasses[:in]
|
35
|
+
raise ArgumentError.new("`:in' parameter is required")
|
36
|
+
end
|
37
|
+
|
38
|
+
klasses[:in].each do |klass|
|
39
|
+
@targets[klass] ||= []
|
40
|
+
@targets[klass] << {
|
41
|
+
:name => name,
|
42
|
+
:block => block,
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'method_repository/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "method_repository"
|
8
|
+
gem.version = MethodRepository::VERSION
|
9
|
+
gem.authors = ["Kentaro Kuribayashi"]
|
10
|
+
gem.email = ["kentarok@gmail.com"]
|
11
|
+
gem.description = %q{Extracting redandunt code and commonalizing it in a different way.}
|
12
|
+
gem.summary = %q{Extracting redandunt code and commonalizing it in a different way}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency "rspec", "~> 2.12"
|
21
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MethodRepository do
|
4
|
+
module Repository
|
5
|
+
include MethodRepository
|
6
|
+
|
7
|
+
insert :method1, in: %w[Foo Bar] do; end
|
8
|
+
insert :method2, in: %w[Baz] do; end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Foo; end
|
12
|
+
class Bar; end
|
13
|
+
class Baz; end
|
14
|
+
class Qux; end
|
15
|
+
|
16
|
+
describe '.insert' do
|
17
|
+
it {
|
18
|
+
expect {
|
19
|
+
module Repository
|
20
|
+
insert :method3
|
21
|
+
end
|
22
|
+
}.to raise_error(
|
23
|
+
ArgumentError,
|
24
|
+
"`:in' parameter is required",
|
25
|
+
)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '.extended' do
|
30
|
+
context 'when classes are extended' do
|
31
|
+
before {
|
32
|
+
Foo.extend(Repository)
|
33
|
+
Bar.extend(Repository)
|
34
|
+
Baz.extend(Repository)
|
35
|
+
Qux.extend(Repository)
|
36
|
+
}
|
37
|
+
|
38
|
+
it {
|
39
|
+
expect(Foo.respond_to?(:method1)).to be true
|
40
|
+
expect(Bar.respond_to?(:method1)).to be true
|
41
|
+
expect(Baz.respond_to?(:method1)).to be false
|
42
|
+
expect(Qux.respond_to?(:method1)).to be false
|
43
|
+
|
44
|
+
expect(Foo.respond_to?(:method2)).to be false
|
45
|
+
expect(Bar.respond_to?(:method2)).to be false
|
46
|
+
expect(Baz.respond_to?(:method2)).to be true
|
47
|
+
expect(Qux.respond_to?(:method1)).to be false
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when objects are extended' do
|
52
|
+
let(:foo) { Foo.new }
|
53
|
+
let(:bar) { Bar.new }
|
54
|
+
let(:baz) { Baz.new }
|
55
|
+
let(:qux) { Qux.new }
|
56
|
+
|
57
|
+
before {
|
58
|
+
foo.extend(Repository)
|
59
|
+
bar.extend(Repository)
|
60
|
+
baz.extend(Repository)
|
61
|
+
qux.extend(Repository)
|
62
|
+
}
|
63
|
+
|
64
|
+
it {
|
65
|
+
expect(foo.respond_to?(:method1)).to be true
|
66
|
+
expect(bar.respond_to?(:method1)).to be true
|
67
|
+
expect(baz.respond_to?(:method1)).to be false
|
68
|
+
expect(qux.respond_to?(:method1)).to be false
|
69
|
+
|
70
|
+
expect(foo.respond_to?(:method2)).to be false
|
71
|
+
expect(bar.respond_to?(:method2)).to be false
|
72
|
+
expect(baz.respond_to?(:method2)).to be true
|
73
|
+
expect(qux.respond_to?(:method1)).to be false
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '.included' do
|
79
|
+
before {
|
80
|
+
Foo.send(:include, Repository)
|
81
|
+
Bar.send(:include, Repository)
|
82
|
+
Baz.send(:include, Repository)
|
83
|
+
Qux.send(:include, Repository)
|
84
|
+
}
|
85
|
+
|
86
|
+
it {
|
87
|
+
expect(Foo.new.respond_to?(:method1)).to be true
|
88
|
+
expect(Bar.new.respond_to?(:method1)).to be true
|
89
|
+
expect(Baz.new.respond_to?(:method1)).to be false
|
90
|
+
expect(Qux.new.respond_to?(:method1)).to be false
|
91
|
+
|
92
|
+
expect(Foo.new.respond_to?(:method2)).to be false
|
93
|
+
expect(Bar.new.respond_to?(:method2)).to be false
|
94
|
+
expect(Baz.new.respond_to?(:method2)).to be true
|
95
|
+
expect(Qux.new.respond_to?(:method1)).to be false
|
96
|
+
}
|
97
|
+
end
|
98
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: method_repository
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kentaro Kuribayashi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '2.12'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '2.12'
|
30
|
+
description: Extracting redandunt code and commonalizing it in a different way.
|
31
|
+
email:
|
32
|
+
- kentarok@gmail.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- LICENSE.txt
|
40
|
+
- README.md
|
41
|
+
- Rakefile
|
42
|
+
- lib/method_repository.rb
|
43
|
+
- lib/method_repository/version.rb
|
44
|
+
- method_repository.gemspec
|
45
|
+
- spec/lib/method_repository_spec.rb
|
46
|
+
- spec/spec_helper.rb
|
47
|
+
homepage: ''
|
48
|
+
licenses: []
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.8.23
|
68
|
+
signing_key:
|
69
|
+
specification_version: 3
|
70
|
+
summary: Extracting redandunt code and commonalizing it in a different way
|
71
|
+
test_files:
|
72
|
+
- spec/lib/method_repository_spec.rb
|
73
|
+
- spec/spec_helper.rb
|
74
|
+
has_rdoc:
|