servactory 2.5.0.rc2 → 2.5.0.rc4
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/README.md +1 -1
- data/lib/generators/servactory/install_generator.rb +21 -0
- data/lib/generators/servactory/rspec_generator.rb +88 -0
- data/lib/generators/servactory/service_generator.rb +49 -0
- data/lib/generators/servactory/templates/services/application_service/base.rb +60 -0
- data/lib/generators/servactory/templates/services/application_service/exceptions.rb +11 -0
- data/lib/generators/servactory/templates/services/application_service/result.rb +5 -0
- data/lib/servactory/context/workspace/internals.rb +1 -1
- data/lib/servactory/info/dsl.rb +56 -4
- data/lib/servactory/maintenance/attributes/options/registrar.rb +1 -1
- data/lib/servactory/result.rb +1 -1
- data/lib/servactory/test_kit/rspec/helpers.rb +95 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/consists_of_matcher.rb +121 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/inclusion_matcher.rb +70 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/must_matcher.rb +61 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/types_matcher.rb +72 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matcher.rb +203 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/default_matcher.rb +67 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/optional_matcher.rb +63 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/required_matcher.rb +78 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_input_matchers/valid_with_matcher.rb +233 -0
- data/lib/servactory/test_kit/rspec/matchers/have_service_internal_matcher.rb +148 -0
- data/lib/servactory/test_kit/rspec/matchers.rb +295 -0
- data/lib/servactory/test_kit/utils/faker.rb +78 -0
- data/lib/servactory/tool_kit/dynamic_options/format.rb +16 -12
- data/lib/servactory/version.rb +1 -1
- data/lib/servactory.rb +1 -0
- metadata +26 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '03950ff6fd385cfe8ba4506f2eb4dc7c2dc94dcf838d2a10b783e25e6b290af6'
|
4
|
+
data.tar.gz: 64182d91fa7a9042cefb99ec422d3710761f8ab412a8b00184c324bae23debfb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f85e47114458349c416a1a64d69098d29a67b8d837025acff53acc91885225c9ecab6036422fcd269793f5cdd22a90fe6ba0b8899074dde10837a6e0989b0cc3
|
7
|
+
data.tar.gz: 96bfba7a9fdc2c763ed8ab4b355a966053fa2a1f0e7bd365bbaa7f51dda089edc30ed00a61566e25252fa12df07eac7e327fb814d5dcb6b77d474f5e3718e1e7
|
data/README.md
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
<p align="center">
|
16
16
|
<a href="https://rubygems.org/gems/servactory"><img src="https://img.shields.io/gem/v/servactory?logo=rubygems&logoColor=fff" alt="Gem version"></a>
|
17
|
-
<a href="https://github.com/
|
17
|
+
<a href="https://github.com/servactory/servactory/releases"><img src="https://img.shields.io/github/release-date/servactory/servactory" alt="Release Date"></a>
|
18
18
|
</p>
|
19
19
|
|
20
20
|
## Documentation
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/base"
|
4
|
+
|
5
|
+
module Servactory
|
6
|
+
module Generators
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
def copy_services
|
11
|
+
directory "services/application_service", "app/services/application_service"
|
12
|
+
end
|
13
|
+
|
14
|
+
def copy_locales
|
15
|
+
%i[en ru].each do |locale|
|
16
|
+
copy_file "../../../../config/locales/#{locale}.yml", "config/locales/servactory.#{locale}.yml"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/named_base"
|
4
|
+
|
5
|
+
module Servactory
|
6
|
+
module Generators
|
7
|
+
class RspecGenerator < Rails::Generators::NamedBase
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
argument :attributes, type: :array, default: [], banner: "input_name"
|
11
|
+
|
12
|
+
def create_service
|
13
|
+
create_file "app/services/#{file_path}_spec.rb" do
|
14
|
+
<<~RUBY
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
RSpec.describe #{class_name}, type: :service do
|
18
|
+
pending "add some examples to (or delete) \#{__FILE__}"
|
19
|
+
|
20
|
+
# let(:attributes) do
|
21
|
+
# {
|
22
|
+
#{input_attribute_draw}
|
23
|
+
# }
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
#{input_let_draw}
|
27
|
+
#
|
28
|
+
# describe "validation" do
|
29
|
+
# describe "inputs" do
|
30
|
+
#{input_validation_draw}
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# describe "internals" do
|
34
|
+
# it { expect { perform }.to have_internal(:some_data).type(String) }
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# describe ".call!" do
|
39
|
+
# subject(:perform) { described_class.call!(**attributes) }
|
40
|
+
#
|
41
|
+
# describe "and the data required for work is also valid" do
|
42
|
+
# it { expect(perform).to be_success_service }
|
43
|
+
#
|
44
|
+
# # ...
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# describe "but the data required for work is invalid" do
|
48
|
+
# # Provide a reason why the data is invalid and then use this:
|
49
|
+
# it { expect(perform).to be_failure_service }
|
50
|
+
#
|
51
|
+
# # ...
|
52
|
+
# end
|
53
|
+
# end
|
54
|
+
end
|
55
|
+
RUBY
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def input_attribute_draw
|
60
|
+
input_names.map do |input_name|
|
61
|
+
<<~RUBY.strip
|
62
|
+
# #{input_name}: #{input_name}
|
63
|
+
RUBY
|
64
|
+
end.join(",\n ")
|
65
|
+
end
|
66
|
+
|
67
|
+
def input_let_draw
|
68
|
+
input_names.map do |input_name|
|
69
|
+
<<~RUBY.strip
|
70
|
+
# let(:#{input_name}) { "Some value" }
|
71
|
+
RUBY
|
72
|
+
end.join("\n ")
|
73
|
+
end
|
74
|
+
|
75
|
+
def input_validation_draw
|
76
|
+
input_names.map do |input_name|
|
77
|
+
<<~RUBY.strip
|
78
|
+
# it { expect { perform }.to have_input(:#{input_name}).valid_with(attributes).type(String).required }
|
79
|
+
RUBY
|
80
|
+
end.join("\n ")
|
81
|
+
end
|
82
|
+
|
83
|
+
def input_names
|
84
|
+
@input_names ||= attributes_names
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails/generators/named_base"
|
4
|
+
|
5
|
+
module Servactory
|
6
|
+
module Generators
|
7
|
+
class ServiceGenerator < Rails::Generators::NamedBase
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
9
|
+
|
10
|
+
argument :attributes, type: :array, default: [], banner: "input_name"
|
11
|
+
|
12
|
+
def create_service # rubocop:disable Metrics/MethodLength
|
13
|
+
create_file "app/services/#{file_path}.rb" do
|
14
|
+
<<~RUBY
|
15
|
+
# frozen_string_literal: true
|
16
|
+
|
17
|
+
class #{class_name} < ApplicationService::Base
|
18
|
+
#{input_draw}
|
19
|
+
|
20
|
+
output :result, type: Symbol
|
21
|
+
|
22
|
+
make :something
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def something
|
27
|
+
# Write your code here
|
28
|
+
|
29
|
+
outputs.result = :done
|
30
|
+
end
|
31
|
+
end
|
32
|
+
RUBY
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def input_draw
|
37
|
+
input_names.map do |input_name|
|
38
|
+
<<~RUBY.squish
|
39
|
+
input :#{input_name}, type: String
|
40
|
+
RUBY
|
41
|
+
end.join("\n ")
|
42
|
+
end
|
43
|
+
|
44
|
+
def input_names
|
45
|
+
@input_names ||= attributes_names
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ApplicationService
|
4
|
+
class Base
|
5
|
+
include Servactory::DSL
|
6
|
+
|
7
|
+
# More information: https://servactory.com/guide/extensions
|
8
|
+
# include Servactory::DSL.with_extensions(
|
9
|
+
# ApplicationService::Extensions::YourExtension::DSL
|
10
|
+
# )
|
11
|
+
|
12
|
+
fail_on! ActiveRecord::RecordInvalid
|
13
|
+
|
14
|
+
# More information: https://servactory.com/guide/configuration
|
15
|
+
configuration do
|
16
|
+
input_exception_class ApplicationService::Exceptions::Input
|
17
|
+
internal_exception_class ApplicationService::Exceptions::Internal
|
18
|
+
output_exception_class ApplicationService::Exceptions::Output
|
19
|
+
|
20
|
+
failure_class ApplicationService::Exceptions::Failure
|
21
|
+
|
22
|
+
result_class ApplicationService::Result
|
23
|
+
|
24
|
+
# input_option_helpers(
|
25
|
+
# [
|
26
|
+
# Servactory::ToolKit::DynamicOptions::Format.use,
|
27
|
+
# Servactory::ToolKit::DynamicOptions::Min.use,
|
28
|
+
# Servactory::ToolKit::DynamicOptions::Max.use,
|
29
|
+
# ApplicationService::DynamicOptions::CustomEq.use
|
30
|
+
# ]
|
31
|
+
# )
|
32
|
+
|
33
|
+
# internal_option_helpers(
|
34
|
+
# [
|
35
|
+
# Servactory::ToolKit::DynamicOptions::Format.use,
|
36
|
+
# Servactory::ToolKit::DynamicOptions::Min.use,
|
37
|
+
# Servactory::ToolKit::DynamicOptions::Max.use,
|
38
|
+
# ApplicationService::DynamicOptions::CustomEq.use
|
39
|
+
# ]
|
40
|
+
# )
|
41
|
+
|
42
|
+
# output_option_helpers(
|
43
|
+
# [
|
44
|
+
# Servactory::ToolKit::DynamicOptions::Format.use,
|
45
|
+
# Servactory::ToolKit::DynamicOptions::Min.use,
|
46
|
+
# Servactory::ToolKit::DynamicOptions::Max.use,
|
47
|
+
# ApplicationService::DynamicOptions::CustomEq.use
|
48
|
+
# ]
|
49
|
+
# )
|
50
|
+
|
51
|
+
# collection_mode_class_names [ActiveRecord::Relation]
|
52
|
+
|
53
|
+
# hash_mode_class_names [CustomHash]
|
54
|
+
|
55
|
+
# action_shortcuts %i[assign build create save]
|
56
|
+
|
57
|
+
# action_aliases %i[do_it!]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ApplicationService
|
4
|
+
module Exceptions
|
5
|
+
class Input < Servactory::Exceptions::Input; end
|
6
|
+
class Output < Servactory::Exceptions::Output; end
|
7
|
+
class Internal < Servactory::Exceptions::Internal; end
|
8
|
+
|
9
|
+
class Failure < Servactory::Exceptions::Failure; end
|
10
|
+
end
|
11
|
+
end
|
data/lib/servactory/info/dsl.rb
CHANGED
@@ -8,11 +8,63 @@ module Servactory
|
|
8
8
|
end
|
9
9
|
|
10
10
|
module ClassMethods
|
11
|
-
def info
|
11
|
+
def info # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
12
12
|
Servactory::Info::Result.new(
|
13
|
-
inputs: collection_of_inputs.
|
14
|
-
|
15
|
-
|
13
|
+
inputs: collection_of_inputs.to_h do |input|
|
14
|
+
work = input.class::Work.new(input)
|
15
|
+
consists_of = input.collection_of_options.find_by(name: :consists_of)
|
16
|
+
inclusion = input.collection_of_options.find_by(name: :inclusion)
|
17
|
+
must = input.collection_of_options.find_by(name: :must)
|
18
|
+
|
19
|
+
[
|
20
|
+
input.name,
|
21
|
+
{
|
22
|
+
work: work,
|
23
|
+
types: input.types,
|
24
|
+
required: input.required,
|
25
|
+
default: input.default,
|
26
|
+
consists_of: consists_of.body,
|
27
|
+
inclusion: inclusion.body,
|
28
|
+
must: must.body
|
29
|
+
}
|
30
|
+
]
|
31
|
+
end,
|
32
|
+
|
33
|
+
internals: collection_of_internals.to_h do |internal|
|
34
|
+
work = internal.class::Work.new(internal)
|
35
|
+
consists_of = internal.collection_of_options.find_by(name: :consists_of)
|
36
|
+
inclusion = internal.collection_of_options.find_by(name: :inclusion)
|
37
|
+
must = internal.collection_of_options.find_by(name: :must)
|
38
|
+
|
39
|
+
[
|
40
|
+
internal.name,
|
41
|
+
{
|
42
|
+
work: work,
|
43
|
+
types: internal.types,
|
44
|
+
consists_of: consists_of.body,
|
45
|
+
inclusion: inclusion.body,
|
46
|
+
must: must.body
|
47
|
+
}
|
48
|
+
]
|
49
|
+
end,
|
50
|
+
|
51
|
+
outputs: collection_of_outputs.to_h do |output|
|
52
|
+
work = output.class::Work.new(output)
|
53
|
+
consists_of = output.collection_of_options.find_by(name: :consists_of)
|
54
|
+
inclusion = output.collection_of_options.find_by(name: :inclusion)
|
55
|
+
must = output.collection_of_options.find_by(name: :must)
|
56
|
+
|
57
|
+
[
|
58
|
+
output.name,
|
59
|
+
{
|
60
|
+
work: work,
|
61
|
+
types: output.types,
|
62
|
+
consists_of: consists_of.body,
|
63
|
+
inclusion: inclusion.body,
|
64
|
+
must: must.body
|
65
|
+
}
|
66
|
+
]
|
67
|
+
end
|
16
68
|
)
|
17
69
|
end
|
18
70
|
end
|
@@ -213,7 +213,7 @@ module Servactory
|
|
213
213
|
)
|
214
214
|
end
|
215
215
|
|
216
|
-
def register_prepare_option # rubocop:disable Metrics/MethodLength
|
216
|
+
def register_prepare_option # rubocop:disable Metrics/MethodLength
|
217
217
|
collection << Servactory::Maintenance::Attributes::Option.new(
|
218
218
|
name: :prepare,
|
219
219
|
attribute: @attribute,
|
data/lib/servactory/result.rb
CHANGED
@@ -110,7 +110,7 @@ module Servactory
|
|
110
110
|
########################################################################
|
111
111
|
|
112
112
|
def rescue_no_method_error_with(exception:) # rubocop:disable Metrics/MethodLength
|
113
|
-
raise exception if @context.blank?
|
113
|
+
raise exception if @context.blank? || @context.instance_of?(Servactory::TestKit::Result)
|
114
114
|
|
115
115
|
raise @context.class.config.failure_class.new(
|
116
116
|
type: :base,
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module TestKit
|
5
|
+
module Rspec
|
6
|
+
module Helpers
|
7
|
+
def allow_service_as_success!(service_class_name, &block)
|
8
|
+
allow_service!(service_class_name, :as_success, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def allow_service_as_success(service_class_name, &block)
|
12
|
+
allow_service(service_class_name, :as_success, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def allow_service_as_failure!(service_class_name, &block)
|
16
|
+
allow_service!(service_class_name, :as_failure, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def allow_service_as_failure(service_class_name, &block)
|
20
|
+
allow_service(service_class_name, :as_failure, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
########################################################################
|
24
|
+
|
25
|
+
def allow_service!(service_class_name, result_type, &block)
|
26
|
+
allow_servactory(service_class_name, :call!, result_type, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def allow_service(service_class_name, result_type, &block)
|
30
|
+
allow_servactory(service_class_name, :call, result_type, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
########################################################################
|
34
|
+
|
35
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
36
|
+
def allow_servactory(service_class_name, method_call, result_type)
|
37
|
+
method_call = method_call.to_sym
|
38
|
+
result_type = result_type.to_sym
|
39
|
+
|
40
|
+
unless %i[call! call].include?(method_call)
|
41
|
+
raise ArgumentError, "Invalid value for `method_call`. Must be `:call!` or `:call`."
|
42
|
+
end
|
43
|
+
|
44
|
+
unless %i[as_success as_failure].include?(result_type)
|
45
|
+
raise ArgumentError, "Invalid value for `result_type`. Must be `:as_success` or `:as_failure`."
|
46
|
+
end
|
47
|
+
|
48
|
+
as_success = result_type == :as_success
|
49
|
+
with_bang = method_call == :call!
|
50
|
+
|
51
|
+
if block_given? && !yield.is_a?(Hash) && as_success
|
52
|
+
raise ArgumentError, "Invalid value for block. Must be a Hash with attributes."
|
53
|
+
end
|
54
|
+
|
55
|
+
and_return_or_raise = with_bang && !as_success ? :and_raise : :and_return
|
56
|
+
|
57
|
+
result = if block_given?
|
58
|
+
if yield.is_a?(Hash)
|
59
|
+
yield
|
60
|
+
else
|
61
|
+
{ with_bang ? :exception : :error => yield }
|
62
|
+
end
|
63
|
+
else
|
64
|
+
{}
|
65
|
+
end
|
66
|
+
|
67
|
+
# puts
|
68
|
+
# puts <<~RUBY
|
69
|
+
# allow(#{service_class_name}).to(
|
70
|
+
# receive(#{method_call.inspect})
|
71
|
+
# .public_send(
|
72
|
+
# #{and_return_or_raise.inspect},
|
73
|
+
# Servactory::TestKit::Result.public_send(#{result_type.inspect}, #{result})
|
74
|
+
# )
|
75
|
+
# )
|
76
|
+
# RUBY
|
77
|
+
# puts
|
78
|
+
|
79
|
+
allow(service_class_name).to(
|
80
|
+
receive(method_call)
|
81
|
+
.public_send(
|
82
|
+
and_return_or_raise,
|
83
|
+
if as_success
|
84
|
+
Servactory::TestKit::Result.public_send(result_type, **result)
|
85
|
+
else
|
86
|
+
Servactory::TestKit::Result.public_send(result_type, result)
|
87
|
+
end
|
88
|
+
)
|
89
|
+
)
|
90
|
+
end
|
91
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/consists_of_matcher.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module TestKit
|
5
|
+
module Rspec
|
6
|
+
module Matchers
|
7
|
+
module HaveServiceAttributeMatchers
|
8
|
+
class ConsistsOfMatcher
|
9
|
+
attr_reader :missing_option
|
10
|
+
|
11
|
+
def initialize(described_class, attribute_type, attribute_name, option_types, consists_of_types,
|
12
|
+
custom_message)
|
13
|
+
@described_class = described_class
|
14
|
+
@attribute_type = attribute_type
|
15
|
+
@attribute_type_plural = attribute_type.to_s.pluralize.to_sym
|
16
|
+
@attribute_name = attribute_name
|
17
|
+
@option_types = option_types
|
18
|
+
@consists_of_types = consists_of_types
|
19
|
+
@custom_message = custom_message
|
20
|
+
|
21
|
+
@attribute_data = described_class.info.public_send(attribute_type_plural).fetch(attribute_name)
|
22
|
+
|
23
|
+
@missing_option = ""
|
24
|
+
end
|
25
|
+
|
26
|
+
def description
|
27
|
+
result = "consists_of: "
|
28
|
+
result + consists_of_types.join(", ")
|
29
|
+
end
|
30
|
+
|
31
|
+
def matches?(subject)
|
32
|
+
if submatcher_passes?(subject)
|
33
|
+
true
|
34
|
+
else
|
35
|
+
@missing_option = build_missing_option
|
36
|
+
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :described_class,
|
44
|
+
:attribute_type,
|
45
|
+
:attribute_type_plural,
|
46
|
+
:attribute_name,
|
47
|
+
:option_types,
|
48
|
+
:consists_of_types,
|
49
|
+
:custom_message,
|
50
|
+
:attribute_data
|
51
|
+
|
52
|
+
def submatcher_passes?(_subject)
|
53
|
+
attribute_consists_of = Array(attribute_data.fetch(:consists_of).fetch(:type) || [])
|
54
|
+
|
55
|
+
matched = attribute_consists_of.difference(consists_of_types).empty?
|
56
|
+
|
57
|
+
matched &&= attribute_consists_of_message.casecmp(custom_message).zero? if custom_message.present?
|
58
|
+
|
59
|
+
matched
|
60
|
+
end
|
61
|
+
|
62
|
+
def attribute_consists_of_message # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
63
|
+
attribute_consists_of_message = attribute_data.fetch(:consists_of).fetch(:message)
|
64
|
+
|
65
|
+
if attribute_consists_of_message.nil?
|
66
|
+
I18n.t(
|
67
|
+
"servactory.#{attribute_type_plural}.validations.required.default_error.for_collection",
|
68
|
+
service_class_name: described_class.name,
|
69
|
+
"#{attribute_type}_name": attribute_name
|
70
|
+
)
|
71
|
+
elsif attribute_consists_of_message.is_a?(Proc)
|
72
|
+
input_work = attribute_data.fetch(:work)
|
73
|
+
|
74
|
+
attribute_consists_of_message.call(
|
75
|
+
input: input_work,
|
76
|
+
expected_type: String,
|
77
|
+
given_type: Servactory::TestKit::FakeType.new.class.name
|
78
|
+
)
|
79
|
+
else
|
80
|
+
attribute_consists_of_message
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def build_missing_option # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
85
|
+
attribute_consists_of = Array(attribute_data.fetch(:consists_of).fetch(:type) || [])
|
86
|
+
|
87
|
+
unless attribute_consists_of.difference(consists_of_types).empty?
|
88
|
+
text_about_types = option_types.size > 1 ? "the following types" : "type"
|
89
|
+
|
90
|
+
return <<~MESSAGE
|
91
|
+
should be a collection consisting of #{text_about_types}
|
92
|
+
|
93
|
+
expected #{consists_of_types.inspect}
|
94
|
+
got #{attribute_consists_of.inspect}
|
95
|
+
MESSAGE
|
96
|
+
end
|
97
|
+
|
98
|
+
if custom_message.present? && !attribute_consists_of_message.casecmp(custom_message).zero?
|
99
|
+
return <<~MESSAGE
|
100
|
+
should be a collection with a message
|
101
|
+
|
102
|
+
expected #{custom_message.inspect}
|
103
|
+
got #{attribute_consists_of_message.inspect}
|
104
|
+
MESSAGE
|
105
|
+
end
|
106
|
+
|
107
|
+
<<~MESSAGE
|
108
|
+
got an unexpected case when using `consists_of`
|
109
|
+
|
110
|
+
Please try to build an example based on the documentation.
|
111
|
+
Or report your problem to us:
|
112
|
+
|
113
|
+
https://github.com/servactory/servactory/issues
|
114
|
+
MESSAGE
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/servactory/test_kit/rspec/matchers/have_service_attribute_matchers/inclusion_matcher.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Servactory
|
4
|
+
module TestKit
|
5
|
+
module Rspec
|
6
|
+
module Matchers
|
7
|
+
module HaveServiceAttributeMatchers
|
8
|
+
class InclusionMatcher
|
9
|
+
attr_reader :missing_option
|
10
|
+
|
11
|
+
def initialize(described_class, attribute_type, attribute_name, values)
|
12
|
+
@described_class = described_class
|
13
|
+
@attribute_type = attribute_type
|
14
|
+
@attribute_type_plural = attribute_type.to_s.pluralize.to_sym
|
15
|
+
@attribute_name = attribute_name
|
16
|
+
@values = values
|
17
|
+
|
18
|
+
@attribute_data = described_class.info.public_send(attribute_type_plural).fetch(attribute_name)
|
19
|
+
|
20
|
+
@missing_option = ""
|
21
|
+
end
|
22
|
+
|
23
|
+
def description
|
24
|
+
"inclusion: #{values.join(', ')}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def matches?(subject)
|
28
|
+
if submatcher_passes?(subject)
|
29
|
+
true
|
30
|
+
else
|
31
|
+
@missing_option = build_missing_option
|
32
|
+
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :described_class,
|
40
|
+
:attribute_type,
|
41
|
+
:attribute_type_plural,
|
42
|
+
:attribute_name,
|
43
|
+
:values,
|
44
|
+
:attribute_data
|
45
|
+
|
46
|
+
def submatcher_passes?(_subject)
|
47
|
+
attribute_inclusion = attribute_data.fetch(:inclusion)
|
48
|
+
attribute_inclusion_in = attribute_inclusion.fetch(:in)
|
49
|
+
|
50
|
+
attribute_inclusion_in.difference(values).empty? &&
|
51
|
+
values.difference(attribute_inclusion_in).empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_missing_option
|
55
|
+
attribute_inclusion = attribute_data.fetch(:inclusion)
|
56
|
+
attribute_inclusion_in = attribute_inclusion.fetch(:in)
|
57
|
+
|
58
|
+
<<~MESSAGE
|
59
|
+
should include the expected values
|
60
|
+
|
61
|
+
expected #{values.inspect}
|
62
|
+
got #{attribute_inclusion_in.inspect}
|
63
|
+
MESSAGE
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|