plumb 0.0.7 → 0.0.8
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/README.md +42 -2
- data/lib/plumb/attributes.rb +34 -11
- data/lib/plumb/not.rb +9 -3
- data/lib/plumb/types.rb +1 -0
- data/lib/plumb/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e5d0ac088968506a61d63da75f4010b050579c873d79604a25dfe0b133d3726
|
4
|
+
data.tar.gz: d559c1a3964544184258043e14d0bf9e3b41ff743a8117eccee09be2c22b084a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1207b06d90baa9833cf39737f2697fb6daf9423d94ca531a99307de561b70415bb6c9ec7fb2394af6c1f8b3f86015996ebfde5db6dc3fa2aadd5284fb1867cb2
|
7
|
+
data.tar.gz: 19131a0a289b8c5082ceb3a9cd716cdabb2d12466bba76ecc5d20c2efd6db3fbb9c04d13c8706996225189de50d81c5d8325fc5527ecc8395c492430fd17393d
|
data/README.md
CHANGED
@@ -294,6 +294,22 @@ NotEmail.parse('hello') # "hello"
|
|
294
294
|
NotEmail.parse('hello@server.com') # error
|
295
295
|
```
|
296
296
|
|
297
|
+
`#not` can also be given a type as argument, which might read better:
|
298
|
+
|
299
|
+
```ruby
|
300
|
+
Types::Any.not(nil)
|
301
|
+
Types::Any.not(Types::Email)
|
302
|
+
```
|
303
|
+
|
304
|
+
Finally, you can use `Types::Not` for the same effect.
|
305
|
+
|
306
|
+
```ruby
|
307
|
+
NotNil = Types::Not[nil]
|
308
|
+
NotNil.parse(1) # 1
|
309
|
+
NotNil.parse('hello') # 'hello'
|
310
|
+
NotNil.parse(nil) # error
|
311
|
+
```
|
312
|
+
|
297
313
|
#### `#options`
|
298
314
|
|
299
315
|
Sets allowed options for value.
|
@@ -506,7 +522,7 @@ So, normally you'd only use this attached to primitive types without further pro
|
|
506
522
|
Passing a proc will evaluate the proc on every invocation. Use this for generated values.
|
507
523
|
|
508
524
|
```ruby
|
509
|
-
random_number = Types::Numeric.
|
525
|
+
random_number = Types::Numeric.generate { rand }
|
510
526
|
random_number.parse # 0.32332
|
511
527
|
random_number.parse('foo') # 0.54322 etc
|
512
528
|
```
|
@@ -514,7 +530,7 @@ random_number.parse('foo') # 0.54322 etc
|
|
514
530
|
Note that the type of generated value must match the initial step's type, validated at invocation.
|
515
531
|
|
516
532
|
```ruby
|
517
|
-
random_number = Types::String.
|
533
|
+
random_number = Types::String.generate { rand } # this won't raise an error here
|
518
534
|
random_number.parse # raises Plumb::ParseError because `rand` is not a String
|
519
535
|
```
|
520
536
|
|
@@ -1200,6 +1216,30 @@ Payload = Types::Hash[
|
|
1200
1216
|
]
|
1201
1217
|
```
|
1202
1218
|
|
1219
|
+
#### Attribute writers
|
1220
|
+
|
1221
|
+
By default `Types::Data` classes are inmutable, but you can define attribute writers to allow for mutation using the `writer: true` option.
|
1222
|
+
|
1223
|
+
```ruby
|
1224
|
+
class DBConfig < Types::Data
|
1225
|
+
attribute :host, Types::String.default('localhost'), writer: true
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
class Config < Types::Data
|
1229
|
+
attribute :host, Types::Forms::URI::HTTP, writer: true
|
1230
|
+
attribute :port, Types::Integer.default(80), writer: true
|
1231
|
+
|
1232
|
+
# Nested structs can have writers too
|
1233
|
+
attribute :db, DBConfig.default(DBConfig.new)
|
1234
|
+
end
|
1235
|
+
|
1236
|
+
config = Config.new
|
1237
|
+
config.host = 'http://localhost'
|
1238
|
+
config.db.host = 'db.local'
|
1239
|
+
config.valid? # true
|
1240
|
+
config.errors # {}
|
1241
|
+
```
|
1242
|
+
|
1203
1243
|
#### Recursive struct definitions
|
1204
1244
|
|
1205
1245
|
You can use `#defer`. See [recursive types](#recursive-types).
|
data/lib/plumb/attributes.rb
CHANGED
@@ -117,6 +117,7 @@ module Plumb
|
|
117
117
|
|
118
118
|
def initialize(attrs = {})
|
119
119
|
assign_attributes(attrs)
|
120
|
+
freeze
|
120
121
|
end
|
121
122
|
|
122
123
|
def ==(other)
|
@@ -140,13 +141,18 @@ module Plumb
|
|
140
141
|
|
141
142
|
# @return [Hash]
|
142
143
|
def to_h
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
144
|
+
self.class._schema._schema.keys.each.with_object({}) do |key, memo|
|
145
|
+
key = key.to_sym
|
146
|
+
value = attributes[key]
|
147
|
+
val = case value
|
148
|
+
when ::Array
|
149
|
+
value.map { |v| v.respond_to?(:to_h) ? v.to_h : v }
|
150
|
+
when ::NilClass
|
151
|
+
nil
|
152
|
+
else
|
153
|
+
value.respond_to?(:to_h) ? value.to_h : value
|
154
|
+
end
|
155
|
+
memo[key] = val
|
150
156
|
end
|
151
157
|
end
|
152
158
|
|
@@ -158,7 +164,7 @@ module Plumb
|
|
158
164
|
def assign_attributes(attrs = BLANK_HASH)
|
159
165
|
raise ArgumentError, 'Must be a Hash of attributes' unless attrs.respond_to?(:to_h)
|
160
166
|
|
161
|
-
@errors =
|
167
|
+
@errors = {}
|
162
168
|
result = self.class._schema.resolve(attrs.to_h)
|
163
169
|
@attributes = prepare_attributes(result.value)
|
164
170
|
@errors = result.errors unless result.valid?
|
@@ -211,7 +217,7 @@ module Plumb
|
|
211
217
|
# attribute(:friends, Types::Array[Person])
|
212
218
|
# attribute(:friends, [Person])
|
213
219
|
#
|
214
|
-
def attribute(name, type = Types::Any, &block)
|
220
|
+
def attribute(name, type = Types::Any, writer: false, &block)
|
215
221
|
key = Key.wrap(name)
|
216
222
|
name = key.to_sym
|
217
223
|
type = Composable.wrap(type)
|
@@ -234,13 +240,30 @@ module Plumb
|
|
234
240
|
end
|
235
241
|
|
236
242
|
@_schema = _schema + { key => type }
|
237
|
-
|
243
|
+
__plumb_define_attribute_reader_method__(name)
|
244
|
+
return name unless writer
|
245
|
+
|
246
|
+
__plumb_define_attribute_writer_method__(name)
|
238
247
|
end
|
239
248
|
|
240
|
-
def
|
249
|
+
def __plumb_define_attribute_reader_method__(name)
|
241
250
|
define_method(name) { @attributes[name] }
|
242
251
|
end
|
243
252
|
|
253
|
+
def __plumb_define_attribute_writer_method__(name)
|
254
|
+
define_method("#{name}=") do |value|
|
255
|
+
type = self.class._schema.at_key(name)
|
256
|
+
result = type.resolve(value)
|
257
|
+
@attributes[name] = result.value
|
258
|
+
if result.valid?
|
259
|
+
@errors.delete(name)
|
260
|
+
else
|
261
|
+
@errors.merge!(name => result.errors)
|
262
|
+
end
|
263
|
+
result.value
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
244
267
|
def attribute?(name, *args, &block)
|
245
268
|
attribute(Key.new(name, optional: true), *args, &block)
|
246
269
|
end
|
data/lib/plumb/not.rb
CHANGED
@@ -8,13 +8,19 @@ module Plumb
|
|
8
8
|
|
9
9
|
attr_reader :children, :errors
|
10
10
|
|
11
|
-
def initialize(step, errors: nil)
|
12
|
-
@step = step
|
13
|
-
@errors = errors
|
11
|
+
def initialize(step = nil, errors: nil)
|
12
|
+
@step = Composable.wrap(step)
|
13
|
+
@errors = errors || "must not be #{step.inspect}"
|
14
14
|
@children = [step].freeze
|
15
15
|
freeze
|
16
16
|
end
|
17
17
|
|
18
|
+
# @param step [Object]
|
19
|
+
# @return [Not]
|
20
|
+
def [](step)
|
21
|
+
self.class.new(step)
|
22
|
+
end
|
23
|
+
|
18
24
|
private def _inspect
|
19
25
|
%(Not(#{@step.inspect}))
|
20
26
|
end
|
data/lib/plumb/types.rb
CHANGED
data/lib/plumb/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plumb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ismael Celis
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bigdecimal
|
@@ -115,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
115
|
- !ruby/object:Gem::Version
|
116
116
|
version: '0'
|
117
117
|
requirements: []
|
118
|
-
rubygems_version: 3.5.
|
118
|
+
rubygems_version: 3.5.21
|
119
119
|
signing_key:
|
120
120
|
specification_version: 4
|
121
121
|
summary: Data validation and transformation library.
|