convenient_service 0.2.0 → 0.2.1

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.
Files changed (23) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -6
  3. data/CHANGELOG.md +9 -0
  4. data/ROADMAP.md +3 -0
  5. data/Taskfile.yml +3 -3
  6. data/env.rb +4 -0
  7. data/lib/convenient_service/examples/dry/gemfile/dry_service/config.rb +3 -1
  8. data/lib/convenient_service/examples/dry/gemfile/services/assert_file_exists.rb +1 -1
  9. data/lib/convenient_service/examples/dry/gemfile/services/assert_file_not_empty.rb +1 -1
  10. data/lib/convenient_service/examples/dry/gemfile/services/assert_npm_package_available.rb +1 -1
  11. data/lib/convenient_service/examples/dry/gemfile/services/parse_content.rb +1 -1
  12. data/lib/convenient_service/examples/dry/gemfile/services/print_shell_command.rb +1 -1
  13. data/lib/convenient_service/examples/dry/gemfile/services/read_file_content.rb +1 -1
  14. data/lib/convenient_service/examples/dry/gemfile/services/run_shell.rb +1 -1
  15. data/lib/convenient_service/examples/dry/gemfile/services/strip_comments.rb +1 -1
  16. data/lib/convenient_service/examples/rails/gemfile/rails_service/config.rb +3 -1
  17. data/lib/convenient_service/rspec/matchers/custom/cache_its_value.rb +7 -7
  18. data/lib/convenient_service/rspec/matchers/custom/delegate_to.rb +50 -12
  19. data/lib/convenient_service/service/plugins/has_result/entities/result/plugins/has_jsend_status_and_attributes/concern/instance_methods.rb +29 -17
  20. data/lib/convenient_service/service/plugins/has_result_params_validations/using_dry_validation/middleware.rb +19 -9
  21. data/lib/convenient_service/service/plugins/has_result_steps/middleware.rb +1 -1
  22. data/lib/convenient_service/version.rb +1 -1
  23. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 03335557e59a7d6c469fe20e478efb1d7f9563d7651b5e0761e61d820e7515e6
4
- data.tar.gz: 055c3cfaa2b176689bf8cc105d649a40779788279c89bd1f5a6bdfde8d7994c1
3
+ metadata.gz: 70d36eabeb3ea9598979a7158d06e0bfc627398066abc5180411f13fce9142e8
4
+ data.tar.gz: 6c6ea0ce690bb915c32f2e810afe70f87e74961f7a3c01b4e3a6389b8f98b1dc
5
5
  SHA512:
6
- metadata.gz: f9f55f6baab2736bcbb8661a55bb494bdfb1f7e000a87b3c7c78f326b417e44bcd69cccb992b54435ec10ce919afc2e3a7cd73695858025fa241aff609b9882c
7
- data.tar.gz: 72778dcdb0df0003b3c9b13a266af24a9c8de4150ed7d048887bd5007b223c88ce34c9494c186c5ac49ba0102ca5bd31858e37d55698fe1cfb49fe22dd6ed6e7
6
+ metadata.gz: aa610f3ac041e97849914d6bf15e626cceef9d8abd9aed0e5244b112595c89c9ac1eb91438bf67a84065bc8b90e91ebd8fff19cbcfb3c4a77e9b1246100b25fd
7
+ data.tar.gz: d704307543e1a14efa13f2701a109ee2748af75ed2260bbf9e4e64bc06b5bbe2a23ac208eabea1ec2d536578c9b9ec97c76541fa79181b9e896f4f844594d743
@@ -128,14 +128,14 @@ jobs:
128
128
  run: task rspec:standard
129
129
  - name: Install dependencies for appraisals
130
130
  run: task deps:install
131
- - name: Run RSpec with Rails 5.2
132
- run: task rspec:rails_5.2
133
- - name: Run RSpec with Rails 6.0
134
- run: task rspec:rails_6.0
135
- - name: Run RSpec with Rails 6.1
136
- run: task rspec:rails_6.1
137
131
  - name: Run RSpec with Rails 7.0
138
132
  run: task rspec:rails_7.0
133
+ - name: Run RSpec with Rails 6.1
134
+ run: task rspec:rails_6.1
135
+ - name: Run RSpec with Rails 6.0
136
+ run: task rspec:rails_6.0
137
+ - name: Run RSpec with Rails 5.2
138
+ run: task rspec:rails_5.2
139
139
  - name: Run RSpec with Dry
140
140
  run: task rspec:dry
141
141
  ##
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.1](https://github.com/marian13/convenient_service/compare/v0.2.0...v0.2.1) (2022-12-14)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **has_result_steps:** return step copy to have fresh state ([55cc368](https://github.com/marian13/convenient_service/commit/55cc368484641040c0c76ecb38872cc9a268397c), [fc7cebb](https://github.com/marian13/convenient_service/commit/fc7cebb4e159af7b35eac3cf8c25c7009e14c9d1))
9
+ * **standard:** place UsingActiveModelValidations before HasResultSteps ([4c43205](https://github.com/marian13/convenient_service/commit/4c43205382da2e7ae395fea6639c2bcc43d1eec2))
10
+ * **standard:** place UsingDryValidation before HasResultSteps ([63c31c0](https://github.com/marian13/convenient_service/commit/63c31c04ac7c2581defd3557aad13db3188806ba))
11
+
3
12
  ## [0.2.0](https://github.com/marian13/convenient_service/compare/v0.1.0...v0.2.0) (2022-11-26)
4
13
 
5
14
 
data/ROADMAP.md CHANGED
@@ -48,5 +48,8 @@
48
48
  | Low | 🚧 | [Receive Counts](https://relishapp.com/rspec/rspec-mocks/docs/setting-constraints/receive-counts) for `delegate_to` | |
49
49
  | Low | 🚧 | Prefer versioning instead of modification plugin | |
50
50
  | Low | 🚧 | Consider to move `__steps__` and `__callbacks__` to `internals_class` | Benefit? |
51
+ | Medium | 🚧 | User friendly `raise` that removes lib backtrace from caller | Should have a `debug` mode. Should work well with examples. Check RSpec `CallerFilter.first_non_rspec_line` |
52
+ | High | 🚧 | A plugin that catches `StandardError` and returns `failure` | Should be the lowest in the stack |
53
+ | High | 🚧 | `Support::Command` alias | Should be visible to the end user |
51
54
 
52
55
  Search for `TODO`s in the codebase for more tasks.
data/Taskfile.yml CHANGED
@@ -201,10 +201,10 @@ tasks:
201
201
  rspec:
202
202
  cmds:
203
203
  - task: rspec:standard
204
- - task: rspec:rails_5.2
205
- - task: rspec:rails_6.0
206
- - task: rspec:rails_6.1
207
204
  - task: rspec:rails_7.0
205
+ - task: rspec:rails_6.1
206
+ - task: rspec:rails_6.0
207
+ - task: rspec:rails_5.2
208
208
  - task: rspec:dry
209
209
 
210
210
  ##
data/env.rb CHANGED
@@ -12,8 +12,12 @@
12
12
  #
13
13
  ENV["APPRAISAL_NAME"] ||= ENV["BUNDLE_GEMFILE"].to_s.then(&File.method(:basename)).then { |name| name.end_with?(".gemfile") ? name.delete_suffix(".gemfile") : "" }
14
14
 
15
+ puts "ENV[\"APPRAISAL_NAME\"] -> `#{ENV["APPRAISAL_NAME"]}`"
16
+
15
17
  ##
16
18
  # NOTE: Ruby version may be set by docker.
17
19
  # https://github.com/docker-library/ruby/blob/master/3.1/alpine3.16/Dockerfile#L30
18
20
  #
19
21
  ENV["RUBY_VERSION"] ||= ::RUBY_VERSION
22
+
23
+ puts "ENV[\"RUBY_VERSION\"] -> `#{ENV["RUBY_VERSION"]}`"
@@ -31,7 +31,9 @@ module ConvenientService
31
31
  end
32
32
 
33
33
  middlewares :result do
34
- use Plugins::Service::HasResultParamsValidations::UsingDryValidation::Middleware
34
+ insert_before \
35
+ Plugins::Service::HasResultSteps::Middleware,
36
+ Plugins::Service::HasResultParamsValidations::UsingDryValidation::Middleware
35
37
  end
36
38
  end
37
39
  end
@@ -12,7 +12,7 @@ module ConvenientService
12
12
 
13
13
  contract do
14
14
  schema do
15
- required(:path).value(:string)
15
+ required(:path).filled(:string)
16
16
  end
17
17
  end
18
18
 
@@ -12,7 +12,7 @@ module ConvenientService
12
12
 
13
13
  contract do
14
14
  schema do
15
- required(:path).value(:string)
15
+ required(:path).filled(:string)
16
16
  end
17
17
  end
18
18
 
@@ -17,7 +17,7 @@ module ConvenientService
17
17
 
18
18
  contract do
19
19
  schema do
20
- required(:name).value(:string)
20
+ required(:name).filled(:string)
21
21
  end
22
22
  end
23
23
 
@@ -44,7 +44,7 @@ module ConvenientService
44
44
 
45
45
  contract do
46
46
  schema do
47
- required(:content).value(:string)
47
+ required(:content).filled(:string)
48
48
  end
49
49
  end
50
50
 
@@ -18,7 +18,7 @@ module ConvenientService
18
18
 
19
19
  contract do
20
20
  schema do
21
- required(:text).value(:string)
21
+ required(:text).filled(:string)
22
22
  end
23
23
  end
24
24
 
@@ -12,7 +12,7 @@ module ConvenientService
12
12
 
13
13
  contract do
14
14
  schema do
15
- required(:path).value(:string)
15
+ required(:path).filled(:string)
16
16
  end
17
17
  end
18
18
 
@@ -13,7 +13,7 @@ module ConvenientService
13
13
 
14
14
  contract do
15
15
  schema do
16
- required(:command).value(:string)
16
+ required(:command).filled(:string)
17
17
  optional(:debug).value(:bool)
18
18
  end
19
19
  end
@@ -17,7 +17,7 @@ module ConvenientService
17
17
 
18
18
  contract do
19
19
  schema do
20
- required(:content).value(:string)
20
+ required(:content).filled(:string)
21
21
  end
22
22
  end
23
23
 
@@ -42,7 +42,9 @@ module ConvenientService
42
42
  end
43
43
 
44
44
  middlewares :result do
45
- use Plugins::Service::HasResultParamsValidations::UsingActiveModelValidations::Middleware
45
+ insert_before \
46
+ Plugins::Service::HasResultSteps::Middleware,
47
+ Plugins::Service::HasResultParamsValidations::UsingActiveModelValidations::Middleware
46
48
  end
47
49
  end
48
50
  end
@@ -23,26 +23,26 @@ module ConvenientService
23
23
  end
24
24
 
25
25
  def failure_message
26
- "expected #{printable_block} to cache its value"
26
+ "expected #{printable_block_expectation} to cache its value"
27
27
  end
28
28
 
29
29
  def failure_message_when_negated
30
- "expected #{printable_block} NOT to cache its value"
30
+ "expected #{printable_block_expectation} NOT to cache its value"
31
31
  end
32
32
 
33
33
  ##
34
34
  # NOTE: An example of how RSpec extracts block source, but they marked it as private.
35
35
  # https://github.com/rspec/rspec-expectations/blob/311aaf245f2c5493572bf683b8c441cb5f7e44c8/lib/rspec/matchers/built_in/change.rb#L437
36
36
  #
37
- # TODO: `printable_block` when `method_source` is available.
37
+ # TODO: `printable_block_expectation` when `method_source` is available.
38
38
  # https://github.com/banister/method_source
39
39
  #
40
- # def printable_block
41
- # @printable_block ||= block_expectation.source
40
+ # def printable_block_expectation
41
+ # @printable_block_expectation ||= block_expectation.source
42
42
  # end
43
43
  #
44
- def printable_block
45
- @printable_block ||= "{ ... }"
44
+ def printable_block_expectation
45
+ @printable_block_expectation ||= "{ ... }"
46
46
  end
47
47
 
48
48
  private
@@ -1,5 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ ##
4
+ # IMPORTANT: This matcher has a dedicated end-user doc. Do NOT forget to update it when needed.
5
+ # https://github.com/marian13/convenient_service_docs/blob/main/docs/api/tests/rspec/matchers/delegate_to.mdx
6
+ #
7
+ # TODO: Refactor into composition:
8
+ # - Ability to compose when `delegate_to` is used `without_arguments`.
9
+ # - Ability to compose when `delegate_to` is used `with_arguments`.
10
+ # - Ability to compose when `delegate_to` is used `and_return_its_value`.
11
+ #
12
+ # TODO: Refactor to NOT use `expect` inside this matcher.
13
+ # This way the matcher will return true or false, but never raise exceptions (descendant of Exception, not StandardError).
14
+ # Then it will be easier to developer a fully comprehensive spec suite for `delegate_to`.
15
+ #
3
16
  module ConvenientService
4
17
  module RSpec
5
18
  module Matchers
@@ -81,15 +94,7 @@ module ConvenientService
81
94
  # https://relishapp.com/rspec/rspec-mocks/docs/configuring-responses/wrapping-the-original-implementation
82
95
  #
83
96
  allow(object).to receive(method).and_wrap_original do |original, *actual_args, **actual_kwargs, &actual_block|
84
- ##
85
- # TODO: Provide customized error messages?
86
- # https://relishapp.com/rspec/rspec-expectations/docs/customized-message
87
- #
88
- # NOTE: `delegate_to` expects that delegation is executed only once during `block_expectation`.
89
- #
90
- expect(actual_args).to eq(expected_args)
91
- expect(actual_kwargs).to eq(expected_kwargs)
92
- expect(actual_block).to eq(expected_block)
97
+ actual_arguments_collection << [actual_args, actual_kwargs, actual_block]
93
98
 
94
99
  ##
95
100
  # NOTE: Imitates `and_call_original`.
@@ -108,7 +113,7 @@ module ConvenientService
108
113
  ##
109
114
  # NOTE: If this expectation fails, it means `delegate_to` is NOT met.
110
115
  #
111
- expect(object).to have_received(method)
116
+ expect(object).to have_received(method).at_least(1) unless used_with_arguments?
112
117
 
113
118
  ##
114
119
  # IMPORTANT: `and_return_its_value` works only when `delegate_to` checks a pure function.
@@ -166,7 +171,13 @@ module ConvenientService
166
171
  # NOTE: RSpec raises exception when any `expect` is NOT satisfied.
167
172
  # So, this `true` is returned only when all `expect` are successful.
168
173
  #
169
- true
174
+ if used_with_arguments?
175
+ actual_arguments_collection.any? do |(actual_args, actual_kwargs, actual_block)|
176
+ actual_args == expected_args && actual_kwargs == expected_kwargs && actual_block == expected_block
177
+ end
178
+ else
179
+ true
180
+ end
170
181
  end
171
182
 
172
183
  ##
@@ -184,8 +195,16 @@ module ConvenientService
184
195
  "delegate to `#{printable_method}`"
185
196
  end
186
197
 
198
+ def failure_message
199
+ if used_with_arguments?
200
+ "expected `#{printable_block_expectation}` to delegate to `#{printable_method}` with expected arguments at least once, but it didn't."
201
+ else
202
+ "expected `#{printable_block_expectation}` to delegate to `#{printable_method}` at least once, but it didn't."
203
+ end
204
+ end
205
+
187
206
  ##
188
- # IMPORTANT: `failure_message`, `failure_message_when_negated` are NOT implemented, since they are never called (since `matches?` always returns `true`).
207
+ # IMPORTANT: `failure_message_when_negated` is NOT supported yet.
189
208
  #
190
209
 
191
210
  def with_arguments(*args, **kwargs, &block)
@@ -248,6 +267,25 @@ module ConvenientService
248
267
  end
249
268
 
250
269
  alias_method :expected_block, :block
270
+
271
+ def actual_arguments_collection
272
+ @actual_arguments_collection ||= []
273
+ end
274
+
275
+ ##
276
+ # NOTE: An example of how RSpec extracts block source, but they marked it as private.
277
+ # https://github.com/rspec/rspec-expectations/blob/311aaf245f2c5493572bf683b8c441cb5f7e44c8/lib/rspec/matchers/built_in/change.rb#L437
278
+ #
279
+ # TODO: `printable_block_expectation` when `method_source` is available.
280
+ # https://github.com/banister/method_source
281
+ #
282
+ # def printable_block_expectation
283
+ # @printable_block_expectation ||= block_expectation.source
284
+ # end
285
+ #
286
+ def printable_block_expectation
287
+ @printable_block_expectation ||= "{ ... }"
288
+ end
251
289
  end
252
290
  end
253
291
  end
@@ -49,36 +49,48 @@ module ConvenientService
49
49
  ##
50
50
  # @return [Class]
51
51
  #
52
- def service
53
- internals.cache[:jsend_attributes].service
54
- end
52
+ delegate :service, to: :jsend_attributes
55
53
 
56
54
  ##
57
55
  # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result::Plugins::HasJsendStatusAndAttributes::Entities::Status]
58
56
  #
59
- def status
60
- internals.cache[:jsend_attributes].status
61
- end
57
+ delegate :status, to: :jsend_attributes
62
58
 
63
59
  ##
64
60
  # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result::Plugins::HasJsendStatusAndAttributes::Entities::Data]
65
61
  #
66
- def data
67
- internals.cache[:jsend_attributes].data
68
- end
62
+ delegate :data, to: :jsend_attributes
63
+
64
+ ##
65
+ # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result::Plugins::HasJsendStatusAndAttributes::Entities::Data]
66
+ #
67
+ alias_method :unsafe_data, :data
69
68
 
70
69
  ##
71
70
  # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result::Plugins::HasJsendStatusAndAttributes::Entities::Message]
72
71
  #
73
- def message
74
- internals.cache[:jsend_attributes].message
75
- end
72
+ delegate :message, to: :jsend_attributes
73
+
74
+ ##
75
+ # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result::Plugins::HasJsendStatusAndAttributes::Entities::Message]
76
+ #
77
+ alias_method :unsafe_message, :message
76
78
 
77
79
  ##
78
80
  # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result::Plugins::HasJsendStatusAndAttributes::Entities::Code]
79
81
  #
80
- def code
81
- internals.cache[:jsend_attributes].code
82
+ delegate :code, to: :jsend_attributes
83
+
84
+ ##
85
+ # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result::Plugins::HasJsendStatusAndAttributes::Entities::Code]
86
+ #
87
+ alias_method :unsafe_code, :code
88
+
89
+ ##
90
+ # @return [ConvenientService::Service::Plugins::HasResult::Entities::Result::Plugins::HasJsendStatusAndAttributes::Structs::JSendAttributes]
91
+ #
92
+ def jsend_attributes
93
+ internals.cache[:jsend_attributes]
82
94
  end
83
95
 
84
96
  ##
@@ -90,9 +102,9 @@ module ConvenientService
90
102
 
91
103
  return false if service.class != other.service.class
92
104
  return false if status != other.status
93
- return false if data != other.data
94
- return false if message != other.message
95
- return false if code != other.code
105
+ return false if unsafe_data != other.unsafe_data
106
+ return false if unsafe_message != other.unsafe_message
107
+ return false if unsafe_code != other.unsafe_code
96
108
 
97
109
  true
98
110
  end
@@ -21,15 +21,25 @@ module ConvenientService
21
21
  # TODO: Return one or all errors?
22
22
  #
23
23
  def errors
24
- @errors ||=
25
- entity
26
- .class
27
- .contract
28
- .new
29
- .call(**entity.constructor_params.kwargs)
30
- .errors
31
- .to_h
32
- .transform_values(&:first)
24
+ @errors ||= resolve_errors
25
+ end
26
+
27
+ def constructor_kwargs
28
+ @constructor_kwargs ||= entity.constructor_params.kwargs
29
+ end
30
+
31
+ def contract
32
+ @contract ||= entity.class.contract
33
+ end
34
+
35
+ def resolve_errors
36
+ return {} unless contract.schema
37
+
38
+ contract.new
39
+ .call(constructor_kwargs)
40
+ .errors
41
+ .to_h
42
+ .transform_values(&:first)
33
43
  end
34
44
  end
35
45
  end
@@ -8,7 +8,7 @@ module ConvenientService
8
8
  def next(...)
9
9
  return chain.next(...) if entity.steps.none?
10
10
 
11
- last_step.result
11
+ last_step.result.copy
12
12
  end
13
13
 
14
14
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ConvenientService
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: convenient_service
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marian Kostyk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-29 00:00:00.000000000 Z
11
+ date: 2022-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appraisal