plumb 0.0.2 → 0.0.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 +287 -119
- data/examples/env_config.rb +122 -0
- data/examples/weekdays.rb +1 -1
- data/lib/plumb/hash_class.rb +1 -3
- data/lib/plumb/json_schema_visitor.rb +49 -6
- data/lib/plumb/match_class.rb +3 -4
- data/lib/plumb/metadata_visitor.rb +10 -1
- data/lib/plumb/policies.rb +81 -0
- data/lib/plumb/policy.rb +31 -0
- data/lib/plumb/schema.rb +2 -2
- data/lib/plumb/steppable.rb +24 -39
- data/lib/plumb/types.rb +114 -23
- data/lib/plumb/version.rb +1 -1
- data/lib/plumb/visitor_handlers.rb +6 -1
- data/lib/plumb.rb +52 -1
- metadata +8 -6
- data/lib/plumb/rules.rb +0 -102
data/lib/plumb/rules.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'plumb/steppable'
|
4
|
-
|
5
|
-
module Plumb
|
6
|
-
class Rules
|
7
|
-
UnsupportedRuleError = Class.new(StandardError)
|
8
|
-
UndefinedRuleError = Class.new(KeyError)
|
9
|
-
|
10
|
-
class Registry
|
11
|
-
RuleDef = Data.define(:name, :error_tpl, :callable, :expects) do
|
12
|
-
def supports?(type)
|
13
|
-
types = [type].flatten # may be an array of types for OR logic
|
14
|
-
case expects
|
15
|
-
when Symbol
|
16
|
-
types.all? { |type| type && type.public_instance_methods.include?(expects) }
|
17
|
-
when Class then types.all? { |type| type <= expects }
|
18
|
-
when Object then true
|
19
|
-
else raise "Unexpected expects: #{expects}"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
Rule = Data.define(:rule_def, :arg_value, :error_str) do
|
25
|
-
def self.build(rule_def, arg_value)
|
26
|
-
error_str = format(rule_def.error_tpl, value: arg_value)
|
27
|
-
new(rule_def, arg_value, error_str)
|
28
|
-
end
|
29
|
-
|
30
|
-
def node_name = :"rule_#{rule_def.name}"
|
31
|
-
def name = rule_def.name
|
32
|
-
|
33
|
-
def error_for(result)
|
34
|
-
return nil if rule_def.callable.call(result, arg_value)
|
35
|
-
|
36
|
-
error_str
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def initialize
|
41
|
-
@definitions = Hash.new { |h, k| h[k] = Set.new }
|
42
|
-
end
|
43
|
-
|
44
|
-
def define(name, error_tpl, callable = nil, expects: Object, &block)
|
45
|
-
name = name.to_sym
|
46
|
-
callable ||= block
|
47
|
-
@definitions[name] << RuleDef.new(name:, error_tpl:, callable:, expects:)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Ex. size: 3, match: /foo/
|
51
|
-
def resolve(rule_specs, for_type)
|
52
|
-
rule_specs.map do |(name, arg_value)|
|
53
|
-
rule_defs = @definitions.fetch(name.to_sym) { raise UndefinedRuleError, "no rule defined with :#{name}" }
|
54
|
-
rule_def = rule_defs.find { |rd| rd.supports?(for_type) }
|
55
|
-
unless rule_def
|
56
|
-
raise UnsupportedRuleError, "No :#{name} rule for type #{for_type.inspect}" unless for_type.is_a?(Array)
|
57
|
-
|
58
|
-
raise UnsupportedRuleError,
|
59
|
-
"Can't apply :#{name} rule for types #{for_type}. All types must support the same rule implementation"
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
Rule.build(rule_def, arg_value)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
include Steppable
|
69
|
-
|
70
|
-
def self.registry
|
71
|
-
@registry ||= Registry.new
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.define(...)
|
75
|
-
registry.define(...)
|
76
|
-
end
|
77
|
-
|
78
|
-
# Ex. new(size: 3, match: /foo/)
|
79
|
-
attr_reader :rules
|
80
|
-
|
81
|
-
def initialize(rule_specs, for_type)
|
82
|
-
@rules = self.class.registry.resolve(rule_specs, for_type).freeze
|
83
|
-
freeze
|
84
|
-
end
|
85
|
-
|
86
|
-
def call(result)
|
87
|
-
errors = []
|
88
|
-
err = nil
|
89
|
-
@rules.each do |rule|
|
90
|
-
err = rule.error_for(result)
|
91
|
-
errors << err if err
|
92
|
-
end
|
93
|
-
return result unless errors.any?
|
94
|
-
|
95
|
-
result.invalid(errors: errors.join(', '))
|
96
|
-
end
|
97
|
-
|
98
|
-
private def _inspect
|
99
|
-
+'Rules(' << @rules.map { |r| [r.name, r.arg_value].join(': ') }.join(', ') << +')'
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|