active_data 1.0.0 → 1.1.0

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 (115) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +13 -0
  3. data/.rubocop.yml +56 -0
  4. data/.rubocop_todo.yml +53 -0
  5. data/.rvmrc +1 -1
  6. data/.travis.yml +15 -2
  7. data/Appraisals +1 -1
  8. data/CHANGELOG.md +31 -0
  9. data/Guardfile +8 -8
  10. data/README.md +256 -0
  11. data/Rakefile +2 -4
  12. data/active_data.gemspec +8 -7
  13. data/gemfiles/rails.4.0.gemfile +1 -1
  14. data/gemfiles/rails.4.1.gemfile +1 -1
  15. data/gemfiles/rails.4.2.gemfile +1 -1
  16. data/gemfiles/rails.5.0.gemfile +1 -1
  17. data/gemfiles/rails.5.1.gemfile +14 -0
  18. data/lib/active_data/active_record/associations.rb +18 -13
  19. data/lib/active_data/active_record/nested_attributes.rb +8 -14
  20. data/lib/active_data/base.rb +13 -0
  21. data/lib/active_data/config.rb +4 -4
  22. data/lib/active_data/errors.rb +29 -13
  23. data/lib/active_data/extensions.rb +22 -21
  24. data/lib/active_data/model/associations/base.rb +22 -6
  25. data/lib/active_data/model/associations/embeds_any.rb +17 -0
  26. data/lib/active_data/model/associations/embeds_many.rb +29 -19
  27. data/lib/active_data/model/associations/embeds_one.rb +30 -26
  28. data/lib/active_data/model/associations/nested_attributes.rb +82 -50
  29. data/lib/active_data/model/associations/persistence_adapters/active_record/referenced_proxy.rb +31 -0
  30. data/lib/active_data/model/associations/persistence_adapters/active_record.rb +66 -0
  31. data/lib/active_data/model/associations/persistence_adapters/base.rb +53 -0
  32. data/lib/active_data/model/associations/references_any.rb +41 -0
  33. data/lib/active_data/model/associations/references_many.rb +51 -37
  34. data/lib/active_data/model/associations/references_one.rb +43 -41
  35. data/lib/active_data/model/associations/reflections/base.rb +19 -29
  36. data/lib/active_data/model/associations/reflections/embeds_any.rb +43 -0
  37. data/lib/active_data/model/associations/reflections/embeds_many.rb +3 -13
  38. data/lib/active_data/model/associations/reflections/embeds_one.rb +5 -37
  39. data/lib/active_data/model/associations/reflections/references_any.rb +62 -0
  40. data/lib/active_data/model/associations/reflections/references_many.rb +7 -7
  41. data/lib/active_data/model/associations/reflections/references_one.rb +9 -7
  42. data/lib/active_data/model/associations/reflections/singular.rb +35 -0
  43. data/lib/active_data/model/associations/validations.rb +2 -27
  44. data/lib/active_data/model/associations.rb +12 -10
  45. data/lib/active_data/model/attributes/attribute.rb +10 -10
  46. data/lib/active_data/model/attributes/base.rb +8 -7
  47. data/lib/active_data/model/attributes/localized.rb +4 -4
  48. data/lib/active_data/model/attributes/reference_many.rb +6 -8
  49. data/lib/active_data/model/attributes/reference_one.rb +17 -9
  50. data/lib/active_data/model/attributes/reflections/attribute.rb +2 -2
  51. data/lib/active_data/model/attributes/reflections/base.rb +8 -11
  52. data/lib/active_data/model/attributes/reflections/localized.rb +2 -2
  53. data/lib/active_data/model/attributes/reflections/reference_one.rb +11 -22
  54. data/lib/active_data/model/attributes/reflections/represents.rb +5 -6
  55. data/lib/active_data/model/attributes/represents.rb +6 -5
  56. data/lib/active_data/model/attributes.rb +33 -87
  57. data/lib/active_data/model/callbacks.rb +6 -7
  58. data/lib/active_data/model/conventions.rb +2 -0
  59. data/lib/active_data/model/dirty.rb +4 -4
  60. data/lib/active_data/model/lifecycle.rb +18 -20
  61. data/lib/active_data/model/localization.rb +5 -2
  62. data/lib/active_data/model/persistence.rb +2 -2
  63. data/lib/active_data/model/primary.rb +19 -14
  64. data/lib/active_data/model/representation.rb +81 -0
  65. data/lib/active_data/model/scopes.rb +22 -12
  66. data/lib/active_data/model/validations/associated.rb +3 -2
  67. data/lib/active_data/model/validations/nested.rb +6 -1
  68. data/lib/active_data/model/validations.rb +3 -3
  69. data/lib/active_data/model.rb +2 -1
  70. data/lib/active_data/undefined_class.rb +9 -0
  71. data/lib/active_data/version.rb +1 -1
  72. data/lib/active_data.rb +40 -17
  73. data/spec/lib/active_data/active_record/associations_spec.rb +107 -45
  74. data/spec/lib/active_data/active_record/nested_attributes_spec.rb +1 -2
  75. data/spec/lib/active_data/config_spec.rb +37 -15
  76. data/spec/lib/active_data/model/associations/embeds_many_spec.rb +475 -172
  77. data/spec/lib/active_data/model/associations/embeds_one_spec.rb +353 -96
  78. data/spec/lib/active_data/model/associations/nested_attributes_spec.rb +108 -12
  79. data/spec/lib/active_data/model/associations/persistence_adapters/active_record_spec.rb +58 -0
  80. data/spec/lib/active_data/model/associations/references_many_spec.rb +440 -64
  81. data/spec/lib/active_data/model/associations/references_one_spec.rb +347 -36
  82. data/spec/lib/active_data/model/associations/reflections/embeds_many_spec.rb +8 -7
  83. data/spec/lib/active_data/model/associations/reflections/embeds_one_spec.rb +7 -6
  84. data/spec/lib/active_data/model/associations/reflections/references_many_spec.rb +81 -33
  85. data/spec/lib/active_data/model/associations/reflections/references_one_spec.rb +116 -37
  86. data/spec/lib/active_data/model/associations/validations_spec.rb +27 -43
  87. data/spec/lib/active_data/model/associations_spec.rb +34 -25
  88. data/spec/lib/active_data/model/attributes/attribute_spec.rb +26 -23
  89. data/spec/lib/active_data/model/attributes/base_spec.rb +5 -6
  90. data/spec/lib/active_data/model/attributes/collection_spec.rb +7 -8
  91. data/spec/lib/active_data/model/attributes/dictionary_spec.rb +40 -33
  92. data/spec/lib/active_data/model/attributes/localized_spec.rb +27 -28
  93. data/spec/lib/active_data/model/attributes/reflections/attribute_spec.rb +6 -6
  94. data/spec/lib/active_data/model/attributes/represents_spec.rb +10 -78
  95. data/spec/lib/active_data/model/attributes_spec.rb +150 -45
  96. data/spec/lib/active_data/model/callbacks_spec.rb +69 -70
  97. data/spec/lib/active_data/model/conventions_spec.rb +0 -1
  98. data/spec/lib/active_data/model/dirty_spec.rb +22 -13
  99. data/spec/lib/active_data/model/lifecycle_spec.rb +49 -23
  100. data/spec/lib/active_data/model/persistence_spec.rb +5 -6
  101. data/spec/lib/active_data/model/representation_spec.rb +126 -0
  102. data/spec/lib/active_data/model/scopes_spec.rb +1 -3
  103. data/spec/lib/active_data/model/typecasting_spec.rb +6 -5
  104. data/spec/lib/active_data/model/validations/associated_spec.rb +26 -18
  105. data/spec/lib/active_data/model/validations/nested_spec.rb +89 -18
  106. data/spec/lib/active_data/model_spec.rb +1 -2
  107. data/spec/lib/active_data_spec.rb +0 -1
  108. data/spec/shared/nested_attribute_examples.rb +332 -0
  109. data/spec/spec_helper.rb +3 -0
  110. data/spec/support/model_helpers.rb +2 -2
  111. data/spec/support/muffle_helper.rb +7 -0
  112. metadata +52 -18
  113. data/lib/active_data/model/associations/collection/referenced.rb +0 -26
  114. data/lib/active_data/model/associations/reflections/reference_reflection.rb +0 -45
  115. data/spec/lib/active_data/model/nested_attributes.rb +0 -202
@@ -1,6 +1,5 @@
1
1
  module ActiveData
2
2
  module Model
3
-
4
3
  # == Lifecycle methods for ActiveData::Model
5
4
  #
6
5
  # Provides methods +save+ and +destroy+ and its bang variants.
@@ -64,12 +63,11 @@ module ActiveData
64
63
  included do
65
64
  include Persistence
66
65
 
67
- class_attribute *[:save, :create, :update, :destroy].map { |action| "_#{action}_performer" }
68
- private *[:save, :create, :update, :destroy].map { |action| "_#{action}_performer=" }
66
+ class_attribute(*%i[save create update destroy].map { |action| "_#{action}_performer" })
67
+ private(*%i[save create update destroy].map { |action| "_#{action}_performer=" })
69
68
  end
70
69
 
71
70
  module ClassMethods
72
-
73
71
  # <tt>define_<action></tt> methods define performers for lifecycle
74
72
  # actions. Every action block must return boolean result, which
75
73
  # would mean the action success. If action performed unsuccessfully
@@ -108,7 +106,7 @@ module ActiveData
108
106
  # author = Author.create # using define_save performer
109
107
  # author.update_attributes(...) # using define_update performer
110
108
  #
111
- [:save, :create, :update, :destroy].each do |action|
109
+ %i[save create update destroy].each do |action|
112
110
  define_method "define_#{action}" do |&block|
113
111
  send("_#{action}_performer=", block)
114
112
  end
@@ -117,7 +115,7 @@ module ActiveData
117
115
  # Initializes new instance with attributes passed and calls +save+
118
116
  # on it. Returns instance in any case.
119
117
  #
120
- def create *args
118
+ def create(*args)
121
119
  new(*args).tap(&:save)
122
120
  end
123
121
 
@@ -125,7 +123,7 @@ module ActiveData
125
123
  # on it. Returns instance in case of success and raises ActiveData::ValidationError
126
124
  # or ActiveData::ObjectNotSaved in case of validation or saving fail respectively.
127
125
  #
128
- def create! *args
126
+ def create!(*args)
129
127
  new(*args).tap(&:save!)
130
128
  end
131
129
  end
@@ -139,7 +137,7 @@ module ActiveData
139
137
  # end
140
138
  # user.save! # => will use instance-level performer
141
139
  #
142
- [:save, :create, :update, :destroy].each do |action|
140
+ %i[save create update destroy].each do |action|
143
141
  define_method "define_#{action}" do |&block|
144
142
  send("_#{action}_performer=", block)
145
143
  end
@@ -158,7 +156,7 @@ module ActiveData
158
156
  #
159
157
  # author.update(name: 'Donald') { REDIS.set(id, attributes.to_json) }
160
158
  #
161
- def update attributes, &block
159
+ def update(attributes, &block)
162
160
  assign_attributes(attributes) && save(&block)
163
161
  end
164
162
  alias_method :update_attributes, :update
@@ -177,7 +175,7 @@ module ActiveData
177
175
  #
178
176
  # author.update!(name: 'Donald') { REDIS.set(id, attributes.to_json) }
179
177
  #
180
- def update! attributes, &block
178
+ def update!(attributes, &block)
181
179
  assign_attributes(attributes) && save!(&block)
182
180
  end
183
181
  alias_method :update_attributes!, :update!
@@ -196,7 +194,7 @@ module ActiveData
196
194
  #
197
195
  # author.save { REDIS.set(id, attributes.to_json) }
198
196
  #
199
- def save options = {}, &block
197
+ def save(_options = {}, &block)
200
198
  raise ActiveData::UnsavableObject unless block || savable?
201
199
  valid? && save_object(&block)
202
200
  end
@@ -216,7 +214,7 @@ module ActiveData
216
214
  #
217
215
  # author.save! { REDIS.set(id, attributes.to_json) }
218
216
  #
219
- def save! options = {}, &block
217
+ def save!(_options = {}, &block)
220
218
  raise ActiveData::UnsavableObject unless block || savable?
221
219
  validate!
222
220
  save_object(&block) or raise ActiveData::ObjectNotSaved
@@ -235,7 +233,7 @@ module ActiveData
235
233
  #
236
234
  # author.destroy { REDIS.del(id) }
237
235
  #
238
- def destroy &block
236
+ def destroy(&block)
239
237
  raise ActiveData::UndestroyableObject unless block || destroyable?
240
238
  destroy_object(&block)
241
239
  self
@@ -255,7 +253,7 @@ module ActiveData
255
253
  #
256
254
  # author.destroy! { REDIS.del(id) }
257
255
  #
258
- def destroy! &block
256
+ def destroy!(&block)
259
257
  raise ActiveData::UndestroyableObject unless block || destroyable?
260
258
  destroy_object(&block) or raise ActiveData::ObjectNotDestroyed
261
259
  self
@@ -267,19 +265,19 @@ module ActiveData
267
265
  !!((persisted? ? _update_performer : _create_performer) || _save_performer)
268
266
  end
269
267
 
270
- def save_object &block
268
+ def save_object(&block)
271
269
  apply_association_changes! if respond_to?(:apply_association_changes!)
272
270
  result = persisted? ? update_object(&block) : create_object(&block)
273
271
  mark_persisted! if result
274
272
  result
275
273
  end
276
274
 
277
- def create_object &block
275
+ def create_object(&block)
278
276
  performer = block || _create_performer || _save_performer
279
277
  !!performer_exec(&performer)
280
278
  end
281
279
 
282
- def update_object &block
280
+ def update_object(&block)
283
281
  performer = block || _update_performer || _save_performer
284
282
  !!performer_exec(&performer)
285
283
  end
@@ -288,16 +286,16 @@ module ActiveData
288
286
  !!_destroy_performer
289
287
  end
290
288
 
291
- def destroy_object &block
289
+ def destroy_object(&block)
292
290
  performer = block || _destroy_performer
293
291
  result = !!performer_exec(&performer)
294
292
  mark_destroyed! if result
295
293
  result
296
294
  end
297
295
 
298
- def performer_exec &block
296
+ def performer_exec(&block)
299
297
  if block.arity == 1
300
- block.call(self)
298
+ yield(self)
301
299
  else
302
300
  instance_exec(&block)
303
301
  end
@@ -1,14 +1,17 @@
1
+ require 'active_data/model/attributes/reflections/localized'
2
+ require 'active_data/model/attributes/localized'
3
+
1
4
  module ActiveData
2
5
  module Model
3
6
  module Localization
4
7
  extend ActiveSupport::Concern
5
8
 
6
9
  module ClassMethods
7
- def localized *args, &block
10
+ def localized(*args, &block)
8
11
  add_attribute(ActiveData::Model::Attributes::Reflections::Localized, *args, &block)
9
12
  end
10
13
 
11
- def fallbacks locale
14
+ def fallbacks(locale)
12
15
  ::I18n.respond_to?(:fallbacks) ? ::I18n.fallbacks[locale] : [locale]
13
16
  end
14
17
 
@@ -4,7 +4,7 @@ module ActiveData
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  module ClassMethods
7
- def instantiate data
7
+ def instantiate(data)
8
8
  data = data.stringify_keys
9
9
  instance = allocate
10
10
 
@@ -14,7 +14,7 @@ module ActiveData
14
14
  instance
15
15
  end
16
16
 
17
- def instantiate_collection data
17
+ def instantiate_collection(data)
18
18
  collection = Array.wrap(data).map { |attrs| instantiate attrs }
19
19
  collection = scope(collection, true) if respond_to?(:scope)
20
20
  collection
@@ -2,10 +2,12 @@ module ActiveData
2
2
  module Model
3
3
  module Primary
4
4
  extend ActiveSupport::Concern
5
- DEFAULT_PRIMARY_ATTRIBUTE_OPTIONS = -> { {
6
- type: ActiveData::UUID,
7
- default: -> { ActiveData::UUID.random_create }
8
- } }
5
+ DEFAULT_PRIMARY_ATTRIBUTE_OPTIONS = lambda do
6
+ {
7
+ type: ActiveData::UUID,
8
+ default: -> { ActiveData::UUID.random_create }
9
+ }
10
+ end
9
11
 
10
12
  included do
11
13
  class_attribute :_primary_name, instance_writer: false
@@ -16,18 +18,18 @@ module ActiveData
16
18
  end
17
19
 
18
20
  module ClassMethods
19
- def primary *args
21
+ def primary(*args)
20
22
  options = args.extract_options!
21
23
  self._primary_name = (args.first.presence || ActiveData.primary_attribute).to_s
22
24
  unless has_attribute?(_primary_name)
23
- options.merge!(type: args.second) if args.second
25
+ options[:type] = args.second if args.second
24
26
  attribute _primary_name, options.presence || DEFAULT_PRIMARY_ATTRIBUTE_OPTIONS.call
25
27
  end
26
28
  alias_attribute :primary_attribute, _primary_name
27
29
  end
28
30
  alias_method :primary_attribute, :primary
29
31
 
30
- def has_primary_attribute?
32
+ def has_primary_attribute? # rubocop:disable Naming/PredicateName
31
33
  has_attribute? _primary_name
32
34
  end
33
35
 
@@ -37,13 +39,16 @@ module ActiveData
37
39
  end
38
40
 
39
41
  module PrependMethods
40
- def == other
41
- other.instance_of?(self.class) &&
42
- has_primary_attribute? ?
43
- primary_attribute ?
44
- primary_attribute == other.primary_attribute :
45
- object_id == other.object_id :
46
- super(other)
42
+ def ==(other)
43
+ if other.instance_of?(self.class) && has_primary_attribute?
44
+ if primary_attribute
45
+ primary_attribute == other.primary_attribute
46
+ else
47
+ object_id == other.object_id
48
+ end
49
+ else
50
+ super(other)
51
+ end
47
52
  end
48
53
  end
49
54
  end
@@ -0,0 +1,81 @@
1
+ require 'active_data/model/attributes/reflections/represents'
2
+ require 'active_data/model/attributes/represents'
3
+
4
+ module ActiveData
5
+ module Model
6
+ module Representation
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ prepend PrependMethods
11
+ end
12
+
13
+ module PrependMethods
14
+ def assign_attributes(attrs)
15
+ if self.class.represented_attributes.present?
16
+ attrs = attrs.to_unsafe_hash if attrs.respond_to?(:to_unsafe_hash)
17
+ attrs = attrs.stringify_keys
18
+ represented_attrs = self.class.represented_names_and_aliases
19
+ .each_with_object({}) do |name, result|
20
+ result[name] = attrs.delete(name) if attrs.key?(name)
21
+ end
22
+
23
+ super(attrs.merge!(represented_attrs))
24
+ else
25
+ super(attrs)
26
+ end
27
+ end
28
+ alias_method :attributes=, :assign_attributes
29
+ end
30
+
31
+ module ClassMethods
32
+ def represents(*names, &block)
33
+ options = names.extract_options!
34
+ names.each do |name|
35
+ add_attribute(ActiveData::Model::Attributes::Reflections::Represents, name, options, &block)
36
+ end
37
+ end
38
+
39
+ def represented_attributes
40
+ @represented_attributes ||= _attributes.values.select do |attribute|
41
+ attribute.is_a? ActiveData::Model::Attributes::Reflections::Represents
42
+ end
43
+ end
44
+
45
+ def represented_names_and_aliases
46
+ @represented_names_and_aliases ||= represented_attributes.flat_map do |attribute|
47
+ [attribute.name, *inverted_attribute_aliases[attribute.name]]
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def run_validations! #:nodoc:
55
+ super
56
+ emerge_represented_attributes_errors!
57
+ errors.empty?
58
+ end
59
+
60
+ # Move represent attribute errors to the top level:
61
+ #
62
+ # {:'role.email' => ['Some error']}
63
+ #
64
+ # to:
65
+ #
66
+ # {email: ['Some error']}
67
+ #
68
+ def emerge_represented_attributes_errors!
69
+ self.class.represented_attributes.each do |attribute|
70
+ key = :"#{attribute.reference}.#{attribute.column}"
71
+ # Rails 5 pollutes messages with an empty array on key data fetch attempt
72
+ messages = errors.messages[key] if errors.messages.key?(key)
73
+ if messages.present?
74
+ errors[attribute.column].concat(messages)
75
+ errors.delete(key)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -20,27 +20,37 @@ module ActiveData
20
20
  end
21
21
 
22
22
  included do
23
- def initialize source = nil, trust = false
23
+ def initialize(source = nil, trust = false)
24
24
  source ||= self.class.superclass.new
25
25
 
26
- source.each do |entity|
27
- raise AssociationTypeMismatch.new(self.class._scope_model, entity.class) unless entity.is_a?(self.class._scope_model)
28
- end unless trust && source.is_a?(self.class)
26
+ unless trust && source.is_a?(self.class)
27
+ source.each do |entity|
28
+ raise AssociationTypeMismatch.new(self.class._scope_model, entity.class) unless entity.is_a?(self.class._scope_model)
29
+ end
30
+ end
29
31
 
30
32
  super source
31
33
  end
32
34
  end
33
35
 
34
- def respond_to_missing? method, _
36
+ def respond_to_missing?(method, _)
35
37
  super || self.class._scope_model.respond_to?(method)
36
38
  end
37
39
 
38
- def method_missing method, *args, &block
39
- with_scope { self.class._scope_model.public_send(method, *args, &block) }
40
+ def method_missing(method, *args, &block)
41
+ with_scope do
42
+ model = self.class._scope_model
43
+ if model.respond_to?(method)
44
+ self.class._scope_model.public_send(method, *args, &block)
45
+ else
46
+ super
47
+ end
48
+ end
40
49
  end
41
50
 
42
51
  def with_scope
43
- previous_scope, self.class._scope_model.current_scope = self.class._scope_model.current_scope, self
52
+ previous_scope = self.class._scope_model.current_scope
53
+ self.class._scope_model.current_scope = self
44
54
  result = yield
45
55
  self.class._scope_model.current_scope = previous_scope
46
56
  result
@@ -48,7 +58,7 @@ module ActiveData
48
58
  end
49
59
 
50
60
  module ClassMethods
51
- def scopify scope_base = Array
61
+ def scopify(scope_base = Array)
52
62
  self._scope_base = scope_base
53
63
  end
54
64
 
@@ -56,15 +66,15 @@ module ActiveData
56
66
  @scope_class ||= ActiveData::Model::Scopes::ScopeProxy.for(self)
57
67
  end
58
68
 
59
- def scope *args
69
+ def scope(*args)
60
70
  if args.empty?
61
71
  current_scope
62
72
  else
63
- scope_class.new *args
73
+ scope_class.new(*args)
64
74
  end
65
75
  end
66
76
 
67
- def current_scope= value
77
+ def current_scope=(value)
68
78
  @current_scope = value
69
79
  end
70
80
 
@@ -3,9 +3,10 @@ module ActiveData
3
3
  module Validations
4
4
  class AssociatedValidator < ActiveModel::EachValidator
5
5
  def validate_each(record, attribute, value)
6
- if Array.wrap(value).reject { |r| r.respond_to?(:valid?) && r.valid?(record.validation_context) }.any?
7
- record.errors.add(attribute, :invalid, options.merge(value: value))
6
+ invalid_records = Array.wrap(value).reject do |r|
7
+ r.respond_to?(:valid?) && r.valid?(record.validation_context)
8
8
  end
9
+ record.errors.add(attribute, :invalid, options.merge(value: value)) if invalid_records.present?
9
10
  end
10
11
  end
11
12
 
@@ -24,7 +24,7 @@ module ActiveData
24
24
 
25
25
  def validate_each(record, attribute, value)
26
26
  self.class.validate_nested(record, attribute, value) do |object|
27
- object.invalid?
27
+ object.invalid? && !(object.respond_to?(:marked_for_destruction?) && object.marked_for_destruction?)
28
28
  end
29
29
  end
30
30
  end
@@ -33,6 +33,11 @@ module ActiveData
33
33
  def validates_nested(*attr_names)
34
34
  validates_with NestedValidator, _merge_attributes(attr_names)
35
35
  end
36
+
37
+ def validates_nested?(attr)
38
+ _validators[attr.to_sym]
39
+ .grep(ActiveData::Model::Validations::NestedValidator).present?
40
+ end
36
41
  end
37
42
  end
38
43
  end
@@ -11,17 +11,17 @@ module ActiveData
11
11
  alias_method :validate, :valid?
12
12
  end
13
13
 
14
- def validate! context = nil
14
+ def validate!(context = nil)
15
15
  valid?(context) || raise_validation_error
16
16
  end
17
17
 
18
18
  protected
19
19
 
20
20
  def raise_validation_error
21
- raise ActiveData::ValidationError.new(self)
21
+ raise ActiveData::ValidationError, self
22
22
  end
23
23
  end
24
24
  end
25
25
  end
26
26
 
27
- Dir[File.dirname(__FILE__) + "/validations/*.rb"].each { |file| require file }
27
+ Dir[File.dirname(__FILE__) + '/validations/*.rb'].each { |file| require file }
@@ -1,13 +1,14 @@
1
1
  require 'active_data/model/conventions'
2
2
  require 'active_data/model/attributes'
3
+ require 'active_data/model/validations'
3
4
  require 'active_data/model/scopes'
4
5
  require 'active_data/model/primary'
5
6
  require 'active_data/model/lifecycle'
6
7
  require 'active_data/model/persistence'
7
8
  require 'active_data/model/callbacks'
8
9
  require 'active_data/model/associations'
9
- require 'active_data/model/validations'
10
10
  require 'active_data/model/localization'
11
+ require 'active_data/model/representation'
11
12
  require 'active_data/model/dirty'
12
13
 
13
14
  module ActiveData
@@ -0,0 +1,9 @@
1
+ require 'singleton'
2
+
3
+ module ActiveData
4
+ class UndefinedClass
5
+ include Singleton
6
+ end
7
+
8
+ UNDEFINED = UndefinedClass.instance.freeze
9
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveData
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'.freeze
3
3
  end
data/lib/active_data.rb CHANGED
@@ -10,8 +10,12 @@ require 'active_model'
10
10
  require 'active_data/version'
11
11
  require 'active_data/errors'
12
12
  require 'active_data/extensions'
13
+ require 'active_data/undefined_class'
13
14
  require 'active_data/config'
14
15
  require 'active_data/railtie' if defined? Rails
16
+ require 'active_data/model'
17
+ require 'active_data/model/associations/persistence_adapters/base'
18
+ require 'active_data/model/associations/persistence_adapters/active_record'
15
19
 
16
20
  module ActiveData
17
21
  BOOLEAN_MAPPING = {
@@ -32,33 +36,29 @@ module ActiveData
32
36
  'y' => true,
33
37
  'n' => false,
34
38
  'yes' => true,
35
- 'no' => false,
36
- }
39
+ 'no' => false
40
+ }.freeze
37
41
 
38
42
  def self.config
39
43
  ActiveData::Config.instance
40
44
  end
41
45
 
42
- singleton_class.delegate *ActiveData::Config.delegated, to: :config
46
+ singleton_class.delegate(*ActiveData::Config.delegated, to: :config)
43
47
 
44
48
  typecaster('Object') { |value, attribute| value if value.class < attribute.type }
45
- typecaster('String') { |value| value.to_s }
49
+ typecaster('String') { |value, _| value.to_s }
46
50
  typecaster('Array') do |value|
47
51
  case value
48
52
  when ::Array then
49
53
  value
50
54
  when ::String then
51
55
  value.split(',').map(&:strip)
52
- else
53
- nil
54
56
  end
55
57
  end
56
58
  typecaster('Hash') do |value|
57
59
  case value
58
60
  when ::Hash then
59
61
  value
60
- else
61
- nil
62
62
  end
63
63
  end
64
64
  typecaster('Date') do |value|
@@ -89,15 +89,36 @@ module ActiveData
89
89
  when ::TZInfo::Timezone
90
90
  ActiveSupport::TimeZone[value.name]
91
91
  when String, Numeric, ActiveSupport::Duration
92
- value = Float(value) rescue value
92
+ value = begin
93
+ Float(value)
94
+ rescue ArgumentError, TypeError
95
+ value
96
+ end
93
97
  ActiveSupport::TimeZone[value]
94
- else
98
+ end
99
+ end
100
+ typecaster('BigDecimal') do |value|
101
+ next unless value
102
+ begin
103
+ ::BigDecimal.new Float(value).to_s
104
+ rescue ArgumentError, TypeError
105
+ nil
106
+ end
107
+ end
108
+ typecaster('Float') do |value|
109
+ begin
110
+ Float(value)
111
+ rescue ArgumentError, TypeError
112
+ nil
113
+ end
114
+ end
115
+ typecaster('Integer') do |value|
116
+ begin
117
+ Float(value).to_i
118
+ rescue ArgumentError, TypeError
95
119
  nil
96
120
  end
97
121
  end
98
- typecaster('BigDecimal') { |value| ::BigDecimal.new Float(value).to_s rescue nil if value }
99
- typecaster('Float') { |value| Float(value) rescue nil }
100
- typecaster('Integer') { |value| Float(value).to_i rescue nil }
101
122
  typecaster('Boolean') { |value| BOOLEAN_MAPPING[value] }
102
123
  typecaster('ActiveData::UUID') do |value|
103
124
  case value
@@ -109,18 +130,20 @@ module ActiveData
109
130
  ActiveData::UUID.parse_string value
110
131
  when Integer
111
132
  ActiveData::UUID.parse_int value
112
- else
113
- nil
114
133
  end
115
134
  end
116
135
  end
117
136
 
118
- require 'active_data/model'
137
+ require 'active_data/base'
119
138
 
120
139
  ActiveSupport.on_load :active_record do
121
140
  require 'active_data/active_record/associations'
122
141
  require 'active_data/active_record/nested_attributes'
123
142
 
124
143
  include ActiveData::ActiveRecord::Associations
125
- include ActiveData::ActiveRecord::NestedAttributes
144
+ singleton_class.prepend ActiveData::ActiveRecord::NestedAttributes
145
+
146
+ def self.active_data_persistence_adapter
147
+ ActiveData::Model::Associations::PersistenceAdapters::ActiveRecord
148
+ end
126
149
  end