forwarder19 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,10 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2012 Robert Dober
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10
+
data/README.md ADDED
@@ -0,0 +1,430 @@
1
+ # Forwarder19
2
+
3
+ This implementation is for, and needs, Ruby 1.9.2 or later. For Ruby 1.8.7 please see https://github.com/RobertDober/Forwarder.
4
+
5
+ ## Abstract
6
+
7
+ Ruby's core Forwardable gets the job done(barely), but produces most unreadable code.
8
+
9
+ This is a nonintrusive (as is Forwardable) module that allows to delegate methods to instance variables,
10
+ objects returned by instance\_methods, other methods of the same receiver, the receiver itself, a chain of messages or
11
+ an arbitrary object. Paramters can be provided in the forwarding definition (parially or totally.
12
+
13
+ It also defines after and before filters. and some more sophisticated use cases}
14
+
15
+ ## License
16
+
17
+ This software is released under the very liberal MIT license as indicated in the attached file LICENSE.
18
+ If you do not have the LICENSE file delivered the terms of the license are referred to here:
19
+ http://www.opensource.org/licenses/mit-license.html
20
+
21
+ ## Performance
22
+
23
+ Performance is _normal_, as it is for 'Forwardable' however the goal is to have delegated methods
24
+ to run about as twice as fast as methods created by 'Forwardable.def_delegator'. This seems to be
25
+ a realistic goal as can be seen here: https://github.com/RobertDober/Forwarder19/blob/dev/bm/study.rb
26
+
27
+
28
+ ## Simple Delegation As In Forwardable
29
+
30
+ ```ruby
31
+
32
+ forward <a_message>, to: <target>
33
+ forward <a_message>, to: <target>, as: <translation>
34
+ ```
35
+
36
+ These two forms of the `forward` method, (and *only* these two forms) are directly implemented with
37
+ `def_delegator` method of `Forwardable`, as follows:
38
+
39
+ ```ruby
40
+ def_delegator <target> <a_message>
41
+ def_delegator <translation> <a_message>
42
+ ```
43
+
44
+ Furthermore the `forward_all` method is translated to the `def_delegators` method in the following form,
45
+ thusly
46
+
47
+ ```ruby
48
+ forward_all msg1, msg2, msg3, ..., to: target
49
+ ```
50
+ is implemented as
51
+
52
+ ```ruby
53
+ def_delegators target, msg1, msg2, msg3, ...
54
+ ```
55
+
56
+ ### Additional Features
57
+
58
+ * Parameters (partial or total application)
59
+ * Custom And Chained Targets
60
+ * AOP Filters
61
+ * Helpers
62
+
63
+
64
+ ## Parameters
65
+
66
+
67
+ ### Passing One Parameter
68
+
69
+ Assuming a class `ArrayWrapper` and that their instances wrap the array object via the instance variable
70
+ `@ary` the Smalltalk method `second` can be implemented as follows.
71
+
72
+ ```ruby
73
+ require 'forwarder'
74
+ class ArrayWrapper
75
+ extend Forwarder
76
+ forward :second, to: :@ary, as: :[], with: 1
77
+ ...
78
+ end
79
+ ```
80
+
81
+ The `with` keyword paramter is thus used to provide the first slice of arguments that will be provided
82
+ to the forwarded invocation. This slice will be extended by the actual parameters of the invocation
83
+ of the proxy method (e.g. the instance method defined by the `forward` method itself).
84
+
85
+ ### Passing More Parameters
86
+
87
+ If `with:` is passed an array, it is splatted into the invocation, thus allowing us to pass more than
88
+ one parameter. This becomes clearer with an example.
89
+
90
+ ```ruby
91
+
92
+ forward :add_whitespace_to_punctuation,
93
+ to: :name,
94
+ as: :gsub!,
95
+ with: [ /[,.]\b/, '\& ' ]
96
+ ```
97
+
98
+ ### Partial Application
99
+
100
+ This example gives us the oppurtunity to look at a use case for partial applications. Let us assume that
101
+ we do not always use whitespaces, than we can leave the second paramter to be provided by the invocation
102
+ of the defined forwarder proxy.
103
+
104
+ ```ruby
105
+ forward :add_whitespace_to_punctuation,
106
+ to: :name,
107
+ as: :gsub!,
108
+ with: /[,.]\b/
109
+ ```
110
+
111
+ We can achieve the same as above with the following invocation
112
+
113
+ ```ruby
114
+ o = Name.new( "the,quick, fox." )
115
+ o.add_whitespace_to_punctuation( '\1 ' )
116
+ # name: "the, quick, fox." )
117
+ ```
118
+
119
+ but we can also add a hyphen after interpunctations with this invocation
120
+
121
+ ```ruby
122
+ o = Name.new( "the,quick, fox." )
123
+ o.add_whitespace_to_punctuation( '\1- ' )
124
+ # name: "the,- quick,- fox." )
125
+ ```
126
+
127
+ ### Passing One Array
128
+
129
+ If a real array shall be passed in as one parameter it can be wrapped into an array of one element,
130
+ or the `with_ary:` keyword parameter can be used.
131
+
132
+ Example:
133
+
134
+ ```ruby
135
+ forward :append_suffix, to: :@ary, as: :concat, with: [%w{ my suffix }]
136
+ forward :append_suffix, to: :@ary, as: :concat, with_ary: %w{ my suffix }
137
+ ```
138
+
139
+ ### Passing A Block
140
+
141
+ In case of the necessity to provide a block to the forwarded invocation, it can be specified as the
142
+ block parameter of the `forward` invocation itself.
143
+
144
+ The following example uses inject to compute a sum of elements
145
+
146
+ ```ruby
147
+ forward :sum, to: :elements, as: :inject do |s,e| s+e end
148
+ ```
149
+
150
+ Please note however that common patterns like this one can benefit of the provided
151
+ helpers, in our case it is Integer.sum.
152
+
153
+ ```ruby
154
+ require 'forwarder/helpers/integer/sum'
155
+ ...
156
+ forward :sum, to: :elements, as: :inject &Integer.sum
157
+ # or
158
+ forward :sum, to: :elements, as: :inject, with_block: Integer.sum
159
+ ...
160
+ ```
161
+
162
+ Accounting for different tastes a block can be provided as a block parameter or
163
+ as a `lambda` to the `with_block:` keyword parameter. The later is taking preference
164
+ over the former, which no defined usage of the block in this case (at least for
165
+ the time being).
166
+
167
+ ### Selective Helpers
168
+
169
+ As we do not want to be intrusive the helpers
170
+ have to be requested explicitly.
171
+
172
+ This can be done in three levels of granularity:
173
+
174
+ * Per helper
175
+
176
+ `require 'forwarder/helpers/integer/sum'`
177
+
178
+ * All helpers
179
+
180
+ `require 'forwarder/helpers'`
181
+
182
+ * Per monkey patched class
183
+
184
+ `require 'forwarder/helpers/integer'`
185
+
186
+ ## Custom And Chained Targets
187
+
188
+ So far the `to:` keyword was followed by a symbol or string denoting a _symbolic receiver_, that is
189
+ an instance_variable or method with the denoted name. Custom and Chain Targets are implementing a
190
+ different story.
191
+
192
+ ### Chain Targets
193
+
194
+ Chain Targets are also expressed with the `to:` keyword parameter, but by passing an array of _symbolic receivers_.
195
+ This array will resolve to the final target by sending each message to the result of the preceding message.
196
+ The following example should make this clearer:
197
+
198
+
199
+ ```ruby
200
+ forward :size, to: %w{@content children}
201
+ ```
202
+
203
+ which could have been implemented by hand as follows:
204
+
205
+ ```ruby
206
+ def size
207
+ @content.children.size
208
+ end
209
+ ```
210
+
211
+ ### Custom Targets
212
+
213
+ Allow the user to define a target that cannot be expressed as a _symbolic receiver_.
214
+
215
+ Custom targets are expressed by the means of the `to_object:` keyword parameter.
216
+
217
+
218
+ I want to give two examples here, the first
219
+ using `self`, which evaluates to the module in which `forward` is invoked of course, and might
220
+ thus be used to forward to class instance methods, as in the following example:
221
+
222
+ ```ruby
223
+ class Callback
224
+ def self.instances; @__instances__ ||= [] end
225
+
226
+ def self.register an_instance
227
+ instances << an_instance
228
+ end
229
+
230
+ extend Forwarder
231
+ forward :register, to_object: self
232
+
233
+ def initialize
234
+ register self
235
+ end
236
+ end
237
+ ```
238
+
239
+ But when looking closely one can see that the `self.register` method is just another delegation, thus the whole code
240
+ can be rewritten even more concesily as:
241
+
242
+ ```ruby
243
+ class Callback
244
+ class << self
245
+ extend Forwarder
246
+ forward :<<, to: :instances
247
+
248
+ def instances; @__instances__ ||= [] end
249
+ end
250
+
251
+ extend Forwarder
252
+ forward :register, to_object: self, as: :<<
253
+ end
254
+ ```
255
+
256
+ The second example is a forward to the instance itself, for that purpose the symbol :self
257
+ can be used. The followin is, again, an implementation of Smalltalk's `second` method. But
258
+ here we are defining it on `Array` itself, not a wrapper.
259
+
260
+
261
+ ```ruby
262
+ class Array
263
+ extend Forwarder
264
+ forward :second, to_object: :self, as: :[], with: 1
265
+ ```
266
+
267
+ However the same could be accomplished by using the object/identity helper and the default
268
+ target implementation.
269
+
270
+ ```ruby
271
+ require 'forwarder/helpers/object/identity'
272
+ class Array
273
+ extend Forwarder
274
+ forward :second, to: :identity, as: :[], with: 1
275
+ ```
276
+
277
+ #### Custom Targets And Closures
278
+
279
+ Another application of custom targets would be to hide a enclosed object, but as in the first
280
+ example above, such an object cannot be defined on instance level, but only on class level.
281
+ Assuming that the class itself does not need access to the object enclosed by the closure, one
282
+ could easily implement an instance count for a class as follows:
283
+
284
+
285
+ ```ruby
286
+
287
+ container = []
288
+ forward :register, to_object: container, as: :<<, with: :sentinel
289
+ forward :instance_count, to_object: container, as: :size
290
+
291
+ ```
292
+
293
+ ## AOP Filters
294
+
295
+ Before and After filters are implemented in this version.
296
+
297
+ The respective `before:` and
298
+ `after:` keyword parameters expect lambdas as paramters, but by specifying the `:use_block`
299
+ value the block parameter of the `forward` method can be _abused_ for this purpose.
300
+
301
+ The following examples all operate on a class wrapping a hash instance via the `hash` attribute
302
+ reader. Our first goal is to implement a `max_value` method, that will return the maxium value
303
+ of all values for given keys.
304
+
305
+ ### After Filter
306
+
307
+ The lambda provided by `after:` is applied to the return value of the forwarded invocation.
308
+ The following three examples all implement the `max_value` method correctly.
309
+
310
+
311
+ ```ruby
312
+ forward :max_value, to: :hash, as: :values_at, after: lambda{ |x| x.max }
313
+ forward :max_value, to: :hash, as: :values_at, after: :use_block do | x |
314
+ x.max
315
+ end
316
+ require 'forwarder/helpers/kernel/sendmsg'
317
+ forward :max_value, to: :hash, as: :values_at, after: sendmsg( :max )
318
+ ```
319
+
320
+ N.B. The `Kernel#sendmsg` method is my reply to the hated - by me that is at least - `Symbol#to_proc` kludge and its
321
+ limitations, I will talk about it more in the Helpers section.
322
+
323
+ ### Before Filter.
324
+
325
+ Our next goal is to implement a method `value_of_max` that returns the value for the greatest of
326
+ all provided keys.
327
+
328
+ For this we will use a before filter, its lambda is applied to the arguments
329
+ of the implemented forwarder and the result will be passed in to the forwarded invocation. The pass in
330
+ will use a splash if appropriate.
331
+
332
+
333
+ ```ruby
334
+ forward :value_of_max, to: :hash, as: :[], before: lambda{ |*args| args.max }
335
+ require 'forwarder/helpers/kernel/sendmsg'
336
+ forward :value_of_max, to: :hash, as: :[], before: sendmsg( :max )
337
+ ```
338
+
339
+ ## Helpers
340
+
341
+ *N.B.* These are no longer part of Forwarder19, but have been moved into the gemdependency lab419_core.
342
+
343
+ Helpers define two type of methods. Firstly methods that return lambdas for frequently used
344
+ block patterns, e.g. `Integer.sum`. Secondly methods that are convenient to use inside `forward`
345
+ invocations, but not necessarily only there, e.g. `Kernel#sendmsg` or `Object#identity`.
346
+
347
+ ### Functional Helpers
348
+
349
+ I see this second group, as small as it is, as an important enhancement for the functional
350
+ programming style. The possibilty to nullify a block that is necessarily used in a chain
351
+ of functional calls by passing in `{|x| x.identity}`, `sendmsg(:identity)` or even the
352
+ hated `&:identity` is a recurring pattern.
353
+
354
+ **Warning:** I will become evangelic now.
355
+
356
+ I do not like the `Symbol#to_proc` kludge, and that for two reasons. The first is pragamatic.
357
+ You cannot pass parameters, and that sucks. Why can I express `map(&:succ)` but not `map(&:+, 2)`.
358
+ Well the answer is clear, Ruby's syntax does not support it.
359
+
360
+ The second reason is on philosophical grounds. It feels wrong that Symbol shall be responsable
361
+ of transforming itself into a lambda.
362
+
363
+ Thus I created a helper in Kernel that takes the responsability, and doing so
364
+ with a clear name, expressing intent. This helper is `Kernel#sendmsg`.
365
+
366
+
367
+ ```ruby
368
+ map do |ele|
369
+ ele.hello "World"
370
+ end
371
+ ```
372
+
373
+ is the same as
374
+
375
+
376
+ ```ruby
377
+ map( &sendmsg( :hello, "World") )
378
+ ```
379
+
380
+ Furthermore it might be usuful to keep the returned `lambda` around, please compare
381
+
382
+ ```ruby
383
+ adder = sendmsg( :+ )
384
+ ```
385
+ versus
386
+
387
+ ```ruby
388
+ adder = :+.to_proc
389
+ ```
390
+
391
+
392
+ Mapping with a `Symbol` might not only be conveniently expressed as sending a message to each
393
+ element, sometimes a different meaning might be appropriate as in the example below:
394
+
395
+
396
+ ```ruby
397
+ map do | ele |
398
+ some_method ele
399
+ end
400
+ ```
401
+
402
+ A different helper can do this job without any ambiguity:
403
+
404
+
405
+ ```ruby
406
+ map( &applyto( :some_method ) )
407
+ ```
408
+
409
+ ### Commonly Used Pattern Helpers
410
+
411
+ This group of helpers is just to avoid to rewrite lambdas you/one/whoever/I have written zillions of times. Here is a short list of examples
412
+ the API doc should give you enough information if you look for something specific.
413
+
414
+ #### Integer.sum
415
+
416
+ ```ruby
417
+ class Integer
418
+ def self.sum
419
+ ->(a, b){ a + b }
420
+ end
421
+ end
422
+ ```
423
+
424
+ #### Integer#inc
425
+
426
+ ```ruby
427
+ class Integer
428
+ alias_method :inc, :succ # should have used forward ;)
429
+ end
430
+ ```
@@ -0,0 +1,145 @@
1
+ module Forwarder
2
+ class Arguments
3
+ attr_reader :args, :message, :target
4
+
5
+ def all?
6
+ !args? && !lambda? && @__all__
7
+ end
8
+
9
+ def after
10
+ @after ||= @params[:after]
11
+ end
12
+
13
+ def after?
14
+ after
15
+ end
16
+
17
+ def aop?
18
+ @__aop__ ||= !aop_values.empty?
19
+ end
20
+
21
+ def args?
22
+ !!args
23
+ end
24
+
25
+ def before
26
+ @before ||= @params[:before]
27
+ end
28
+
29
+ def before?
30
+ before
31
+ end
32
+
33
+ def chain?
34
+ @params[ :to_chain ]
35
+ end
36
+
37
+ def custom_target?
38
+ @params[:to_object]
39
+ end
40
+
41
+ def delegatable?
42
+ !aop? && !custom_target? && !all? && !chain? && !args && !lambda?
43
+ end
44
+
45
+ def complete_args *args
46
+ (self.args || []) + args
47
+ end
48
+
49
+ def lambda default=nil
50
+ lambda? || default
51
+ end
52
+
53
+ def lambda?
54
+ @lambda
55
+ end
56
+
57
+ # This is always nil unless we are a custom_target, in which case
58
+ # default is returned if target is :self, else target is returned
59
+ def object_target default
60
+ return unless custom_target?
61
+ target == :self ? default : target
62
+ end
63
+
64
+ def translation alternative=nil, &blk
65
+ @params[ :as ].tap do | tltion |
66
+ break alternative unless tltion
67
+ break tltion unless blk
68
+ blk.( tltion )
69
+ end
70
+ end
71
+
72
+ private
73
+ def aop_values
74
+ @__aop_values__ ||= @params.values_at( :after, :before ).compact
75
+ end
76
+
77
+ def initialize *args, &blk
78
+ @message = args.shift
79
+ raise ArgumentError, "need one message and a hash of kwd params, plus an optional block" unless args.size == 1 && args.first.is_a?( Hash )
80
+ @params = args.first
81
+ set_message
82
+ set_target
83
+ set_args blk
84
+ end
85
+
86
+ def set_args blk
87
+ set_lambda blk
88
+ hw = @params.has_key? :with
89
+ ha = @params.has_key? :with_ary
90
+ raise ArgumentError, "cannot use :with and :with_ary parameter" if hw && ha
91
+ set_args_normal if hw
92
+ set_args_ary if ha
93
+ end
94
+
95
+ def set_args_ary
96
+ @args = [ @params[:with_ary] ]
97
+ raise ArgumentError, ":with_ary needs an array parameter" unless Array === @args.first
98
+ end
99
+
100
+ def set_args_normal
101
+ case arg = @params[:with]
102
+ when Array
103
+ @args = arg.dup
104
+ else
105
+ @args = [ arg ]
106
+ end
107
+ end
108
+
109
+ def set_message
110
+ case @message
111
+ when Array
112
+ @__all__ = true
113
+ end
114
+ end
115
+
116
+ def set_lambda blk
117
+
118
+ if use_block?
119
+ @after = blk if @params[:after] == :use_block
120
+ @before = blk if @params[:before] == :use_block
121
+ @lambda = @params[:with_block]
122
+ else
123
+ raise ArgumentError, "cannot use :with_block and a block" if
124
+ @params[:with_block] && blk
125
+
126
+ @lambda = @params.fetch :with_block, blk
127
+ end
128
+ end
129
+
130
+ def set_target
131
+ [:to, :to_chain, :to_object].each do | tgt_kwd |
132
+ tgt = @params[ tgt_kwd ]
133
+ next unless tgt
134
+
135
+ raise ArgumentError, "more than one target specified." if @target
136
+ @target = tgt
137
+ end
138
+ raise ArgumentError, "no target specified." unless @target
139
+ end
140
+
141
+ def use_block?
142
+ aop_values.include?( :use_block )
143
+ end
144
+ end # class Arguments
145
+ end # module Forwarder
@@ -0,0 +1,4 @@
1
+ require 'forwarder/helpers/proc'
2
+ require 'forwarder/helpers/integer'
3
+ require 'forwarder/helpers/kernel'
4
+ require 'forwarder/helpers/object'
@@ -0,0 +1,71 @@
1
+ module Forwarder
2
+ # I am the workerbee defining the methods and stuff
3
+ class Meta
4
+
5
+ attr_reader :arguments, :forwardee
6
+
7
+
8
+ # TODO: Break AOP out of this so that we do not check @ runtime
9
+ def forward
10
+ a = arguments
11
+ sr = symbolic_receiver
12
+ forwardee.module_eval do
13
+ define_method a.message do |*args, &blk|
14
+ args = a.before.(*args) if a.before?
15
+ sr
16
+ .( self, a.target )
17
+ .send( a.translation( a.message ), *a.complete_args(*args), &a.lambda( blk ) ).tap do | result |
18
+ break a.after.( result ) if a.after?
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ def forward_chain
25
+ a = arguments
26
+ sr = symbolic_receiver
27
+ forwardee.module_eval do
28
+ define_method a.message do |*args, &blk|
29
+ args = a.before.(*args) if a.before?
30
+ tgt = a.target.inject( self ){ |r, sym| sr.( r, sym ) }
31
+ tgt.send( a.translation( a.message ), *a.complete_args(*args), &a.lambda( blk ) ).tap do | result |
32
+ break a.after.( result ) if a.after?
33
+ end
34
+ #.send( a.translation( a.message ), *a.complete_args(*args), &a.lambda( blk ) )
35
+ end
36
+ end
37
+ end
38
+
39
+ def forward_object
40
+ a = arguments
41
+ forwardee.module_eval do
42
+ define_method a.message do |*args, &blk|
43
+ args = a.before.(*args) if a.before?
44
+ a.object_target( self )
45
+ .send( a.translation( a.message ), *a.complete_args(*args), &a.lambda( blk ) ).tap do | result |
46
+ break a.after.( result ) if a.after?
47
+ end
48
+ end
49
+ end
50
+
51
+ end
52
+
53
+ private
54
+ def initialize forwardee, arguments
55
+ @forwardee = forwardee
56
+ @arguments = arguments
57
+ end
58
+
59
+ def symbolic_receiver
60
+ @__symbolic_receiver__ = ->(rec, sym) do
61
+ case "#{sym}"
62
+ when /\A@/
63
+ rec.instance_variable_get sym
64
+ else
65
+ rec.send sym
66
+ end
67
+ end
68
+ end
69
+
70
+ end # class Meta
71
+ end # module Forwarder
@@ -0,0 +1,70 @@
1
+ require 'forwarder/arguments'
2
+ require 'forwarder/meta'
3
+ module Forwarder
4
+ class Params
5
+ attr_reader :forwardee, :arguments
6
+ def forward!
7
+ return if delegate
8
+ return if delegate_all
9
+ return if delegate_chain
10
+ return if delegate_object
11
+ general_delegate
12
+ end
13
+
14
+ def prepare_forward *args, &blk
15
+ @arguments = Arguments.new( *args, &blk )
16
+ end
17
+
18
+ private
19
+
20
+ def delegate
21
+ return unless arguments.delegatable?
22
+ delegate_to_forwardee
23
+ true
24
+ end
25
+
26
+ def delegate_all
27
+ return unless arguments.all?
28
+ delegate_all_to_forwardee
29
+ true
30
+ end
31
+
32
+ def delegate_all_to_forwardee
33
+ forwardee.extend Forwardable
34
+ forwardee.def_delegators( arguments.target, *arguments.message )
35
+ end
36
+
37
+
38
+ def delegate_chain
39
+ return unless arguments.chain?
40
+ delegate_to_chain
41
+ true
42
+ end
43
+
44
+ def delegate_to_chain
45
+ Meta.new( forwardee, arguments ).forward_chain
46
+ end
47
+
48
+ def delegate_object
49
+ return unless arguments.custom_target?
50
+ Meta.new( forwardee, arguments ).forward_object
51
+ true
52
+ end
53
+
54
+ def delegate_to_forwardee
55
+ forwardee.extend Forwardable
56
+ arguments.translation do | tltion |
57
+ forwardee.def_delegator arguments.target, tltion, arguments.message
58
+ end or
59
+ forwardee.def_delegator arguments.target, arguments.message
60
+ end
61
+
62
+ def initialize forwardee
63
+ @forwardee = forwardee
64
+ end
65
+
66
+ def general_delegate
67
+ Meta.new( forwardee, arguments ).forward
68
+ end
69
+ end # class Params
70
+ end # module Forwarder
@@ -0,0 +1,3 @@
1
+ module Forwarder
2
+ VERSION = '0.1.0'
3
+ end # module Forwarder
data/lib/forwarder.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'forwardable'
2
+ require 'forwarder/params'
3
+
4
+ module Forwarder
5
+
6
+ def forward *args, &blk
7
+ params = Forwarder::Params.new self
8
+ params.prepare_forward( *args, &blk )
9
+ params.forward!
10
+ end
11
+
12
+ def forward_all *args, &blk
13
+ params = Forwarder::Params.new self
14
+ opts = args.pop
15
+ params.prepare_forward( args, opts, &blk )
16
+ params.forward!
17
+ end
18
+ end # module Forwarder
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: forwarder19
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Robert Dober
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-15 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: lab419_core
16
+ requirement: &82223890 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 0.0.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *82223890
25
+ - !ruby/object:Gem::Dependency
26
+ name: ruby-debug19
27
+ requirement: &82223620 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '0.11'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *82223620
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &82223370 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.2.2
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *82223370
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec
49
+ requirement: &82223140 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.9.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *82223140
58
+ - !ruby/object:Gem::Dependency
59
+ name: maruku
60
+ requirement: &82222910 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 0.6.0
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *82222910
69
+ - !ruby/object:Gem::Dependency
70
+ name: wirble
71
+ requirement: &82222680 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 0.1.3
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *82222680
80
+ description: ! 'Ruby''s core Forwardable gets the job done(barely) and produces most
81
+ unreadable code. Furthermore it is about twice as slow (1.9.2-p290) or thrice as
82
+ slow (1.9.3-p0) as it needs to be.
83
+
84
+ This is a nonintrusive (as is Forwardable) module that allows to delegate methods
85
+ to instance variables,
86
+
87
+ objects returned by instance_methods, other methods of the same receiver, the receiver
88
+ itself, a chain of messages or
89
+
90
+ an arbitrary object. Paramters can be provided in the forwarding definition (parially
91
+ or totally=.
92
+
93
+ It also defines some AOP support as after and before filters.
94
+
95
+ Performance will be pushed to 2~3 times of Fowardable with the 0.2 branch of this
96
+ gem'
97
+ email: robert.dober@gmail.com
98
+ executables: []
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - lib/forwarder/arguments.rb
103
+ - lib/forwarder/meta.rb
104
+ - lib/forwarder/params.rb
105
+ - lib/forwarder/helpers.rb
106
+ - lib/forwarder/version.rb
107
+ - lib/forwarder.rb
108
+ - LICENSE
109
+ - README.md
110
+ homepage: https://github.com/RobertDober/Forwarder
111
+ licenses:
112
+ - MIT
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: 1.9.2
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 1.8.11
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: Delegation And AOP Filters For It
135
+ test_files: []
136
+ has_rdoc: