magic-decorator 1.1.1 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7cf3d435ee5af817990bfe657305a0112a012786540a89628a78d1bd6649dda
4
- data.tar.gz: 61a1f7a7a3f1a8734ecb7ab5b8e414bd4055181d11a8ef2ef164868ecf27bbfa
3
+ metadata.gz: d922af068afa4289fc270fe9b007de813cff5b8855fc12ff925cfcbe0831d018
4
+ data.tar.gz: 0d95e22503c504847815bad194faf699614840be21fb2aadc231d47c107823a0
5
5
  SHA512:
6
- metadata.gz: 8146547bc999da507600a3af86de3aaf174e27f66cd3e1b866e2e8e4703f92ef3a6c48f5a2ca217decc7950e645cc03af35a1e6a8f94db5849ef0663470bfe6c
7
- data.tar.gz: d33c6fd8584763e694870b2047093964ecdf7ee770649fc0f7d3c89c3711c26108ee9f9dd7b7dfb6c76b3d9e7a3f08e5e902bfa9e5eb8241a366601993be0799
6
+ metadata.gz: 8a3c8d64bbf55a1a9aac586f3489b9ccead69dfb734d1352d44f908e5a8c6973de230d1a498615cef92ac59c4f0727f30c38ded0ed61072dcaf1ce78d0612485
7
+ data.tar.gz: ef85e806210c58a398d43f0bf558482ee62e94632757cb7de3e0e9c5c96ff1c56ff81ef069f88ddaef4c1b2154b1932f753d180f8b709ebddcd9659f346025a3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [1.2.0] — 2026-10-28
2
+
3
+ ### Added
4
+
5
+ - `Module#decorated_method`
6
+ to decorate method return values.
7
+
8
+
1
9
  ## [1.1.1] — 2026-10-27
2
10
 
3
11
  ### Fixed
@@ -46,7 +54,7 @@ This release marks the gem to be stable enough.
46
54
 
47
55
  - Improved extendability: one may override `Magic::Decoratable#decorator_base` to be used for lookups.
48
56
  - `Magic::Decoratable.classes`
49
- for all the decoratables.
57
+ for all the decoratables.
50
58
 
51
59
  ### Fixed
52
60
 
@@ -58,7 +66,7 @@ This release marks the gem to be stable enough.
58
66
  ### Changed
59
67
 
60
68
  - For almost any method called on a decorated object, both its result and `yield`ed arguments get decorated.
61
- Some methods aren’t meant to be decorated though:
69
+ Some methods aren’t meant to be decorated though:
62
70
  - `deconstruct` & `deconstruct_keys` for _pattern matching_,
63
71
  - _converting_ methods: those starting with `to_`,
64
72
  - _system_ methods: those starting with `_`.
@@ -66,12 +74,12 @@ This release marks the gem to be stable enough.
66
74
  ### Added
67
75
 
68
76
  - `Magic::Decorator::Base.undecorated`
69
- to exclude methods from being decorated automagically.
77
+ to exclude methods from being decorated automagically.
70
78
 
71
79
  #### Default decorators
72
80
 
73
81
  - `EnumerableDecorator`
74
- to decorate `Enumerable`s.
82
+ to decorate `Enumerable`s.
75
83
  - enables _splat_ operator: `*decorated` ,
76
84
  - enables _double-splat_ operator: `**decorated`,
77
85
  - enumerating methods yield decorated items.
@@ -82,9 +90,9 @@ This release marks the gem to be stable enough.
82
90
  ### Added
83
91
 
84
92
  - `Magic::Decorator::Base`
85
- — a basic decorator class.
93
+ — a basic decorator class.
86
94
  - `Magic::Decoratable`
87
- to be included in decoratable classes.
95
+ to be included in decoratable classes.
88
96
  - `#decorate`,
89
97
  - `#decorate!`,
90
98
  - `#decorated`,
data/README.md CHANGED
@@ -93,6 +93,38 @@ end
93
93
  Special::Model.new.decorate # looks for Special::Decorator descendants
94
94
  ```
95
95
 
96
+ ### Decorating methods
97
+
98
+ `Module#decorated_method` decorates the return value of one or more existing instance methods by calling `#decorated` on it.
99
+ It accepts method names as symbols or strings, either separately or in one array, and returns those names as `Module#private` does:
100
+
101
+ ```ruby
102
+ class Account
103
+ decorated_method attr_reader :owner
104
+ decorated_method def address = owner.address
105
+ decorated_method :method_missing
106
+ end
107
+ ```
108
+
109
+ Calling it without arguments decorates instance methods defined afterward:
110
+
111
+ ```ruby
112
+ class Account
113
+ decorated_method
114
+
115
+ attr_reader :owner
116
+ def address = owner.address
117
+ end
118
+ ```
119
+
120
+ Method arguments, keyword arguments, blocks, and visibility are preserved.
121
+
122
+ > [!IMPORTANT]
123
+ > This core class extension is not loaded by default and should be required explicitly if needed:
124
+ > ```ruby
125
+ > require 'magic/decorator/core_ext/module'
126
+ > ```
127
+
96
128
  ## 🪄 Magic
97
129
 
98
130
  ### Decoratable scope
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # = Enumerable Decorator
4
+ #
5
+ # As the name suggests, it’s used automatically to decorate any
6
+ # `Enumerable` collection. The collection itself doesn’t get decorated,
7
+ # while its items do.
3
8
  class EnumerableDecorator < Magic::Decorator::Base
4
9
  def to_a(...) = super.map &:decorated
5
10
  def to_ary(...) = super.map &:decorated
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Magic
4
+ # = Decoratable object
5
+ #
6
+ # This module allows a descendant to be decorated. Decorator class is
7
+ # being inferred automatically via Magic Lookup.
4
8
  module Decoratable
5
9
  include Lookup::Scope
6
10
 
@@ -4,6 +4,18 @@ require 'delegate'
4
4
 
5
5
  module Magic
6
6
  module Decorator
7
+ # = Magic Decorator
8
+ #
9
+ # Any decorator should inherit `Magic::Decorator::Base`.
10
+ # It further inherits from `SimpleDelegator` and behaves like that.
11
+ #
12
+ # == Decorator class inference
13
+ #
14
+ # Decorators provide automatic class inference for any class based
15
+ # on its name powered by Magic Lookup.
16
+ # For example, `MyObject.new` looks for `MyObjectDecorator` first.
17
+ # If not found, it looks for decorators of its ancestor classes,
18
+ # up to `ObjectDecorator`.
7
19
  class Base < SimpleDelegator
8
20
  extend Lookup
9
21
  include Decoratable
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Lint/EmptyInPattern
4
+
5
+ require 'active_support/core_ext/module/redefine_method'
6
+
7
+ # Extends Module with method return-value decoration.
8
+ class Module
9
+ # Prepend it to decorate all subsequently defined instance methods.
10
+ module DecorateAllMethods
11
+ def method_added name
12
+ super
13
+
14
+ decorated_method name
15
+ end
16
+ end
17
+
18
+ # Decorates the return values of named instance methods.
19
+ #
20
+ # Like Module#private, names can be passed individually or as a single array.
21
+ # With no arguments, subsequently defined instance methods are decorated.
22
+ def decorated_method *methods
23
+ case methods
24
+ in []
25
+ singleton_class.prepend DecorateAllMethods
26
+
27
+ return
28
+ in [ Symbol | String => method ]
29
+ in [ (Symbol | String), * ]
30
+ in [ [ (Symbol | String), * ] | [] => methods ]
31
+ end
32
+
33
+ location = caller_locations(1, 1).first
34
+
35
+ methods.map do |method|
36
+ decorated_methods_module.module_eval <<~RUBY.strip, location.path, location.lineno
37
+ #{method_visibility method} def #{method}(...) = super.decorated
38
+ RUBY
39
+ end
40
+
41
+ method || methods
42
+ end
43
+
44
+ private
45
+
46
+ def decorated_methods_module
47
+ if const_defined? :DecoratedMethods, false
48
+ const_get :DecoratedMethods
49
+ else
50
+ const_set :DecoratedMethods, Module.new
51
+ .tap { it.include const_get :DecoratedMethods if const_defined? :DecoratedMethods } # inheritance
52
+ .tap { prepend it }
53
+ end
54
+ end
55
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Magic
4
4
  module Decorator
5
- VERSION = '1.1.1'
5
+ VERSION = '1.2.0'
6
6
  end
7
7
  end
@@ -4,11 +4,15 @@ require 'magic/lookup'
4
4
 
5
5
  require_relative 'decorator/version'
6
6
 
7
- module Magic
7
+ module Magic # :nodoc:
8
8
  autoload :Decoratable, 'magic/decoratable'
9
9
 
10
10
  Object.include Decoratable
11
11
 
12
+ # = Magic Decorator
13
+ #
14
+ # It implements a general decorator logic. It is not meant to be a
15
+ # presenter.
12
16
  module Decorator
13
17
  autoload :Base, 'magic/decorator/base'
14
18
 
data/sig/module.rbs ADDED
@@ -0,0 +1,10 @@
1
+ class Module
2
+ def decorated_method: (interned) -> interned
3
+ | (interned, interned, *interned) -> Array[interned]
4
+ | (Array[interned]) -> Array[interned]
5
+ | -> nil
6
+
7
+ private
8
+
9
+ def decorated_methods_module: -> Module
10
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: magic-decorator
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Senko
@@ -42,18 +42,20 @@ files:
42
42
  - lib/magic/decorator.rb
43
43
  - lib/magic/decorator/authors.rb
44
44
  - lib/magic/decorator/base.rb
45
+ - lib/magic/decorator/core_ext/module.rb
45
46
  - lib/magic/decorator/version.rb
46
47
  - sig/enumerable_decorator.rbs
47
48
  - sig/magic/decoratable.rbs
48
49
  - sig/magic/decorator.rbs
49
50
  - sig/magic/decorator/base.rbs
51
+ - sig/module.rbs
50
52
  homepage: "https://github.com/Alexander-Senko/magic-decorator"
51
53
  licenses:
52
54
  - MIT
53
55
  metadata:
54
56
  homepage_uri: "https://github.com/Alexander-Senko/magic-decorator"
55
57
  source_code_uri: "https://github.com/Alexander-Senko/magic-decorator"
56
- changelog_uri: "https://github.com/Alexander-Senko/magic-decorator/blob/v1.1.1/CHANGELOG.md"
58
+ changelog_uri: "https://github.com/Alexander-Senko/magic-decorator/blob/v1.2.0/CHANGELOG.md"
57
59
  rdoc_options: []
58
60
  require_paths:
59
61
  - lib