diff --git a/docs/pre_processing_fields.md b/docs/pre_processing_fields.md index f13eb81..f8efb50 100644 --- a/docs/pre_processing_fields.md +++ b/docs/pre_processing_fields.md @@ -33,6 +33,22 @@ current time: end ``` +Keyword parameters passed to the `amoeba_dup` command can also be used: + +```ruby + amoeba do + set string_field: ->(str_arg:) { str_arg } + set integer_field: ->(int_arg:) { int_arg } + set combined_field: ->(str_arg:, int_arg: 33, other_arg: 'default') { "#{str_arg} - #{int_arg} - #{other_arg}" } + end + +new_item = item.amoeba_dup(str_arg: 'new string', int_arg: 45) +# => new_item.string_field = 'new_string' +# => new_item.integer_field = 99 +# => new_item.combined_field = 'new_string - 99 - default' +``` + + ## regex To do diff --git a/lib/amoeba/cloner.rb b/lib/amoeba/cloner.rb index b8c344d..6dc1a47 100644 --- a/lib/amoeba/cloner.rb +++ b/lib/amoeba/cloner.rb @@ -13,9 +13,9 @@ class Cloner def_delegators :object_klass, :amoeba, :fresh_amoeba, :reset_amoeba - def initialize(object, options = {}) + def initialize(object, **kwargs) @old_object = object - @options = options + @params = kwargs @object_klass = @old_object.class inherit_parent_settings @new_object = object.__send__(amoeba.dup_method) @@ -135,7 +135,12 @@ def process_null_fields def process_coercions # prepend any extra strings to indicate uniqueness of the new record(s) amoeba.coercions.each do |field, coercion| - @new_object[field] = coercion.is_a?(Proc) ? coercion.call : coercion.to_s + if coercion.is_a?(Proc) + keys = coercion.parameters.select { |pair| %i[key keyreq].include?(pair.first) }.map(&:second) + @new_object[field] = coercion.call(**@params.slice(*keys)) + else + @new_object[field] = coercion.to_s + end end end diff --git a/lib/amoeba/instance_methods.rb b/lib/amoeba/instance_methods.rb index 1be2592..e1d079c 100644 --- a/lib/amoeba/instance_methods.rb +++ b/lib/amoeba/instance_methods.rb @@ -33,8 +33,8 @@ def _parent_amoeba_settings end end - def amoeba_dup(options = {}) - ::Amoeba::Cloner.new(self, options).run + def amoeba_dup(**kwargs) + ::Amoeba::Cloner.new(self, **kwargs).run end end end diff --git a/lib/amoeba/macros/has_many.rb b/lib/amoeba/macros/has_many.rb index 3269b6b..0cb5923 100644 --- a/lib/amoeba/macros/has_many.rb +++ b/lib/amoeba/macros/has_many.rb @@ -32,7 +32,7 @@ def follow_without_clone(relation_name, association) return if association.is_a?(ActiveRecord::Reflection::ThroughReflection) @old_object.__send__(relation_name).each do |old_obj| - copy_of_obj = old_obj.amoeba_dup(@options) + copy_of_obj = old_obj.amoeba_dup copy_of_obj[:"#{association.foreign_key}"] = nil relation_name = remapped_relation_name(relation_name) # associate this new child to the new parent object diff --git a/lib/amoeba/macros/has_one.rb b/lib/amoeba/macros/has_one.rb index 6ae2e24..b08babf 100644 --- a/lib/amoeba/macros/has_one.rb +++ b/lib/amoeba/macros/has_one.rb @@ -9,7 +9,7 @@ def follow(relation_name, association) old_obj = @old_object.__send__(relation_name) return unless old_obj - copy_of_obj = old_obj.amoeba_dup(@options) + copy_of_obj = old_obj.amoeba_dup copy_of_obj[:"#{association.foreign_key}"] = nil relation_name = remapped_relation_name(relation_name) @new_object.__send__(:"#{relation_name}=", copy_of_obj) diff --git a/spec/lib/amoeba/class_methods_spec.rb b/spec/lib/amoeba/class_methods_spec.rb index 4344ec7..55d6ebe 100644 --- a/spec/lib/amoeba/class_methods_spec.rb +++ b/spec/lib/amoeba/class_methods_spec.rb @@ -4,8 +4,9 @@ RSpec.describe Amoeba::ClassMethods do describe '#amoeba' do - let(:dup) { test.amoeba_dup } - let(:test) { TestModel.new(**params) } + let(:dup) { original.amoeba_dup(**dup_params) } + # let(:test) { TestModel.new(**params) } + let(:dup_params) { {} } before do stub_const 'TestModel', Class.new(ActiveRecord::Base) @@ -22,7 +23,7 @@ describe 'set' do context 'with a static string value' do - let(:params) { { test_field: 'original string' } } + let(:original) { TestModel.new(test_field: 'original string') } let(:field_type) { :string } let(:config) do <<~CONFIG @@ -36,7 +37,7 @@ end context 'with a static integer value' do - let(:params) { { test_field: 33 } } + let(:original) { TestModel.new(test_field: 33) } let(:field_type) { :integer } let(:config) do <<~CONFIG @@ -50,7 +51,7 @@ end context 'with a static boolean value' do - let(:params) { { test_field: true } } + let(:original) { TestModel.new(test_field: true) } let(:field_type) { :boolean } let(:config) do <<~CONFIG @@ -64,7 +65,7 @@ end context 'with a datetime field set by a lambda' do - let(:params) { { test_field: DateTime.parse('30 Jun 2024 18:19') } } + let(:original) { TestModel.new(test_field: DateTime.parse('30 Jun 2024 18:19')) } let(:field_type) { :datetime } let(:config) do <<~CONFIG @@ -79,6 +80,45 @@ it { expect(dup.test_field).to eq(DateTime.parse('1 Jul 2024 09:35')) } end + + context 'with a field set by a parameter' do + let(:original) { TestModel.new(test_field: 'original string') } + let(:dup_params) { { str_arg: 'new string arg' } } + let(:field_type) { :string } + let(:config) do + <<~CONFIG + amoeba do + set test_field: ->(str_arg:) { ">> \#{str_arg} <<" } + end + CONFIG + end + + it { expect(dup.test_field).to eq('>> new string arg <<') } + end + + context 'with fields set by different parameters' do + let(:original) { TestModel.new(test_field: 'original string', second_test_field: 33, third_test_field: '') } + let(:dup_params) { { str_arg: 'new string arg', int_arg: 99 } } + let(:field_type) { :string } + let(:config) do + <<~CONFIG + amoeba do + set test_field: ->(str_arg:) { ">> \#{str_arg} <<" } + set second_test_field: ->(int_arg:) { int_arg * 2 } + set third_test_field: ->(str_arg:, int_arg: 33, other_arg: 'default') { "\#{str_arg} - \#{int_arg} - default" } + end + CONFIG + end + + before do + ActiveRecord::Base.connection.add_column :test_models, :second_test_field, :integer + ActiveRecord::Base.connection.add_column :test_models, :third_test_field, :string + end + + it { expect(dup.test_field).to eq('>> new string arg <<') } + it { expect(dup.second_test_field).to eq(198) } + it { expect(dup.third_test_field).to eq('new string arg - 99 - default') } + end end end end