poncho 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +302 -0
- data/Rakefile +8 -0
- data/examples/app.rb +80 -0
- data/lib/poncho.rb +27 -0
- data/lib/poncho/error.rb +75 -0
- data/lib/poncho/errors.rb +142 -0
- data/lib/poncho/filters.rb +52 -0
- data/lib/poncho/json_method.rb +47 -0
- data/lib/poncho/method.rb +271 -0
- data/lib/poncho/param.rb +29 -0
- data/lib/poncho/params.rb +92 -0
- data/lib/poncho/params/array.rb +15 -0
- data/lib/poncho/params/boolean.rb +20 -0
- data/lib/poncho/params/boolean_string.rb +19 -0
- data/lib/poncho/params/integer.rb +17 -0
- data/lib/poncho/params/object.rb +15 -0
- data/lib/poncho/params/resource.rb +27 -0
- data/lib/poncho/params/string.rb +15 -0
- data/lib/poncho/params/validations.rb +24 -0
- data/lib/poncho/request.rb +71 -0
- data/lib/poncho/resource.rb +80 -0
- data/lib/poncho/response.rb +28 -0
- data/lib/poncho/returns.rb +25 -0
- data/lib/poncho/validations.rb +198 -0
- data/lib/poncho/validations/exclusions.rb +77 -0
- data/lib/poncho/validations/format.rb +105 -0
- data/lib/poncho/validations/inclusions.rb +77 -0
- data/lib/poncho/validations/length.rb +123 -0
- data/lib/poncho/validations/presence.rb +49 -0
- data/lib/poncho/validator.rb +172 -0
- data/lib/poncho/version.rb +3 -0
- data/poncho.gemspec +19 -0
- data/test/poncho/test_method.rb +105 -0
- data/test/poncho/test_resource.rb +71 -0
- metadata +84 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module Poncho
|
2
|
+
module Returns
|
3
|
+
class InvalidReturn < ServerError
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def returns(*resources)
|
12
|
+
@returns = resources if resources.any?
|
13
|
+
@returns ||= []
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def body(value = nil)
|
18
|
+
if value && success? && self.class.returns.none? {|res| value.is_a?(res) }
|
19
|
+
raise InvalidReturn, "Invalid body: #{value}"
|
20
|
+
end
|
21
|
+
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
module Poncho
|
2
|
+
# == Poncho Validations
|
3
|
+
#
|
4
|
+
# Provides a full validation framework to your objects.
|
5
|
+
#
|
6
|
+
# A minimal implementation could be:
|
7
|
+
#
|
8
|
+
# class Person
|
9
|
+
# include Poncho::Validations
|
10
|
+
#
|
11
|
+
# attr_accessor :first_name, :last_name
|
12
|
+
#
|
13
|
+
# validates_each :first_name, :last_name do |record, attr, value|
|
14
|
+
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# Which provides you with the full standard validation stack that you
|
19
|
+
# know from Active Record:
|
20
|
+
#
|
21
|
+
# person = Person.new
|
22
|
+
# person.valid? # => true
|
23
|
+
# person.invalid? # => false
|
24
|
+
#
|
25
|
+
# person.first_name = 'zoolander'
|
26
|
+
# person.valid? # => false
|
27
|
+
# person.invalid? # => true
|
28
|
+
# person.errors # => #<OrderedHash {:first_name=>["starts with z."]}>
|
29
|
+
#
|
30
|
+
# Note that <tt>Poncho::Validations</tt> automatically adds an +errors+ method
|
31
|
+
# to your instances initialized with a new <tt>Poncho::Errors</tt> object, so
|
32
|
+
# there is no need for you to do this manually.
|
33
|
+
#
|
34
|
+
module Validations
|
35
|
+
def self.included(base)
|
36
|
+
base.extend ClassMethods
|
37
|
+
base.extend HelperMethods
|
38
|
+
end
|
39
|
+
|
40
|
+
module HelperMethods
|
41
|
+
end
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
|
45
|
+
VALIDATES_DEFAULT_KEYS = [:if, :unless, :on, :allow_blank, :allow_nil , :strict]
|
46
|
+
|
47
|
+
# Validates each attribute against a block.
|
48
|
+
#
|
49
|
+
# class Person
|
50
|
+
# include Poncho::Validations
|
51
|
+
#
|
52
|
+
# attr_accessor :first_name, :last_name
|
53
|
+
#
|
54
|
+
# validates_each :first_name, :last_name do |record, attr, value|
|
55
|
+
# record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# Options:
|
60
|
+
# * <tt>:on</tt> - Specifies the context where this validation is active
|
61
|
+
# (e.g. <tt>:on => :create</tt> or <tt>:on => :custom_validation_context</tt>)
|
62
|
+
# * <tt>:allow_nil</tt> - Skip validation if attribute is +nil+.
|
63
|
+
# * <tt>:allow_blank</tt> - Skip validation if attribute is blank.
|
64
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
65
|
+
# if the validation should occur (e.g. <tt>:if => :allow_validation</tt>,
|
66
|
+
# or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
67
|
+
# proc or string should return or evaluate to a true or false value.
|
68
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
|
69
|
+
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or
|
70
|
+
# <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
71
|
+
# method, proc or string should return or evaluate to a true or false value.
|
72
|
+
def validates_each(*attr_names, &block)
|
73
|
+
options = attr_names.last.is_a?(::Hash) ? attr_names.pop : {}
|
74
|
+
validates_with BlockValidator, options.merge(:attributes => attr_names.flatten), &block
|
75
|
+
end
|
76
|
+
|
77
|
+
# Adds a validation method or block to the class. This is useful when
|
78
|
+
# overriding the +validate+ instance method becomes too unwieldy and
|
79
|
+
# you're looking for more descriptive declaration of your validations.
|
80
|
+
#
|
81
|
+
# This can be done with a symbol pointing to a method:
|
82
|
+
#
|
83
|
+
# class Comment
|
84
|
+
# include Poncho::Validations
|
85
|
+
#
|
86
|
+
# validate :must_be_friends
|
87
|
+
#
|
88
|
+
# def must_be_friends
|
89
|
+
# errors.add(:base, "Must be friends to leave a comment") unless commenter.friend_of?(commentee)
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# With a block which is passed with the current record to be validated:
|
94
|
+
#
|
95
|
+
# class Comment
|
96
|
+
# include Poncho::Validations
|
97
|
+
#
|
98
|
+
# validate do |comment|
|
99
|
+
# comment.must_be_friends
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# def must_be_friends
|
103
|
+
# errors.add(:base, "Must be friends to leave a comment") unless commenter.friend_of?(commentee)
|
104
|
+
# end
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# Or with a block where self points to the current record to be validated:
|
108
|
+
#
|
109
|
+
# class Comment
|
110
|
+
# include Poncho::Validations
|
111
|
+
#
|
112
|
+
# validate do
|
113
|
+
# errors.add(:base, "Must be friends to leave a comment") unless commenter.friend_of?(commentee)
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
def validate(proc = nil, &block)
|
118
|
+
proc ||= block
|
119
|
+
proc = method(proc) if proc.is_a?(Symbol)
|
120
|
+
|
121
|
+
validators << proc
|
122
|
+
end
|
123
|
+
|
124
|
+
# List all validators that are being used to validate the model using
|
125
|
+
# +validates_with+ method.
|
126
|
+
def validators
|
127
|
+
@validators ||= []
|
128
|
+
end
|
129
|
+
|
130
|
+
def validates_with(*args, &block)
|
131
|
+
options = args.last.is_a?(::Hash) ? args.pop : {}
|
132
|
+
|
133
|
+
args.each do |klass|
|
134
|
+
validator = klass.new(options, &block)
|
135
|
+
validate(validator.method(:validate))
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def validates(*attributes)
|
140
|
+
options = attributes.last.is_a?(::Hash) ? attributes.pop : {}
|
141
|
+
|
142
|
+
validations = options.reject {|key, value| VALIDATES_DEFAULT_KEYS.include?(key) || !value }
|
143
|
+
options = options.merge(:attributes => attributes)
|
144
|
+
|
145
|
+
validations.each do |key, validator_options|
|
146
|
+
validator_options = {} if validator_options == true
|
147
|
+
validates_with(validator_for_kind(key), validator_options.merge(:attributes => attributes))
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def validator_for_kind(kind)
|
154
|
+
return type if type.is_a?(Class)
|
155
|
+
name = kind.to_s.split('_').map {|w| w.capitalize }.join
|
156
|
+
const_get("#{name}Validator")
|
157
|
+
rescue NameError
|
158
|
+
raise ArgumentError, "Unknown validator: #{kind}"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Returns the +Errors+ object that holds all information about attribute error messages.
|
163
|
+
def errors
|
164
|
+
@errors ||= Errors.new(self)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Runs all the specified validations and returns true if no errors were added
|
168
|
+
# otherwise false. Context can optionally be supplied to define which callbacks
|
169
|
+
# to test against.
|
170
|
+
def valid?(context = nil)
|
171
|
+
errors.clear
|
172
|
+
run_validations!
|
173
|
+
end
|
174
|
+
|
175
|
+
# Performs the opposite of <tt>valid?</tt>. Returns true if errors were added,
|
176
|
+
# false otherwise.
|
177
|
+
def invalid?
|
178
|
+
!valid?
|
179
|
+
end
|
180
|
+
|
181
|
+
alias :read_attribute_for_validation :send
|
182
|
+
|
183
|
+
protected
|
184
|
+
|
185
|
+
def run_validations!
|
186
|
+
self.class.validators.each do |validator|
|
187
|
+
instance_eval(&validator)
|
188
|
+
end
|
189
|
+
|
190
|
+
errors.empty?
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
Dir[File.dirname(__FILE__) + '/validations/*.rb'].sort.each do |path|
|
196
|
+
filename = File.basename(path)
|
197
|
+
require "poncho/validations/#{filename}"
|
198
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Poncho
|
2
|
+
module Validations
|
3
|
+
class ExclusionValidator < EachValidator
|
4
|
+
ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " <<
|
5
|
+
"and must be supplied as the :in (or :within) option of the configuration hash"
|
6
|
+
|
7
|
+
def check_validity!
|
8
|
+
unless [:include?, :call].any? { |method| delimiter.respond_to?(method) }
|
9
|
+
raise ArgumentError, ERROR_MESSAGE
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate_each(record, attribute, value)
|
14
|
+
exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter
|
15
|
+
if exclusions.send(inclusion_method(exclusions), value)
|
16
|
+
record.errors.add(attribute, :exclusion, options.merge(:value => value))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def delimiter
|
23
|
+
@delimiter ||= options[:in] || options[:within]
|
24
|
+
end
|
25
|
+
|
26
|
+
# In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible
|
27
|
+
# values in the range for equality, so it may be slow for large ranges. The new
|
28
|
+
# <tt>Range#cover?</tt> uses the previous logic of comparing a value with the
|
29
|
+
# range endpoints.
|
30
|
+
def inclusion_method(enumerable)
|
31
|
+
enumerable.is_a?(Range) ? :cover? : :include?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module HelperMethods
|
36
|
+
# Validates that the value of the specified attribute is not in a particular
|
37
|
+
# enumerable object.
|
38
|
+
#
|
39
|
+
# class Person < ActiveRecord::Base
|
40
|
+
# validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
|
41
|
+
# validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
|
42
|
+
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
|
43
|
+
# validates_exclusion_of :password, :in => lambda { |p| [p.username, p.first_name] },
|
44
|
+
# :message => "should not be the same as your username or first name"
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# Configuration options:
|
48
|
+
# * <tt>:in</tt> - An enumerable object of items that the value shouldn't be
|
49
|
+
# part of. This can be supplied as a proc or lambda which returns an enumerable.
|
50
|
+
# If the enumerable is a range the test is performed with <tt>Range#cover?</tt>
|
51
|
+
# (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
|
52
|
+
# * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
|
53
|
+
# * <tt>:message</tt> - Specifies a custom error message (default is: "is reserved").
|
54
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
|
55
|
+
# is +nil+ (default is +false+).
|
56
|
+
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the
|
57
|
+
# attribute is blank (default is +false+).
|
58
|
+
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
|
59
|
+
# validation contexts by default (+nil+), other options are <tt>:create</tt>
|
60
|
+
# and <tt>:update</tt>.
|
61
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the
|
62
|
+
# validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
|
63
|
+
# <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
|
64
|
+
# or string should return or evaluate to a true or false value.
|
65
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if
|
66
|
+
# the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
|
67
|
+
# or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
|
68
|
+
# proc or string should return or evaluate to a true or false value.
|
69
|
+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
|
70
|
+
# See <tt>Poncho::Validation#validates!</tt> for more information.
|
71
|
+
def validates_exclusion_of(*attr_names)
|
72
|
+
options = attr_names.last.is_a?(::Hash) ? attr_names.pop : {}
|
73
|
+
validates_with ExclusionValidator, options.merge(:attributes => attr_names)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Poncho
|
2
|
+
module Validations
|
3
|
+
class FormatValidator < EachValidator
|
4
|
+
def validate_each(record, attribute, value)
|
5
|
+
if options[:with]
|
6
|
+
regexp = option_call(record, :with)
|
7
|
+
record_error(record, attribute, :with, value) if value.to_s !~ regexp
|
8
|
+
elsif options[:without]
|
9
|
+
regexp = option_call(record, :without)
|
10
|
+
record_error(record, attribute, :without, value) if value.to_s =~ regexp
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def check_validity!
|
15
|
+
unless options.include?(:with) ^ options.include?(:without) # ^ == xor, or "exclusive or"
|
16
|
+
raise ArgumentError, "Either :with or :without must be supplied (but not both)"
|
17
|
+
end
|
18
|
+
|
19
|
+
check_options_validity(options, :with)
|
20
|
+
check_options_validity(options, :without)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def option_call(record, name)
|
26
|
+
option = options[name]
|
27
|
+
option.respond_to?(:call) ? option.call(record) : option
|
28
|
+
end
|
29
|
+
|
30
|
+
def record_error(record, attribute, name, value)
|
31
|
+
record.errors.add(attribute, options.merge(:value => value))
|
32
|
+
end
|
33
|
+
|
34
|
+
def check_options_validity(options, name)
|
35
|
+
option = options[name]
|
36
|
+
if option && !option.is_a?(Regexp) && !option.respond_to?(:call)
|
37
|
+
raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module HelperMethods
|
43
|
+
# Validates whether the value of the specified attribute is of the correct form,
|
44
|
+
# going by the regular expression provided. You can require that the attribute
|
45
|
+
# matches the regular expression:
|
46
|
+
#
|
47
|
+
# class Person < ActiveRecord::Base
|
48
|
+
# validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# Alternatively, you can require that the specified attribute does _not_ match
|
52
|
+
# the regular expression:
|
53
|
+
#
|
54
|
+
# class Person < ActiveRecord::Base
|
55
|
+
# validates_format_of :email, :without => /NOSPAM/
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# You can also provide a proc or lambda which will determine the regular
|
59
|
+
# expression that will be used to validate the attribute.
|
60
|
+
#
|
61
|
+
# class Person < ActiveRecord::Base
|
62
|
+
# # Admin can have number as a first letter in their screen name
|
63
|
+
# validates_format_of :screen_name,
|
64
|
+
# :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i }
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# Note: use <tt>\A</tt> and <tt>\Z</tt> to match the start and end of the string,
|
68
|
+
# <tt>^</tt> and <tt>$</tt> match the start/end of a line.
|
69
|
+
#
|
70
|
+
# You must pass either <tt>:with</tt> or <tt>:without</tt> as an option. In
|
71
|
+
# addition, both must be a regular expression or a proc or lambda, or else an
|
72
|
+
# exception will be raised.
|
73
|
+
#
|
74
|
+
# Configuration options:
|
75
|
+
# * <tt>:message</tt> - A custom error message (default is: "is invalid").
|
76
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
|
77
|
+
# is +nil+ (default is +false+).
|
78
|
+
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the
|
79
|
+
# attribute is blank (default is +false+).
|
80
|
+
# * <tt>:with</tt> - Regular expression that if the attribute matches will
|
81
|
+
# result in a successful validation. This can be provided as a proc or lambda
|
82
|
+
# returning regular expression which will be called at runtime.
|
83
|
+
# * <tt>:without</tt> - Regular expression that if the attribute does not match
|
84
|
+
# will result in a successful validation. This can be provided as a proc or
|
85
|
+
# lambda returning regular expression which will be called at runtime.
|
86
|
+
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
|
87
|
+
# validation contexts by default (+nil+), other options are <tt>:create</tt>
|
88
|
+
# and <tt>:update</tt>.
|
89
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the
|
90
|
+
# validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
|
91
|
+
# <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
|
92
|
+
# or string should return or evaluate to a true or false value.
|
93
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if
|
94
|
+
# the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
|
95
|
+
# or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
|
96
|
+
# proc or string should return or evaluate to a true or false value.
|
97
|
+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
|
98
|
+
# See <tt>Poncho::Validation#validates!</tt> for more information.
|
99
|
+
def validates_format_of(*attr_names)
|
100
|
+
options = attr_names.last.is_a?(::Hash) ? attr_names.pop : {}
|
101
|
+
validates_with FormatValidator, options.merge(:attributes => attr_names)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Poncho
|
2
|
+
module Validations
|
3
|
+
class InclusionValidator < EachValidator
|
4
|
+
ERROR_MESSAGE = "An object with the method #include? or a proc or lambda is required, " <<
|
5
|
+
"and must be supplied as the :in (or :within) option of the configuration hash"
|
6
|
+
|
7
|
+
def check_validity!
|
8
|
+
unless [:include?, :call].any?{ |method| delimiter.respond_to?(method) }
|
9
|
+
raise ArgumentError, ERROR_MESSAGE
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate_each(record, attribute, value)
|
14
|
+
exclusions = delimiter.respond_to?(:call) ? delimiter.call(record) : delimiter
|
15
|
+
unless exclusions.send(inclusion_method(exclusions), value)
|
16
|
+
record.errors.add(attribute, :inclusion, options.merge(:value => value))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def delimiter
|
23
|
+
@delimiter ||= options[:in] || options[:within]
|
24
|
+
end
|
25
|
+
|
26
|
+
# In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible
|
27
|
+
# values in the range for equality, so it may be slow for large ranges. The new
|
28
|
+
# <tt>Range#cover?</tt> uses the previous logic of comparing a value with the
|
29
|
+
# range endpoints.
|
30
|
+
def inclusion_method(enumerable)
|
31
|
+
enumerable.is_a?(Range) ? :cover? : :include?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module HelperMethods
|
36
|
+
# Validates whether the value of the specified attribute is available in a
|
37
|
+
# particular enumerable object.
|
38
|
+
#
|
39
|
+
# class Person < ActiveRecord::Base
|
40
|
+
# validates_inclusion_of :gender, :in => %w( m f )
|
41
|
+
# validates_inclusion_of :age, :in => 0..99
|
42
|
+
# validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %{value} is not included in the list"
|
43
|
+
# validates_inclusion_of :states, :in => lambda{ |person| STATES[person.country] }
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# Configuration options:
|
47
|
+
# * <tt>:in</tt> - An enumerable object of available items. This can be
|
48
|
+
# supplied as a proc or lambda which returns an enumerable. If the enumerable
|
49
|
+
# is a range the test is performed with <tt>Range#cover?</tt>
|
50
|
+
# (backported in Active Support for 1.8), otherwise with <tt>include?</tt>.
|
51
|
+
# * <tt>:within</tt> - A synonym(or alias) for <tt>:in</tt>
|
52
|
+
# * <tt>:message</tt> - Specifies a custom error message (default is: "is not
|
53
|
+
# included in the list").
|
54
|
+
# * <tt>:allow_nil</tt> - If set to true, skips this validation if the attribute
|
55
|
+
# is +nil+ (default is +false+).
|
56
|
+
# * <tt>:allow_blank</tt> - If set to true, skips this validation if the
|
57
|
+
# attribute is blank (default is +false+).
|
58
|
+
# * <tt>:on</tt> - Specifies when this validation is active. Runs in all
|
59
|
+
# validation contexts by default (+nil+), other options are <tt>:create</tt>
|
60
|
+
# and <tt>:update</tt>.
|
61
|
+
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine if
|
62
|
+
# the validation should occur (e.g. <tt>:if => :allow_validation</tt>, or
|
63
|
+
# <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The method, proc
|
64
|
+
# or string should return or evaluate to a true or false value.
|
65
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to determine
|
66
|
+
# if the validation should not occur (e.g. <tt>:unless => :skip_validation</tt>,
|
67
|
+
# or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
|
68
|
+
# proc or string should return or evaluate to a true or false value.
|
69
|
+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
|
70
|
+
# See <tt>Poncho::Validation#validates!</tt> for more information.
|
71
|
+
def validates_inclusion_of(*attr_names)
|
72
|
+
options = attr_names.last.is_a?(::Hash) ? attr_names.pop : {}
|
73
|
+
validates_with InclusionValidator, options.merge(:attributes => attr_names)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|