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
@@ -15,3 +15,4 @@ rvm:
15
15
  notifications:
16
16
  email:
17
17
  - piotr.solnica@gmail.com
18
+ - dan.kubb@gmail.com
@@ -1,10 +1,18 @@
1
+ # v0.4.1 2012-05-06
2
+
3
+ * [changed] backports gem is now a runtime dependency (solnic)
4
+ * [BREAKING CHANGE] Renamed Virtus::DefaultValue#evaluate => Virtus::DefaultValue#call (solnic)
5
+ * [BREAKING CHANGE] Renamed Virtus::ValueObject::Equalizer to Virtus::Equalizer (dkubb)
6
+
7
+ [Compare v0.4.0..v0.4.1](https://github.com/solnic/virtus/compare/v0.4.0...v0.4.1)
8
+
1
9
  # v0.4.0 2012-03-22
2
10
 
3
11
  * [improvement] Add a caching mechanism for type lookups (solnic)
4
12
  * [fixed] Fix attributes mass-assignment when nil is passed (fgrehm)
5
13
  * [changed] Replace usage of #to_hash with Hash.try_convert (dkubb)
6
14
 
7
- [Compare v0.3.0..v0.4.0](https://github.com/solnic/virtus/compare/v0.3.0...master)
15
+ [Compare v0.3.0..v0.4.0](https://github.com/solnic/virtus/compare/v0.3.0...v0.4.0)
8
16
 
9
17
  # v0.3.0 2012-02-25
10
18
 
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
data/Guardfile CHANGED
@@ -6,4 +6,3 @@ guard 'rspec', :version => 1 do
6
6
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
7
  watch('spec/spec_helper.rb') { "spec" }
8
8
  end
9
-
data/README.md CHANGED
@@ -27,8 +27,6 @@ or in your **Gemfile**
27
27
  gem 'virtus'
28
28
  ```
29
29
 
30
- *IMPORTANT*: If you are still using Ruby 1.8.7 then you also have to install backports gem!
31
-
32
30
  Examples
33
31
  --------
34
32
 
data/Rakefile CHANGED
@@ -1,4 +1,3 @@
1
- require 'rubygems'
2
1
  require 'rake'
3
2
 
4
3
  FileList['tasks/**/*.rake'].each { |task| import task }
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 19
3
- total_score: 344
3
+ total_score: 365
@@ -1,2 +1,2 @@
1
1
  ---
2
- threshold: 19.4
2
+ threshold: 22.2
@@ -54,7 +54,7 @@ NestedIterators:
54
54
  ignore_iterators: []
55
55
  exclude: []
56
56
  enabled: true
57
- max_allowed_nesting: 1
57
+ max_allowed_nesting: 2
58
58
  LongMethod:
59
59
  max_statements: 6
60
60
  exclude: []
@@ -3,13 +3,15 @@ require 'date'
3
3
  require 'time'
4
4
  require 'bigdecimal'
5
5
  require 'bigdecimal/util'
6
+ require 'ostruct'
7
+ require 'backports'
6
8
 
7
9
  # Base module which adds Attribute API to your classes
8
10
  module Virtus
9
11
 
10
12
  # Provides args for const_get and const_defined? to make them behave
11
13
  # consistently across different versions of ruby
12
- EXTRA_CONST_ARGS = (RUBY_VERSION < '1.9' || RUBY_ENGINE == 'rbx' ? [] : [ false ]).freeze
14
+ EXTRA_CONST_ARGS = (RUBY_VERSION < '1.9' ? [] : [ false ]).freeze
13
15
 
14
16
  # Represents an undefined parameter used by auto-generated option methods
15
17
  Undefined = Object.new.freeze
@@ -34,6 +36,7 @@ end # module Virtus
34
36
  require 'virtus/support/descendants_tracker'
35
37
  require 'virtus/support/type_lookup'
36
38
  require 'virtus/support/options'
39
+ require 'virtus/support/equalizer'
37
40
 
38
41
  require 'virtus/attributes_accessor'
39
42
  require 'virtus/class_methods'
@@ -83,4 +86,3 @@ require 'virtus/attribute/symbol'
83
86
  require 'virtus/attribute/string'
84
87
  require 'virtus/attribute/time'
85
88
  require 'virtus/attribute/embedded_value'
86
-
@@ -127,7 +127,7 @@ module Virtus
127
127
  @instance_variable_name = "@#{@name}".to_sym
128
128
  @primitive = @options.fetch(:primitive)
129
129
  @coercion_method = @options.fetch(:coercion_method)
130
- @default = DefaultValue.build(self, @options[:default])
130
+ @default = DefaultValue.build(@options[:default])
131
131
  initialize_visibility
132
132
  end
133
133
 
@@ -160,7 +160,7 @@ module Virtus
160
160
  if instance.instance_variable_defined?(@instance_variable_name)
161
161
  get!(instance)
162
162
  else
163
- value = default.evaluate(instance)
163
+ value = default.call(instance, self)
164
164
  set!(instance, value)
165
165
  value
166
166
  end
@@ -31,7 +31,7 @@ module Virtus
31
31
  #
32
32
  # @api public
33
33
  def value_coerced?(value)
34
- value.equal?(true) || value.equal?(false)
34
+ value.equal?(true) or value.equal?(false)
35
35
  end
36
36
 
37
37
  # Creates an attribute reader method as a query
@@ -17,13 +17,6 @@ module Virtus
17
17
  klass.new(*args)
18
18
  end
19
19
 
20
- # Returns the attribute associated with this default value instance
21
- #
22
- # @return [Virtus::Attribute::Object]
23
- #
24
- # @api private
25
- attr_reader :attribute
26
-
27
20
  # Returns the value instance
28
21
  #
29
22
  # @return [Object]
@@ -33,27 +26,24 @@ module Virtus
33
26
 
34
27
  # Initializes an default value instance
35
28
  #
36
- # @param [Virtus::Attribute] attribute
37
29
  # @param [Object] value
38
30
  #
39
31
  # @return [undefined]
40
32
  #
41
33
  # @api private
42
- def initialize(attribute, value)
43
- @attribute, @value = attribute, value
34
+ def initialize(value)
35
+ @value = value
44
36
  end
45
37
 
46
38
  # Evaluates the value
47
39
  #
48
- # @param [Object]
49
- #
50
40
  # @return [Object] evaluated value
51
41
  #
52
42
  # @api private
53
- def evaluate(instance)
43
+ def call(*)
54
44
  value
55
45
  end
56
- end # class DefaultValue
57
46
 
47
+ end # class DefaultValue
58
48
  end # class Attribute
59
49
  end # module Virtus
@@ -9,10 +9,12 @@ module Virtus
9
9
 
10
10
  # Return if the class can handle the value
11
11
  #
12
+ # @param [Object] value
13
+ #
12
14
  # @return [Boolean]
13
15
  #
14
16
  # @api private
15
- def self.handle?(attribute, value)
17
+ def self.handle?(value)
16
18
  value.respond_to?(:call)
17
19
  end
18
20
 
@@ -23,8 +25,8 @@ module Virtus
23
25
  # @return [Object] evaluated value
24
26
  #
25
27
  # @api private
26
- def evaluate(instance)
27
- @value.call(instance, @attribute)
28
+ def call(*args)
29
+ @value.call(*args)
28
30
  end
29
31
 
30
32
  end # class FromCallable
@@ -11,10 +11,12 @@ module Virtus
11
11
 
12
12
  # Return if the class can handle the value
13
13
  #
14
+ # @param [Object] value
15
+ #
14
16
  # @return [Boolean]
15
17
  #
16
18
  # @api private
17
- def self.handle?(attribute, value)
19
+ def self.handle?(value)
18
20
  case value
19
21
  when *SINGLETON_CLASSES
20
22
  false
@@ -25,12 +27,10 @@ module Virtus
25
27
 
26
28
  # Evaluates the value via value#clone
27
29
  #
28
- # @param [Object]
29
- #
30
30
  # @return [Object] evaluated value
31
31
  #
32
32
  # @api private
33
- def evaluate(instance)
33
+ def call(*)
34
34
  @value.clone
35
35
  end
36
36
 
@@ -9,10 +9,12 @@ module Virtus
9
9
 
10
10
  # Return if the class can handle the value
11
11
  #
12
+ # @param [Object] value
13
+ #
12
14
  # @return [Boolean]
13
15
  #
14
16
  # @api private
15
- def self.handle?(attribute, value)
17
+ def self.handle?(value)
16
18
  value.is_a?(::Symbol)
17
19
  end
18
20
 
@@ -20,12 +22,10 @@ module Virtus
20
22
  #
21
23
  # Symbol value is returned if the instance doesn't respond to value
22
24
  #
23
- # @param [Object]
24
- #
25
25
  # @return [Object] evaluated value
26
26
  #
27
27
  # @api private
28
- def evaluate(instance)
28
+ def call(instance, *)
29
29
  instance.respond_to?(@value) ? instance.public_send(@value) : @value
30
30
  end
31
31
 
@@ -1,5 +1,3 @@
1
- require 'ostruct'
2
-
3
1
  module Virtus
4
2
  class Attribute
5
3
 
@@ -143,7 +143,7 @@ module Virtus
143
143
  #
144
144
  # @api private
145
145
  def const_missing(name)
146
- Attribute.determine_type(name) || super
146
+ Attribute.determine_type(name) or super
147
147
  end
148
148
 
149
149
  # Add the attribute to the class' and descendants' attributes
@@ -25,7 +25,7 @@ module Virtus
25
25
  #
26
26
  # @api private
27
27
  def self.[](name)
28
- determine_type(name) || Coercion::Object
28
+ determine_type(name) or Coercion::Object
29
29
  end
30
30
 
31
31
  end # Coerce
@@ -8,9 +8,9 @@ module Virtus
8
8
  # Coerce given value to String
9
9
  #
10
10
  # @example
11
- # Virtus::Coercion::Float.to_string(1.0) # => "1.0"
11
+ # Virtus::Coercion::Numeric.to_string(Rational(2, 2)) # => "1.0"
12
12
  #
13
- # @param [Float] value
13
+ # @param [Numeric] value
14
14
  #
15
15
  # @return [String]
16
16
  #
@@ -19,14 +19,14 @@ module Virtus
19
19
  value.to_s
20
20
  end
21
21
 
22
- # Creates a Fixnum instance from a numeric object
22
+ # Creates an Integer instance from a numeric object
23
23
  #
24
24
  # @example
25
- # Virtus::Coercion::BigDecimal.to_integer(BigDecimal('1.0')) # => 1
25
+ # Virtus::Coercion::Numeric.to_integer(Rational(2, 2)) # => 1
26
26
  #
27
- # @param [BigDecimal] value
27
+ # @param [Numeric] value
28
28
  #
29
- # @return [Fixnum]
29
+ # @return [Integer]
30
30
  #
31
31
  # @api public
32
32
  def self.to_integer(value)
@@ -36,23 +36,23 @@ module Virtus
36
36
  # Creates a Float instance from a numeric object
37
37
  #
38
38
  # @example
39
- # Virtus::Coercion::BigDecimal.to_float(BigDecimal('1.0')) # => 1.0
39
+ # Virtus::Coercion::Numeric.to_float(Rational(2, 2)) # => 1.0
40
40
  #
41
- # @param [BigDecimal] value
41
+ # @param [Numeric] value
42
42
  #
43
- # @return [Fixnum]
43
+ # @return [Float]
44
44
  #
45
45
  # @api public
46
46
  def self.to_float(value)
47
47
  value.to_f
48
48
  end
49
49
 
50
- # Coerce given value to BigDecimal
50
+ # Coerce a BigDecimal instance from a numeric object
51
51
  #
52
52
  # @example
53
- # Virtus::Coercion::Float.to_decimal(1.0) # => BigDecimal('1.0')
53
+ # Virtus::Coercion::Numeric.to_decimal(Rational(2, 2)) # => BigDecimal('1.0')
54
54
  #
55
- # @param [Float] value
55
+ # @param [Numeric] value
56
56
  #
57
57
  # @return [BigDecimal]
58
58
  #
@@ -96,7 +96,7 @@ module Virtus
96
96
  #
97
97
  # @api private
98
98
  def self.method_missing(method, *args)
99
- if method.to_s =~ COERCION_METHOD_REGEXP && args.size == 1
99
+ if method.to_s =~ COERCION_METHOD_REGEXP and args.size == 1
100
100
  args.first
101
101
  else
102
102
  super
@@ -0,0 +1,129 @@
1
+ module Virtus
2
+
3
+ # Define equality, equivalence and inspection methods
4
+ class Equalizer < Module
5
+
6
+ # Initialize an Equalizer with the given keys
7
+ #
8
+ # Will use the keys with which it is initialized to define #cmp?,
9
+ # #hash, and #inspect
10
+ #
11
+ # @param [String] name
12
+ #
13
+ # @param [Array<Symbol>] keys
14
+ #
15
+ # @return [undefined]
16
+ #
17
+ # @api private
18
+ def initialize(name, keys = [])
19
+ @name = name.dup.freeze
20
+ @keys = keys.dup
21
+ define_methods
22
+ include_comparison_methods
23
+ end
24
+
25
+ # Append a key and compile the equality methods
26
+ #
27
+ # @return [Equalizer] self
28
+ #
29
+ # @api private
30
+ def <<(key)
31
+ @keys << key
32
+ self
33
+ end
34
+
35
+ private
36
+
37
+ # Define the equalizer methods based on #keys
38
+ #
39
+ # @return [undefined]
40
+ #
41
+ # @api private
42
+ def define_methods
43
+ define_cmp_method
44
+ define_hash_method
45
+ define_inspect_method
46
+ end
47
+
48
+ # Define an #cmp? method based on the instance's values identified by #keys
49
+ #
50
+ # @return [undefined]
51
+ #
52
+ # @api private
53
+ def define_cmp_method
54
+ keys = @keys
55
+ define_method(:cmp?) do |comparator, other|
56
+ keys.all? { |key| send(key).send(comparator, other.send(key)) }
57
+ end
58
+ end
59
+
60
+ # Define a #hash method based on the instance's values identified by #keys
61
+ #
62
+ # @return [undefined]
63
+ #
64
+ # @api private
65
+ def define_hash_method
66
+ keys = @keys
67
+ define_method(:hash) do
68
+ keys.map { |key| send(key).hash }.reduce(self.class.hash, :^)
69
+ end
70
+ end
71
+
72
+ # Define an inspect method that reports the values of the instance's keys
73
+ #
74
+ # @return [undefined]
75
+ #
76
+ # @api private
77
+ def define_inspect_method
78
+ name, keys = @name, @keys
79
+ define_method(:inspect) do
80
+ "#<#{name}#{keys.map { |key| " #{key}=#{send(key).inspect}" }.join}>"
81
+ end
82
+ end
83
+
84
+ # Include the #eql? and #== methods
85
+ #
86
+ # @return [undefined]
87
+ #
88
+ # @api private
89
+ def include_comparison_methods
90
+ module_eval { include Methods }
91
+ end
92
+
93
+ # The comparison methods
94
+ module Methods
95
+
96
+ # Compare the object with other object for equality
97
+ #
98
+ # @example
99
+ # object.eql?(other) # => true or false
100
+ #
101
+ # @param [Object] other
102
+ # the other object to compare with
103
+ #
104
+ # @return [Boolean]
105
+ #
106
+ # @api public
107
+ def eql?(other)
108
+ instance_of?(other.class) and cmp?(__method__, other)
109
+ end
110
+
111
+ # Compare the object with other object for equivalency
112
+ #
113
+ # @example
114
+ # object == other # => true or false
115
+ #
116
+ # @param [Object] other
117
+ # the other object to compare with
118
+ #
119
+ # @return [Boolean]
120
+ #
121
+ # @api public
122
+ def ==(other)
123
+ return false unless self.class <=> other.class
124
+ cmp?(__method__, other)
125
+ end
126
+
127
+ end # module Methods
128
+ end # class Equalizer
129
+ end # module Virtus