DEV: Add policy objects to services

This patch introduces policy objects to chat services. It allows putting
more complex logic in a dedicated class, which will make services
thinner. It also allows providing a reason why the policy failed.

Some change has been made to the service runner too to use more easily
these new policy objects: when matching a failing policy (or any failing
step actually), the result object is now provided to the block. This
way, instead of having to access the reason why the policy failed by
doing `result["result.policy.policy_name"].reason` inside the block,
this one can be simply written like this:
```ruby
  on_failed_policy(:policy_name) { |policy| policy.reason }
```
This commit is contained in:
Loïc Guitaut
2023-05-24 16:32:49 +02:00
committed by Loïc Guitaut
parent 22a6ae7e32
commit 0733dda1cb
7 changed files with 199 additions and 42 deletions

View File

@ -210,8 +210,22 @@ RSpec.describe ServiceRunner do
context "when the service policy fails" do
let(:service) { FailedPolicyService }
it "runs the provided block" do
expect(runner).to eq :policy_failure
context "when not using the block argument" do
it "runs the provided block" do
expect(runner).to eq :policy_failure
end
end
context "when using the block argument" do
let(:actions) { <<-BLOCK }
proc do
on_failed_policy(:test) { |policy| policy == result["result.policy.test"] }
end
BLOCK
it "runs the provided block" do
expect(runner).to be true
end
end
end
@ -234,8 +248,22 @@ RSpec.describe ServiceRunner do
context "when the service contract fails" do
let(:service) { FailedContractService }
it "runs the provided block" do
expect(runner).to eq :contract_failure
context "when not using the block argument" do
it "runs the provided block" do
expect(runner).to eq :contract_failure
end
end
context "when using the block argument" do
let(:actions) { <<-BLOCK }
proc do
on_failed_contract { |contract| contract == result["result.contract.default"] }
end
BLOCK
it "runs the provided block" do
expect(runner).to be true
end
end
end
@ -250,7 +278,7 @@ RSpec.describe ServiceRunner do
context "when using the on_model_not_found action" do
let(:actions) { <<-BLOCK }
->(*) do
proc do
on_model_not_found(:fake_model) { :no_model }
end
BLOCK
@ -259,8 +287,22 @@ RSpec.describe ServiceRunner do
context "when the service fails without a model" do
let(:service) { FailureWithModelService }
it "runs the provided block" do
expect(runner).to eq :no_model
context "when not using the block argument" do
it "runs the provided block" do
expect(runner).to eq :no_model
end
end
context "when using the block argument" do
let(:actions) { <<-BLOCK }
proc do
on_model_not_found(:fake_model) { |model| model == result["result.model.fake_model"] }
end
BLOCK
it "runs the provided block" do
expect(runner).to be true
end
end
end
@ -294,7 +336,7 @@ RSpec.describe ServiceRunner do
context "when using the on_model_errors action" do
let(:actions) { <<-BLOCK }
->(*) do
proc do
on_model_errors(:fake_model) { :model_errors }
end
BLOCK
@ -302,8 +344,22 @@ RSpec.describe ServiceRunner do
context "when the service fails with a model containing errors" do
let(:service) { FailureWithModelErrorsService }
it "runs the provided block" do
expect(runner).to eq :model_errors
context "when not using the block argument" do
it "runs the provided block" do
expect(runner).to eq :model_errors
end
end
context "when using the block argument" do
let(:actions) { <<-BLOCK }
proc do
on_model_errors(:fake_model) { |model| model == OpenStruct.new(invalid?: true) }
end
BLOCK
it "runs the provided block" do
expect(runner).to be true
end
end
end