virtus 0.0.5 → 0.0.6

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.
Files changed (113) hide show
  1. data/.travis.yml +9 -2
  2. data/.yardopts +1 -0
  3. data/History.md +51 -0
  4. data/{README.markdown → README.md} +63 -7
  5. data/TODO +2 -4
  6. data/VERSION +1 -1
  7. data/config/flay.yml +2 -2
  8. data/config/flog.yml +1 -1
  9. data/config/roodi.yml +5 -6
  10. data/config/site.reek +3 -3
  11. data/examples/custom_coercion_spec.rb +50 -0
  12. data/examples/default_values_spec.rb +21 -0
  13. data/lib/virtus.rb +21 -6
  14. data/lib/virtus/attribute.rb +113 -253
  15. data/lib/virtus/attribute/array.rb +6 -3
  16. data/lib/virtus/attribute/boolean.rb +9 -28
  17. data/lib/virtus/attribute/date.rb +9 -12
  18. data/lib/virtus/attribute/date_time.rb +10 -12
  19. data/lib/virtus/attribute/decimal.rb +4 -11
  20. data/lib/virtus/attribute/float.rb +4 -11
  21. data/lib/virtus/attribute/hash.rb +5 -3
  22. data/lib/virtus/attribute/integer.rb +4 -11
  23. data/lib/virtus/attribute/numeric.rb +1 -0
  24. data/lib/virtus/attribute/object.rb +1 -0
  25. data/lib/virtus/attribute/string.rb +4 -11
  26. data/lib/virtus/attribute/time.rb +9 -16
  27. data/lib/virtus/class_methods.rb +42 -7
  28. data/lib/virtus/coercion.rb +32 -0
  29. data/lib/virtus/coercion/date.rb +26 -0
  30. data/lib/virtus/coercion/date_time.rb +26 -0
  31. data/lib/virtus/coercion/decimal.rb +40 -0
  32. data/lib/virtus/coercion/false_class.rb +24 -0
  33. data/lib/virtus/coercion/float.rb +24 -0
  34. data/lib/virtus/coercion/hash.rb +82 -0
  35. data/lib/virtus/coercion/integer.rb +60 -0
  36. data/lib/virtus/coercion/numeric.rb +66 -0
  37. data/lib/virtus/coercion/object.rb +25 -0
  38. data/lib/virtus/coercion/string.rb +155 -0
  39. data/lib/virtus/coercion/symbol.rb +24 -0
  40. data/lib/virtus/coercion/time.rb +26 -0
  41. data/lib/virtus/coercion/time_coercions.rb +85 -0
  42. data/lib/virtus/coercion/true_class.rb +24 -0
  43. data/lib/virtus/instance_methods.rb +7 -0
  44. data/lib/virtus/support/descendants_tracker.rb +1 -1
  45. data/lib/virtus/support/options.rb +114 -0
  46. data/lib/virtus/support/type_lookup.rb +95 -0
  47. data/spec/integration/virtus/attributes/attribute/{typecast_spec.rb → set_spec.rb} +7 -7
  48. data/spec/unit/shared/attribute.rb +3 -3
  49. data/spec/unit/shared/attribute/accept_options.rb +0 -18
  50. data/spec/unit/shared/attribute/accepted_options.rb +0 -6
  51. data/spec/unit/shared/attribute/get.rb +32 -17
  52. data/spec/unit/shared/attribute/inspect.rb +7 -0
  53. data/spec/unit/shared/attribute/primitive.rb +15 -0
  54. data/spec/unit/shared/attribute/set.rb +16 -21
  55. data/spec/unit/virtus/attribute/array_spec.rb +18 -3
  56. data/spec/unit/virtus/attribute/boolean_spec.rb +8 -6
  57. data/spec/unit/virtus/attribute/date_spec.rb +8 -6
  58. data/spec/unit/virtus/attribute/date_time_spec.rb +8 -6
  59. data/spec/unit/virtus/attribute/decimal_spec.rb +18 -6
  60. data/spec/unit/virtus/attribute/float_spec.rb +19 -7
  61. data/spec/unit/virtus/attribute/hash_spec.rb +5 -3
  62. data/spec/unit/virtus/attribute/integer_spec.rb +10 -8
  63. data/spec/unit/virtus/attribute/string_spec.rb +10 -8
  64. data/spec/unit/virtus/attribute/time_spec.rb +8 -6
  65. data/spec/unit/virtus/class_methods/attributes_spec.rb +11 -0
  66. data/spec/unit/virtus/coercion/class_name_reference_spec.rb +17 -0
  67. data/spec/unit/virtus/coercion/date/class_methods/to_datetime_spec.rb +30 -0
  68. data/spec/unit/virtus/coercion/date/class_methods/to_string_spec.rb +12 -0
  69. data/spec/unit/virtus/coercion/date/class_methods/to_time_spec.rb +12 -0
  70. data/spec/unit/virtus/coercion/date_time/class_methods/to_date_spec.rb +30 -0
  71. data/spec/unit/virtus/coercion/date_time/class_methods/to_string_spec.rb +12 -0
  72. data/spec/unit/virtus/coercion/date_time/class_methods/to_time_spec.rb +30 -0
  73. data/spec/unit/virtus/coercion/decimal/class_methods/to_float_spec.rb +12 -0
  74. data/spec/unit/virtus/coercion/decimal/class_methods/to_integer_spec.rb +12 -0
  75. data/spec/unit/virtus/coercion/decimal/class_methods/to_string_spec.rb +12 -0
  76. data/spec/unit/virtus/coercion/false_class/class_methods/to_string_spec.rb +12 -0
  77. data/spec/unit/virtus/coercion/float/class_methods/to_decimal_spec.rb +12 -0
  78. data/spec/unit/virtus/coercion/float/class_methods/to_integer_spec.rb +12 -0
  79. data/spec/unit/virtus/coercion/float/class_methods/to_string_spec.rb +12 -0
  80. data/spec/unit/virtus/coercion/hash/class_methods/to_array_spec.rb +12 -0
  81. data/spec/unit/virtus/coercion/hash/class_methods/to_date_spec.rb +31 -0
  82. data/spec/unit/virtus/coercion/hash/class_methods/to_datetime_spec.rb +31 -0
  83. data/spec/unit/virtus/coercion/hash/class_methods/to_time_spec.rb +31 -0
  84. data/spec/unit/virtus/coercion/integer/class_methods/to_boolean_spec.rb +25 -0
  85. data/spec/unit/virtus/coercion/integer/class_methods/to_decimal_spec.rb +12 -0
  86. data/spec/unit/virtus/coercion/integer/class_methods/to_float_spec.rb +12 -0
  87. data/spec/unit/virtus/coercion/integer/class_methods/to_string_spec.rb +12 -0
  88. data/spec/unit/virtus/coercion/object/class_methods/method_missing_spec.rb +33 -0
  89. data/spec/unit/virtus/coercion/string/class_methods/to_boolean_spec.rb +29 -0
  90. data/spec/unit/virtus/coercion/string/class_methods/to_date_spec.rb +23 -0
  91. data/spec/unit/virtus/coercion/string/class_methods/to_datetime_spec.rb +50 -0
  92. data/spec/unit/virtus/coercion/string/class_methods/to_decimal_spec.rb +23 -0
  93. data/spec/unit/virtus/coercion/string/class_methods/to_float_spec.rb +21 -0
  94. data/spec/unit/virtus/coercion/string/class_methods/to_integer_spec.rb +21 -0
  95. data/spec/unit/virtus/coercion/string/class_methods/to_time_spec.rb +50 -0
  96. data/spec/unit/virtus/coercion/symbol/class_methods/to_string_spec.rb +12 -0
  97. data/spec/unit/virtus/coercion/true_class/class_methods/to_string_spec.rb +12 -0
  98. data/spec/unit/virtus/instance_methods/attributes_spec.rb +7 -0
  99. data/spec/unit/virtus/options/accept_options_spec.rb +38 -0
  100. data/spec/unit/virtus/options/accepted_options_spec.rb +21 -0
  101. data/spec/unit/virtus/options/options_spec.rb +11 -0
  102. data/spec/unit/virtus/type_lookup/determine_type_spec.rb +68 -0
  103. data/spec/unit/virtus/type_lookup/primitive_spec.rb +9 -0
  104. data/virtus.gemspec +70 -17
  105. metadata +78 -27
  106. data/History.txt +0 -38
  107. data/lib/virtus/typecast/boolean.rb +0 -29
  108. data/lib/virtus/typecast/numeric.rb +0 -87
  109. data/lib/virtus/typecast/string.rb +0 -24
  110. data/lib/virtus/typecast/time.rb +0 -192
  111. data/spec/unit/shared/attribute/complex.rb +0 -15
  112. data/spec/unit/shared/attribute/options.rb +0 -7
  113. data/spec/unit/virtus/attribute/attribute_spec.rb +0 -12
@@ -2,18 +2,20 @@ require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute::String do
4
4
  it_should_behave_like 'Attribute' do
5
- let(:attribute_name) { :email }
6
- let(:attribute_value) { 'red john' }
7
- let(:attribute_value_other) { :'red john' }
5
+ let(:attribute_name) { :email }
6
+ let(:attribute_value) { 'red john' }
7
+ let(:attribute_value_other) { :'red john' }
8
+ let(:attribute_default) { '' }
9
+ let(:attribute_default_proc) { lambda { |instance, attribute| attribute.name == :email } }
8
10
  end
9
11
 
10
- describe '#typecast' do
11
- let(:attribute) { Virtus::Attribute::String.new(:name) }
12
+ describe '#coerce' do
13
+ let(:attribute) { described_class.new(:name) }
12
14
  let(:value) { 1 }
13
- let(:typecast_value) { '1' }
15
+ let(:coerce_value) { '1' }
14
16
 
15
- subject { attribute.typecast(value) }
17
+ subject { attribute.coerce(value) }
16
18
 
17
- it { should eql(typecast_value) }
19
+ it { should eql(coerce_value) }
18
20
  end
19
21
  end
@@ -2,13 +2,15 @@ require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute::Time do
4
4
  it_should_behave_like 'Attribute' do
5
- let(:attribute_name) { :birthday }
6
- let(:attribute_value) { Time.now }
7
- let(:attribute_value_other) { Time.now.to_s }
5
+ let(:attribute_name) { :birthday }
6
+ let(:attribute_value) { Time.now }
7
+ let(:attribute_value_other) { Time.now.to_s }
8
+ let(:attribute_default) { Time.now-1 }
9
+ let(:attribute_default_proc) { lambda { |instance, attribute| attribute.name == :birthday } }
8
10
  end
9
11
 
10
- describe '#typecast' do
11
- let(:attribute) { Virtus::Attribute::Time.new(:bday) }
12
+ describe '#coerce' do
13
+ let(:attribute) { described_class.new(:bday) }
12
14
 
13
15
  let(:year) { 1983 }
14
16
  let(:month) { 11 }
@@ -17,7 +19,7 @@ describe Virtus::Attribute::Time do
17
19
  let(:min) { 16 }
18
20
  let(:sec) { 32 }
19
21
 
20
- subject { attribute.typecast(value) }
22
+ subject { attribute.coerce(value) }
21
23
 
22
24
  shared_examples_for "a correct time" do
23
25
  it { should be_kind_of(Time) }
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::ClassMethods, '.attributes' do
4
+ subject { described_class.attributes }
5
+
6
+ let(:described_class) do
7
+ Class.new { extend Virtus::ClassMethods }
8
+ end
9
+
10
+ it { should be_instance_of(Virtus::AttributeSet) }
11
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion, '#[]' do
4
+ %w[ Decimal Date DateTime FalseClass Integer Float Hash String Symbol Time TrueClass ].each do |class_name|
5
+ context "with #{class_name.inspect}" do
6
+ subject { described_class[class_name] }
7
+
8
+ it { should == described_class.const_get(class_name) }
9
+ end
10
+ end
11
+
12
+ context 'with a name of a class not defined in Coercion' do
13
+ subject { described_class['Set'] }
14
+
15
+ it { should == Virtus::Coercion::Object }
16
+ end
17
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Date, '.to_datetime' do
4
+ subject { object.to_datetime(date) }
5
+
6
+ let(:object) { described_class }
7
+ let(:date) { Date.new(2011, 1, 1) }
8
+
9
+ context 'when Date does not support #to_datetime' do
10
+ if RUBY_VERSION < '1.9'
11
+ before do
12
+ date.should_not respond_to(:to_datetime)
13
+ end
14
+ end
15
+
16
+ it { should be_instance_of(DateTime) }
17
+
18
+ it { should eql(DateTime.new(2011, 1, 1)) }
19
+ end
20
+
21
+ context 'when Date supports #to_datetime' do
22
+ let(:datetime) { DateTime.new(2011, 1, 1) }
23
+
24
+ before do
25
+ date.stub!(:to_datetime).and_return(datetime)
26
+ end
27
+
28
+ it { should equal(datetime) }
29
+ end
30
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Date, '.to_string' do
4
+ subject { object.to_string(date) }
5
+
6
+ let(:object) { described_class }
7
+ let(:date) { Date.new(2011, 1, 1) }
8
+
9
+ it { should be_instance_of(String) }
10
+
11
+ it { should eql('2011-01-01') }
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Date, '.to_time' do
4
+ subject { object.to_time(date) }
5
+
6
+ let(:object) { described_class }
7
+ let(:date) { Date.new(2011, 1, 1) }
8
+
9
+ it { should be_instance_of(Time) }
10
+
11
+ it { should eql(Time.local(2011, 1, 1)) }
12
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::DateTime, '.to_date' do
4
+ subject { object.to_date(date_time) }
5
+
6
+ let(:object) { described_class }
7
+ let(:date_time) { DateTime.new(2011, 1, 1) }
8
+
9
+ context 'when DateTime does not support #to_date' do
10
+ if RUBY_VERSION < '1.9'
11
+ before do
12
+ date_time.should_not respond_to(:to_date)
13
+ end
14
+ end
15
+
16
+ it { should be_instance_of(Date) }
17
+
18
+ it { should eql(Date.new(2011, 1, 1)) }
19
+ end
20
+
21
+ context 'when DateTime supports #to_date' do
22
+ let(:date) { Date.new(2011, 1, 1) }
23
+
24
+ before do
25
+ date_time.stub!(:to_date).and_return(date)
26
+ end
27
+
28
+ it { should equal(date) }
29
+ end
30
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::DateTime, '.to_string' do
4
+ subject { object.to_string(date_time) }
5
+
6
+ let(:object) { described_class }
7
+ let(:date_time) { DateTime.new(2011, 1, 1, 0, 0, 0, 0) }
8
+
9
+ it { should be_instance_of(String) }
10
+
11
+ it { should eql('2011-01-01T00:00:00+00:00') }
12
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::DateTime, '.to_time' do
4
+ subject { object.to_time(date_time) }
5
+
6
+ let(:object) { described_class }
7
+ let(:date_time) { DateTime.new(2011, 1, 1) }
8
+
9
+ context 'when DateTime does not support #to_time' do
10
+ if RUBY_VERSION < '1.9'
11
+ before do
12
+ date_time.should_not respond_to(:to_time)
13
+ end
14
+ end
15
+
16
+ it { should be_instance_of(Time) }
17
+
18
+ it { should eql(Time.local(2011, 1, 1)) }
19
+ end
20
+
21
+ context 'when DateTime supports #to_time' do
22
+ let(:time) { Time.local(2011, 1, 1) }
23
+
24
+ before do
25
+ date_time.stub!(:to_time).and_return(time)
26
+ end
27
+
28
+ it { should equal(time) }
29
+ end
30
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Decimal, '.to_float' do
4
+ subject { object.to_float(big_decimal) }
5
+
6
+ let(:object) { described_class }
7
+ let(:big_decimal) { BigDecimal('1.0') }
8
+
9
+ it { should be_instance_of(Float) }
10
+
11
+ it { should eql(1.0) }
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Decimal, '.to_integer' do
4
+ subject { object.to_integer(big_decimal) }
5
+
6
+ let(:object) { described_class }
7
+ let(:big_decimal) { BigDecimal('1.0') }
8
+
9
+ it { should be_kind_of(Integer) }
10
+
11
+ it { should eql(1) }
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Decimal, '.to_string' do
4
+ subject { object.to_string(big_decimal) }
5
+
6
+ let(:object) { described_class }
7
+ let(:big_decimal) { BigDecimal('1.0') }
8
+
9
+ it { should be_instance_of(String) }
10
+
11
+ it { should eql('1.0') }
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::FalseClass, '.to_string' do
4
+ subject { object.to_string(false_class) }
5
+
6
+ let(:object) { described_class }
7
+ let(:false_class) { false }
8
+
9
+ it { should be_instance_of(String) }
10
+
11
+ it { should eql('false') }
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Float, '.to_decimal' do
4
+ subject { object.to_decimal(float) }
5
+
6
+ let(:object) { described_class }
7
+ let(:float) { 1.0 }
8
+
9
+ it { should be_instance_of(BigDecimal) }
10
+
11
+ it { should eql(BigDecimal('1.0')) }
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Float, '.to_integer' do
4
+ subject { object.to_integer(float) }
5
+
6
+ let(:object) { described_class }
7
+ let(:float) { 1.0 }
8
+
9
+ it { should be_kind_of(Integer) }
10
+
11
+ it { should eql(1) }
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Float, '.to_string' do
4
+ subject { object.to_string(float) }
5
+
6
+ let(:object) { described_class }
7
+ let(:float) { 1.0 }
8
+
9
+ it { should be_instance_of(String) }
10
+
11
+ it { should eql('1.0') }
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Hash, '.to_array' do
4
+ subject { object.to_array(hash) }
5
+
6
+ let(:object) { described_class }
7
+ let(:hash) { { 'a' => 1, 'b' => 2 } }
8
+
9
+ it { should be_instance_of(Array) }
10
+
11
+ it { should =~ [ [ 'a', 1 ], [ 'b', 2 ] ] }
12
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Hash, '.to_date' do
4
+ subject { object.to_date(hash) }
5
+
6
+ let(:object) { described_class }
7
+
8
+ context 'when time segments are missing' do
9
+ let(:time_now) { Time.local(2011, 1, 1) }
10
+ let(:hash) { {} }
11
+
12
+ before do
13
+ now = time_now
14
+ Time.stub!(:now).and_return(now) # freeze time
15
+ end
16
+
17
+ it { should be_instance_of(Date) }
18
+
19
+ it 'uses the Time now to populate the segments' do
20
+ should eql(Date.new(2011, 1, 1))
21
+ end
22
+ end
23
+
24
+ context 'when time segments are populated' do
25
+ let(:hash) { { :year => 2011, :month => 1, :day => 1 } }
26
+
27
+ it { should be_instance_of(Date) }
28
+
29
+ it { should eql(Date.new(2011, 1, 1)) }
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Hash, '.to_datetime' do
4
+ subject { object.to_datetime(hash) }
5
+
6
+ let(:object) { described_class }
7
+
8
+ context 'when time segments are missing' do
9
+ let(:time_now) { Time.local(2011, 1, 1) }
10
+ let(:hash) { {} }
11
+
12
+ before do
13
+ now = time_now
14
+ Time.stub!(:now).and_return(now) # freeze time
15
+ end
16
+
17
+ it { should be_instance_of(DateTime) }
18
+
19
+ it 'uses the Time now to populate the segments' do
20
+ should eql(DateTime.new(2011, 1, 1))
21
+ end
22
+ end
23
+
24
+ context 'when time segments are populated' do
25
+ let(:hash) { { :year => 2011, :month => 1, :day => 1, :hour => 1, :min => 1, :sec => 1 } }
26
+
27
+ it { should be_instance_of(DateTime) }
28
+
29
+ it { should eql(DateTime.new(2011, 1, 1, 1, 1, 1)) }
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Hash, '.to_time' do
4
+ subject { object.to_time(hash) }
5
+
6
+ let(:object) { described_class }
7
+
8
+ context 'when time segments are missing' do
9
+ let(:time_now) { Time.local(2011, 1, 1) }
10
+ let(:hash) { {} }
11
+
12
+ before do
13
+ now = time_now
14
+ Time.stub!(:now).and_return(now) # freeze time
15
+ end
16
+
17
+ it { should be_instance_of(Time) }
18
+
19
+ it 'uses the Time now to populate the segments' do
20
+ should eql(time_now)
21
+ end
22
+ end
23
+
24
+ context 'when time segments are populated' do
25
+ let(:hash) { { :year => 2011, :month => 1, :day => 1, :hour => 1, :min => 1, :sec => 1 } }
26
+
27
+ it { should be_instance_of(Time) }
28
+
29
+ it { should eql(Time.local(2011, 1, 1, 1, 1, 1)) }
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Integer, '.to_boolean' do
4
+ subject { object.to_boolean(fixnum) }
5
+
6
+ let(:object) { described_class }
7
+
8
+ context 'when the fixnum is 1' do
9
+ let(:fixnum) { 1 }
10
+
11
+ it { should be(true) }
12
+ end
13
+
14
+ context 'when the fixnum is 0' do
15
+ let(:fixnum) { 0 }
16
+
17
+ it { should be(false) }
18
+ end
19
+
20
+ context 'when the fixnum is not 1 or 0' do
21
+ let(:fixnum) { -1 }
22
+
23
+ it { should be(-1) }
24
+ end
25
+ end