virtus 0.0.5 → 0.0.6

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