shale-builder 0.4.0 → 0.5.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 +17 -1
- data/Gemfile.lock +1 -1
- data/README.md +41 -24
- data/lib/shale/attribute.rb +10 -3
- data/lib/shale/builder/assigned_attributes.rb +94 -0
- data/lib/shale/builder/nested_validations.rb +1 -1
- data/lib/shale/builder/value.rb +30 -0
- data/lib/shale/builder/version.rb +1 -1
- data/lib/shale/builder.rb +42 -32
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: febc908c436d767296b5869c0f83de5192ebd2dea56649a68840f951ca61210e
|
|
4
|
+
data.tar.gz: 921efc21393a6a01516dc0954efe6f87fe74326d51d1969c00e985f3f8ad9824
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 315da1873bcba3a08cbf4a6d405b975a8c9be51442726faab0e886138be48b50fa6bec7c5367064d1d0cc731af17ec0c10bbe9cfb04716a5b1d0712de46244a5
|
|
7
|
+
data.tar.gz: 54df3a9708bc1e327ecb7f85338a1420cca5b98d82b754acbecd03417541951472b9f2d005035abe5fe1217bfd5db10d3730a1966043c65956b3cdb83d080299
|
data/CHANGELOG.md
CHANGED
|
@@ -5,9 +5,25 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.5.0] - 2025-10-15
|
|
9
|
+
|
|
10
|
+
[Diff](https://github.com/Verseth/ruby-shale-builder/compare/v0.4.1...v0.5.0)
|
|
11
|
+
|
|
12
|
+
### Changes
|
|
13
|
+
- Add `Shale::Builder::AssignedAttributes` module which grants a shale mapper class with the ability to record which attributes have been assigned
|
|
14
|
+
- Add `Shale::Builder::Value` which represents a value of a shale attribute.
|
|
15
|
+
- Add `Shale::Builder#attribute_values`, a method that returns an array of `Shale::Builder::Value` objects for each attribute.
|
|
16
|
+
|
|
17
|
+
## [0.4.1] - 2025-10-14
|
|
18
|
+
|
|
19
|
+
[Diff](https://github.com/Verseth/ruby-shale-builder/compare/v0.4.0...v0.4.1)
|
|
20
|
+
|
|
21
|
+
### Changes
|
|
22
|
+
- Fix `Shale::Builder::alias_attribute`, improve changelog
|
|
23
|
+
|
|
8
24
|
## [0.4.0] - 2025-10-14
|
|
9
25
|
|
|
10
|
-
[Diff](https://github.com/Verseth/ruby-shale-builder/compare/v0.3.0...v0.
|
|
26
|
+
[Diff](https://github.com/Verseth/ruby-shale-builder/compare/v0.3.0...v0.4.0)
|
|
11
27
|
|
|
12
28
|
### Changes
|
|
13
29
|
- Add `Shale::Builder::NestedValidations`
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -263,50 +263,67 @@ obj.errors.messages #=> {cvv_code: ["can't be blank"], "amount.value": ["can't b
|
|
|
263
263
|
|
|
264
264
|
You MUST include `ActiveModel::Validations` before `Shale::Builder::NestedValidations`.
|
|
265
265
|
|
|
266
|
-
###
|
|
266
|
+
### Recording Assigned Attributes
|
|
267
267
|
|
|
268
|
-
|
|
268
|
+
There is an additional module `Shale::Builder::AssignedAttributes` that provides
|
|
269
|
+
support for recording which attributes have been assigned in a shale mapper object.
|
|
270
|
+
|
|
271
|
+
In order to load it do:
|
|
272
|
+
|
|
273
|
+
```rb
|
|
274
|
+
require 'shale/builder/assigned_attributes'
|
|
275
|
+
```
|
|
269
276
|
|
|
270
277
|
Then you can use it like so
|
|
271
278
|
|
|
272
279
|
```rb
|
|
273
280
|
class AmountType < ::Shale::Mapper
|
|
274
281
|
include ::Shale::Builder
|
|
275
|
-
include ::
|
|
276
|
-
include ::Shale::Builder::NestedValidations
|
|
282
|
+
include ::Shale::Builder::AssignedAttributes
|
|
277
283
|
|
|
278
284
|
attribute :value, ::Shale::Type::Float
|
|
279
285
|
attribute :currency, ::Shale::Type::String
|
|
280
|
-
|
|
281
|
-
validates :value, presence: true
|
|
282
286
|
end
|
|
283
287
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
include ::ActiveModel::Validations
|
|
287
|
-
include ::Shale::Builder::NestedValidations
|
|
288
|
+
obj = AmountType.new
|
|
289
|
+
obj.assigned_attribute_names #=> #<Set: {}>
|
|
288
290
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
+
obj.value = 3
|
|
292
|
+
obj.assigned_attribute_names #=> #<Set: {:value}>
|
|
293
|
+
obj.assigned_attributes #=> [#<Shale::Attribute:0x000000011e959b50 @collection=false, @default=nil, @doc=nil, @name=:value, @setter="value=", @type=Shale::Type::Float>]
|
|
294
|
+
obj.assigned_values #=> [#<Shale::Builder::Value:0x000000011d693318 @attribute=#<Shale::Attribute:0x000000011e959b50 @collection=false, @default=nil, @doc=nil, @name=:value, @setter="value=", @type=Shale::Type::Float>, @value=3.0>]
|
|
295
|
+
```
|
|
291
296
|
|
|
292
|
-
|
|
293
|
-
|
|
297
|
+
- `assigned_attribute_names` returns a set of attribute names
|
|
298
|
+
- `assigned_attributes` returns an array of attribute definitions
|
|
299
|
+
- `assigned_values` returns an array of `Shale::Builder::Value`, which contains the current value of an attribute and a reference to its definition
|
|
300
|
+
|
|
301
|
+
### Attribute aliases
|
|
302
|
+
|
|
303
|
+
You can easily create aliases for attributes using `alias_attribute`
|
|
304
|
+
|
|
305
|
+
Then you can use it like so
|
|
306
|
+
|
|
307
|
+
```rb
|
|
308
|
+
require 'shale/builder'
|
|
309
|
+
|
|
310
|
+
class Amount < Shale::Mapper
|
|
311
|
+
include Shale::Builder
|
|
312
|
+
|
|
313
|
+
attribute :value, Shale::Type::Float
|
|
314
|
+
attribute :currency, Shale::Type::String
|
|
315
|
+
|
|
316
|
+
alias_attribute :val, :value
|
|
294
317
|
end
|
|
295
318
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
a.currency = 'USD'
|
|
299
|
-
end
|
|
319
|
+
a = Amount.build do |a|
|
|
320
|
+
a.val = 3.2
|
|
300
321
|
end
|
|
301
322
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
obj.errors.messages #=> {cvv_code: ["can't be blank"], "amount.value": ["can't be blank"]}
|
|
323
|
+
a.val #=> 3.2
|
|
324
|
+
a.value #=> 3.2
|
|
305
325
|
```
|
|
306
326
|
|
|
307
|
-
You MUST include `ActiveModel::Validations` before `Shale::Builder::NestedValidations`.
|
|
308
|
-
|
|
309
|
-
|
|
310
327
|
### Sorbet support
|
|
311
328
|
|
|
312
329
|
Shale-builder adds support for sorbet and tapioca.
|
data/lib/shale/attribute.rb
CHANGED
|
@@ -9,15 +9,15 @@ module Shale
|
|
|
9
9
|
|
|
10
10
|
# Contains the documentation comment for the shale attribute
|
|
11
11
|
# in a Ruby String.
|
|
12
|
-
|
|
12
|
+
#: String?
|
|
13
13
|
attr_accessor :doc
|
|
14
14
|
|
|
15
15
|
# Contains the documentation comment for the shale attribute
|
|
16
16
|
# in a Ruby String.
|
|
17
|
-
|
|
17
|
+
#: Array[Symbol]?
|
|
18
18
|
attr_accessor :aliases
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
#: -> Array[Symbol]
|
|
21
21
|
def all_names
|
|
22
22
|
names = [name]
|
|
23
23
|
aliases = self.aliases
|
|
@@ -25,5 +25,12 @@ module Shale
|
|
|
25
25
|
|
|
26
26
|
names + aliases
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
# Returns `true` if the attribute is handled by a shale mapper.
|
|
30
|
+
#
|
|
31
|
+
#: -> bool
|
|
32
|
+
def mapper?
|
|
33
|
+
type.is_a?(Class) && type < Shale::Mapper
|
|
34
|
+
end
|
|
28
35
|
end
|
|
29
36
|
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'shale'
|
|
5
|
+
require 'booleans'
|
|
6
|
+
|
|
7
|
+
module Shale
|
|
8
|
+
module Builder
|
|
9
|
+
# Include in a class that already includes `Shale::Builder` to add support
|
|
10
|
+
# for getting a list of attributes that have been assigned.
|
|
11
|
+
#
|
|
12
|
+
# @requires_ancestor: Object
|
|
13
|
+
module AssignedAttributes
|
|
14
|
+
extend T::Sig
|
|
15
|
+
extend T::Helpers
|
|
16
|
+
|
|
17
|
+
class << self
|
|
18
|
+
extend T::Sig
|
|
19
|
+
|
|
20
|
+
# Gets called after including this module in a module or class.
|
|
21
|
+
#: (Module mod) -> void
|
|
22
|
+
def included(mod)
|
|
23
|
+
mod.extend ClassMethods
|
|
24
|
+
AssignedAttributes.prepare_mod(mod)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Prepares the received module or class
|
|
28
|
+
# for dynamic method definition.
|
|
29
|
+
#: (Module mod) -> void
|
|
30
|
+
def prepare_mod(mod)
|
|
31
|
+
assigned_attributes_methods_module = ::Module.new
|
|
32
|
+
mod.instance_variable_set :@assigned_attributes_methods_module, assigned_attributes_methods_module
|
|
33
|
+
mod.include assigned_attributes_methods_module
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# @requires_ancestor: singleton(Shale::Mapper)
|
|
38
|
+
module ClassMethods
|
|
39
|
+
extend T::Sig
|
|
40
|
+
|
|
41
|
+
# Contains overridden getter methods for attributes
|
|
42
|
+
# with complex types (so that they accept a block for building)
|
|
43
|
+
#: Module
|
|
44
|
+
attr_reader :assigned_attributes_methods_module
|
|
45
|
+
|
|
46
|
+
#: (String | Symbol name, Class type, ?collection: bool, ?default: Proc?, ?doc: String?, **untyped kwargs) ?{ -> void } -> void
|
|
47
|
+
def attribute(name, type, collection: false, default: nil, doc: nil, **kwargs, &block)
|
|
48
|
+
super
|
|
49
|
+
|
|
50
|
+
@assigned_attributes_methods_module.class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
51
|
+
def #{name}=(val)
|
|
52
|
+
super
|
|
53
|
+
return unless @__initialized
|
|
54
|
+
|
|
55
|
+
self.assigned_attribute_names << #{name.to_sym.inspect}
|
|
56
|
+
end
|
|
57
|
+
RUBY
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
mixes_in_class_methods ClassMethods
|
|
61
|
+
|
|
62
|
+
# Returns a set of names of assigned shale attributes.
|
|
63
|
+
#
|
|
64
|
+
#: -> Set[Symbol]
|
|
65
|
+
def assigned_attribute_names
|
|
66
|
+
@assigned_attribute_names ||= Set.new
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Returns an array of shale attributes
|
|
70
|
+
# that have been assigned.
|
|
71
|
+
#
|
|
72
|
+
#: -> Array[Shale::Attribute]
|
|
73
|
+
def assigned_attributes
|
|
74
|
+
klass = self.class #: as untyped
|
|
75
|
+
assigned_attribute_names.map do |name|
|
|
76
|
+
klass.attributes.fetch(name)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns an array of shale values
|
|
81
|
+
# that have been assigned.
|
|
82
|
+
#
|
|
83
|
+
#: -> Array[Shale::Builder::Value]
|
|
84
|
+
def assigned_values
|
|
85
|
+
klass = self.class #: as untyped
|
|
86
|
+
assigned_attribute_names.map do |name|
|
|
87
|
+
attr = klass.attributes.fetch(name)
|
|
88
|
+
Shale::Builder::Value.new(attr, public_send(attr.name))
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -6,7 +6,7 @@ require 'booleans'
|
|
|
6
6
|
|
|
7
7
|
module Shale
|
|
8
8
|
module Builder
|
|
9
|
-
# Include in a class
|
|
9
|
+
# Include in a class that already includes `Shale::Builder` to add support
|
|
10
10
|
# for nested ActiveModel validations.
|
|
11
11
|
#
|
|
12
12
|
# @requires_ancestor: Object
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'shale'
|
|
5
|
+
|
|
6
|
+
module Shale
|
|
7
|
+
module Builder
|
|
8
|
+
# Represents a value of a particular shale attribute.
|
|
9
|
+
# Hold the value and a reference to the attribute definition.
|
|
10
|
+
class Value
|
|
11
|
+
extend T::Sig
|
|
12
|
+
|
|
13
|
+
# Shale attribute definition
|
|
14
|
+
#
|
|
15
|
+
#: Shale::Attribute
|
|
16
|
+
attr_reader :attribute
|
|
17
|
+
|
|
18
|
+
# Value of the attribute.
|
|
19
|
+
#
|
|
20
|
+
#: untyped
|
|
21
|
+
attr_reader :value
|
|
22
|
+
|
|
23
|
+
#: (Shale::Attribute, untyped) -> void
|
|
24
|
+
def initialize(attribute, value)
|
|
25
|
+
@attribute = attribute
|
|
26
|
+
@value = value
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/shale/builder.rb
CHANGED
|
@@ -39,6 +39,7 @@ module Shale
|
|
|
39
39
|
# end
|
|
40
40
|
# end
|
|
41
41
|
#
|
|
42
|
+
# @requires_ancestor: Object
|
|
42
43
|
module Builder
|
|
43
44
|
extend T::Sig
|
|
44
45
|
extend T::Helpers
|
|
@@ -47,7 +48,7 @@ module Shale
|
|
|
47
48
|
extend T::Sig
|
|
48
49
|
|
|
49
50
|
# Gets called after including this module in a module or class.
|
|
50
|
-
|
|
51
|
+
#: (Module mod) -> void
|
|
51
52
|
def included(mod)
|
|
52
53
|
mod.extend ClassMethods
|
|
53
54
|
Builder.prepare_mod(mod)
|
|
@@ -55,7 +56,7 @@ module Shale
|
|
|
55
56
|
|
|
56
57
|
# Prepares the received module or class
|
|
57
58
|
# for dynamic method definition.
|
|
58
|
-
|
|
59
|
+
#: (Module mod) -> void
|
|
59
60
|
def prepare_mod(mod)
|
|
60
61
|
builder_methods_module = ::Module.new
|
|
61
62
|
mod.instance_variable_set :@builder_methods_module, builder_methods_module
|
|
@@ -71,7 +72,7 @@ module Shale
|
|
|
71
72
|
abstract!
|
|
72
73
|
has_attached_class!
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
#: (Class subclass) -> void
|
|
75
76
|
def inherited(subclass)
|
|
76
77
|
super
|
|
77
78
|
Builder.prepare_mod(subclass)
|
|
@@ -79,10 +80,10 @@ module Shale
|
|
|
79
80
|
|
|
80
81
|
# Contains overridden getter methods for attributes
|
|
81
82
|
# with complex types (so that they accept a block for building)
|
|
82
|
-
|
|
83
|
+
#: Module
|
|
83
84
|
attr_reader :builder_methods_module
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
#: { (instance arg0) -> void } -> instance
|
|
86
87
|
def build(&_block)
|
|
87
88
|
body = new
|
|
88
89
|
yield(body)
|
|
@@ -96,17 +97,7 @@ module Shale
|
|
|
96
97
|
sig { abstract.returns(T::Hash[Symbol, Shale::Attribute]) }
|
|
97
98
|
def attributes; end
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
params(
|
|
101
|
-
name: T.any(String, Symbol),
|
|
102
|
-
type: Class,
|
|
103
|
-
collection: T::Boolean,
|
|
104
|
-
default: T.nilable(Proc),
|
|
105
|
-
doc: T.nilable(String),
|
|
106
|
-
kwargs: Object,
|
|
107
|
-
block: T.nilable(T.proc.void),
|
|
108
|
-
).void
|
|
109
|
-
end
|
|
100
|
+
#: ((String | Symbol) name, Class type, ?collection: bool, ?default: Proc?, ?doc: String?, **Object kwargs) ?{ -> void } -> void
|
|
110
101
|
def attribute(name, type, collection: false, default: nil, doc: nil, **kwargs, &block)
|
|
111
102
|
super(name, type, collection:, default:, **kwargs, &block)
|
|
112
103
|
if (attr_def = attributes[name.to_sym])
|
|
@@ -140,27 +131,46 @@ module Shale
|
|
|
140
131
|
RUBY
|
|
141
132
|
end
|
|
142
133
|
|
|
143
|
-
|
|
144
|
-
|
|
134
|
+
# Create an alias for the getter and setter of an attribute.
|
|
135
|
+
#: (Symbol new_name, Symbol old_name) -> void
|
|
136
|
+
def alias_attribute(new_name, old_name)
|
|
137
|
+
attr = attributes.fetch(old_name)
|
|
138
|
+
(attr.aliases ||= []) << new_name
|
|
145
139
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
140
|
+
builder_methods_module.class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
|
141
|
+
def #{new_name}
|
|
142
|
+
#{old_name}
|
|
143
|
+
end
|
|
150
144
|
|
|
151
|
-
|
|
152
|
-
|
|
145
|
+
def #{new_name}=(val)
|
|
146
|
+
self.#{old_name} = val
|
|
147
|
+
end
|
|
148
|
+
RUBY
|
|
149
|
+
end
|
|
153
150
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
#{old_name}
|
|
157
|
-
end
|
|
151
|
+
end
|
|
152
|
+
mixes_in_class_methods(ClassMethods)
|
|
158
153
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
154
|
+
def initialize(*args, **kwargs, &block)
|
|
155
|
+
super
|
|
156
|
+
@__initialized = true
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
#: bool?
|
|
160
|
+
attr_reader :__initialized
|
|
161
|
+
|
|
162
|
+
# Returns an array of shale values
|
|
163
|
+
# that have been assigned.
|
|
164
|
+
#
|
|
165
|
+
#: -> Array[Shale::Builder::Value]
|
|
166
|
+
def attribute_values
|
|
167
|
+
klass = self.class #: as untyped
|
|
168
|
+
klass.attributes.map do |name, attr|
|
|
169
|
+
Shale::Builder::Value.new(attr, public_send(name))
|
|
170
|
+
end
|
|
163
171
|
end
|
|
164
172
|
|
|
165
173
|
end
|
|
166
174
|
end
|
|
175
|
+
|
|
176
|
+
require_relative 'builder/value'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: shale-builder
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mateusz Drewniak
|
|
@@ -69,7 +69,9 @@ files:
|
|
|
69
69
|
- Rakefile
|
|
70
70
|
- lib/shale/attribute.rb
|
|
71
71
|
- lib/shale/builder.rb
|
|
72
|
+
- lib/shale/builder/assigned_attributes.rb
|
|
72
73
|
- lib/shale/builder/nested_validations.rb
|
|
74
|
+
- lib/shale/builder/value.rb
|
|
73
75
|
- lib/shale/builder/version.rb
|
|
74
76
|
- lib/shale/mapper.rbi
|
|
75
77
|
- lib/tapioca/dsl/compilers/shale.rb
|