virtus 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/.rvmrc +1 -1
- data/Gemfile +20 -1
- data/History.txt +21 -0
- data/README.markdown +2 -2
- data/Rakefile +1 -2
- data/VERSION +1 -1
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/roodi.yml +18 -0
- data/config/site.reek +91 -0
- data/config/yardstick.yml +2 -0
- data/lib/virtus.rb +51 -45
- data/lib/virtus/attribute.rb +301 -0
- data/lib/virtus/attribute/array.rb +17 -0
- data/lib/virtus/attribute/boolean.rb +60 -0
- data/lib/virtus/attribute/date.rb +35 -0
- data/lib/virtus/attribute/date_time.rb +34 -0
- data/lib/virtus/attribute/decimal.rb +24 -0
- data/lib/virtus/attribute/float.rb +33 -0
- data/lib/virtus/attribute/hash.rb +18 -0
- data/lib/virtus/attribute/integer.rb +30 -0
- data/lib/virtus/{attributes → attribute}/numeric.rb +2 -3
- data/lib/virtus/{attributes → attribute}/object.rb +2 -1
- data/lib/virtus/attribute/string.rb +31 -0
- data/lib/virtus/attribute/time.rb +34 -0
- data/lib/virtus/class_methods.rb +25 -8
- data/lib/virtus/instance_methods.rb +48 -9
- data/lib/virtus/support/chainable.rb +4 -6
- data/lib/virtus/typecast/boolean.rb +27 -0
- data/lib/virtus/typecast/numeric.rb +82 -0
- data/lib/virtus/typecast/time.rb +162 -0
- data/spec/integration/virtus/attributes/attribute/typecast_spec.rb +4 -4
- data/spec/integration/virtus/class_methods/attribute_spec.rb +1 -1
- data/spec/integration/virtus/class_methods/attributes_spec.rb +3 -2
- data/spec/integration/virtus/class_methods/const_missing_spec.rb +2 -2
- data/spec/rcov.opts +6 -0
- data/spec/spec_helper.rb +0 -9
- data/spec/unit/shared/attribute.rb +8 -8
- data/spec/unit/virtus/{attributes → attribute}/array_spec.rb +1 -1
- data/spec/unit/virtus/attribute/attribute_spec.rb +12 -0
- data/spec/unit/virtus/{attributes → attribute}/boolean_spec.rb +4 -4
- data/spec/unit/virtus/{attributes → attribute}/date_spec.rb +13 -7
- data/spec/unit/virtus/{attributes → attribute}/date_time_spec.rb +31 -10
- data/spec/unit/virtus/{attributes → attribute}/decimal_spec.rb +18 -18
- data/spec/unit/virtus/{attributes → attribute}/float_spec.rb +18 -18
- data/spec/unit/virtus/{attributes → attribute}/hash_spec.rb +1 -1
- data/spec/unit/virtus/{attributes → attribute}/integer_spec.rb +18 -18
- data/spec/unit/virtus/attribute/numeric/class_methods/descendants_spec.rb +15 -0
- data/spec/unit/virtus/attribute/object/class_methods/descendants_spec.rb +16 -0
- data/spec/unit/virtus/{attributes → attribute}/string_spec.rb +2 -2
- data/spec/unit/virtus/{attributes → attribute}/time_spec.rb +19 -9
- data/spec/unit/virtus/class_methods/new_spec.rb +7 -7
- data/spec/unit/virtus/determine_type_spec.rb +4 -4
- data/spec/unit/virtus/instance_methods/attribute_get_spec.rb +1 -1
- data/spec/unit/virtus/instance_methods/attribute_set_spec.rb +2 -2
- data/spec/unit/virtus/instance_methods/attributes_spec.rb +2 -2
- data/tasks/metrics/ci.rake +7 -0
- data/tasks/metrics/flay.rake +41 -0
- data/tasks/metrics/flog.rake +43 -0
- data/tasks/metrics/heckle.rake +261 -0
- data/tasks/metrics/metric_fu.rake +29 -0
- data/tasks/metrics/reek.rake +9 -0
- data/tasks/metrics/roodi.rake +15 -0
- data/tasks/metrics/yardstick.rake +23 -0
- data/tasks/spec.rake +26 -0
- data/tasks/yard.rake +9 -0
- data/virtus.gemspec +48 -33
- metadata +51 -41
- data/lib/virtus/attributes/array.rb +0 -8
- data/lib/virtus/attributes/attribute.rb +0 -214
- data/lib/virtus/attributes/boolean.rb +0 -39
- data/lib/virtus/attributes/date.rb +0 -44
- data/lib/virtus/attributes/date_time.rb +0 -43
- data/lib/virtus/attributes/decimal.rb +0 -24
- data/lib/virtus/attributes/float.rb +0 -20
- data/lib/virtus/attributes/hash.rb +0 -8
- data/lib/virtus/attributes/integer.rb +0 -20
- data/lib/virtus/attributes/string.rb +0 -11
- data/lib/virtus/attributes/time.rb +0 -45
- data/lib/virtus/attributes/typecast/numeric.rb +0 -32
- data/lib/virtus/attributes/typecast/time.rb +0 -27
- data/spec/unit/virtus/attributes/attribute_spec.rb +0 -13
- data/spec/unit/virtus/attributes/numeric/class_methods/descendants_spec.rb +0 -15
- 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
|
@@ -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
|
data/lib/virtus/class_methods.rb
CHANGED
@@ -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
|
30
|
-
|
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
|
-
#
|
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
|
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.
|
72
|
-
if
|
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
|