lib/embedson/model/embedded_builder.rb in embedson-1.0.2 vs lib/embedson/model/embedded_builder.rb in embedson-1.0.3
- old
+ new
@@ -8,93 +8,116 @@
@klass = builder.klass
end
def define
methods_embedded.each do |meth|
- klass.class_exec builder, &send(meth)
+ klass.class_exec builder, &self.method(meth)
end
end
private
def methods_embedded
self.class.private_instance_methods(false).select{ |m| m.to_s.start_with?('embedded_') }
end
- def embedded_initializer
- proc do |builder|
- alias_method :orig_initialize, :initialize
+ def embedded_alter_initialize(builder)
+ klass.send :alias_method, "#{builder.field_name}_initialize".to_sym, :initialize
+ klass.send :private, "#{builder.field_name}_initialize"
+ end
- define_method("initialize") do |*args|
- attrs = args[0]
- attrs ||= {}
- public_send("#{builder.field_name}=", attrs.fetch(builder.field_name, nil))
- orig_initialize(*args)
- end
+ def embedded_initializer(builder)
+ klass.send :define_method, "initialize" do |*args|
+ attrs = args[0] || {}
+ val = attrs.delete(builder.field_name)
+
+ send("#{builder.field_name}_initialize", *args)
+ public_send("#{builder.field_name}=", val) if val.present?
end
end
- def embedded_writer
- proc do |builder|
- define_method("#{builder.field_name}=") do |arg|
- verify_arg_klass(arg)
+ def embedded_writer(builder)
+ klass.send :define_method, "#{builder.field_name}=" do |arg|
+ send("#{builder.field_name}_verify_arg_klass", arg)
- instance_variable_set(builder.instance_var_name, arg)
- parent = public_send(builder.field_name)
+ instance_variable_set(builder.instance_var_name, arg)
- send_self_to_related(parent)
- end
+ send("#{builder.field_name}_send_to_related", self)
end
end
- def embedded_reader
- proc do |builder|
- define_method(builder.field_name) do
- instance_variable_get(builder.instance_var_name)
- end
+ def embedded_reader(builder)
+ klass.send :define_method, builder.field_name do
+ instance_variable_get(builder.instance_var_name)
end
end
- def embedded_destroy
- proc do |builder|
- define_method('destroy') do
- parent = public_send(builder.field_name)
- return false unless parent.present?
- parent.public_send(builder.inverse_set, nil)
- parent.save!
- end
+ def embedded_destroy(builder)
+ klass.send :define_method, 'destroy' do
+ call_in_transaction_for_all_embedding('save!', nil)
end
end
- def embedded_save
- proc do |builder|
- define_method('save') do
- parent = public_send(builder.field_name)
- return false unless parent.present?
- parent.save
+ def embedded_save(builder)
+ klass.send :define_method, 'save' do
+ call_in_transaction_for_all_embedding('save', self)
+ end
+ end
+
+ def embedded_save!(builder)
+ klass.send :define_method, 'save!' do
+ raise NoParentError.new('save!', self.class.name) unless any_embedding_present?
+ call_in_transaction_for_all_embedding('save!', self)
+ end
+ end
+
+ def embedded_changed(builder)
+ klass.send :define_method, 'embedson_model_changed!' do
+ raise NoParentError.new('register change', self.class.name) unless any_embedding_present?
+
+ self.class.embedson_relations.each do |relation|
+ send("#{relation}_send_to_related", self) if public_send(relation).present?
end
+ true
end
end
- def embedded_save!
- proc do |builder|
- define_method('save!') do
- parent = public_send(builder.field_name)
- raise NoParentError.new('save', self.class.name) unless parent.present?
- parent.save!
+ def embedded_send_to_related(builder)
+ klass.send :define_method, "#{builder.field_name}_send_to_related" do |arg|
+ parent = public_send(builder.field_name)
+ return if parent.nil?
+ unless parent.respond_to?(builder.inverse_set)
+ raise NoRelationDefinedError.new(parent.class, builder.inverse_set)
end
+ parent.public_send(builder.inverse_set, arg)
end
+ klass.send :private, "#{builder.field_name}_send_to_related"
end
- def embedded_changed
- proc do |builder|
- define_method('embedson_model_changed!') do
- parent = public_send(builder.field_name)
- raise NoParentError.new('register change', self.class.name) unless parent.present?
- parent.public_send(builder.inverse_set, self)
- true
+ def embedded_call_in_transaction_for_all_embedding(builder)
+ return if klass.methods.include? :call_in_transaction_for_all_embedding
+ klass.send :define_method, :call_in_transaction_for_all_embedding do |method, object|
+ results = []
+ ActiveRecord::Base.transaction do
+ self.class.embedson_relations.each do |field_name|
+ next if public_send(field_name).nil?
+ send("#{field_name}_send_to_related", object)
+ save_res = public_send(field_name).send(method)
+ results << save_res
+ raise ActiveRecord::Rollback unless save_res
+ end
end
+ !results.size.zero? && results.all?
end
+ end
+
+ def embedded_any_present?(builder)
+ return if klass.methods.include? :any_ebedding_present?
+ klass.send :define_method, :any_embedding_present? do
+ self.class.embedson_relations.any?{ |r| public_send(r).present? }
+ end
+
+ klass.send :private, :any_embedding_present?
end
end
end
end