def initialize(model, name, type, options = {})
assert_kind_of 'model', model, Model
assert_kind_of 'name', name, Symbol
assert_kind_of 'type', type, Class, Module
assert_kind_of 'options', options, Hash
options = options.dup
if TrueClass == type
warn "#{type} is deprecated, use Boolean instead at #{caller[2]}"
type = Types::Boolean
elsif Integer == type && options.delete(:serial)
warn "#{type} with explicit :serial option is deprecated, use Serial instead (#{caller[2]})"
type = Types::Serial
elsif options.key?(:size)
if String == type
warn ":size option is deprecated, use #{type} with :length instead (#{caller[2]})"
length = options.delete(:size)
options[:length] = length unless options.key?(:length)
elsif Numeric > type
warn ":size option is deprecated, specify :min and :max instead (#{caller[2]})"
end
end
assert_valid_options(options)
unless type.name.blank?
type = Types.find_const(type.name)
end
unless PRIMITIVES.include?(type) || (Type > type && PRIMITIVES.include?(type.primitive))
raise ArgumentError, "+type+ was #{type.inspect}, which is not a supported type"
end
@repository_name = model.repository_name
@model = model
@name = name.to_s.sub(/\?$/, '').to_sym
@type = type
@custom = Type > @type
@options = (@custom ? @type.options.merge(options) : options.dup).freeze
@instance_variable_name = "@#{@name}".freeze
@primitive = @type.respond_to?(:primitive) ? @type.primitive : @type
@field = @options[:field].freeze
@default = @options[:default]
@serial = @options.fetch(:serial, false)
@key = @options.fetch(:key, @serial || false)
@nullable = @options.fetch(:nullable, @key == false)
@index = @options.fetch(:index, nil)
@unique_index = @options.fetch(:unique_index, nil)
@unique = @options.fetch(:unique, @serial || @key || false)
@lazy = @options.fetch(:lazy, @type.respond_to?(:lazy) ? @type.lazy : false) && !@key
if String == @primitive || Class == @primitive
@length = @options.fetch(:length, DEFAULT_LENGTH)
elsif BigDecimal == @primitive || Float == @primitive
@precision = @options.fetch(:precision, DEFAULT_PRECISION)
@scale = @options.fetch(:scale, Float == @primitive ? DEFAULT_SCALE_FLOAT : DEFAULT_SCALE_BIGDECIMAL)
unless @precision > 0
raise ArgumentError, "precision must be greater than 0, but was #{@precision.inspect}"
end
unless Float == @primitive && @scale.nil?
unless @scale >= 0
raise ArgumentError, "scale must be equal to or greater than 0, but was #{@scale.inspect}"
end
unless @precision >= @scale
raise ArgumentError, "precision must be equal to or greater than scale, but was #{@precision.inspect} and scale was #{@scale.inspect}"
end
end
end
if Numeric > @primitive && (@options.keys & [ :min, :max ]).any?
@min = @options.fetch(:min, DEFAULT_NUMERIC_MIN)
@max = @options.fetch(:max, DEFAULT_NUMERIC_MAX)
if @max < DEFAULT_NUMERIC_MIN && !@options.key?(:min)
raise ArgumentError, "min should be specified when the max is less than #{DEFAULT_NUMERIC_MIN}"
elsif @max < @min
raise ArgumentError, "max must be less than the min, but was #{@max} while the min was #{@min}"
end
end
determine_visibility
if custom?
type.bind(self)
end
@model.auto_generate_validations(self) if @model.respond_to?(:auto_generate_validations)
end