diff --git a/lib/service/base.rb b/lib/service/base.rb index 13a59d68e08..bde43a0f9aa 100644 --- a/lib/service/base.rb +++ b/lib/service/base.rb @@ -441,8 +441,12 @@ module Service def initialize(initial_context = {}) @context = Context.build( - initial_context.merge(__steps__: self.class.steps, __service_class__: self.class), + initial_context + .compact + .reverse_merge(params: {}) + .merge(__steps__: self.class.steps, __service_class__: self.class), ) + initialize_params end # @!visibility private @@ -463,5 +467,21 @@ module Service context["result.step.#{step_name}"].fail(error: message) context.fail! end + + private + + def initialize_params + klass = + Data.define(*context[:params].keys) do + alias to_hash to_h + + delegate :slice, :merge, to: :to_h + + def method_missing(*) + nil + end + end + context[:params] = klass.new(*context[:params].values) + end end end diff --git a/plugins/chat/app/services/chat/create_message.rb b/plugins/chat/app/services/chat/create_message.rb index 2d4c2aad2a4..449e814d1a2 100644 --- a/plugins/chat/app/services/chat/create_message.rb +++ b/plugins/chat/app/services/chat/create_message.rb @@ -92,7 +92,7 @@ module Chat private def accept_blocks(guardian:, params:) - params[:blocks] ? guardian.user.bot? : true + params.blocks ? guardian.user.bot? : true end def no_silenced_user(guardian:) diff --git a/plugins/chat/app/services/chat/update_channel.rb b/plugins/chat/app/services/chat/update_channel.rb index e50d04652fd..fbcadd5bbb3 100644 --- a/plugins/chat/app/services/chat/update_channel.rb +++ b/plugins/chat/app/services/chat/update_channel.rb @@ -61,7 +61,7 @@ module Chat private def fetch_channel(params:) - Chat::Channel.find_by(id: params[:channel_id]) + Chat::Channel.find_by(id: params.channel_id) end def check_channel_permission(guardian:, channel:) diff --git a/spec/lib/service_spec.rb b/spec/lib/service_spec.rb index 94746999223..18575c8876a 100644 --- a/spec/lib/service_spec.rb +++ b/spec/lib/service_spec.rb @@ -58,4 +58,38 @@ RSpec.describe Service do end end end + + describe "Parameters handling" do + subject(:result) { service_class.call(**args) } + + context "when calling the service without any params" do + let(:args) { {} } + + it "instantiate a default params object" do + expect(result[:params]).not_to be_nil + end + end + + context "when calling the service with params" do + let(:args) { { params: { param1: "one" } } } + + context "when there is no `params` step defined" do + it "allows accessing `params` through methods" do + expect(result[:params].param1).to eq("one") + end + + it "returns nothing for a non-existent key" do + expect(result[:params].non_existent_key).to be_nil + end + end + + context "when there is a `params` step defined" do + before { service_class.class_eval { params { attribute :param1 } } } + + it "returns the contract as the params object" do + expect(result[:params]).to be_a(Service::ContractBase) + end + end + end + end end