no_backsies 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,56 @@
1
+ = No Backsies
2
+
3
+ == DESCRIPTION
4
+
5
+ NoBackies is a callback layer built on top of Ruby's built-in callback
6
+ methods. It makes it possible to add new callbacks very easily, without
7
+ having to fuss with more nuanced issues of defining and redefining callback
8
+ methods.
9
+
10
+
11
+ == RESOURCES
12
+
13
+ * home: http://rubyworks.github.com/nobacksies
14
+ * code: http://github.com/rubyworks/nobacksies
15
+ * mail: http://groups.google.com/group/rubyworks-mailinglist
16
+
17
+
18
+ == EXAMPLE
19
+
20
+ Here is an example take from the Anise[http://rubyworks.github.com/anise]
21
+ project.
22
+
23
+ class Y
24
+ include Anise
25
+ include NoBacksies
26
+
27
+ def self.doc(string)
28
+ callback :method_added do |method|
29
+ self.ann(method, :doc=>string)
30
+ end
31
+ end
32
+
33
+ doc "here"
34
+
35
+ def foo; end
36
+ end
37
+
38
+ Y.ann(:foo, :doc) #=> "here"
39
+
40
+
41
+ == INSTALLATION
42
+
43
+ Install the RubyGems package in the usual fahsion.
44
+
45
+ $ gem install nobacksies
46
+
47
+
48
+ == LEGAL
49
+
50
+ (Apache 2.0 License)
51
+
52
+ Copyright (c) 2011 Thomas Sawyer
53
+
54
+ Unless otherwise negotiated with the original author, NoBacksies is
55
+ distributable under the terms of the Apache 2.0 license. See the
56
+ Apache2.txt file for details.
@@ -0,0 +1,289 @@
1
+ # NoBacksies module ecapsulates all supported callback mixins.
2
+ #
3
+ # NoBackseis::Callbacks can be mixed-in and all supported callbacks will
4
+ # be applied to the class or module.
5
+ #
6
+ # class Y
7
+ # include NoBacksies::Callbacks
8
+ #
9
+ # def self.list
10
+ # @list ||= []
11
+ # end
12
+ #
13
+ # callback :method_added do |method|
14
+ # list << method
15
+ # end
16
+ #
17
+ # def foo; end
18
+ # def bar; end
19
+ # end
20
+ #
21
+ # Y.list.assert #=> [:foo, :bar]
22
+ #
23
+ # Using callbacks can easily lead to infinite loops. NoBacksies makes it
24
+ # easier to control callback expression via the #callback_express
25
+ # method.
26
+ #
27
+ # class Z
28
+ # include NoBacksies::Callbacks
29
+ #
30
+ # def self.list
31
+ # @list ||= []
32
+ # end
33
+ #
34
+ # callback :method_added do |method|
35
+ # callback_express :method_added=>false do
36
+ # define_method("#{method}!") do
37
+ # send(method) + "!"
38
+ # end
39
+ # end
40
+ # end
41
+ #
42
+ # def foo; "foo"; end
43
+ # def bar; "bar"; end
44
+ # end
45
+ #
46
+ # y = Y.new
47
+ # y.foo! #=> "foo!"
48
+ #
49
+ # NOTE: Currently the NoBackies module only supports class level callbacks.
50
+ # We will look into adding instance level callbacks in a future version.
51
+ #
52
+ #--
53
+ # TODO: What about adding `super if defined?(super)` to callback methods?
54
+ # Should this be standard? Should it occur before or after? Or should
55
+ # in be controlled via a special callback, e.g. `callback method_added, :super`?
56
+ #++
57
+
58
+ module NoBacksies
59
+
60
+ #
61
+
62
+ module Callbacks
63
+ # Apply all supported callback modules.
64
+ def self.append_features(base)
65
+ base.extend CallbackMethods
66
+ base.extend MethodAdded
67
+ base.extend MethodRemoved
68
+ base.extend MethodUndefined
69
+ base.extend SingletonMethodAdded
70
+ base.extend SingletonMethodRemoved
71
+ base.extend SingletonMethodUndefined
72
+ base.extend ConstMissing
73
+ base.extend Included
74
+ base.extend Extended
75
+ end
76
+ end
77
+
78
+ # The CallbackMethods module adds the callback methods which are used
79
+ # define and access callback definitions. Mixing-in this module is
80
+ # handled automatically, so you do not need to worry with it. In other
81
+ # words, consider the module *private*.
82
+
83
+ module CallbackMethods
84
+ # Define a callback.
85
+ def callback(name, express={}, &block)
86
+ callbacks[name.to_sym] << block
87
+ end
88
+
89
+ #
90
+ def callbacks
91
+ @_callbacks ||= (
92
+ anc = ancestors[1..-1].find do |anc|
93
+ anc.callbacks rescue nil # TODO: Need faster way!
94
+ end
95
+ anc ? anc.callbacks.dup : Hash.new{|h,k| h[k]=[]}
96
+ )
97
+ end
98
+
99
+ # Returns Hash of true/false activity state of callbacks.
100
+ #
101
+ # TODO: Should expression be inherited?
102
+ def callback_express(express={}, &block)
103
+ @_callback_express ||= Hash.new{|h,k| h[k]=true}
104
+
105
+ if block
106
+ tmp = @_callback_express.dup
107
+ express.each{ |k,v| @_callback_express[k.to_sym] = !!v }
108
+ block.call
109
+ @_callback_express = tmp
110
+ else
111
+ express.each{ |k,v| @_callback_express[k.to_sym] = !!v }
112
+ end
113
+
114
+ @_callback_express
115
+ end
116
+ end
117
+
118
+ # Callback system for #method_added.
119
+ module MethodAdded
120
+ #
121
+ def self.append_features(base)
122
+ base.extend CallbackMethods
123
+ base.extend self
124
+ end
125
+
126
+ #
127
+ def method_added(method)
128
+ return unless callback_express[:method_added]
129
+ callbacks[:method_added].each do |block|
130
+ block.call(method)
131
+ end
132
+ end
133
+ end
134
+
135
+ # Callback system for #method_removed.
136
+ module MethodRemoved
137
+ #
138
+ def self.append_features(base)
139
+ base.extend CallbackMethods
140
+ base.extend self
141
+ end
142
+
143
+ #
144
+ def method_removed(method)
145
+ return unless callback_express[:method_removed]
146
+ callbacks[:method_removed].each do |block|
147
+ block.call(method)
148
+ end
149
+ end
150
+ end
151
+
152
+ # Callback system for #method_removed.
153
+ module MethodUndefined
154
+ #
155
+ def self.append_features(base)
156
+ base.extend CallbackMethods
157
+ base.extend self
158
+ end
159
+
160
+ #
161
+ def method_undefined(method)
162
+ return unless callback_express[:method_undefined]
163
+ callbacks[:method_undefined].each do |block|
164
+ block.call(method)
165
+ end
166
+ end
167
+ end
168
+
169
+ # Callback system for #method_added.
170
+ module SingletonMethodAdded
171
+ #
172
+ def self.append_features(base)
173
+ base.extend CallbackMethods
174
+ base.extend self
175
+ end
176
+
177
+ #
178
+ def singleton_method_added(method)
179
+ return unless callback_express[:singleton_method_added]
180
+ callbacks[:singleton_method_added].each do |block|
181
+ block.call(method)
182
+ end
183
+ end
184
+ end
185
+
186
+ # Callback system for #method_removed.
187
+ module SingletonMethodRemoved
188
+ #
189
+ def self.append_features(base)
190
+ base.extend CallbackMethods
191
+ base.extend self
192
+ end
193
+
194
+ #
195
+ def singleton_method_removed(method)
196
+ return unless callback_express[:singleton_method_removed]
197
+ callbacks[:singleton_method_removed].each do |block|
198
+ block.call(method)
199
+ end
200
+ end
201
+ end
202
+
203
+ # Callback system for #method_removed.
204
+ module SingletonMethodUndefined
205
+ #
206
+ def self.append_features(base)
207
+ base.extend CallbackMethods
208
+ base.extend self
209
+ end
210
+
211
+ #
212
+ def singleton_method_undefined(method)
213
+ return unless callback_express[:singleton_method_undefined]
214
+ callbacks[:singleton_method_undefined].each do |block|
215
+ block.call(method)
216
+ end
217
+ end
218
+ end
219
+
220
+ # Callback system for #const_missing.
221
+ module ConstMissing
222
+ #
223
+ def self.append_features(base)
224
+ base.extend CallbackMethods
225
+ base.extend self
226
+ end
227
+
228
+ #
229
+ def const_missing(const)
230
+ return unless callback_express[:cont_missing]
231
+ callbacks[:const_missing].each do |block|
232
+ block.call(const)
233
+ end
234
+ end
235
+ end
236
+
237
+ # Callback system for #included.
238
+ module Included
239
+ #
240
+ def self.append_features(base)
241
+ base.extend CallbackMethods
242
+ base.extend self
243
+ end
244
+
245
+ #
246
+ def included(mod)
247
+ return unless callback_express[:included]
248
+ callbacks[:included].each do |block|
249
+ block.call(mod)
250
+ end
251
+ end
252
+ end
253
+
254
+ # Callback system for #extended.
255
+ module Extended
256
+ #
257
+ def self.append_features(base)
258
+ base.extend CallbackMethods
259
+ base.extend self
260
+ end
261
+
262
+ #
263
+ def extended(mod)
264
+ return unless callback_express[:extended]
265
+ callbacks[:extended].each do |block|
266
+ block.call(mod)
267
+ end
268
+ end
269
+ end
270
+
271
+ # Callback system for #inherited.
272
+ module Inherited
273
+ #
274
+ def self.append_features(base)
275
+ base.extend CallbackMethods
276
+ base.extend self
277
+ end
278
+
279
+ #
280
+ def extended(mod)
281
+ return unless callback_express[:inherited]
282
+ callbacks[:inherited].each do |block|
283
+ block.call(mod)
284
+ end
285
+ end
286
+ end
287
+
288
+ end
289
+
@@ -0,0 +1,28 @@
1
+ = Basic Example
2
+
3
+ First require the 'nobacksies' library.
4
+
5
+ require 'no_backsies'
6
+
7
+ Include the Callbacks module in a class and define
8
+ a callback procedure.
9
+
10
+ class Y
11
+ include NoBacksies::Callbacks
12
+
13
+ def self.list
14
+ @list ||= []
15
+ end
16
+
17
+ callback :method_added do |method|
18
+ list << method
19
+ end
20
+
21
+ def foo; end
22
+ def bar; end
23
+ end
24
+
25
+ We can see that +list+ holds the methods added.
26
+
27
+ Y.list.assert == [:foo, :bar]
28
+
@@ -0,0 +1,38 @@
1
+ = Callback Expression
2
+
3
+ NoBacksies makes it easier to control callback expression. This
4
+ is useful in the prevention of infinite recursion. For instance,
5
+ infinite recursion is a common problem when a +method_added+ callback
6
+ defines a new method.
7
+
8
+ Here is an example that demonstrates how to work around this problem
9
+ using the +callback_express+ method.
10
+
11
+ class Z
12
+ include NoBacksies::Callbacks
13
+
14
+ def self.list
15
+ @list ||= []
16
+ end
17
+
18
+ callback :method_added do |method|
19
+ callback_express :method_added=>false do
20
+ define_method("#{method}!") do
21
+ send(method) + "!"
22
+ end
23
+ end
24
+ end
25
+
26
+ def foo; "foo"; end
27
+ def bar; "bar"; end
28
+ end
29
+
30
+ In this example, a new `Z` object will get an automatically defined bang method
31
+ for every explicitly defined method.
32
+
33
+ z = Z.new
34
+ z.foo #=> "foo"
35
+ z.foo! #=> "foo!"
36
+ z.bar #=> "bar"
37
+ z.bar! #=> "bar!"
38
+
@@ -0,0 +1,2 @@
1
+ require 'no_backsies'
2
+
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: no_backsies
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Thomas Sawyer
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-04-29 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: syckle
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: qed
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :development
48
+ version_requirements: *id002
49
+ description: |-
50
+ NoBackies is a callback layer built on top of Ruby's built-in callback
51
+ methods. It makes it possible to add new callbacks very easily, without
52
+ having to fuss with more nuanced issues of defining and redefining callback
53
+ methods.
54
+ email: transfire@gmail.com
55
+ executables: []
56
+
57
+ extensions: []
58
+
59
+ extra_rdoc_files:
60
+ - README.rdoc
61
+ files:
62
+ - lib/no_backsies.rb
63
+ - qed/01_example.rdoc
64
+ - qed/02_express.rdoc
65
+ - qed/applique/no_backsies.rb
66
+ - README.rdoc
67
+ has_rdoc: true
68
+ homepage: http://rubyworks.github.com/nobacksies
69
+ licenses: []
70
+
71
+ post_install_message:
72
+ rdoc_options:
73
+ - --title
74
+ - NoBacksies API
75
+ - --main
76
+ - README.rdoc
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ hash: 3
85
+ segments:
86
+ - 0
87
+ version: "0"
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 3
94
+ segments:
95
+ - 0
96
+ version: "0"
97
+ requirements: []
98
+
99
+ rubyforge_project: no_backsies
100
+ rubygems_version: 1.3.7
101
+ signing_key:
102
+ specification_version: 3
103
+ summary: Better handling of Ruby callbacks
104
+ test_files: []
105
+