Class: CircuitBreaker::Rules::DSL
- Inherits:
-
Object
- Object
- CircuitBreaker::Rules::DSL
- Defined in:
- lib/circuit_breaker/rules.rb
Class Method Summary collapse
Instance Method Summary collapse
- #all(*rules) ⇒ Object
- #any(*rules) ⇒ Object
- #chain(token) ⇒ Object
- #context ⇒ Object
- #custom(field = nil, message = nil, &block) ⇒ Object
- #depends_on(field, other_field, &block) ⇒ Object
- #description(name) ⇒ Object
- #different_values(field1, field2) ⇒ Object
- #evaluate(rule_name, token) ⇒ Object
-
#initialize ⇒ DSL
constructor
A new instance of DSL.
- #json_schema(field, schema) ⇒ Object
- #length(field, options = {}) ⇒ Object
- #matches(field, pattern, message = nil) ⇒ Object
- #none(*rules) ⇒ Object
- #numericality(field, options = {}) ⇒ Object
- #one_of(field, values) ⇒ Object
-
#presence(field) ⇒ Object
Helper methods for common rule conditions.
- #rule(name, desc = nil, &block) ⇒ Object
- #rules ⇒ Object
- #with_context(context) ⇒ Object
Constructor Details
#initialize ⇒ DSL
Returns a new instance of DSL.
40 41 42 43 44 |
# File 'lib/circuit_breaker/rules.rb', line 40 def initialize @rules = {} @descriptions = {} @context = nil end |
Class Method Details
.define(&block) ⇒ Object
46 47 48 49 50 |
# File 'lib/circuit_breaker/rules.rb', line 46 def self.define(&block) dsl = new dsl.instance_eval(&block) if block_given? dsl end |
Instance Method Details
#all(*rules) ⇒ Object
176 177 178 179 180 181 |
# File 'lib/circuit_breaker/rules.rb', line 176 def all(*rules) ->(token) { results = rules.map { |rule| rule.call(token) } results.reduce(RuleResult.new(true)) { |acc, result| acc & (result.is_a?(RuleResult) ? result : RuleResult.new(result)) } } end |
#any(*rules) ⇒ Object
183 184 185 186 187 188 |
# File 'lib/circuit_breaker/rules.rb', line 183 def any(*rules) ->(token) { results = rules.map { |rule| rule.call(token) } results.reduce(RuleResult.new(false)) { |acc, result| acc | (result.is_a?(RuleResult) ? result : RuleResult.new(result)) } } end |
#chain(token) ⇒ Object
76 77 78 |
# File 'lib/circuit_breaker/rules.rb', line 76 def chain(token) RuleChain.new(self, token) end |
#context ⇒ Object
96 97 98 |
# File 'lib/circuit_breaker/rules.rb', line 96 def context @context end |
#custom(field = nil, message = nil, &block) ⇒ Object
198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/circuit_breaker/rules.rb', line 198 def custom(field = nil, = nil, &block) if field ->(token) { result = block.call(token.send(field)) result.is_a?(RuleResult) ? result : RuleResult.new(result, ? [] : []) } else ->(token) { result = block.call(token) result.is_a?(RuleResult) ? result : RuleResult.new(result, ? [] : []) } end end |
#depends_on(field, other_field, &block) ⇒ Object
212 213 214 215 216 217 218 219 220 |
# File 'lib/circuit_breaker/rules.rb', line 212 def depends_on(field, other_field, &block) ->(token) { other_value = token.send(other_field) return RuleResult.new(true) if other_value.nil? result = block.call(token.send(field), other_value) result.is_a?(RuleResult) ? result : RuleResult.new(result, ["#{field} dependency on #{other_field} failed"]) } end |
#description(name) ⇒ Object
84 85 86 |
# File 'lib/circuit_breaker/rules.rb', line 84 def description(name) @descriptions[name] end |
#different_values(field1, field2) ⇒ Object
109 110 111 112 113 114 115 116 117 |
# File 'lib/circuit_breaker/rules.rb', line 109 def different_values(field1, field2) ->(token) { val1, val2 = token.send(field1), token.send(field2) result = presence(field1).call(token).valid? && presence(field2).call(token).valid? && val1 != val2 RuleResult.new(result, result ? [] : ["#{field1} must be different from #{field2}"]) } end |
#evaluate(rule_name, token) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/circuit_breaker/rules.rb', line 57 def evaluate(rule_name, token) raise RuleError, "Unknown rule: #{rule_name}" unless @rules.key?(rule_name) puts "Evaluating rule '#{rule_name}' for token #{token.id}" puts " Context: #{@context.inspect}" result = @rules[rule_name].call(token) puts " Result: #{result.inspect}" case result when RuleResult result.valid? when true, false result else !!result end rescue StandardError => e raise RuleError, "Rule '#{rule_name}' failed for token #{token.id}: #{e.message}" end |
#json_schema(field, schema) ⇒ Object
148 149 150 151 152 153 154 155 156 157 |
# File 'lib/circuit_breaker/rules.rb', line 148 def json_schema(field, schema) ->(token) { begin JSON::Validator.validate!(schema, token.send(field)) RuleResult.new(true) rescue JSON::Schema::ValidationError => e RuleResult.new(false, [e.]) end } end |
#length(field, options = {}) ⇒ Object
133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/circuit_breaker/rules.rb', line 133 def length(field, = {}) ->(token) { val = token.send(field).to_s min_valid = ![:min] || val.length >= [:min] max_valid = ![:max] || val.length <= [:max] result = min_valid && max_valid errors = [] errors << "#{field} must be at least #{options[:min]} characters" if !min_valid errors << "#{field} must be at most #{options[:max]} characters" if !max_valid RuleResult.new(result, errors) } end |
#matches(field, pattern, message = nil) ⇒ Object
119 120 121 122 123 124 |
# File 'lib/circuit_breaker/rules.rb', line 119 def matches(field, pattern, = nil) ->(token) { result = token.send(field).to_s.match?(pattern) RuleResult.new(result, result ? [] : [ || "#{field} does not match pattern"]) } end |
#none(*rules) ⇒ Object
190 191 192 193 194 195 196 |
# File 'lib/circuit_breaker/rules.rb', line 190 def none(*rules) ->(token) { results = rules.map { |rule| rule.call(token) } result = results.none? { |r| r.is_a?(RuleResult) ? r.valid? : r } RuleResult.new(result, result ? [] : ["none of the rules should pass"]) } end |
#numericality(field, options = {}) ⇒ Object
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/circuit_breaker/rules.rb', line 159 def numericality(field, = {}) ->(token) { val = token.send(field) return RuleResult.new(false, ["#{field} must be a number"]) unless val.is_a?(Numeric) errors = [] errors << "must be greater than #{options[:greater_than]}" if [:greater_than] && !(val > [:greater_than]) errors << "must be greater than or equal to #{options[:greater_than_or_equal_to]}" if [:greater_than_or_equal_to] && !(val >= [:greater_than_or_equal_to]) errors << "must be less than #{options[:less_than]}" if [:less_than] && !(val < [:less_than]) errors << "must be less than or equal to #{options[:less_than_or_equal_to]}" if [:less_than_or_equal_to] && !(val <= [:less_than_or_equal_to]) errors << "must be equal to #{options[:equal_to]}" if [:equal_to] && val != [:equal_to] errors << "must not be equal to #{options[:other_than]}" if [:other_than] && val == [:other_than] RuleResult.new(errors.empty?, errors.map { |e| "#{field} #{e}" }) } end |
#one_of(field, values) ⇒ Object
126 127 128 129 130 131 |
# File 'lib/circuit_breaker/rules.rb', line 126 def one_of(field, values) ->(token) { result = values.include?(token.send(field)) RuleResult.new(result, result ? [] : ["#{field} must be one of: #{values.join(', ')}"]) } end |
#presence(field) ⇒ Object
Helper methods for common rule conditions
101 102 103 104 105 106 107 |
# File 'lib/circuit_breaker/rules.rb', line 101 def presence(field) ->(token) { val = token.send(field) result = !val.nil? && (!val.respond_to?(:empty?) || !val.empty?) RuleResult.new(result, result ? [] : ["#{field} must be present"]) } end |
#rule(name, desc = nil, &block) ⇒ Object
52 53 54 55 |
# File 'lib/circuit_breaker/rules.rb', line 52 def rule(name, desc = nil, &block) @rules[name] = block @descriptions[name] = desc if desc end |
#rules ⇒ Object
80 81 82 |
# File 'lib/circuit_breaker/rules.rb', line 80 def rules @rules.keys end |
#with_context(context) ⇒ Object
88 89 90 91 92 93 94 |
# File 'lib/circuit_breaker/rules.rb', line 88 def with_context(context) old_context = @context @context = context yield ensure @context = old_context end |