ratatouille 1.3.0 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## 1.3.2
2
+
3
+ ### Updates
4
+
5
+ * is\_empty and is\_not\_empty have been moved to generic ghost methods in the Ratifier object that also support other boolean methods.
6
+ * Say you have Object#foo?, you can use **is\_foo** and **is\_not\_foo** for validation against that boolean method
7
+ * **:is\_a** added as option to perform class validation prior to the core method logic for the following methods:
8
+ * HashMethod#given_key
9
+ * HashMethod#required_key
10
+
1
11
  ## 1.3.0 (API Change!)
2
12
 
3
13
  ### Updates
@@ -2,47 +2,6 @@ module Ratatouille
2
2
 
3
3
  # Module used to provide Array-specific validation methods
4
4
  module ArrayMethods
5
-
6
- # @param [Hash] options
7
- # @option options [Boolean] :unwrap_block (false)
8
- # Perform block validation only -- skip is_empty validation logic.
9
- # Useless unless block provided
10
- # @return [void]
11
- def is_empty(options={}, &block)
12
- unless options.fetch(:unwrap_block, false) == true
13
- # Wrapped Validation
14
- unless @ratifiable_object.empty?
15
- validation_error("not empty")
16
- return
17
- end
18
- end
19
-
20
- instance_eval(&block) if block_given?
21
- rescue Exception => e
22
- validation_error("#{e.message}")
23
- end#is_empty
24
-
25
-
26
- # @param [Hash] options
27
- # @option options [Boolean] :unwrap_block (false)
28
- # Perform block validation only -- skip is_not_empty validation logic.
29
- # Useless unless block provided
30
- # @return [void]
31
- def is_not_empty(options={}, &block)
32
- unless options.fetch(:unwrap_block, false) == true
33
- # Wrapped Validation
34
- if @ratifiable_object.empty?
35
- validation_error("empty")
36
- return
37
- end
38
- end
39
-
40
- instance_eval(&block) if block_given?
41
- rescue Exception => e
42
- validation_error("#{e.message}")
43
- end#is_not_empty
44
-
45
-
46
5
  # Define Minimum Length of Array
47
6
  #
48
7
  # @param [Integer] min_size
@@ -52,7 +11,9 @@ module Ratatouille
52
11
  # Useless unless block provided
53
12
  # @return [void]
54
13
  def min_length(min_size=0, options={}, &block)
55
- unless options.fetch(:unwrap_block, false) == true
14
+ parse_options(options)
15
+
16
+ unless @unwrap_block == true
56
17
  # Wrapped Validation
57
18
  return unless valid_min_length?(min_size)
58
19
  end
@@ -72,7 +33,9 @@ module Ratatouille
72
33
  # Useless unless block provided
73
34
  # @return [void]
74
35
  def max_length(max_size=0, options={}, &block)
75
- unless options.fetch(:unwrap_block, false) == true
36
+ parse_options(options)
37
+
38
+ unless @unwrap_block == true
76
39
  # Wrapped Validation
77
40
  return unless valid_max_length?(max_size)
78
41
  end
@@ -93,7 +56,9 @@ module Ratatouille
93
56
  # Useless unless block provided
94
57
  # @return [void]
95
58
  def length_between(min_size=0, max_size=nil, options={}, &block)
96
- unless options.fetch(:unwrap_block, false) == true
59
+ parse_options(options)
60
+
61
+ unless @unwrap_block == true
97
62
  # Wrapped Validation
98
63
  return unless valid_min_length?(min_size)
99
64
 
@@ -16,19 +16,22 @@ module Ratatouille
16
16
  #
17
17
  # @param [String, Symbol] key
18
18
  # @param [Hash] options
19
+ # @option options [Class] :is_a (nil)
20
+ # Used to ensure that the value of the required key is of the given class.
21
+ # * Performed before all other validation (if defined).
22
+ # * Validation will be skipped if option not defined.
19
23
  # @option options [String, Symbol] :name (key.to_s)
20
24
  # Name of ratifiable_object for use with validation error messages.
21
25
  # @option options [Boolean] :required (false)
22
26
  # Ensure that ratifiable_object has the given key
23
- # @option options [Boolean] :unwrap_block (false)
24
- # Perform block validation only -- skip is_empty validation logic.
25
- # Useless unless block provided
26
27
  def given_key(key, options={}, &block)
27
28
  options[:name] = options.fetch(:name, (Symbol === key ? ":#{key}" : key.to_s) )
28
29
 
29
- unless options.fetch(:unwrap_block, false) == true
30
- # Wrapped Validation
31
- if options.fetch(:required, false) == true
30
+ parse_options(options)
31
+
32
+ unless @unwrap_block == true
33
+ # WRAPPED VALIDATION
34
+ if @required == true
32
35
  unless @ratifiable_object.has_key?(key)
33
36
  validation_error("Missing key #{key.inspect}")
34
37
  return
@@ -36,57 +39,48 @@ module Ratatouille
36
39
  end
37
40
  end
38
41
 
39
- if @ratifiable_object.has_key?(key) && block_given?
40
- child_object = Ratatouille::Ratifier.new(@ratifiable_object[key], options, &block)
41
- @errors[key] = child_object.errors unless child_object.valid?
42
- end
43
- rescue Exception => e
44
- validation_error("#{e.message}")
45
- end#given_key
46
-
42
+ if @ratifiable_object.has_key?(key)
43
+ unless @unwrap_block == true
44
+ # WRAPPED VALIDATION
45
+ unless @is_a.nil?
46
+ unless @is_a === @ratifiable_object[key]
47
+ validation_error("key value is not of type #{@is_a}")
48
+ return
49
+ end
50
+ end
51
+ end
47
52
 
48
- # Self-explanatory
49
- #
50
- # @param [Hash] options
51
- # @option options [Boolean] :unwrap_block (false)
52
- # Perform block validation only -- skip is_empty validation logic.
53
- # Useless unless block provided
54
- # @return [void]
55
- def is_empty(options={}, &block)
56
- unless options.fetch(:unwrap_block, false) == true
57
- # Wrapped Validation
58
- unless @ratifiable_object.empty?
59
- validation_error("not empty")
60
- return
53
+ if block_given?
54
+ child_object = Ratatouille::Ratifier.new(@ratifiable_object[key], options, &block)
55
+ @errors[key] = child_object.errors unless child_object.valid?
61
56
  end
62
57
  end
63
-
64
- instance_eval(&block) if block_given?
65
58
  rescue Exception => e
66
59
  validation_error("#{e.message}")
67
- end#is_empty
60
+ end#given_key
68
61
 
69
62
 
70
- # Self-explanatory
63
+ # Perform validation on a single key that must be present in the Hash to validate.
64
+ # Otherwise, an error will be added.
71
65
  #
66
+ # * Eliminates the need to perform given_key methods within a required_keys block.
67
+ # * Evaluates an optional block in context of key value (same as given_key)
68
+ #
69
+ # @param key Required Key
72
70
  # @param [Hash] options
73
- # @option options [Boolean] :unwrap_block (false)
74
- # Perform block validation only -- skip is_not_empty validation logic.
75
- # Useless unless block provided
71
+ # @option options [Class] :is_a (nil)
72
+ # Used to ensure that the value of the required key is of the given class.
73
+ # * Performed before all other validation (if defined).
74
+ # * Validation will be skipped if option not defined.
75
+ # @option options [Boolean] :required (true) Used to call given_key.
76
76
  # @return [void]
77
- def is_not_empty(options={}, &block)
78
- unless options.fetch(:unwrap_block, false) == true
79
- # Wrapped Validation
80
- if @ratifiable_object.empty?
81
- validation_error("empty")
82
- return
83
- end
84
- end
85
-
86
- instance_eval(&block) if block_given?
77
+ def required_key(key, options={}, &block)
78
+ options[:required] = true
79
+ # Pass on processing to given_key with :required => true option
80
+ given_key(key, options, &block)
87
81
  rescue Exception => e
88
82
  validation_error("#{e.message}")
89
- end#is_not_empty
83
+ end
90
84
 
91
85
 
92
86
  # Provide a list of keys that must be present in the Hash to validate.
@@ -110,7 +104,9 @@ module Ratatouille
110
104
  # Useless unless block provided
111
105
  # @return [void]
112
106
  def required_keys(options={}, &block)
113
- unless options.fetch(:unwrap_block, false) == true
107
+ parse_options(options)
108
+
109
+ unless @unwrap_block == true
114
110
  req_keys = options.fetch(:key_list, [])
115
111
 
116
112
  # Wrapped Validation
@@ -140,25 +136,6 @@ module Ratatouille
140
136
  end#required_keys
141
137
 
142
138
 
143
- # Perform validation on a single key that must be present in the Hash to validate.
144
- # Otherwise, an error will be added.
145
- #
146
- # * Eliminates the need to perform given_key methods within a required_keys block.
147
- # * Evaluates an optional block in context of key value (same as given_key)
148
- #
149
- # @param key Required Key
150
- # @param [Hash] options
151
- # @option options [Boolean] :required (true) Used to call given_key.
152
- # @return [void]
153
- def required_key(key, options={}, &block)
154
- options[:required] = true
155
- # Pass on processing to given_key with :required => true option
156
- given_key(key, options, &block)
157
- rescue Exception => e
158
- validation_error("#{e.message}")
159
- end
160
-
161
-
162
139
  # Provide a list of keys to choose from and a choice size.
163
140
  # When the Hash does not contain at least 'choice_size' keys of the key
164
141
  # list provided, an error will be added.
@@ -184,10 +161,10 @@ module Ratatouille
184
161
  # Perform block validation only -- skip choice_of validation logic.
185
162
  # Useless unless block provided
186
163
  # @return [void]
187
- def choice_of(options, &block)
188
- options ||= {}
164
+ def choice_of(options={}, &block)
165
+ parse_options(options)
189
166
 
190
- unless options.fetch(:unwrap_block, false) == true
167
+ unless @unwrap_block == true
191
168
  choice_size = options.fetch(:choice_size, 1)
192
169
  key_list = options.fetch(:key_list, [])
193
170
 
@@ -140,6 +140,55 @@ module Ratatouille
140
140
  rescue Exception => e
141
141
  validation_error("#{e.message}", "/")
142
142
  end#is_a?
143
+
144
+
145
+ # Parse out common options into instance_variables for use within the
146
+ # validation methods defined in various places.
147
+ #
148
+ # @param [Hash] options
149
+ # @option options [Boolean] :unwrap_block (false)
150
+ # Perform block validation only -- skip method validation logic.
151
+ def parse_options(options={})
152
+ @unwrap_block = options.fetch(:unwrap_block, false)
153
+ @is_a = options.fetch(:is_a, nil)
154
+ @required = options.fetch(:required, false)
155
+ end#parse_options
156
+
157
+
158
+ # Override Method Missing for a Ratifier to generate errors for invalid
159
+ # methods called on incorrect objects (hash validation on arrays, etc.)
160
+ # as well as some catch-all methods for boolean validations (is_* and is_not_*)
161
+ def method_missing(id, *args, &block)
162
+ should_unwrap = false
163
+ if args.first.respond_to?(:keys)
164
+ if args.first.fetch(:unwrap_block, false) == true
165
+ should_unwrap = true
166
+ end
167
+ end
168
+
169
+ case
170
+ when should_unwrap == true
171
+ # Perform no validation logic
172
+ # Skip to block evaluation
173
+ when id.to_s =~ /^is_not_(.*)$/
174
+ if @ratifiable_object.respond_to?("#{$1}?")
175
+ if @ratifiable_object.send("#{$1}?") == true
176
+ validation_error("is #{$1}")
177
+ end
178
+ end
179
+ when id.to_s =~ /^is_(.*)$/
180
+ if @ratifiable_object.respond_to?("#{$1}?")
181
+ if @ratifiable_object.send("#{$1}?") == false
182
+ validation_error("is not #{$1}")
183
+ end
184
+ end
185
+ else
186
+ validation_error("#{id} is not supported for the given object (#{@ratifiable_object.class})")
187
+ end
188
+
189
+ instance_eval(&block) if block_given?
190
+ return
191
+ end#method_missing
143
192
  end#Ratifier
144
193
 
145
194
  end
@@ -1,4 +1,4 @@
1
1
  module Ratatouille
2
2
  # Gem Version
3
- VERSION = "1.3.0"
3
+ VERSION = "1.3.2"
4
4
  end
@@ -1,9 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Ratatouille::ArrayMethods" do
4
- [ :is_empty,
5
- :is_not_empty,
6
- :min_length,
4
+ [ :min_length,
7
5
  :max_length,
8
6
  :length_between
9
7
  ].each do |m|
@@ -1,42 +1,56 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe "Ratatouille::HashMethods" do
4
- describe "is_empty" do
5
- it "should be invalid for non-empty Hash" do
6
- RatifierTest.new({:bar => 'biz'}){ is_empty }.should_not be_valid
4
+ [ :choice_of,
5
+ :required_keys,
6
+ :required_key,
7
+ :given_key
8
+ ].each do |m|
9
+ it "block context should respond to #{m}" do
10
+ r = nil
11
+ RatifierTest.new({}) { r = self }
12
+ r.should respond_to m
7
13
  end
14
+ end
8
15
 
9
- it "should be valid for empty Hash" do
10
- RatifierTest.new({}){ is_empty }.should be_valid
11
- end
16
+ describe "(backward compatibility)" do
17
+ describe "is_empty" do
18
+ it "should be invalid for non-empty Hash" do
19
+ RatifierTest.new({:bar => 'biz'}){ is_empty }.should_not be_valid
20
+ end
12
21
 
13
- describe "when :unwrap_block is true" do
14
- it "should be valid for non-empty Hash" do
15
- RatifierTest.new({:bar => 'biz'}){
16
- is_empty(:unwrap_block => true) do
17
- # Nothing to validate, wrapper ignored.
18
- end
19
- }.should be_valid
22
+ it "should be valid for empty Hash" do
23
+ RatifierTest.new({}){ is_empty }.should be_valid
20
24
  end
21
- end
22
- end
23
25
 
24
- describe "is_not_empty" do
25
- it "should be valid for non-empty hash" do
26
- RatifierTest.new({:bar => "biz"}){ is_not_empty }.should be_valid
26
+ describe "when :unwrap_block is true" do
27
+ it "should be valid for non-empty Hash" do
28
+ RatifierTest.new({:bar => 'biz'}){
29
+ is_empty(:unwrap_block => true) do
30
+ # Nothing to validate, wrapper ignored.
31
+ end
32
+ }.should be_valid
33
+ end
34
+ end
27
35
  end
28
36
 
29
- it "should not be valid for empty hash" do
30
- RatifierTest.new({}){ is_not_empty }.should_not be_valid
31
- end
37
+ describe "is_not_empty" do
38
+ it "should be valid for non-empty hash" do
39
+ RatifierTest.new({:bar => "biz"}){ is_not_empty }.should be_valid
40
+ end
32
41
 
33
- describe "when :unwrap_block is true" do
34
- it "should be valid for empty hash" do
35
- RatifierTest.new({}){
36
- is_not_empty(:unwrap_block => true) do
37
- # Nothing to validate, wrapper ignored
38
- end
39
- }.should be_valid
42
+ it "should not be valid for empty hash" do
43
+ RatifierTest.new({}){ is_not_empty }.should_not be_valid
44
+ end
45
+
46
+ describe "when :unwrap_block is true" do
47
+ it "should be valid for empty hash" do
48
+ RatifierTest.new({}){
49
+ is_not_empty(:unwrap_block => true) do
50
+ # Nothing to validate, wrapper ignored
51
+ end
52
+ }.should be_valid
53
+ end
40
54
  end
41
55
  end
42
56
  end
@@ -173,6 +187,24 @@ describe "Ratatouille::HashMethods" do
173
187
  }.should be_valid
174
188
  end
175
189
  end
190
+
191
+ describe "when :is_a is given" do
192
+ it "should be valid with matching key value class" do
193
+ RatifierTest.new({:foo => "bar"}){
194
+ required_key(:foo, :class => String) do
195
+ # Nothing to validate, wrapper ignored
196
+ end
197
+ }.should be_valid
198
+ end
199
+
200
+ it "should be invalid with non-matching key value class" do
201
+ RatifierTest.new({:foo => "bar"}){
202
+ required_key(:foo, :is_a => Hash) do
203
+ # Nothing to validate, wrapper ignored
204
+ end
205
+ }.should_not be_valid
206
+ end
207
+ end
176
208
  end
177
209
 
178
210
  describe "given_key" do
@@ -17,6 +17,20 @@ describe Ratatouille::Ratifier do
17
17
  x['/'].should be_empty
18
18
  end
19
19
 
20
+ describe "when attempting to call an undefined method" do
21
+ it "should be invalid to call required_keys on an Array" do
22
+ RatifierTest.new([]){
23
+ required_keys(:key_list => [:foo])
24
+ }.should_not be_valid
25
+ end
26
+
27
+ it "should be invalid to call required_keys on an Object" do
28
+ RatifierTest.new(Object.new){
29
+ required_keys(:key_list => [:foo])
30
+ }.should_not be_valid
31
+ end
32
+ end
33
+
20
34
  describe "validation_error" do
21
35
  it "should create an error when called within a Ratifier block" do
22
36
  test = RatifierTest.new(Object.new) do
@@ -178,4 +192,22 @@ describe Ratatouille::Ratifier do
178
192
  end
179
193
  end
180
194
  end
195
+
196
+ describe "method_missing" do
197
+ describe "for non-standard boolean methods" do
198
+ it "should render object invalid for given method" do
199
+ obj = Object.new
200
+ obj.stub(:foo?).and_return(false)
201
+ RatifierTest.new(obj) { is_foo }.should_not be_valid
202
+ RatifierTest.new(obj) { is_not_foo }.should be_valid
203
+ end
204
+
205
+ it "should render object valid for given method" do
206
+ obj = Object.new
207
+ obj.stub(:bar?).and_return(true)
208
+ RatifierTest.new(obj) { is_bar }.should be_valid
209
+ RatifierTest.new(obj) { is_not_bar }.should_not be_valid
210
+ end
211
+ end
212
+ end
181
213
  end
data/spec/spec_helper.rb CHANGED
@@ -3,6 +3,7 @@ require 'ratatouille'
3
3
 
4
4
  RSpec.configure do |config|
5
5
  config.color_enabled = true
6
+ config.mock_with :rspec
6
7
  end
7
8
 
8
9
  class RatifierTest < Ratatouille::Ratifier
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ratatouille
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 31
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 3
9
- - 0
10
- version: 1.3.0
9
+ - 2
10
+ version: 1.3.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ryan Johnson
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-04-20 00:00:00 Z
18
+ date: 2012-04-23 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: rspec