poncho 0.0.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/.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
|