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
@@ -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