dumb_delegator 0.8.1 → 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.
- checksums.yaml +4 -4
- data/.gitignore +23 -20
- data/.rspec +2 -1
- data/.travis.yml +1 -7
- data/CHANGELOG.md +8 -0
- data/Gemfile +3 -2
- data/README.md +102 -20
- data/Rakefile +4 -4
- data/dumb_delegator.gemspec +23 -14
- data/lib/dumb_delegator.rb +53 -8
- data/lib/dumb_delegator/triple_equal_ext.rb +29 -0
- data/lib/dumb_delegator/version.rb +1 -1
- data/spec/dumb_delegator_spec.rb +84 -32
- data/spec/spec_helper.rb +31 -4
- metadata +34 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3dfd1848821cd96312119f18cd2cc09bfcdc72c2efca3f53ddca59bb6247008f
|
4
|
+
data.tar.gz: 6dfd0d7689ed6b8d83dd0029e3687e624594e021c5ed0c58ca4ce6489abd8812
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72c45104a5258f109d258c6ff3268da7b7f1d2810f4a22ee916f8806d8cd5f3ca76ef01cfa6a7d2e18347158a25b4a727814e49be8ddec576a40d3b2bee6ca61
|
7
|
+
data.tar.gz: 49588ab5d55d168cf1916c7961285e9dc1c1a2f8fe0a6a097e6c671adee01424e374e99797410018e891fc6c9e09069515efbb84331fbd2f4c1cf9b486229ecd
|
data/.gitignore
CHANGED
@@ -1,20 +1,23 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
1
|
+
# Ignore all logfiles and tempfiles
|
2
|
+
/tmp/
|
3
|
+
/tags
|
4
|
+
|
5
|
+
# Environment normalisation
|
6
|
+
/.env
|
7
|
+
/.rspec-local
|
8
|
+
/.yardoc
|
9
|
+
/lib/bundler/man/
|
10
|
+
|
11
|
+
# Gem packaging stuff
|
12
|
+
/*.gem
|
13
|
+
/pkg/
|
14
|
+
|
15
|
+
# Dependencies and such
|
16
|
+
/.bundle
|
17
|
+
/.ruby-version
|
18
|
+
/Gemfile.lock
|
19
|
+
|
20
|
+
# Spec and coverage housekeeping
|
21
|
+
/coverage/
|
22
|
+
/spec/rspec-status.txt
|
23
|
+
/spec/reports
|
data/.rspec
CHANGED
data/.travis.yml
CHANGED
@@ -4,20 +4,14 @@ env:
|
|
4
4
|
global:
|
5
5
|
- CC_TEST_REPORTER_ID=de7062a4090ce5638b515a2cf9f2ab619de3e3f4ff439dc6cdad025c7a8d6b76
|
6
6
|
rvm:
|
7
|
-
- 1.9.3
|
8
|
-
- 2.0
|
9
|
-
- 2.1
|
10
|
-
- 2.2
|
11
|
-
- 2.3
|
12
7
|
- 2.4
|
13
8
|
- 2.5
|
14
9
|
- 2.6
|
15
10
|
- 2.7
|
16
|
-
- jruby-19mode
|
17
11
|
- jruby
|
18
12
|
cache: bundler
|
19
13
|
before_install:
|
20
|
-
- gem update --system --conservative
|
14
|
+
- gem update --system --conservative
|
21
15
|
- gem update bundler --conservative
|
22
16
|
before_script:
|
23
17
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|
5
5
|
|
6
6
|
## [Unreleased]
|
7
7
|
|
8
|
+
## [1.0.0] 2020-01-27
|
9
|
+
### Changed
|
10
|
+
- Require Ruby >= 2.4. We may still work with older Rubies, but no promises.
|
11
|
+
- Basic introspection support for a DumbDelegator instance: `#inspect`, `#method`, and `#methods`. [[13](https://github.com/stevenharman/dumb_delegator/pull/13)]
|
12
|
+
|
13
|
+
### Added
|
14
|
+
- Optional support for using a DumbDelegator instance in a `case` statement. [[12](https://github.com/stevenharman/dumb_delegator/pull/12)]
|
15
|
+
|
8
16
|
## [0.8.1] 2020-01-25
|
9
17
|
### Changed
|
10
18
|
- Explicitly Require Ruby >= 1.9.3
|
data/Gemfile
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
source
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in dumb_delegator.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem "simplecov", :
|
6
|
+
gem "simplecov", group: :test, require: nil
|
7
|
+
gem "pry-byebug", group: [:development, :test], platforms: [:ruby]
|
data/README.md
CHANGED
@@ -5,11 +5,10 @@
|
|
5
5
|
[](https://codeclimate.com/github/stevenharman/dumb_delegator/maintainability)
|
6
6
|
[](https://codeclimate.com/github/stevenharman/dumb_delegator/test_coverage)
|
7
7
|
|
8
|
-
|
9
8
|
Ruby provides the `delegate` standard library.
|
10
9
|
However, we found that it is not appropriate for cases that require nearly every call to be proxied.
|
11
10
|
|
12
|
-
For instance, Rails uses `#class` and `#instance_of?` to introspect on
|
11
|
+
For instance, Rails uses `#class` and `#instance_of?` to introspect on Model classes when generating forms and URL helpers.
|
13
12
|
These methods are not forwarded when using `Delegator` or `SimpleDelegator`.
|
14
13
|
|
15
14
|
```ruby
|
@@ -42,16 +41,47 @@ d.class #=> MyAwesomeClass
|
|
42
41
|
d.is_a? MyAwesomeClass #=> true
|
43
42
|
```
|
44
43
|
|
45
|
-
##
|
44
|
+
## Installation
|
46
45
|
|
47
|
-
|
46
|
+
Add this line to your application's Gemfile:
|
48
47
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
48
|
+
```ruby
|
49
|
+
gem "dumb_delegator"
|
50
|
+
```
|
51
|
+
|
52
|
+
And then execute:
|
53
|
+
|
54
|
+
```bash
|
55
|
+
$ bundle
|
56
|
+
```
|
57
|
+
|
58
|
+
Or install it yourself as:
|
59
|
+
|
60
|
+
```bash
|
61
|
+
$ gem install dumb_delegator
|
62
|
+
```
|
63
|
+
|
64
|
+
### Versioning
|
65
|
+
|
66
|
+
This project adheres to [Semantic Versioning][semver].
|
67
|
+
|
68
|
+
#### Version `0.8.x`
|
69
|
+
|
70
|
+
The `0.8.0` release was downloaded 1.2MM times before the `1.0.0` work began.
|
71
|
+
Which is great.
|
72
|
+
But, we wanted to clean up some cruft, fix a few small things, and improve ergonomics.
|
73
|
+
And do all of that, while, hopefully, not breaking existing usage.
|
74
|
+
|
75
|
+
To that end, `1.0.0` dropped support for all [EoL'd Rubies][ruby-releases] and only officially supported Ruby `2.4` - `2.7` when it was released.
|
76
|
+
However, most older Rubies, _should_ still work.
|
77
|
+
Maybe… Shmaybe?
|
78
|
+
Except for Ruby 1.9, which probably _does not work_ with `DumbDelegator` `> 1.0.0`.
|
79
|
+
If you're on an EoL'd Ruby, please try the `0.8.x` versions of this gem.
|
80
|
+
|
81
|
+
## Usage
|
53
82
|
|
54
|
-
|
83
|
+
`DumbDelegator`'s API and usage patters were inspired by Ruby stdlib's `SimpleDelegator`.
|
84
|
+
As such, the usage and ergonomics are quite similar.
|
55
85
|
|
56
86
|
```ruby
|
57
87
|
require "dumb_delegator"
|
@@ -79,25 +109,73 @@ class Sugar < DumbDelegator
|
|
79
109
|
end
|
80
110
|
|
81
111
|
coffee = Coffee.new
|
82
|
-
|
83
|
-
Sugar.new(
|
84
|
-
|
85
|
-
|
112
|
+
|
113
|
+
cup_o_coffee = Sugar.new(Milk.new(coffee))
|
114
|
+
cup_o_coffee.origin #=> Colombia
|
115
|
+
cup_o_coffee.cost #=> 2.6
|
116
|
+
|
117
|
+
# Introspection
|
118
|
+
cup_o_coffee.class #=> Coffee
|
119
|
+
cup_o_coffee.__getobj__ #=> #<Coffee:0x00007fabed1d6910>
|
120
|
+
cup_o_coffee.inspect #=> "#<Sugar:70188197507600 obj: #<Milk:70188197507620 obj: #<Coffee:0x00007fabed1d6910>>>"
|
121
|
+
cup_o_coffee.is_a?(Coffee) #=> true
|
122
|
+
cup_o_coffee.is_a?(Milk) #=> true
|
123
|
+
cup_o_coffee.is_a?(Sugar) #=> true
|
86
124
|
```
|
87
125
|
|
88
|
-
|
126
|
+
### Rails Model Decorator
|
89
127
|
|
90
|
-
|
128
|
+
There are [many decorator implementations](http://robots.thoughtbot.com/post/14825364877/evaluating-alternative-decorator-implementations-in) in Ruby.
|
129
|
+
One of the simplest is "`SimpleDelegator` + `super` + `__getobj__`," but it has the drawback of confusing Rails.
|
130
|
+
It is necessary to redefine `#class`, at a minimum.
|
131
|
+
If you're relying on Rails' URL Helpers with a delegated object, you also need to redefine `#instance_of?`.
|
132
|
+
We've also observed the need to redefine other Rails-y methods to get various bits of 🧙 Rails Magic 🧙 to work as expected.
|
91
133
|
|
92
|
-
|
134
|
+
With `DumbDelegator`, there's not a need for redefining these things because nearly every possible method is delegated.
|
93
135
|
|
94
|
-
|
136
|
+
### Optional `case` statement support
|
95
137
|
|
96
|
-
|
138
|
+
Instances of `DumbDelegator` will delegate `#===` out of the box.
|
139
|
+
Meaning an instance can be used in a `case` statement so long as the `when` clauses rely on instance comparison.
|
140
|
+
For example, when using a `case` with a regular expression, range, etc...
|
97
141
|
|
98
|
-
|
142
|
+
It's also common to use Class/Module in the `where` clauses.
|
143
|
+
In such usage, it's the Class/Module's `::===` method that gets called, rather than the `#===` method on the `DumbDelegator` instance.
|
144
|
+
That means we need to override each Class/Module's `::===` method, or even monkey-patch `::Module::===`.
|
145
|
+
|
146
|
+
`DumbDelegator` ships with an optional extension to override a Class/Module's `::===` method.
|
147
|
+
But you need to extend each Class/Module you use in a `where` clause.
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
def try_a_case(thing)
|
151
|
+
case thing
|
152
|
+
when MyAwesomeClass
|
153
|
+
"thing is a MyAwesomeClass."
|
154
|
+
when DumbDelegator
|
155
|
+
"thing is a DumbDelegator."
|
156
|
+
else
|
157
|
+
"Bad. This is bad."
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
target = MyAwesomeClass.new
|
162
|
+
dummy = DumbDelegator.new(target)
|
163
|
+
|
164
|
+
try_a_case(dummy) #=> thing is a DumbDelegator.
|
165
|
+
|
166
|
+
MyAwesomeClass.extend(DumbDelegator::TripleEqualExt)
|
167
|
+
|
168
|
+
try_a_case(dummy) #=> thing is a MyAwesomeClass.
|
169
|
+
```
|
99
170
|
|
100
|
-
|
171
|
+
#### Overriding `Module::===`
|
172
|
+
If necessary, you could also override the base `Module::===`, though that's pretty invasive.
|
173
|
+
|
174
|
+
🐲 _There be dragons!_ 🐉
|
175
|
+
|
176
|
+
```ruby
|
177
|
+
::Module.extend(DumbDelegator::TripleEqualExt)
|
178
|
+
```
|
101
179
|
|
102
180
|
## Contributing
|
103
181
|
|
@@ -110,3 +188,7 @@ Or install it yourself as:
|
|
110
188
|
## Contribution Ideas/Needs
|
111
189
|
|
112
190
|
1. Ruby 1.8 support (use the `blankslate` gem?)
|
191
|
+
|
192
|
+
|
193
|
+
[ruby-releases]: https://www.ruby-lang.org/en/downloads/branches/ "The current maintenance status of the various Ruby branches"
|
194
|
+
[semver]: https://semver.org/spec/v2.0.0.html "Semantic Versioning 2.0.0"
|
data/Rakefile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
-
require
|
2
|
+
require "bundler/gem_tasks"
|
3
3
|
|
4
|
-
require
|
4
|
+
require "rspec/core/rake_task"
|
5
5
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
6
|
-
t.rspec_opts =
|
6
|
+
t.rspec_opts = "--tag ~objectspace" if RUBY_PLATFORM == "java"
|
7
7
|
end
|
8
8
|
|
9
|
-
task :
|
9
|
+
task default: :spec
|
data/dumb_delegator.gemspec
CHANGED
@@ -1,22 +1,31 @@
|
|
1
|
-
|
2
|
-
require File.expand_path('../lib/dumb_delegator/version', __FILE__)
|
1
|
+
require File.expand_path("../lib/dumb_delegator/version", __FILE__)
|
3
2
|
|
4
3
|
Gem::Specification.new do |gem|
|
5
4
|
gem.name = "dumb_delegator"
|
6
5
|
gem.version = DumbDelegator::VERSION
|
7
|
-
gem.required_ruby_version = ">=
|
8
|
-
gem.authors
|
9
|
-
gem.email
|
10
|
-
gem.
|
11
|
-
gem.summary
|
12
|
-
|
6
|
+
gem.required_ruby_version = ">= 2.4.0"
|
7
|
+
gem.authors = ["Andy Lindeman", "Steven Harman"]
|
8
|
+
gem.email = ["alindeman@gmail.com", "steven@harmanly.com"]
|
9
|
+
gem.licenses = ["MIT"]
|
10
|
+
gem.summary = "Delegator class that delegates ALL the things"
|
11
|
+
gem.description = <<~EOD
|
12
|
+
Delegator and SimpleDelegator in Ruby's stdlib are useful, but they pull in most of Kernel.
|
13
|
+
This is not appropriate for many uses; for instance, delegation to Rails Models.
|
14
|
+
DumbDelegator, on the other hand, delegates nearly everything to the wrapped object.
|
13
15
|
EOD
|
14
|
-
gem.homepage
|
16
|
+
gem.homepage = "https://github.com/stevenharman/dumb_delegator"
|
15
17
|
|
16
|
-
gem.
|
17
|
-
|
18
|
-
|
18
|
+
gem.metadata = {
|
19
|
+
"changelog_uri" => "https://github.com/stevenharman/dumb_delegator/blob/master/CHANGELOG.md",
|
20
|
+
"documentation_uri" => "https://rubydoc.info/gems/dumb_delegator",
|
21
|
+
"source_code_uri" => "https://github.com/stevenharman/dumb_delegator",
|
22
|
+
}
|
19
23
|
|
20
|
-
gem.
|
21
|
-
gem.
|
24
|
+
gem.files = `git ls-files`.split($\)
|
25
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
26
|
+
gem.require_paths = ["lib"]
|
27
|
+
|
28
|
+
gem.add_development_dependency "pry"
|
29
|
+
gem.add_development_dependency "rake", "~> 13.0"
|
30
|
+
gem.add_development_dependency "rspec", "~> 3.9"
|
22
31
|
end
|
data/lib/dumb_delegator.rb
CHANGED
@@ -1,13 +1,48 @@
|
|
1
|
-
require
|
1
|
+
require "dumb_delegator/triple_equal_ext"
|
2
|
+
require "dumb_delegator/version"
|
2
3
|
|
4
|
+
##
|
5
|
+
# @example
|
6
|
+
# class Coffee
|
7
|
+
# def cost
|
8
|
+
# 2
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# def origin
|
12
|
+
# "Colombia"
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# class Milk < DumbDelegator
|
17
|
+
# def cost
|
18
|
+
# super + 0.4
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# class Sugar < DumbDelegator
|
23
|
+
# def cost
|
24
|
+
# super + 0.2
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# coffee = Coffee.new
|
29
|
+
# Milk.new(coffee).origin #=> Colombia
|
30
|
+
# Sugar.new(Sugar.new(coffee)).cost #=> 2.4
|
31
|
+
#
|
32
|
+
# cup_o_coffee = Sugar.new(Milk.new(coffee))
|
33
|
+
# cup_o_coffee.cost #=> 2.6
|
34
|
+
# cup_o_coffee.class #=> Coffee
|
35
|
+
# cup_o_coffee.is_a?(Coffee) #=> true
|
36
|
+
# cup_o_coffee.is_a?(Milk) #=> true
|
37
|
+
# cup_o_coffee.is_a?(Sugar) #=> true
|
3
38
|
class DumbDelegator < ::BasicObject
|
4
39
|
(::BasicObject.instance_methods - [:equal?, :__id__, :__send__, :method_missing]).each do |method|
|
5
|
-
undef_method
|
40
|
+
undef_method(method)
|
6
41
|
end
|
7
42
|
|
8
43
|
kernel = ::Kernel.dup
|
9
|
-
(kernel.instance_methods - [:dup, :clone, :respond_to?, :object_id]).each do |method|
|
10
|
-
kernel.__send__
|
44
|
+
(kernel.instance_methods - [:dup, :clone, :method, :methods, :respond_to?, :object_id]).each do |method|
|
45
|
+
kernel.__send__(:undef_method, method)
|
11
46
|
end
|
12
47
|
include kernel
|
13
48
|
|
@@ -15,8 +50,12 @@ class DumbDelegator < ::BasicObject
|
|
15
50
|
__setobj__(target)
|
16
51
|
end
|
17
52
|
|
18
|
-
def
|
19
|
-
|
53
|
+
def inspect
|
54
|
+
"#<#{(class << self; self; end).superclass}:#{object_id} obj: #{__getobj__.inspect}>"
|
55
|
+
end
|
56
|
+
|
57
|
+
def methods(all = true)
|
58
|
+
__getobj__.methods(all) | super
|
20
59
|
end
|
21
60
|
|
22
61
|
def method_missing(method, *args, &block)
|
@@ -27,19 +66,25 @@ class DumbDelegator < ::BasicObject
|
|
27
66
|
end
|
28
67
|
end
|
29
68
|
|
69
|
+
def respond_to_missing?(method, include_private = false)
|
70
|
+
__getobj__.respond_to?(method, include_private) || super
|
71
|
+
end
|
72
|
+
|
73
|
+
# @return [Object] The object calls are being delegated to
|
30
74
|
def __getobj__
|
31
75
|
@__dumb_target__
|
32
76
|
end
|
33
77
|
|
78
|
+
# @param obj [Object] Change the object delegate to +obj+.
|
34
79
|
def __setobj__(obj)
|
35
|
-
raise ::ArgumentError,
|
80
|
+
raise ::ArgumentError, "Delegation to self is not allowed." if obj.__id__ == __id__
|
36
81
|
@__dumb_target__ = obj
|
37
82
|
end
|
38
83
|
|
39
84
|
def marshal_dump
|
40
85
|
[
|
41
86
|
:__v1__,
|
42
|
-
__getobj__
|
87
|
+
__getobj__,
|
43
88
|
]
|
44
89
|
end
|
45
90
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class DumbDelegator < ::BasicObject
|
2
|
+
##
|
3
|
+
# This optional extension enables a Class/Module to support +case+ statements.
|
4
|
+
#
|
5
|
+
# Specifically, it monkey-patches a Class/Module's +:===+ method to check if the +other+ argument is an instance of the extended Class/Module.
|
6
|
+
#
|
7
|
+
# @example Extending a Class/Module to handle class equality for a DumbDelegator instance.
|
8
|
+
#
|
9
|
+
# target = MyAwesomeClass.new
|
10
|
+
# dummy = DumbDelegator.new(target)
|
11
|
+
#
|
12
|
+
# MyAwesomeClass === dummy #=> false
|
13
|
+
# DumbDelegator === dummy #=> true
|
14
|
+
#
|
15
|
+
# MyAwesomeClass.extend(DumbDelegator::TripleEqualExt)
|
16
|
+
#
|
17
|
+
# MyAwesomeClass === dummy #=> true
|
18
|
+
# DumbDelegator === dummy #=> true
|
19
|
+
module TripleEqualExt
|
20
|
+
# Case equality for the extended Class/Module and then given +other+.
|
21
|
+
#
|
22
|
+
# @param other [Object] An instance of any Object
|
23
|
+
#
|
24
|
+
# @return [Boolean] If the +other+ is an instance of the Class/Module.
|
25
|
+
def ===(other)
|
26
|
+
super || other.is_a?(self)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/dumb_delegator_spec.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
describe DumbDelegator do
|
1
|
+
RSpec.describe DumbDelegator do
|
4
2
|
subject(:dummy) { Wrapper.new(target) }
|
5
3
|
let(:target) { Target.new }
|
6
4
|
|
@@ -55,8 +53,6 @@ describe DumbDelegator do
|
|
55
53
|
end
|
56
54
|
|
57
55
|
it "responds to methods defined by child classes" do
|
58
|
-
expect(target).to receive(:wrapper_method).never
|
59
|
-
|
60
56
|
expect(dummy.wrapper_method).to eq("Method only on wrapper.")
|
61
57
|
end
|
62
58
|
|
@@ -85,51 +81,76 @@ describe DumbDelegator do
|
|
85
81
|
end
|
86
82
|
|
87
83
|
it "delegates object equivalence" do
|
88
|
-
|
89
|
-
|
84
|
+
aggregate_failures do
|
85
|
+
expect(dummy).to eql(target)
|
86
|
+
expect(dummy == target).to be true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it "delegates #===" do
|
91
|
+
expect(dummy === target).to be true
|
90
92
|
end
|
91
93
|
|
92
94
|
it "delegates class checks" do
|
93
|
-
|
94
|
-
|
95
|
-
|
95
|
+
aggregate_failures do
|
96
|
+
expect(dummy.is_a?(Target)).to be(true)
|
97
|
+
expect(dummy.kind_of?(Target)).to be(true) # rubocop:disable Style/ClassCheck
|
98
|
+
expect(dummy.instance_of?(Target)).to be(true)
|
99
|
+
end
|
96
100
|
end
|
97
101
|
|
98
|
-
it "
|
99
|
-
|
100
|
-
|
102
|
+
it "does not delegate ::=== to the target's class" do
|
103
|
+
aggregate_failures do
|
104
|
+
expect(Target === dummy).to be false
|
105
|
+
expect(DumbDelegator === dummy).to be true
|
106
|
+
end
|
101
107
|
end
|
102
108
|
|
103
|
-
|
109
|
+
context "with a Module/Class's ::=== overridden via extension" do
|
110
|
+
let(:target) { TargetWithTripleEqualExt.new }
|
111
|
+
|
112
|
+
class TargetWithTripleEqualExt
|
113
|
+
extend DumbDelegator::TripleEqualExt
|
114
|
+
end
|
115
|
+
|
116
|
+
it "delegates ::=== to the target's class" do
|
117
|
+
aggregate_failures do
|
118
|
+
expect(TargetWithTripleEqualExt === dummy).to be true
|
119
|
+
expect(DumbDelegator === dummy).to be true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
it "delegates instance_eval" do
|
104
125
|
expect(target).to receive(:instance_eval)
|
105
126
|
dummy.instance_eval { true }
|
106
127
|
end
|
107
128
|
|
108
|
-
it
|
129
|
+
it "delegates instance_exec" do
|
109
130
|
expect(target).to receive(:instance_exec)
|
110
131
|
dummy.instance_exec { true }
|
111
132
|
end
|
112
133
|
|
113
|
-
describe
|
114
|
-
it
|
134
|
+
describe "#dup" do
|
135
|
+
it "returns a shallow of itself, the delegator (not the underlying object)", objectspace: true do
|
115
136
|
dupped = dummy.dup
|
116
137
|
|
117
138
|
expect(ObjectSpace.each_object(DumbDelegator).map(&:__id__)).to include dupped.__id__
|
118
139
|
end
|
119
140
|
end
|
120
141
|
|
121
|
-
describe
|
122
|
-
it
|
142
|
+
describe "#clone" do
|
143
|
+
it "returns a shallow of itself, the delegator (not the underlying object)", objectspace: true do
|
123
144
|
cloned = dummy.clone
|
124
145
|
|
125
146
|
expect(ObjectSpace.each_object(DumbDelegator).map(&:__id__)).to include cloned.__id__
|
126
147
|
end
|
127
148
|
end
|
128
149
|
|
129
|
-
describe
|
150
|
+
describe "marshaling" do
|
130
151
|
let(:target) { Object.new }
|
131
152
|
|
132
|
-
it
|
153
|
+
it "marshals and unmarshals itself, the delegator (not the underlying object)", objectspace: true do
|
133
154
|
marshaled = Marshal.dump(dummy)
|
134
155
|
unmarshaled = Marshal.load(marshaled)
|
135
156
|
|
@@ -137,7 +158,7 @@ describe DumbDelegator do
|
|
137
158
|
end
|
138
159
|
end
|
139
160
|
|
140
|
-
describe
|
161
|
+
describe "#respond_to?" do
|
141
162
|
[:equal?, :__id__, :__send__, :dup, :clone, :__getobj__, :__setobj__, :marshal_dump, :marshal_load, :respond_to?].each do |method|
|
142
163
|
it "responds to #{method}" do
|
143
164
|
expect(dummy.respond_to?(method)).to be true
|
@@ -157,22 +178,53 @@ describe DumbDelegator do
|
|
157
178
|
end
|
158
179
|
end
|
159
180
|
|
160
|
-
describe
|
161
|
-
it
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
181
|
+
describe "#__setobj__" do
|
182
|
+
it "resets the target object to a different object" do
|
183
|
+
new_target = Target.new.tap do |nt|
|
184
|
+
def nt.a_new_thing
|
185
|
+
true
|
186
|
+
end
|
187
|
+
end
|
166
188
|
|
167
189
|
dummy.__setobj__(new_target)
|
168
|
-
dummy.
|
190
|
+
expect(dummy.a_new_thing).to be true
|
169
191
|
end
|
170
192
|
|
171
|
-
it
|
193
|
+
it "cannot delegate to itself" do
|
172
194
|
expect {
|
173
195
|
dummy.__setobj__(dummy)
|
174
|
-
dummy.
|
175
|
-
}.to raise_error(ArgumentError,
|
196
|
+
dummy.common_method
|
197
|
+
}.to raise_error(ArgumentError, "Delegation to self is not allowed.")
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe "introspection capabilities" do
|
202
|
+
it "provides a human-friendly representation of the delegator and wrapped object" do
|
203
|
+
expect(dummy.inspect).to match(/#<Wrapper:\w+ obj: .+Target.+>/)
|
204
|
+
end
|
205
|
+
|
206
|
+
it "reports methods defined on the target" do
|
207
|
+
expect(dummy.methods).to include(:target_method, :common_method)
|
208
|
+
end
|
209
|
+
|
210
|
+
it "reports methods defined on the wrapper" do
|
211
|
+
expect(dummy.methods).to include(:wrapper_method, :common_method)
|
212
|
+
end
|
213
|
+
|
214
|
+
it "looks up a named method on the target" do
|
215
|
+
method = dummy.method(:target_method)
|
216
|
+
aggregate_failures do
|
217
|
+
expect(method).not_to be_nil
|
218
|
+
expect(method.receiver).to eq(target)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
it "looks up a named method on the wrapper" do
|
223
|
+
method = dummy.method(:wrapper_method)
|
224
|
+
aggregate_failures do
|
225
|
+
expect(method).not_to be_nil
|
226
|
+
expect(method.receiver).to equal(dummy)
|
227
|
+
end
|
176
228
|
end
|
177
229
|
end
|
178
230
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,11 +1,38 @@
|
|
1
|
-
if ENV["
|
1
|
+
if ENV["CC_TEST_REPORTER_ID"] || ENV["COVERAGE"]
|
2
2
|
require "simplecov"
|
3
3
|
SimpleCov.start
|
4
4
|
end
|
5
5
|
|
6
|
-
require
|
6
|
+
require "pry"
|
7
|
+
require File.expand_path("../lib/dumb_delegator", File.dirname(__FILE__))
|
7
8
|
|
8
9
|
RSpec.configure do |config|
|
9
|
-
config.
|
10
|
-
|
10
|
+
config.expect_with :rspec do |expectations|
|
11
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
12
|
+
end
|
13
|
+
|
14
|
+
config.mock_with :rspec do |mocks|
|
15
|
+
mocks.verify_partial_doubles = true
|
16
|
+
end
|
17
|
+
|
18
|
+
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
19
|
+
# have no way to turn it off -- the option exists only for backwards
|
20
|
+
# compatibility in RSpec 3). It causes shared context metadata to be
|
21
|
+
# inherited by the metadata hash of host groups and examples, rather than
|
22
|
+
# triggering implicit auto-inclusion in groups with matching metadata.
|
23
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
24
|
+
|
25
|
+
config.filter_run_when_matching :focus
|
26
|
+
config.example_status_persistence_file_path = "spec/rspec-status.txt"
|
27
|
+
config.disable_monkey_patching!
|
28
|
+
config.warnings = true
|
29
|
+
|
30
|
+
if config.files_to_run.one?
|
31
|
+
# Use the documentation formatter for detailed output,
|
32
|
+
# unless a formatter has already been configured
|
33
|
+
# (e.g. via a command-line flag).
|
34
|
+
config.default_formatter = "doc"
|
35
|
+
end
|
36
|
+
config.order = :random
|
37
|
+
Kernel.srand config.seed
|
11
38
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dumb_delegator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Lindeman
|
@@ -9,37 +9,54 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-01-
|
12
|
+
date: 2020-01-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: pry
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: rake
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
17
31
|
requirements:
|
18
32
|
- - "~>"
|
19
33
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
34
|
+
version: '13.0'
|
21
35
|
type: :development
|
22
36
|
prerelease: false
|
23
37
|
version_requirements: !ruby/object:Gem::Requirement
|
24
38
|
requirements:
|
25
39
|
- - "~>"
|
26
40
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
41
|
+
version: '13.0'
|
28
42
|
- !ruby/object:Gem::Dependency
|
29
43
|
name: rspec
|
30
44
|
requirement: !ruby/object:Gem::Requirement
|
31
45
|
requirements:
|
32
46
|
- - "~>"
|
33
47
|
- !ruby/object:Gem::Version
|
34
|
-
version: '3.
|
48
|
+
version: '3.9'
|
35
49
|
type: :development
|
36
50
|
prerelease: false
|
37
51
|
version_requirements: !ruby/object:Gem::Requirement
|
38
52
|
requirements:
|
39
53
|
- - "~>"
|
40
54
|
- !ruby/object:Gem::Version
|
41
|
-
version: '3.
|
42
|
-
description:
|
55
|
+
version: '3.9'
|
56
|
+
description: |
|
57
|
+
Delegator and SimpleDelegator in Ruby's stdlib are useful, but they pull in most of Kernel.
|
58
|
+
This is not appropriate for many uses; for instance, delegation to Rails Models.
|
59
|
+
DumbDelegator, on the other hand, delegates nearly everything to the wrapped object.
|
43
60
|
email:
|
44
61
|
- alindeman@gmail.com
|
45
62
|
- steven@harmanly.com
|
@@ -57,12 +74,17 @@ files:
|
|
57
74
|
- Rakefile
|
58
75
|
- dumb_delegator.gemspec
|
59
76
|
- lib/dumb_delegator.rb
|
77
|
+
- lib/dumb_delegator/triple_equal_ext.rb
|
60
78
|
- lib/dumb_delegator/version.rb
|
61
79
|
- spec/dumb_delegator_spec.rb
|
62
80
|
- spec/spec_helper.rb
|
63
81
|
homepage: https://github.com/stevenharman/dumb_delegator
|
64
|
-
licenses:
|
65
|
-
|
82
|
+
licenses:
|
83
|
+
- MIT
|
84
|
+
metadata:
|
85
|
+
changelog_uri: https://github.com/stevenharman/dumb_delegator/blob/master/CHANGELOG.md
|
86
|
+
documentation_uri: https://rubydoc.info/gems/dumb_delegator
|
87
|
+
source_code_uri: https://github.com/stevenharman/dumb_delegator
|
66
88
|
post_install_message:
|
67
89
|
rdoc_options: []
|
68
90
|
require_paths:
|
@@ -71,19 +93,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
71
93
|
requirements:
|
72
94
|
- - ">="
|
73
95
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
96
|
+
version: 2.4.0
|
75
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
98
|
requirements:
|
77
99
|
- - ">="
|
78
100
|
- !ruby/object:Gem::Version
|
79
101
|
version: '0'
|
80
102
|
requirements: []
|
81
|
-
rubygems_version: 3.0.
|
103
|
+
rubygems_version: 3.0.3
|
82
104
|
signing_key:
|
83
105
|
specification_version: 4
|
84
|
-
summary: Delegator
|
85
|
-
pull in most of Kernel. This is not appropriate for many uses; for instance, delegation
|
86
|
-
to Rails models.
|
106
|
+
summary: Delegator class that delegates ALL the things
|
87
107
|
test_files:
|
88
108
|
- spec/dumb_delegator_spec.rb
|
89
109
|
- spec/spec_helper.rb
|