rubysl-delegate 1.0.0 → 2.0.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.
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
  - - '>='