plumb 0.2.0.beta.1 → 0.2.0.beta.3
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 +160 -93
- data/lib/plumb/array_class.rb +72 -9
- data/lib/plumb/codec.rb +275 -140
- data/lib/plumb/composable.rb +2 -2
- data/lib/plumb/hash_class.rb +5 -4
- data/lib/plumb/hash_map.rb +1 -5
- data/lib/plumb/stream_class.rb +1 -5
- data/lib/plumb/types.rb +21 -4
- data/lib/plumb/version.rb +1 -1
- metadata +1 -1
data/lib/plumb/composable.rb
CHANGED
|
@@ -232,8 +232,8 @@ module Plumb
|
|
|
232
232
|
callable
|
|
233
233
|
elsif callable.respond_to?(:to_composable)
|
|
234
234
|
# The context-free resolution hook for objects that become a type on
|
|
235
|
-
# demand: an Encoder class resolves to its default (declared)
|
|
236
|
-
#
|
|
235
|
+
# demand: an Encoder class resolves to its default (declared) direction; a
|
|
236
|
+
# Codec raises, having no type to become. Used in schema literals,
|
|
237
237
|
# `Array[Enc]`, `#/`, etc. The composition operators (#>>, #|, #&)
|
|
238
238
|
# consult #to_plumb_type BEFORE wrapping, so a composed operand can
|
|
239
239
|
# resolve against context and never reaches this branch.
|
data/lib/plumb/hash_class.rb
CHANGED
|
@@ -453,11 +453,12 @@ module Plumb
|
|
|
453
453
|
# A filtered Hash is lenient: it accepts ANY hash and drops invalid/missing/
|
|
454
454
|
# extra fields (it never rejects a Hash), so as a #>> consumer it accepts any
|
|
455
455
|
# hash-like value. (Its #input_type still declares the schema it relaxes.)
|
|
456
|
-
|
|
457
|
-
# when this file is).
|
|
458
|
-
def self.each_pair_interface = @each_pair_interface ||= Types::Interface[:each_pair]
|
|
456
|
+
def accepted_type = Types::EachPair
|
|
459
457
|
|
|
460
|
-
|
|
458
|
+
# Re-derived, NOT rebuilt around the old #fn: the filter closes over the schema it
|
|
459
|
+
# was built from, so Function#with_children returns a node that inspects as the
|
|
460
|
+
# new schema and still filters by the old one.
|
|
461
|
+
def with_children(children) = children.first.filtered
|
|
461
462
|
|
|
462
463
|
# Neither boundary check runs — the per-field validation in HashClass#filtered
|
|
463
464
|
# subsumes both. Overriding #call is also what excludes this node from fusion,
|
data/lib/plumb/hash_map.rb
CHANGED
|
@@ -93,11 +93,7 @@ module Plumb
|
|
|
93
93
|
# entries (it never rejects a Hash), so as a #>> consumer it accepts any
|
|
94
94
|
# hash-like value — not itself. Without this, `Hash >> Hash[K, V].filtered`
|
|
95
95
|
# would be flagged as an illegal narrowing.
|
|
96
|
-
|
|
97
|
-
# yet when this file is).
|
|
98
|
-
def self.each_pair_interface = @each_pair_interface ||= Types::Interface[:each_pair]
|
|
99
|
-
|
|
100
|
-
def accepted_type = FilteredHashMap.each_pair_interface
|
|
96
|
+
def accepted_type = Types::EachPair
|
|
101
97
|
|
|
102
98
|
def call(result)
|
|
103
99
|
result.invalid(errors: 'must be a Hash') unless result.value.is_a?(::Hash)
|
data/lib/plumb/stream_class.rb
CHANGED
|
@@ -41,11 +41,7 @@ module Plumb
|
|
|
41
41
|
# #>> composition check. This lets a producer of a raw Enumerator/Array (eg.
|
|
42
42
|
# a CSV enumerator) feed a Stream. Covariant Stream[X] <= Stream[Y]
|
|
43
43
|
# subtyping is unaffected (that goes through #subtype_of? / #children).
|
|
44
|
-
|
|
45
|
-
# when this file is) — #call hits it on every data invocation.
|
|
46
|
-
def self.each_interface = @each_interface ||= Types::Interface[:each]
|
|
47
|
-
|
|
48
|
-
def input_type = StreamClass.each_interface
|
|
44
|
+
def input_type = Types::Each
|
|
49
45
|
|
|
50
46
|
# The [Step] interface
|
|
51
47
|
# @param result [Result]
|
data/lib/plumb/types.rb
CHANGED
|
@@ -96,11 +96,16 @@ module Plumb
|
|
|
96
96
|
# Works with a block too:
|
|
97
97
|
# date = Type::Any[Date].default { Date.today }
|
|
98
98
|
#
|
|
99
|
+
# A generated default declares, and is checked against, `type`'s OUTPUT — not `type`
|
|
100
|
+
# itself, which would re-run a conversion on a value the block already produced
|
|
101
|
+
# (`Types::String.transform(::Integer).default { 10 }` generates the Integer).
|
|
102
|
+
# Declaring it also tells the rest of the library what fills this position: without
|
|
103
|
+
# it the branch resolves to `Any`, and a Codec has nothing to encode.
|
|
99
104
|
policy :default, helper: true do |type, value = Undefined, &block|
|
|
100
105
|
val_type = if value == Undefined
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
fn = ->(result) { result.valid(block.call) }
|
|
107
|
+
Function.new(Types::Any, Plumb::Subtyping.resolved_output(type), fn,
|
|
108
|
+
inspect: 'default proc', identity: [:default, block])
|
|
104
109
|
else
|
|
105
110
|
Types::Static[value]
|
|
106
111
|
end
|
|
@@ -112,12 +117,20 @@ module Plumb
|
|
|
112
117
|
# Expect a specific exception class, and return an invalid result if it is raised.
|
|
113
118
|
# Usage:
|
|
114
119
|
# type = Types::String.build(Date, :parse).policy(:rescue, Date::Error)
|
|
120
|
+
#
|
|
121
|
+
# The guard returns what `type` returned, so it declares `type`'s OUTPUT — opaque,
|
|
122
|
+
# it would erase the type it wraps (the closure is invisible) and resolve to `Any`.
|
|
123
|
+
# Unchecked: `type` already validated what it produced. The INPUT stays `Any`, or
|
|
124
|
+
# `type`'s own input check runs a second time, outside the rescue.
|
|
115
125
|
policy :rescue do |type, exception_class|
|
|
116
|
-
|
|
126
|
+
fn = lambda do |result|
|
|
117
127
|
type.call(result)
|
|
118
128
|
rescue exception_class => e
|
|
119
129
|
result.invalid(errors: e.message)
|
|
120
130
|
end
|
|
131
|
+
|
|
132
|
+
GuaranteedFunction.new(Types::Any, Plumb::Subtyping.resolved_output(type), fn,
|
|
133
|
+
inspect: 'Rescue', identity: [:rescue, type, exception_class])
|
|
121
134
|
end
|
|
122
135
|
|
|
123
136
|
# Split a string into an array. Default separator is /\s*,\s*/
|
|
@@ -168,6 +181,10 @@ module Plumb
|
|
|
168
181
|
Email = String[URI::MailTo::EMAIL_REGEXP].as_node(:email)
|
|
169
182
|
Date = Any[::Date]
|
|
170
183
|
Time = Any[::Time]
|
|
184
|
+
# What a lenient container accepts (a Stream, a `.filtered` Array/Hash/HashMap).
|
|
185
|
+
# Here, not beside those classes, because Types is loaded after all of them.
|
|
186
|
+
Each = Interface[:each]
|
|
187
|
+
EachPair = Interface[:each_pair]
|
|
171
188
|
|
|
172
189
|
# A type that recursively converts string keys to symbols in nested hashes.
|
|
173
190
|
# This is commonly used for normalizing payload data in commands and events.
|
data/lib/plumb/version.rb
CHANGED