virtus 0.4.0 → 0.4.1

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 (69) hide show
  1. data/.travis.yml +1 -0
  2. data/Changelog.md +9 -1
  3. data/Gemfile +1 -1
  4. data/Guardfile +0 -1
  5. data/README.md +0 -2
  6. data/Rakefile +0 -1
  7. data/config/flay.yml +1 -1
  8. data/config/flog.yml +1 -1
  9. data/config/site.reek +1 -1
  10. data/lib/virtus.rb +4 -2
  11. data/lib/virtus/attribute.rb +2 -2
  12. data/lib/virtus/attribute/boolean.rb +1 -1
  13. data/lib/virtus/attribute/default_value.rb +4 -14
  14. data/lib/virtus/attribute/default_value/from_callable.rb +5 -3
  15. data/lib/virtus/attribute/default_value/from_clonable.rb +4 -4
  16. data/lib/virtus/attribute/default_value/from_symbol.rb +4 -4
  17. data/lib/virtus/attribute/embedded_value.rb +0 -2
  18. data/lib/virtus/class_methods.rb +1 -1
  19. data/lib/virtus/coercion.rb +1 -1
  20. data/lib/virtus/coercion/numeric.rb +12 -12
  21. data/lib/virtus/coercion/object.rb +1 -1
  22. data/lib/virtus/support/equalizer.rb +129 -0
  23. data/lib/virtus/support/type_lookup.rb +2 -2
  24. data/lib/virtus/value_object.rb +0 -5
  25. data/lib/virtus/version.rb +1 -1
  26. data/spec/spec_helper.rb +0 -3
  27. data/spec/unit/virtus/attribute/default_spec.rb +0 -4
  28. data/spec/unit/virtus/attribute/default_value/call_spec.rb +21 -0
  29. data/spec/unit/virtus/attribute/default_value/class_methods/build_spec.rb +1 -3
  30. data/spec/unit/virtus/attribute/default_value/class_methods/new_spec.rb +1 -3
  31. data/spec/unit/virtus/attribute/default_value/from_callable/call_spec.rb +19 -0
  32. data/spec/unit/virtus/attribute/default_value/from_callable/class_methods/handle_spec.rb +1 -4
  33. data/spec/unit/virtus/attribute/default_value/from_clonable/call_spec.rb +20 -0
  34. data/spec/unit/virtus/attribute/default_value/from_clonable/class_methods/handle_spec.rb +1 -2
  35. data/spec/unit/virtus/attribute/default_value/from_symbol/{evaluate_spec.rb → call_spec.rb} +3 -4
  36. data/spec/unit/virtus/attribute/default_value/from_symbol/class_methods/handle_spec.rb +1 -4
  37. data/spec/unit/virtus/attribute/default_value/value_spec.rb +2 -3
  38. data/spec/unit/virtus/attributes_accessor/define_reader_method_spec.rb +0 -1
  39. data/spec/unit/virtus/attributes_accessor/define_writer_method_spec.rb +0 -1
  40. data/spec/unit/virtus/coercion/decimal/class_methods/to_decimal_spec.rb +0 -1
  41. data/spec/unit/virtus/coercion/float/class_methods/to_float_spec.rb +0 -1
  42. data/spec/unit/virtus/coercion/integer/class_methods/to_integer_spec.rb +0 -1
  43. data/spec/unit/virtus/coercion/numeric/class_methods/to_decimal_spec.rb +10 -0
  44. data/spec/unit/virtus/coercion/numeric/class_methods/to_float_spec.rb +10 -0
  45. data/spec/unit/virtus/coercion/numeric/class_methods/to_integer_spec.rb +10 -0
  46. data/spec/unit/virtus/coercion/numeric/class_methods/to_string_spec.rb +12 -0
  47. data/spec/unit/virtus/coercion/string/class_methods/to_symbol_spec.rb +0 -1
  48. data/spec/unit/virtus/coercion/time/class_methods/to_integer_spec.rb +0 -1
  49. data/spec/unit/virtus/coercion/time_coercions/to_date_spec.rb +33 -0
  50. data/spec/unit/virtus/coercion/time_coercions/to_datetime_spec.rb +33 -0
  51. data/spec/unit/virtus/coercion/time_coercions/to_string_spec.rb +18 -0
  52. data/spec/unit/virtus/coercion/time_coercions/to_time_spec.rb +33 -0
  53. data/spec/unit/virtus/equalizer/append_spec.rb +82 -0
  54. data/spec/unit/virtus/equalizer/class_method/new_spec.rb +111 -0
  55. data/spec/unit/virtus/equalizer/methods/eql_spec.rb +47 -0
  56. data/spec/unit/virtus/equalizer/methods/equal_value_spec.rb +57 -0
  57. data/spec/unit/virtus/type_lookup/class_methods/extended_spec.rb +0 -1
  58. data/spec/unit/virtus/value_object/class_methods/attribute_spec.rb +15 -8
  59. data/spec/unit/virtus/value_object/class_methods/equalizer_spec.rb +1 -1
  60. data/spec/unit/virtus/value_object/{with_spec.rb → instance_methods/with_spec.rb} +1 -1
  61. data/tasks/metrics/heckle.rake +2 -2
  62. data/virtus.gemspec +2 -1
  63. metadata +29 -23
  64. data/lib/virtus/value_object/equalizer.rb +0 -125
  65. data/spec/unit/virtus/attribute/default_value/attribute_spec.rb +0 -11
  66. data/spec/unit/virtus/attribute/default_value/evaluate_spec.rb +0 -22
  67. data/spec/unit/virtus/attribute/default_value/from_callable/evaluate_spec.rb +0 -21
  68. data/spec/unit/virtus/attribute/default_value/from_clonable/evaluate_spec.rb +0 -22
  69. data/spec/unit/virtus/value_object/equalizer/append_spec.rb +0 -61
@@ -84,7 +84,7 @@ module Virtus
84
84
  descendants.reverse_each do |descendant|
85
85
  descendant_primitive = descendant.primitive
86
86
  next unless primitive <= descendant_primitive
87
- type = descendant if type.nil? || type.primitive > descendant_primitive
87
+ type = descendant if type.nil? or type.primitive > descendant_primitive
88
88
  end
89
89
  type
90
90
  end
@@ -100,7 +100,7 @@ module Virtus
100
100
  #
101
101
  # @api private
102
102
  def determine_type_from_string(string)
103
- if string =~ TYPE_FORMAT && const_defined?(string, *EXTRA_CONST_ARGS)
103
+ if string =~ TYPE_FORMAT and const_defined?(string, *EXTRA_CONST_ARGS)
104
104
  const_get(string, *EXTRA_CONST_ARGS)
105
105
  end
106
106
  end
@@ -1,8 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
-
3
- require 'virtus'
4
- require 'virtus/value_object/equalizer'
5
-
6
1
  module Virtus
7
2
 
8
3
  # Include this Module for Value Object semantics
@@ -1,3 +1,3 @@
1
1
  module Virtus
2
- VERSION = '0.4.0'
2
+ VERSION = '0.4.1'
3
3
  end
@@ -1,6 +1,3 @@
1
- require 'rubygems'
2
- require 'backports'
3
-
4
1
  begin
5
2
  require 'rspec' # try for RSpec 2
6
3
  rescue LoadError
@@ -11,8 +11,6 @@ describe Virtus::Attribute, '#default' do
11
11
  context 'when the default is not specified' do
12
12
  it { should be_instance_of(Virtus::Attribute::DefaultValue) }
13
13
 
14
- its(:attribute) { should be(object) }
15
-
16
14
  its(:value) { should be_nil }
17
15
  end
18
16
 
@@ -25,8 +23,6 @@ describe Virtus::Attribute, '#default' do
25
23
 
26
24
  it { should be_instance_of(Virtus::Attribute::DefaultValue::FromClonable) }
27
25
 
28
- its(:attribute) { should be(object) }
29
-
30
26
  its(:value) { should be(default) }
31
27
  end
32
28
  end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute::DefaultValue, '#call' do
4
+ subject { object.call(instance) }
5
+
6
+ let(:object) { described_class.build(value) }
7
+ let(:value) { mock('value') }
8
+ let(:instance) { mock('instance') }
9
+ let(:response) { stub('response') }
10
+
11
+ # smallest number that is Bignum across major ruby impls
12
+ bignum = 0x7fffffffffffffff + 1
13
+
14
+ [ nil, true, false, 0, 0.0, bignum, :symbol ].each do |value|
15
+ context "when the value is #{value.inspect} (#{value.class})" do
16
+ let(:value) { value }
17
+
18
+ it { should be(value) }
19
+ end
20
+ end
21
+ end
@@ -1,9 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute::DefaultValue, '.build' do
4
- subject { described_class.build(attribute, default) }
5
-
6
- let(:attribute) { mock('attribute') }
4
+ subject { described_class.build(default) }
7
5
 
8
6
  context 'when default is a symbol' do
9
7
  let(:default) { :symbol }
@@ -1,9 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute::DefaultValue, '.new' do
4
- subject { described_class.new(attribute, value) }
5
-
6
- let(:attribute) { Virtus::Attribute::String.new(:attribute) }
4
+ subject { described_class.new(value) }
7
5
 
8
6
  context 'with a cloneable value' do
9
7
  let(:value) { 'something' }
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute::DefaultValue::FromCallable, '#call' do
4
+ subject { object.call(instance) }
5
+
6
+ let(:object) { described_class.new(value) }
7
+ let(:value) { mock('value') }
8
+ let(:instance) { mock('instance') }
9
+ let(:response) { stub('response') }
10
+
11
+ before { value.stub(:call => response) }
12
+
13
+ it { should be(response) }
14
+
15
+ it 'calls the value with the instance and attribute' do
16
+ value.should_receive(:call).with(instance)
17
+ subject
18
+ end
19
+ end
@@ -1,9 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute::DefaultValue::FromCallable, '.handle?' do
4
- subject { described_class.handle?(attribute, default) }
5
-
6
- let(:attribute) { mock('attribute') }
4
+ subject { described_class.handle?(default) }
7
5
 
8
6
  context 'with a callable' do
9
7
  let(:default) { Proc.new {} }
@@ -17,4 +15,3 @@ describe Virtus::Attribute::DefaultValue::FromCallable, '.handle?' do
17
15
  it { should be(false) }
18
16
  end
19
17
  end
20
-
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Attribute::DefaultValue::FromClonable, '#call' do
4
+ subject { object.call(instance) }
5
+
6
+ let(:object) { described_class.new(value) }
7
+ let(:value) { mock('value') }
8
+ let(:instance) { mock('instance') }
9
+ let(:response) { mock('response') }
10
+ let(:clone) { mock('clone') }
11
+
12
+ before { value.stub(:clone => clone) }
13
+
14
+ it { should be(clone) }
15
+
16
+ it 'clones the value' do
17
+ value.should_receive(:clone).with(no_args)
18
+ subject
19
+ end
20
+ end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute::DefaultValue::FromClonable, '.handle?' do
4
- subject { described_class.handle?(attribute, default) }
4
+ subject { described_class.handle?(default) }
5
5
 
6
6
  let(:attribute) { mock('attribute') }
7
7
 
@@ -17,4 +17,3 @@ describe Virtus::Attribute::DefaultValue::FromClonable, '.handle?' do
17
17
  it { should be(false) }
18
18
  end
19
19
  end
20
-
@@ -1,10 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Virtus::Attribute::DefaultValue::FromSymbol, '#evaluate' do
4
- subject { object.evaluate(instance) }
3
+ describe Virtus::Attribute::DefaultValue::FromSymbol, '#call' do
4
+ subject { object.call(instance) }
5
5
 
6
- let(:object) { described_class.new(attribute, value) }
7
- let(:attribute) { mock('attribute') }
6
+ let(:object) { described_class.new(value) }
8
7
  let(:instance) { mock('instance', value => retval) }
9
8
  let(:value) { :set_default }
10
9
  let(:retval) { mock('retval') }
@@ -1,9 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Virtus::Attribute::DefaultValue::FromSymbol, '.handle?' do
4
- subject { described_class.handle?(attribute, default) }
5
-
6
- let(:attribute) { mock('attribute') }
4
+ subject { described_class.handle?(default) }
7
5
 
8
6
  context 'with a symbol' do
9
7
  let(:default) { :method_name }
@@ -17,4 +15,3 @@ describe Virtus::Attribute::DefaultValue::FromSymbol, '.handle?' do
17
15
  it { should be(false) }
18
16
  end
19
17
  end
20
-
@@ -3,9 +3,8 @@ require 'spec_helper'
3
3
  describe Virtus::Attribute::DefaultValue, '#value' do
4
4
  subject { object.value }
5
5
 
6
- let(:object) { described_class.new(attribute, value) }
7
- let(:attribute) { mock('attribute') }
8
- let(:value) { mock('value') }
6
+ let(:object) { described_class.new(value) }
7
+ let(:value) { mock('value') }
9
8
 
10
9
  it { should be(value) }
11
10
  end
@@ -33,4 +33,3 @@ describe Virtus::AttributesAccessor, '#define_reader_method' do
33
33
  its(:protected_instance_methods) { should include(method_name) }
34
34
  end
35
35
  end
36
-
@@ -33,4 +33,3 @@ describe Virtus::AttributesAccessor, '#define_writer_method' do
33
33
  its(:protected_instance_methods) { should include(method_name) }
34
34
  end
35
35
  end
36
-
@@ -7,4 +7,3 @@ describe Virtus::Coercion::Decimal, '.to_decimal' do
7
7
 
8
8
  it { should be(value) }
9
9
  end
10
-
@@ -7,4 +7,3 @@ describe Virtus::Coercion::Float, '.to_float' do
7
7
 
8
8
  it { should be(value) }
9
9
  end
10
-
@@ -7,4 +7,3 @@ describe Virtus::Coercion::Integer, '.to_integer' do
7
7
 
8
8
  it { should be(value) }
9
9
  end
10
-
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Numeric, '.to_decimal' do
4
+ subject { object.to_decimal(numeric) }
5
+
6
+ let(:object) { described_class }
7
+ let(:numeric) { Rational(2, 2) }
8
+
9
+ it { should eql(BigDecimal('1.0')) }
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Numeric, '.to_float' do
4
+ subject { object.to_float(numeric) }
5
+
6
+ let(:object) { described_class }
7
+ let(:numeric) { Rational(2, 2) }
8
+
9
+ it { should eql(1.0) }
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Numeric, '.to_integer' do
4
+ subject { object.to_integer(numeric) }
5
+
6
+ let(:object) { described_class }
7
+ let(:numeric) { Rational(2, 2) }
8
+
9
+ it { should eql(1) }
10
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::Numeric, '.to_string' do
4
+ subject { object.to_string(numeric) }
5
+
6
+ let(:object) { described_class }
7
+ let(:numeric) { Rational(2, 2) }
8
+
9
+ let(:coerced_value) { RUBY_VERSION < '1.9' ? '1' : '1/1' }
10
+
11
+ it { should eql(coerced_value) }
12
+ end
@@ -7,4 +7,3 @@ describe Virtus::Coercion::String, '.to_symbol' do
7
7
 
8
8
  it { should be(:value) }
9
9
  end
10
-
@@ -8,4 +8,3 @@ describe Virtus::Coercion::Time, '.to_integer' do
8
8
 
9
9
  it { should eql(time.to_i) }
10
10
  end
11
-
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::TimeCoercions, '.to_date' do
4
+ subject { object.to_date(value) }
5
+
6
+ let(:object) { Class.new(Virtus::Coercion::Object) }
7
+ let(:value) { mock('value') }
8
+
9
+ context 'when the value responds to #to_date' do
10
+ before do
11
+ object.extend Virtus::Coercion::TimeCoercions
12
+
13
+ value.should_receive(:to_date).and_return(Date.new(2011, 1, 1))
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 the value does not respond to #to_date' do
22
+ before do
23
+ object.extend Virtus::Coercion::TimeCoercions
24
+
25
+ # use a string that Date.parse can handle
26
+ value.should_receive(:to_s).and_return('2011-01-01')
27
+ end
28
+
29
+ it { should be_instance_of(Date) }
30
+
31
+ it { should eql(Date.new(2011, 1, 1)) }
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::TimeCoercions, '.to_datetime' do
4
+ subject { object.to_datetime(value) }
5
+
6
+ let(:object) { Class.new(Virtus::Coercion::Object) }
7
+ let(:value) { mock('value') }
8
+
9
+ context 'when the value responds to #to_datetime' do
10
+ before do
11
+ object.extend Virtus::Coercion::TimeCoercions
12
+
13
+ value.should_receive(:to_datetime).and_return(DateTime.new(2011, 1, 1, 0, 0, 0))
14
+ end
15
+
16
+ it { should be_instance_of(DateTime) }
17
+
18
+ it { should eql(DateTime.new(2011, 1, 1, 0, 0, 0)) }
19
+ end
20
+
21
+ context 'when the value does not respond to #to_datetime' do
22
+ before do
23
+ object.extend Virtus::Coercion::TimeCoercions
24
+
25
+ # use a string that DateTime.parse can handle
26
+ value.should_receive(:to_s).and_return('2011-01-01T00:00:00+00:00')
27
+ end
28
+
29
+ it { should be_instance_of(DateTime) }
30
+
31
+ it { should eql(DateTime.new(2011, 1, 1, 0, 0, 0)) }
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::TimeCoercions, '.to_string' do
4
+ subject { object.to_string(value) }
5
+
6
+ let(:object) { Class.new(Virtus::Coercion::Object) }
7
+ let(:value) { mock('value') }
8
+
9
+ before do
10
+ object.extend Virtus::Coercion::TimeCoercions
11
+
12
+ value.should_receive(:to_s).and_return('2011-01-01')
13
+ end
14
+
15
+ it { should be_instance_of(String) }
16
+
17
+ it { should eql('2011-01-01') }
18
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Coercion::TimeCoercions, '.to_time' do
4
+ subject { object.to_time(value) }
5
+
6
+ let(:object) { Class.new(Virtus::Coercion::Object) }
7
+ let(:value) { mock('value') }
8
+
9
+ context 'when the value responds to #to_time' do
10
+ before do
11
+ object.extend Virtus::Coercion::TimeCoercions
12
+
13
+ value.should_receive(:to_time).and_return(Time.utc(2011, 1, 1))
14
+ end
15
+
16
+ it { should be_instance_of(Time) }
17
+
18
+ it { should eql(Time.utc(2011, 1, 1)) }
19
+ end
20
+
21
+ context 'when the value does not respond to #to_time' do
22
+ before do
23
+ object.extend Virtus::Coercion::TimeCoercions
24
+
25
+ # use a string that Time.parse can handle
26
+ value.should_receive(:to_s).and_return('Sat Jan 01 00:00:00 UTC 2011')
27
+ end
28
+
29
+ it { should be_instance_of(Time) }
30
+
31
+ it { should eql(Time.utc(2011, 1, 1)) }
32
+ end
33
+ end
@@ -0,0 +1,82 @@
1
+ require 'spec_helper'
2
+
3
+ describe Virtus::Equalizer, '#<<' do
4
+ subject { object << :last_name }
5
+
6
+ let(:object) { described_class.new(name, attributes) }
7
+ let(:name) { 'User' }
8
+ let(:attributes) { [ :first_name ].freeze }
9
+ let(:first_name) { 'John' }
10
+ let(:last_name) { 'Doe' }
11
+
12
+ let(:klass) do
13
+ klass = Class.new { attr_accessor :first_name, :last_name }
14
+ klass.send(:include, object)
15
+ klass
16
+ end
17
+
18
+ let(:instance) do
19
+ klass.new.tap do |instance|
20
+ instance.first_name = first_name
21
+ instance.last_name = last_name
22
+ end
23
+ end
24
+
25
+ describe '#eql?' do
26
+ context 'when the objects are similar' do
27
+ let(:other) { instance.dup }
28
+
29
+ it 'adds a key to the comparison' do
30
+ expect { subject }.to_not change { instance.eql?(other) }.from(true)
31
+ end
32
+ end
33
+
34
+ context 'when the objects are different' do
35
+ let(:other) { instance.dup }
36
+
37
+ before do
38
+ other.last_name = 'Smith'
39
+ end
40
+
41
+ it 'adds a key to the comparison' do
42
+ expect { subject }.to change { instance.eql?(other) }.
43
+ from(true).to(false)
44
+ end
45
+ end
46
+ end
47
+
48
+ describe '#==' do
49
+ context 'when the objects are similar' do
50
+ let(:other) { instance.dup }
51
+
52
+ it 'adds a key to the comparison' do
53
+ expect { subject }.to_not change { instance == other }.from(true)
54
+ end
55
+ end
56
+
57
+ context 'when the objects are different' do
58
+ let(:other) { instance.dup }
59
+
60
+ before do
61
+ other.last_name = 'Smith'
62
+ end
63
+
64
+ it 'adds a key to the comparison' do
65
+ expect { subject }.to change { instance == other }.
66
+ from(true).to(false)
67
+ end
68
+ end
69
+ end
70
+
71
+ it 'adds a new to #hash' do
72
+ expect { subject }.to change(instance, :hash).
73
+ from(klass.hash ^ first_name.hash).
74
+ to(klass.hash ^ first_name.hash ^ last_name.hash)
75
+ end
76
+
77
+ it 'adds a new to #inspect' do
78
+ expect { subject }.to change(instance, :inspect).
79
+ from('#<User first_name="John">').
80
+ to('#<User first_name="John" last_name="Doe">')
81
+ end
82
+ end