delegate 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6cd16ea3c730a702d06a1721e2213829db7c2ccc0109aa267fa62201f9f5b910
4
+ data.tar.gz: 7e46d4c7174ff100079239050e33e41589c9d1a553d8497ab0fb763b22939835
5
+ SHA512:
6
+ metadata.gz: 9779b0aa3f86278c7ddef289936be20530e6056c22cfca97039740495a80e9cd9f77d22cb51ff6bc02e9b43e7dfdb3917dd22bd0fb93bf6e38c8858d6080e174
7
+ data.tar.gz: 7d1ce7b641a66022ac9ef56f46dbcfd0999fdd4f6834fbdfb4142d0fbb39fa689a4007395657704f174181709ca251e5f78965e9cbead70b8a8f9cb0f0d8bc3a
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 2.0.2
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem "bundler"
7
+ gem "rake"
8
+ gem "test-unit"
9
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,59 @@
1
+ # Delegator
2
+
3
+ This library provides three different ways to delegate method calls to an
4
+ object. The easiest to use is SimpleDelegator. Pass an object to the
5
+ constructor and all methods supported by the object will be delegated. This
6
+ object can be changed later.
7
+
8
+ Going a step further, the top level DelegateClass method allows you to easily
9
+ setup delegation through class inheritance. This is considerably more
10
+ flexible and thus probably the most common use for this library.
11
+
12
+ Finally, if you need full control over the delegation scheme, you can inherit
13
+ from the abstract class Delegator and customize as needed. (If you find
14
+ yourself needing this control, have a look at Forwardable which is also in
15
+ the standard library. It may suit your needs better.)
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'delegate'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ $ bundle
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install delegate
32
+
33
+ ## Usage
34
+
35
+ SimpleDelegator's implementation serves as a nice example of the use of
36
+ Delegator:
37
+
38
+ ```ruby
39
+ class SimpleDelegator < Delegator
40
+ def __getobj__
41
+ @delegate_sd_obj # return object we are delegating to, required
42
+ end
43
+
44
+ def __setobj__(obj)
45
+ @delegate_sd_obj = obj # change delegation object,
46
+ # a feature we're providing
47
+ end
48
+ end
49
+ ```
50
+
51
+ ## Development
52
+
53
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
54
+
55
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
56
+
57
+ ## Contributing
58
+
59
+ Bug reports and pull requests are welcome on GitHub at https://github.com/hsbt/delegate.
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test/lib"
6
+ t.ruby_opts << "-rhelper"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "delegate"
5
+
6
+ require "irb"
7
+ IRB.start(__FILE__)
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,25 @@
1
+ lib = File.expand_path("lib", __dir__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "delegate/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "delegate"
7
+ spec.version = Delegator::VERSION
8
+ spec.authors = ["Hiroshi SHIBATA"]
9
+ spec.email = ["hsbt@ruby-lang.org"]
10
+
11
+ spec.summary = %q{Provides three abilities to delegate method calls to an object.}
12
+ spec.description = %q{Provides three abilities to delegate method calls to an object.}
13
+ spec.homepage = "https://github.com/ruby/delegate"
14
+ spec.license = "BSD-2-Clause"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+
19
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+ end
@@ -0,0 +1,429 @@
1
+ # frozen_string_literal: true
2
+ # = delegate -- Support for the Delegation Pattern
3
+ #
4
+ # Documentation by James Edward Gray II and Gavin Sinclair
5
+
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 which is also in
19
+ # the standard library. It may suit your needs better.)
20
+ #
21
+ # SimpleDelegator's implementation serves as a nice example of the use of
22
+ # Delegator:
23
+ #
24
+ # class SimpleDelegator < Delegator
25
+ # def __getobj__
26
+ # @delegate_sd_obj # return object we are delegating to, required
27
+ # end
28
+ #
29
+ # def __setobj__(obj)
30
+ # @delegate_sd_obj = obj # change delegation object,
31
+ # # a feature we're providing
32
+ # end
33
+ # end
34
+ #
35
+ # == Notes
36
+ #
37
+ # Be advised, RDoc will not detect delegated methods.
38
+ #
39
+ class Delegator < BasicObject
40
+ kernel = ::Kernel.dup
41
+ kernel.class_eval do
42
+ alias __raise__ raise
43
+ [:to_s, :inspect, :=~, :!~, :===, :<=>, :hash].each do |m|
44
+ undef_method m
45
+ end
46
+ private_instance_methods.each do |m|
47
+ if /\Ablock_given\?\z|\Aiterator\?\z|\A__.*__\z/ =~ m
48
+ next
49
+ end
50
+ undef_method m
51
+ end
52
+ end
53
+ include kernel
54
+
55
+ # :stopdoc:
56
+ def self.const_missing(n)
57
+ ::Object.const_get(n)
58
+ end
59
+ # :startdoc:
60
+
61
+ ##
62
+ # :method: raise
63
+ # Use #__raise__ if your Delegator does not have a object to delegate the
64
+ # #raise method call.
65
+ #
66
+
67
+ #
68
+ # Pass in the _obj_ to delegate method calls to. All methods supported by
69
+ # _obj_ will be delegated to.
70
+ #
71
+ def initialize(obj)
72
+ __setobj__(obj)
73
+ end
74
+
75
+ #
76
+ # Handles the magic of delegation through \_\_getobj\_\_.
77
+ #
78
+ def method_missing(m, *args, &block)
79
+ r = true
80
+ target = self.__getobj__ {r = false}
81
+
82
+ if r && target.respond_to?(m)
83
+ target.__send__(m, *args, &block)
84
+ elsif ::Kernel.method_defined?(m) || ::Kernel.private_method_defined?(m)
85
+ ::Kernel.instance_method(m).bind(self).(*args, &block)
86
+ else
87
+ super(m, *args, &block)
88
+ end
89
+ end
90
+
91
+ #
92
+ # Checks for a method provided by this the delegate object by forwarding the
93
+ # call through \_\_getobj\_\_.
94
+ #
95
+ def respond_to_missing?(m, include_private)
96
+ r = true
97
+ target = self.__getobj__ {r = false}
98
+ r &&= target.respond_to?(m, include_private)
99
+ if r && include_private && !target.respond_to?(m, false)
100
+ warn "delegator does not forward private method \##{m}", uplevel: 3
101
+ return false
102
+ end
103
+ r
104
+ end
105
+
106
+ #
107
+ # Returns the methods available to this delegate object as the union
108
+ # of this object's and \_\_getobj\_\_ methods.
109
+ #
110
+ def methods(all=true)
111
+ __getobj__.methods(all) | super
112
+ end
113
+
114
+ #
115
+ # Returns the methods available to this delegate object as the union
116
+ # of this object's and \_\_getobj\_\_ public methods.
117
+ #
118
+ def public_methods(all=true)
119
+ __getobj__.public_methods(all) | super
120
+ end
121
+
122
+ #
123
+ # Returns the methods available to this delegate object as the union
124
+ # of this object's and \_\_getobj\_\_ protected methods.
125
+ #
126
+ def protected_methods(all=true)
127
+ __getobj__.protected_methods(all) | super
128
+ end
129
+
130
+ # Note: no need to specialize private_methods, since they are not forwarded
131
+
132
+ #
133
+ # Returns true if two objects are considered of equal value.
134
+ #
135
+ def ==(obj)
136
+ return true if obj.equal?(self)
137
+ self.__getobj__ == obj
138
+ end
139
+
140
+ #
141
+ # Returns true if two objects are not considered of equal value.
142
+ #
143
+ def !=(obj)
144
+ return false if obj.equal?(self)
145
+ __getobj__ != obj
146
+ end
147
+
148
+ #
149
+ # Returns true if two objects are considered of equal value.
150
+ #
151
+ def eql?(obj)
152
+ return true if obj.equal?(self)
153
+ obj.eql?(__getobj__)
154
+ end
155
+
156
+ #
157
+ # Delegates ! to the \_\_getobj\_\_
158
+ #
159
+ def !
160
+ !__getobj__
161
+ end
162
+
163
+ #
164
+ # This method must be overridden by subclasses and should return the object
165
+ # method calls are being delegated to.
166
+ #
167
+ def __getobj__
168
+ __raise__ ::NotImplementedError, "need to define `__getobj__'"
169
+ end
170
+
171
+ #
172
+ # This method must be overridden by subclasses and change the object delegate
173
+ # to _obj_.
174
+ #
175
+ def __setobj__(obj)
176
+ __raise__ ::NotImplementedError, "need to define `__setobj__'"
177
+ end
178
+
179
+ #
180
+ # Serialization support for the object returned by \_\_getobj\_\_.
181
+ #
182
+ def marshal_dump
183
+ ivars = instance_variables.reject {|var| /\A@delegate_/ =~ var}
184
+ [
185
+ :__v2__,
186
+ ivars, ivars.map {|var| instance_variable_get(var)},
187
+ __getobj__
188
+ ]
189
+ end
190
+
191
+ #
192
+ # Reinitializes delegation from a serialized object.
193
+ #
194
+ def marshal_load(data)
195
+ version, vars, values, obj = data
196
+ if version == :__v2__
197
+ vars.each_with_index {|var, i| instance_variable_set(var, values[i])}
198
+ __setobj__(obj)
199
+ else
200
+ __setobj__(data)
201
+ end
202
+ end
203
+
204
+ def initialize_clone(obj) # :nodoc:
205
+ self.__setobj__(obj.__getobj__.clone)
206
+ end
207
+ def initialize_dup(obj) # :nodoc:
208
+ self.__setobj__(obj.__getobj__.dup)
209
+ end
210
+ private :initialize_clone, :initialize_dup
211
+
212
+ ##
213
+ # :method: trust
214
+ # Trust both the object returned by \_\_getobj\_\_ and self.
215
+ #
216
+
217
+ ##
218
+ # :method: untrust
219
+ # Untrust both the object returned by \_\_getobj\_\_ and self.
220
+ #
221
+
222
+ ##
223
+ # :method: taint
224
+ # Taint both the object returned by \_\_getobj\_\_ and self.
225
+ #
226
+
227
+ ##
228
+ # :method: untaint
229
+ # Untaint both the object returned by \_\_getobj\_\_ and self.
230
+ #
231
+
232
+ ##
233
+ # :method: freeze
234
+ # Freeze both the object returned by \_\_getobj\_\_ and self.
235
+ #
236
+
237
+ [:trust, :untrust, :taint, :untaint, :freeze].each do |method|
238
+ define_method method do
239
+ __getobj__.send(method)
240
+ super()
241
+ end
242
+ end
243
+
244
+ @delegator_api = self.public_instance_methods
245
+ def self.public_api # :nodoc:
246
+ @delegator_api
247
+ end
248
+ end
249
+
250
+ ##
251
+ # A concrete implementation of Delegator, this class provides the means to
252
+ # delegate all supported method calls to the object passed into the constructor
253
+ # and even to change the object being delegated to at a later time with
254
+ # #__setobj__.
255
+ #
256
+ # class User
257
+ # def born_on
258
+ # Date.new(1989, 9, 10)
259
+ # end
260
+ # end
261
+ #
262
+ # class UserDecorator < SimpleDelegator
263
+ # def birth_year
264
+ # born_on.year
265
+ # end
266
+ # end
267
+ #
268
+ # decorated_user = UserDecorator.new(User.new)
269
+ # decorated_user.birth_year #=> 1989
270
+ # decorated_user.__getobj__ #=> #<User: ...>
271
+ #
272
+ # A SimpleDelegator instance can take advantage of the fact that SimpleDelegator
273
+ # is a subclass of +Delegator+ to call <tt>super</tt> to have methods called on
274
+ # the object being delegated to.
275
+ #
276
+ # class SuperArray < SimpleDelegator
277
+ # def [](*args)
278
+ # super + 1
279
+ # end
280
+ # end
281
+ #
282
+ # SuperArray.new([1])[0] #=> 2
283
+ #
284
+ # Here's a simple example that takes advantage of the fact that
285
+ # SimpleDelegator's delegation object can be changed at any time.
286
+ #
287
+ # class Stats
288
+ # def initialize
289
+ # @source = SimpleDelegator.new([])
290
+ # end
291
+ #
292
+ # def stats(records)
293
+ # @source.__setobj__(records)
294
+ #
295
+ # "Elements: #{@source.size}\n" +
296
+ # " Non-Nil: #{@source.compact.size}\n" +
297
+ # " Unique: #{@source.uniq.size}\n"
298
+ # end
299
+ # end
300
+ #
301
+ # s = Stats.new
302
+ # puts s.stats(%w{James Edward Gray II})
303
+ # puts
304
+ # puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])
305
+ #
306
+ # Prints:
307
+ #
308
+ # Elements: 4
309
+ # Non-Nil: 4
310
+ # Unique: 4
311
+ #
312
+ # Elements: 8
313
+ # Non-Nil: 7
314
+ # Unique: 6
315
+ #
316
+ class SimpleDelegator < Delegator
317
+ # Returns the current object method calls are being delegated to.
318
+ def __getobj__
319
+ unless defined?(@delegate_sd_obj)
320
+ return yield if block_given?
321
+ __raise__ ::ArgumentError, "not delegated"
322
+ end
323
+ @delegate_sd_obj
324
+ end
325
+
326
+ #
327
+ # Changes the delegate object to _obj_.
328
+ #
329
+ # It's important to note that this does *not* cause SimpleDelegator's methods
330
+ # to change. Because of this, you probably only want to change delegation
331
+ # to objects of the same type as the original delegate.
332
+ #
333
+ # Here's an example of changing the delegation object.
334
+ #
335
+ # names = SimpleDelegator.new(%w{James Edward Gray II})
336
+ # puts names[1] # => Edward
337
+ # names.__setobj__(%w{Gavin Sinclair})
338
+ # puts names[1] # => Sinclair
339
+ #
340
+ def __setobj__(obj)
341
+ __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
342
+ @delegate_sd_obj = obj
343
+ end
344
+ end
345
+
346
+ def Delegator.delegating_block(mid) # :nodoc:
347
+ lambda do |*args, &block|
348
+ target = self.__getobj__
349
+ target.__send__(mid, *args, &block)
350
+ end
351
+ end
352
+
353
+ #
354
+ # The primary interface to this library. Use to setup delegation when defining
355
+ # your class.
356
+ #
357
+ # class MyClass < DelegateClass(ClassToDelegateTo) # Step 1
358
+ # def initialize
359
+ # super(obj_of_ClassToDelegateTo) # Step 2
360
+ # end
361
+ # end
362
+ #
363
+ # or:
364
+ #
365
+ # MyClass = DelegateClass(ClassToDelegateTo) do # Step 1
366
+ # def initialize
367
+ # super(obj_of_ClassToDelegateTo) # Step 2
368
+ # end
369
+ # end
370
+ #
371
+ # Here's a sample of use from Tempfile which is really a File object with a
372
+ # few special rules about storage location and when the File should be
373
+ # deleted. That makes for an almost textbook perfect example of how to use
374
+ # delegation.
375
+ #
376
+ # class Tempfile < DelegateClass(File)
377
+ # # constant and class member data initialization...
378
+ #
379
+ # def initialize(basename, tmpdir=Dir::tmpdir)
380
+ # # build up file path/name in var tmpname...
381
+ #
382
+ # @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
383
+ #
384
+ # # ...
385
+ #
386
+ # super(@tmpfile)
387
+ #
388
+ # # below this point, all methods of File are supported...
389
+ # end
390
+ #
391
+ # # ...
392
+ # end
393
+ #
394
+ def DelegateClass(superclass, &block)
395
+ klass = Class.new(Delegator)
396
+ ignores = [*::Delegator.public_api, :to_s, :inspect, :=~, :!~, :===]
397
+ protected_instance_methods = superclass.protected_instance_methods
398
+ protected_instance_methods -= ignores
399
+ public_instance_methods = superclass.public_instance_methods
400
+ public_instance_methods -= ignores
401
+ klass.module_eval do
402
+ def __getobj__ # :nodoc:
403
+ unless defined?(@delegate_dc_obj)
404
+ return yield if block_given?
405
+ __raise__ ::ArgumentError, "not delegated"
406
+ end
407
+ @delegate_dc_obj
408
+ end
409
+ def __setobj__(obj) # :nodoc:
410
+ __raise__ ::ArgumentError, "cannot delegate to self" if self.equal?(obj)
411
+ @delegate_dc_obj = obj
412
+ end
413
+ protected_instance_methods.each do |method|
414
+ define_method(method, Delegator.delegating_block(method))
415
+ protected method
416
+ end
417
+ public_instance_methods.each do |method|
418
+ define_method(method, Delegator.delegating_block(method))
419
+ end
420
+ end
421
+ klass.define_singleton_method :public_instance_methods do |all=true|
422
+ super(all) | superclass.public_instance_methods
423
+ end
424
+ klass.define_singleton_method :protected_instance_methods do |all=true|
425
+ super(all) | superclass.protected_instance_methods
426
+ end
427
+ klass.module_eval(&block) if block
428
+ return klass
429
+ end
@@ -0,0 +1,3 @@
1
+ class Delegator
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: delegate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Hiroshi SHIBATA
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-11-06 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Provides three abilities to delegate method calls to an object.
14
+ email:
15
+ - hsbt@ruby-lang.org
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".travis.yml"
22
+ - Gemfile
23
+ - LICENSE.txt
24
+ - README.md
25
+ - Rakefile
26
+ - bin/console
27
+ - bin/setup
28
+ - delegate.gemspec
29
+ - lib/delegate.rb
30
+ - lib/delegate/version.rb
31
+ homepage: https://github.com/ruby/delegate
32
+ licenses:
33
+ - BSD-2-Clause
34
+ metadata:
35
+ homepage_uri: https://github.com/ruby/delegate
36
+ source_code_uri: https://github.com/ruby/delegate
37
+ post_install_message:
38
+ rdoc_options: []
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ required_rubygems_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubygems_version: 3.0.3
53
+ signing_key:
54
+ specification_version: 4
55
+ summary: Provides three abilities to delegate method calls to an object.
56
+ test_files: []