virtus 0.0.2 → 0.0.3

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