mutations 0.5.2 → 0.5.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.
@@ -7,7 +7,7 @@ module Mutations
7
7
  end
8
8
 
9
9
  def to_s
10
- "Mutations::ValidationException: #{self.errors.message_list.join('; ')}"
10
+ "#{self.errors.message_list.join('; ')}"
11
11
  end
12
12
  end
13
13
  end
@@ -2,17 +2,30 @@ module Mutations
2
2
  class HashFilter < InputFilter
3
3
  @default_options = {
4
4
  nils: false, # true allows an explicit nil to be valid. Overrides any other options
5
+ key_class: nil, # Can be a string or Class. If present, all keys must be of this class. Note that this field can't be set if a block is passed.
6
+ value_class: nil # Can be a string or Class. If present, all values must be of this class. Note that this field can't be set if a block is passed.
5
7
  }
6
8
 
9
+ attr_accessor :general_inputs # defaults to false
7
10
  attr_accessor :optional_inputs
8
11
  attr_accessor :required_inputs
9
12
 
13
+ # There's two types of Hash filters:
14
+ # - those that accept specific inputs (eg, the hash needs to have an email key with a string value matching %r{...})
15
+ # - those that accept general hashes (eg, the hash needs to have String keys and values, but can have any such k/v's)
10
16
  def initialize(opts = {}, &block)
11
17
  super(opts)
12
18
 
13
- @optional_inputs = {}
14
- @required_inputs = {}
15
- @current_inputs = @required_inputs
19
+ raise ArgumentError, "Can't use key_class/value_class with a block." if block_given? && (options[:key_class] || options[:value_class])
20
+
21
+ if options[:key_class] || options[:value_class]
22
+ @general_inputs = true
23
+ else
24
+ @general_inputs = false
25
+ @optional_inputs = {}
26
+ @required_inputs = {}
27
+ @current_inputs = @required_inputs
28
+ end
16
29
 
17
30
  if block_given?
18
31
  instance_eval &block
@@ -27,16 +40,21 @@ module Mutations
27
40
  @required_inputs.each_pair do |k, v|
28
41
  dupped.required_inputs[k] = v
29
42
  end
43
+ dupped.general_inputs = @general_inputs
30
44
  dupped
31
45
  end
32
46
 
33
47
  def required(&block)
48
+ raise ArgumentError, "Can't use specific filters if you're filtering by key." if general_inputs
49
+
34
50
  # TODO: raise if nesting is wrong
35
51
  @current_inputs = @required_inputs
36
52
  instance_eval &block
37
53
  end
38
54
 
39
55
  def optional(&block)
56
+ raise ArgumentError, "Can't use specific filters if you're filtering by key." if general_inputs
57
+
40
58
  # TODO: raise if nesting is wrong
41
59
  @current_inputs = @optional_inputs
42
60
  instance_eval &block
@@ -64,6 +82,9 @@ module Mutations
64
82
  end
65
83
 
66
84
  def hash(name, options = {}, &block)
85
+ unless block_given?
86
+ options.reverse_merge!(key_class: String, value_class: String)
87
+ end
67
88
  @current_inputs[name.to_sym] = HashFilter.new(options, &block)
68
89
  end
69
90
 
@@ -97,26 +118,46 @@ module Mutations
97
118
  errors = ErrorHash.new
98
119
  filtered_data = HashWithIndifferentAccess.new
99
120
 
100
- [[@required_inputs, true], [@optional_inputs, false]].each do |(inputs, is_required)|
101
- inputs.each_pair do |key, filterer|
102
- data_element = data[key]
103
- default_used = false
104
- if !data.has_key?(key) && filterer.has_default?
105
- data_element = filterer.default
106
- default_used = true
107
- end
108
-
109
- if data.has_key?(key) || default_used
110
- sub_data, sub_error = filterer.filter(data_element)
111
-
112
- if sub_error.nil?
113
- filtered_data[key] = sub_data
121
+ if @general_inputs
122
+ key_class_const = options[:key_class] || raise
123
+ key_class_const = key_class_const.constantize if key_class_const.is_a?(String)
124
+
125
+ value_class_const = options[:value_class] || raise
126
+ value_class_const = value_class_const.constantize if value_class_const.is_a?(String)
127
+ data.each_pair do |k, v|
128
+ if k.is_a?(key_class_const) && v.is_a?(value_class_const)
129
+ filtered_data[k] = v
130
+ else
131
+ k_string = k.to_s
132
+ if !k.is_a?(key_class_const)
133
+ errors[k_string] = ErrorAtom.new(k_string, :key_class)
114
134
  else
115
- sub_error = ErrorAtom.new(key, sub_error) if sub_error.is_a?(Symbol)
116
- errors[key] = sub_error
135
+ errors[k_string] = ErrorAtom.new(k_string, :value_class)
136
+ end
137
+ end
138
+ end
139
+ else
140
+ [[@required_inputs, true], [@optional_inputs, false]].each do |(inputs, is_required)|
141
+ inputs.each_pair do |key, filterer|
142
+ data_element = data[key]
143
+ default_used = false
144
+ if !data.has_key?(key) && filterer.has_default?
145
+ data_element = filterer.default
146
+ default_used = true
147
+ end
148
+
149
+ if data.has_key?(key) || default_used
150
+ sub_data, sub_error = filterer.filter(data_element)
151
+
152
+ if sub_error.nil?
153
+ filtered_data[key] = sub_data
154
+ else
155
+ sub_error = ErrorAtom.new(key, sub_error) if sub_error.is_a?(Symbol)
156
+ errors[key] = sub_error
157
+ end
158
+ elsif is_required
159
+ errors[key] = ErrorAtom.new(key, :required)
117
160
  end
118
- elsif is_required
119
- errors[key] = ErrorAtom.new(key, :required)
120
161
  end
121
162
  end
122
163
  end
@@ -1,3 +1,3 @@
1
1
  module Mutations
2
- VERSION = "0.5.2"
2
+ VERSION = "0.5.3"
3
3
  end
@@ -0,0 +1,41 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe "Mutations::HashFilter" do
4
+
5
+ it "allows valid hashes" do
6
+ hf = Mutations::HashFilter.new do
7
+ string :foo
8
+ end
9
+ filtered, errors = hf.filter(foo: "bar")
10
+ assert_equal ({"foo" => "bar"}), filtered
11
+ assert_equal nil, errors
12
+ end
13
+
14
+ it 'disallows non-hashes' do
15
+ hf = Mutations::HashFilter.new do
16
+ string :foo
17
+ end
18
+ filtered, errors = hf.filter("bar")
19
+ assert_equal :hash, errors
20
+ end
21
+
22
+ it 'allows general hashes' do
23
+ hf = Mutations::HashFilter.new(key_class: String, value_class: Symbol)
24
+ filtered, errors = hf.filter("f1" => :v1, "f2" => :v2)
25
+ assert_equal ({"f1" => :v1, "f2" => :v2}), filtered
26
+ assert_equal nil, errors
27
+ end
28
+
29
+ it 'doesnt allows invalid general hashes (wrong value type)' do
30
+ hf = Mutations::HashFilter.new(key_class: String, value_class: Symbol)
31
+ filtered, errors = hf.filter("f1" => "v1", "f2" => :v2)
32
+ assert_equal ({"f1" => :value_class}), errors.symbolic
33
+ end
34
+
35
+ it 'doesnt allows invalid general hashes (wrong key type)' do
36
+ hf = Mutations::HashFilter.new(key_class: Fixnum, value_class: Symbol)
37
+ filtered, errors = hf.filter("f1" => :v1)
38
+ assert_equal ({"f1" => :key_class}), errors.symbolic
39
+ end
40
+
41
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'minitest/unit'
2
- require 'minitest/pride'
2
+ #require 'minitest/pride'
3
3
  require 'minitest/autorun'
4
4
  require 'pp'
5
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.5.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-29 00:00:00.000000000 Z
12
+ date: 2013-01-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -92,6 +92,7 @@ files:
92
92
  - spec/command_spec.rb
93
93
  - spec/default_spec.rb
94
94
  - spec/errors_spec.rb
95
+ - spec/hash_filter_spec.rb
95
96
  - spec/inheritance_spec.rb
96
97
  - spec/integer_filter_spec.rb
97
98
  - spec/model_filter_spec.rb