virtus 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,13 @@
1
- # v0.5.3 2012-09-01 2012-12-13
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)
@@ -1,5 +1,5 @@
1
1
  group :development do
2
- gem 'rake', '~> 0.9.2'
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.0'
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
@@ -83,7 +83,9 @@ module Virtus
83
83
  case class_or_name
84
84
  when ::Class
85
85
  Attribute::EmbeddedValue.determine_type(class_or_name) || super
86
- when ::Array, ::Set, ::Hash
86
+ when ::String
87
+ super
88
+ when ::Enumerable
87
89
  super(class_or_name.class)
88
90
  else
89
91
  super
@@ -75,12 +75,10 @@ module Virtus
75
75
  # @api private
76
76
  def initialize(*)
77
77
  super
78
- if @options.has_key?(:key_type) && @options.has_key?(:value_type)
79
- @key_type = @options[:key_type]
80
- @value_type = @options[:value_type]
81
- @key_type_instance = Attribute.build(@name, @key_type)
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 |key_and_value, hash|
97
- key = @key_type_instance.coerce(key_and_value[0])
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|[1-9]\d*)/.freeze
12
+ INTEGER_REGEXP = /[-+]?(?:[0-9]\d*)/.freeze
13
13
  EXPONENT_REGEXP = /(?:[eE][-+]?\d+)/.freeze
14
14
  FRACTIONAL_REGEXP = /(?:\.\d+)/.freeze
15
15
 
@@ -1,3 +1,3 @@
1
1
  module Virtus
2
- VERSION = '0.5.3'
2
+ VERSION = '0.5.4'
3
3
  end
@@ -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, '00.0', '0.', '-.0', 'string' ].each do |non_num_value|
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, '00.0', '0.', '-.0', 'string' ].each do |non_num_value|
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, '00.0', '0.', '-.0', 'string' ].each do |non_num_value|
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
 
@@ -18,7 +18,4 @@ Gem::Specification.new do |gem|
18
18
 
19
19
  gem.add_dependency('backports', '~> 2.6.1')
20
20
  gem.add_dependency('descendants_tracker', '~> 0.0.1')
21
-
22
- gem.add_development_dependency('rake', '~> 0.9.2')
23
- gem.add_development_dependency('rspec', '~> 2.12')
24
21
  end
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.3
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-13 00:00:00.000000000 Z
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