rubysl-delegate 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf8ff4ff2f94d4ba5c50fedd156c62938ad603fa
4
- data.tar.gz: e491184acb98306a8c7b52950e78a187b012ab83
3
+ metadata.gz: 0eced264b69375946afd5adf72327ac9006d09ad
4
+ data.tar.gz: 93f3a46d00dfd8cd429bddaa17866e6ca425671d
5
5
  SHA512:
6
- metadata.gz: 5f7facd1e4e160e0e333d4419bf58f9dbdbc401cdc2f48a050cc4c9bc2a58f6ac02ff12bfc65a10b51a8a7c65fa230a8b41a8a66feddf24a0b4f433143e2a6ef
7
- data.tar.gz: a184e130c057571eb98c38a0949024912447e0de40742ac08abe47e4d53fb564fea2d86956caf39f9177c527ffea1c267588f360a2e662edf794722cab97ad29
6
+ metadata.gz: a532da1faa6f9ecc57316bca8b1bce391718439b86a2275633b11bcf1831aaf4eda5b31848df01a3cfebe14b0c19dc7d6dba8604006f08139aa9b2f726b34105
7
+ data.tar.gz: 6a06857191f3019166b3a3657473e347929afbb3dedb8fd0bf34bdb549f7ff7bbe07e47c9c920da2393770b8d8e4816dbf2b94f946a530fa87c4e31ec4037919
@@ -3,5 +3,5 @@ env:
3
3
  - RUBYLIB=lib
4
4
  script: bundle exec mspec
5
5
  rvm:
6
- - 1.8.7
7
- - rbx-nightly-18mode
6
+ - 1.9.3
7
+ - rbx-nightly-19mode
@@ -1,9 +1,8 @@
1
1
  # = delegate -- Support for the Delegation Pattern
2
2
  #
3
3
  # Documentation by James Edward Gray II and Gavin Sinclair
4
- #
5
- # == Introduction
6
- #
4
+
5
+ ##
7
6
  # This library provides three different ways to delegate method calls to an
8
7
  # object. The easiest to use is SimpleDelegator. Pass an object to the
9
8
  # constructor and all methods supported by the object will be delegated. This
@@ -15,157 +14,128 @@
15
14
  #
16
15
  # Finally, if you need full control over the delegation scheme, you can inherit
17
16
  # from the abstract class Delegator and customize as needed. (If you find
18
- # yourself needing this control, have a look at _forwardable_, also in the
19
- # standard library. It may suit your needs better.)
20
- #
21
- # == Notes
22
- #
23
- # Be advised, RDoc will not detect delegated methods.
24
- #
25
- # <b>delegate.rb provides full-class delegation via the
26
- # DelegateClass() method. For single-method delegation via
27
- # def_delegator(), see forwardable.rb.</b>
28
- #
29
- # == Examples
17
+ # yourself needing this control, have a look at Forwardable which is also in
18
+ # the standard library. It may suit your needs better.)
30
19
  #
31
- # === SimpleDelegator
32
- #
33
- # Here's a simple example that takes advantage of the fact that
34
- # SimpleDelegator's delegation object can be changed at any time.
20
+ # SimpleDelegator's implementation serves as a nice example if the use of
21
+ # Delegator:
35
22
  #
36
- # class Stats
37
- # def initialize
38
- # @source = SimpleDelegator.new([])
39
- # end
40
- #
41
- # def stats( records )
42
- # @source.__setobj__(records)
43
- #
44
- # "Elements: #{@source.size}\n" +
45
- # " Non-Nil: #{@source.compact.size}\n" +
46
- # " Unique: #{@source.uniq.size}\n"
23
+ # class SimpleDelegator < Delegator
24
+ # def initialize(obj)
25
+ # super # pass obj to Delegator constructor, required
26
+ # @delegate_sd_obj = obj # store obj for future use
47
27
  # end
48
- # end
49
- #
50
- # s = Stats.new
51
- # puts s.stats(%w{James Edward Gray II})
52
- # puts
53
- # puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])
54
- #
55
- # <i>Prints:</i>
56
- #
57
- # Elements: 4
58
- # Non-Nil: 4
59
- # Unique: 4
60
- #
61
- # Elements: 8
62
- # Non-Nil: 7
63
- # Unique: 6
64
28
  #
65
- # === DelegateClass()
66
- #
67
- # Here's a sample of use from <i>tempfile.rb</i>.
68
- #
69
- # A _Tempfile_ object is really just a _File_ object with a few special rules
70
- # about storage location and/or when the File should be deleted. That makes for
71
- # an almost textbook perfect example of how to use delegation.
29
+ # def __getobj__
30
+ # @delegate_sd_obj # return object we are delegating to, required
31
+ # end
72
32
  #
73
- # class Tempfile < DelegateClass(File)
74
- # # constant and class member data initialization...
75
- #
76
- # def initialize(basename, tmpdir=Dir::tmpdir)
77
- # # build up file path/name in var tmpname...
78
- #
79
- # @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
80
- #
81
- # # ...
82
- #
83
- # super(@tmpfile)
84
- #
85
- # # below this point, all methods of File are supported...
33
+ # def __setobj__(obj)
34
+ # @delegate_sd_obj = obj # change delegation object,
35
+ # # a feature we're providing
86
36
  # end
87
- #
88
- # # ...
89
37
  # end
90
38
  #
91
- # === Delegator
39
+ # == Notes
92
40
  #
93
- # SimpleDelegator's implementation serves as a nice example here.
41
+ # Be advised, RDoc will not detect delegated methods.
94
42
  #
95
- # class SimpleDelegator < Delegator
96
- # def initialize(obj)
97
- # super # pass obj to Delegator constructor, required
98
- # @_sd_obj = obj # store obj for future use
99
- # end
100
- #
101
- # def __getobj__
102
- # @_sd_obj # return object we are delegating to, required
103
- # end
104
- #
105
- # def __setobj__(obj)
106
- # @_sd_obj = obj # change delegation object, a feature we're providing
107
- # end
108
- #
109
- # # ...
110
- # end
43
+ class Delegator < BasicObject
44
+ kernel = ::Kernel.dup
45
+ kernel.class_eval do
46
+ [:to_s,:inspect,:=~,:!~,:===,:<=>,:eql?,:hash].each do |m|
47
+ undef_method m
48
+ end
49
+ end
50
+ include kernel
111
51
 
112
- #
113
- # Delegator is an abstract class used to build delegator pattern objects from
114
- # subclasses. Subclasses should redefine \_\_getobj\_\_. For a concrete
115
- # implementation, see SimpleDelegator.
116
- #
117
- class Delegator
118
- IgnoreBacktracePat = %r"\A#{Regexp.quote(__FILE__)}:\d+:in `"
52
+ # :stopdoc:
53
+ def self.const_missing(n)
54
+ ::Object.const_get(n)
55
+ end
56
+ # :startdoc:
119
57
 
120
58
  #
121
59
  # Pass in the _obj_ to delegate method calls to. All methods supported by
122
60
  # _obj_ will be delegated to.
123
61
  #
124
62
  def initialize(obj)
125
- preserved = ::Kernel.public_instance_methods(false)
126
- preserved -= ["to_s","to_a","inspect","==","=~","==="]
127
- for t in self.class.ancestors
128
- preserved |= t.public_instance_methods(false)
129
- preserved |= t.private_instance_methods(false)
130
- preserved |= t.protected_instance_methods(false)
131
- break if t == Delegator
132
- end
133
- preserved << "singleton_method_added"
134
- for method in obj.methods
135
- next if preserved.include? method
136
- begin
137
- eval <<-EOS, nil, __FILE__, __LINE__+1
138
- def self.#{method}(*args, &block)
139
- begin
140
- __getobj__.__send__(:#{method}, *args, &block)
141
- ensure
142
- $@.delete_if{|s|IgnoreBacktracePat=~s} if $@
143
- end
144
- end
145
- EOS
146
- rescue SyntaxError
147
- raise NameError, "invalid identifier %s" % method, caller(4)
148
- end
149
- end
63
+ __setobj__(obj)
150
64
  end
151
- alias initialize_methods initialize
152
65
 
66
+ #
153
67
  # Handles the magic of delegation through \_\_getobj\_\_.
68
+ #
154
69
  def method_missing(m, *args, &block)
155
70
  target = self.__getobj__
156
- unless target.respond_to?(m)
157
- super(m, *args, &block)
71
+ begin
72
+ target.respond_to?(m) ? target.__send__(m, *args, &block) : super(m, *args, &block)
73
+ ensure
74
+ $@.delete_if {|t| %r"\A#{Regexp.quote(__FILE__)}:#{__LINE__-2}:"o =~ t} if $@
158
75
  end
159
- target.__send__(m, *args, &block)
160
76
  end
161
77
 
162
- #
163
- # Checks for a method provided by this the delegate object by fowarding the
78
+ #
79
+ # Checks for a method provided by this the delegate object by forwarding the
164
80
  # call through \_\_getobj\_\_.
165
- #
166
- def respond_to?(m, include_private = false)
167
- return true if super
168
- return self.__getobj__.respond_to?(m, include_private)
81
+ #
82
+ def respond_to_missing?(m, include_private)
83
+ r = self.__getobj__.respond_to?(m, include_private)
84
+ if r && include_private && !self.__getobj__.respond_to?(m, false)
85
+ warn "#{caller(3)[0]}: delegator does not forward private method \##{m}"
86
+ return false
87
+ end
88
+ r
89
+ end
90
+
91
+ #
92
+ # Returns the methods available to this delegate object as the union
93
+ # of this object's and \_\_getobj\_\_ methods.
94
+ #
95
+ def methods(all=true)
96
+ if all
97
+ __getobj__.methods | super
98
+ else
99
+ __getobj__.singleton_methods | singleton_methods
100
+ end
101
+ end
102
+
103
+ #
104
+ # Returns the methods available to this delegate object as the union
105
+ # of this object's and \_\_getobj\_\_ public methods.
106
+ #
107
+ def public_methods(all=true)
108
+ __getobj__.public_methods(all) | super
109
+ end
110
+
111
+ #
112
+ # Returns the methods available to this delegate object as the union
113
+ # of this object's and \_\_getobj\_\_ protected methods.
114
+ #
115
+ def protected_methods(all=true)
116
+ __getobj__.protected_methods(all) | super
117
+ end
118
+
119
+ # Note: no need to specialize private_methods, since they are not forwarded
120
+
121
+ #
122
+ # Returns true if two objects are considered of equal value.
123
+ #
124
+ def ==(obj)
125
+ return true if obj.equal?(self)
126
+ self.__getobj__ == obj
127
+ end
128
+
129
+ #
130
+ # Returns true if two objects are not considered of equal value.
131
+ #
132
+ def !=(obj)
133
+ return false if obj.equal?(self)
134
+ __getobj__ != obj
135
+ end
136
+
137
+ def !
138
+ !__getobj__
169
139
  end
170
140
 
171
141
  #
@@ -176,34 +146,127 @@ class Delegator
176
146
  raise NotImplementedError, "need to define `__getobj__'"
177
147
  end
178
148
 
149
+ #
150
+ # This method must be overridden by subclasses and change the object delegate
151
+ # to _obj_.
152
+ #
153
+ def __setobj__(obj)
154
+ raise NotImplementedError, "need to define `__setobj__'"
155
+ end
156
+
157
+ #
179
158
  # Serialization support for the object returned by \_\_getobj\_\_.
159
+ #
180
160
  def marshal_dump
181
- __getobj__
161
+ ivars = instance_variables.reject {|var| /\A@delegate_/ =~ var.to_s}
162
+ [
163
+ :__v2__,
164
+ ivars, ivars.map{|var| instance_variable_get(var)},
165
+ __getobj__
166
+ ]
182
167
  end
168
+
169
+ #
183
170
  # Reinitializes delegation from a serialized object.
184
- def marshal_load(obj)
185
- initialize_methods(obj)
186
- __setobj__(obj)
171
+ #
172
+ def marshal_load(data)
173
+ version, vars, values, obj = data
174
+ if version == :__v2__
175
+ vars.each_with_index{|var, i| instance_variable_set(var, values[i])}
176
+ __setobj__(obj)
177
+ else
178
+ __setobj__(data)
179
+ end
180
+ end
181
+
182
+ def initialize_clone(obj) # :nodoc:
183
+ self.__setobj__(obj.__getobj__.clone)
184
+ end
185
+ def initialize_dup(obj) # :nodoc:
186
+ self.__setobj__(obj.__getobj__.dup)
187
+ end
188
+ private :initialize_clone, :initialize_dup
189
+
190
+ ##
191
+ # :method: trust
192
+ # Trust both the object returned by \_\_getobj\_\_ and self.
193
+ #
194
+
195
+ ##
196
+ # :method: untrust
197
+ # Untrust both the object returned by \_\_getobj\_\_ and self.
198
+ #
199
+
200
+ ##
201
+ # :method: taint
202
+ # Taint both the object returned by \_\_getobj\_\_ and self.
203
+ #
204
+
205
+ ##
206
+ # :method: untaint
207
+ # Untaint both the object returned by \_\_getobj\_\_ and self.
208
+ #
209
+
210
+ ##
211
+ # :method: freeze
212
+ # Freeze both the object returned by \_\_getobj\_\_ and self.
213
+ #
214
+
215
+ [:trust, :untrust, :taint, :untaint, :freeze].each do |method|
216
+ define_method method do
217
+ __getobj__.send(method)
218
+ super()
219
+ end
220
+ end
221
+
222
+ @delegator_api = self.public_instance_methods
223
+ def self.public_api # :nodoc:
224
+ @delegator_api
187
225
  end
188
226
  end
189
227
 
190
- #
228
+ ##
191
229
  # A concrete implementation of Delegator, this class provides the means to
192
230
  # delegate all supported method calls to the object passed into the constructor
193
231
  # and even to change the object being delegated to at a later time with
194
- # \_\_setobj\_\_ .
232
+ # #__setobj__.
233
+ #
234
+ # Here's a simple example that takes advantage of the fact that
235
+ # SimpleDelegator's delegation object can be changed at any time.
236
+ #
237
+ # class Stats
238
+ # def initialize
239
+ # @source = SimpleDelegator.new([])
240
+ # end
241
+ #
242
+ # def stats(records)
243
+ # @source.__setobj__(records)
244
+ #
245
+ # "Elements: #{@source.size}\n" +
246
+ # " Non-Nil: #{@source.compact.size}\n" +
247
+ # " Unique: #{@source.uniq.size}\n"
248
+ # end
249
+ # end
250
+ #
251
+ # s = Stats.new
252
+ # puts s.stats(%w{James Edward Gray II})
253
+ # puts
254
+ # puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])
255
+ #
256
+ # Prints:
257
+ #
258
+ # Elements: 4
259
+ # Non-Nil: 4
260
+ # Unique: 4
261
+ #
262
+ # Elements: 8
263
+ # Non-Nil: 7
264
+ # Unique: 6
195
265
  #
196
266
  class SimpleDelegator<Delegator
197
-
198
- # Pass in the _obj_ you would like to delegate method calls to.
199
- def initialize(obj)
200
- super
201
- @_sd_obj = obj
202
- end
203
-
204
267
  # Returns the current object method calls are being delegated to.
205
268
  def __getobj__
206
- @_sd_obj
269
+ @delegate_sd_obj
207
270
  end
208
271
 
209
272
  #
@@ -222,91 +285,79 @@ class SimpleDelegator<Delegator
222
285
  #
223
286
  def __setobj__(obj)
224
287
  raise ArgumentError, "cannot delegate to self" if self.equal?(obj)
225
- @_sd_obj = obj
226
- end
227
-
228
- # Clone support for the object returned by \_\_getobj\_\_.
229
- def clone
230
- new = super
231
- new.__setobj__(__getobj__.clone)
232
- new
233
- end
234
- # Duplication support for the object returned by \_\_getobj\_\_.
235
- def dup
236
- new = super
237
- new.__setobj__(__getobj__.clone)
238
- new
288
+ @delegate_sd_obj = obj
239
289
  end
240
290
  end
241
291
 
242
292
  # :stopdoc:
243
- # backward compatibility ^_^;;;
244
- Delegater = Delegator
245
- SimpleDelegater = SimpleDelegator
293
+ def Delegator.delegating_block(mid)
294
+ lambda do |*args, &block|
295
+ target = self.__getobj__
296
+ begin
297
+ target.__send__(mid, *args, &block)
298
+ ensure
299
+ $@.delete_if {|t| /\A#{Regexp.quote(__FILE__)}:#{__LINE__-2}:/o =~ t} if $@
300
+ end
301
+ end
302
+ end
246
303
  # :startdoc:
247
304
 
248
305
  #
249
306
  # The primary interface to this library. Use to setup delegation when defining
250
307
  # your class.
251
308
  #
252
- # class MyClass < DelegateClass( ClassToDelegateTo ) # Step 1
309
+ # class MyClass < DelegateClass(ClassToDelegateTo) # Step 1
253
310
  # def initialize
254
- # super(obj_of_ClassToDelegateTo) # Step 2
311
+ # super(obj_of_ClassToDelegateTo) # Step 2
312
+ # end
313
+ # end
314
+ #
315
+ # Here's a sample of use from Tempfile which is really a File object with a
316
+ # few special rules about storage location and when the File should be
317
+ # deleted. That makes for an almost textbook perfect example of how to use
318
+ # delegation.
319
+ #
320
+ # class Tempfile < DelegateClass(File)
321
+ # # constant and class member data initialization...
322
+ #
323
+ # def initialize(basename, tmpdir=Dir::tmpdir)
324
+ # # build up file path/name in var tmpname...
325
+ #
326
+ # @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
327
+ #
328
+ # # ...
329
+ #
330
+ # super(@tmpfile)
331
+ #
332
+ # # below this point, all methods of File are supported...
255
333
  # end
334
+ #
335
+ # # ...
256
336
  # end
257
337
  #
258
338
  def DelegateClass(superclass)
259
- klass = Class.new
260
- methods = superclass.public_instance_methods(true)
261
- methods -= ::Kernel.public_instance_methods(false)
262
- methods |= ["to_s","to_a","inspect","==","=~","==="]
263
- klass.module_eval {
264
- def initialize(obj) # :nodoc:
265
- @_dc_obj = obj
266
- end
267
- def method_missing(m, *args, &block) # :nodoc:
268
- unless @_dc_obj.respond_to?(m)
269
- super(m, *args, &block)
270
- end
271
- @_dc_obj.__send__(m, *args, &block)
272
- end
273
- def respond_to?(m, include_private = false) # :nodoc:
274
- return true if super
275
- return @_dc_obj.respond_to?(m, include_private)
276
- end
339
+ klass = Class.new(Delegator)
340
+ methods = superclass.instance_methods
341
+ methods -= ::Delegator.public_api
342
+ methods -= [:to_s,:inspect,:=~,:!~,:===]
343
+ klass.module_eval do
277
344
  def __getobj__ # :nodoc:
278
- @_dc_obj
345
+ @delegate_dc_obj
279
346
  end
280
347
  def __setobj__(obj) # :nodoc:
281
348
  raise ArgumentError, "cannot delegate to self" if self.equal?(obj)
282
- @_dc_obj = obj
283
- end
284
- def clone # :nodoc:
285
- new = super
286
- new.__setobj__(__getobj__.clone)
287
- new
349
+ @delegate_dc_obj = obj
288
350
  end
289
- def dup # :nodoc:
290
- new = super
291
- new.__setobj__(__getobj__.clone)
292
- new
293
- end
294
- }
295
- for method in methods
296
- begin
297
- klass.module_eval <<-EOS, __FILE__, __LINE__+1
298
- def #{method}(*args, &block)
299
- begin
300
- @_dc_obj.__send__(:#{method}, *args, &block)
301
- ensure
302
- $@.delete_if{|s| ::Delegator::IgnoreBacktracePat =~ s} if $@
303
- end
304
- end
305
- EOS
306
- rescue SyntaxError
307
- raise NameError, "invalid identifier %s" % method, caller(3)
351
+ methods.each do |method|
352
+ define_method(method, Delegator.delegating_block(method))
308
353
  end
309
354
  end
355
+ klass.define_singleton_method :public_instance_methods do |all=true|
356
+ super(all) - superclass.protected_instance_methods
357
+ end
358
+ klass.define_singleton_method :protected_instance_methods do |all=true|
359
+ super(all) | superclass.protected_instance_methods
360
+ end
310
361
  return klass
311
362
  end
312
363
 
@@ -323,15 +374,23 @@ if __FILE__ == $0
323
374
  p ary.class
324
375
  ary.push 25
325
376
  p ary
377
+ ary.push 42
378
+ ary.each {|x| p x}
326
379
 
327
380
  foo = Object.new
328
381
  def foo.test
329
382
  25
330
383
  end
384
+ def foo.iter
385
+ yield self
386
+ end
331
387
  def foo.error
332
388
  raise 'this is OK'
333
389
  end
334
390
  foo2 = SimpleDelegator.new(foo)
335
- p foo.test == foo2.test # => true
336
- foo2.error # raise error!
337
- end
391
+ p foo2
392
+ foo2.instance_eval{print "foo\n"}
393
+ p foo.test == foo2.test # => true
394
+ p foo2.iter{[55,true]} # => true
395
+ foo2.error # raise error!
396
+ end
@@ -1,5 +1,5 @@
1
1
  module RubySL
2
2
  module Delegator
3
- VERSION = "1.0.0"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
@@ -16,6 +16,8 @@ Gem::Specification.new do |spec|
16
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
17
  spec.require_paths = ["lib"]
18
18
 
19
+ spec.required_ruby_version = "~> 2.0"
20
+
19
21
  spec.add_development_dependency "bundler", "~> 1.3"
20
22
  spec.add_development_dependency "rake", "~> 10.0"
21
23
  spec.add_development_dependency "mspec", "~> 1.5"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubysl-delegate
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Shirai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-27 00:00:00.000000000 Z
11
+ date: 2013-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -108,9 +108,9 @@ require_paths:
108
108
  - lib
109
109
  required_ruby_version: !ruby/object:Gem::Requirement
110
110
  requirements:
111
- - - '>='
111
+ - - ~>
112
112
  - !ruby/object:Gem::Version
113
- version: '0'
113
+ version: '2.0'
114
114
  required_rubygems_version: !ruby/object:Gem::Requirement
115
115
  requirements:
116
116
  - - '>='