sub-setter 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +37 -0
- data/Rakefile +1 -0
- data/lib/sub-setter.rb +3 -0
- data/lib/sub-setter/object.rb +3 -0
- data/lib/sub-setter/sub-setter.rb +71 -0
- data/lib/sub-setter/version.rb +5 -0
- data/spec/sub-setter/object_spec.rb +7 -0
- data/spec/sub-setter/sub-setter_spec.rb +213 -0
- data/sub-setter.gemspec +26 -0
- metadata +67 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
SubSetter Pattern implementation for Ruby
|
2
|
+
=========================================
|
3
|
+
|
4
|
+
As described in [SubSetter Pattern for Ruby][xaviervia-subsetter].
|
5
|
+
|
6
|
+
Installation
|
7
|
+
------------
|
8
|
+
|
9
|
+
> Not yet
|
10
|
+
|
11
|
+
This implementation creates
|
12
|
+
---------------------------
|
13
|
+
|
14
|
+
- The **SubSetter** Module, containing three methods (and three more aliases) that are included into Object.
|
15
|
+
- The **SubSetter::Object** Class, implementation (empty right now) of a generic subsetter for Object.
|
16
|
+
|
17
|
+
[xaviervia-subsetter]: http://xaviervia.com.ar/patterns/sub-setter
|
18
|
+
|
19
|
+
New methods in Object
|
20
|
+
---------------------
|
21
|
+
|
22
|
+
### Public
|
23
|
+
|
24
|
+
- `subsetter`: returns an instance of the designated subsetter for the class of this instance.
|
25
|
+
- `_subsetter`, `by` and `filter`: aliases for `subsetter`. `by` and `filter` are added for legibility, and `_subsetter` in the remote case that all other method names are overriden, in order to not jeopardize the subsetting functionality
|
26
|
+
|
27
|
+
> `_subsetter` is the recommended form to be used when developing a library on top of the sub-setter gem.
|
28
|
+
|
29
|
+
### Private
|
30
|
+
|
31
|
+
- `_subsetter_for(Class)`: returns an instance of the designated subsetting class for the given `Class`
|
32
|
+
- `_has_subsetter_for(Class)`: returns true if for the passed class a corresponding subsetter class exists, false otherwise
|
33
|
+
|
34
|
+
License
|
35
|
+
-------
|
36
|
+
|
37
|
+
GPL
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/sub-setter.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# SubSetter Pattern implementation for Ruby
|
2
|
+
#
|
3
|
+
# As described in SubSetter Pattern for Ruby
|
4
|
+
# http://xaviervia.com.ar/patterns/sub-setter
|
5
|
+
module SubSetter
|
6
|
+
# Gets the subsetter for self
|
7
|
+
#
|
8
|
+
# The default behaviour is, for class Klass, to look for a
|
9
|
+
# class named SubSetter::Klass; for a class Library::Klass, a class
|
10
|
+
# named SubSetter::Library::Klass, following the criteria described
|
11
|
+
# in http://xaviervia.com.ar/patterns/sub-setter
|
12
|
+
#
|
13
|
+
# If a SubSetter for the current class is not found, a SubSetter for
|
14
|
+
# the superclass is searched instead, and if is not found in that
|
15
|
+
# class, further in the class hierarchy until a SubSetter is found.
|
16
|
+
def subsetter
|
17
|
+
_subsetter_for(self.class).new self
|
18
|
+
end
|
19
|
+
|
20
|
+
alias :by :subsetter
|
21
|
+
alias :filter :subsetter
|
22
|
+
alias :_subsetter :subsetter
|
23
|
+
|
24
|
+
private
|
25
|
+
# Returns an instance of the designated subsetting class for the
|
26
|
+
# given `Class`
|
27
|
+
def _subsetter_for the_class
|
28
|
+
if RUBY_VERSION.match /1.9/
|
29
|
+
Kernel.raise RuntimeError, "You are awesome. Why on Earth do you want to subset a Basi... Anyway, you rule. Seriously.\nFWI, this is an error, you can't do that. Stop trying. Cheers, xav" if the_class == BasicObject
|
30
|
+
end
|
31
|
+
return eval("SubSetter::#{the_class.name}") if _there_is_subsetter_for? the_class
|
32
|
+
_subsetter_for the_class.superclass
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns true if for the passed class a corresponding subsetter
|
36
|
+
# class exists, false otherwise
|
37
|
+
def _there_is_subsetter_for? the_class
|
38
|
+
unless RUBY_VERSION.match /1.8/
|
39
|
+
return ::SubSetter.const_defined? the_class.name, false unless the_class.name["::"]
|
40
|
+
|
41
|
+
parts = the_class.name.split("::")
|
42
|
+
class_name = parts.pop
|
43
|
+
current_module = ::SubSetter
|
44
|
+
while parts.length > 0
|
45
|
+
return false unless current_module.const_defined? parts.first, false
|
46
|
+
current_module = current_module.const_get parts.shift, false
|
47
|
+
end
|
48
|
+
current_module.const_defined? class_name, false
|
49
|
+
else
|
50
|
+
return ::SubSetter.const_defined? the_class.name unless the_class.name["::"]
|
51
|
+
|
52
|
+
parts = the_class.name.split("::")
|
53
|
+
class_name = parts.pop
|
54
|
+
current_module = ::SubSetter
|
55
|
+
while parts.length > 0
|
56
|
+
return false unless current_module.const_defined? parts.first
|
57
|
+
current_module = current_module.const_get parts.shift
|
58
|
+
end
|
59
|
+
current_module.const_defined? class_name
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
public
|
64
|
+
|
65
|
+
# SubSetter for Object: placeholder mostly
|
66
|
+
class Object
|
67
|
+
def initialize instance
|
68
|
+
@source = instance
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require "sub-setter/sub-setter"
|
2
|
+
|
3
|
+
describe SubSetter do
|
4
|
+
shared_examples_for "any subsetting" do
|
5
|
+
it "should call _subsetter_for with the class as argument" do
|
6
|
+
the_object = Object.new
|
7
|
+
the_object.extend SubSetter
|
8
|
+
the_object.should_receive(:_subsetter_for).with(Object).and_return(SubSetter::Object)
|
9
|
+
the_object.send @method
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should call .new on the returned class" do
|
13
|
+
the_object = Object.new
|
14
|
+
the_object.extend SubSetter
|
15
|
+
SubSetter::Object.should_receive(:new).with(the_object)
|
16
|
+
the_object.send @method
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return an instance of the designated subsetter" do
|
20
|
+
the_object = Object.new
|
21
|
+
the_object.extend SubSetter
|
22
|
+
the_object.send(@method).should be_instance_of SubSetter::Object
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#_subsetter" do
|
27
|
+
before { @method = :_subsetter }
|
28
|
+
it_behaves_like "any subsetting"
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#subsetter" do
|
32
|
+
before { @method = :subsetter }
|
33
|
+
it_behaves_like "any subsetting"
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#filter" do
|
37
|
+
before { @method = :filter }
|
38
|
+
it_behaves_like "any subsetting"
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#by" do
|
42
|
+
before { @method = :by }
|
43
|
+
it_behaves_like "any subsetting"
|
44
|
+
end
|
45
|
+
|
46
|
+
# Priv8 methods
|
47
|
+
describe "#_there_is_subsetter_for?" do
|
48
|
+
context "there it no subsetter for this class" do
|
49
|
+
it "should return false" do
|
50
|
+
class Klass
|
51
|
+
include SubSetter
|
52
|
+
def test_me
|
53
|
+
_there_is_subsetter_for? self.class
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Klass.new.test_me.should === false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "there is a subsetter for this class" do
|
62
|
+
it "should return true" do
|
63
|
+
module SubSetter; class Klass; end; end
|
64
|
+
class Klass
|
65
|
+
include SubSetter
|
66
|
+
def test_me
|
67
|
+
_there_is_subsetter_for? self.class
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Klass.new.test_me.should === true
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#_subsetter_for" do
|
77
|
+
context "this is an Object" do
|
78
|
+
it "should return SubSetter::Object" do
|
79
|
+
the_object = Object.new
|
80
|
+
the_object.extend SubSetter
|
81
|
+
class << the_object
|
82
|
+
def test_me
|
83
|
+
_subsetter_for self.class
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
the_object.test_me.should == SubSetter::Object
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
if RUBY_VERSION.match /1.9/
|
92
|
+
context "this is a BasicObject" do
|
93
|
+
it "should raise an awesome exception" do
|
94
|
+
ay = BasicObject.new
|
95
|
+
class BasicObject
|
96
|
+
include ::SubSetter
|
97
|
+
end
|
98
|
+
|
99
|
+
def ay.genius
|
100
|
+
_subsetter_for BasicObject
|
101
|
+
end
|
102
|
+
|
103
|
+
expect { ay.genius
|
104
|
+
}.to raise_error RuntimeError, "You are awesome. Why on Earth do you want to subset a Basi... Anyway, you rule. Seriously.\nFWI, this is an error, you can't do that. Stop trying. Cheers, xav"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "there is a subsetter for the superclass" do
|
110
|
+
it "should return the superclass's subsetter" do
|
111
|
+
class SuperKlass; end
|
112
|
+
class ActualKlass < SuperKlass; end
|
113
|
+
|
114
|
+
module SubSetter; class SuperKlass; end; end
|
115
|
+
|
116
|
+
klassy = ActualKlass.new
|
117
|
+
klassy.extend SubSetter
|
118
|
+
|
119
|
+
def klassy.test_me
|
120
|
+
_subsetter_for self.class
|
121
|
+
end
|
122
|
+
|
123
|
+
klassy.test_me.should == SubSetter::SuperKlass
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "there is a subsetter for the supersuperclass" do
|
128
|
+
it "should return the supersuperclass's subsetter" do
|
129
|
+
class CoolKlass; end
|
130
|
+
class IMRunningOutOfNamesKlass < CoolKlass; end
|
131
|
+
class WhyWasThatLong < IMRunningOutOfNamesKlass; end
|
132
|
+
|
133
|
+
module SubSetter; class CoolKlass; end; end
|
134
|
+
|
135
|
+
klick = WhyWasThatLong.new
|
136
|
+
klick.extend SubSetter
|
137
|
+
|
138
|
+
def klick.test_me; _subsetter_for self.class; end
|
139
|
+
|
140
|
+
klick.test_me.should == SubSetter::CoolKlass
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "has two superclasses but non of them has a subsetter" do
|
145
|
+
it "should return SubSetter::Object" do
|
146
|
+
class SuperSuper; end
|
147
|
+
class Superr < SuperSuper; end
|
148
|
+
class Aktual < Superr; end
|
149
|
+
|
150
|
+
kla = Aktual.new
|
151
|
+
kla.extend SubSetter
|
152
|
+
def kla.test; _subsetter_for self.class; end
|
153
|
+
|
154
|
+
kla.test.should == SubSetter::Object
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context "there is a subsetter for this class" do
|
159
|
+
it "should return that subsetter" do
|
160
|
+
class Hey; end
|
161
|
+
module SubSetter; class Hey; end; end
|
162
|
+
|
163
|
+
hi = Hey.new
|
164
|
+
hi.extend SubSetter
|
165
|
+
def hi.t; _subsetter_for self.class; end
|
166
|
+
|
167
|
+
hi.t.should == SubSetter::Hey
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "this class is within several modules" do
|
172
|
+
context "there is a subsetter for this class" do
|
173
|
+
it "should return that subsetter" do
|
174
|
+
module One; module Two; module Three; class AAA;
|
175
|
+
end; end; end; end
|
176
|
+
|
177
|
+
module SubSetter; module One; module Two; module Three;
|
178
|
+
class AAA;
|
179
|
+
end; end; end; end; end
|
180
|
+
|
181
|
+
deeeep = One::Two::Three::AAA.new
|
182
|
+
deeeep.extend SubSetter
|
183
|
+
|
184
|
+
def deeeep.dowwwn; _subsetter_for self.class; end
|
185
|
+
|
186
|
+
deeeep.dowwwn.should == SubSetter::One::Two::Three::AAA
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe SubSetter::Object do
|
194
|
+
describe "#new" do
|
195
|
+
it "should require an argument" do
|
196
|
+
SubSetter::Object.new "an argument"
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should store the argument in the @source variable" do
|
200
|
+
module SubSetter
|
201
|
+
class Object
|
202
|
+
def reveal_source
|
203
|
+
@source
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
the_var = %w{1 2 3 4}
|
209
|
+
subsetter_the_var = SubSetter::Object.new the_var
|
210
|
+
subsetter_the_var.reveal_source.should === the_var
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
data/sub-setter.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "sub-setter/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "sub-setter"
|
7
|
+
s.version = Sub::Setter::VERSION
|
8
|
+
s.authors = ["Xavier Via"]
|
9
|
+
s.email = ["xavierviacanel@gmail.com"]
|
10
|
+
s.homepage = "http://xaviervia.com.ar/patterns/sub-setter"
|
11
|
+
s.summary = %q{SubSetter Design Pattern implementation for Ruby}
|
12
|
+
s.description = %q{SubSetter Design Pattern implementation for Ruby}
|
13
|
+
|
14
|
+
s.rubyforge_project = "sub-setter"
|
15
|
+
|
16
|
+
s.add_development_dependency "rspec"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
# specify any dependencies here; for example:
|
24
|
+
# s.add_development_dependency "rspec"
|
25
|
+
# s.add_runtime_dependency "rest-client"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sub-setter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Xavier Via
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-06 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &70621040 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70621040
|
25
|
+
description: SubSetter Design Pattern implementation for Ruby
|
26
|
+
email:
|
27
|
+
- xavierviacanel@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- README.md
|
35
|
+
- Rakefile
|
36
|
+
- lib/sub-setter.rb
|
37
|
+
- lib/sub-setter/object.rb
|
38
|
+
- lib/sub-setter/sub-setter.rb
|
39
|
+
- lib/sub-setter/version.rb
|
40
|
+
- spec/sub-setter/object_spec.rb
|
41
|
+
- spec/sub-setter/sub-setter_spec.rb
|
42
|
+
- sub-setter.gemspec
|
43
|
+
homepage: http://xaviervia.com.ar/patterns/sub-setter
|
44
|
+
licenses: []
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
require_paths:
|
48
|
+
- lib
|
49
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
56
|
+
none: false
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project: sub-setter
|
63
|
+
rubygems_version: 1.8.15
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: SubSetter Design Pattern implementation for Ruby
|
67
|
+
test_files: []
|