convenient_service 0.2.0 → 0.3.0
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/.github/workflows/ci.yml +6 -6
- data/CHANGELOG.md +16 -0
- data/ROADMAP.md +5 -0
- data/Taskfile.yml +3 -3
- data/env.rb +4 -0
- data/lib/convenient_service/configs/standard.rb +16 -0
- data/lib/convenient_service/dependencies/built_in.rb +8 -0
- data/lib/convenient_service/dependencies.rb +37 -0
- data/lib/convenient_service/examples/dry/gemfile/dry_service/config.rb +3 -1
- data/lib/convenient_service/examples/dry/gemfile/services/assert_file_exists.rb +1 -1
- data/lib/convenient_service/examples/dry/gemfile/services/assert_file_not_empty.rb +1 -1
- data/lib/convenient_service/examples/dry/gemfile/services/assert_npm_package_available.rb +1 -1
- data/lib/convenient_service/examples/dry/gemfile/services/parse_content.rb +1 -1
- data/lib/convenient_service/examples/dry/gemfile/services/print_shell_command.rb +1 -1
- data/lib/convenient_service/examples/dry/gemfile/services/read_file_content.rb +1 -1
- data/lib/convenient_service/examples/dry/gemfile/services/run_shell.rb +1 -1
- data/lib/convenient_service/examples/dry/gemfile/services/strip_comments.rb +1 -1
- data/lib/convenient_service/examples/rails/gemfile/rails_service/config.rb +3 -1
- data/lib/convenient_service/examples/rails/gemfile/services/assert_file_exists.rb +1 -1
- data/lib/convenient_service/examples/rails/gemfile/services/assert_file_not_empty.rb +1 -1
- data/lib/convenient_service/examples/rails/gemfile/services/assert_npm_package_available.rb +1 -1
- data/lib/convenient_service/examples/rails/gemfile/services/parse_content.rb +1 -1
- data/lib/convenient_service/examples/rails/gemfile/services/print_shell_command.rb +1 -1
- data/lib/convenient_service/examples/rails/gemfile/services/read_file_content.rb +1 -1
- data/lib/convenient_service/examples/rails/gemfile/services/run_shell.rb +1 -1
- data/lib/convenient_service/examples/rails/gemfile/services/strip_comments.rb +1 -1
- data/lib/convenient_service/rspec/helpers/custom/stub_service/entities/result_spec.rb +17 -1
- data/lib/convenient_service/rspec/helpers/custom/stub_service/entities/stubbed_service.rb +47 -53
- data/lib/convenient_service/rspec/matchers/custom/cache_its_value.rb +7 -7
- data/lib/convenient_service/rspec/matchers/custom/delegate_to.rb +50 -12
- data/lib/convenient_service/service/plugins/can_have_stubbed_result/concern.rb +32 -0
- data/lib/convenient_service/service/plugins/can_have_stubbed_result/middleware.rb +36 -0
- data/lib/convenient_service/service/plugins/can_have_stubbed_result.rb +4 -0
- data/lib/convenient_service/service/plugins/has_result/entities/result/plugins/has_jsend_status_and_attributes/concern/instance_methods.rb +29 -17
- data/lib/convenient_service/service/plugins/has_result_params_validations/using_dry_validation/middleware.rb +19 -9
- data/lib/convenient_service/service/plugins/has_result_steps/middleware.rb +1 -1
- data/lib/convenient_service/service/plugins.rb +1 -0
- data/lib/convenient_service/support/cache.rb +26 -0
- data/lib/convenient_service/support/gems/active_model.rb +36 -0
- data/lib/convenient_service/support/gems/rspec.rb +36 -0
- data/lib/convenient_service/support/gems.rb +4 -0
- data/lib/convenient_service/support/ruby.rb +22 -0
- data/lib/convenient_service/support/version/null_version.rb +78 -0
- data/lib/convenient_service/support/version.rb +65 -0
- data/lib/convenient_service/support.rb +3 -0
- data/lib/convenient_service/utils/object/instance_variable_fetch.rb +53 -0
- data/lib/convenient_service/utils/object.rb +9 -0
- data/lib/convenient_service/version.rb +1 -1
- metadata +12 -2
@@ -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
|
-
|
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: `
|
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
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ConvenientService
|
4
|
+
module Service
|
5
|
+
module Plugins
|
6
|
+
module CanHaveStubbedResult
|
7
|
+
module Concern
|
8
|
+
include Support::Concern
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
##
|
12
|
+
# @return [ConvenientService::Support::Cache]
|
13
|
+
#
|
14
|
+
# @internal
|
15
|
+
# `::RSpec.current_example` docs:
|
16
|
+
# - https://www.rubydoc.info/github/rspec/rspec-core/RSpec.current_example
|
17
|
+
# - https://github.com/rspec/rspec-core/blob/v3.12.0/lib/rspec/core.rb#L122
|
18
|
+
# - https://relishapp.com/rspec/rspec-core/docs/metadata/current-example
|
19
|
+
#
|
20
|
+
# TODO: Mutex for thread-safety when parallel steps will be supported.
|
21
|
+
#
|
22
|
+
def stubbed_results
|
23
|
+
cache = Utils::Object.instance_variable_fetch(::RSpec.current_example, :@__convenient_service_stubbed_results__) { Support::Cache.new }
|
24
|
+
|
25
|
+
cache.scope(self)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ConvenientService
|
4
|
+
module Service
|
5
|
+
module Plugins
|
6
|
+
module CanHaveStubbedResult
|
7
|
+
class Middleware < Core::MethodChainMiddleware
|
8
|
+
##
|
9
|
+
# @param args [Array]
|
10
|
+
# @param kwargs [Hash]
|
11
|
+
# @param block [Proc]
|
12
|
+
# @return [Object] Can be any type.
|
13
|
+
#
|
14
|
+
def next(*args, **kwargs, &block)
|
15
|
+
key_with_arguments = cache.keygen(*args, **kwargs, &block)
|
16
|
+
key_without_arguments = cache.keygen
|
17
|
+
|
18
|
+
return cache[key_with_arguments] if cache.exist?(key_with_arguments)
|
19
|
+
return cache[key_without_arguments] if cache.exist?(key_without_arguments)
|
20
|
+
|
21
|
+
chain.next(*args, **kwargs, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
##
|
27
|
+
# @return [ConvenientService::Support::Cache]
|
28
|
+
#
|
29
|
+
def cache
|
30
|
+
entity.stubbed_results
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -49,36 +49,48 @@ module ConvenientService
|
|
49
49
|
##
|
50
50
|
# @return [Class]
|
51
51
|
#
|
52
|
-
|
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
|
-
|
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
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
81
|
-
|
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
|
94
|
-
return false if
|
95
|
-
return false if
|
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
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
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
|
@@ -21,6 +21,16 @@ module ConvenientService
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
##
|
25
|
+
# @return [Boolean]
|
26
|
+
#
|
27
|
+
# @internal
|
28
|
+
# https://ruby-doc.org/core-2.7.0/Hash.html#method-i-empty-3F
|
29
|
+
#
|
30
|
+
def empty?
|
31
|
+
hash.empty?
|
32
|
+
end
|
33
|
+
|
24
34
|
##
|
25
35
|
# @return [Boolean]
|
26
36
|
#
|
@@ -100,6 +110,22 @@ module ConvenientService
|
|
100
110
|
exist?(key) ? read(key) : write(key, block.call)
|
101
111
|
end
|
102
112
|
|
113
|
+
##
|
114
|
+
# @return [ConvenientService::Support::Cache]
|
115
|
+
#
|
116
|
+
def clear
|
117
|
+
hash.clear
|
118
|
+
|
119
|
+
self
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# @return [ConvenientService::Support::Cache]
|
124
|
+
#
|
125
|
+
def scope(key)
|
126
|
+
fetch(key) { Support::Cache.new }
|
127
|
+
end
|
128
|
+
|
103
129
|
##
|
104
130
|
# @return [ConvenientService::Support::Cache::Key]
|
105
131
|
#
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ConvenientService
|
4
|
+
module Support
|
5
|
+
module Gems
|
6
|
+
##
|
7
|
+
# @api private
|
8
|
+
#
|
9
|
+
class ActiveModel
|
10
|
+
class << self
|
11
|
+
##
|
12
|
+
# @return [Boolean]
|
13
|
+
#
|
14
|
+
# @internal
|
15
|
+
# `Style/TernaryParentheses` is disabled since `defined?` has too low priority without parentheses.
|
16
|
+
#
|
17
|
+
# rubocop:disable Style/TernaryParentheses
|
18
|
+
def loaded?
|
19
|
+
(defined? ::ActiveModel) ? true : false
|
20
|
+
end
|
21
|
+
# rubocop:enable Style/TernaryParentheses
|
22
|
+
|
23
|
+
##
|
24
|
+
# @return [ConvenientService::Support::Version]
|
25
|
+
#
|
26
|
+
# @internal
|
27
|
+
# https://github.com/rails/rails/blob/main/activemodel/lib/active_model/version.rb
|
28
|
+
#
|
29
|
+
def version
|
30
|
+
loaded? ? Support::Version.new(::ActiveModel.version) : Support::Version.null_version
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ConvenientService
|
4
|
+
module Support
|
5
|
+
module Gems
|
6
|
+
##
|
7
|
+
# @api private
|
8
|
+
#
|
9
|
+
class RSpec
|
10
|
+
class << self
|
11
|
+
##
|
12
|
+
# @return [Boolean]
|
13
|
+
#
|
14
|
+
# @internal
|
15
|
+
# `Style/TernaryParentheses` is disabled since `defined?` has too low priority without parentheses.
|
16
|
+
#
|
17
|
+
# rubocop:disable Style/TernaryParentheses
|
18
|
+
def loaded?
|
19
|
+
(defined? ::RSpec) ? true : false
|
20
|
+
end
|
21
|
+
# rubocop:enable Style/TernaryParentheses
|
22
|
+
|
23
|
+
##
|
24
|
+
# @return [ConvenientService::Support::Version]
|
25
|
+
#
|
26
|
+
# @internal
|
27
|
+
# https://github.com/rspec/rspec-core/blob/main/lib/rspec/core/version.rb
|
28
|
+
#
|
29
|
+
def version
|
30
|
+
loaded? ? Support::Version.new(::RSpec::Core::Version::STRING) : Support::Version.null_version
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ConvenientService
|
4
|
+
module Support
|
5
|
+
##
|
6
|
+
# @api private
|
7
|
+
#
|
8
|
+
class Ruby
|
9
|
+
class << self
|
10
|
+
##
|
11
|
+
# @return [ConvenientService::Support::Version]
|
12
|
+
#
|
13
|
+
# @internal
|
14
|
+
# https://ruby-doc.org/core-2.7.2/doc/globals_rdoc.html
|
15
|
+
#
|
16
|
+
def version
|
17
|
+
@version ||= Support::Version.new(::RUBY_VERSION)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ConvenientService
|
4
|
+
module Support
|
5
|
+
class Version
|
6
|
+
##
|
7
|
+
# @api private
|
8
|
+
#
|
9
|
+
# @internal
|
10
|
+
# - https://thoughtbot.com/blog/rails-refactoring-example-introduce-null-object
|
11
|
+
# - https://avdi.codes/null-objects-and-falsiness/
|
12
|
+
#
|
13
|
+
class NullVersion
|
14
|
+
##
|
15
|
+
# @return [nil]
|
16
|
+
#
|
17
|
+
def gem_version
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
##
|
22
|
+
# @param other [Object] Can be any type.
|
23
|
+
# @return [nil]
|
24
|
+
#
|
25
|
+
def <=>(other)
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# @param other [Object] Can be any type.
|
31
|
+
# @return [nil]
|
32
|
+
#
|
33
|
+
def <(other)
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# @param other [Object] Can be any type.
|
39
|
+
# @return [nil]
|
40
|
+
#
|
41
|
+
def <=(other)
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# @param other [Object] Can be any type.
|
47
|
+
# @return [nil]
|
48
|
+
#
|
49
|
+
def ==(other)
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# @param other [Object] Can be any type.
|
55
|
+
# @return [nil]
|
56
|
+
#
|
57
|
+
def >(other)
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# @param other [Object] Can be any type.
|
63
|
+
# @return [nil]
|
64
|
+
#
|
65
|
+
def >=(other)
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# @return [String]
|
71
|
+
#
|
72
|
+
def to_s
|
73
|
+
""
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "version/null_version"
|
4
|
+
|
5
|
+
module ConvenientService
|
6
|
+
module Support
|
7
|
+
class Version
|
8
|
+
include ::Comparable
|
9
|
+
|
10
|
+
undef_method :between?
|
11
|
+
|
12
|
+
undef_method :clamp
|
13
|
+
|
14
|
+
##
|
15
|
+
# @param value [String]
|
16
|
+
# @return [void]
|
17
|
+
#
|
18
|
+
def initialize(value)
|
19
|
+
@value = value
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
##
|
24
|
+
# @return [ConvenientService::Support::Version::NullVersion]
|
25
|
+
#
|
26
|
+
def null_version
|
27
|
+
@null_version ||= NullVersion.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# @return [Gem::Version, nil]
|
33
|
+
#
|
34
|
+
def gem_version
|
35
|
+
cast_gem_version(value)
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# @param other [Object] Can be any type.
|
40
|
+
# @return [Boolean, nil]
|
41
|
+
#
|
42
|
+
def <=>(other)
|
43
|
+
gem_version <=> cast_gem_version(other)
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# @return [String]
|
48
|
+
#
|
49
|
+
def to_s
|
50
|
+
gem_version.to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
attr_reader :value
|
56
|
+
|
57
|
+
##
|
58
|
+
# @return [Gem::Version, nil]
|
59
|
+
#
|
60
|
+
def cast_gem_version(value)
|
61
|
+
::Gem::Version.create(value.to_s) if ::Gem::Version.correct?(value.to_s)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -9,4 +9,7 @@ require_relative "support/command"
|
|
9
9
|
require_relative "support/copyable"
|
10
10
|
require_relative "support/delegate"
|
11
11
|
require_relative "support/finite_loop"
|
12
|
+
require_relative "support/gems"
|
12
13
|
require_relative "support/middleware"
|
14
|
+
require_relative "support/ruby"
|
15
|
+
require_relative "support/version"
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
#
|
5
|
+
#
|
6
|
+
module ConvenientService
|
7
|
+
module Utils
|
8
|
+
module Object
|
9
|
+
class InstanceVariableFetch < Support::Command
|
10
|
+
##
|
11
|
+
# @!attribute [r] object
|
12
|
+
# @return [Object]
|
13
|
+
#
|
14
|
+
attr_reader :object
|
15
|
+
|
16
|
+
##
|
17
|
+
# @!attribute [r] ivar_name
|
18
|
+
# @return [Symbol, String]
|
19
|
+
#
|
20
|
+
attr_reader :ivar_name
|
21
|
+
|
22
|
+
##
|
23
|
+
# @!attribute [r] fallback_block
|
24
|
+
# @return [Proc, nil]
|
25
|
+
#
|
26
|
+
attr_reader :fallback_block
|
27
|
+
|
28
|
+
##
|
29
|
+
# @param object [Object]
|
30
|
+
# @param ivar_name [Symbol]
|
31
|
+
# @param fallback_block [Proc]
|
32
|
+
# @return [void]
|
33
|
+
#
|
34
|
+
def initialize(object, ivar_name, &fallback_block)
|
35
|
+
@object = object
|
36
|
+
@ivar_name = ivar_name
|
37
|
+
@fallback_block = fallback_block
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# @return [Object] Value of ivar. Can be any type.
|
42
|
+
#
|
43
|
+
def call
|
44
|
+
return object.instance_variable_get(ivar_name) if object.instance_variable_defined?(ivar_name)
|
45
|
+
|
46
|
+
return object.instance_variable_set(ivar_name, fallback_block.call) if fallback_block
|
47
|
+
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -1,11 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "object/instance_variable_fetch"
|
3
4
|
require_relative "object/resolve_type"
|
4
5
|
|
5
6
|
module ConvenientService
|
6
7
|
module Utils
|
7
8
|
module Object
|
8
9
|
class << self
|
10
|
+
##
|
11
|
+
# @example
|
12
|
+
# ConvenientService::Utils::Object.instance_variable_fetch("abc", :@foo) { :bar }
|
13
|
+
#
|
14
|
+
def instance_variable_fetch(...)
|
15
|
+
InstanceVariableFetch.call(...)
|
16
|
+
end
|
17
|
+
|
9
18
|
##
|
10
19
|
# @example
|
11
20
|
# ConvenientService::Utils::Object.resolve_type("foo")
|