inheritance-helper 0.1.5 → 0.2.6
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 +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +211 -0
- data/lib/inheritance-helper/class_builder/utils.rb +59 -0
- data/lib/inheritance-helper/methods.rb +84 -5
- data/lib/inheritance-helper/version.rb +6 -0
- data/lib/inheritance-helper.rb +8 -1
- metadata +22 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 31680a3ae280b81619d4eef1777f9821a4c47ef390225e56a4805b9686747fb9
|
|
4
|
+
data.tar.gz: 998ec788e4497c7e90870ece2d008dc76226344d7d24c0be408b7e6d4b859673
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 47fc914a0bae8fedf35b01b0c9f4db8db002b1b1368d9bdaaf9b13a9ad537a5fc94a84900d652515874e6597acbd76f6d366bf50e2da6c798f9b756f89059333
|
|
7
|
+
data.tar.gz: 96f5b2c69b69ef9a8720b9c5db7f64aeb6cfb578516c2586a4bc57085b91700e393090872f986ebfbbd598ba26eb1578f7ec182fede9272e5bb887fa0362de8c
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.6](https://github.com/dougyouch/inheritance-helper/compare/v0.2.5...v0.2.6) (2026-10-05)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* **class-builder:** handle repeated and trailing underscores in class names ([92488f2](https://github.com/dougyouch/inheritance-helper/commit/92488f260e9da03693745c46c9064cafb1f2159f))
|
|
9
|
+
* **methods:** keep the visibility of redefined class methods ([5cd1f79](https://github.com/dougyouch/inheritance-helper/commit/5cd1f79529de471c27249a163b6de66cc45d9453))
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Douglas Youch
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# inheritance-helper
|
|
2
|
+
|
|
3
|
+
Class-level settings that subclasses can extend without changing their parents.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/dougyouch/inheritance-helper/actions/workflows/ci.yml)
|
|
6
|
+
[](https://github.com/dougyouch/inheritance-helper/actions/workflows/ci.yml)
|
|
7
|
+
[](https://github.com/dougyouch/inheritance-helper/actions/workflows/ci.yml)
|
|
8
|
+
[](https://rubygems.org/gems/inheritance-helper)
|
|
9
|
+
|
|
10
|
+
[API reference](https://rubydoc.info/gems/inheritance-helper) · [Changelog](CHANGELOG.md)
|
|
11
|
+
|
|
12
|
+
DSLs often collect data at the class level: attributes, options, callbacks. With a class instance variable,
|
|
13
|
+
subclasses don't see the parent's data. With a class variable (`@@attributes`), every class in the chain
|
|
14
|
+
shares and changes the same object. `inheritance-helper` avoids both: each call replaces the class method on
|
|
15
|
+
the class it's called on, so a subclass starts with its parent's value, adds to it, and the parent keeps its
|
|
16
|
+
own.
|
|
17
|
+
|
|
18
|
+
It has no dependencies. It is used by [schema-model](https://github.com/dougyouch/schema) to collect
|
|
19
|
+
attribute definitions.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Requires Ruby 3.2 or newer. Add this line to your application's Gemfile:
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
gem 'inheritance-helper'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
And then execute:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
$ bundle install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
Extend a class with `InheritanceHelper::Methods` and define a class method that returns the starting value.
|
|
38
|
+
Freezing the value is recommended: values built from a frozen value are frozen too, so no class can change
|
|
39
|
+
another's data by mutating it.
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
require 'inheritance-helper'
|
|
43
|
+
|
|
44
|
+
class Model
|
|
45
|
+
extend InheritanceHelper::Methods
|
|
46
|
+
|
|
47
|
+
def self.attributes
|
|
48
|
+
{}.freeze
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.attribute(name, type)
|
|
52
|
+
add_value_to_class_method(:attributes, name => type)
|
|
53
|
+
attr_accessor name
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class Person < Model
|
|
58
|
+
attribute :name, :string
|
|
59
|
+
attribute :phone, :string
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
class Employee < Person
|
|
63
|
+
attribute :employee_id, :integer
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
Model.attributes # => {}
|
|
67
|
+
Person.attributes # => {name: :string, phone: :string}
|
|
68
|
+
Employee.attributes # => {name: :string, phone: :string, employee_id: :integer}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### add_value_to_class_method
|
|
72
|
+
|
|
73
|
+
Redefines a class method to return its current value with more added:
|
|
74
|
+
|
|
75
|
+
- a **Hash** is merged with the new hash
|
|
76
|
+
- an **Array** or **Set** is combined with `Array(value)`, so an array of values adds each one and the
|
|
77
|
+
result stays flat
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
class Base
|
|
81
|
+
extend InheritanceHelper::Methods
|
|
82
|
+
|
|
83
|
+
def self.fields = [].freeze
|
|
84
|
+
def self.tags = Set.new.freeze
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
class Child < Base
|
|
88
|
+
add_value_to_class_method :fields, :name
|
|
89
|
+
add_value_to_class_method :fields, %i[email phone]
|
|
90
|
+
add_value_to_class_method :tags, :admin
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
Child.fields # => [:name, :email, :phone]
|
|
94
|
+
Child.tags # => Set[:admin]
|
|
95
|
+
Base.fields # => []
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### append_value_to_class_method
|
|
99
|
+
|
|
100
|
+
Redefines a class method to return its current array with one element appended. Unlike
|
|
101
|
+
`add_value_to_class_method`, an array is added as a single element:
|
|
102
|
+
|
|
103
|
+
```ruby
|
|
104
|
+
class Base
|
|
105
|
+
extend InheritanceHelper::Methods
|
|
106
|
+
|
|
107
|
+
def self.callbacks = [].freeze
|
|
108
|
+
|
|
109
|
+
def self.before_save(*methods)
|
|
110
|
+
append_value_to_class_method(:callbacks, methods)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
class Child < Base
|
|
115
|
+
before_save :normalize, :validate
|
|
116
|
+
before_save :log
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
Child.callbacks # => [[:normalize, :validate], [:log]]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### redefine_class_method
|
|
123
|
+
|
|
124
|
+
Replaces a class method with one that returns the given value. Use it for settings that are replaced rather
|
|
125
|
+
than added to:
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
class Base
|
|
129
|
+
extend InheritanceHelper::Methods
|
|
130
|
+
|
|
131
|
+
def self.table_name = 'records'
|
|
132
|
+
|
|
133
|
+
def self.table(name)
|
|
134
|
+
redefine_class_method(:table_name, name.freeze)
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
class User < Base
|
|
139
|
+
table 'users'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
User.table_name # => "users"
|
|
143
|
+
Base.table_name # => "records"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The method returns the same object on every call, so freeze values that callers shouldn't change. The new
|
|
147
|
+
method keeps the visibility of the one it replaces, so a private class method stays private.
|
|
148
|
+
|
|
149
|
+
`InheritanceHelper::Methods.redefine_class_method(klass, method, value)` does the same for a class that
|
|
150
|
+
doesn't extend the module.
|
|
151
|
+
|
|
152
|
+
### Notes
|
|
153
|
+
|
|
154
|
+
- The class method must already return a value: `add_value_to_class_method` and
|
|
155
|
+
`append_value_to_class_method` call it to get the current value.
|
|
156
|
+
- Each call defines a method on the class's singleton class. Classes declared at load time (the usual DSL
|
|
157
|
+
case) are fine; redefining class methods from several threads at once is not synchronized.
|
|
158
|
+
|
|
159
|
+
## ClassBuilder::Utils
|
|
160
|
+
|
|
161
|
+
`InheritanceHelper::ClassBuilder::Utils` creates named classes at runtime, which is useful for DSLs that
|
|
162
|
+
build nested classes (such as a `has_many :items do ... end` block):
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
module Shop; end
|
|
166
|
+
|
|
167
|
+
klass = InheritanceHelper::ClassBuilder::Utils.create_class(Shop, :line_item, nil, 'Schema', nil) do
|
|
168
|
+
attr_accessor :quantity
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
klass # => Shop::SchemaLineItem
|
|
172
|
+
klass.name # => "Shop::SchemaLineItem"
|
|
173
|
+
|
|
174
|
+
InheritanceHelper::ClassBuilder::Utils.get_class_name(:line_item, 'Has', 'Class')
|
|
175
|
+
# => "HasLineItemClass"
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`create_class(base_module, name, base_class, prefix, suffix, &block)` subclasses `base_class` (or `Object` when
|
|
179
|
+
`nil`), assigns it to the constant in `base_module`, and evaluates the block in the new class. If the constant
|
|
180
|
+
already exists it is replaced, with Ruby's "already initialized constant" warning.
|
|
181
|
+
|
|
182
|
+
`get_class_name` uses `String#classify` when ActiveSupport is loaded, which also singularizes the name
|
|
183
|
+
(`line_items` becomes `LineItem`). Without ActiveSupport the name is split on underscores and each part is
|
|
184
|
+
capitalized (`line_items` becomes `LineItems`).
|
|
185
|
+
|
|
186
|
+
## Development
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
bundle install
|
|
190
|
+
bundle exec rspec # tests, with line and branch coverage in coverage/
|
|
191
|
+
bundle exec rubocop # lint
|
|
192
|
+
bundle exec yard doc # API docs in doc/
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
CI requires 100% line and branch coverage, no RuboCop offenses, and every public method documented with YARD.
|
|
196
|
+
|
|
197
|
+
Releases are automated with [release-please](https://github.com/googleapis/release-please): conventional
|
|
198
|
+
commits on `master` (`fix:`, `feat:`) update a release PR, and merging it tags the release and publishes the
|
|
199
|
+
gem.
|
|
200
|
+
|
|
201
|
+
## Contributing
|
|
202
|
+
|
|
203
|
+
1. Fork the repository
|
|
204
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
205
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
206
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
207
|
+
5. Create a new Pull Request
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module InheritanceHelper
|
|
4
|
+
module ClassBuilder
|
|
5
|
+
# Functions for creating named classes inside a module.
|
|
6
|
+
#
|
|
7
|
+
# @example
|
|
8
|
+
# InheritanceHelper::ClassBuilder::Utils.create_class(MyApp, :line_item, Struct.new(:id), 'Schema', nil)
|
|
9
|
+
# # => MyApp::SchemaLineItem
|
|
10
|
+
module Utils
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# Builds a class name from `name` with an optional prefix and suffix.
|
|
14
|
+
#
|
|
15
|
+
# `name` is converted with `String#classify` when ActiveSupport is loaded (which also singularizes it).
|
|
16
|
+
# Otherwise it is split on underscores and each part is capitalized.
|
|
17
|
+
#
|
|
18
|
+
# @param name [String, Symbol] the base name, such as `:line_item`
|
|
19
|
+
# @param prefix_class_name [String, nil] text to put before the converted name
|
|
20
|
+
# @param suffix_class_name [String, nil] text to put after the converted name
|
|
21
|
+
# @return [String] the class name, such as `"SchemaLineItem"`
|
|
22
|
+
# @example
|
|
23
|
+
# get_class_name(:line_item, 'Schema', 'Class') # => "SchemaLineItemClass"
|
|
24
|
+
def get_class_name(name, prefix_class_name, suffix_class_name)
|
|
25
|
+
name = name.to_s
|
|
26
|
+
|
|
27
|
+
class_name =
|
|
28
|
+
if name.respond_to?(:classify)
|
|
29
|
+
name.classify
|
|
30
|
+
else
|
|
31
|
+
name.split('_').map { |part| part.sub(/\A./, &:upcase) }.join
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
"#{prefix_class_name}#{class_name}#{suffix_class_name}"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Creates a class and assigns it to a constant in `base_module`, which gives the class a name.
|
|
38
|
+
#
|
|
39
|
+
# If the constant already exists it is replaced, and Ruby prints an "already initialized constant"
|
|
40
|
+
# warning.
|
|
41
|
+
#
|
|
42
|
+
# @param base_module [Module] the module the class is defined in
|
|
43
|
+
# @param name [String, Symbol] the base name, converted with {get_class_name}
|
|
44
|
+
# @param base_class [Class, nil] the superclass, or `nil` for `Object`
|
|
45
|
+
# @param prefix_class_name [String, nil] text to put before the converted name
|
|
46
|
+
# @param suffix_class_name [String, nil] text to put after the converted name
|
|
47
|
+
# @yield evaluated in the new class with `class_eval`, to define its methods
|
|
48
|
+
# @return [Class] the new class
|
|
49
|
+
# @raise [NameError] if the resulting name isn't a valid constant name
|
|
50
|
+
def create_class(base_module, name, base_class, prefix_class_name, suffix_class_name, &block)
|
|
51
|
+
class_name = get_class_name(name, prefix_class_name, suffix_class_name)
|
|
52
|
+
kls = Class.new(base_class || Object)
|
|
53
|
+
base_module.const_set(class_name, kls)
|
|
54
|
+
kls.class_eval(&block) if block
|
|
55
|
+
kls
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -1,19 +1,88 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module InheritanceHelper
|
|
4
|
-
#
|
|
4
|
+
# Class methods for redefining class methods on a subclass.
|
|
5
|
+
#
|
|
6
|
+
# Extend a class with this module. A class method on that class, or on any subclass, can then be replaced
|
|
7
|
+
# with one that returns a new value. The new method is defined on the receiving class's singleton class,
|
|
8
|
+
# so the parent class keeps its own method and value.
|
|
9
|
+
#
|
|
10
|
+
# @example Collect attributes across an inheritance chain
|
|
11
|
+
# class Model
|
|
12
|
+
# extend InheritanceHelper::Methods
|
|
13
|
+
#
|
|
14
|
+
# def self.attributes
|
|
15
|
+
# {}.freeze
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# def self.attribute(name, type)
|
|
19
|
+
# add_value_to_class_method(:attributes, name => type)
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
#
|
|
23
|
+
# class Person < Model
|
|
24
|
+
# attribute :name, :string
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# Person.attributes # => {name: :string}
|
|
28
|
+
# Model.attributes # => {}
|
|
5
29
|
module Methods
|
|
30
|
+
# Defines (or replaces) the class method `method` on `klass` so that it returns `value`.
|
|
31
|
+
#
|
|
32
|
+
# The new method keeps the visibility of the method it replaces, so a private class method stays private.
|
|
33
|
+
#
|
|
34
|
+
# @param klass [Module] the class or module to define the method on
|
|
35
|
+
# @param method [Symbol, String] name of the class method
|
|
36
|
+
# @param value [Object] the value the method returns. The same object is returned on every call, so
|
|
37
|
+
# freeze it if callers shouldn't change it
|
|
38
|
+
# @return [Module] `klass`
|
|
6
39
|
def self.redefine_class_method(klass, method, value)
|
|
7
|
-
|
|
40
|
+
singleton = klass.singleton_class
|
|
41
|
+
visibility = method_visibility(singleton, method)
|
|
42
|
+
singleton.send(:define_method, method) { value }
|
|
43
|
+
singleton.send(visibility, method)
|
|
8
44
|
klass
|
|
9
45
|
end
|
|
10
46
|
|
|
47
|
+
# @api private
|
|
48
|
+
# @param mod [Module] the module to look the method up in
|
|
49
|
+
# @param method [Symbol, String] name of the method
|
|
50
|
+
# @return [Symbol] `:private`, `:protected` or `:public` (also for a method that isn't defined yet)
|
|
51
|
+
def self.method_visibility(mod, method)
|
|
52
|
+
if mod.private_method_defined?(method)
|
|
53
|
+
:private
|
|
54
|
+
elsif mod.protected_method_defined?(method)
|
|
55
|
+
:protected
|
|
56
|
+
else
|
|
57
|
+
:public
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
private_class_method :method_visibility
|
|
61
|
+
|
|
62
|
+
# Defines (or replaces) the class method `method` on this class so that it returns `value`.
|
|
63
|
+
#
|
|
64
|
+
# @param method [Symbol, String] name of the class method
|
|
65
|
+
# @param value [Object] the value the method returns
|
|
66
|
+
# @return [Module] this class
|
|
67
|
+
# @see InheritanceHelper::Methods.redefine_class_method
|
|
11
68
|
def redefine_class_method(method, value)
|
|
12
69
|
::InheritanceHelper::Methods.redefine_class_method(self, method, value)
|
|
13
70
|
end
|
|
14
71
|
|
|
15
|
-
#
|
|
16
|
-
#
|
|
72
|
+
# Redefines the class method `method` to return its current value with `value` added.
|
|
73
|
+
#
|
|
74
|
+
# - A Hash is merged with `value`, which must be a Hash.
|
|
75
|
+
# - Anything else (an Array, a Set) is combined with `Array(value)`, so an array of values adds each one
|
|
76
|
+
# and the result stays flat. Use {#append_value_to_class_method} to add an array as a single element.
|
|
77
|
+
#
|
|
78
|
+
# The current value isn't changed. If it is frozen, the new value is frozen too.
|
|
79
|
+
#
|
|
80
|
+
# @param method [Symbol, String] name of a class method that returns a Hash, Array or Set
|
|
81
|
+
# @param value [Object] the value or values to add
|
|
82
|
+
# @return [Module] this class
|
|
83
|
+
# @example
|
|
84
|
+
# add_value_to_class_method(:attributes, name: :string) # {} => {name: :string}
|
|
85
|
+
# add_value_to_class_method(:fields, [:a, :b]) # [] => [:a, :b]
|
|
17
86
|
def add_value_to_class_method(method, value)
|
|
18
87
|
old_value = send(method)
|
|
19
88
|
|
|
@@ -28,7 +97,17 @@ module InheritanceHelper
|
|
|
28
97
|
redefine_class_method(method, old_value.frozen? ? new_value.freeze : new_value)
|
|
29
98
|
end
|
|
30
99
|
|
|
31
|
-
#
|
|
100
|
+
# Redefines the class method `method` to return a copy of its current value with `value` appended as a
|
|
101
|
+
# single element (using `<<`).
|
|
102
|
+
#
|
|
103
|
+
# The current value isn't changed. If it is frozen, the new value is frozen too.
|
|
104
|
+
#
|
|
105
|
+
# @param method [Symbol, String] name of a class method that returns an Array (or anything that responds
|
|
106
|
+
# to `dup` and `<<`)
|
|
107
|
+
# @param value [Object] the element to append
|
|
108
|
+
# @return [Module] this class
|
|
109
|
+
# @example
|
|
110
|
+
# append_value_to_class_method(:callbacks, [:save, :log]) # [] => [[:save, :log]]
|
|
32
111
|
def append_value_to_class_method(method, value)
|
|
33
112
|
old_value = send(method)
|
|
34
113
|
new_value = old_value.dup << value
|
data/lib/inheritance-helper.rb
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require_relative 'inheritance-helper/version'
|
|
4
|
+
|
|
5
|
+
# Helpers for class-level values that subclasses can extend without changing their parent classes.
|
|
4
6
|
module InheritanceHelper
|
|
5
7
|
autoload :Methods, 'inheritance-helper/methods'
|
|
8
|
+
|
|
9
|
+
# Helpers for creating classes at runtime.
|
|
10
|
+
module ClassBuilder
|
|
11
|
+
autoload :Utils, 'inheritance-helper/class_builder/utils'
|
|
12
|
+
end
|
|
6
13
|
end
|
metadata
CHANGED
|
@@ -1,28 +1,40 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: inheritance-helper
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Doug Youch
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies: []
|
|
13
|
-
description:
|
|
14
|
-
|
|
12
|
+
description: Redefine a class method on a subclass to return a new value, so hashes,
|
|
13
|
+
arrays and sets declared on a parent class can be added to by each subclass while
|
|
14
|
+
the parent keeps its own copy. Built for DSLs that collect attributes, options or
|
|
15
|
+
callbacks at the class level. Also includes a helper for creating named classes
|
|
16
|
+
inside a module.
|
|
17
|
+
email: dougyouch@gmail.com
|
|
15
18
|
executables: []
|
|
16
19
|
extensions: []
|
|
17
20
|
extra_rdoc_files: []
|
|
18
21
|
files:
|
|
22
|
+
- CHANGELOG.md
|
|
23
|
+
- LICENSE.txt
|
|
24
|
+
- README.md
|
|
19
25
|
- lib/inheritance-helper.rb
|
|
26
|
+
- lib/inheritance-helper/class_builder/utils.rb
|
|
20
27
|
- lib/inheritance-helper/methods.rb
|
|
28
|
+
- lib/inheritance-helper/version.rb
|
|
21
29
|
homepage: https://github.com/dougyouch/inheritance-helper
|
|
22
30
|
licenses:
|
|
23
31
|
- MIT
|
|
24
|
-
metadata:
|
|
25
|
-
|
|
32
|
+
metadata:
|
|
33
|
+
rubygems_mfa_required: 'true'
|
|
34
|
+
source_code_uri: https://github.com/dougyouch/inheritance-helper
|
|
35
|
+
changelog_uri: https://github.com/dougyouch/inheritance-helper/blob/master/CHANGELOG.md
|
|
36
|
+
bug_tracker_uri: https://github.com/dougyouch/inheritance-helper/issues
|
|
37
|
+
documentation_uri: https://rubydoc.info/gems/inheritance-helper
|
|
26
38
|
rdoc_options: []
|
|
27
39
|
require_paths:
|
|
28
40
|
- lib
|
|
@@ -30,15 +42,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
30
42
|
requirements:
|
|
31
43
|
- - ">="
|
|
32
44
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
45
|
+
version: '3.2'
|
|
34
46
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
35
47
|
requirements:
|
|
36
48
|
- - ">="
|
|
37
49
|
- !ruby/object:Gem::Version
|
|
38
50
|
version: '0'
|
|
39
51
|
requirements: []
|
|
40
|
-
rubygems_version:
|
|
41
|
-
signing_key:
|
|
52
|
+
rubygems_version: 4.0.20
|
|
42
53
|
specification_version: 4
|
|
43
|
-
summary:
|
|
54
|
+
summary: Class-level settings that subclasses can extend without changing their parents
|
|
44
55
|
test_files: []
|