virtus 0.5.3 → 0.5.4
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/Changelog.md +10 -1
- data/Gemfile.devtools +2 -2
- data/lib/virtus/attribute.rb +3 -1
- data/lib/virtus/attribute/hash.rb +6 -10
- data/lib/virtus/coercion/float.rb +15 -0
- data/lib/virtus/coercion/integer.rb +23 -0
- data/lib/virtus/coercion/string.rb +1 -1
- data/lib/virtus/version.rb +1 -1
- data/spec/unit/virtus/attribute/class_methods/determine_type_spec.rb +42 -0
- data/spec/unit/virtus/attribute/date_time/coerce_spec.rb +12 -0
- data/spec/unit/virtus/attribute/decimal/coerce_spec.rb +7 -1
- data/spec/unit/virtus/attribute/float/coerce_spec.rb +7 -1
- data/spec/unit/virtus/attribute/hash/coerce_spec.rb +8 -0
- data/spec/unit/virtus/attribute/integer/coerce_spec.rb +7 -1
- data/virtus.gemspec +0 -3
- metadata +2 -34
data/Changelog.md
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
-
# v0.5.
|
1
|
+
# v0.5.4 2012-12-20
|
2
|
+
|
3
|
+
* [feature] Allow *any* enumerable to be a collection attribute (aptinio)
|
4
|
+
* [feature] Add Integer.to_datetime and Float.to_datetime coercion (brutuscat)
|
5
|
+
* [fixed] Fixed a regression with Hash attribute introduced by key/member coercion (shingara)
|
6
|
+
* [fixed] Change leading non-significant digit type coercion to be coerced (maskact)
|
7
|
+
|
8
|
+
[Compare v0.5.3..v0.5.4](https://github.com/solnic/virtus/compare/v0.5.3...v0.5.4)
|
9
|
+
|
10
|
+
# v0.5.3 2012-12-13
|
2
11
|
|
3
12
|
* [feature] Added Hash member type coercion [example](https://github.com/solnic/virtus#hash-attributes-coercion) (greyblake)
|
4
13
|
* [fixed] Fixed issues with String=>Integer coercion and e-notation (greyblake)
|
data/Gemfile.devtools
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
group :development do
|
2
|
-
gem 'rake', '~> 0
|
2
|
+
gem 'rake', '~> 10.0'
|
3
3
|
gem 'rspec', '~> 2.12.0'
|
4
4
|
gem 'yard', '~> 0.8.3'
|
5
5
|
end
|
@@ -27,7 +27,7 @@ group :metrics do
|
|
27
27
|
gem 'reek', '~> 1.2.8', :git => 'https://github.com/dkubb/reek.git'
|
28
28
|
gem 'roodi', '~> 2.1.0'
|
29
29
|
gem 'yardstick', '~> 0.8.0'
|
30
|
-
gem 'mutant', '~> 0.2.
|
30
|
+
gem 'mutant', '~> 0.2.6'
|
31
31
|
|
32
32
|
platforms :ruby_18, :ruby_19 do
|
33
33
|
# this indirectly depends on ffi which does not build on ruby-head
|
data/lib/virtus/attribute.rb
CHANGED
@@ -75,12 +75,10 @@ module Virtus
|
|
75
75
|
# @api private
|
76
76
|
def initialize(*)
|
77
77
|
super
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
@value_type_instance = Attribute.build(@name, @value_type)
|
83
|
-
end
|
78
|
+
@key_type = @options[:key_type] || Object
|
79
|
+
@value_type = @options[:value_type] || Object
|
80
|
+
@key_type_instance = Attribute.build(@name, @key_type)
|
81
|
+
@value_type_instance = Attribute.build(@name, @value_type)
|
84
82
|
end
|
85
83
|
|
86
84
|
# Coerce a hash with keys and values
|
@@ -93,10 +91,8 @@ module Virtus
|
|
93
91
|
def coerce(value)
|
94
92
|
coerced = super
|
95
93
|
return coerced unless coerced.respond_to?(:each_with_object)
|
96
|
-
coerced.each_with_object({}) do |
|
97
|
-
key
|
98
|
-
value = @value_type_instance.coerce(key_and_value[1])
|
99
|
-
hash[key] = value
|
94
|
+
coerced.each_with_object({}) do |(key, value), hash|
|
95
|
+
hash[@key_type_instance.coerce(key)] = @value_type_instance.coerce(value)
|
100
96
|
end
|
101
97
|
end
|
102
98
|
|
@@ -19,6 +19,21 @@ module Virtus
|
|
19
19
|
value
|
20
20
|
end
|
21
21
|
|
22
|
+
# Coerce given value to a DateTime
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# datetime = Virtus::Coercion::Float.to_datetime(1000000000.999) # => Sun, 09 Sep 2001 01:46:40 +0000
|
26
|
+
# datetime.to_f # => 1000000000.999
|
27
|
+
#
|
28
|
+
# @param [Float] value
|
29
|
+
#
|
30
|
+
# @return [DateTime]
|
31
|
+
#
|
32
|
+
# @api public
|
33
|
+
def self.to_datetime(value)
|
34
|
+
::DateTime.strptime((value * 10**3).to_s, "%Q")
|
35
|
+
end
|
36
|
+
|
22
37
|
end # class Float
|
23
38
|
end # class Coercion
|
24
39
|
end # module Virtus
|
@@ -55,6 +55,29 @@ module Virtus
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
+
# Coerce given value to a DateTime
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# Virtus::Coercion::Fixnum.to_datetime(0) # => Thu, 01 Jan 1970 00:00:00 +0000
|
62
|
+
#
|
63
|
+
# @param [Integer] value
|
64
|
+
#
|
65
|
+
# @return [DateTime]
|
66
|
+
#
|
67
|
+
# @api public
|
68
|
+
def self.to_datetime(value)
|
69
|
+
# FIXME: Remove after Rubinius 2.0 is released
|
70
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
71
|
+
datetime_format = '%Q'
|
72
|
+
value = "#{value * 10**3}"
|
73
|
+
else
|
74
|
+
datetime_format = '%s'
|
75
|
+
value = "#{value}"
|
76
|
+
end
|
77
|
+
|
78
|
+
::DateTime.strptime(value, datetime_format)
|
79
|
+
end
|
80
|
+
|
58
81
|
end # class Fixnum
|
59
82
|
end # class Coercion
|
60
83
|
end # module Virtus
|
@@ -9,7 +9,7 @@ module Virtus
|
|
9
9
|
FALSE_VALUES = %w[ 0 off f false n no ].freeze
|
10
10
|
BOOLEAN_MAP = ::Hash[ TRUE_VALUES.product([ true ]) + FALSE_VALUES.product([ false ]) ].freeze
|
11
11
|
|
12
|
-
INTEGER_REGEXP = /[-+]?(?:0
|
12
|
+
INTEGER_REGEXP = /[-+]?(?:[0-9]\d*)/.freeze
|
13
13
|
EXPONENT_REGEXP = /(?:[eE][-+]?\d+)/.freeze
|
14
14
|
FRACTIONAL_REGEXP = /(?:\.\d+)/.freeze
|
15
15
|
|
data/lib/virtus/version.rb
CHANGED
@@ -72,4 +72,46 @@ describe Virtus::Attribute, '.determine_type' do
|
|
72
72
|
|
73
73
|
it { should equal(Virtus::Attribute::Set) }
|
74
74
|
end
|
75
|
+
|
76
|
+
context 'with an instance of an enumerable' do
|
77
|
+
before do
|
78
|
+
module Examples
|
79
|
+
class EnumerableClass
|
80
|
+
include Enumerable
|
81
|
+
|
82
|
+
def self.[](*args)
|
83
|
+
new
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class EnumerableAttribute < Virtus::Attribute::Collection
|
88
|
+
primitive EnumerableClass
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
subject { object.determine_type(primitive) }
|
94
|
+
|
95
|
+
let(:primitive) { Examples::EnumerableClass[String] }
|
96
|
+
|
97
|
+
it { should equal(Examples::EnumerableAttribute) }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'with an instance of an array subclass' do
|
101
|
+
before do
|
102
|
+
module Examples
|
103
|
+
ArraySubclass = Class.new(Array)
|
104
|
+
|
105
|
+
class ArraySubclassAttribute < Virtus::Attribute::Collection
|
106
|
+
primitive ArraySubclass
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
subject { object.determine_type(primitive) }
|
112
|
+
|
113
|
+
let(:primitive) { Examples::ArraySubclass[String] }
|
114
|
+
|
115
|
+
it { should equal(Examples::ArraySubclassAttribute) }
|
116
|
+
end
|
75
117
|
end
|
@@ -60,6 +60,18 @@ describe Virtus::Attribute::DateTime, '#coerce' do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
context 'with an integer with the seconds since the Unix Epoch' do
|
64
|
+
let(:value) { 1302139609 }
|
65
|
+
|
66
|
+
it_should_behave_like 'a correct date time'
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'with a float with the seconds and milliseconds since the Unix Epoch' do
|
70
|
+
let(:value) { 1302139609.664 }
|
71
|
+
|
72
|
+
it_should_behave_like 'a correct date time'
|
73
|
+
end
|
74
|
+
|
63
75
|
context 'with a on-date value' do
|
64
76
|
let(:value) { 'non-date' }
|
65
77
|
|
@@ -59,6 +59,12 @@ describe Virtus::Attribute::Decimal, '#coerce' do
|
|
59
59
|
it { should eql(BigDecimal('0.41')) }
|
60
60
|
end
|
61
61
|
|
62
|
+
context 'with a positive string float and leading non-significant digits' do
|
63
|
+
let (:value) { '00.0' }
|
64
|
+
|
65
|
+
it { should eql(BigDecimal('0.0')) }
|
66
|
+
end
|
67
|
+
|
62
68
|
context 'with a zero integer' do
|
63
69
|
let(:value) { 0 }
|
64
70
|
|
@@ -107,7 +113,7 @@ describe Virtus::Attribute::Decimal, '#coerce' do
|
|
107
113
|
it { should eql(BigDecimal('-24.35')) }
|
108
114
|
end
|
109
115
|
|
110
|
-
[ Object.new, true, '
|
116
|
+
[ Object.new, true, '0.', '-.0', 'string' ].each do |non_num_value|
|
111
117
|
context 'with a non-numeric value = #{non_num_value.inspect}' do
|
112
118
|
let(:value) { non_num_value }
|
113
119
|
|
@@ -59,6 +59,12 @@ describe Virtus::Attribute::Float, '#coerce' do
|
|
59
59
|
it { should eql(0.41) }
|
60
60
|
end
|
61
61
|
|
62
|
+
context 'with a positive string float and leading non-significant digits' do
|
63
|
+
let (:value) { '00.0' }
|
64
|
+
|
65
|
+
it { should eql(0.0) }
|
66
|
+
end
|
67
|
+
|
62
68
|
context 'with a zero integer' do
|
63
69
|
let(:value) { 0 }
|
64
70
|
|
@@ -107,7 +113,7 @@ describe Virtus::Attribute::Float, '#coerce' do
|
|
107
113
|
it { should eql(-24.35) }
|
108
114
|
end
|
109
115
|
|
110
|
-
[ Object.new, true, '
|
116
|
+
[ Object.new, true, '0.', '-.0', 'string' ].each do |non_num_value|
|
111
117
|
context 'does not coerce non-numeric value #{non_num_value.inspect}' do
|
112
118
|
let(:value) { non_num_value }
|
113
119
|
|
@@ -17,4 +17,12 @@ describe Virtus::Attribute::Hash, '#coerce' do
|
|
17
17
|
|
18
18
|
it { should be(:symbol) }
|
19
19
|
end
|
20
|
+
|
21
|
+
context "without Hash Coerce type define" do
|
22
|
+
let(:options) { { } }
|
23
|
+
let(:input_value) { { :one => '1', 'two' => 2 } }
|
24
|
+
|
25
|
+
it { should eq(:one => '1', 'two' => 2) }
|
26
|
+
|
27
|
+
end
|
20
28
|
end
|
@@ -59,6 +59,12 @@ describe Virtus::Attribute::Integer, '#coerce' do
|
|
59
59
|
it { should eql(0) }
|
60
60
|
end
|
61
61
|
|
62
|
+
context 'with a positive string float and leading non-significant digits' do
|
63
|
+
let (:value) { '00.0' }
|
64
|
+
|
65
|
+
it { should eql(0) }
|
66
|
+
end
|
67
|
+
|
62
68
|
context 'with a zero float' do
|
63
69
|
let(:value) { 0.0 }
|
64
70
|
|
@@ -101,7 +107,7 @@ describe Virtus::Attribute::Integer, '#coerce' do
|
|
101
107
|
it { should eql(value.to_i) }
|
102
108
|
end
|
103
109
|
|
104
|
-
[ Object.new, true, false, '
|
110
|
+
[ Object.new, true, false, '0.', '-.0', 'string' ].each do |non_num_value|
|
105
111
|
context 'does not coerce non-numeric value #{non_num_value.inspect}' do
|
106
112
|
let(:value) { non_num_value }
|
107
113
|
|
data/virtus.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: virtus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-12-
|
12
|
+
date: 2012-12-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: backports
|
@@ -43,38 +43,6 @@ dependencies:
|
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: 0.0.1
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
|
-
name: rake
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
|
-
requirements:
|
51
|
-
- - ~>
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: 0.9.2
|
54
|
-
type: :development
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
59
|
-
- - ~>
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 0.9.2
|
62
|
-
- !ruby/object:Gem::Dependency
|
63
|
-
name: rspec
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
|
-
requirements:
|
67
|
-
- - ~>
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '2.12'
|
70
|
-
type: :development
|
71
|
-
prerelease: false
|
72
|
-
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ~>
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: '2.12'
|
78
46
|
description: Attributes on Steroids for Plain Old Ruby Objects
|
79
47
|
email:
|
80
48
|
- piotr.solnica@gmail.com
|