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.
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