mini_defender 0.5.0 → 0.5.2
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/lib/mini_defender/rule.rb +7 -0
- data/lib/mini_defender/rules/array.rb +4 -0
- data/lib/mini_defender/rules/hash.rb +4 -0
- data/lib/mini_defender/rules_expander.rb +14 -1
- data/lib/mini_defender/rules_factory.rb +10 -3
- data/lib/mini_defender/validator.rb +63 -8
- data/lib/mini_defender/version.rb +1 -1
- data/lib/mini_defender.rb +0 -1
- metadata +2 -3
- data/lib/mini_defender/extensions/hash.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7eb4878351ebf49bb42e33a10f8fefd34745b4067bdf40b50180792d2883819
|
4
|
+
data.tar.gz: 93ec54964db744a7f2f03a7fc23bf96b6458637d94dbfb00c4307a0e5e598964
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a04dc7d2a819a0d3f8e443342900bd29db0c7e9b730128ff7d8f266f7853e52079166903997f660ef87c26c3965dd689c229bd5e533a0ff824debd3548f65417
|
7
|
+
data.tar.gz: cd0109845a3f6f2ddc22c23448856124384554b6e3bbc75f1d952773c589797a421c1f7e04da15ed3461713f65ee436a8c102776ff0377dbbdeecc96da746196
|
data/lib/mini_defender/rule.rb
CHANGED
@@ -16,6 +16,13 @@ class MiniDefender::Rule
|
|
16
16
|
true
|
17
17
|
end
|
18
18
|
|
19
|
+
# Priority is used to sort rules in a rule set to allow rules to validate data
|
20
|
+
# before rules that will radically change data
|
21
|
+
# @return [Integer]
|
22
|
+
def priority
|
23
|
+
100
|
24
|
+
end
|
25
|
+
|
19
26
|
# @param [MiniDefender::Validator] validator
|
20
27
|
# @return [Boolean]
|
21
28
|
def implicit?(validator)
|
@@ -15,14 +15,27 @@ module MiniDefender
|
|
15
15
|
end
|
16
16
|
|
17
17
|
k_pattern = Regexp.compile('\A' + rule_key.gsub(/\*/, '\d+') + '\Z')
|
18
|
+
k_pattern_result = {}
|
18
19
|
|
19
20
|
flat_data.each do |value_key, _|
|
20
21
|
next unless k_pattern.match?(value_key)
|
21
|
-
|
22
|
+
k_pattern_result[value_key] = rule_set
|
22
23
|
end
|
24
|
+
|
25
|
+
if k_pattern_result.empty?
|
26
|
+
k_pattern_result[k_pattern.source.gsub(/\\[AZ]/, '').gsub('\d+', '0')] = rule_set
|
27
|
+
end
|
28
|
+
|
29
|
+
result.merge!(k_pattern_result)
|
23
30
|
end
|
24
31
|
|
25
32
|
result
|
26
33
|
end
|
34
|
+
|
35
|
+
def array_patterns(rules)
|
36
|
+
rules
|
37
|
+
.filter { |key, _| key.include?('*') }
|
38
|
+
.map { |key, _| Regexp.compile('\A' + key.gsub(/\*/, '\d+') + '\Z') }
|
39
|
+
end
|
27
40
|
end
|
28
41
|
end
|
@@ -11,16 +11,23 @@ module MiniDefender
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def init_set(rule_set)
|
14
|
-
|
15
|
-
|
14
|
+
if rule_set.is_a?(String)
|
15
|
+
rule_set = rule_set.split('|')
|
16
|
+
end
|
17
|
+
|
18
|
+
unless rule_set.is_a?(Array)
|
19
|
+
raise ArgumentError, 'Rule set must be a string or an array'
|
20
|
+
end
|
16
21
|
|
17
|
-
rule_set.map do |rule|
|
22
|
+
rule_set = rule_set.map do |rule|
|
18
23
|
unless rule.is_a?(String) || rule.is_a?(Rule)
|
19
24
|
raise ArgumentError, 'Rule must be a string or an instance of MiniDefender::Rule'
|
20
25
|
end
|
21
26
|
|
22
27
|
rule.is_a?(String) ? init_rule(rule) : rule
|
23
28
|
end
|
29
|
+
|
30
|
+
rule_set.sort_by! { |r| r.priority }
|
24
31
|
end
|
25
32
|
|
26
33
|
def init_rule(signature)
|
@@ -12,10 +12,13 @@ module MiniDefender
|
|
12
12
|
@coerced = {}
|
13
13
|
@expander = RulesExpander.new
|
14
14
|
@factory = RulesFactory.new
|
15
|
+
@array_patterns = @expander.array_patterns(rules)
|
15
16
|
end
|
16
17
|
|
17
18
|
def validate
|
18
|
-
|
19
|
+
unless @errors.nil?
|
20
|
+
return
|
21
|
+
end
|
19
22
|
|
20
23
|
@errors = {}
|
21
24
|
|
@@ -59,7 +62,7 @@ module MiniDefender
|
|
59
62
|
|
60
63
|
value_included &= !rule.excluded?(self)
|
61
64
|
|
62
|
-
if rule.passes?(k,
|
65
|
+
if rule.passes?(k, coerced, self)
|
63
66
|
coerced = rule.coerce(coerced)
|
64
67
|
force_coerce = rule.force_coerce?
|
65
68
|
else
|
@@ -77,15 +80,15 @@ module MiniDefender
|
|
77
80
|
end
|
78
81
|
end
|
79
82
|
|
80
|
-
@validated = @validated.expand
|
81
|
-
@coerced = @coerced.expand
|
82
|
-
|
83
83
|
@errors.reject! { |_, v| v.empty? }
|
84
84
|
end
|
85
85
|
|
86
86
|
def validate!
|
87
87
|
validate if @errors.nil?
|
88
|
-
|
88
|
+
|
89
|
+
unless @errors.empty?
|
90
|
+
raise ValidationError.new('Data validation failed', @errors)
|
91
|
+
end
|
89
92
|
end
|
90
93
|
|
91
94
|
def passes?
|
@@ -99,12 +102,12 @@ module MiniDefender
|
|
99
102
|
|
100
103
|
def validated
|
101
104
|
validate! if @errors.nil?
|
102
|
-
@validated
|
105
|
+
@validated_compacted ||= compact_expanded(@validated)
|
103
106
|
end
|
104
107
|
|
105
108
|
def coerced
|
106
109
|
validate! if @errors.nil?
|
107
|
-
@coerced
|
110
|
+
@coerced_compacted = compact_expanded(@coerced)
|
108
111
|
end
|
109
112
|
|
110
113
|
# @return [Hash]
|
@@ -133,5 +136,57 @@ module MiniDefender
|
|
133
136
|
|
134
137
|
Regexp.compile("\\A#{search_key.reverse.join('\.')}\\z")
|
135
138
|
end
|
139
|
+
|
140
|
+
def compact_expanded(hash)
|
141
|
+
expanded = {}
|
142
|
+
|
143
|
+
hash.each do |k, v|
|
144
|
+
keys = k.split('.')
|
145
|
+
node = expanded
|
146
|
+
|
147
|
+
while keys.length > 1
|
148
|
+
next_key = keys.shift
|
149
|
+
next_node = (node[next_key] ||= {})
|
150
|
+
|
151
|
+
if next_node.is_a?(Array)
|
152
|
+
node[next_key] = next_node = next_node.each_with_index.to_h do |value, index|
|
153
|
+
[index.to_s, value]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
node = next_node
|
158
|
+
end
|
159
|
+
|
160
|
+
node[keys.shift] = v
|
161
|
+
end
|
162
|
+
|
163
|
+
compact_keys(expanded)
|
164
|
+
end
|
165
|
+
|
166
|
+
def compact_keys(hash, current_key = '')
|
167
|
+
current_key_suffixed = if current_key == ''
|
168
|
+
''
|
169
|
+
else
|
170
|
+
"#{current_key}."
|
171
|
+
end
|
172
|
+
|
173
|
+
result = hash.to_h do |k, v|
|
174
|
+
[k, v.is_a?(Hash) ? compact_keys(v, current_key_suffixed + k) : v]
|
175
|
+
end
|
176
|
+
|
177
|
+
if result.empty?
|
178
|
+
return result
|
179
|
+
end
|
180
|
+
|
181
|
+
unless @array_patterns.any? { |p| p.match?("#{current_key_suffixed}#{result.keys.first}") }
|
182
|
+
return result
|
183
|
+
end
|
184
|
+
|
185
|
+
if result.all? { |k, _v| k.match?(/\A\d+\z/) }
|
186
|
+
return result.values
|
187
|
+
end
|
188
|
+
|
189
|
+
result
|
190
|
+
end
|
136
191
|
end
|
137
192
|
end
|
data/lib/mini_defender.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_defender
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ali Alhoshaiyan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -97,7 +97,6 @@ files:
|
|
97
97
|
- Rakefile
|
98
98
|
- lib/mini_defender.rb
|
99
99
|
- lib/mini_defender/extensions/enumerable.rb
|
100
|
-
- lib/mini_defender/extensions/hash.rb
|
101
100
|
- lib/mini_defender/handles_validation_errors.rb
|
102
101
|
- lib/mini_defender/rule.rb
|
103
102
|
- lib/mini_defender/rules.rb
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Hash
|
4
|
-
def expand
|
5
|
-
expanded = {}
|
6
|
-
|
7
|
-
each do |k, v|
|
8
|
-
keys = k.split('.')
|
9
|
-
node = expanded
|
10
|
-
|
11
|
-
while keys.length > 1
|
12
|
-
next_key = keys.shift
|
13
|
-
next_node = (node[next_key] ||= {})
|
14
|
-
|
15
|
-
if next_node.is_a?(Array)
|
16
|
-
node[next_key] = next_node = next_node.each_with_index.to_h { |value, index| [index.to_s, value] }
|
17
|
-
end
|
18
|
-
|
19
|
-
node = next_node
|
20
|
-
end
|
21
|
-
|
22
|
-
node[keys.shift] = v
|
23
|
-
end
|
24
|
-
|
25
|
-
expanded.compact_keys
|
26
|
-
end
|
27
|
-
|
28
|
-
def compact_keys
|
29
|
-
result = to_h do |k, v|
|
30
|
-
[k, v.is_a?(Hash) ? v.compact_keys : v]
|
31
|
-
end
|
32
|
-
|
33
|
-
if !result.empty? && result.all? { |k, _v| k.match?(/\A\d+\z/) }
|
34
|
-
result.values
|
35
|
-
else
|
36
|
-
result
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|