virtus 0.0.2 → 0.0.3

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 (85) hide show
  1. data/.gitignore +3 -0
  2. data/.rvmrc +1 -1
  3. data/Gemfile +20 -1
  4. data/History.txt +21 -0
  5. data/README.markdown +2 -2
  6. data/Rakefile +1 -2
  7. data/VERSION +1 -1
  8. data/config/flay.yml +3 -0
  9. data/config/flog.yml +2 -0
  10. data/config/roodi.yml +18 -0
  11. data/config/site.reek +91 -0
  12. data/config/yardstick.yml +2 -0
  13. data/lib/virtus.rb +51 -45
  14. data/lib/virtus/attribute.rb +301 -0
  15. data/lib/virtus/attribute/array.rb +17 -0
  16. data/lib/virtus/attribute/boolean.rb +60 -0
  17. data/lib/virtus/attribute/date.rb +35 -0
  18. data/lib/virtus/attribute/date_time.rb +34 -0
  19. data/lib/virtus/attribute/decimal.rb +24 -0
  20. data/lib/virtus/attribute/float.rb +33 -0
  21. data/lib/virtus/attribute/hash.rb +18 -0
  22. data/lib/virtus/attribute/integer.rb +30 -0
  23. data/lib/virtus/{attributes → attribute}/numeric.rb +2 -3
  24. data/lib/virtus/{attributes → attribute}/object.rb +2 -1
  25. data/lib/virtus/attribute/string.rb +31 -0
  26. data/lib/virtus/attribute/time.rb +34 -0
  27. data/lib/virtus/class_methods.rb +25 -8
  28. data/lib/virtus/instance_methods.rb +48 -9
  29. data/lib/virtus/support/chainable.rb +4 -6
  30. data/lib/virtus/typecast/boolean.rb +27 -0
  31. data/lib/virtus/typecast/numeric.rb +82 -0
  32. data/lib/virtus/typecast/time.rb +162 -0
  33. data/spec/integration/virtus/attributes/attribute/typecast_spec.rb +4 -4
  34. data/spec/integration/virtus/class_methods/attribute_spec.rb +1 -1
  35. data/spec/integration/virtus/class_methods/attributes_spec.rb +3 -2
  36. data/spec/integration/virtus/class_methods/const_missing_spec.rb +2 -2
  37. data/spec/rcov.opts +6 -0
  38. data/spec/spec_helper.rb +0 -9
  39. data/spec/unit/shared/attribute.rb +8 -8
  40. data/spec/unit/virtus/{attributes → attribute}/array_spec.rb +1 -1
  41. data/spec/unit/virtus/attribute/attribute_spec.rb +12 -0
  42. data/spec/unit/virtus/{attributes → attribute}/boolean_spec.rb +4 -4
  43. data/spec/unit/virtus/{attributes → attribute}/date_spec.rb +13 -7
  44. data/spec/unit/virtus/{attributes → attribute}/date_time_spec.rb +31 -10
  45. data/spec/unit/virtus/{attributes → attribute}/decimal_spec.rb +18 -18
  46. data/spec/unit/virtus/{attributes → attribute}/float_spec.rb +18 -18
  47. data/spec/unit/virtus/{attributes → attribute}/hash_spec.rb +1 -1
  48. data/spec/unit/virtus/{attributes → attribute}/integer_spec.rb +18 -18
  49. data/spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb +15 -0
  50. data/spec/unit/virtus/attribute/object/class_methods/descendants_spec.rb +16 -0
  51. data/spec/unit/virtus/{attributes → attribute}/string_spec.rb +2 -2
  52. data/spec/unit/virtus/{attributes → attribute}/time_spec.rb +19 -9
  53. data/spec/unit/virtus/class_methods/new_spec.rb +7 -7
  54. data/spec/unit/virtus/determine_type_spec.rb +4 -4
  55. data/spec/unit/virtus/instance_methods/attribute_get_spec.rb +1 -1
  56. data/spec/unit/virtus/instance_methods/attribute_set_spec.rb +2 -2
  57. data/spec/unit/virtus/instance_methods/attributes_spec.rb +2 -2
  58. data/tasks/metrics/ci.rake +7 -0
  59. data/tasks/metrics/flay.rake +41 -0
  60. data/tasks/metrics/flog.rake +43 -0
  61. data/tasks/metrics/heckle.rake +261 -0
  62. data/tasks/metrics/metric_fu.rake +29 -0
  63. data/tasks/metrics/reek.rake +9 -0
  64. data/tasks/metrics/roodi.rake +15 -0
  65. data/tasks/metrics/yardstick.rake +23 -0
  66. data/tasks/spec.rake +26 -0
  67. data/tasks/yard.rake +9 -0
  68. data/virtus.gemspec +48 -33
  69. metadata +51 -41
  70. data/lib/virtus/attributes/array.rb +0 -8
  71. data/lib/virtus/attributes/attribute.rb +0 -214
  72. data/lib/virtus/attributes/boolean.rb +0 -39
  73. data/lib/virtus/attributes/date.rb +0 -44
  74. data/lib/virtus/attributes/date_time.rb +0 -43
  75. data/lib/virtus/attributes/decimal.rb +0 -24
  76. data/lib/virtus/attributes/float.rb +0 -20
  77. data/lib/virtus/attributes/hash.rb +0 -8
  78. data/lib/virtus/attributes/integer.rb +0 -20
  79. data/lib/virtus/attributes/string.rb +0 -11
  80. data/lib/virtus/attributes/time.rb +0 -45
  81. data/lib/virtus/attributes/typecast/numeric.rb +0 -32
  82. data/lib/virtus/attributes/typecast/time.rb +0 -27
  83. data/spec/unit/virtus/attributes/attribute_spec.rb +0 -13
  84. data/spec/unit/virtus/attributes/numeric/class_methods/descendants_spec.rb +0 -15
  85. data/spec/unit/virtus/attributes/object/class_methods/descendants_spec.rb +0 -16
@@ -0,0 +1,17 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Example usage:
4
+ #
5
+ # class Post
6
+ # include Virtus
7
+ #
8
+ # attribute :tags, Array
9
+ # end
10
+ #
11
+ # post = Post.new(:tags => %w(red green blue))
12
+ class Array < Object
13
+ primitive ::Array
14
+ complex true
15
+ end # Integer
16
+ end # Attributes
17
+ end # Virtus
@@ -0,0 +1,60 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Bolean attribute allows true or false values to be set
4
+ # Additionally it adds boolean reader method, like "admin?"
5
+ #
6
+ # Example usage:
7
+ #
8
+ # class Post
9
+ # include Virtus
10
+ #
11
+ # attribute :published, Boolean
12
+ # end
13
+ #
14
+ # post = Post.new(:published => false)
15
+ # post.published? # => false
16
+ #
17
+ class Boolean < Object
18
+ primitive TrueClass
19
+
20
+ # Returns if the given value is either true or false
21
+ #
22
+ # @return [TrueClass,FalseClass]
23
+ #
24
+ # @api private
25
+ def primitive?(value)
26
+ value.equal?(true) || value.equal?(false)
27
+ end
28
+
29
+ # Coerce value into true or false
30
+ #
31
+ # @see Virtus::Typecast::Boolean.call
32
+ #
33
+ # @return [TrueClass,FalseClass]
34
+ #
35
+ # @api private
36
+ def typecast_to_primitive(value)
37
+ Typecast::Boolean.call(value)
38
+ end
39
+
40
+ # Creates standard and boolean attribute reader methods
41
+ #
42
+ # @return [NilClass]
43
+ #
44
+ # @api private
45
+ def add_reader_method(model)
46
+ super
47
+
48
+ model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
49
+ chainable(:attribute) do
50
+ #{reader_visibility}
51
+
52
+ def #{name}?
53
+ #{name}
54
+ end
55
+ end
56
+ RUBY
57
+ end
58
+ end # Boolean
59
+ end # Attributes
60
+ end # Virtus
@@ -0,0 +1,35 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Example usage:
4
+ #
5
+ # class Post
6
+ # include Virtus
7
+ #
8
+ # attribute :published_on, Date
9
+ # end
10
+ #
11
+ # Post.new(:published_on => Date.today)
12
+ #
13
+ # # typecasting from a string
14
+ # Post.new(:published_on => '2011/06/09')
15
+ #
16
+ # # typecasting from a hash
17
+ # Post.new(:published_on => { :year => 2011, :month => 6, :day => 9 })
18
+ #
19
+ # # typecasting from an object which implements #to_date
20
+ # Post.new(:published_on => DateTime.now)
21
+ #
22
+ class Date < Object
23
+ primitive ::Date
24
+
25
+ # @see Virtus::Typecast::Time.to_date
26
+ #
27
+ # @return [Date]
28
+ #
29
+ # @api private
30
+ def typecast_to_primitive(value)
31
+ Typecast::Time.to_date(value)
32
+ end
33
+ end # Date
34
+ end # Attributes
35
+ end # Virtus
@@ -0,0 +1,34 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Example usage:
4
+ #
5
+ # class Post
6
+ # include Virtus
7
+ #
8
+ # attribute :published_at, DateTime
9
+ # end
10
+ #
11
+ # Post.new(:published_at => DateTime.now)
12
+ #
13
+ # # typecasting from a string
14
+ # Post.new(:published_on => '2011/06/09 10:48')
15
+ #
16
+ # # typecasting from a hash
17
+ # Post.new(:published_on => {
18
+ # :year => 2011, :month => 6, :day => 9, :hour => 10, :minutes => 48 })
19
+ #
20
+ # # typecasting from an object which implements #to_datetime
21
+ # Post.new(:published_on => Time.now)
22
+ #
23
+ class DateTime < Object
24
+ primitive ::DateTime
25
+
26
+ # @see Virtus::Typecast::Time.to_datetime
27
+ #
28
+ # @api private
29
+ def typecast_to_primitive(value)
30
+ Typecast::Time.to_datetime(value)
31
+ end
32
+ end # DateTime
33
+ end # Attributes
34
+ end # Virtus
@@ -0,0 +1,24 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Example usage:
4
+ #
5
+ # class ExchangeRate
6
+ # include Virtus
7
+ #
8
+ # attribute :dollar, Decimal
9
+ # end
10
+ #
11
+ # ExchangeRate.new(:dollar => '2.6948')
12
+ #
13
+ class Decimal < Numeric
14
+ primitive ::BigDecimal
15
+
16
+ # @see Virtus::Typecast::Numeric.to_d
17
+ #
18
+ # @api private
19
+ def typecast_to_primitive(value)
20
+ Typecast::Numeric.to_d(value)
21
+ end
22
+ end # Decimal
23
+ end # Attributes
24
+ end # Virtus
@@ -0,0 +1,33 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Example usage:
4
+ #
5
+ # class ExchangeRate
6
+ # include Virtus
7
+ #
8
+ # attribute :dollar, Float
9
+ # end
10
+ #
11
+ # ExchangeRate.new(:dollar => 2.69)
12
+ #
13
+ # # typecasting from a string
14
+ # ExchangeRate.new(:dollar => '2.69')
15
+ #
16
+ # # typecasting from an integer
17
+ # ExchangeRate.new(:dollar => 2)
18
+ #
19
+ # # typecasting from an object which implements #to_f
20
+ # ExchangeRate.new(:dollar => BigDecimal.new('2.69')
21
+ #
22
+ class Float < Numeric
23
+ primitive ::Float
24
+
25
+ # @see Virtus::Typecast::Numeric.to_f
26
+ #
27
+ # @api private
28
+ def typecast_to_primitive(value)
29
+ Typecast::Numeric.to_f(value)
30
+ end
31
+ end # Float
32
+ end # Attributes
33
+ end # Virtus
@@ -0,0 +1,18 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Example usage:
4
+ #
5
+ # class Post
6
+ # include Virtus
7
+ #
8
+ # attribute :meta, Hash
9
+ # end
10
+ #
11
+ # Post.new(:meta => { :tags => %w(foo bar) })
12
+ #
13
+ class Hash < Object
14
+ primitive ::Hash
15
+ complex true
16
+ end # Integer
17
+ end # Attributes
18
+ end # Virtus
@@ -0,0 +1,30 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Example usage:
4
+ #
5
+ # class Post
6
+ # include Virtus
7
+ #
8
+ # attribute :read_count, Integer
9
+ # end
10
+ #
11
+ # Post.new(:read_count => 100)
12
+ #
13
+ # # typecasting from a string
14
+ # Post.new(:read_count => '100')
15
+ #
16
+ # # typecasting from an object that implements #to_i
17
+ # Post.new(:read_count => 100.0)
18
+ #
19
+ class Integer < Numeric
20
+ primitive ::Integer
21
+
22
+ # @see Virtus::Typecast::Numeric.to_i
23
+ #
24
+ # @api private
25
+ def typecast_to_primitive(value)
26
+ Typecast::Numeric.to_i(value)
27
+ end
28
+ end # Integer
29
+ end # Attributes
30
+ end # Virtus
@@ -1,8 +1,7 @@
1
1
  module Virtus
2
- module Attributes
2
+ class Attribute
3
+ # Base class for all numerical attributes
3
4
  class Numeric < Object
4
- include Typecast::Numeric
5
-
6
5
  accept_options :min, :max
7
6
  end # Numeric
8
7
  end # Attributes
@@ -1,5 +1,6 @@
1
1
  module Virtus
2
- module Attributes
2
+ class Attribute
3
+ # Base class for every attribute
3
4
  class Object < Attribute
4
5
  primitive ::Object
5
6
  complex false
@@ -0,0 +1,31 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Example usage
4
+ #
5
+ # class User
6
+ # include Virtus
7
+ #
8
+ # attribute :name, String
9
+ # end
10
+ #
11
+ # User.new(:name => 'John')
12
+ #
13
+ # # typecasting from an object which implements #to_s
14
+ # User.new(:name => :John)
15
+ #
16
+ class String < Object
17
+ primitive ::String
18
+
19
+ # Typecast the given value to a string
20
+ #
21
+ # @param [Object]
22
+ #
23
+ # @return [String]
24
+ #
25
+ # @api private
26
+ def typecast_to_primitive(value)
27
+ value.to_s
28
+ end
29
+ end # String
30
+ end # Attributes
31
+ end # Virtus
@@ -0,0 +1,34 @@
1
+ module Virtus
2
+ class Attribute
3
+ # Example usage:
4
+ #
5
+ # class Post
6
+ # include Virtus
7
+ #
8
+ # attribute :published_at, Time
9
+ # end
10
+ #
11
+ # Post.new(:published_at => Time.now)
12
+ #
13
+ # # typecasting from a string
14
+ # Post.new(:published_at => '2011/06/09 11:08')
15
+ #
16
+ # # typecasting from a hash
17
+ # Post.new(:published_at => {
18
+ # :year => 2011, :month => 6, :day => 9, :hour => 11, :minutes => 8 })
19
+ #
20
+ # # typecasting from an object which implements #to_time
21
+ # Post.new(:published_at => DateTime.now)
22
+ #
23
+ class Time < Object
24
+ primitive ::Time
25
+
26
+ # @see Virtus::Typecast::Time.to_time
27
+ #
28
+ # @api private
29
+ def typecast_to_primitive(value)
30
+ Typecast::Time.to_time(value)
31
+ end
32
+ end # Time
33
+ end # Attributes
34
+ end # Virtus
@@ -1,9 +1,9 @@
1
1
  module Virtus
2
+ # Class methods that are added when you include Virtus
2
3
  module ClassMethods
3
- # Defines an attribute on an object's class.
4
- #
5
- # Usage:
4
+ # Defines an attribute on an object's class
6
5
  #
6
+ # @example
7
7
  # class Book
8
8
  # include Virtus
9
9
  #
@@ -26,11 +26,28 @@ module Virtus
26
26
  #
27
27
  # @api public
28
28
  def attribute(name, type, options = {})
29
- attribute_klass = Virtus.determine_type(type)
30
- attributes[name] = attribute_klass.new(name, self, options)
29
+ attribute_klass = Virtus.determine_type(type)
30
+ attribute = attribute_klass.new(name, options)
31
+
32
+ attribute.add_reader_method(self)
33
+ attribute.add_writer_method(self)
34
+
35
+ attributes[name] = attribute
31
36
  end
32
37
 
33
- # Returns all the attributes defined on a Class.
38
+ # Returns all the attributes defined on a Class
39
+ #
40
+ # @example
41
+ # class User
42
+ # include Virtus
43
+ #
44
+ # attribute :name, String
45
+ # attribute :age, Integer
46
+ # end
47
+ #
48
+ # User.attributes # =>
49
+ #
50
+ # TODO: implement inspect so the output is not cluttered - solnic
34
51
  #
35
52
  # @return [Hash]
36
53
  # an attributes hash indexed by attribute names
@@ -42,11 +59,11 @@ module Virtus
42
59
 
43
60
  private
44
61
 
45
- # Hooks into const missing process to determine types of attributes.
62
+ # Hooks into const missing process to determine types of attributes
46
63
  #
47
64
  # It is used when an attribute is defined and a global class like String
48
65
  # or Integer is provided as the type which needs to be mapped to
49
- # Virtus::Attributes::String and Virtus::Attributes::Integer.
66
+ # Virtus::Attributes::String and Virtus::Attributes::Integer
50
67
  #
51
68
  # @param [String] name
52
69
  #
@@ -1,7 +1,7 @@
1
1
  module Virtus
2
+ # Instance methods that are added when you include Virtus
2
3
  module InstanceMethods
3
- # Chains Class.new to be able to set attributes during initialization of
4
- # an object.
4
+ # Set attributes during initialization of an object
5
5
  #
6
6
  # @param [Hash] attributes
7
7
  # the attributes hash to be set
@@ -15,6 +15,16 @@ module Virtus
15
15
 
16
16
  # Returns a value of the attribute with the given name
17
17
  #
18
+ # @example
19
+ # class User
20
+ # include Virtus
21
+ #
22
+ # attribute :name, String
23
+ # end
24
+ #
25
+ # user = User.new(:name => 'John')
26
+ # user.attribute_get(:name) # => "john"
27
+ #
18
28
  # @param [Symbol] name
19
29
  # a name of an attribute
20
30
  #
@@ -28,6 +38,17 @@ module Virtus
28
38
 
29
39
  # Sets a value of the attribute with the given name
30
40
  #
41
+ # @example
42
+ # class User
43
+ # include Virtus
44
+ #
45
+ # attribute :name, String
46
+ # end
47
+ #
48
+ # user = User.new
49
+ # user.attribute_set(:name) # => "john"
50
+ # user.name # => "john"
51
+ #
31
52
  # @param [Symbol] name
32
53
  # a name of an attribute
33
54
  #
@@ -44,6 +65,17 @@ module Virtus
44
65
 
45
66
  # Mass-assign of attribute values
46
67
  #
68
+ # @example
69
+ # class User
70
+ # include Virtus
71
+ #
72
+ # attribute :name, String
73
+ # attribute :age, Integer
74
+ # end
75
+ #
76
+ # user = User.new
77
+ # user.attributes = { :name => 'John', :age => 28 }
78
+ #
47
79
  # @param [Hash] attributes
48
80
  # a hash of attribute values to be set on an object
49
81
  #
@@ -53,14 +85,23 @@ module Virtus
53
85
  # @api public
54
86
  def attributes=(attributes)
55
87
  attributes.each do |name, value|
56
- if self.class.public_method_defined?(writer_name = "#{name}=")
57
- __send__(writer_name, value)
58
- end
88
+ attribute_set(name, value) if respond_to?("#{name}=")
59
89
  end
60
90
  end
61
91
 
62
92
  # Returns a hash of all publicly accessible attributes
63
93
  #
94
+ # @example
95
+ # class User
96
+ # include Virtus
97
+ #
98
+ # attribute :name, String
99
+ # attribute :age, Integer
100
+ # end
101
+ #
102
+ # user = User.new(:name => 'John', :age => 28)
103
+ # user.attributes # => { :name => 'John', :age => 28 }
104
+ #
64
105
  # @return [Hash]
65
106
  # the attributes
66
107
  #
@@ -68,10 +109,8 @@ module Virtus
68
109
  def attributes
69
110
  attributes = {}
70
111
 
71
- self.class.attributes.each do |name, attribute|
72
- if self.class.public_method_defined?(name)
73
- attributes[name] = __send__(attribute.name)
74
- end
112
+ self.class.attributes.each_key do |name|
113
+ attributes[name] = attribute_get(name) if respond_to?(name)
75
114
  end
76
115
 
77
116
  attributes