magic-decorator 0.2.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 910cb75b4dedfce18a494e39779b65821642feb96a24f3cda7228deea96ccd04
4
- data.tar.gz: 98603bb63196fa955b4aec3172ff6326f5be10371b0fffb96404a9f5cd84a86b
3
+ metadata.gz: 84b46e61d09d011e36bfd527b1e99bf9b83a7d3d4844f9afcd11304abd5c7990
4
+ data.tar.gz: 22f50120c5b4b8b2887d28b3e909f698128c04a37293c9409d93411dddb1f2e3
5
5
  SHA512:
6
- metadata.gz: 4b4bfb9bbb3838ac81dc35527caddd9d42d86887e1019ad75c7aad5f21af03607a1540523555aa0669baef7705a989af99487d3fa0a925fe8fedca96749070e3
7
- data.tar.gz: 9f1cc4b1b608fd9b795b2a296c7919e513ed0a9ea7a9c0d1957fe23e5f5b537edc7ea30985ccc02ce72ca5fac1c7707d8b44769502a4f702e426dd26c2ce1260
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
+ ![GitHub Actions Workflow Status](
4
+ https://img.shields.io/github/actions/workflow/status/Alexander-Senko/magic-decorator/ci.yml
5
+ )
3
6
  ![Code Climate maintainability](
4
7
  https://img.shields.io/codeclimate/maintainability-percentage/Alexander-Senko/magic-decorator
5
8
  )
@@ -60,12 +63,40 @@ One can test for the object is actually decorated with `#decorated?`.
60
63
  .decorated? # => true
61
64
  ```
62
65
 
63
- ## Magic
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.
@@ -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, Decorator)
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 = Decorator.for self.class
25
+ def decorator = decorator_base.for self.class
26
+ def decorator_base = Decorator
13
27
  end
14
28
  end
@@ -5,7 +5,8 @@ require 'delegate'
5
5
  module Magic
6
6
  module Decorator
7
7
  class Base < SimpleDelegator
8
- extend Lookup
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Magic
4
4
  module Decorator
5
- VERSION = '0.2.0'
5
+ VERSION = '1.0.0'
6
6
  end
7
7
  end
@@ -1,13 +1,16 @@
1
1
  module Magic
2
2
  module Decoratable
3
- def decorate: -> Decorator?
4
- def decorate!: -> Decorator
5
- def decorated: -> (Decorator | self)
3
+ def self.classes: () -> Array[Class]
6
4
 
7
- def decorated?: -> bool
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.2.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-17 00:00:00.000000000 Z
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/v0.2.0/CHANGELOG.md
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