rest-easy 1.3.1 → 1.4.1
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 +88 -1
- data/README.md +35 -6
- data/lib/rest_easy/attribute.rb +14 -0
- data/lib/rest_easy/meta.rb +40 -2
- data/lib/rest_easy/resource.rb +49 -8
- data/lib/rest_easy/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a30780e0b38e31f1c183d1ec0a91ea93658a78e67d2415aeb8aef279d03359b7
|
|
4
|
+
data.tar.gz: 2ed7aafbcaf5e0c6fd463992a65293d1f064c693611f64b9b3256e8e4b518fdf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3ac9ea37e26b652d5fe590075d7668f70e2cf8b7290b02d7e4dd1f227bf7a7e26ea9e5faa02ed1b84b5706262d90e774db52381ea0ce2d026da40d410ae38c11
|
|
7
|
+
data.tar.gz: 8f8773d0cbacc6366daade22ceee18ee76de91ee5eb5cd718c392e0abfe1ed3a911658a867dab1bcd1f21b077f2296e0cb5ffbb1aa5597f6fee7e77a7b40b84d
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,91 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [1.4.1] - 2026-08-18
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **`Meta` no longer claims to implement methods it has no value for.**
|
|
10
|
+
`Meta#respond_to_missing?` returned `true` for every name, so any caller
|
|
11
|
+
that asks an object what it can do before calling it got a false yes, then
|
|
12
|
+
received the `nil` that `method_missing` returns for an unknown key as
|
|
13
|
+
though it were a real answer. Ruby does this constantly and implicitly —
|
|
14
|
+
coercion probes when a value is splatted or interpolated, serialisation
|
|
15
|
+
hooks, and any library that duck-types with `respond_to?` — so the failure
|
|
16
|
+
surfaced far from `Meta` and looked unrelated to it. Marshalling was the
|
|
17
|
+
sharpest case: `dump` silently wrote an empty payload and `load` then
|
|
18
|
+
raised `NoMethodError` from inside `method_missing`, which broke every
|
|
19
|
+
consumer caching resources in a store that marshals its entries.
|
|
20
|
+
|
|
21
|
+
Bare getters are now claimed only for keys the instance actually holds.
|
|
22
|
+
Setters and predicates are still claimed unconditionally, since writing is
|
|
23
|
+
how a key comes into existence and an unset predicate is meaningfully
|
|
24
|
+
`false`; no core Ruby probe uses those two shapes. Library-level
|
|
25
|
+
duck-typing can, though — ActiveSupport's `acts_like?(:date)` asks for
|
|
26
|
+
`acts_like_date?`, and `Meta` still answers yes — so the guarantee is
|
|
27
|
+
narrower than "nothing probes for `=` or `?`", and closing it properly is
|
|
28
|
+
tracked in #7. Operators are no longer claimed either: the check is
|
|
29
|
+
anchored to identifier-shaped names, so `<=` is not mistaken for a setter
|
|
30
|
+
(`method_missing` still is — #6).
|
|
31
|
+
`Resource::MetaCollector` had the identical defect and is fixed the same
|
|
32
|
+
way.
|
|
33
|
+
|
|
34
|
+
**Upgrading with a warm cache:** entries written by an earlier version are
|
|
35
|
+
not recoverable. A payload dumped before this fix carries `nil` where the
|
|
36
|
+
meta state should be, and loading it now raises `TypeError: instance of
|
|
37
|
+
RestEasy::Meta needs to have method 'marshal_load'` — legible, but still
|
|
38
|
+
an error. Consumers on a cache that survives deploys (`:file_store`,
|
|
39
|
+
Redis, Memcached) must flush it or bump the cache key namespace when
|
|
40
|
+
upgrading. A process-local `:memory_store` clears itself on restart and
|
|
41
|
+
needs nothing.
|
|
42
|
+
|
|
43
|
+
`method_missing` is unchanged: a bare getter for a key that was never set
|
|
44
|
+
still returns `nil` rather than raising, as the "gem author extensions"
|
|
45
|
+
example in `docs/model-architecture.md` depends on. `respond_to?`
|
|
46
|
+
therefore under-reports for those keys; reconciling the two halves
|
|
47
|
+
requires declaring meta keys up front and is tracked in #7.
|
|
48
|
+
|
|
49
|
+
## [1.4.0] - 2026-06-26
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- **`:required` is now enforced on serialise as well as parse.** Previously
|
|
54
|
+
the flag raised `MissingAttributeError` only when an API response omitted
|
|
55
|
+
the field; it was silently ignored when sending (`save`), letting
|
|
56
|
+
incomplete payloads reach the backend and surface as a generic
|
|
57
|
+
`RequestError`. The flag now also fires at `serialise` time (and therefore
|
|
58
|
+
on `save`) when a required attribute is `nil`, before any HTTP request,
|
|
59
|
+
with the attribute name on the exception (`#attribute_name`). Inbound
|
|
60
|
+
behavior is unchanged — `parse` still raises on missing required fields.
|
|
61
|
+
A field is treated as missing whether the API response omits the key
|
|
62
|
+
entirely or includes it as explicit `null`; both are rejected as
|
|
63
|
+
incomplete data.
|
|
64
|
+
- **`:required` is now enforced on synthetic attributes (merge / combine /
|
|
65
|
+
split patterns).** Previously the flag was silently a no-op for any
|
|
66
|
+
attribute with a multi-parameter parse or serialise block. It now
|
|
67
|
+
enforces presence on all underlying API or model fields: a merge
|
|
68
|
+
attribute requires every source API field on parse; a combine attribute
|
|
69
|
+
requires every named model attribute on serialise; a split attribute
|
|
70
|
+
requires the underlying API field on parse. `:read_only` continues to
|
|
71
|
+
skip the serialise-time check.
|
|
72
|
+
|
|
73
|
+
### Changed
|
|
74
|
+
|
|
75
|
+
- **The DSL auto-applies `:synthetic` to multi-parameter serialise blocks**
|
|
76
|
+
(and mapper `serialise` methods), mirroring the existing behavior for
|
|
77
|
+
multi-parameter parse. Previously only the parse side was tagged,
|
|
78
|
+
leaving the flag inconsistent with its intent of marking attributes whose
|
|
79
|
+
storage shape diverges from the standard one-slot layout.
|
|
80
|
+
- **Combine attributes no longer read from their `api_name` on parse.**
|
|
81
|
+
A combine attribute's API name does not correspond to a real inbound
|
|
82
|
+
field by design — the value is built from `target_fields` at serialise
|
|
83
|
+
time. The previous code looked up `api_data[api_name]`, stored it at
|
|
84
|
+
the model slot, and ran the standard `:required` check, raising
|
|
85
|
+
spuriously when the field was absent (the documented case). Inbound
|
|
86
|
+
values for the shadowed API key are now ignored and the model slot is
|
|
87
|
+
set to `nil`, avoiding the contradiction where `instance.address` could
|
|
88
|
+
return one value while serialise would overwrite it with another.
|
|
89
|
+
|
|
5
90
|
## [1.3.1] - 2026-05-27
|
|
6
91
|
|
|
7
92
|
### Fixed
|
|
@@ -82,7 +167,9 @@
|
|
|
82
167
|
|
|
83
168
|
Initial release.
|
|
84
169
|
|
|
85
|
-
[Unreleased]: https://github.com/accodeing/rest-easy/compare/v1.
|
|
170
|
+
[Unreleased]: https://github.com/accodeing/rest-easy/compare/v1.4.1...HEAD
|
|
171
|
+
[1.4.1]: https://github.com/accodeing/rest-easy/compare/v1.4.0...v1.4.1
|
|
172
|
+
[1.4.0]: https://github.com/accodeing/rest-easy/compare/v1.3.1...v1.4.0
|
|
86
173
|
[1.3.1]: https://github.com/accodeing/rest-easy/compare/v1.3.0...v1.3.1
|
|
87
174
|
[1.3.0]: https://github.com/accodeing/rest-easy/compare/v1.2.0...v1.3.0
|
|
88
175
|
[1.2.0]: https://github.com/accodeing/rest-easy/compare/v1.1.2...v1.2.0
|
data/README.md
CHANGED
|
@@ -326,12 +326,12 @@ attr [:tax_url, '@urlTaxReductionList'], String, :read_only
|
|
|
326
326
|
|
|
327
327
|
### Flags
|
|
328
328
|
|
|
329
|
-
| Flag | Effect
|
|
330
|
-
|
|
331
|
-
| `:required` | Raises `MissingAttributeError` if
|
|
332
|
-
| `:optional` | Documents that the field may be absent (default)
|
|
333
|
-
| `:read_only` | Excluded from serialisation (not sent back to the API)
|
|
334
|
-
| `:key` | Marks the unique identifier for CRUD operations
|
|
329
|
+
| Flag | Effect |
|
|
330
|
+
|--------------|------------------------------------------------------------------------|
|
|
331
|
+
| `:required` | Raises `MissingAttributeError` if missing or explicitly `null` in the API response (on parse) or `nil` at serialise time (`save`, `to_api`). Omitted keys and explicit `null` are treated identically — a required attribute must carry a value. See [Merge](#merge-pattern--many-api-fields-into-one-model-attribute), [Combine](#combine-pattern--many-model-attributes-into-one-api-field), and [Split](#split-pattern--one-api-field-into-many-model-attributes) patterns for how this applies to synthetic attributes. |
|
|
332
|
+
| `:optional` | Documents that the field may be absent (default) |
|
|
333
|
+
| `:read_only` | Excluded from serialisation (not sent back to the API) |
|
|
334
|
+
| `:key` | Marks the unique identifier for CRUD operations |
|
|
335
335
|
|
|
336
336
|
```ruby
|
|
337
337
|
key :id, Integer, :read_only
|
|
@@ -430,6 +430,31 @@ end
|
|
|
430
430
|
attr :full_name, String, FullNameMapper
|
|
431
431
|
```
|
|
432
432
|
|
|
433
|
+
Marking a merge attribute `:required` enforces that **all** underlying API fields are present in the response on parse. If the attribute is also round-trippable (not `:read_only`), the merged model value must additionally be non-`nil` at serialise time.
|
|
434
|
+
|
|
435
|
+
Note that string-concatenation merges like the `full_name` example above are inherently lossy on the round-trip — splitting `"Hans Erik Nilsson"` back into `FirstName`/`LastName` is ambiguous. Such attributes should normally be `:read_only`. Round-trippable merges work when the model representation preserves the structure (e.g. a tuple, a `Money` value object, or a `Date` built from year/month/day components).
|
|
436
|
+
|
|
437
|
+
### Combine pattern — many model attributes into one API field
|
|
438
|
+
|
|
439
|
+
The dual of merge: when the serialise method takes multiple parameters, RestEasy gathers the values from the corresponding model attributes and passes them in. The block returns the single combined API value:
|
|
440
|
+
|
|
441
|
+
```ruby
|
|
442
|
+
attr :street, String
|
|
443
|
+
attr :city, String
|
|
444
|
+
|
|
445
|
+
attr :address, String do
|
|
446
|
+
serialise { |street, city| "#{street}, #{city}" }
|
|
447
|
+
end
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
The parameter names (`street`, `city`) name model attributes; the framework reads them from the instance and splats them into the block. The block's return value is written under the attribute's API name (`Address`).
|
|
451
|
+
|
|
452
|
+
This also works with mapper objects whose `serialise` method takes multiple parameters.
|
|
453
|
+
|
|
454
|
+
Marking a combine attribute `:required` enforces that **all** named model attributes are non-`nil` at serialise time. The parse side does not apply — combine attributes don't read from a single API field on the way in, so users typically populate the underlying model attributes directly.
|
|
455
|
+
|
|
456
|
+
Combine attributes do not run a `parse` block. If you declare one alongside a multi-parameter `serialise`, RestEasy emits a warning at load time — the parse block would be silently ignored otherwise. If you need to read from an API field on parse, declare a separate attribute for it (or restructure as a merge pattern).
|
|
457
|
+
|
|
433
458
|
### Split pattern — one API field into many model attributes
|
|
434
459
|
|
|
435
460
|
Use a bare block with a parameter to extract from a single API field:
|
|
@@ -446,6 +471,10 @@ end
|
|
|
446
471
|
|
|
447
472
|
The parameter name (`address`) determines which API field to read from.
|
|
448
473
|
|
|
474
|
+
Marking a split attribute `:required` enforces that the underlying API field is present on parse — in the example above, the API response must include `Address`.
|
|
475
|
+
|
|
476
|
+
On serialise, split attributes are emitted under their own api_names (here, `Street` and `City`) rather than being recombined into the original source field. If the API does not accept the parts as independent top-level fields, mark them `:read_only` to keep them out of the outbound payload entirely; alternatively, reconstruct the source field in an `after_serialise` hook.
|
|
477
|
+
|
|
449
478
|
### Ignoring fields
|
|
450
479
|
|
|
451
480
|
Tell RestEasy to silently skip API fields you don't need:
|
data/lib/rest_easy/attribute.rb
CHANGED
|
@@ -36,6 +36,20 @@ module RestEasy
|
|
|
36
36
|
@flags.include?(:synthetic)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
# A combine attribute is built from multiple model fields on serialise
|
|
40
|
+
# (target_fields), with no inbound source from its own api_name on parse.
|
|
41
|
+
# See the "Combine pattern" section of the README.
|
|
42
|
+
def combine?
|
|
43
|
+
@target_fields.any? && @source_fields.empty?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def validate_required!(*values)
|
|
47
|
+
return unless required?
|
|
48
|
+
return if values.none?(&:nil?)
|
|
49
|
+
|
|
50
|
+
raise RestEasy::MissingAttributeError.new(model_name)
|
|
51
|
+
end
|
|
52
|
+
|
|
39
53
|
def coerce(value)
|
|
40
54
|
@type[value]
|
|
41
55
|
rescue Dry::Types::ConstraintError, Dry::Types::CoercionError => e
|
data/lib/rest_easy/meta.rb
CHANGED
|
@@ -25,8 +25,46 @@ module RestEasy
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
# Accessor shapes `method_missing` synthesises. Anchored, so operators
|
|
29
|
+
# stay out: `<=` ends with `=`, and claiming it would let `meta <= 5`
|
|
30
|
+
# read as a setter. `method_missing` itself is still unanchored and
|
|
31
|
+
# writes `@data[:<]` for that call — see issue #6.
|
|
32
|
+
#
|
|
33
|
+
# POSIX classes rather than `[a-zA-Z_]\w*`, because Ruby identifiers are
|
|
34
|
+
# not ASCII-only: `meta.företag = x` is a valid setter that
|
|
35
|
+
# `method_missing` stores, so `respond_to?` has to claim it too.
|
|
36
|
+
ACCESSOR_PATTERN = /\A[[:alpha:]_][[:word:]]*[=?]\z/
|
|
37
|
+
private_constant :ACCESSOR_PATTERN
|
|
38
|
+
|
|
39
|
+
# `method_missing` answers to any name, but this must not, because callers
|
|
40
|
+
# routinely ask an object what it can do before calling it — Ruby's own
|
|
41
|
+
# coercion probes (`to_hash` on double-splat, `to_ary`, `to_str`),
|
|
42
|
+
# serialisation hooks (`marshal_dump`, `init_with`), and any library that
|
|
43
|
+
# duck-types with `respond_to?`. Claiming those hands the caller the `nil`
|
|
44
|
+
# that `method_missing` returns for an unknown key as though it were an
|
|
45
|
+
# answer.
|
|
46
|
+
#
|
|
47
|
+
# Bare getters are therefore claimed only for keys actually held. Setters
|
|
48
|
+
# and predicates are claimed unconditionally: writing is how a key comes
|
|
49
|
+
# into existence, and an unset predicate is meaningfully `false`. No core
|
|
50
|
+
# Ruby probe uses those two shapes — though library-level duck-typing can,
|
|
51
|
+
# and ActiveSupport's `acts_like?(:date)` asking for `acts_like_date?` is
|
|
52
|
+
# a known false positive. Closing it properly means declaring meta keys
|
|
53
|
+
# up front, which is a breaking change — see issue #7.
|
|
54
|
+
#
|
|
55
|
+
# `@data` is guarded because `respond_to?` must never raise, and Ruby
|
|
56
|
+
# allocates an instance before initialising it: Psych's `revive` probes
|
|
57
|
+
# `init_with` on a bare allocation, and so does `Marshal.load` on a
|
|
58
|
+
# payload written before this fix.
|
|
59
|
+
#
|
|
60
|
+
# This under-claims a bare getter for a key that was never set, which
|
|
61
|
+
# `method_missing` still answers with `nil`. Reconciling the two halves
|
|
62
|
+
# means declaring meta keys up front, and that is a 2.0 — see issue #7.
|
|
63
|
+
def respond_to_missing?(name, include_private = false)
|
|
64
|
+
return true if ACCESSOR_PATTERN.match?(name.to_s)
|
|
65
|
+
return super unless @data
|
|
66
|
+
|
|
67
|
+
@data.key?(name.to_sym) || super
|
|
30
68
|
end
|
|
31
69
|
end
|
|
32
70
|
end
|
data/lib/rest_easy/resource.rb
CHANGED
|
@@ -119,8 +119,22 @@ module RestEasy
|
|
|
119
119
|
end
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
# Anchored so operators stay out — see Meta::ACCESSOR_PATTERN and
|
|
123
|
+
# issue #6. Only the setter shape here; unlike Meta, `method_missing`
|
|
124
|
+
# above has no predicate form.
|
|
125
|
+
SETTER_PATTERN = /\A[[:alpha:]_][[:word:]]*=\z/
|
|
126
|
+
private_constant :SETTER_PATTERN
|
|
127
|
+
|
|
128
|
+
# Same reasoning as Meta#respond_to_missing? — a blanket `true` makes
|
|
129
|
+
# this claim Ruby's implicit protocol methods and hand them the `nil`
|
|
130
|
+
# from `method_missing`. `@data` is guarded for the same reason too:
|
|
131
|
+
# `respond_to?` must never raise, and Psych and Marshal both probe a
|
|
132
|
+
# bare allocation before it is initialised.
|
|
133
|
+
def respond_to_missing?(name, include_private = false)
|
|
134
|
+
return true if SETTER_PATTERN.match?(name.to_s)
|
|
135
|
+
return super unless @data
|
|
136
|
+
|
|
137
|
+
@data.key?(name.to_sym) || super
|
|
124
138
|
end
|
|
125
139
|
end
|
|
126
140
|
|
|
@@ -250,6 +264,7 @@ module RestEasy
|
|
|
250
264
|
|
|
251
265
|
serialise_params = serialise_block.parameters.select { |ptype, _| ptype == :opt || ptype == :req }
|
|
252
266
|
if serialise_params.length > 1
|
|
267
|
+
flags << :synthetic unless flags.include?(:synthetic)
|
|
253
268
|
target_fields = serialise_params.map { |_, pname| pname }
|
|
254
269
|
end
|
|
255
270
|
elsif block
|
|
@@ -284,9 +299,22 @@ module RestEasy
|
|
|
284
299
|
if serialise_block
|
|
285
300
|
params = serialise_block.parameters.select { |ptype, _| ptype == :opt || ptype == :req }
|
|
286
301
|
if params.length > 1
|
|
302
|
+
flags << :synthetic unless flags.include?(:synthetic)
|
|
287
303
|
target_fields = params.map { |_, pname| pname }
|
|
288
304
|
end
|
|
289
305
|
end
|
|
306
|
+
|
|
307
|
+
# Combine pattern (multi-param serialise, no multi-param parse)
|
|
308
|
+
# has no inbound api_name on parse. If the user also wrote an
|
|
309
|
+
# explicit `parse` block, it will be silently ignored — warn so
|
|
310
|
+
# the inconsistency is visible at load time.
|
|
311
|
+
if target_fields.any? && source_fields.empty? && parse_block
|
|
312
|
+
warn "RestEasy: :#{attribute_model_name} declares a combine pattern " \
|
|
313
|
+
"(serialise from #{target_fields.inspect}) and also defines a parse block. " \
|
|
314
|
+
"Combine attributes have no inbound API field to read, so the parse block " \
|
|
315
|
+
"will not run. Remove the parse block, or restructure the declaration if you " \
|
|
316
|
+
"intended to read from the API."
|
|
317
|
+
end
|
|
290
318
|
end
|
|
291
319
|
end
|
|
292
320
|
|
|
@@ -591,13 +619,15 @@ module RestEasy
|
|
|
591
619
|
# Serialise all attributes
|
|
592
620
|
klass.all_attribute_definitions.each do |_model_name, attr_def|
|
|
593
621
|
next if attr_def.read_only?
|
|
594
|
-
value = @model_attributes[attr_def.model_name]
|
|
595
622
|
|
|
596
623
|
if attr_def.target_fields.any?
|
|
597
624
|
# Multi-param serialise: gather model values by param names, splat into block
|
|
598
625
|
model_values = attr_def.target_fields.map { |fn| @model_attributes[fn] }
|
|
626
|
+
attr_def.validate_required!(*model_values)
|
|
599
627
|
result[attr_def.api_name] = attr_def.serialise_value(*model_values)
|
|
600
628
|
elsif attr_def.source_fields.any?
|
|
629
|
+
value = @model_attributes[attr_def.model_name]
|
|
630
|
+
attr_def.validate_required!(value)
|
|
601
631
|
serialised = attr_def.serialise_value(value)
|
|
602
632
|
if serialised.is_a?(::Array)
|
|
603
633
|
# Array return: zip with source field API names
|
|
@@ -613,6 +643,8 @@ module RestEasy
|
|
|
613
643
|
result[attr_def.api_name] = serialised
|
|
614
644
|
end
|
|
615
645
|
else
|
|
646
|
+
value = @model_attributes[attr_def.model_name]
|
|
647
|
+
attr_def.validate_required!(value)
|
|
616
648
|
result[attr_def.api_name] = attr_def.serialise_value(value)
|
|
617
649
|
end
|
|
618
650
|
end
|
|
@@ -683,13 +715,19 @@ module RestEasy
|
|
|
683
715
|
api_key = convention.serialise(field_name)
|
|
684
716
|
api_data[api_key]
|
|
685
717
|
end
|
|
718
|
+
|
|
719
|
+
attr_def.validate_required!(*raw_values)
|
|
720
|
+
|
|
686
721
|
@model_attributes[model_name] = attr_def.parse_value(*raw_values)
|
|
722
|
+
elsif attr_def.combine?
|
|
723
|
+
# Combine pattern: the attribute's api_name does not exist on the
|
|
724
|
+
# API side by design — the value is built from target_fields at
|
|
725
|
+
# serialise time. Nothing inbound to read or validate.
|
|
726
|
+
@model_attributes[model_name] = nil
|
|
687
727
|
else
|
|
688
728
|
raw_value = api_data[attr_def.api_name]
|
|
689
729
|
|
|
690
|
-
|
|
691
|
-
raise MissingAttributeError.new(model_name)
|
|
692
|
-
end
|
|
730
|
+
attr_def.validate_required!(raw_value)
|
|
693
731
|
|
|
694
732
|
if raw_value.nil?
|
|
695
733
|
@model_attributes[model_name] = nil
|
|
@@ -717,9 +755,12 @@ module RestEasy
|
|
|
717
755
|
end
|
|
718
756
|
end
|
|
719
757
|
|
|
720
|
-
# Warn about declared attributes missing from the API response
|
|
758
|
+
# Warn about declared attributes missing from the API response.
|
|
759
|
+
# Combine attrs have no inbound api_name by design; non-combine
|
|
760
|
+
# required attrs already raised in the parse loop above.
|
|
721
761
|
klass.all_attribute_definitions.each do |model_name, attr_def|
|
|
722
|
-
next if attr_def.
|
|
762
|
+
next if attr_def.combine?
|
|
763
|
+
next if attr_def.required?
|
|
723
764
|
|
|
724
765
|
api_keys_to_check = if attr_def.source_fields.any?
|
|
725
766
|
attr_def.source_fields.map { |sf| convention.serialise(sf) }
|
data/lib/rest_easy/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rest-easy
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jonas Schubert Erlandsson
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2026-
|
|
13
|
+
date: 2026-08-18 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: dry-types
|