mutations 0.5.2 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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