virtus 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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