-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
921 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# frozen_string_literal: true | ||
|
||
require "active_model/type/helpers" | ||
require "active_model/type/value" | ||
|
||
require "active_model/type/big_integer" | ||
require "active_model/type/binary" | ||
require "active_model/type/boolean" | ||
require "active_model/type/date" | ||
require "active_model/type/date_time" | ||
require "active_model/type/decimal" | ||
require "active_model/type/float" | ||
require "active_model/type/immutable_string" | ||
require "active_model/type/integer" | ||
require "active_model/type/string" | ||
require "active_model/type/time" | ||
|
||
require "active_model/type/registry" | ||
|
||
module ActiveModel | ||
module Type | ||
@registry = Registry.new | ||
|
||
class << self | ||
attr_accessor :registry # :nodoc: | ||
|
||
# Add a new type to the registry, allowing it to be get through ActiveModel::Type#lookup | ||
def register(type_name, klass = nil, **options, &block) | ||
registry.register(type_name, klass, **options, &block) | ||
end | ||
|
||
def lookup(*args, **kwargs) # :nodoc: | ||
registry.lookup(*args, **kwargs) | ||
end | ||
end | ||
|
||
register(:big_integer, Type::BigInteger) | ||
register(:binary, Type::Binary) | ||
register(:boolean, Type::Boolean) | ||
register(:date, Type::Date) | ||
register(:datetime, Type::DateTime) | ||
register(:decimal, Type::Decimal) | ||
register(:float, Type::Float) | ||
register(:immutable_string, Type::ImmutableString) | ||
register(:integer, Type::Integer) | ||
register(:string, Type::String) | ||
register(:time, Type::Time) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# frozen_string_literal: true | ||
|
||
require "active_model/type/integer" | ||
|
||
module ActiveModel | ||
module Type | ||
class BigInteger < Integer # :nodoc: | ||
private | ||
|
||
def max_value | ||
::Float::INFINITY | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
# frozen_string_literal: true | ||
|
||
module ActiveModel | ||
module Type | ||
class Binary < Value # :nodoc: | ||
def type | ||
:binary | ||
end | ||
|
||
def binary? | ||
true | ||
end | ||
|
||
def cast(value) | ||
if value.is_a?(Data) | ||
value.to_s | ||
else | ||
super | ||
end | ||
end | ||
|
||
def serialize(value) | ||
return if value.nil? | ||
Data.new(super) | ||
end | ||
|
||
def changed_in_place?(raw_old_value, value) | ||
old_value = deserialize(raw_old_value) | ||
old_value != value | ||
end | ||
|
||
class Data # :nodoc: | ||
def initialize(value) | ||
@value = value.to_s | ||
end | ||
|
||
def to_s | ||
@value | ||
end | ||
alias_method :to_str, :to_s | ||
|
||
def hex | ||
@value.unpack("H*")[0] | ||
end | ||
|
||
def ==(other) | ||
other == to_s || super | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# frozen_string_literal: true | ||
|
||
module ActiveModel | ||
module Type | ||
# == Active \Model \Type \Boolean | ||
# | ||
# A class that behaves like a boolean type, including rules for coercion of user input. | ||
# | ||
# === Coercion | ||
# Values set from user input will first be coerced into the appropriate ruby type. | ||
# Coercion behavior is roughly mapped to Ruby's boolean semantics. | ||
# | ||
# - "false", "f" , "0", +0+ or any other value in +FALSE_VALUES+ will be coerced to +false+ | ||
# - Empty strings are coerced to +nil+ | ||
# - All other values will be coerced to +true+ | ||
class Boolean < Value | ||
FALSE_VALUES = [false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"].to_set | ||
|
||
def type # :nodoc: | ||
:boolean | ||
end | ||
|
||
private | ||
|
||
def cast_value(value) | ||
if value == "" | ||
nil | ||
else | ||
!FALSE_VALUES.include?(value) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# frozen_string_literal: true | ||
|
||
module ActiveModel | ||
module Type | ||
class Date < Value # :nodoc: | ||
include Helpers::AcceptsMultiparameterTime.new | ||
|
||
def type | ||
:date | ||
end | ||
|
||
def serialize(value) | ||
cast(value) | ||
end | ||
|
||
def type_cast_for_schema(value) | ||
value.to_s(:db).inspect | ||
end | ||
|
||
private | ||
|
||
def cast_value(value) | ||
if value.is_a?(::String) | ||
return if value.empty? | ||
fast_string_to_date(value) || fallback_string_to_date(value) | ||
elsif value.respond_to?(:to_date) | ||
value.to_date | ||
else | ||
value | ||
end | ||
end | ||
|
||
ISO_DATE = /\A(\d{4})-(\d\d)-(\d\d)\z/ | ||
def fast_string_to_date(string) | ||
if string =~ ISO_DATE | ||
new_date $1.to_i, $2.to_i, $3.to_i | ||
end | ||
end | ||
|
||
def fallback_string_to_date(string) | ||
new_date(*::Date._parse(string, false).values_at(:year, :mon, :mday)) | ||
end | ||
|
||
def new_date(year, mon, mday) | ||
if year && year != 0 | ||
::Date.new(year, mon, mday) rescue nil | ||
end | ||
end | ||
|
||
def value_from_multiparameter_assignment(*) | ||
time = super | ||
time && time.to_date | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# frozen_string_literal: true | ||
|
||
module ActiveModel | ||
module Type | ||
class DateTime < Value # :nodoc: | ||
include Helpers::TimeValue | ||
include Helpers::AcceptsMultiparameterTime.new( | ||
defaults: { 4 => 0, 5 => 0 } | ||
) | ||
|
||
def type | ||
:datetime | ||
end | ||
|
||
private | ||
|
||
def cast_value(value) | ||
return apply_seconds_precision(value) unless value.is_a?(::String) | ||
return if value.empty? | ||
|
||
fast_string_to_time(value) || fallback_string_to_time(value) | ||
end | ||
|
||
# '0.123456' -> 123456 | ||
# '1.123456' -> 123456 | ||
def microseconds(time) | ||
time[:sec_fraction] ? (time[:sec_fraction] * 1_000_000).to_i : 0 | ||
end | ||
|
||
def fallback_string_to_time(string) | ||
time_hash = ::Date._parse(string) | ||
time_hash[:sec_fraction] = microseconds(time_hash) | ||
|
||
new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset)) | ||
end | ||
|
||
def value_from_multiparameter_assignment(values_hash) | ||
missing_parameter = (1..3).detect { |key| !values_hash.key?(key) } | ||
if missing_parameter | ||
raise ArgumentError, missing_parameter | ||
end | ||
super | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# frozen_string_literal: true | ||
|
||
require "bigdecimal/util" | ||
|
||
module ActiveModel | ||
module Type | ||
class Decimal < Value # :nodoc: | ||
include Helpers::Numeric | ||
BIGDECIMAL_PRECISION = 18 | ||
|
||
def type | ||
:decimal | ||
end | ||
|
||
def type_cast_for_schema(value) | ||
value.to_s.inspect | ||
end | ||
|
||
private | ||
|
||
def cast_value(value) | ||
casted_value = \ | ||
case value | ||
when ::Float | ||
convert_float_to_big_decimal(value) | ||
when ::Numeric | ||
BigDecimal(value, precision || BIGDECIMAL_PRECISION) | ||
when ::String | ||
begin | ||
value.to_d | ||
rescue ArgumentError | ||
BigDecimal(0) | ||
end | ||
else | ||
if value.respond_to?(:to_d) | ||
value.to_d | ||
else | ||
cast_value(value.to_s) | ||
end | ||
end | ||
|
||
apply_scale(casted_value) | ||
end | ||
|
||
def convert_float_to_big_decimal(value) | ||
if precision | ||
BigDecimal(apply_scale(value), float_precision) | ||
else | ||
value.to_d | ||
end | ||
end | ||
|
||
def float_precision | ||
if precision.to_i > ::Float::DIG + 1 | ||
::Float::DIG + 1 | ||
else | ||
precision.to_i | ||
end | ||
end | ||
|
||
def apply_scale(value) | ||
if scale | ||
value.round(scale) | ||
else | ||
value | ||
end | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.