virtus 1.0.2 → 1.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.
- checksums.yaml +7 -0
- data/.ruby-version +1 -1
- data/.travis.yml +2 -2
- data/Changelog.md +11 -0
- data/Gemfile +4 -2
- data/Gemfile.devtools +25 -19
- data/README.md +56 -4
- data/lib/virtus.rb +26 -5
- data/lib/virtus/attribute/builder.rb +2 -2
- data/lib/virtus/attribute/collection.rb +7 -3
- data/lib/virtus/attribute/hash.rb +3 -3
- data/lib/virtus/attribute/strict.rb +1 -1
- data/lib/virtus/builder.rb +1 -1
- data/lib/virtus/configuration.rb +7 -36
- data/lib/virtus/instance_methods.rb +1 -0
- data/lib/virtus/module_extensions.rb +8 -2
- data/lib/virtus/support/options.rb +1 -0
- data/lib/virtus/support/type_lookup.rb +1 -1
- data/lib/virtus/version.rb +1 -1
- data/spec/integration/custom_attributes_spec.rb +2 -2
- data/spec/integration/custom_collection_attributes_spec.rb +6 -6
- data/spec/integration/default_values_spec.rb +8 -8
- data/spec/integration/defining_attributes_spec.rb +25 -18
- data/spec/integration/embedded_value_spec.rb +5 -5
- data/spec/integration/extending_objects_spec.rb +5 -5
- data/spec/integration/hash_attributes_coercion_spec.rb +11 -7
- data/spec/integration/mass_assignment_with_accessors_spec.rb +5 -5
- data/spec/integration/overriding_virtus_spec.rb +4 -4
- data/spec/integration/required_attributes_spec.rb +1 -1
- data/spec/integration/struct_as_embedded_value_spec.rb +4 -4
- data/spec/integration/using_modules_spec.rb +8 -8
- data/spec/integration/value_object_with_custom_constructor_spec.rb +4 -4
- data/spec/integration/virtus/instance_level_attributes_spec.rb +1 -1
- data/spec/integration/virtus/value_object_spec.rb +14 -14
- data/spec/shared/freeze_method_behavior.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/virtus/attribute/class_methods/build_spec.rb +9 -1
- data/spec/unit/virtus/attribute/collection/class_methods/build_spec.rb +13 -2
- data/spec/unit/virtus/attribute/collection/coerce_spec.rb +21 -0
- data/spec/unit/virtus/attribute/hash/class_methods/build_spec.rb +14 -2
- data/spec/unit/virtus/attribute_set/each_spec.rb +21 -16
- data/spec/unit/virtus/attribute_set/element_reference_spec.rb +1 -1
- data/spec/unit/virtus/attribute_set/reset_spec.rb +5 -3
- data/spec/unit/virtus/attribute_spec.rb +4 -3
- data/spec/unit/virtus/attributes_reader_spec.rb +1 -1
- data/spec/unit/virtus/attributes_writer_spec.rb +1 -1
- data/spec/unit/virtus/model_spec.rb +3 -3
- data/spec/unit/virtus/module_spec.rb +59 -2
- data/spec/unit/virtus/value_object_spec.rb +2 -2
- data/virtus.gemspec +2 -2
- metadata +34 -32
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 9159a933adbe9e8abeda7386590659134150c554
|
|
4
|
+
data.tar.gz: cd8c5f3edb39d1dc81d5796ab6a42ba941a1485f
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b57dce024748303a11bb12631e7133b8ac1ee66711bb08b09cd85080552d815c283596b8a9b7af9a87ae77e413592ece743f8059c8293b808d6e4a653bba7837
|
|
7
|
+
data.tar.gz: f1704e07a82c1de070711b117387fcb2bd067e7bfa95a8f46daf2e1bad818f3faa82500636004d0474e0994ab2a3eb7d1e123ad163b0727f015cdf5ac1ef8326
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1
|
|
1
|
+
2.1
|
data/.travis.yml
CHANGED
data/Changelog.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
# v1.0.3 2014-07-24
|
|
2
|
+
|
|
3
|
+
* [improvement] Expose attribute name in the exception when in strict mode (ntl)
|
|
4
|
+
* [improvement] Set #to_h as an alias to #to_hash (fnando)
|
|
5
|
+
* [fixed] Fix handling of nil in collection coercion (edgibbs)
|
|
6
|
+
* [fixed] Fix issues with using multiple virtus modules (trptcolin)
|
|
7
|
+
* [fixed] Fix handling of Range type (hampei)
|
|
8
|
+
* [fixed] Fix strict mode for collection and hash types (solnic)
|
|
9
|
+
|
|
10
|
+
[Compare v1.0.2..v1.0.3](https://github.com/solnic/virtus/compare/v1.0.2...v1.0.3)
|
|
11
|
+
|
|
1
12
|
# v1.0.2 2014-12-03
|
|
2
13
|
|
|
3
14
|
* [improvement] Don’t override already-defined default values when freezing (amarshall)
|
data/Gemfile
CHANGED
|
@@ -5,6 +5,8 @@ gemspec
|
|
|
5
5
|
gem 'bogus', '~> 0.1'
|
|
6
6
|
gem 'devtools', :git => 'https://github.com/rom-rb/devtools', branch: 'master'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
group :test do
|
|
9
|
+
gem 'inflecto', '~> 0.0.2'
|
|
10
|
+
end
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
eval_gemfile 'Gemfile.devtools'
|
data/Gemfile.devtools
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
3
|
group :development do
|
|
4
|
-
gem 'rake', '~> 10.
|
|
5
|
-
gem 'rspec', '~>
|
|
6
|
-
gem 'rspec-
|
|
7
|
-
gem 'yard', '~> 0.8.7'
|
|
4
|
+
gem 'rake', '~> 10.3.2'
|
|
5
|
+
gem 'rspec', '~> 3.0.0'
|
|
6
|
+
gem 'rspec-its', '~> 1.0.1'
|
|
7
|
+
gem 'yard', '~> 0.8.7.4'
|
|
8
8
|
|
|
9
9
|
platform :rbx do
|
|
10
10
|
gem 'rubysl-singleton', '~> 2.0.0'
|
|
@@ -12,45 +12,51 @@ group :development do
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
group :yard do
|
|
15
|
-
gem 'kramdown', '~> 1.3.
|
|
15
|
+
gem 'kramdown', '~> 1.3.3'
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
group :guard do
|
|
19
|
-
gem 'guard', '~> 2.
|
|
19
|
+
gem 'guard', '~> 2.6.1'
|
|
20
20
|
gem 'guard-bundler', '~> 2.0.0'
|
|
21
|
-
gem 'guard-rspec', '~> 4.2.
|
|
22
|
-
gem 'guard-rubocop', '~> 1.0
|
|
21
|
+
gem 'guard-rspec', '~> 4.2.9'
|
|
22
|
+
gem 'guard-rubocop', '~> 1.1.0'
|
|
23
23
|
|
|
24
24
|
# file system change event handling
|
|
25
|
-
gem 'listen', '~> 2.
|
|
25
|
+
gem 'listen', '~> 2.7.7'
|
|
26
26
|
gem 'rb-fchange', '~> 0.0.6', require: false
|
|
27
|
-
gem 'rb-fsevent', '~> 0.9.
|
|
28
|
-
gem 'rb-inotify', '~> 0.9.
|
|
27
|
+
gem 'rb-fsevent', '~> 0.9.4', require: false
|
|
28
|
+
gem 'rb-inotify', '~> 0.9.5', require: false
|
|
29
29
|
|
|
30
30
|
# notification handling
|
|
31
|
-
gem 'libnotify', '~> 0.8.
|
|
31
|
+
gem 'libnotify', '~> 0.8.3', require: false
|
|
32
32
|
gem 'rb-notifu', '~> 0.0.4', require: false
|
|
33
33
|
gem 'terminal-notifier-guard', '~> 1.5.3', require: false
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
group :metrics do
|
|
37
37
|
gem 'coveralls', '~> 0.7.0'
|
|
38
|
-
gem 'flay', '~> 2.
|
|
39
|
-
gem 'flog', '~> 4.2.
|
|
40
|
-
gem 'reek', '~> 1.3.
|
|
41
|
-
gem '
|
|
38
|
+
gem 'flay', '~> 2.5.0'
|
|
39
|
+
gem 'flog', '~> 4.2.1'
|
|
40
|
+
gem 'reek', '~> 1.3.7'
|
|
41
|
+
gem 'rubocop', '~> 0.23.0'
|
|
42
|
+
gem 'simplecov', '~> 0.7.1'
|
|
42
43
|
gem 'yardstick', '~> 0.9.9'
|
|
43
44
|
|
|
45
|
+
platforms :mri do
|
|
46
|
+
gem 'mutant', '~> 0.5.23'
|
|
47
|
+
gem 'mutant-rspec', '~> 0.5.21'
|
|
48
|
+
end
|
|
49
|
+
|
|
44
50
|
platforms :ruby_19, :ruby_20 do
|
|
45
51
|
gem 'yard-spellcheck', '~> 0.1.5'
|
|
46
52
|
end
|
|
47
53
|
|
|
48
54
|
platform :rbx do
|
|
49
55
|
gem 'json', '~> 1.8.1'
|
|
50
|
-
gem 'racc', '~> 1.4'
|
|
56
|
+
gem 'racc', '~> 1.4.11'
|
|
51
57
|
gem 'rubysl-logger', '~> 2.0.0'
|
|
52
58
|
gem 'rubysl-open-uri', '~> 2.0.0'
|
|
53
|
-
gem 'rubysl-prettyprint', '~> 2.0.
|
|
59
|
+
gem 'rubysl-prettyprint', '~> 2.0.3'
|
|
54
60
|
end
|
|
55
61
|
end
|
|
56
62
|
|
|
@@ -60,6 +66,6 @@ end
|
|
|
60
66
|
|
|
61
67
|
platform :jruby do
|
|
62
68
|
group :jruby do
|
|
63
|
-
gem 'jruby-openssl', '~> 0.
|
|
69
|
+
gem 'jruby-openssl', '~> 0.9.4'
|
|
64
70
|
end
|
|
65
71
|
end
|
data/README.md
CHANGED
|
@@ -6,14 +6,14 @@ Virtus
|
|
|
6
6
|
[][gemnasium]
|
|
7
7
|
[][codeclimate]
|
|
8
8
|
[][coveralls]
|
|
9
|
-
[][inchpages]
|
|
10
10
|
|
|
11
11
|
[gem]: https://rubygems.org/gems/virtus
|
|
12
12
|
[travis]: https://travis-ci.org/solnic/virtus
|
|
13
13
|
[gemnasium]: https://gemnasium.com/solnic/virtus
|
|
14
14
|
[codeclimate]: https://codeclimate.com/github/solnic/virtus
|
|
15
15
|
[coveralls]: https://coveralls.io/r/solnic/virtus
|
|
16
|
-
[inchpages]: http://inch-
|
|
16
|
+
[inchpages]: http://inch-ci.org/github/solnic/virtus
|
|
17
17
|
|
|
18
18
|
This is a partial extraction of the DataMapper [Property
|
|
19
19
|
API](http://rubydoc.info/github/datamapper/dm-core/master/DataMapper/Property)
|
|
@@ -273,6 +273,22 @@ package = Package.new(:dimensions => { 'width' => "2.2", :height => 2, "length"
|
|
|
273
273
|
package.dimensions # => { :width => 2.2, :height => 2.0, :length => 4.5 }
|
|
274
274
|
```
|
|
275
275
|
|
|
276
|
+
### IMPORTANT note about Boolean type
|
|
277
|
+
|
|
278
|
+
Be aware that some libraries may do a terrible thing and define a global Boolean
|
|
279
|
+
constant which breaks virtus' constant type lookup, if you see issues with the
|
|
280
|
+
boolean type you can workaround it like that:
|
|
281
|
+
|
|
282
|
+
``` ruby
|
|
283
|
+
class User
|
|
284
|
+
include Virtus.model
|
|
285
|
+
|
|
286
|
+
attribute :admin, Axiom::Types::Boolean
|
|
287
|
+
end
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
This will be improved in Virtus 2.0.
|
|
291
|
+
|
|
276
292
|
### IMPORTANT note about member coercions
|
|
277
293
|
|
|
278
294
|
Virtus performs coercions only when a value is being assigned. If you mutate the value later on using its own
|
|
@@ -383,7 +399,7 @@ end
|
|
|
383
399
|
class User
|
|
384
400
|
include Virtus.model
|
|
385
401
|
|
|
386
|
-
attribute :info, Json
|
|
402
|
+
attribute :info, Json, default: {}
|
|
387
403
|
end
|
|
388
404
|
|
|
389
405
|
user = User.new
|
|
@@ -429,6 +445,31 @@ user.set_unique_id('1234-1234')
|
|
|
429
445
|
user.unique_id # => '1234-1234'
|
|
430
446
|
```
|
|
431
447
|
|
|
448
|
+
### Overriding setters
|
|
449
|
+
|
|
450
|
+
``` ruby
|
|
451
|
+
class User
|
|
452
|
+
include Virtus.model
|
|
453
|
+
|
|
454
|
+
attribute :name, String
|
|
455
|
+
|
|
456
|
+
def name=(new_name)
|
|
457
|
+
custom_name = nil
|
|
458
|
+
if new_name == "Godzilla"
|
|
459
|
+
custom_name = "Can't tell"
|
|
460
|
+
end
|
|
461
|
+
super custom_name || new_name
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
user = User.new(name: "Frank")
|
|
466
|
+
user.name # => 'Frank'
|
|
467
|
+
|
|
468
|
+
user = User.new(name: "Godzilla")
|
|
469
|
+
user.name # => 'Can't tell'
|
|
470
|
+
|
|
471
|
+
```
|
|
472
|
+
|
|
432
473
|
## Strict Coercion Mode
|
|
433
474
|
|
|
434
475
|
By default Virtus returns the input value even when it couldn't coerce it to the expected type.
|
|
@@ -453,7 +494,7 @@ You can also build Virtus modules that contain their own configuration.
|
|
|
453
494
|
```ruby
|
|
454
495
|
YupNopeBooleans = Virtus.model { |mod|
|
|
455
496
|
mod.coerce = true
|
|
456
|
-
mod.string.boolean_map = { '
|
|
497
|
+
mod.coercer.config.string.boolean_map = { 'nope' => false, 'yup' => true }
|
|
457
498
|
}
|
|
458
499
|
|
|
459
500
|
class User
|
|
@@ -501,6 +542,17 @@ Blog.attribute_set[:posts].member_type.primitive # => Post
|
|
|
501
542
|
Post.attribute_set[:blog].type.primitive # => Blog
|
|
502
543
|
```
|
|
503
544
|
|
|
545
|
+
Ruby version support
|
|
546
|
+
--------------------
|
|
547
|
+
|
|
548
|
+
Virtus is known to work correctly with the following rubies:
|
|
549
|
+
|
|
550
|
+
* 1.9.3
|
|
551
|
+
* 2.0.0
|
|
552
|
+
* 2.1.2
|
|
553
|
+
* jruby
|
|
554
|
+
* (probably) rbx
|
|
555
|
+
|
|
504
556
|
Credits
|
|
505
557
|
-------
|
|
506
558
|
|
data/lib/virtus.rb
CHANGED
|
@@ -11,11 +11,31 @@ module Virtus
|
|
|
11
11
|
Undefined = Object.new.freeze
|
|
12
12
|
|
|
13
13
|
class CoercionError < StandardError
|
|
14
|
-
attr_reader :output, :
|
|
14
|
+
attr_reader :output, :attribute
|
|
15
15
|
|
|
16
|
-
def initialize(output,
|
|
17
|
-
@output, @
|
|
18
|
-
super(
|
|
16
|
+
def initialize(output, attribute)
|
|
17
|
+
@output, @attribute = output, attribute
|
|
18
|
+
super(build_message)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def build_message
|
|
22
|
+
if attribute_name?
|
|
23
|
+
"Failed to coerce attribute `#{attribute_name}' from #{output.inspect} into #{target_type}"
|
|
24
|
+
else
|
|
25
|
+
"Failed to coerce #{output.inspect} into #{target_type}"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def attribute_name
|
|
30
|
+
attribute.options[:name]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def attribute_name?
|
|
34
|
+
attribute_name ? true : false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def target_type
|
|
38
|
+
attribute.primitive.inspect
|
|
19
39
|
end
|
|
20
40
|
end
|
|
21
41
|
|
|
@@ -101,7 +121,8 @@ module Virtus
|
|
|
101
121
|
#
|
|
102
122
|
# @api public
|
|
103
123
|
def self.config(&block)
|
|
104
|
-
configuration
|
|
124
|
+
yield configuration if block_given?
|
|
125
|
+
configuration
|
|
105
126
|
end
|
|
106
127
|
|
|
107
128
|
# Provides access to the Virtus module builder
|
|
@@ -53,7 +53,7 @@ module Virtus
|
|
|
53
53
|
|
|
54
54
|
# @api private
|
|
55
55
|
def pending?
|
|
56
|
-
@pending
|
|
56
|
+
@pending if defined?(@pending)
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
private
|
|
@@ -107,7 +107,7 @@ module Virtus
|
|
|
107
107
|
determine_type(klass.primitive)
|
|
108
108
|
elsif EmbeddedValue.handles?(klass)
|
|
109
109
|
EmbeddedValue
|
|
110
|
-
elsif klass < Enumerable
|
|
110
|
+
elsif klass < Enumerable && !(klass <= Range)
|
|
111
111
|
Collection
|
|
112
112
|
end
|
|
113
113
|
end
|
|
@@ -66,12 +66,16 @@ module Virtus
|
|
|
66
66
|
|
|
67
67
|
# @api private
|
|
68
68
|
def self.merge_options!(type, options)
|
|
69
|
-
options[:member_type] ||= Attribute.build(type.member_type)
|
|
69
|
+
options[:member_type] ||= Attribute.build(type.member_type, strict: options[:strict])
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
# @api public
|
|
73
|
-
def coerce(
|
|
74
|
-
|
|
73
|
+
def coerce(value)
|
|
74
|
+
coerced = super
|
|
75
|
+
|
|
76
|
+
return coerced unless coerced.respond_to?(:each_with_object)
|
|
77
|
+
|
|
78
|
+
coerced.each_with_object(primitive.new) do |entry, collection|
|
|
75
79
|
collection << member_type.coerce(entry)
|
|
76
80
|
end
|
|
77
81
|
end
|
|
@@ -70,7 +70,7 @@ module Virtus
|
|
|
70
70
|
value_type
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
{ :key_type
|
|
73
|
+
{ :key_type => key_primitive, :value_type => value_primitive}
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
|
|
@@ -92,8 +92,8 @@ module Virtus
|
|
|
92
92
|
|
|
93
93
|
# @api private
|
|
94
94
|
def self.merge_options!(type, options)
|
|
95
|
-
options[:key_type] ||= Attribute.build(type.key_type)
|
|
96
|
-
options[:value_type] ||= Attribute.build(type.value_type)
|
|
95
|
+
options[:key_type] ||= Attribute.build(type.key_type, :strict => options[:strict])
|
|
96
|
+
options[:value_type] ||= Attribute.build(type.value_type, :strict => options[:strict])
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
# Coerce members
|
data/lib/virtus/builder.rb
CHANGED
data/lib/virtus/configuration.rb
CHANGED
|
@@ -18,49 +18,20 @@ module Virtus
|
|
|
18
18
|
# Access the mass-assignment setting for this instance
|
|
19
19
|
attr_accessor :mass_assignment
|
|
20
20
|
|
|
21
|
-
# Build new configuration instance using the passed block
|
|
22
|
-
#
|
|
23
|
-
# @example
|
|
24
|
-
# Configuration.build do |config|
|
|
25
|
-
# config.coerce = false
|
|
26
|
-
# end
|
|
27
|
-
#
|
|
28
|
-
# @return [Configuration]
|
|
29
|
-
#
|
|
30
|
-
# @api public
|
|
31
|
-
def self.build(options = {}, &block)
|
|
32
|
-
config = new.call(&block)
|
|
33
|
-
options.each { |key, value| config.public_send("#{key}=", value) }
|
|
34
|
-
config
|
|
35
|
-
end
|
|
36
|
-
|
|
37
21
|
# Initialized a configuration instance
|
|
38
22
|
#
|
|
39
23
|
# @return [undefined]
|
|
40
24
|
#
|
|
41
25
|
# @api private
|
|
42
|
-
def initialize
|
|
43
|
-
@finalize = true
|
|
44
|
-
@coerce = true
|
|
45
|
-
@strict = false
|
|
46
|
-
@constructor = true
|
|
47
|
-
@mass_assignment = true
|
|
26
|
+
def initialize(options={})
|
|
27
|
+
@finalize = options.fetch(:finalize,true)
|
|
28
|
+
@coerce = options.fetch(:coerce,true)
|
|
29
|
+
@strict = options.fetch(:strict,false)
|
|
30
|
+
@constructor = options.fetch(:constructor,true)
|
|
31
|
+
@mass_assignment = options.fetch(:mass_assignment,true)
|
|
48
32
|
@coercer = Coercible::Coercer.new
|
|
49
|
-
end
|
|
50
33
|
|
|
51
|
-
|
|
52
|
-
#
|
|
53
|
-
# @example
|
|
54
|
-
# configuration.call do |config|
|
|
55
|
-
# config.coerce = false
|
|
56
|
-
# end
|
|
57
|
-
#
|
|
58
|
-
# @return [self]
|
|
59
|
-
#
|
|
60
|
-
# @api private
|
|
61
|
-
def call(&block)
|
|
62
|
-
block.call(self) if block_given?
|
|
63
|
-
self
|
|
34
|
+
yield self if block_given?
|
|
64
35
|
end
|
|
65
36
|
|
|
66
37
|
# Access the coercer for this instance and optional configure a
|
|
@@ -15,7 +15,9 @@ module Virtus
|
|
|
15
15
|
# @api private
|
|
16
16
|
def self.setup(mod, inclusions = [Model], attribute_definitions = [])
|
|
17
17
|
mod.instance_variable_set('@inclusions', inclusions)
|
|
18
|
-
mod.
|
|
18
|
+
existing_attributes = mod.instance_variable_get('@attribute_definitions')
|
|
19
|
+
new_attributes = (existing_attributes || []) + attribute_definitions
|
|
20
|
+
mod.instance_variable_set('@attribute_definitions', new_attributes)
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
# Define an attribute in the module
|
|
@@ -57,7 +59,11 @@ module Virtus
|
|
|
57
59
|
super
|
|
58
60
|
|
|
59
61
|
if Class === object
|
|
60
|
-
@inclusions.
|
|
62
|
+
@inclusions.reject do |mod|
|
|
63
|
+
object.ancestors.include?(mod)
|
|
64
|
+
end.each do |mod|
|
|
65
|
+
object.send(:include, mod)
|
|
66
|
+
end
|
|
61
67
|
define_attributes(object)
|
|
62
68
|
else
|
|
63
69
|
object.extend(ModuleExtensions)
|