strict 2.0.0 → 2.1.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/API.md +5 -3
- data/CHANGELOG.md +8 -1
- data/Gemfile.lock +1 -1
- data/README.md +7 -1
- data/lib/strict/union.rb +34 -0
- data/lib/strict/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2cf2282196d21b0f929b9339bd7e93f6f97ce80796c47b29330519241d2ae11
|
|
4
|
+
data.tar.gz: 63ee491ee31552fa9b6449cedd24b2754f83222e362cf9cc4c0fca51cd367426
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f8cb4a343d08ef27c01ffa3d8bc02da8657cdcd98663e235e3ffe79598c0de55a9dc571b09524b6d2da31bb9cdc87e67494395eb71caff53bc90198d99d55699
|
|
7
|
+
data.tar.gz: e22d700e910206b31514c3661cbac6f3df04001082e4307922cd2f0203eb3e5f0b29129c1d2aab74bc03d68f561cd38a4114fd94f759a9197f0f3808b7b6d132
|
data/API.md
CHANGED
|
@@ -116,10 +116,12 @@ There is no default discriminator. A union can declare zero or one `attributes`
|
|
|
116
116
|
|
|
117
117
|
A variant name must be a lower snake-case string or symbol, and Strict generates its PascalCase nested subclass. By default, the discriminator tag is the name's corresponding symbol. The optional `tag:` can assign a different string or symbol. For example, `variant :requires_action, tag: "action-required"` generates `PaymentResult::RequiresAction < PaymentResult` with the tag `"action-required"`.
|
|
118
118
|
|
|
119
|
+
Each variant name also generates a class-level convenience constructor and an instance interrogation method. `PaymentResult.authorized(...)` calls `PaymentResult::Authorized.new(...)`. Every union member responds to `authorized?`, which is true for authorized members and false for other variants. These methods use the variant name even when the discriminator tag differs.
|
|
120
|
+
|
|
119
121
|
The variant block configures the generated subclass. It can include modules, define methods, and contain zero or one `attributes` block. Strict combines the discriminator, shared union attributes, and variant attributes in that order. The discriminator is an implicit first attribute with a fixed default value:
|
|
120
122
|
|
|
121
123
|
```ruby
|
|
122
|
-
PaymentResult
|
|
124
|
+
PaymentResult.authorized(
|
|
123
125
|
request_id: "request_123",
|
|
124
126
|
authorization_id: "auth_123",
|
|
125
127
|
amount_in_cents: 1_000
|
|
@@ -127,7 +129,7 @@ PaymentResult::Authorized.new(
|
|
|
127
129
|
# => { status: "payment.authorized", request_id: "request_123", authorization_id: "auth_123", amount_in_cents: 1_000 }
|
|
128
130
|
```
|
|
129
131
|
|
|
130
|
-
Variants therefore use the documented `Strict::Value` behavior for initialization, validation, coercion, defaults, copying, equality, hashing, conversion, inspection, pattern matching, and declaration errors. A variant attribute cannot duplicate or share a backing instance variable with the discriminator or a shared union attribute, and generated readers cannot collide with methods defined in the variant block. The union base cannot be instantiated directly.
|
|
132
|
+
Variants therefore use the documented `Strict::Value` behavior for initialization, validation, coercion, defaults, copying, equality, hashing, conversion, inspection, pattern matching, and declaration errors. A variant attribute cannot duplicate or share a backing instance variable with the discriminator or a shared union attribute, and generated readers cannot collide with methods defined in the variant block. Generated convenience constructors and interrogation methods cannot collide with existing class or instance methods or with variant behavior. The union base cannot be instantiated directly.
|
|
131
133
|
|
|
132
134
|
`PaymentResult === value` is true only when `value` has the exact class of a registered variant. Generated variant classes retain normal Ruby class matching, including matching instances of their subclasses. Union and variant inheritance are outside the compatibility boundary.
|
|
133
135
|
|
|
@@ -147,7 +149,7 @@ payment_result PaymentResult
|
|
|
147
149
|
strict_payment_result PaymentResult, coerce: false
|
|
148
150
|
```
|
|
149
151
|
|
|
150
|
-
Declaring a discriminator more than once, declaring equivalent duplicate string or symbol tags, using an invalid variant name or tag, replacing an existing generated constant, declaring multiple union or variant attribute blocks, declaring union attributes after a variant, or redeclaring the discriminator raises `ArgumentError`. Declaration return values, generated-class reflection details, and the exact text of declaration and coercion errors are outside the compatibility boundary.
|
|
152
|
+
Declaring a discriminator more than once, declaring equivalent duplicate string or symbol tags, using an invalid or conflicting variant name or tag, replacing an existing generated constant, declaring multiple union or variant attribute blocks, declaring union attributes after a variant, or redeclaring the discriminator raises `ArgumentError`. Declaration return values, generated-class reflection details, and the exact text of declaration and coercion errors are outside the compatibility boundary.
|
|
151
153
|
|
|
152
154
|
### Signed methods
|
|
153
155
|
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [2.1.0] - 2026-08-21
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Add class-level convenience constructors and instance interrogation methods for every `Strict::Union` variant.
|
|
8
|
+
|
|
3
9
|
## [2.0.0] - 2026-08-20
|
|
4
10
|
|
|
5
11
|
### Added
|
|
@@ -102,7 +108,8 @@ The equal-weight geometric mean of the eight after/before timing ratios is 0.57,
|
|
|
102
108
|
|
|
103
109
|
- Start initial development.
|
|
104
110
|
|
|
105
|
-
[Unreleased]: https://github.com/kylekthompson/strict/compare/v2.
|
|
111
|
+
[Unreleased]: https://github.com/kylekthompson/strict/compare/v2.1.0...HEAD
|
|
112
|
+
[2.1.0]: https://github.com/kylekthompson/strict/compare/v2.0.0...v2.1.0
|
|
106
113
|
[2.0.0]: https://github.com/kylekthompson/strict/compare/v1.5.0...v2.0.0
|
|
107
114
|
[1.5.0]: https://github.com/kylekthompson/strict/compare/v1.4.0...v1.5.0
|
|
108
115
|
[1.4.0]: https://github.com/kylekthompson/strict/compare/v1.3.1...v1.4.0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -103,7 +103,7 @@ class PaymentResult
|
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
authorized = PaymentResult
|
|
106
|
+
authorized = PaymentResult.authorized(
|
|
107
107
|
request_id: "request_123",
|
|
108
108
|
authorization_id: "auth_123",
|
|
109
109
|
amount_in_cents: 1_000
|
|
@@ -111,6 +111,12 @@ authorized = PaymentResult::Authorized.new(
|
|
|
111
111
|
authorized.to_h
|
|
112
112
|
# => { status: "payment.authorized", request_id: "request_123", authorization_id: "auth_123", amount_in_cents: 1_000 }
|
|
113
113
|
|
|
114
|
+
authorized.authorized?
|
|
115
|
+
# => true
|
|
116
|
+
|
|
117
|
+
authorized.declined?
|
|
118
|
+
# => false
|
|
119
|
+
|
|
114
120
|
authorized.successful?
|
|
115
121
|
# => true
|
|
116
122
|
|
data/lib/strict/union.rb
CHANGED
|
@@ -43,6 +43,7 @@ module Strict
|
|
|
43
43
|
tag_key = strict_union_tag_key(tag)
|
|
44
44
|
constant_name = strict_union_validate_variant!(name, tag, tag_key)
|
|
45
45
|
variant_class = strict_union_build_variant(discriminator, name, tag, definition)
|
|
46
|
+
strict_union_validate_interrogation_method!(name, variant_class)
|
|
46
47
|
strict_union_register_variant(name, tag, tag_key, constant_name, variant_class)
|
|
47
48
|
end
|
|
48
49
|
|
|
@@ -66,17 +67,50 @@ module Strict
|
|
|
66
67
|
raise ArgumentError, "tag #{tag.inspect} already declared for #{self}" if @strict_union_variants.key?(tag_key)
|
|
67
68
|
raise ArgumentError, "constant #{constant_name} is already defined for #{self}" if
|
|
68
69
|
const_defined?(constant_name, false)
|
|
70
|
+
raise ArgumentError, "variant convenience method #{name.inspect} already exists for #{self}" if
|
|
71
|
+
strict_union_method_defined?(singleton_class, name)
|
|
69
72
|
|
|
70
73
|
constant_name
|
|
71
74
|
end
|
|
72
75
|
|
|
76
|
+
def strict_union_validate_interrogation_method!(name, variant_class)
|
|
77
|
+
method_name = strict_union_interrogation_method(name)
|
|
78
|
+
owners = [self, *@strict_union_variant_names.values, variant_class]
|
|
79
|
+
conflicting_owner = owners.find { |owner| strict_union_method_defined?(owner, method_name) }
|
|
80
|
+
raise ArgumentError, "interrogation method #{method_name.inspect} already exists for #{conflicting_owner}" if
|
|
81
|
+
conflicting_owner
|
|
82
|
+
|
|
83
|
+
strict_union_validate_existing_interrogation_methods!(variant_class)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def strict_union_validate_existing_interrogation_methods!(variant_class)
|
|
87
|
+
@strict_union_variant_names.each_key do |variant_name|
|
|
88
|
+
existing_method = strict_union_interrogation_method(variant_name)
|
|
89
|
+
next if variant_class.instance_method(existing_method).owner.equal?(self)
|
|
90
|
+
|
|
91
|
+
raise ArgumentError, "interrogation method #{existing_method.inspect} already exists for #{variant_class}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
73
95
|
def strict_union_register_variant(name, tag, tag_key, constant_name, variant_class)
|
|
74
96
|
const_set(constant_name, variant_class)
|
|
75
97
|
@strict_union_variant_names[name] = variant_class
|
|
76
98
|
@strict_union_variants[tag_key] = Variant.new(tag:, variant_class:)
|
|
99
|
+
define_singleton_method(name) { |**attributes| variant_class.new(**attributes) }
|
|
100
|
+
define_method(strict_union_interrogation_method(name)) { variant_class === self }
|
|
77
101
|
variant_class
|
|
78
102
|
end
|
|
79
103
|
|
|
104
|
+
def strict_union_interrogation_method(name)
|
|
105
|
+
:"#{name}?"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def strict_union_method_defined?(owner, name)
|
|
109
|
+
owner.public_method_defined?(name) ||
|
|
110
|
+
owner.protected_method_defined?(name) ||
|
|
111
|
+
owner.private_method_defined?(name)
|
|
112
|
+
end
|
|
113
|
+
|
|
80
114
|
def strict_union_discriminator!
|
|
81
115
|
@strict_union_discriminator ||
|
|
82
116
|
raise(ArgumentError, "declare a discriminator before variants for #{self}")
|
data/lib/strict/version.rb
CHANGED