ratatouille 1.3.0 → 1.3.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.
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