rubysl-delegate 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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