plumb 0.0.3 → 0.0.4

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.
data/lib/plumb/schema.rb CHANGED
@@ -5,13 +5,13 @@ require 'plumb/json_schema_visitor'
5
5
 
6
6
  module Plumb
7
7
  class Schema
8
- include Steppable
8
+ include Composable
9
9
 
10
10
  def self.wrap(sch = nil, &block)
11
11
  raise ArgumentError, 'expected a block or a schema' if sch.nil? && !block_given?
12
12
 
13
13
  if sch
14
- raise ArgumentError, 'expected a Steppable' unless sch.is_a?(Steppable)
14
+ raise ArgumentError, 'expected a Composable' unless sch.is_a?(Composable)
15
15
 
16
16
  return sch
17
17
  end
@@ -49,8 +49,8 @@ module Plumb
49
49
  self
50
50
  end
51
51
 
52
- def json_schema
53
- JSONSchemaVisitor.call(_hash).to_h
52
+ def to_json_schema
53
+ _hash.to_json_schema(root: true)
54
54
  end
55
55
 
56
56
  def call(result)
@@ -120,7 +120,7 @@ module Plumb
120
120
  block_given? ? ArrayClass.new(element_type: Schema.new(&block)) : type
121
121
  when nil
122
122
  block_given? ? Schema.new(&block) : Types::Any
123
- when Steppable
123
+ when Composable
124
124
  type
125
125
  when Class
126
126
  if type == Array && block_given?
@@ -140,13 +140,14 @@ module Plumb
140
140
  self
141
141
  end
142
142
 
143
- def meta(md = nil)
144
- @_type = @_type.meta(md) if md
145
- self
143
+ def metadata(data = Undefined)
144
+ if data == Undefined
145
+ @_type.metadata
146
+ else
147
+ @_type = @_type.metadata(data)
148
+ end
146
149
  end
147
150
 
148
- def metadata = @_type.metadata
149
-
150
151
  def options(opts)
151
152
  @_type = @_type.options(opts)
152
153
  self
@@ -1,17 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class StaticClass
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :value
9
+ attr_reader :children
10
10
 
11
11
  def initialize(value = Undefined)
12
12
  raise ArgumentError, 'value must be frozen' unless value.frozen?
13
13
 
14
14
  @value = value
15
+ @children = [value].freeze
15
16
  freeze
16
17
  end
17
18
 
data/lib/plumb/step.rb CHANGED
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class Step
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :_metadata
9
+ attr_reader :_metadata, :children
10
10
 
11
11
  def initialize(callable = nil, inspect = nil, &block)
12
12
  @_metadata = callable.respond_to?(:metadata) ? callable.metadata : BLANK_HASH
13
13
  @callable = callable || block
14
+ @children = [@callable].freeze
14
15
  @inspect = inspect || @callable.inspect
15
16
  freeze
16
17
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'thread'
4
- require 'plumb/steppable'
4
+ require 'plumb/composable'
5
5
 
6
6
  module Plumb
7
7
  # A stream that validates each element.
@@ -15,18 +15,19 @@ module Plumb
15
15
  # result.value # => ['name', 10]
16
16
  # end
17
17
  class StreamClass
18
- include Steppable
18
+ include Composable
19
19
 
20
- attr_reader :element_type
20
+ attr_reader :children
21
21
 
22
- # @option element_type [Steppable] the type of the elements in the stream
22
+ # @option element_type [Composable] the type of the elements in the stream
23
23
  def initialize(element_type: Types::Any)
24
- @element_type = Steppable.wrap(element_type)
24
+ @element_type = Composable.wrap(element_type)
25
+ @children = [@element_type].freeze
25
26
  freeze
26
27
  end
27
28
 
28
29
  # return a new Stream definition.
29
- # @param element_type [Steppable] the type of the elements in the stream
30
+ # @param element_type [Composable] the type of the elements in the stream
30
31
  def [](element_type)
31
32
  self.class.new(element_type:)
32
33
  end
@@ -39,7 +40,7 @@ module Plumb
39
40
 
40
41
  enum = Enumerator.new do |y|
41
42
  result.value.each do |e|
42
- y << element_type.resolve(e)
43
+ y << @element_type.resolve(e)
43
44
  end
44
45
  end
45
46
 
@@ -1,29 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class TaggedHash
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :key, :types
9
+ attr_reader :key, :children
10
10
 
11
- def initialize(hash_type, key, types)
11
+ def initialize(hash_type, key, children)
12
12
  @hash_type = hash_type
13
13
  @key = Key.wrap(key)
14
- @types = types
14
+ @children = children
15
15
 
16
- raise ArgumentError, 'all types must be HashClass' if @types.size.zero? || @types.any? do |t|
16
+ raise ArgumentError, 'all types must be HashClass' if @children.size.zero? || @children.any? do |t|
17
17
  !t.is_a?(HashClass)
18
18
  end
19
- raise ArgumentError, "all types must define key #{@key}" unless @types.all? { |t| !!t.at_key(@key) }
19
+ raise ArgumentError, "all types must define key #{@key}" unless @children.all? { |t| !!t.at_key(@key) }
20
20
 
21
21
  # types are assumed to have literal values for the index field :key
22
- @index = @types.each.with_object({}) do |t, memo|
22
+ @index = @children.each.with_object({}) do |t, memo|
23
23
  key_type = t.at_key(@key)
24
24
  raise TypeError, "key type at :#{@key} #{key_type} must be a Match type" unless key_type.is_a?(MatchClass)
25
25
 
26
- memo[key_type.matcher] = t
26
+ memo[key_type.children[0]] = t
27
27
  end
28
28
 
29
29
  freeze
@@ -41,6 +41,6 @@ module Plumb
41
41
 
42
42
  private
43
43
 
44
- def _inspect = "TaggedHash[#{@key.inspect}, #{@types.map(&:inspect).join(', ')}]"
44
+ def _inspect = "TaggedHash[#{@key.inspect}, #{@children.map(&:inspect).join(', ')}]"
45
45
  end
46
46
  end
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class Transform
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :target_type
9
+ attr_reader :children
10
10
 
11
11
  def initialize(target_type, callable)
12
12
  @target_type = target_type
13
13
  @callable = callable || Plumb::NOOP
14
+ @children = [target_type].freeze
14
15
  freeze
15
16
  end
16
17
 
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class TupleClass
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :types
9
+ attr_reader :children
10
10
 
11
- def initialize(*types)
12
- @types = types.map { |t| Steppable.wrap(t) }
11
+ def initialize(*children)
12
+ @children = children.map { |t| Composable.wrap(t) }.freeze
13
13
  freeze
14
14
  end
15
15
 
@@ -21,10 +21,10 @@ module Plumb
21
21
 
22
22
  def call(result)
23
23
  return result.invalid(errors: 'must be an Array') unless result.value.is_a?(::Array)
24
- return result.invalid(errors: 'must have the same size') unless result.value.size == @types.size
24
+ return result.invalid(errors: 'must have the same size') unless result.value.size == @children.size
25
25
 
26
26
  errors = {}
27
- values = @types.map.with_index do |type, idx|
27
+ values = @children.map.with_index do |type, idx|
28
28
  val = result.value[idx]
29
29
  r = type.resolve(val)
30
30
  errors[idx] = ["expected #{type.inspect}, got #{val.inspect}", r.errors].flatten unless r.valid?
@@ -39,7 +39,7 @@ module Plumb
39
39
  private
40
40
 
41
41
  def _inspect
42
- "Tuple[#{@types.map(&:inspect).join(', ')}]"
42
+ "Tuple[#{@children.map(&:inspect).join(', ')}]"
43
43
  end
44
44
  end
45
45
  end
@@ -7,7 +7,7 @@ module Plumb
7
7
  case obj
8
8
  when Module
9
9
  obj.extend TypeRegistry
10
- when Steppable
10
+ when Composable
11
11
  anc = [name, const_name].join('::')
12
12
  obj.freeze.name.set(anc)
13
13
  end
@@ -17,16 +17,19 @@ module Plumb
17
17
  host.extend TypeRegistry
18
18
  constants(false).each do |const_name|
19
19
  const = const_get(const_name)
20
+
20
21
  anc = [host.name, const_name].join('::')
21
22
  case const
22
23
  when Module
24
+ next if const.is_a?(Class)
25
+
23
26
  child_mod = Module.new
24
27
  child_mod.define_singleton_method(:name) do
25
28
  anc
26
29
  end
27
30
  child_mod.send(:include, const)
28
31
  host.const_set(const_name, child_mod)
29
- when Steppable
32
+ when Composable
30
33
  type = const.dup
31
34
  type.freeze.name.set(anc)
32
35
  host.const_set(const_name, type)
data/lib/plumb/types.rb CHANGED
@@ -101,7 +101,7 @@ module Plumb
101
101
  Types::Static[value]
102
102
  end
103
103
 
104
- type | (Types::Undefined >> val_type)
104
+ (Types::Undefined >> val_type) | type
105
105
  end
106
106
 
107
107
  # Split a string into an array. Default separator is /\s*,\s*/
@@ -146,6 +146,11 @@ module Plumb
146
146
  Hash = HashClass.new
147
147
  Interface = InterfaceClass.new
148
148
 
149
+ class Data
150
+ extend Composable
151
+ include Plumb::Attributes
152
+ end
153
+
149
154
  module Lax
150
155
  NUMBER_EXPR = /^\d{1,3}(?:,\d{3})*(?:\.\d+)?$/
151
156
 
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'plumb/steppable'
3
+ require 'plumb/composable'
4
4
 
5
5
  module Plumb
6
6
  class ValueClass
7
- include Steppable
7
+ include Composable
8
8
 
9
- attr_reader :value
9
+ attr_reader :children
10
10
 
11
11
  def initialize(value = Undefined)
12
12
  @value = value
13
+ @children = [value].freeze
13
14
  freeze
14
15
  end
15
16
 
data/lib/plumb/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Plumb
4
- VERSION = '0.0.3'
4
+ VERSION = '0.0.4'
5
5
  end
@@ -39,5 +39,11 @@ module Plumb
39
39
  def on_missing_handler(node, _props, method_name)
40
40
  raise "No handler for #{node.inspect} with :#{method_name}"
41
41
  end
42
+
43
+ def visit_children(node, props = BLANK_HASH)
44
+ node.children.reduce(props) do |acc, child|
45
+ visit(child, acc)
46
+ end
47
+ end
42
48
  end
43
49
  end
data/lib/plumb.rb CHANGED
@@ -10,7 +10,7 @@ module Plumb
10
10
  end
11
11
 
12
12
  # Register a policy with the given name and block.
13
- # Optionally define a method on the Steppable method to call the policy.
13
+ # Optionally define a method on the Composable method to call the policy.
14
14
  # Example:
15
15
  # Plumb.policy(:multiply_by, for_type: Integer, helper: true) do |step, factor, &block|
16
16
  # step.transform(Integer) { |number| number * factor }
@@ -39,11 +39,11 @@ module Plumb
39
39
 
40
40
  return self unless helper
41
41
 
42
- if Steppable.instance_methods.include?(name)
43
- raise Policies::MethodAlreadyDefinedError, "Method #{name} is already defined on Steppable"
42
+ if Composable.instance_methods.include?(name)
43
+ raise Policies::MethodAlreadyDefinedError, "Method #{name} is already defined on Composable"
44
44
  end
45
45
 
46
- Steppable.define_method(name) do |arg = Undefined, &bl|
46
+ Composable.define_method(name) do |arg = Undefined, &bl|
47
47
  if arg == Undefined
48
48
  policy(name, &bl)
49
49
  else
@@ -53,11 +53,15 @@ module Plumb
53
53
 
54
54
  self
55
55
  end
56
+
57
+ def self.decorate(type, &block)
58
+ Decorator.call(type, &block)
59
+ end
56
60
  end
57
61
 
58
62
  require 'plumb/result'
59
63
  require 'plumb/type_registry'
60
- require 'plumb/steppable'
64
+ require 'plumb/composable'
61
65
  require 'plumb/any_class'
62
66
  require 'plumb/step'
63
67
  require 'plumb/and'
@@ -72,6 +76,8 @@ require 'plumb/array_class'
72
76
  require 'plumb/stream_class'
73
77
  require 'plumb/hash_class'
74
78
  require 'plumb/interface_class'
79
+ require 'plumb/attributes'
75
80
  require 'plumb/types'
76
81
  require 'plumb/json_schema_visitor'
77
82
  require 'plumb/schema'
83
+ require 'plumb/decorator'
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.3
4
+ version: 0.0.4
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-07-18 00:00:00.000000000 Z
11
+ date: 2024-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal
@@ -54,13 +54,17 @@ files:
54
54
  - examples/concurrent_downloads.rb
55
55
  - examples/csv_stream.rb
56
56
  - examples/env_config.rb
57
+ - examples/event_registry.rb
57
58
  - examples/programmers.csv
58
59
  - examples/weekdays.rb
59
60
  - lib/plumb.rb
60
61
  - lib/plumb/and.rb
61
62
  - lib/plumb/any_class.rb
62
63
  - lib/plumb/array_class.rb
64
+ - lib/plumb/attributes.rb
63
65
  - lib/plumb/build.rb
66
+ - lib/plumb/composable.rb
67
+ - lib/plumb/decorator.rb
64
68
  - lib/plumb/deferred.rb
65
69
  - lib/plumb/hash_class.rb
66
70
  - lib/plumb/hash_map.rb
@@ -79,7 +83,6 @@ files:
79
83
  - lib/plumb/schema.rb
80
84
  - lib/plumb/static_class.rb
81
85
  - lib/plumb/step.rb
82
- - lib/plumb/steppable.rb
83
86
  - lib/plumb/stream_class.rb
84
87
  - lib/plumb/tagged_hash.rb
85
88
  - lib/plumb/transform.rb