rubysl-delegate 1.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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/lib/delegate.rb +1 -0
  9. data/lib/rubysl/delegate.rb +2 -0
  10. data/lib/rubysl/delegate/delegate.rb +337 -0
  11. data/lib/rubysl/delegate/version.rb +5 -0
  12. data/rubysl-delegate.gemspec +22 -0
  13. data/spec/delegate_class/instance_method_spec.rb +53 -0
  14. data/spec/delegate_class/instance_methods_spec.rb +49 -0
  15. data/spec/delegate_class/private_instance_methods_spec.rb +41 -0
  16. data/spec/delegate_class/protected_instance_methods_spec.rb +55 -0
  17. data/spec/delegate_class/public_instance_methods_spec.rb +45 -0
  18. data/spec/delegator/case_compare_spec.rb +10 -0
  19. data/spec/delegator/compare_spec.rb +10 -0
  20. data/spec/delegator/complement_spec.rb +12 -0
  21. data/spec/delegator/eql_spec.rb +12 -0
  22. data/spec/delegator/equal_spec.rb +12 -0
  23. data/spec/delegator/equal_value_spec.rb +31 -0
  24. data/spec/delegator/frozen_spec.rb +48 -0
  25. data/spec/delegator/hash_spec.rb +12 -0
  26. data/spec/delegator/marshal_spec.rb +22 -0
  27. data/spec/delegator/method_spec.rb +76 -0
  28. data/spec/delegator/methods_spec.rb +65 -0
  29. data/spec/delegator/not_equal_spec.rb +25 -0
  30. data/spec/delegator/not_spec.rb +12 -0
  31. data/spec/delegator/private_methods_spec.rb +33 -0
  32. data/spec/delegator/protected_methods_spec.rb +31 -0
  33. data/spec/delegator/public_methods_spec.rb +29 -0
  34. data/spec/delegator/send_spec.rb +33 -0
  35. data/spec/delegator/taint_spec.rb +24 -0
  36. data/spec/delegator/tap_spec.rb +17 -0
  37. data/spec/delegator/trust_spec.rb +41 -0
  38. data/spec/delegator/untaint_spec.rb +25 -0
  39. data/spec/delegator/untrust_spec.rb +24 -0
  40. data/spec/fixtures/classes.rb +65 -0
  41. metadata +153 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cf8ff4ff2f94d4ba5c50fedd156c62938ad603fa
4
+ data.tar.gz: e491184acb98306a8c7b52950e78a187b012ab83
5
+ SHA512:
6
+ metadata.gz: 5f7facd1e4e160e0e333d4419bf58f9dbdbc401cdc2f48a050cc4c9bc2a58f6ac02ff12bfc65a10b51a8a7c65fa230a8b41a8a66feddf24a0b4f433143e2a6ef
7
+ data.tar.gz: a184e130c057571eb98c38a0949024912447e0de40742ac08abe47e4d53fb564fea2d86956caf39f9177c527ffea1c267588f360a2e662edf794722cab97ad29
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ env:
3
+ - RUBYLIB=lib
4
+ script: bundle exec mspec
5
+ rvm:
6
+ - 1.8.7
7
+ - rbx-nightly-18mode
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rubysl-delegate.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2013, Brian Shirai
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+ 2. Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ 3. Neither the name of the library nor the names of its contributors may be
13
+ used to endorse or promote products derived from this software without
14
+ specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY DIRECT,
20
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
25
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Rubysl::Delegate
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rubysl-delegate'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rubysl-delegate
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/delegate.rb ADDED
@@ -0,0 +1 @@
1
+ require "rubysl/delegate"
@@ -0,0 +1,2 @@
1
+ require "rubysl/delegate/version"
2
+ require "rubysl/delegate/delegate"
@@ -0,0 +1,337 @@
1
+ # = delegate -- Support for the Delegation Pattern
2
+ #
3
+ # Documentation by James Edward Gray II and Gavin Sinclair
4
+ #
5
+ # == Introduction
6
+ #
7
+ # This library provides three different ways to delegate method calls to an
8
+ # object. The easiest to use is SimpleDelegator. Pass an object to the
9
+ # constructor and all methods supported by the object will be delegated. This
10
+ # object can be changed later.
11
+ #
12
+ # Going a step further, the top level DelegateClass method allows you to easily
13
+ # setup delegation through class inheritance. This is considerably more
14
+ # flexible and thus probably the most common use for this library.
15
+ #
16
+ # Finally, if you need full control over the delegation scheme, you can inherit
17
+ # 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
30
+ #
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.
35
+ #
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"
47
+ # 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
+ #
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.
72
+ #
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...
86
+ # end
87
+ #
88
+ # # ...
89
+ # end
90
+ #
91
+ # === Delegator
92
+ #
93
+ # SimpleDelegator's implementation serves as a nice example here.
94
+ #
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
111
+
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 `"
119
+
120
+ #
121
+ # Pass in the _obj_ to delegate method calls to. All methods supported by
122
+ # _obj_ will be delegated to.
123
+ #
124
+ 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
150
+ end
151
+ alias initialize_methods initialize
152
+
153
+ # Handles the magic of delegation through \_\_getobj\_\_.
154
+ def method_missing(m, *args, &block)
155
+ target = self.__getobj__
156
+ unless target.respond_to?(m)
157
+ super(m, *args, &block)
158
+ end
159
+ target.__send__(m, *args, &block)
160
+ end
161
+
162
+ #
163
+ # Checks for a method provided by this the delegate object by fowarding the
164
+ # 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)
169
+ end
170
+
171
+ #
172
+ # This method must be overridden by subclasses and should return the object
173
+ # method calls are being delegated to.
174
+ #
175
+ def __getobj__
176
+ raise NotImplementedError, "need to define `__getobj__'"
177
+ end
178
+
179
+ # Serialization support for the object returned by \_\_getobj\_\_.
180
+ def marshal_dump
181
+ __getobj__
182
+ end
183
+ # Reinitializes delegation from a serialized object.
184
+ def marshal_load(obj)
185
+ initialize_methods(obj)
186
+ __setobj__(obj)
187
+ end
188
+ end
189
+
190
+ #
191
+ # A concrete implementation of Delegator, this class provides the means to
192
+ # delegate all supported method calls to the object passed into the constructor
193
+ # and even to change the object being delegated to at a later time with
194
+ # \_\_setobj\_\_ .
195
+ #
196
+ 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
+ # Returns the current object method calls are being delegated to.
205
+ def __getobj__
206
+ @_sd_obj
207
+ end
208
+
209
+ #
210
+ # Changes the delegate object to _obj_.
211
+ #
212
+ # It's important to note that this does *not* cause SimpleDelegator's methods
213
+ # to change. Because of this, you probably only want to change delegation
214
+ # to objects of the same type as the original delegate.
215
+ #
216
+ # Here's an example of changing the delegation object.
217
+ #
218
+ # names = SimpleDelegator.new(%w{James Edward Gray II})
219
+ # puts names[1] # => Edward
220
+ # names.__setobj__(%w{Gavin Sinclair})
221
+ # puts names[1] # => Sinclair
222
+ #
223
+ def __setobj__(obj)
224
+ 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
239
+ end
240
+ end
241
+
242
+ # :stopdoc:
243
+ # backward compatibility ^_^;;;
244
+ Delegater = Delegator
245
+ SimpleDelegater = SimpleDelegator
246
+ # :startdoc:
247
+
248
+ #
249
+ # The primary interface to this library. Use to setup delegation when defining
250
+ # your class.
251
+ #
252
+ # class MyClass < DelegateClass( ClassToDelegateTo ) # Step 1
253
+ # def initialize
254
+ # super(obj_of_ClassToDelegateTo) # Step 2
255
+ # end
256
+ # end
257
+ #
258
+ 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
277
+ def __getobj__ # :nodoc:
278
+ @_dc_obj
279
+ end
280
+ def __setobj__(obj) # :nodoc:
281
+ 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
288
+ 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)
308
+ end
309
+ end
310
+ return klass
311
+ end
312
+
313
+ # :enddoc:
314
+
315
+ if __FILE__ == $0
316
+ class ExtArray<DelegateClass(Array)
317
+ def initialize()
318
+ super([])
319
+ end
320
+ end
321
+
322
+ ary = ExtArray.new
323
+ p ary.class
324
+ ary.push 25
325
+ p ary
326
+
327
+ foo = Object.new
328
+ def foo.test
329
+ 25
330
+ end
331
+ def foo.error
332
+ raise 'this is OK'
333
+ end
334
+ foo2 = SimpleDelegator.new(foo)
335
+ p foo.test == foo2.test # => true
336
+ foo2.error # raise error!
337
+ end