mixers 1.0.0 → 1.1.0
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/{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
|