Skip to content

Commit

Permalink
Return Hash with integer keys as is instead of transforming it into a…
Browse files Browse the repository at this point in the history
…rray (#15)
  • Loading branch information
ahoshaiyan committed Jan 17, 2024
1 parent 3cee772 commit d246190
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 49 deletions.
1 change: 0 additions & 1 deletion lib/mini_defender.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

# Extensions to Ruby Core
require_relative 'mini_defender/extensions/enumerable'
require_relative 'mini_defender/extensions/hash'

module MiniDefender
end
Expand Down
39 changes: 0 additions & 39 deletions lib/mini_defender/extensions/hash.rb

This file was deleted.

15 changes: 14 additions & 1 deletion lib/mini_defender/rules_expander.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,27 @@ def expand(rules, flat_data)
end

k_pattern = Regexp.compile('\A' + rule_key.gsub(/\*/, '\d+') + '\Z')
k_pattern_result = {}

flat_data.each do |value_key, _|
next unless k_pattern.match?(value_key)
result[value_key] = rule_set
k_pattern_result[value_key] = rule_set
end

if k_pattern_result.empty?
k_pattern_result[k_pattern.source.gsub(/\\[AZ]/, '').gsub('\d+', '0')] = rule_set
end

result.merge!(k_pattern_result)
end

result
end

def array_patterns(rules)
rules
.filter { |key, _| key.include?('*') }
.map { |key, _| Regexp.compile('\A' + key.gsub(/\*/, '\d+') + '\Z') }
end
end
end
69 changes: 62 additions & 7 deletions lib/mini_defender/validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ def initialize(rules, data)
@coerced = {}
@expander = RulesExpander.new
@factory = RulesFactory.new
@array_patterns = @expander.array_patterns(rules)
end

def validate
return unless @errors.nil?
unless @errors.nil?
return
end

@errors = {}

Expand Down Expand Up @@ -77,15 +80,15 @@ def validate
end
end

@validated = @validated.expand
@coerced = @coerced.expand

@errors.reject! { |_, v| v.empty? }
end

def validate!
validate if @errors.nil?
raise ValidationError.new('Data validation failed', @errors) unless @errors.empty?

unless @errors.empty?
raise ValidationError.new('Data validation failed', @errors)
end
end

def passes?
Expand All @@ -99,12 +102,12 @@ def fails?

def validated
validate! if @errors.nil?
@validated
@validated_compacted ||= compact_expanded(@validated)
end

def coerced
validate! if @errors.nil?
@coerced
@coerced_compacted = compact_expanded(@coerced)
end

# @return [Hash]
Expand Down Expand Up @@ -133,5 +136,57 @@ def leveled_search_pattern(key, level = 1)

Regexp.compile("\\A#{search_key.reverse.join('\.')}\\z")
end

def compact_expanded(hash)
expanded = {}

hash.each do |k, v|
keys = k.split('.')
node = expanded

while keys.length > 1
next_key = keys.shift
next_node = (node[next_key] ||= {})

if next_node.is_a?(Array)
node[next_key] = next_node = next_node.each_with_index.to_h do |value, index|
[index.to_s, value]
end
end

node = next_node
end

node[keys.shift] = v
end

compact_keys(expanded)
end

def compact_keys(hash, current_key = '')
current_key_suffixed = if current_key == ''
''
else
"#{current_key}."
end

result = hash.to_h do |k, v|
[k, v.is_a?(Hash) ? compact_keys(v, current_key_suffixed + k) : v]
end

if result.empty?
return result
end

unless @array_patterns.any? { |p| p.match?("#{current_key_suffixed}#{result.keys.first}") }
return result
end

if result.all? { |k, _v| k.match?(/\A\d+\z/) }
return result.values
end

result
end
end
end
2 changes: 1 addition & 1 deletion lib/mini_defender/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module MiniDefender
VERSION = "0.5.0"
VERSION = "0.5.1"
end
1 change: 1 addition & 0 deletions test/fixtures/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
large-result.json
40 changes: 40 additions & 0 deletions test/rules/hash_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,44 @@ def test_hash_should_success_when_integer_value_type_specified_and_integer_provi

assert validator.passes?
end

def test_hash_must_return_all_elements_when_all_mode_is_used
validator = MiniDefender::Validator.new(
{
'metadata' => 'required|hash:all,string,integer'
},
{
'metadata' => {
'foo' => 1,
'zee' => 2
}
}
)

assert validator.coerced['metadata'].is_a?(Hash)
assert_equal 2, validator.coerced['metadata'].length

assert_equal 1, validator.coerced['metadata']['foo']
assert_equal 2, validator.coerced['metadata']['zee']
end

def test_hash_must_return_all_elements_when_all_mode_is_used_2
validator = MiniDefender::Validator.new(
{
'metadata' => 'required|hash:all,string,string'
},
{
'metadata' => {
'1' => 'foo',
'2' => 'bar'
}
}
)

assert validator.coerced['metadata'].is_a?(Hash)
assert_equal 2, validator.coerced['metadata'].length

assert_equal 'foo', validator.coerced['metadata']['1']
assert_equal 'bar', validator.coerced['metadata']['2']
end
end

0 comments on commit d246190

Please sign in to comment.