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
@@ -1,8 +1,9 @@
1
1
  module Virtus
2
2
  class Attribute
3
3
 
4
- # Example usage:
4
+ # Array
5
5
  #
6
+ # @example
6
7
  # class Post
7
8
  # include Virtus
8
9
  #
@@ -10,9 +11,11 @@ module Virtus
10
11
  # end
11
12
  #
12
13
  # post = Post.new(:tags => %w(red green blue))
14
+ #
13
15
  class Array < Object
14
- primitive ::Array
15
- complex true
16
+ primitive ::Array
17
+ coercion_method :to_array
18
+
16
19
  end # class Array
17
20
  end # class Attribute
18
21
  end # module Virtus
@@ -4,8 +4,7 @@ module Virtus
4
4
  # Bolean attribute allows true or false values to be set
5
5
  # Additionally it adds boolean reader method, like "admin?"
6
6
  #
7
- # Example usage:
8
- #
7
+ # @example
9
8
  # class Post
10
9
  # include Virtus
11
10
  #
@@ -16,7 +15,8 @@ module Virtus
16
15
  # post.published? # => false
17
16
  #
18
17
  class Boolean < Object
19
- primitive TrueClass
18
+ primitive TrueClass
19
+ coercion_method :to_boolean
20
20
 
21
21
  # Returns if the given value is either true or false
22
22
  #
@@ -33,40 +33,21 @@ module Virtus
33
33
  value.equal?(true) || value.equal?(false)
34
34
  end
35
35
 
36
- # Coerce value into true or false
37
- #
38
- # @see Virtus::Typecast::Boolean.call
39
- #
40
- # @return [Boolean]
41
- #
42
- # @api private
43
- def typecast_to_primitive(value)
44
- Typecast::Boolean.call(value)
45
- end
46
-
47
36
  # Creates standard and boolean attribute reader methods
48
37
  #
49
- # @param [Class] model
38
+ # @param [Module] mod
50
39
  #
51
40
  # @return [self]
52
41
  #
53
42
  # @api private
54
- def add_reader_method(model)
43
+ def define_reader_method(mod)
55
44
  super
56
45
 
57
- name = self.name
58
- method_name = "#{name}?"
59
-
60
- model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
61
- module AttributeMethods # module AttributeMethods
62
- def #{method_name} # def active?
63
- #{name} # @active
64
- end # end
65
- end # end
66
- include AttributeMethods # include AttributeMethods
67
- RUBY
46
+ reader_method_name = "#{name}?"
47
+ attribute = self
68
48
 
69
- model.send(reader_visibility, method_name)
49
+ mod.send(:define_method, reader_method_name) { attribute.get(self) }
50
+ mod.send(reader_visibility, reader_method_name)
70
51
 
71
52
  self
72
53
  end
@@ -1,8 +1,9 @@
1
1
  module Virtus
2
2
  class Attribute
3
3
 
4
- # Example usage:
4
+ # Date
5
5
  #
6
+ # @example
6
7
  # class Post
7
8
  # include Virtus
8
9
  #
@@ -15,22 +16,18 @@ module Virtus
15
16
  # Post.new(:published_on => '2011/06/09')
16
17
  #
17
18
  # # typecasting from a hash
18
- # Post.new(:published_on => { :year => 2011, :month => 6, :day => 9 })
19
+ # Post.new(:published_on => {
20
+ # :year => 2011,
21
+ # :month => 6,
22
+ # :day => 9,
23
+ # })
19
24
  #
20
25
  # # typecasting from an object which implements #to_date
21
26
  # Post.new(:published_on => DateTime.now)
22
27
  #
23
28
  class Date < Object
24
- primitive ::Date
25
-
26
- # @see Virtus::Typecast::Time.to_date
27
- #
28
- # @return [Date]
29
- #
30
- # @api private
31
- def typecast_to_primitive(value)
32
- Typecast::Time.to_date(value)
33
- end
29
+ primitive ::Date
30
+ coercion_method :to_date
34
31
 
35
32
  end # class Date
36
33
  end # class Attribute
@@ -1,8 +1,9 @@
1
1
  module Virtus
2
2
  class Attribute
3
3
 
4
- # Example usage:
4
+ # DateTime
5
5
  #
6
+ # @example
6
7
  # class Post
7
8
  # include Virtus
8
9
  #
@@ -16,22 +17,19 @@ module Virtus
16
17
  #
17
18
  # # typecasting from a hash
18
19
  # Post.new(:published_on => {
19
- # :year => 2011, :month => 6, :day => 9, :hour => 10, :minutes => 48 })
20
+ # :year => 2011,
21
+ # :month => 6,
22
+ # :day => 9,
23
+ # :hour => 10,
24
+ # :min => 48,
25
+ # })
20
26
  #
21
27
  # # typecasting from an object which implements #to_datetime
22
28
  # Post.new(:published_on => Time.now)
23
29
  #
24
30
  class DateTime < Object
25
- primitive ::DateTime
26
-
27
- # @see Virtus::Typecast::Time.to_datetime
28
- #
29
- # @return [DateTime]
30
- #
31
- # @api private
32
- def typecast_to_primitive(value)
33
- Typecast::Time.to_datetime(value)
34
- end
31
+ primitive ::DateTime
32
+ coercion_method :to_datetime
35
33
 
36
34
  end # class DateTim
37
35
  end # class Attribute
@@ -1,8 +1,9 @@
1
1
  module Virtus
2
2
  class Attribute
3
3
 
4
- # Example usage:
4
+ # Decimal
5
5
  #
6
+ # @example
6
7
  # class ExchangeRate
7
8
  # include Virtus
8
9
  #
@@ -12,16 +13,8 @@ module Virtus
12
13
  # ExchangeRate.new(:dollar => '2.6948')
13
14
  #
14
15
  class Decimal < Numeric
15
- primitive ::BigDecimal
16
-
17
- # @see Virtus::Typecast::Numeric.to_d
18
- #
19
- # @return [BigDecimal]
20
- #
21
- # @api private
22
- def typecast_to_primitive(value)
23
- Typecast::Numeric.to_d(value)
24
- end
16
+ primitive ::BigDecimal
17
+ coercion_method :to_decimal
25
18
 
26
19
  end # class Decimal
27
20
  end # class Attribute
@@ -1,8 +1,9 @@
1
1
  module Virtus
2
2
  class Attribute
3
3
 
4
- # Example usage:
4
+ # Float
5
5
  #
6
+ # @example
6
7
  # class ExchangeRate
7
8
  # include Virtus
8
9
  #
@@ -21,16 +22,8 @@ module Virtus
21
22
  # ExchangeRate.new(:dollar => BigDecimal.new('2.69')
22
23
  #
23
24
  class Float < Numeric
24
- primitive ::Float
25
-
26
- # @see Virtus::Typecast::Numeric.to_f
27
- #
28
- # @return [Float]
29
- #
30
- # @api private
31
- def typecast_to_primitive(value)
32
- Typecast::Numeric.to_f(value)
33
- end
25
+ primitive ::Float
26
+ coercion_method :to_float
34
27
 
35
28
  end # class Float
36
29
  end # class Attribute
@@ -1,8 +1,9 @@
1
1
  module Virtus
2
2
  class Attribute
3
3
 
4
- # Example usage:
4
+ # Hash
5
5
  #
6
+ # @example
6
7
  # class Post
7
8
  # include Virtus
8
9
  #
@@ -12,8 +13,9 @@ module Virtus
12
13
  # Post.new(:meta => { :tags => %w(foo bar) })
13
14
  #
14
15
  class Hash < Object
15
- primitive ::Hash
16
- complex true
16
+ primitive ::Hash
17
+ coercion_method :to_hash
18
+
17
19
  end # class Hash
18
20
  end # class Attribute
19
21
  end # module Virtus
@@ -1,8 +1,9 @@
1
1
  module Virtus
2
2
  class Attribute
3
3
 
4
- # Example usage:
4
+ # Integer
5
5
  #
6
+ # @example
6
7
  # class Post
7
8
  # include Virtus
8
9
  #
@@ -18,16 +19,8 @@ module Virtus
18
19
  # Post.new(:read_count => 100.0)
19
20
  #
20
21
  class Integer < Numeric
21
- primitive ::Integer
22
-
23
- # @see Virtus::Typecast::Numeric.to_i
24
- #
25
- # @return [Integer]
26
- #
27
- # @api private
28
- def typecast_to_primitive(value)
29
- Typecast::Numeric.to_i(value)
30
- end
22
+ primitive ::Integer
23
+ coercion_method :to_integer
31
24
 
32
25
  end # class Integer
33
26
  end # class Attribute
@@ -5,6 +5,7 @@ module Virtus
5
5
  class Numeric < Object
6
6
  primitive ::Numeric
7
7
  accept_options :min, :max
8
+
8
9
  end # class Numeric
9
10
  end # class Attribute
10
11
  end # module Virtus
@@ -4,6 +4,7 @@ module Virtus
4
4
  # Base class for every attribute
5
5
  class Object < Attribute
6
6
  primitive ::Object
7
+
7
8
  end # class Object
8
9
  end # class Attribute
9
10
  end # module Virtus
@@ -1,8 +1,9 @@
1
1
  module Virtus
2
2
  class Attribute
3
3
 
4
- # Example usage
4
+ # String
5
5
  #
6
+ # @example
6
7
  # class User
7
8
  # include Virtus
8
9
  #
@@ -15,16 +16,8 @@ module Virtus
15
16
  # User.new(:name => :John)
16
17
  #
17
18
  class String < Object
18
- primitive ::String
19
-
20
- # @see Virtus::Typecast::String.call
21
- #
22
- # @return [String]
23
- #
24
- # @api private
25
- def typecast_to_primitive(value)
26
- Virtus::Typecast::String.call(value)
27
- end
19
+ primitive ::String
20
+ coercion_method :to_string
28
21
 
29
22
  end # class String
30
23
  end # class Attribute
@@ -1,8 +1,9 @@
1
1
  module Virtus
2
2
  class Attribute
3
3
 
4
- # Example usage:
4
+ # Time
5
5
  #
6
+ # @example
6
7
  # class Post
7
8
  # include Virtus
8
9
  #
@@ -16,27 +17,19 @@ module Virtus
16
17
  #
17
18
  # # typecasting from a hash
18
19
  # Post.new(:published_at => {
19
- # :year => 2011,
20
- # :month => 6,
21
- # :day => 9,
22
- # :hour => 11,
23
- # :minutes => 8
20
+ # :year => 2011,
21
+ # :month => 6,
22
+ # :day => 9,
23
+ # :hour => 11,
24
+ # :min => 8,
24
25
  # })
25
26
  #
26
27
  # # typecasting from an object which implements #to_time
27
28
  # Post.new(:published_at => DateTime.now)
28
29
  #
29
30
  class Time < Object
30
- primitive ::Time
31
-
32
- # @see Virtus::Typecast::Time.to_time
33
- #
34
- # @return [Time]
35
- #
36
- # @api private
37
- def typecast_to_primitive(value)
38
- Typecast::Time.to_time(value)
39
- end
31
+ primitive ::Time
32
+ coercion_method :to_time
40
33
 
41
34
  end # class Time
42
35
  end # class Attribute
@@ -3,6 +3,21 @@ module Virtus
3
3
  # Class methods that are added when you include Virtus
4
4
  module ClassMethods
5
5
 
6
+ # Hook called when module is extended
7
+ #
8
+ # @param [Class] descendant
9
+ #
10
+ # @return [undefined]
11
+ #
12
+ # @api private
13
+ def self.extended(descendant)
14
+ super
15
+ descendant.extend(DescendantsTracker)
16
+ descendant.const_set(:AttributeMethods, Module.new)
17
+ end
18
+
19
+ private_class_method :extended
20
+
6
21
  # Defines an attribute on an object's class
7
22
  #
8
23
  # @example
@@ -29,13 +44,8 @@ module Virtus
29
44
  # @api public
30
45
  def attribute(name, type, options = {})
31
46
  attribute = Attribute.determine_type(type).new(name, options)
32
-
33
- attribute.add_reader_method(self)
34
- attribute.add_writer_method(self)
35
-
36
- attributes << attribute
37
- descendants.each { |descendant| descendant.attributes.reset }
38
-
47
+ define_attribute_methods(attribute)
48
+ add_attribute(attribute)
39
49
  self
40
50
  end
41
51
 
@@ -81,5 +91,30 @@ module Virtus
81
91
  Attribute.determine_type(name) || super
82
92
  end
83
93
 
94
+ # Define the attribute reader and writer methods in the class
95
+ #
96
+ # @param [Attribute]
97
+ #
98
+ # @return [undefined]
99
+ #
100
+ # @api private
101
+ def define_attribute_methods(attribute)
102
+ attribute.define_reader_method(self)
103
+ attribute.define_writer_method(self)
104
+ include self::AttributeMethods
105
+ end
106
+
107
+ # Add the attribute to the class' and descendants' attributes
108
+ #
109
+ # @param [Attribute]
110
+ #
111
+ # @return [undefined]
112
+ #
113
+ # @api private
114
+ def add_attribute(attribute)
115
+ attributes << attribute
116
+ descendants.each { |descendant| descendant.attributes.reset }
117
+ end
118
+
84
119
  end # module ClassMethods
85
120
  end # module Virtus