magic-decorator 0.2.0 → 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/CHANGELOG.md +26 -0
- data/README.md +77 -1
- data/lib/magic/decoratable.rb +16 -2
- data/lib/magic/decorator/base.rb +4 -1
- data/lib/magic/decorator/version.rb +1 -1
- data/sig/magic/decoratable.rbs +8 -5
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84b46e61d09d011e36bfd527b1e99bf9b83a7d3d4844f9afcd11304abd5c7990
|
4
|
+
data.tar.gz: 22f50120c5b4b8b2887d28b3e909f698128c04a37293c9409d93411dddb1f2e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ad5fc1e9e7cf8fab9a75a792cc31f027e113e95f7968ee2f6502b113c4f8f943bf7f111fa599929896e6bf7a3a77cf7cf13d46c6fe58dd52e770fc109278d42
|
7
|
+
data.tar.gz: 743f50f6835be84d59028240ec9c306df79f8647c90d4b4c34d39eb9e462741cbfc3f0ebde4bea447c0a94b731e61a8e370c497d84821bfe9dfa4272771f3d8b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
## [1.0.0] — 2024-11-23
|
2
|
+
|
3
|
+
This release marks the gem to be stable enough.
|
4
|
+
|
5
|
+
> [!NOTE]
|
6
|
+
> Nothing notable was changed in the code since the last version.
|
7
|
+
|
8
|
+
### Documentation
|
9
|
+
|
10
|
+
- Added a section about overriding the defaults.
|
11
|
+
- Added a section about testing.
|
12
|
+
|
13
|
+
|
14
|
+
## [0.3.0] — 2024-10-27
|
15
|
+
|
16
|
+
### Added
|
17
|
+
|
18
|
+
- Improved extendability: one may override `Magic::Decoratable#decorator_base` to be used for lookups.
|
19
|
+
- `Magic::Decoratable.classes` for all the decoratables.
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
|
23
|
+
- Failures on double decoration attempts.
|
24
|
+
|
25
|
+
|
1
26
|
## [0.2.0] — 2024-10-17
|
2
27
|
|
3
28
|
### Changed
|
@@ -19,6 +44,7 @@
|
|
19
44
|
- enables _double-splat_ operator: `**decorated`,
|
20
45
|
- enumerating methods yield decorated items.
|
21
46
|
|
47
|
+
|
22
48
|
## [0.1.0] — 2024-10-13
|
23
49
|
|
24
50
|
### Added
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# 🪄 Magic Decorator
|
2
2
|
|
3
|
+

|
3
6
|

|
@@ -60,12 +63,40 @@ One can test for the object is actually decorated with `#decorated?`.
|
|
60
63
|
.decorated? # => true
|
61
64
|
```
|
62
65
|
|
63
|
-
|
66
|
+
### Extending decorator logic
|
67
|
+
|
68
|
+
When extending `Magic::Decoratable`, one may override `#decorator_base` to be used for lookup.
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
class Special::Decorator < Magic::Decorator::Base
|
72
|
+
def self.name_for object_class
|
73
|
+
"Special::#{object_class}Decorator"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module Special::Decoratable
|
78
|
+
include Magic::Decoratable
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def decorator_base = Special::Decorator
|
83
|
+
end
|
84
|
+
|
85
|
+
class Special::Model
|
86
|
+
include Special::Decoratable
|
87
|
+
end
|
88
|
+
|
89
|
+
Special::Model.new.decorate # looks for Special::Decorator descendants
|
90
|
+
```
|
91
|
+
|
92
|
+
## 🪄 Magic
|
64
93
|
|
65
94
|
### Decoratable scope
|
66
95
|
|
67
96
|
`Magic::Decoratable` is mixed into `Object` by default. It means that effectively any object is _magically decoratable_.
|
68
97
|
|
98
|
+
One can use `Magic::Decoratable.classes` to see all the decoratable classes.
|
99
|
+
|
69
100
|
### Decoration expansion
|
70
101
|
|
71
102
|
For almost any method called on a decorated object, both its result and `yield`ed arguments get decorated.
|
@@ -134,6 +165,51 @@ It automagically decorates all its decoratable items.
|
|
134
165
|
- enables _double-splat_ operator: `**decorated`,
|
135
166
|
- enumerating methods yield decorated items.
|
136
167
|
|
168
|
+
## Overriding the magic
|
169
|
+
|
170
|
+
When one needs more complicated behavior than the default one or feels like [_explicit is better than implicit_](
|
171
|
+
https://peps.python.org/pep-0020/#the-zen-of-python
|
172
|
+
).
|
173
|
+
|
174
|
+
### Decorator class inference
|
175
|
+
|
176
|
+
One may override `#decorator` for any decoratable class, to be used instead of Magic Lookup.
|
177
|
+
|
178
|
+
- That could be as straightforward as a constant:
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
class Guest
|
182
|
+
private
|
183
|
+
|
184
|
+
def decorator = UserDecorator
|
185
|
+
end
|
186
|
+
|
187
|
+
guest.decorate # => instance of UserDecorator
|
188
|
+
```
|
189
|
+
|
190
|
+
- Or, that could be virtually any logic:
|
191
|
+
|
192
|
+
```ruby
|
193
|
+
class User
|
194
|
+
private
|
195
|
+
|
196
|
+
def decorator = admin? ? AdminDecorator : super
|
197
|
+
end
|
198
|
+
|
199
|
+
user.decorate # => instance of UserDecorator
|
200
|
+
admin.decorate # => instance of AdminDecorator
|
201
|
+
```
|
202
|
+
|
203
|
+
## Testing decorators
|
204
|
+
|
205
|
+
Testing a decorator is much like testing any other class.
|
206
|
+
|
207
|
+
To test whether an object is decorated one can use `#decorated?` method.
|
208
|
+
|
209
|
+
> [!NOTE]
|
210
|
+
> A decorated object equals the original one (`object.decorated == object`).
|
211
|
+
> Thus, any existing tests shouldn’t break when the objects being tested get decorated.
|
212
|
+
|
137
213
|
## Development
|
138
214
|
|
139
215
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/magic/decoratable.rb
CHANGED
@@ -1,14 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
3
5
|
module Magic
|
4
6
|
module Decoratable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
class_methods do
|
10
|
+
def classes
|
11
|
+
ObjectSpace.each_object(Class)
|
12
|
+
.select { _1 < self }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
extend ClassMethods
|
17
|
+
|
5
18
|
def decorate = decorator&.new self
|
6
|
-
def decorate! = decorate || raise(Lookup::Error.for self,
|
19
|
+
def decorate! = decorate || raise(Lookup::Error.for self, decorator_base)
|
7
20
|
def decorated = decorate || self
|
8
21
|
def decorated? = false
|
9
22
|
|
10
23
|
private
|
11
24
|
|
12
|
-
def decorator
|
25
|
+
def decorator = decorator_base.for self.class
|
26
|
+
def decorator_base = Decorator
|
13
27
|
end
|
14
28
|
end
|
data/lib/magic/decorator/base.rb
CHANGED
@@ -5,7 +5,8 @@ require 'delegate'
|
|
5
5
|
module Magic
|
6
6
|
module Decorator
|
7
7
|
class Base < SimpleDelegator
|
8
|
-
extend
|
8
|
+
extend Lookup
|
9
|
+
include Decoratable
|
9
10
|
|
10
11
|
class << self
|
11
12
|
def name_for(object_class) = "#{object_class}Decorator"
|
@@ -33,6 +34,8 @@ module Magic
|
|
33
34
|
deconstruct_keys
|
34
35
|
]
|
35
36
|
|
37
|
+
private
|
38
|
+
|
36
39
|
def method_missing(method, ...)
|
37
40
|
return super if method.start_with? 'to_' # converter
|
38
41
|
return super if method.start_with? '_' # system
|
data/sig/magic/decoratable.rbs
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
module Magic
|
2
2
|
module Decoratable
|
3
|
-
def
|
4
|
-
def decorate!: -> Decorator
|
5
|
-
def decorated: -> (Decorator | self)
|
3
|
+
def self.classes: () -> Array[Class]
|
6
4
|
|
7
|
-
def
|
5
|
+
def decorate: () -> Decorator?
|
6
|
+
def decorate!: () -> Decorator
|
7
|
+
def decorated: () -> (Decorator | self)
|
8
|
+
|
9
|
+
def decorated?: () -> bool
|
8
10
|
|
9
11
|
private
|
10
12
|
|
11
|
-
def decorator: -> Class?
|
13
|
+
def decorator: () -> Class?
|
14
|
+
def decorator_base: () -> Module
|
12
15
|
end
|
13
16
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: magic-decorator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Senko
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2024-
|
10
|
+
date: 2024-11-23 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: magic-lookup
|
@@ -23,6 +23,20 @@ dependencies:
|
|
23
23
|
- - ">="
|
24
24
|
- !ruby/object:Gem::Version
|
25
25
|
version: '0'
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: activesupport
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
26
40
|
description: 'SimpleDelegator on steroids: automatic delegation, decorator class inference,
|
27
41
|
etc.'
|
28
42
|
email:
|
@@ -55,7 +69,7 @@ licenses:
|
|
55
69
|
metadata:
|
56
70
|
homepage_uri: https://github.com/Alexander-Senko/magic-decorator
|
57
71
|
source_code_uri: https://github.com/Alexander-Senko/magic-decorator
|
58
|
-
changelog_uri: https://github.com/Alexander-Senko/magic-decorator/blob/
|
72
|
+
changelog_uri: https://github.com/Alexander-Senko/magic-decorator/blob/v1.0.0/CHANGELOG.md
|
59
73
|
rdoc_options: []
|
60
74
|
require_paths:
|
61
75
|
- lib
|