mixers 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{README → README.rdoc} +0 -0
- data/lib/mixers/advisable.rb +44 -112
- data/lib/mixers/expirable.rb +18 -9
- data/lib/mixers/{preinitilizable.rb → preinitialize.rb} +1 -0
- data/lib/mixers/registerable.rb +3 -2
- data/meta/authors +1 -0
- data/meta/repository +1 -0
- data/meta/sites/api +1 -0
- data/meta/sites/blog +1 -0
- data/meta/{resource → sites}/development +0 -0
- data/meta/sites/documentation +1 -0
- data/meta/{homepage → sites/homepage} +0 -0
- data/meta/sites/mail +1 -0
- data/meta/sites/source +1 -0
- data/meta/sites/wiki +1 -0
- data/meta/version +1 -1
- data/qed/01_advisable.rdoc +71 -0
- data/qed/02_cloneable.rdoc +46 -0
- data/qed/03_enumargs.rdoc +75 -0
- data/qed/04_equitable.rdoc +35 -0
- data/qed/05_instantiable.rdoc +42 -0
- data/qed/06_expirable.rdoc +32 -0
- data/qed/08_ostructable.rdoc +23 -0
- data/qed/09_preinitialize.rdoc +28 -0
- data/qed/10_registerable.rdoc +40 -0
- metadata +28 -14
- data/meta/resource/homepage +0 -1
data/{README → README.rdoc}
RENAMED
File without changes
|
data/lib/mixers/advisable.rb
CHANGED
@@ -1,9 +1,3 @@
|
|
1
|
-
# Copyright (c) 2007 Thomas Sawyer
|
2
|
-
|
3
|
-
require 'facets/kernel/method'
|
4
|
-
require 'facets/module/instance_method'
|
5
|
-
require 'facets/unboundmethod/arguments'
|
6
|
-
|
7
1
|
# = Advisable
|
8
2
|
#
|
9
3
|
# Advisable provides a means of using before, after and
|
@@ -11,138 +5,76 @@ require 'facets/unboundmethod/arguments'
|
|
11
5
|
#
|
12
6
|
module Advisable
|
13
7
|
|
14
|
-
|
15
|
-
base.extend self
|
16
|
-
end
|
8
|
+
require 'facets/proc/bind'
|
17
9
|
|
18
|
-
def
|
19
|
-
|
20
|
-
end
|
21
|
-
|
22
|
-
def advice_after
|
23
|
-
@advice_after ||= {} #Hash.new{|h,k| h[k] = []}
|
24
|
-
end
|
25
|
-
|
26
|
-
def advice_around
|
27
|
-
@advice_around ||= {} #Hash.new{|h,k| h[k] = []}
|
10
|
+
def self.append_features(base)
|
11
|
+
base.extend(self)
|
28
12
|
end
|
29
13
|
|
30
14
|
def before(meth, &block)
|
31
|
-
|
32
|
-
|
33
|
-
(advice_before[meth.to_sym] ||= []) << name
|
15
|
+
advice_before[meth.to_sym] << block
|
16
|
+
method_added(meth) if method_defined?(meth)
|
34
17
|
end
|
35
18
|
|
36
19
|
def after(meth, &block)
|
37
|
-
|
38
|
-
|
39
|
-
(advice_after[meth.to_sym] ||= []) << name
|
20
|
+
advice_after[meth.to_sym] << block
|
21
|
+
method_added(meth) if method_defined?(meth)
|
40
22
|
end
|
41
23
|
|
42
24
|
def around(meth, &block)
|
43
|
-
|
44
|
-
|
45
|
-
(advice_around[meth.to_sym] ||= []) << name
|
25
|
+
advice_around[meth.to_sym] << block
|
26
|
+
method_added(meth) if method_defined?(meth)
|
46
27
|
end
|
47
28
|
|
48
|
-
|
49
|
-
|
50
|
-
def advise(meth)
|
51
|
-
#return false if defined?(meth_origin)
|
52
|
-
args = instance_method(meth).arguments
|
53
|
-
|
54
|
-
module_eval(<<-END, __FILE__, __LINE__)
|
55
|
-
alias_method '#{meth}_origin', '#{meth}'
|
56
|
-
def #{meth}(#{args})
|
57
|
-
target = method!('#{meth}_origin')
|
58
|
-
|
59
|
-
unless target.advised
|
60
|
-
ancs = self.class.ancestors.select{ |anc| anc.respond_to?(:advice_before) }
|
61
|
-
target.advice_before = ancs.collect{ |anc| anc.advice_before[:'#{meth}'] }
|
62
|
-
target.advice_after = ancs.collect{ |anc| anc.advice_after[:'#{meth}'] }
|
63
|
-
target.advice_around = ancs.collect{ |anc| anc.advice_around[:'#{meth}'] }
|
64
|
-
target.advised = true
|
65
|
-
end
|
66
|
-
|
67
|
-
target.call_with_advice(self, *[#{args}])
|
68
|
-
end
|
69
|
-
END
|
29
|
+
def advice_before
|
30
|
+
@@advice_before ||= Hash.new{|h,k| h[k] = []}
|
70
31
|
end
|
71
32
|
|
72
|
-
|
73
|
-
|
74
|
-
#after :method_added do |meth|
|
75
|
-
# advise(meth) unless defined?("#{meth}_orig")
|
76
|
-
#end
|
77
|
-
|
78
|
-
def method_added(meth)
|
79
|
-
return if meth == :method_added
|
80
|
-
@added_stack ||= []
|
81
|
-
return if @added_stack.last == meth
|
82
|
-
return if /_(origin)$/ =~ meth.to_s
|
83
|
-
return if /:(before|after|around)/ =~ meth.to_s
|
84
|
-
@added_stack << meth
|
85
|
-
#return if instance_methods(false).include?("#{meth}_orig")
|
86
|
-
advise(meth)
|
87
|
-
@added_stack.pop
|
33
|
+
def advice_after
|
34
|
+
@@advice_after ||= Hash.new{|h,k| h[k] = []}
|
88
35
|
end
|
89
36
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
attr_accessor :advised
|
95
|
-
|
96
|
-
attr_reader :advice_before
|
97
|
-
attr_reader :advice_after
|
98
|
-
attr_reader :advice_around
|
99
|
-
|
100
|
-
def advised?
|
101
|
-
@advised
|
102
|
-
end
|
37
|
+
def advice_around
|
38
|
+
@@advice_around ||= Hash.new{|h,k| h[k] = []}
|
39
|
+
end
|
103
40
|
|
104
|
-
|
105
|
-
|
106
|
-
|
41
|
+
# TODO: Should around advice be fed the result of the last around advice?
|
42
|
+
def method_added(meth)
|
43
|
+
@method_added_stack ||= []
|
44
|
+
return if @method_added_stack.last == meth
|
45
|
+
@method_added_stack << meth
|
107
46
|
|
108
|
-
|
47
|
+
if advice_before.key?(meth) or advice_after.key?(meth)
|
109
48
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
obj.send(name, *args, &blk)
|
114
|
-
end
|
49
|
+
before = advice_before[meth] || []
|
50
|
+
around = advice_around[meth] || []
|
51
|
+
after = advice_after[meth] || []
|
115
52
|
|
116
|
-
|
117
|
-
|
118
|
-
target = lambda_target(obj, name, target, *args, &blk)
|
119
|
-
end
|
120
|
-
ret = target.call
|
53
|
+
alias_method "#{meth}:advised", meth
|
54
|
+
target = instance_method("#{meth}:advised")
|
121
55
|
|
122
|
-
|
123
|
-
|
124
|
-
|
56
|
+
define_method meth do |*a, &b|
|
57
|
+
before.reverse_each do |block|
|
58
|
+
block.bind(self).call(*a,&b)
|
59
|
+
end
|
60
|
+
if around.empty?
|
61
|
+
result = target.bind(self).call(*a,&b)
|
62
|
+
else
|
63
|
+
around.each do |block|
|
64
|
+
result = block.call(target.bind(self),*a,&b)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
after.each do |block|
|
68
|
+
block.bind(self).call(*a,&b)
|
69
|
+
end
|
70
|
+
result
|
125
71
|
end
|
126
|
-
|
127
|
-
return ret
|
128
72
|
end
|
129
73
|
|
130
|
-
|
131
|
-
|
132
|
-
# Using separate method for this prevents infinite loop.
|
133
|
-
|
134
|
-
def lambda_target(obj, name, target, *args, &blk)
|
135
|
-
lambda do
|
136
|
-
#advice.call(target, *args, &blk)
|
137
|
-
obj.send(name, target, *args, &blk)
|
138
|
-
end
|
139
|
-
end
|
74
|
+
super(meth)
|
140
75
|
|
76
|
+
@method_added_stack.pop
|
141
77
|
end
|
142
78
|
|
143
79
|
end
|
144
80
|
|
145
|
-
class Method #:nodoc:
|
146
|
-
include Advisable::Method
|
147
|
-
end
|
148
|
-
|
data/lib/mixers/expirable.rb
CHANGED
@@ -4,25 +4,34 @@
|
|
4
4
|
#
|
5
5
|
module Expirable
|
6
6
|
|
7
|
-
attr_accessor :
|
7
|
+
attr_accessor :expiration
|
8
8
|
|
9
9
|
# Set the expires timeout for this entry.
|
10
10
|
|
11
|
-
def
|
12
|
-
|
11
|
+
def expiration=(time)
|
12
|
+
case time
|
13
|
+
when Time, Date, DateTime
|
14
|
+
@expiration = time
|
15
|
+
else
|
16
|
+
@expiration = Time.now + time
|
17
|
+
end
|
13
18
|
end
|
14
19
|
|
15
|
-
#
|
16
|
-
#
|
20
|
+
#def expires_after(timeout = 86400)
|
21
|
+
# @expires = Time.now + timeout
|
22
|
+
#end
|
17
23
|
|
18
|
-
|
19
|
-
|
20
|
-
|
24
|
+
## Set the expire timeout for this entry. The timeout happens
|
25
|
+
## after (base + rand(spread)) seconds.
|
26
|
+
#
|
27
|
+
#def expires_spread(base, spread)
|
28
|
+
# @expires = Time.now + base + rand(spread)
|
29
|
+
#end
|
21
30
|
|
22
31
|
# Is this entry expired?
|
23
32
|
|
24
33
|
def expired?
|
25
|
-
if @
|
34
|
+
if @expiration.nil? or (Time.now > @expiration)
|
26
35
|
return true
|
27
36
|
else
|
28
37
|
return false
|
data/lib/mixers/registerable.rb
CHANGED
@@ -4,9 +4,9 @@ module Registerable
|
|
4
4
|
|
5
5
|
# Register format names.
|
6
6
|
|
7
|
-
def register(*names)
|
7
|
+
def register(obj, *names)
|
8
8
|
names.each do |name|
|
9
|
-
registry[name
|
9
|
+
registry[name] = obj
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -27,3 +27,4 @@ module Registerable
|
|
27
27
|
end
|
28
28
|
|
29
29
|
end
|
30
|
+
|
data/meta/authors
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Thomas Sawyer
|
data/meta/repository
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
git://github.com/rubyworks/mixers.git
|
data/meta/sites/api
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
http://rubyworks.github.com/mixers/rdoc
|
data/meta/sites/blog
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
http://rubyworks.github.com/
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
http://wiki.github.com/rubyworks/mixers
|
File without changes
|
data/meta/sites/mail
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
http://groups.google.com/group/rubyworks-mailinglist
|
data/meta/sites/source
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
http://github.com/rubyworks/mixers
|
data/meta/sites/wiki
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
http://wiki.github.com/rubyworks/mixers
|
data/meta/version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.1.0
|
@@ -0,0 +1,71 @@
|
|
1
|
+
= Advisable
|
2
|
+
|
3
|
+
Require the library.
|
4
|
+
|
5
|
+
require 'mixers/advisable'
|
6
|
+
|
7
|
+
We will use this fixture.
|
8
|
+
|
9
|
+
class X
|
10
|
+
include Advisable
|
11
|
+
|
12
|
+
attr_reader :out
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@out = []
|
16
|
+
end
|
17
|
+
|
18
|
+
before :x do
|
19
|
+
@out << "BEFORE X#x"
|
20
|
+
end
|
21
|
+
|
22
|
+
after :x do
|
23
|
+
@out << "AFTER X#x"
|
24
|
+
end
|
25
|
+
|
26
|
+
def x
|
27
|
+
@out << "X#x"
|
28
|
+
"x"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Our results:
|
33
|
+
|
34
|
+
x = X.new
|
35
|
+
r = x.x
|
36
|
+
o = x.out
|
37
|
+
r.assert == "x"
|
38
|
+
o.assert == ["BEFORE X#x", "X#x", "AFTER X#x"]
|
39
|
+
|
40
|
+
And let's see what a subclass of the example does:
|
41
|
+
|
42
|
+
class Y < X
|
43
|
+
before :x do
|
44
|
+
@out << "BEFORE Y#x"
|
45
|
+
end
|
46
|
+
|
47
|
+
after :x do
|
48
|
+
@out << "AFTER Y#x"
|
49
|
+
end
|
50
|
+
|
51
|
+
around :x do |target|
|
52
|
+
"{" + target.call + "}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def x
|
56
|
+
@out << "Y#x"
|
57
|
+
super
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
y = Y.new
|
62
|
+
|
63
|
+
The result of #x should be a bracketed "x".
|
64
|
+
|
65
|
+
y.x.assert == "{x}"
|
66
|
+
|
67
|
+
Then the out variable should indicate where the call has been.
|
68
|
+
|
69
|
+
y.out.assert == ["BEFORE Y#x", "BEFORE X#x", "Y#x", "X#x", "AFTER X#x", "AFTER Y#x"]
|
70
|
+
|
71
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
= Cloneable
|
2
|
+
|
3
|
+
Require the library.
|
4
|
+
|
5
|
+
require 'mixers/cloneable'
|
6
|
+
|
7
|
+
We'll use this dummy class.
|
8
|
+
|
9
|
+
class Foo
|
10
|
+
include Cloneable
|
11
|
+
def initialize
|
12
|
+
@bar=[]
|
13
|
+
end
|
14
|
+
def bar_id
|
15
|
+
@bar.object_id
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Try #dup.
|
20
|
+
|
21
|
+
a = Foo.new
|
22
|
+
b = a.dup
|
23
|
+
b.bar_id.refute == a.bar_id
|
24
|
+
|
25
|
+
a.taint
|
26
|
+
b = a.dup
|
27
|
+
b.assert.tainted?
|
28
|
+
|
29
|
+
a.freeze
|
30
|
+
b = a.dup
|
31
|
+
b.refute.frozen?
|
32
|
+
|
33
|
+
Note try #clone.
|
34
|
+
|
35
|
+
a = Foo.new
|
36
|
+
b = a.clone
|
37
|
+
b.bar_id.refute == a.bar_id
|
38
|
+
|
39
|
+
a.taint
|
40
|
+
b = a.dup
|
41
|
+
b.assert.tainted?
|
42
|
+
|
43
|
+
a.freeze
|
44
|
+
b = a.clone
|
45
|
+
b.assert.frozen?
|
46
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
= Enumerable::Arguments
|
2
|
+
|
3
|
+
Require the library.
|
4
|
+
|
5
|
+
require 'mixers/enumargs'
|
6
|
+
|
7
|
+
This will serve as our example class.
|
8
|
+
|
9
|
+
class PlusArray
|
10
|
+
include Enumerable::Arguments
|
11
|
+
|
12
|
+
def initialize(arr)
|
13
|
+
@arr = arr
|
14
|
+
end
|
15
|
+
|
16
|
+
def each(n=0)
|
17
|
+
@arr.each{ |e| yield(e+n) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Now Enumerable methods such as #map and #collect
|
22
|
+
take an argument as well.
|
23
|
+
|
24
|
+
t = PlusArray.new([1,2,3])
|
25
|
+
t.collect(4){ |e| e }.assert == [5,6,7]
|
26
|
+
|
27
|
+
Filtering methods such as #select and reject work
|
28
|
+
as well.
|
29
|
+
|
30
|
+
t = PlusArray.new([1,2,3])
|
31
|
+
t.select(4){ |x| x == 6 }.assert == [6]
|
32
|
+
|
33
|
+
t = PlusArray.new([1,2,3])
|
34
|
+
t.reject(4){ |x| x == 6 }.assert == [5,7]
|
35
|
+
|
36
|
+
We can covert to an array using #to_a with an argument.
|
37
|
+
|
38
|
+
t = PlusArray.new([1,2,3])
|
39
|
+
t.to_a(4).assert == [5,6,7]
|
40
|
+
|
41
|
+
We can get the minimum value using #min.
|
42
|
+
|
43
|
+
t = PlusArray.new([1,2,3])
|
44
|
+
t.min(4).assert == 5
|
45
|
+
|
46
|
+
And get the maximum value using #min.
|
47
|
+
|
48
|
+
t = PlusArray.new([1,2,3])
|
49
|
+
t.max(4).assert == 7
|
50
|
+
|
51
|
+
Methods that already take and argument, now take two
|
52
|
+
such as #include?
|
53
|
+
|
54
|
+
t = PlusArray.new([1,2,3])
|
55
|
+
t.assert.include?(7,4)
|
56
|
+
|
57
|
+
And #each_slice.
|
58
|
+
|
59
|
+
t = PlusArray.new([1,2,3,4])
|
60
|
+
a = []
|
61
|
+
t.each_slice(2,4){ |e,f| a << [e,f] }
|
62
|
+
a.assert == [[5,6],[7,8]]
|
63
|
+
|
64
|
+
The #find method has a slightly different interface
|
65
|
+
than the original Enumerable.
|
66
|
+
|
67
|
+
t = PlusArray.new([1,2,3,4])
|
68
|
+
f = t.find(2, :ifnone=>lambda{:NOPE}) { |a| a == 10 }
|
69
|
+
f.assert == :NOPE
|
70
|
+
|
71
|
+
The #grep method should also work.
|
72
|
+
|
73
|
+
t = PlusArray.new(['a1','b2','a3','b4'])
|
74
|
+
t.grep(/^b/, 'x').assert == ['b2x','b4x']
|
75
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
= Equitqable
|
2
|
+
|
3
|
+
Require the library.
|
4
|
+
|
5
|
+
require 'mixers/equitable'
|
6
|
+
|
7
|
+
We will use this simple class as an example.
|
8
|
+
|
9
|
+
class C
|
10
|
+
include Equitable(:a,:b)
|
11
|
+
|
12
|
+
attr_accessor :a, :b
|
13
|
+
|
14
|
+
def initialize(a,b)
|
15
|
+
@a = a
|
16
|
+
@b = b
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Now, if two instance of our sample class +C+ have
|
21
|
+
equal attributes +@a+ and +@b+ then they will
|
22
|
+
be equal.
|
23
|
+
|
24
|
+
c1 = C.new(10,20)
|
25
|
+
c2 = C.new(10,20)
|
26
|
+
c2.assert == c1
|
27
|
+
|
28
|
+
Otherwise they will not be equal.
|
29
|
+
|
30
|
+
c1 = C.new(10, 10)
|
31
|
+
c2 = C.new(10, 20)
|
32
|
+
c2.refute == c1
|
33
|
+
|
34
|
+
|
35
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
= Instantiable
|
2
|
+
|
3
|
+
Require the library.
|
4
|
+
|
5
|
+
require 'mixers/instantiable'
|
6
|
+
|
7
|
+
We will use this module as an example.
|
8
|
+
|
9
|
+
module M
|
10
|
+
include Instantiable
|
11
|
+
|
12
|
+
attr :a
|
13
|
+
|
14
|
+
def initialize(a)
|
15
|
+
@a = a
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
As we can see M is now fully instantiable, as any
|
20
|
+
class would be.
|
21
|
+
|
22
|
+
m = M.new(1)
|
23
|
+
m.a.assert == 1
|
24
|
+
|
25
|
+
We can also use #extend rather than #include and
|
26
|
+
get the same result.
|
27
|
+
|
28
|
+
module N
|
29
|
+
extend Instantiable
|
30
|
+
|
31
|
+
attr :a
|
32
|
+
|
33
|
+
def initialize( a )
|
34
|
+
@a = a
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
As we saw with +M+ so too with +N+.
|
39
|
+
|
40
|
+
n = N.new( 1 )
|
41
|
+
n.a.assert == 1
|
42
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
= Expirable
|
2
|
+
|
3
|
+
Require the library.
|
4
|
+
|
5
|
+
require 'mixers/expirable'
|
6
|
+
|
7
|
+
Example class.
|
8
|
+
|
9
|
+
class X
|
10
|
+
extend Expirable
|
11
|
+
end
|
12
|
+
|
13
|
+
Now the experation can be set to a Time object, or a number of seconds
|
14
|
+
from +Time.now+. For instance, to set the expiration for one second
|
15
|
+
from now:
|
16
|
+
|
17
|
+
X.expiration = 1
|
18
|
+
|
19
|
+
We can see the the object has not yet expired.
|
20
|
+
|
21
|
+
X.refute.expired?
|
22
|
+
|
23
|
+
But if we wait one second.
|
24
|
+
|
25
|
+
sleep 1
|
26
|
+
|
27
|
+
Then it will have expired.
|
28
|
+
|
29
|
+
X.assert.expired?
|
30
|
+
|
31
|
+
Expiration does not invoke a trigger, it is merely queriable.
|
32
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
= OpenStructable
|
2
|
+
|
3
|
+
Require the library.
|
4
|
+
|
5
|
+
require 'mixers/ostructable'
|
6
|
+
|
7
|
+
We will use the simpliest example class:
|
8
|
+
|
9
|
+
class X
|
10
|
+
include OpenStructable
|
11
|
+
end
|
12
|
+
|
13
|
+
x = X.new
|
14
|
+
|
15
|
+
So arbitrary attributes can be added to the object
|
16
|
+
just as if it were an OpenStruct.
|
17
|
+
|
18
|
+
x.a = 1
|
19
|
+
x.b = 2
|
20
|
+
|
21
|
+
x.assert.a == 1
|
22
|
+
x.assert.a == 2
|
23
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
= Preinitialize
|
2
|
+
|
3
|
+
Require the library.
|
4
|
+
|
5
|
+
require 'mixers/preinitialize'
|
6
|
+
|
7
|
+
Use example module.
|
8
|
+
|
9
|
+
module M
|
10
|
+
def preinitialize
|
11
|
+
@a = 23
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Define a class to support it.
|
16
|
+
|
17
|
+
class X
|
18
|
+
include Preinitializable
|
19
|
+
include M
|
20
|
+
def a ; @a ; end
|
21
|
+
end
|
22
|
+
|
23
|
+
The result should be:
|
24
|
+
|
25
|
+
x = X.new
|
26
|
+
x.a.assert == 23
|
27
|
+
|
28
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
= Registerable
|
2
|
+
|
3
|
+
Require the library.
|
4
|
+
|
5
|
+
require 'mixers/registerable'
|
6
|
+
|
7
|
+
Registerable can be used directly.
|
8
|
+
|
9
|
+
module MyStuff
|
10
|
+
extend Registerable
|
11
|
+
end
|
12
|
+
|
13
|
+
MyStuff.register(10, :x)
|
14
|
+
|
15
|
+
Then the MyStuff registry will contain 10 indexed by :x.
|
16
|
+
|
17
|
+
MyStuff.registry[:x].assert == 10
|
18
|
+
|
19
|
+
Registrable can also be used as a base class callback to
|
20
|
+
track subclasses.
|
21
|
+
|
22
|
+
class Abstract
|
23
|
+
extend Registerable
|
24
|
+
|
25
|
+
def self.inherited(base)
|
26
|
+
register(base, base.name.split('::').last.downcase)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Now when we inherit from Abstract, the subclass will
|
31
|
+
be automatically registered.
|
32
|
+
|
33
|
+
class Example < Abstract
|
34
|
+
end
|
35
|
+
|
36
|
+
We see that the class is in the Abstract registry.
|
37
|
+
|
38
|
+
Abstract.registry['example'].assert == Example
|
39
|
+
|
40
|
+
|
metadata
CHANGED
@@ -4,17 +4,17 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 1
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 1.0.0
|
9
|
+
version: 1.1.0
|
10
10
|
platform: ruby
|
11
|
-
authors:
|
12
|
-
|
11
|
+
authors:
|
12
|
+
- Thomas Sawyer
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-05-07 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -29,8 +29,8 @@ executables: []
|
|
29
29
|
|
30
30
|
extensions: []
|
31
31
|
|
32
|
-
extra_rdoc_files:
|
33
|
-
|
32
|
+
extra_rdoc_files: []
|
33
|
+
|
34
34
|
files:
|
35
35
|
- lib/mixers/advisable.rb
|
36
36
|
- lib/mixers/cloneable.rb
|
@@ -40,17 +40,33 @@ files:
|
|
40
40
|
- lib/mixers/hook.rb
|
41
41
|
- lib/mixers/instantiable.rb
|
42
42
|
- lib/mixers/ostructable.rb
|
43
|
-
- lib/mixers/
|
43
|
+
- lib/mixers/preinitialize.rb
|
44
44
|
- lib/mixers/registerable.rb
|
45
|
+
- meta/authors
|
45
46
|
- meta/contact
|
46
47
|
- meta/description
|
47
|
-
- meta/homepage
|
48
48
|
- meta/name
|
49
|
-
- meta/
|
50
|
-
- meta/
|
49
|
+
- meta/repository
|
50
|
+
- meta/sites/api
|
51
|
+
- meta/sites/blog
|
52
|
+
- meta/sites/development
|
53
|
+
- meta/sites/documentation
|
54
|
+
- meta/sites/homepage
|
55
|
+
- meta/sites/mail
|
56
|
+
- meta/sites/source
|
57
|
+
- meta/sites/wiki
|
51
58
|
- meta/suite
|
52
59
|
- meta/summary
|
53
60
|
- meta/version
|
61
|
+
- qed/01_advisable.rdoc
|
62
|
+
- qed/02_cloneable.rdoc
|
63
|
+
- qed/03_enumargs.rdoc
|
64
|
+
- qed/04_equitable.rdoc
|
65
|
+
- qed/05_instantiable.rdoc
|
66
|
+
- qed/06_expirable.rdoc
|
67
|
+
- qed/08_ostructable.rdoc
|
68
|
+
- qed/09_preinitialize.rdoc
|
69
|
+
- qed/10_registerable.rdoc
|
54
70
|
- test/test_advisable.rb
|
55
71
|
- test/test_cloneable.rb
|
56
72
|
- test/test_enumargs.rb
|
@@ -58,7 +74,7 @@ files:
|
|
58
74
|
- test/test_instantiable.rb
|
59
75
|
- test/test_preinitilizable.rb
|
60
76
|
- LICENSE
|
61
|
-
- README
|
77
|
+
- README.rdoc
|
62
78
|
- HISTORY
|
63
79
|
has_rdoc: true
|
64
80
|
homepage: http://rubyworks.github.com/mixers
|
@@ -68,8 +84,6 @@ post_install_message:
|
|
68
84
|
rdoc_options:
|
69
85
|
- --title
|
70
86
|
- Mixers API
|
71
|
-
- --main
|
72
|
-
- README
|
73
87
|
require_paths:
|
74
88
|
- lib
|
75
89
|
required_ruby_version: !ruby/object:Gem::Requirement
|
data/meta/resource/homepage
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
http://rubyworks.github.com/mixers
|