active_data 0.3.0 → 1.0.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/.rspec +0 -1
- data/.rvmrc +1 -1
- data/.travis.yml +13 -6
- data/Appraisals +7 -0
- data/Gemfile +1 -5
- data/Guardfile +68 -15
- data/README.md +144 -2
- data/active_data.gemspec +19 -11
- data/gemfiles/rails.4.0.gemfile +14 -0
- data/gemfiles/rails.4.1.gemfile +14 -0
- data/gemfiles/rails.4.2.gemfile +14 -0
- data/gemfiles/rails.5.0.gemfile +14 -0
- data/lib/active_data.rb +120 -3
- data/lib/active_data/active_record/associations.rb +50 -0
- data/lib/active_data/active_record/nested_attributes.rb +24 -0
- data/lib/active_data/config.rb +40 -0
- data/lib/active_data/errors.rb +93 -0
- data/lib/active_data/extensions.rb +33 -0
- data/lib/active_data/model.rb +16 -74
- data/lib/active_data/model/associations.rb +84 -15
- data/lib/active_data/model/associations/base.rb +79 -0
- data/lib/active_data/model/associations/collection/embedded.rb +12 -0
- data/lib/active_data/model/associations/collection/proxy.rb +32 -0
- data/lib/active_data/model/associations/collection/referenced.rb +26 -0
- data/lib/active_data/model/associations/embeds_many.rb +124 -18
- data/lib/active_data/model/associations/embeds_one.rb +90 -15
- data/lib/active_data/model/associations/nested_attributes.rb +180 -0
- data/lib/active_data/model/associations/references_many.rb +96 -0
- data/lib/active_data/model/associations/references_one.rb +83 -0
- data/lib/active_data/model/associations/reflections/base.rb +100 -0
- data/lib/active_data/model/associations/reflections/embeds_many.rb +25 -0
- data/lib/active_data/model/associations/reflections/embeds_one.rb +49 -0
- data/lib/active_data/model/associations/reflections/reference_reflection.rb +45 -0
- data/lib/active_data/model/associations/reflections/references_many.rb +28 -0
- data/lib/active_data/model/associations/reflections/references_one.rb +28 -0
- data/lib/active_data/model/associations/validations.rb +63 -0
- data/lib/active_data/model/attributes.rb +247 -0
- data/lib/active_data/model/attributes/attribute.rb +73 -0
- data/lib/active_data/model/attributes/base.rb +116 -0
- data/lib/active_data/model/attributes/collection.rb +17 -0
- data/lib/active_data/model/attributes/dictionary.rb +26 -0
- data/lib/active_data/model/attributes/localized.rb +42 -0
- data/lib/active_data/model/attributes/reference_many.rb +21 -0
- data/lib/active_data/model/attributes/reference_one.rb +42 -0
- data/lib/active_data/model/attributes/reflections/attribute.rb +55 -0
- data/lib/active_data/model/attributes/reflections/base.rb +62 -0
- data/lib/active_data/model/attributes/reflections/collection.rb +10 -0
- data/lib/active_data/model/attributes/reflections/dictionary.rb +13 -0
- data/lib/active_data/model/attributes/reflections/localized.rb +43 -0
- data/lib/active_data/model/attributes/reflections/reference_many.rb +10 -0
- data/lib/active_data/model/attributes/reflections/reference_one.rb +58 -0
- data/lib/active_data/model/attributes/reflections/represents.rb +55 -0
- data/lib/active_data/model/attributes/represents.rb +64 -0
- data/lib/active_data/model/callbacks.rb +71 -0
- data/lib/active_data/model/conventions.rb +35 -0
- data/lib/active_data/model/dirty.rb +77 -0
- data/lib/active_data/model/lifecycle.rb +307 -0
- data/lib/active_data/model/localization.rb +21 -0
- data/lib/active_data/model/persistence.rb +57 -0
- data/lib/active_data/model/primary.rb +51 -0
- data/lib/active_data/model/scopes.rb +77 -0
- data/lib/active_data/model/validations.rb +27 -0
- data/lib/active_data/model/validations/associated.rb +19 -0
- data/lib/active_data/model/validations/nested.rb +39 -0
- data/lib/active_data/railtie.rb +7 -0
- data/lib/active_data/version.rb +1 -1
- data/spec/lib/active_data/active_record/associations_spec.rb +149 -0
- data/spec/lib/active_data/active_record/nested_attributes_spec.rb +16 -0
- data/spec/lib/active_data/config_spec.rb +44 -0
- data/spec/lib/active_data/model/associations/embeds_many_spec.rb +362 -52
- data/spec/lib/active_data/model/associations/embeds_one_spec.rb +250 -31
- data/spec/lib/active_data/model/associations/nested_attributes_spec.rb +23 -0
- data/spec/lib/active_data/model/associations/references_many_spec.rb +196 -0
- data/spec/lib/active_data/model/associations/references_one_spec.rb +134 -0
- data/spec/lib/active_data/model/associations/reflections/embeds_many_spec.rb +144 -0
- data/spec/lib/active_data/model/associations/reflections/embeds_one_spec.rb +116 -0
- data/spec/lib/active_data/model/associations/reflections/references_many_spec.rb +255 -0
- data/spec/lib/active_data/model/associations/reflections/references_one_spec.rb +208 -0
- data/spec/lib/active_data/model/associations/validations_spec.rb +153 -0
- data/spec/lib/active_data/model/associations_spec.rb +189 -0
- data/spec/lib/active_data/model/attributes/attribute_spec.rb +144 -0
- data/spec/lib/active_data/model/attributes/base_spec.rb +82 -0
- data/spec/lib/active_data/model/attributes/collection_spec.rb +73 -0
- data/spec/lib/active_data/model/attributes/dictionary_spec.rb +93 -0
- data/spec/lib/active_data/model/attributes/localized_spec.rb +88 -33
- data/spec/lib/active_data/model/attributes/reflections/attribute_spec.rb +72 -0
- data/spec/lib/active_data/model/attributes/reflections/base_spec.rb +56 -0
- data/spec/lib/active_data/model/attributes/reflections/collection_spec.rb +37 -0
- data/spec/lib/active_data/model/attributes/reflections/dictionary_spec.rb +43 -0
- data/spec/lib/active_data/model/attributes/reflections/localized_spec.rb +37 -0
- data/spec/lib/active_data/model/attributes/reflections/represents_spec.rb +70 -0
- data/spec/lib/active_data/model/attributes/represents_spec.rb +153 -0
- data/spec/lib/active_data/model/attributes_spec.rb +243 -0
- data/spec/lib/active_data/model/callbacks_spec.rb +338 -0
- data/spec/lib/active_data/model/conventions_spec.rb +12 -0
- data/spec/lib/active_data/model/dirty_spec.rb +75 -0
- data/spec/lib/active_data/model/lifecycle_spec.rb +330 -0
- data/spec/lib/active_data/model/nested_attributes.rb +202 -0
- data/spec/lib/active_data/model/persistence_spec.rb +47 -0
- data/spec/lib/active_data/model/primary_spec.rb +84 -0
- data/spec/lib/active_data/model/scopes_spec.rb +88 -0
- data/spec/lib/active_data/model/typecasting_spec.rb +192 -0
- data/spec/lib/active_data/model/validations/associated_spec.rb +94 -0
- data/spec/lib/active_data/model/validations/nested_spec.rb +93 -0
- data/spec/lib/active_data/model/validations_spec.rb +31 -0
- data/spec/lib/active_data/model_spec.rb +1 -32
- data/spec/lib/active_data_spec.rb +12 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/model_helpers.rb +10 -0
- metadata +246 -54
- data/gemfiles/Gemfile.rails-3 +0 -14
- data/lib/active_data/attributes/base.rb +0 -69
- data/lib/active_data/attributes/localized.rb +0 -42
- data/lib/active_data/model/associations/association.rb +0 -30
- data/lib/active_data/model/attributable.rb +0 -122
- data/lib/active_data/model/collectionizable.rb +0 -55
- data/lib/active_data/model/collectionizable/proxy.rb +0 -42
- data/lib/active_data/model/extensions.rb +0 -9
- data/lib/active_data/model/extensions/array.rb +0 -24
- data/lib/active_data/model/extensions/big_decimal.rb +0 -17
- data/lib/active_data/model/extensions/boolean.rb +0 -38
- data/lib/active_data/model/extensions/date.rb +0 -17
- data/lib/active_data/model/extensions/date_time.rb +0 -17
- data/lib/active_data/model/extensions/float.rb +0 -17
- data/lib/active_data/model/extensions/hash.rb +0 -22
- data/lib/active_data/model/extensions/integer.rb +0 -17
- data/lib/active_data/model/extensions/localized.rb +0 -22
- data/lib/active_data/model/extensions/object.rb +0 -17
- data/lib/active_data/model/extensions/string.rb +0 -17
- data/lib/active_data/model/extensions/time.rb +0 -17
- data/lib/active_data/model/localizable.rb +0 -31
- data/lib/active_data/model/nested_attributes.rb +0 -58
- data/lib/active_data/model/parameterizable.rb +0 -29
- data/lib/active_data/validations.rb +0 -7
- data/lib/active_data/validations/associated.rb +0 -17
- data/spec/lib/active_data/model/attributable_spec.rb +0 -191
- data/spec/lib/active_data/model/collectionizable_spec.rb +0 -60
- data/spec/lib/active_data/model/nested_attributes_spec.rb +0 -67
- data/spec/lib/active_data/model/type_cast_spec.rb +0 -116
- data/spec/lib/active_data/validations/associated_spec.rb +0 -88
@@ -0,0 +1,64 @@
|
|
1
|
+
module ActiveData
|
2
|
+
module Model
|
3
|
+
module Attributes
|
4
|
+
class Represents < Attribute
|
5
|
+
delegate :reader, :reader_before_type_cast, :writer, to: :reflection
|
6
|
+
|
7
|
+
def write value
|
8
|
+
return if readonly?
|
9
|
+
pollute do
|
10
|
+
reset
|
11
|
+
reference.send(writer, value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def reset
|
16
|
+
super
|
17
|
+
remove_variable(:cached_value, :cached_value_before_type_cast)
|
18
|
+
end
|
19
|
+
|
20
|
+
def read
|
21
|
+
reset if cached_value != read_value
|
22
|
+
variable_cache(:value) do
|
23
|
+
normalize(enumerize(defaultize(cached_value, read_before_type_cast)))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def read_before_type_cast
|
28
|
+
reset if cached_value_before_type_cast != read_value_before_type_cast
|
29
|
+
variable_cache(:value_before_type_cast) do
|
30
|
+
defaultize(cached_value_before_type_cast)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def reference
|
37
|
+
owner.send(reflection.reference)
|
38
|
+
end
|
39
|
+
|
40
|
+
def read_value
|
41
|
+
ref = reference
|
42
|
+
ref.public_send(reader) if ref
|
43
|
+
end
|
44
|
+
|
45
|
+
def cached_value
|
46
|
+
variable_cache(:cached_value) { read_value }
|
47
|
+
end
|
48
|
+
|
49
|
+
def read_value_before_type_cast
|
50
|
+
ref = reference
|
51
|
+
if ref
|
52
|
+
ref.respond_to?(reader_before_type_cast) ?
|
53
|
+
ref.public_send(reader_before_type_cast) :
|
54
|
+
ref.public_send(reader)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def cached_value_before_type_cast
|
59
|
+
variable_cache(:cached_value_before_type_cast) { read_value_before_type_cast }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module ActiveData
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# == Callbacks for ActiveData::Model lifecycle
|
5
|
+
#
|
6
|
+
# Provides ActiveModel callbacks support for lifecycle
|
7
|
+
# actions.
|
8
|
+
#
|
9
|
+
# class Book
|
10
|
+
# include ActiveData::Model
|
11
|
+
#
|
12
|
+
# attribute :id, Integer
|
13
|
+
# attribute :title, String
|
14
|
+
#
|
15
|
+
# define_save do
|
16
|
+
# REDIS.set(id, attributes.to_json)
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# define_destroy do
|
20
|
+
# REDIS.del(instance.id)
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# after_initialize :setup_id
|
24
|
+
# before_save :do_something
|
25
|
+
# around_update do |&block|
|
26
|
+
# ...
|
27
|
+
# block.call
|
28
|
+
# ...
|
29
|
+
# end
|
30
|
+
# after_destroy { ... }
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
module Callbacks
|
34
|
+
extend ActiveSupport::Concern
|
35
|
+
|
36
|
+
included do
|
37
|
+
extend ActiveModel::Callbacks
|
38
|
+
|
39
|
+
include ActiveModel::Validations::Callbacks
|
40
|
+
include Lifecycle
|
41
|
+
prepend PrependMethods
|
42
|
+
|
43
|
+
define_model_callbacks :initialize, only: :after
|
44
|
+
define_model_callbacks :save, :create, :update, :destroy
|
45
|
+
end
|
46
|
+
|
47
|
+
module PrependMethods
|
48
|
+
def initialize *_
|
49
|
+
super(*_)
|
50
|
+
run_callbacks :initialize
|
51
|
+
end
|
52
|
+
|
53
|
+
def save_object &block
|
54
|
+
run_callbacks(:save) { super(&block) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_object &block
|
58
|
+
run_callbacks(:create) { super(&block) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def update_object &block
|
62
|
+
run_callbacks(:update) { super(&block) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def destroy_object &block
|
66
|
+
run_callbacks(:destroy) { super(&block) }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ActiveData
|
2
|
+
module Model
|
3
|
+
module Conventions
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
delegate :logger, to: ActiveData
|
8
|
+
self.include_root_in_json = ActiveData.include_root_in_json
|
9
|
+
end
|
10
|
+
|
11
|
+
def persisted?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
def new_record?
|
16
|
+
!persisted?
|
17
|
+
end
|
18
|
+
alias_method :new_object?, :new_record?
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def i18n_scope
|
22
|
+
ActiveData.i18n_scope
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_ary
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def primary_name
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module ActiveData
|
2
|
+
module Model
|
3
|
+
module Dirty
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
::Module.class_eval do
|
7
|
+
alias_method :unconcerned_append_features, :append_features
|
8
|
+
end
|
9
|
+
|
10
|
+
DIRTY_CLONE = ActiveModel::Dirty.clone
|
11
|
+
DIRTY_CLONE.class_eval do
|
12
|
+
def self.append_features(base)
|
13
|
+
unconcerned_append_features(base)
|
14
|
+
end
|
15
|
+
def self.included(base)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
included do
|
20
|
+
include DIRTY_CLONE
|
21
|
+
|
22
|
+
unless method_defined?(:set_attribute_was)
|
23
|
+
def set_attribute_was(attr, old_value)
|
24
|
+
changed_attributes[attr] = old_value
|
25
|
+
end
|
26
|
+
private :set_attribute_was
|
27
|
+
end
|
28
|
+
|
29
|
+
unless method_defined?(:clear_changes_information)
|
30
|
+
if method_defined?(:reset_changes)
|
31
|
+
def clear_changes_information
|
32
|
+
reset_changes
|
33
|
+
end
|
34
|
+
else
|
35
|
+
def clear_changes_information
|
36
|
+
@previously_changed = nil
|
37
|
+
@changed_attributes = nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
attribute_names(false).each do |name|
|
43
|
+
define_dirty name, generated_attributes_methods
|
44
|
+
end
|
45
|
+
_attribute_aliases.keys.each do |name|
|
46
|
+
define_dirty name, generated_attributes_methods
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module ClassMethods
|
51
|
+
def define_dirty method, target = self
|
52
|
+
reflection = reflect_on_attribute(method)
|
53
|
+
name = reflection ? reflection.name : method
|
54
|
+
|
55
|
+
%w[changed? change will_change! was
|
56
|
+
previously_changed? previous_change].each do |suffix|
|
57
|
+
target.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
58
|
+
def #{method}_#{suffix}
|
59
|
+
attribute_#{suffix} '#{name}'
|
60
|
+
end
|
61
|
+
RUBY
|
62
|
+
end
|
63
|
+
|
64
|
+
target.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
65
|
+
def restore_#{method}!
|
66
|
+
restore_attribute! '#{name}'
|
67
|
+
end
|
68
|
+
RUBY
|
69
|
+
end
|
70
|
+
|
71
|
+
def dirty?
|
72
|
+
true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,307 @@
|
|
1
|
+
module ActiveData
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# == Lifecycle methods for ActiveData::Model
|
5
|
+
#
|
6
|
+
# Provides methods +save+ and +destroy+ and its bang variants.
|
7
|
+
# Also, patches +create+ and +update_attributes+ methods by adding
|
8
|
+
# save at the end.
|
9
|
+
#
|
10
|
+
# You can define save or destroy performers with <tt>define_<action></tt>
|
11
|
+
# methods. Create and update performers might be defined instead of
|
12
|
+
# save performer:
|
13
|
+
#
|
14
|
+
# class Book
|
15
|
+
# include ActiveData::Model
|
16
|
+
# include ActiveData::Model::Lifecycle
|
17
|
+
#
|
18
|
+
# attribute :id, Integer
|
19
|
+
# attribute :title, String
|
20
|
+
#
|
21
|
+
# define_save do # executes in the instance scope
|
22
|
+
# REDIS.set(id, attributes.to_json)
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# define_destroy do
|
26
|
+
# REDIS.del(id)
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# class Author
|
31
|
+
# include ActiveData::Model
|
32
|
+
# include ActiveData::Model::Lifecycle
|
33
|
+
#
|
34
|
+
# attribute :id, Integer
|
35
|
+
# attribute :name, String
|
36
|
+
#
|
37
|
+
# define_create do # will be called on create only
|
38
|
+
# REDIS.sadd('author_ids', id)
|
39
|
+
# REDIS.set(id, attributes.to_json)
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# define_update do # will be called on update only
|
43
|
+
# REDIS.set(id, attributes.to_json)
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# In case of undefined performer ActiveData::UnsavableObject
|
48
|
+
# or ActiveData::UndestroyableObject will be raised respectively.
|
49
|
+
#
|
50
|
+
# If performers was not defined in model, they cat be passed as
|
51
|
+
# blocks to `save`, `update` and `destroy` methods:
|
52
|
+
#
|
53
|
+
# authos.save { REDIS.set(id, attributes.to_json) }
|
54
|
+
# authos.update { REDIS.set(id, attributes.to_json) }
|
55
|
+
# authos.destroy { REDIS.del(id) }
|
56
|
+
#
|
57
|
+
# Save and destroy processes acts almost the save way as
|
58
|
+
# ActiveRecord's (with +persisted?+ and +destroyed?+ methods
|
59
|
+
# affecting).
|
60
|
+
#
|
61
|
+
module Lifecycle
|
62
|
+
extend ActiveSupport::Concern
|
63
|
+
|
64
|
+
included do
|
65
|
+
include Persistence
|
66
|
+
|
67
|
+
class_attribute *[:save, :create, :update, :destroy].map { |action| "_#{action}_performer" }
|
68
|
+
private *[:save, :create, :update, :destroy].map { |action| "_#{action}_performer=" }
|
69
|
+
end
|
70
|
+
|
71
|
+
module ClassMethods
|
72
|
+
|
73
|
+
# <tt>define_<action></tt> methods define performers for lifecycle
|
74
|
+
# actions. Every action block must return boolean result, which
|
75
|
+
# would mean the action success. If action performed unsuccessfully
|
76
|
+
# ActiveData::ObjectNotSaved or ActiveData::ObjectNotDestroyed will
|
77
|
+
# be raised respectively in case of bang methods using.
|
78
|
+
#
|
79
|
+
# class Author
|
80
|
+
# define_create { true }
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# Author.new.save # => true
|
84
|
+
# Author.new.save! # => true
|
85
|
+
#
|
86
|
+
# class Author
|
87
|
+
# define_create { false }
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# Author.new.save # => false
|
91
|
+
# Author.new.save! # => ActiveData::ObjectNotSaved
|
92
|
+
#
|
93
|
+
# Also performers blocks are executed in the instance context, but
|
94
|
+
# instance also passed as argument
|
95
|
+
#
|
96
|
+
# define_update do |instance|
|
97
|
+
# instance.attributes.to_json
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# +define_create+ and +define_update+ performers has higher priority
|
101
|
+
# than +define_save+.
|
102
|
+
#
|
103
|
+
# class Author
|
104
|
+
# define_update { ... }
|
105
|
+
# define_save { ... }
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# author = Author.create # using define_save performer
|
109
|
+
# author.update_attributes(...) # using define_update performer
|
110
|
+
#
|
111
|
+
[:save, :create, :update, :destroy].each do |action|
|
112
|
+
define_method "define_#{action}" do |&block|
|
113
|
+
send("_#{action}_performer=", block)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Initializes new instance with attributes passed and calls +save+
|
118
|
+
# on it. Returns instance in any case.
|
119
|
+
#
|
120
|
+
def create *args
|
121
|
+
new(*args).tap(&:save)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Initializes new instance with attributes passed and calls +save!+
|
125
|
+
# on it. Returns instance in case of success and raises ActiveData::ValidationError
|
126
|
+
# or ActiveData::ObjectNotSaved in case of validation or saving fail respectively.
|
127
|
+
#
|
128
|
+
def create! *args
|
129
|
+
new(*args).tap(&:save!)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# <tt>define_<action></tt> on instance level works the same
|
134
|
+
# way as class <tt>define_<action></tt> methods, but defines
|
135
|
+
# performers for instance only
|
136
|
+
#
|
137
|
+
# user.define_save do
|
138
|
+
# REDIS.set(id, attributes.to_json)
|
139
|
+
# end
|
140
|
+
# user.save! # => will use instance-level performer
|
141
|
+
#
|
142
|
+
[:save, :create, :update, :destroy].each do |action|
|
143
|
+
define_method "define_#{action}" do |&block|
|
144
|
+
send("_#{action}_performer=", block)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Assigns passed attributes and calls +save+
|
149
|
+
# Returns true or false in case of successful or unsuccessful
|
150
|
+
# saving respectively.
|
151
|
+
#
|
152
|
+
# author.update(name: 'Donald')
|
153
|
+
#
|
154
|
+
# If update performer is not defined with `define_update`
|
155
|
+
# or `define_save`, it raises ActiveData::UnsavableObject.
|
156
|
+
# Also save performer block might be passed instead of in-class
|
157
|
+
# performer definition:
|
158
|
+
#
|
159
|
+
# author.update(name: 'Donald') { REDIS.set(id, attributes.to_json) }
|
160
|
+
#
|
161
|
+
def update attributes, &block
|
162
|
+
assign_attributes(attributes) && save(&block)
|
163
|
+
end
|
164
|
+
alias_method :update_attributes, :update
|
165
|
+
|
166
|
+
# Assigns passed attributes and calls +save!+
|
167
|
+
# Returns true in case of success and raises ActiveData::ValidationError
|
168
|
+
# or ActiveData::ObjectNotSaved in case of validation or
|
169
|
+
# saving fail respectively.
|
170
|
+
#
|
171
|
+
# author.update!(name: 'Donald')
|
172
|
+
#
|
173
|
+
# If update performer is not defined with `define_update`
|
174
|
+
# or `define_save`, it raises ActiveData::UnsavableObject.
|
175
|
+
# Also save performer block might be passed instead of in-class
|
176
|
+
# performer definition:
|
177
|
+
#
|
178
|
+
# author.update!(name: 'Donald') { REDIS.set(id, attributes.to_json) }
|
179
|
+
#
|
180
|
+
def update! attributes, &block
|
181
|
+
assign_attributes(attributes) && save!(&block)
|
182
|
+
end
|
183
|
+
alias_method :update_attributes!, :update!
|
184
|
+
|
185
|
+
# # Saves object by calling save performer defined with +define_save+,
|
186
|
+
# +define_create+ or +define_update+ methods.
|
187
|
+
# Returns true or false in case of successful
|
188
|
+
# or unsuccessful saving respectively. Changes +persisted?+ to true
|
189
|
+
#
|
190
|
+
# author.save
|
191
|
+
#
|
192
|
+
# If save performer is not defined with `define_update` or
|
193
|
+
# `define_create` or `define_save`, it raises ActiveData::UnsavableObject.
|
194
|
+
# Also save performer block might be passed instead of in-class
|
195
|
+
# performer definition:
|
196
|
+
#
|
197
|
+
# author.save { REDIS.set(id, attributes.to_json) }
|
198
|
+
#
|
199
|
+
def save options = {}, &block
|
200
|
+
raise ActiveData::UnsavableObject unless block || savable?
|
201
|
+
valid? && save_object(&block)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Saves object by calling save performer defined with +define_save+,
|
205
|
+
# +define_create+ or +define_update+ methods.
|
206
|
+
# Returns true in case of success and raises ActiveData::ValidationError
|
207
|
+
# or ActiveData::ObjectNotSaved in case of validation or
|
208
|
+
# saving fail respectively. Changes +persisted?+ to true
|
209
|
+
#
|
210
|
+
# author.save!
|
211
|
+
#
|
212
|
+
# If save performer is not defined with `define_update` or
|
213
|
+
# `define_create` or `define_save`, it raises ActiveData::UnsavableObject.
|
214
|
+
# Also save performer block might be passed instead of in-class
|
215
|
+
# performer definition:
|
216
|
+
#
|
217
|
+
# author.save! { REDIS.set(id, attributes.to_json) }
|
218
|
+
#
|
219
|
+
def save! options = {}, &block
|
220
|
+
raise ActiveData::UnsavableObject unless block || savable?
|
221
|
+
validate!
|
222
|
+
save_object(&block) or raise ActiveData::ObjectNotSaved
|
223
|
+
end
|
224
|
+
|
225
|
+
# Destroys object by calling the destroy performer.
|
226
|
+
# Returns instance in any case. Changes +persisted?+
|
227
|
+
# to false and +destroyed?+ to true in case of success.
|
228
|
+
#
|
229
|
+
# author.destroy
|
230
|
+
#
|
231
|
+
# If destroy performer is not defined with `define_destroy`,
|
232
|
+
# it raises ActiveData::UndestroyableObject.
|
233
|
+
# Also destroy performer block might be passed instead of in-class
|
234
|
+
# performer definition:
|
235
|
+
#
|
236
|
+
# author.destroy { REDIS.del(id) }
|
237
|
+
#
|
238
|
+
def destroy &block
|
239
|
+
raise ActiveData::UndestroyableObject unless block || destroyable?
|
240
|
+
destroy_object(&block)
|
241
|
+
self
|
242
|
+
end
|
243
|
+
|
244
|
+
# Destroys object by calling the destroy performer.
|
245
|
+
# In case of success returns instance and changes +persisted?+
|
246
|
+
# to false and +destroyed?+ to true.
|
247
|
+
# Raises ActiveData::ObjectNotDestroyed in case of fail.
|
248
|
+
#
|
249
|
+
# author.destroy!
|
250
|
+
#
|
251
|
+
# If destroy performer is not defined with `define_destroy`,
|
252
|
+
# it raises ActiveData::UndestroyableObject.
|
253
|
+
# Also destroy performer block might be passed instead of in-class
|
254
|
+
# performer definition:
|
255
|
+
#
|
256
|
+
# author.destroy! { REDIS.del(id) }
|
257
|
+
#
|
258
|
+
def destroy! &block
|
259
|
+
raise ActiveData::UndestroyableObject unless block || destroyable?
|
260
|
+
destroy_object(&block) or raise ActiveData::ObjectNotDestroyed
|
261
|
+
self
|
262
|
+
end
|
263
|
+
|
264
|
+
private
|
265
|
+
|
266
|
+
def savable?
|
267
|
+
!!((persisted? ? _update_performer : _create_performer) || _save_performer)
|
268
|
+
end
|
269
|
+
|
270
|
+
def save_object &block
|
271
|
+
apply_association_changes! if respond_to?(:apply_association_changes!)
|
272
|
+
result = persisted? ? update_object(&block) : create_object(&block)
|
273
|
+
mark_persisted! if result
|
274
|
+
result
|
275
|
+
end
|
276
|
+
|
277
|
+
def create_object &block
|
278
|
+
performer = block || _create_performer || _save_performer
|
279
|
+
!!performer_exec(&performer)
|
280
|
+
end
|
281
|
+
|
282
|
+
def update_object &block
|
283
|
+
performer = block || _update_performer || _save_performer
|
284
|
+
!!performer_exec(&performer)
|
285
|
+
end
|
286
|
+
|
287
|
+
def destroyable?
|
288
|
+
!!_destroy_performer
|
289
|
+
end
|
290
|
+
|
291
|
+
def destroy_object &block
|
292
|
+
performer = block || _destroy_performer
|
293
|
+
result = !!performer_exec(&performer)
|
294
|
+
mark_destroyed! if result
|
295
|
+
result
|
296
|
+
end
|
297
|
+
|
298
|
+
def performer_exec &block
|
299
|
+
if block.arity == 1
|
300
|
+
block.call(self)
|
301
|
+
else
|
302
|
+
instance_exec(&block)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|