virtus 0.0.4 → 0.0.5

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.
data/Gemfile CHANGED
@@ -1,8 +1,9 @@
1
1
  source :rubygems
2
2
 
3
3
  group :development do
4
- gem 'jeweler', '~> 1.6.4'
5
- gem 'rspec', '~> 2.6.0'
4
+ gem 'backports', '~> 2.3.0'
5
+ gem 'jeweler', '~> 1.6.4'
6
+ gem 'rspec', '~> 2.6.0'
6
7
  end
7
8
 
8
9
  group :metrics do
@@ -14,6 +15,7 @@ group :metrics do
14
15
 
15
16
  platforms :mri_18 do
16
17
  gem 'heckle', '~> 1.4.3'
18
+ gem 'json', '~> 1.5.3'
17
19
  gem 'metric_fu', '~> 2.1.1'
18
20
  gem 'mspec', '~> 1.5.17'
19
21
  gem 'rcov', '~> 0.9.9'
@@ -1,3 +1,10 @@
1
+ === v0.0.5 to-be-released
2
+
3
+ Details: https://github.com/solnic/virtus/compare/v0.0.4...master
4
+
5
+ * [BREAKING CHANGE] Moved Virtus.determine_type to Virtus::Attribute.determine_type (dkubb)
6
+ * [general] Added backports as a development dependency (dkubb)
7
+
1
8
  === v0.0.4 2011-07-08
2
9
 
3
10
  * [BREAKING CHANGE] attributes hash has been replaced by a specialized class AttributeSet (dkubb)
@@ -25,20 +25,20 @@ attributes that require typecasting and/or validations.
25
25
  end
26
26
 
27
27
  # setting attributes in the constructor
28
- user = User.new(:age => 28)
28
+ user = User.new(:name => 'Piotr', :age => 28)
29
29
 
30
30
  # attribute readers
31
- user.name # => "Piotr"
31
+ user.name # => "Piotr"
32
32
 
33
33
  # hash of attributes
34
- user.attributes # => { :name => "Piotr" }
34
+ user.attributes # => { :name => "Piotr" }
35
35
 
36
36
  # automatic typecasting
37
37
  user.age = '28'
38
- user.age # => 28
38
+ user.age # => 28
39
39
 
40
40
  user.birthday = 'November 18th, 1983'
41
- user.birthday # => #<DateTime: 1983-11-18T00:00:00+00:00 (4891313/2,0/1,2299161)>
41
+ user.birthday # => #<DateTime: 1983-11-18T00:00:00+00:00 (4891313/2,0/1,2299161)>
42
42
 
43
43
  ## Custom Attributes
44
44
 
@@ -65,8 +65,8 @@ attributes that require typecasting and/or validations.
65
65
 
66
66
  user = MyApp::User.new
67
67
 
68
- user.info = '{"email" : "john@domain.com" }'
69
- user.info # => {"email"=>"john@domain.com"}
68
+ user.info = '{"email":"john@domain.com"}'
69
+ user.info # => {"email"=>"john@domain.com"}
70
70
 
71
71
  ## Note on Patches/Pull Requests
72
72
 
data/Rakefile CHANGED
@@ -4,18 +4,13 @@ require 'jeweler'
4
4
  require 'rspec/core/rake_task'
5
5
 
6
6
  Jeweler::Tasks.new do |gem|
7
- gem.name = "virtus"
7
+ gem.name = 'virtus'
8
8
  gem.platform = Gem::Platform::RUBY
9
- gem.authors = ["Piotr Solnica"]
10
- gem.email = ["piotr@rubyverse.com"]
11
- gem.homepage = "https://github.com/solnic/virtus"
12
- gem.summary = %q{Attributes for your plain ruby objects}
9
+ gem.authors = [ 'Piotr Solnica' ]
10
+ gem.email = [ 'piotr@rubyverse.com' ]
11
+ gem.homepage = 'https://github.com/solnic/virtus'
12
+ gem.summary = 'Attributes for your plain ruby objects'
13
13
  gem.description = gem.summary
14
-
15
- gem.files = `git ls-files`.split("\n")
16
- gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
- gem.require_paths = ["lib"]
19
14
  end
20
15
 
21
16
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.0.5
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 19.0
3
- total_score: 208
3
+ total_score: 187
@@ -2,7 +2,7 @@
2
2
  AbcMetricMethodCheck: { score: 9.5 }
3
3
  AssignmentInConditionalCheck: { }
4
4
  CaseMissingElseCheck: { }
5
- ClassLineCountCheck: { line_count: 345 }
5
+ ClassLineCountCheck: { line_count: 404 }
6
6
  ClassNameCheck: { pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ }
7
7
  ClassVariableCheck: { }
8
8
  CyclomaticComplexityBlockCheck: { complexity: 2 }
@@ -10,9 +10,9 @@ CyclomaticComplexityMethodCheck: { complexity: 3 }
10
10
  EmptyRescueBodyCheck: { }
11
11
  ForLoopCheck: { }
12
12
  # TODO: decrease line_count to 5 to 10
13
- MethodLineCountCheck: { line_count: 17 }
13
+ MethodLineCountCheck: { line_count: 19 }
14
14
  MethodNameCheck: { pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|<<|[+*&|-])\z/ }
15
- ModuleLineCountCheck: { line_count: 351 }
15
+ ModuleLineCountCheck: { line_count: 410 }
16
16
  ModuleNameCheck: { pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/ }
17
17
  # TODO: decrease parameter_count to 2 or less
18
18
  ParameterNumberCheck: { parameter_count: 3 }
@@ -11,41 +11,15 @@ module Virtus
11
11
 
12
12
  # Extends base class with class and instance methods
13
13
  #
14
- # @param [Class] base
14
+ # @param [Class] descendant
15
15
  #
16
16
  # @return [Class]
17
17
  #
18
18
  # @api private
19
- def self.included(base)
20
- base.extend(DescendantsTracker)
21
- base.extend(ClassMethods)
22
- base.send(:include, InstanceMethods)
23
- end
24
-
25
- # Returns a Virtus::Attribute::Object sub-class based on a name or class
26
- #
27
- # @example
28
- # Virtus.determine_type('String') # => Virtus::Attribute::String
29
- #
30
- # @param [Class,String] class_or_name
31
- # name of a class or a class itself
32
- #
33
- # @return [Class]
34
- # one of the Virtus::Attribute::Object sub-class
35
- #
36
- # @api semipublic
37
- def self.determine_type(class_or_name)
38
- if class_or_name.kind_of?(Class)
39
- if class_or_name < Attribute::Object
40
- class_or_name
41
- else
42
- Attribute.descendants.detect do |descendant|
43
- class_or_name <= descendant.primitive
44
- end
45
- end
46
- elsif Attribute.const_defined?(name = class_or_name.to_s)
47
- Attribute.const_get(name)
48
- end
19
+ def self.included(descendant)
20
+ descendant.extend(DescendantsTracker)
21
+ descendant.extend(ClassMethods)
22
+ descendant.send(:include, InstanceMethods)
49
23
  end
50
24
 
51
25
  end # module Virtus
@@ -6,6 +6,77 @@ module Virtus
6
6
  class Attribute
7
7
  extend DescendantsTracker
8
8
 
9
+ # Returns a Virtus::Attribute::Object descendant based on a name or class
10
+ #
11
+ # @example
12
+ # Attribute.determine_type('String') # => Virtus::Attribute::String
13
+ #
14
+ # @param [Class, #to_s] class_or_name
15
+ # name of a class or a class itself
16
+ #
17
+ # @return [Class]
18
+ # one of the Virtus::Attribute::Object descendants
19
+ #
20
+ # @return [nil]
21
+ # nil if the type cannot be determined by the class_or_name
22
+ #
23
+ # @api public
24
+ def self.determine_type(class_or_name)
25
+ # first match on the Attribute singleton class first, then match
26
+ # any class, finally fallback to matching on the string
27
+ case class_or_name
28
+ when Attribute::Object.singleton_class then determine_type_from_attribute(class_or_name)
29
+ when Class then determine_type_from_primitive(class_or_name)
30
+ else
31
+ determine_type_from_string(class_or_name.to_s)
32
+ end
33
+ end
34
+
35
+ # Return the Attribute class given an Attribute descendant
36
+ #
37
+ # @param [Class<Attribute>] attribute
38
+ #
39
+ # @return [Class<Attribute>]
40
+ #
41
+ # @api private
42
+ def self.determine_type_from_attribute(attribute)
43
+ attribute
44
+ end
45
+
46
+ private_class_method :determine_type_from_attribute
47
+
48
+ # Return the Attribute class given a primitive
49
+ #
50
+ # @param [Class] primitive
51
+ #
52
+ # @return [Class<Attribute>]
53
+ #
54
+ # @return [nil]
55
+ # nil if the type cannot be determined by the primitive
56
+ #
57
+ # @api private
58
+ def self.determine_type_from_primitive(primitive)
59
+ descendants.detect { |descendant| primitive <= descendant.primitive }
60
+ end
61
+
62
+ private_class_method :determine_type_from_primitive
63
+
64
+ # Return the Attribute class given a string
65
+ #
66
+ # @param [String] string
67
+ #
68
+ # @return [Class<Attribute>]
69
+ #
70
+ # @return [nil]
71
+ # nil if the type cannot be determined by the string
72
+ #
73
+ # @api private
74
+ def self.determine_type_from_string(string)
75
+ const_get(string) if const_defined?(string)
76
+ end
77
+
78
+ private_class_method :determine_type_from_string
79
+
9
80
  # Returns default options hash for a given attribute class
10
81
  #
11
82
  # @example
@@ -51,29 +122,23 @@ module Virtus
51
122
  #
52
123
  # @api public
53
124
  def self.accept_options(*new_options)
54
- # add new options to the array
55
- concat_options(new_options)
56
-
57
- # create methods for each new option
125
+ add_accepted_options(new_options)
58
126
  new_options.each { |option| add_option_method(option) }
59
-
60
- # add new options to all descendants
61
- descendants.each { |descendant| descendant.concat_options(new_options) }
62
-
63
- accepted_options
127
+ descendants.each { |descendant| descendant.add_accepted_options(new_options) }
128
+ self
64
129
  end
65
130
 
66
131
  # Adds a reader/writer method for the give option name
67
132
  #
68
- # @return [NilClass]
133
+ # @return [undefined]
69
134
  #
70
135
  # @api private
71
136
  def self.add_option_method(option)
72
137
  class_eval <<-RUBY, __FILE__, __LINE__ + 1
73
- def self.#{option}(value = Undefined) # def self.unique(value = Undefined)
74
- return @#{option} if value.equal?(Undefined) # return @unique if value.equal?(Undefined)
75
- @#{option} = value # @unique = value
76
- end # end
138
+ def self.#{option}(value = Undefined) # def self.primitive(value = Undefined)
139
+ return @#{option} if value.equal?(Undefined) # return @primitive if value.equal?(Undefined)
140
+ @#{option} = value # @primitive = value
141
+ end # end
77
142
  RUBY
78
143
  end
79
144
 
@@ -84,14 +149,14 @@ module Virtus
84
149
  # @param [#to_hash] new_options
85
150
  # options to be set
86
151
  #
87
- # @return [Hash]
88
- # default options set on the attribute class
152
+ # @return [self]
89
153
  #
90
154
  # @api private
91
155
  def self.set_options(new_options)
92
156
  new_options.to_hash.each do |option_name, option_value|
93
157
  send(option_name, option_value)
94
158
  end
159
+ self
95
160
  end
96
161
 
97
162
  # Adds new options that an attribute class can accept
@@ -99,12 +164,12 @@ module Virtus
99
164
  # @param [#to_ary] new_options
100
165
  # new options to be added
101
166
  #
102
- # @return [Array]
103
- # all accepted options
167
+ # @return [self]
104
168
  #
105
169
  # @api private
106
- def self.concat_options(new_options)
107
- accepted_options.concat(new_options.to_ary).uniq
170
+ def self.add_accepted_options(new_options)
171
+ accepted_options.concat(new_options.to_ary)
172
+ self
108
173
  end
109
174
 
110
175
  # Adds descendant to descendants array and inherits default options
@@ -116,19 +181,18 @@ module Virtus
116
181
  # @api private
117
182
  def self.inherited(descendant)
118
183
  super
119
- descendant.concat_options(accepted_options)
120
- descendant.set_options(options)
184
+ descendant.add_accepted_options(accepted_options).set_options(options)
121
185
  self
122
186
  end
123
187
 
124
188
  # Returns if the given value's class is an attribute's primitive
125
189
  #
126
190
  # @example
127
- # Virtus::Attribute::String.primitive?('String') # => true
191
+ # Virtus::Attribute::String.primitive?('String') # => true
128
192
  #
129
- # @return [TrueClass, FalseClass]
193
+ # @return [Boolean]
130
194
  #
131
- # @api semipublic
195
+ # @api public
132
196
  def self.primitive?(value)
133
197
  value.kind_of?(primitive)
134
198
  end
@@ -136,7 +200,7 @@ module Virtus
136
200
  # Returns name of the attribute
137
201
  #
138
202
  # @example
139
- # User.attributes[:age].name # => :age
203
+ # User.attributes[:age].name # => :age
140
204
  #
141
205
  # @return [Symbol]
142
206
  #
@@ -185,6 +249,8 @@ module Virtus
185
249
  # @param [#to_hash] options
186
250
  # hash of extra options which overrides defaults set on an attribute class
187
251
  #
252
+ # @return [undefined]
253
+ #
188
254
  # @api private
189
255
  def initialize(name, options = {})
190
256
  @name = name
@@ -199,12 +265,12 @@ module Virtus
199
265
  # Returns if an attribute is a complex one
200
266
  #
201
267
  # @example
202
- # Virtus::Attribute::String.complex? # => false
203
- # Virtus::Attribute::Array.complex? # => true
268
+ # Virtus::Attribute::String.complex? # => false
269
+ # Virtus::Attribute::Array.complex? # => true
204
270
  #
205
- # @return [TrueClass, FalseClass]
271
+ # @return [Boolean]
206
272
  #
207
- # @api semipublic
273
+ # @api public
208
274
  def complex?
209
275
  @complex
210
276
  end
@@ -228,6 +294,8 @@ module Virtus
228
294
 
229
295
  # Converts the given value to the primitive type
230
296
  #
297
+ # @return [Object]
298
+ #
231
299
  # @api private
232
300
  def typecast_to_primitive(value)
233
301
  value
@@ -275,7 +343,7 @@ module Virtus
275
343
 
276
344
  # Creates an attribute reader method
277
345
  #
278
- # @return [NilClass]
346
+ # @return [self]
279
347
  #
280
348
  # @api private
281
349
  def add_reader_method(model)
@@ -283,22 +351,24 @@ module Virtus
283
351
  method_name = name
284
352
 
285
353
  model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
286
- module AttributeMethods
287
- def #{method_name}
288
- return #{instance_variable_name} if defined?(#{instance_variable_name})
289
- attribute = self.class.attributes[#{method_name.inspect}]
290
- #{instance_variable_name} = attribute ? attribute.get(self) : nil
291
- end
292
- end
293
- include AttributeMethods
354
+ module AttributeMethods # module AttributeMethods
355
+ def #{method_name} # def name
356
+ return #{instance_variable_name} if defined?(#{instance_variable_name}) # return @name if defined?(@name)
357
+ attribute = self.class.attributes[#{method_name.inspect}] # attribute = self.class.attributes[:name]
358
+ #{instance_variable_name} = attribute ? attribute.get(self) : nil # @name = attribute ? attribute.get(self) : nil
359
+ end # end
360
+ end # end
361
+ include AttributeMethods # include AttributeMethods
294
362
  RUBY
295
363
 
296
364
  model.send(reader_visibility, method_name)
365
+
366
+ self
297
367
  end
298
368
 
299
369
  # Creates an attribute writer method
300
370
  #
301
- # @return [NilClass]
371
+ # @return [self]
302
372
  #
303
373
  # @api private
304
374
  def add_writer_method(model)
@@ -306,15 +376,17 @@ module Virtus
306
376
  method_name = "#{name}="
307
377
 
308
378
  model.class_eval <<-RUBY, __FILE__, __LINE__ + 1
309
- module AttributeMethods
310
- def #{method_name}(value)
311
- self.class.attributes[#{name.inspect}].set(self, value)
312
- end
313
- end
314
- include AttributeMethods
379
+ module AttributeMethods # module AttributeMethods
380
+ def #{method_name}(value) # def name=(value)
381
+ self.class.attributes[#{name.inspect}].set(self, value) # self.class.attributes[:name].set(self, value)
382
+ end # end
383
+ end # end
384
+ include AttributeMethods # include AttributeMethods
315
385
  RUBY
316
386
 
317
387
  model.send(writer_visibility, method_name)
388
+
389
+ self
318
390
  end
319
391
 
320
392
  private