dm-core 1.1.0 → 1.2.0.rc1
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/Gemfile +13 -11
- data/README.rdoc +1 -1
- data/Rakefile +1 -2
- data/VERSION +1 -1
- data/dm-core.gemspec +30 -176
- data/lib/dm-core.rb +32 -67
- data/lib/dm-core/adapters/abstract_adapter.rb +1 -2
- data/lib/dm-core/associations/many_to_many.rb +11 -5
- data/lib/dm-core/associations/many_to_one.rb +17 -2
- data/lib/dm-core/associations/one_to_many.rb +16 -0
- data/lib/dm-core/backwards.rb +13 -0
- data/lib/dm-core/collection.rb +1 -1
- data/lib/dm-core/model.rb +99 -41
- data/lib/dm-core/model/property.rb +24 -27
- data/lib/dm-core/model/relationship.rb +22 -28
- data/lib/dm-core/property.rb +37 -50
- data/lib/dm-core/property/boolean.rb +6 -10
- data/lib/dm-core/property/date.rb +0 -2
- data/lib/dm-core/property/date_time.rb +0 -2
- data/lib/dm-core/property/decimal.rb +5 -1
- data/lib/dm-core/property/discriminator.rb +24 -26
- data/lib/dm-core/property/float.rb +5 -1
- data/lib/dm-core/property/numeric.rb +6 -9
- data/lib/dm-core/property/string.rb +2 -1
- data/lib/dm-core/property/time.rb +0 -2
- data/lib/dm-core/property/typecast/time.rb +7 -2
- data/lib/dm-core/property_set.rb +1 -3
- data/lib/dm-core/query.rb +3 -10
- data/lib/dm-core/query/conditions/comparison.rb +5 -1
- data/lib/dm-core/query/conditions/operation.rb +1 -1
- data/lib/dm-core/relationship_set.rb +0 -2
- data/lib/dm-core/resource.rb +27 -28
- data/lib/dm-core/resource/{state.rb → persistence_state.rb} +2 -2
- data/lib/dm-core/resource/{state → persistence_state}/clean.rb +4 -4
- data/lib/dm-core/resource/{state → persistence_state}/deleted.rb +2 -2
- data/lib/dm-core/resource/{state → persistence_state}/dirty.rb +2 -2
- data/lib/dm-core/resource/{state → persistence_state}/immutable.rb +3 -3
- data/lib/dm-core/resource/{state → persistence_state}/persisted.rb +3 -3
- data/lib/dm-core/resource/{state → persistence_state}/transient.rb +3 -3
- data/lib/dm-core/spec/lib/adapter_helpers.rb +2 -5
- data/lib/dm-core/spec/setup.rb +3 -2
- data/lib/dm-core/spec/shared/public/property_spec.rb +8 -0
- data/lib/dm-core/spec/shared/resource_spec.rb +14 -0
- data/lib/dm-core/spec/shared/semipublic/property_spec.rb +1 -1
- data/lib/dm-core/support/descendant_set.rb +0 -2
- data/lib/dm-core/support/ext/array.rb +0 -19
- data/lib/dm-core/support/ext/blank.rb +1 -0
- data/lib/dm-core/support/hook.rb +0 -3
- data/lib/dm-core/support/naming_conventions.rb +6 -0
- data/lib/dm-core/support/ordered_set.rb +0 -2
- data/lib/dm-core/support/subject_set.rb +0 -2
- data/lib/dm-core/version.rb +1 -1
- data/spec/public/associations/many_to_many_spec.rb +0 -1
- data/spec/public/model/property_spec.rb +55 -9
- data/spec/public/model/relationship_spec.rb +24 -2
- data/spec/public/model_spec.rb +32 -0
- data/spec/public/property/binary_spec.rb +14 -6
- data/spec/public/property/boolean_spec.rb +14 -6
- data/spec/public/property/class_spec.rb +14 -6
- data/spec/public/property/date_spec.rb +14 -6
- data/spec/public/property/date_time_spec.rb +14 -6
- data/spec/public/property/decimal_spec.rb +10 -2
- data/spec/public/property/discriminator_spec.rb +15 -1
- data/spec/public/property/float_spec.rb +14 -6
- data/spec/public/property/integer_spec.rb +14 -6
- data/spec/public/property/object_spec.rb +8 -0
- data/spec/public/property/serial_spec.rb +14 -6
- data/spec/public/property/string_spec.rb +14 -6
- data/spec/public/property/text_spec.rb +14 -6
- data/spec/public/property/time_spec.rb +14 -6
- data/spec/public/resource_spec.rb +58 -0
- data/spec/public/shared/finder_shared_spec.rb +8 -4
- data/spec/semipublic/associations/many_to_many_spec.rb +2 -0
- data/spec/semipublic/associations/many_to_one_spec.rb +2 -0
- data/spec/semipublic/associations/one_to_many_spec.rb +2 -0
- data/spec/semipublic/associations/one_to_one_spec.rb +2 -0
- data/spec/semipublic/property/binary_spec.rb +5 -5
- data/spec/semipublic/property/boolean_spec.rb +5 -5
- data/spec/semipublic/property/class_spec.rb +5 -5
- data/spec/semipublic/property/date_spec.rb +5 -5
- data/spec/semipublic/property/date_time_spec.rb +5 -5
- data/spec/semipublic/property/decimal_spec.rb +2 -2
- data/spec/semipublic/property/discriminator_spec.rb +5 -5
- data/spec/semipublic/property/float_spec.rb +5 -5
- data/spec/semipublic/property/integer_spec.rb +5 -5
- data/spec/semipublic/property/lookup_spec.rb +3 -3
- data/spec/semipublic/property/serial_spec.rb +5 -5
- data/spec/semipublic/property/string_spec.rb +5 -5
- data/spec/semipublic/property/text_spec.rb +5 -5
- data/spec/semipublic/property/time_spec.rb +5 -5
- data/spec/semipublic/query/conditions/comparison_spec.rb +44 -4
- data/spec/semipublic/query_spec.rb +2 -11
- data/spec/semipublic/resource/state/clean_spec.rb +6 -6
- data/spec/semipublic/resource/state/deleted_spec.rb +4 -4
- data/spec/semipublic/resource/state/dirty_spec.rb +8 -8
- data/spec/semipublic/resource/state/immutable_spec.rb +6 -6
- data/spec/semipublic/resource/state/transient_spec.rb +5 -5
- data/spec/semipublic/resource/state_spec.rb +15 -15
- data/spec/semipublic/shared/resource_shared_spec.rb +7 -1
- data/spec/semipublic/shared/resource_state_shared_spec.rb +8 -8
- data/spec/unit/array_spec.rb +0 -14
- data/spec/unit/blank_spec.rb +11 -0
- metadata +70 -188
- data/lib/dm-core/support/inflector.rb +0 -3
@@ -1,15 +1,12 @@
|
|
1
1
|
# TODO: update Model#respond_to? to return true if method_method missing
|
2
2
|
# would handle the message
|
3
3
|
|
4
|
-
require 'dm-core/relationship_set'
|
5
|
-
|
6
4
|
module DataMapper
|
7
5
|
module Model
|
8
6
|
module Relationship
|
9
7
|
Model.append_extensions self
|
10
8
|
|
11
9
|
include DataMapper::Assertions
|
12
|
-
extend Chainable
|
13
10
|
|
14
11
|
# Initializes relationships hash for extended model
|
15
12
|
# class.
|
@@ -23,21 +20,19 @@ module DataMapper
|
|
23
20
|
model.instance_variable_set(:@relationships, {})
|
24
21
|
end
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
model.instance_variable_set(:@relationships, {})
|
33
|
-
|
34
|
-
@relationships.each do |repository_name, relationships|
|
35
|
-
model_relationships = model.relationships(repository_name)
|
36
|
-
relationships.each { |relationship| model_relationships << relationship }
|
37
|
-
end
|
23
|
+
# When DataMapper model is inherited, relationships
|
24
|
+
# of parent are duplicated and copied to subclass model
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def inherited(model)
|
28
|
+
model.instance_variable_set(:@relationships, {})
|
38
29
|
|
39
|
-
|
30
|
+
@relationships.each do |repository_name, relationships|
|
31
|
+
model_relationships = model.relationships(repository_name)
|
32
|
+
relationships.each { |relationship| model_relationships << relationship }
|
40
33
|
end
|
34
|
+
|
35
|
+
super
|
41
36
|
end
|
42
37
|
|
43
38
|
# Returns copy of relationships set in given repository.
|
@@ -194,7 +189,7 @@ module DataMapper
|
|
194
189
|
relationship
|
195
190
|
end
|
196
191
|
|
197
|
-
|
192
|
+
private
|
198
193
|
|
199
194
|
# Extract the model from an Array of arguments
|
200
195
|
#
|
@@ -342,7 +337,7 @@ module DataMapper
|
|
342
337
|
# of 1:1, the underlying collection is hidden in a
|
343
338
|
# private ivar, and the resource is in a known ivar
|
344
339
|
|
345
|
-
|
340
|
+
persistence_state.get(relationships[#{name.inspect}], query)
|
346
341
|
end
|
347
342
|
RUBY
|
348
343
|
end
|
@@ -362,22 +357,21 @@ module DataMapper
|
|
362
357
|
#{writer_visibility}
|
363
358
|
def #{writer_name}(target)
|
364
359
|
relationship = relationships[#{name.inspect}]
|
365
|
-
self.
|
366
|
-
|
360
|
+
self.persistence_state = persistence_state.set(relationship, target)
|
361
|
+
persistence_state.get(relationship)
|
367
362
|
end
|
368
363
|
RUBY
|
369
364
|
end
|
370
365
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
return Query::Path.new([ relationship ])
|
376
|
-
end
|
377
|
-
|
378
|
-
super
|
366
|
+
# @api public
|
367
|
+
def method_missing(method, *args, &block)
|
368
|
+
if relationship = relationships(repository_name)[method]
|
369
|
+
return Query::Path.new([ relationship ])
|
379
370
|
end
|
371
|
+
|
372
|
+
super
|
380
373
|
end
|
374
|
+
|
381
375
|
end # module Relationship
|
382
376
|
end # module Model
|
383
377
|
end # module DataMapper
|
data/lib/dm-core/property.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'dm-core/resource'
|
2
|
-
require 'dm-core/query'
|
3
|
-
|
4
1
|
module DataMapper
|
5
2
|
# = Properties
|
6
3
|
# Properties for a model are not derived from a database structure, but
|
@@ -83,11 +80,13 @@ module DataMapper
|
|
83
80
|
# property :title, String
|
84
81
|
#
|
85
82
|
# def title=(new_title)
|
86
|
-
# raise ArgumentError if new_title != '
|
87
|
-
#
|
83
|
+
# raise ArgumentError if new_title != 'Lee is l337'
|
84
|
+
# super(new_title)
|
88
85
|
# end
|
89
86
|
# end
|
90
87
|
#
|
88
|
+
# Calling super ensures that any validators defined for the property are kept active.
|
89
|
+
#
|
91
90
|
# == Lazy Loading
|
92
91
|
# By default, some properties are not loaded when an object is fetched in
|
93
92
|
# DataMapper. These lazily loaded properties are fetched on demand when their
|
@@ -107,7 +106,7 @@ module DataMapper
|
|
107
106
|
#
|
108
107
|
# If you want to over-ride the lazy loading on any field you can set it to a
|
109
108
|
# context or false to disable it with the :lazy option. Contexts allow
|
110
|
-
#
|
109
|
+
# multiple lazy properties to be loaded at one time. If you set :lazy to
|
111
110
|
# true, it is placed in the :default context
|
112
111
|
#
|
113
112
|
# class Post
|
@@ -179,44 +178,40 @@ module DataMapper
|
|
179
178
|
#
|
180
179
|
# == Inferred Validations
|
181
180
|
# If you require the dm-validations plugin, auto-validations will
|
182
|
-
# automatically be mixed-in in to your model classes:
|
183
|
-
#
|
184
|
-
# specific column restrictions.
|
181
|
+
# automatically be mixed-in in to your model classes: validation rules that
|
182
|
+
# are inferred when properties are declared with specific column restrictions.
|
185
183
|
#
|
186
|
-
#
|
187
|
-
#
|
188
|
-
#
|
189
|
-
# property :title, String, :length => 250
|
190
|
-
# # => infers 'validates_length :title,
|
191
|
-
# :minimum => 0, :maximum => 250'
|
184
|
+
# class Post
|
185
|
+
# include DataMapper::Resource
|
192
186
|
#
|
193
|
-
#
|
194
|
-
#
|
187
|
+
# property :title, String, :length => 250, :min => 0, :max => 250
|
188
|
+
# # => infers 'validates_length :title'
|
195
189
|
#
|
196
|
-
#
|
197
|
-
#
|
190
|
+
# property :title, String, :required => true
|
191
|
+
# # => infers 'validates_present :title'
|
198
192
|
#
|
199
|
-
#
|
200
|
-
#
|
201
|
-
# # 'validates_present'
|
202
|
-
# # better: property :title, String, :length => 1..255
|
193
|
+
# property :email, String, :format => :email_address
|
194
|
+
# # => infers 'validates_format :email, :with => :email_address'
|
203
195
|
#
|
204
|
-
#
|
196
|
+
# property :title, String, :length => 255, :required => true
|
197
|
+
# # => infers both 'validates_length' as well as 'validates_present'
|
198
|
+
# # better: property :title, String, :length => 1..255
|
199
|
+
# end
|
205
200
|
#
|
206
201
|
# This functionality is available with the dm-validations gem. For more information
|
207
202
|
# about validations, check the documentation for dm-validations.
|
208
203
|
#
|
209
204
|
# == Default Values
|
210
|
-
# To set a default for a property, use the <tt>:default</tt> key.
|
205
|
+
# To set a default for a property, use the <tt>:default</tt> key. The
|
211
206
|
# property will be set to the value associated with that key the first time
|
212
207
|
# it is accessed, or when the resource is saved if it hasn't been set with
|
213
|
-
# another value already.
|
208
|
+
# another value already. This value can be a static value, such as 'hello'
|
214
209
|
# but it can also be a proc that will be evaluated when the property is read
|
215
|
-
# before its value has been set.
|
216
|
-
# proc.
|
210
|
+
# before its value has been set. The property is set to the return of the
|
211
|
+
# proc. The proc is passed two values, the resource the property is being set
|
217
212
|
# for and the property itself.
|
218
213
|
#
|
219
|
-
# property :display_name, String, :default => { |resource, property| resource.login }
|
214
|
+
# property :display_name, String, :default => lambda { |resource, property| resource.login }
|
220
215
|
#
|
221
216
|
# Word of warning. Don't try to read the value of the property you're setting
|
222
217
|
# the default for in the proc. An infinite loop will ensue.
|
@@ -270,9 +265,6 @@ module DataMapper
|
|
270
265
|
# Only makes sense for float type properties. Must be > 0.
|
271
266
|
# Default is nil for Float type and 10 for BigDecimal
|
272
267
|
#
|
273
|
-
# All other keys you pass to +property+ method are stored and available
|
274
|
-
# as options[:extra_keys].
|
275
|
-
#
|
276
268
|
# == Overriding default Property options
|
277
269
|
#
|
278
270
|
# There is the ability to reconfigure a Property and it's subclasses by explicitly
|
@@ -291,7 +283,7 @@ module DataMapper
|
|
291
283
|
# DataMapper::Property.auto_validation(false)
|
292
284
|
#
|
293
285
|
# # set all mutator methods to be private by default
|
294
|
-
# DataMapper::Property.writer(
|
286
|
+
# DataMapper::Property.writer(:private)
|
295
287
|
#
|
296
288
|
# Please note that this has no effect when a subclass has explicitly
|
297
289
|
# defined it's own option. For example, setting the String length to
|
@@ -311,8 +303,7 @@ module DataMapper
|
|
311
303
|
module PassThroughLoadDump
|
312
304
|
# @api semipublic
|
313
305
|
def load(value)
|
314
|
-
|
315
|
-
typecast(value)
|
306
|
+
typecast(value) unless value.nil?
|
316
307
|
end
|
317
308
|
|
318
309
|
# Stub instance method for dumping
|
@@ -329,10 +320,9 @@ module DataMapper
|
|
329
320
|
|
330
321
|
include DataMapper::Assertions
|
331
322
|
include Subject
|
332
|
-
extend Chainable
|
333
323
|
extend Equalizer
|
334
324
|
|
335
|
-
equalize :model, :name
|
325
|
+
equalize :model, :name, :options
|
336
326
|
|
337
327
|
PRIMITIVES = [
|
338
328
|
TrueClass,
|
@@ -357,7 +347,10 @@ module DataMapper
|
|
357
347
|
VISIBILITY_OPTIONS = [ :public, :protected, :private ].to_set.freeze
|
358
348
|
|
359
349
|
# Invalid property names
|
360
|
-
INVALID_NAMES = (Resource.instance_methods +
|
350
|
+
INVALID_NAMES = (Resource.instance_methods +
|
351
|
+
Resource.private_instance_methods +
|
352
|
+
Query::OPTIONS.to_a
|
353
|
+
).map { |name| name.to_s }
|
361
354
|
|
362
355
|
attr_reader :primitive, :model, :name, :instance_variable_name,
|
363
356
|
:reader_visibility, :writer_visibility, :options,
|
@@ -462,9 +455,8 @@ module DataMapper
|
|
462
455
|
# @api public
|
463
456
|
def options
|
464
457
|
options = {}
|
465
|
-
accepted_options.each do |
|
466
|
-
|
467
|
-
options[method] = value unless value.nil?
|
458
|
+
accepted_options.each do |name|
|
459
|
+
options[name] = send(name) if instance_variable_defined?("@#{name}")
|
468
460
|
end
|
469
461
|
options
|
470
462
|
end
|
@@ -737,20 +729,15 @@ module DataMapper
|
|
737
729
|
value.kind_of?(primitive)
|
738
730
|
end
|
739
731
|
|
740
|
-
|
741
|
-
def self.new(model, name, options = {})
|
742
|
-
super
|
743
|
-
end
|
744
|
-
end
|
745
|
-
|
746
|
-
protected
|
732
|
+
protected
|
747
733
|
|
748
734
|
# @api semipublic
|
749
735
|
def initialize(model, name, options = {})
|
750
736
|
options = options.to_hash.dup
|
751
737
|
|
752
|
-
if INVALID_NAMES.include?(name.to_s)
|
753
|
-
raise ArgumentError,
|
738
|
+
if INVALID_NAMES.include?(name.to_s) || (kind_of?(Boolean) && INVALID_NAMES.include?("#{name}?"))
|
739
|
+
raise ArgumentError,
|
740
|
+
"+name+ was #{name.inspect}, which cannot be used as a property name since it collides with an existing method or a query option"
|
754
741
|
end
|
755
742
|
|
756
743
|
assert_valid_options(options)
|
@@ -5,6 +5,11 @@ module DataMapper
|
|
5
5
|
|
6
6
|
primitive ::TrueClass
|
7
7
|
|
8
|
+
TRUE_VALUES = [ 1, '1', 't', 'T', 'true', 'TRUE' ].freeze
|
9
|
+
FALSE_VALUES = [ 0, '0', 'f', 'F', 'false', 'FALSE' ].freeze
|
10
|
+
BOOLEAN_MAP = Hash[
|
11
|
+
TRUE_VALUES.product([ true ]) + FALSE_VALUES.product([ false ]) ].freeze
|
12
|
+
|
8
13
|
def primitive?(value)
|
9
14
|
value == true || value == false
|
10
15
|
end
|
@@ -19,16 +24,7 @@ module DataMapper
|
|
19
24
|
#
|
20
25
|
# @api private
|
21
26
|
def typecast_to_primitive(value)
|
22
|
-
|
23
|
-
return true if value == 1
|
24
|
-
return false if value == 0
|
25
|
-
elsif value.respond_to?(:to_str)
|
26
|
-
string_value = value.to_str.downcase
|
27
|
-
return true if %w[ true 1 t ].include?(string_value)
|
28
|
-
return false if %w[ false 0 f ].include?(string_value)
|
29
|
-
end
|
30
|
-
|
31
|
-
value
|
27
|
+
BOOLEAN_MAP.fetch(value, value)
|
32
28
|
end
|
33
29
|
end # class Boolean
|
34
30
|
end # class Property
|
@@ -8,40 +8,38 @@ module DataMapper
|
|
8
8
|
|
9
9
|
# @api private
|
10
10
|
def bind
|
11
|
-
model.
|
12
|
-
|
13
|
-
model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
14
|
-
extend Chainable
|
11
|
+
model.extend Model unless model < Model
|
12
|
+
end
|
15
13
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
module Model
|
15
|
+
def inherited(model)
|
16
|
+
super # setup self.descendants
|
17
|
+
set_discriminator_scope_for(model)
|
18
|
+
end
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
def new(*args, &block)
|
21
|
+
if args.size == 1 && args.first.kind_of?(Hash)
|
22
|
+
discriminator = properties(repository_name).discriminator
|
25
23
|
|
26
|
-
|
27
|
-
|
24
|
+
if discriminator_value = args.first[discriminator.name]
|
25
|
+
model = discriminator.typecast_to_primitive(discriminator_value)
|
28
26
|
|
29
|
-
|
30
|
-
|
31
|
-
end
|
32
|
-
end
|
27
|
+
if model.kind_of?(Model) && !model.equal?(self)
|
28
|
+
return model.new(*args, &block)
|
33
29
|
end
|
34
|
-
|
35
|
-
super
|
36
30
|
end
|
31
|
+
end
|
37
32
|
|
38
|
-
|
33
|
+
super
|
34
|
+
end
|
39
35
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
36
|
+
private
|
37
|
+
|
38
|
+
def set_discriminator_scope_for(model)
|
39
|
+
discriminator = self.properties.discriminator
|
40
|
+
default_scope = model.default_scope(discriminator.repository_name)
|
41
|
+
default_scope.update(discriminator.name => model.descendants.dup << model)
|
42
|
+
end
|
45
43
|
end
|
46
44
|
end # class Discriminator
|
47
45
|
end # module Property
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'dm-core/property/typecast/numeric'
|
2
|
-
|
3
1
|
module DataMapper
|
4
2
|
class Property
|
5
3
|
class Numeric < Object
|
@@ -9,9 +7,8 @@ module DataMapper
|
|
9
7
|
accept_options :precision, :scale, :min, :max
|
10
8
|
attr_reader :precision, :scale, :min, :max
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
DEFAULT_NUMERIC_MAX = 2**31-1
|
10
|
+
DEFAULT_NUMERIC_MIN = 0
|
11
|
+
DEFAULT_NUMERIC_MAX = 2**31-1
|
15
12
|
|
16
13
|
protected
|
17
14
|
|
@@ -19,8 +16,8 @@ module DataMapper
|
|
19
16
|
super
|
20
17
|
|
21
18
|
if @primitive == BigDecimal || @primitive == ::Float
|
22
|
-
@precision = @options.fetch(:precision
|
23
|
-
@scale = @options.fetch(:scale
|
19
|
+
@precision = @options.fetch(:precision)
|
20
|
+
@scale = @options.fetch(:scale)
|
24
21
|
|
25
22
|
unless @precision > 0
|
26
23
|
raise ArgumentError, "precision must be greater than 0, but was #{@precision.inspect}"
|
@@ -28,8 +25,8 @@ module DataMapper
|
|
28
25
|
end
|
29
26
|
|
30
27
|
if @options.key?(:min) || @options.key?(:max)
|
31
|
-
@min = @options.fetch(:min, DEFAULT_NUMERIC_MIN)
|
32
|
-
@max = @options.fetch(:max, DEFAULT_NUMERIC_MAX)
|
28
|
+
@min = @options.fetch(:min, self.class::DEFAULT_NUMERIC_MIN)
|
29
|
+
@max = @options.fetch(:max, self.class::DEFAULT_NUMERIC_MAX)
|
33
30
|
|
34
31
|
if @max < DEFAULT_NUMERIC_MIN && !@options.key?(:min)
|
35
32
|
raise ArgumentError, "min should be specified when the max is less than #{DEFAULT_NUMERIC_MIN}"
|