treaty 0.0.1 → 0.1.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/README.md +19 -18
- data/Rakefile +4 -2
- data/lib/treaty/attribute/base.rb +172 -0
- data/lib/treaty/attribute/builder/base.rb +142 -0
- data/lib/treaty/attribute/collection.rb +65 -0
- data/lib/treaty/attribute/helper_mapper.rb +72 -0
- data/lib/treaty/attribute/option/base.rb +159 -0
- data/lib/treaty/attribute/option/modifiers/as_modifier.rb +87 -0
- data/lib/treaty/attribute/option/modifiers/default_modifier.rb +103 -0
- data/lib/treaty/attribute/option/registry.rb +128 -0
- data/lib/treaty/attribute/option/registry_initializer.rb +90 -0
- data/lib/treaty/attribute/option/validators/inclusion_validator.rb +80 -0
- data/lib/treaty/attribute/option/validators/required_validator.rb +94 -0
- data/lib/treaty/attribute/option/validators/type_validator.rb +153 -0
- data/lib/treaty/attribute/option_normalizer.rb +150 -0
- data/lib/treaty/attribute/option_orchestrator.rb +186 -0
- data/lib/treaty/attribute/validation/attribute_validator.rb +144 -0
- data/lib/treaty/attribute/validation/base.rb +93 -0
- data/lib/treaty/attribute/validation/nested_array_validator.rb +194 -0
- data/lib/treaty/attribute/validation/nested_object_validator.rb +103 -0
- data/lib/treaty/attribute/validation/nested_transformer.rb +240 -0
- data/lib/treaty/attribute/validation/orchestrator/base.rb +196 -0
- data/lib/treaty/base.rb +9 -0
- data/lib/treaty/configuration.rb +17 -0
- data/lib/treaty/context/callable.rb +24 -0
- data/lib/treaty/context/dsl.rb +12 -0
- data/lib/treaty/context/workspace.rb +28 -0
- data/lib/treaty/controller/dsl.rb +38 -0
- data/lib/treaty/engine.rb +37 -0
- data/lib/treaty/exceptions/base.rb +8 -0
- data/lib/treaty/exceptions/class_name.rb +11 -0
- data/lib/treaty/exceptions/deprecated.rb +8 -0
- data/lib/treaty/exceptions/execution.rb +8 -0
- data/lib/treaty/exceptions/method_name.rb +8 -0
- data/lib/treaty/exceptions/nested_attributes.rb +8 -0
- data/lib/treaty/exceptions/strategy.rb +8 -0
- data/lib/treaty/exceptions/unexpected.rb +8 -0
- data/lib/treaty/exceptions/validation.rb +8 -0
- data/lib/treaty/info/builder.rb +122 -0
- data/lib/treaty/info/dsl.rb +26 -0
- data/lib/treaty/info/result.rb +13 -0
- data/lib/treaty/request/attribute/attribute.rb +24 -0
- data/lib/treaty/request/attribute/builder.rb +22 -0
- data/lib/treaty/request/attribute/validation/orchestrator.rb +27 -0
- data/lib/treaty/request/attribute/validator.rb +50 -0
- data/lib/treaty/request/factory.rb +32 -0
- data/lib/treaty/request/scope/collection.rb +21 -0
- data/lib/treaty/request/scope/factory.rb +42 -0
- data/lib/treaty/response/attribute/attribute.rb +24 -0
- data/lib/treaty/response/attribute/builder.rb +22 -0
- data/lib/treaty/response/attribute/validation/orchestrator.rb +27 -0
- data/lib/treaty/response/attribute/validator.rb +44 -0
- data/lib/treaty/response/factory.rb +38 -0
- data/lib/treaty/response/scope/collection.rb +21 -0
- data/lib/treaty/response/scope/factory.rb +42 -0
- data/lib/treaty/result.rb +22 -0
- data/lib/treaty/strategy.rb +31 -0
- data/lib/treaty/support/loader.rb +24 -0
- data/lib/treaty/version.rb +8 -1
- data/lib/treaty/versions/collection.rb +15 -0
- data/lib/treaty/versions/dsl.rb +30 -0
- data/lib/treaty/versions/execution/request.rb +151 -0
- data/lib/treaty/versions/executor.rb +14 -0
- data/lib/treaty/versions/factory.rb +93 -0
- data/lib/treaty/versions/resolver.rb +72 -0
- data/lib/treaty/versions/semantic.rb +22 -0
- data/lib/treaty/versions/workspace.rb +40 -0
- data/lib/treaty.rb +3 -3
- metadata +184 -27
- data/.standard.yml +0 -3
- data/CHANGELOG.md +0 -5
- data/CODE_OF_CONDUCT.md +0 -84
- data/LICENSE.txt +0 -21
- data/sig/treaty.rbs +0 -4
- data/treaty.gemspec +0 -35
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Request
|
|
5
|
+
module Attribute
|
|
6
|
+
module Validation
|
|
7
|
+
class Orchestrator < Treaty::Attribute::Validation::Orchestrator::Base
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def collection_of_scopes
|
|
11
|
+
return Treaty::Request::Scope::Collection.new if version_factory.request_factory.nil?
|
|
12
|
+
|
|
13
|
+
version_factory.request_factory.collection_of_scopes
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def scope_data_for(name)
|
|
17
|
+
# If the scope is :_self, it's the root level.
|
|
18
|
+
return data if name == :_self
|
|
19
|
+
|
|
20
|
+
# Otherwise, fetch data from the named scope.
|
|
21
|
+
data.fetch(name, {})
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Request
|
|
5
|
+
module Attribute
|
|
6
|
+
class Validator < Treaty::Attribute::Validation::Base
|
|
7
|
+
def self.validate!(...)
|
|
8
|
+
new(...).validate!
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(controller:, version_factory:)
|
|
12
|
+
super(version_factory:)
|
|
13
|
+
|
|
14
|
+
@controller = controller
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def validate!
|
|
18
|
+
validate_request_attributes!
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def request_data
|
|
24
|
+
@request_data ||= begin
|
|
25
|
+
@controller.params.to_unsafe_h
|
|
26
|
+
rescue NoMethodError
|
|
27
|
+
@controller.params
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def validate_request_attributes!
|
|
32
|
+
return request_data unless adapter_strategy?
|
|
33
|
+
return request_data unless request_attributes_exist?
|
|
34
|
+
|
|
35
|
+
# For adapter strategy:
|
|
36
|
+
Validation::Orchestrator.validate!(
|
|
37
|
+
version_factory: @version_factory,
|
|
38
|
+
data: request_data
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def request_attributes_exist?
|
|
43
|
+
return false if @version_factory.request_factory&.collection_of_scopes&.empty?
|
|
44
|
+
|
|
45
|
+
@version_factory.request_factory.collection_of_scopes.exists?
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Request
|
|
5
|
+
class Factory
|
|
6
|
+
def scope(name, &block)
|
|
7
|
+
@scope_factory = Scope::Factory.new(name)
|
|
8
|
+
|
|
9
|
+
@scope_factory.instance_eval(&block) if block_given?
|
|
10
|
+
|
|
11
|
+
collection_of_scopes << @scope_factory
|
|
12
|
+
|
|
13
|
+
@scope_factory = nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def collection_of_scopes
|
|
17
|
+
@collection_of_scopes ||= Scope::Collection.new
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
##########################################################################
|
|
21
|
+
|
|
22
|
+
def method_missing(name, *, &_block)
|
|
23
|
+
# TODO: It needs to be implemented.
|
|
24
|
+
puts "Unknown request block method: #{name}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def respond_to_missing?(name, *)
|
|
28
|
+
super
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Request
|
|
5
|
+
module Scope
|
|
6
|
+
class Collection
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
def_delegators :@collection, :<<, :to_h, :each, :find, :empty?
|
|
10
|
+
|
|
11
|
+
def initialize(collection = Set.new)
|
|
12
|
+
@collection = collection
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def exists?
|
|
16
|
+
!empty?
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Request
|
|
5
|
+
module Scope
|
|
6
|
+
class Factory
|
|
7
|
+
attr_reader :name
|
|
8
|
+
|
|
9
|
+
def initialize(name)
|
|
10
|
+
@name = name
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def attribute(name, type, *helpers, **options, &block)
|
|
14
|
+
collection_of_attributes << Attribute::Attribute.new(
|
|
15
|
+
name,
|
|
16
|
+
type,
|
|
17
|
+
*helpers,
|
|
18
|
+
nesting_level: 0,
|
|
19
|
+
**options,
|
|
20
|
+
&block
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def collection_of_attributes
|
|
25
|
+
@collection_of_attributes ||= Treaty::Attribute::Collection.new
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
########################################################################
|
|
29
|
+
|
|
30
|
+
def method_missing(type, *helpers, **options, &block)
|
|
31
|
+
name = helpers.shift
|
|
32
|
+
|
|
33
|
+
attribute(name, type, *helpers, **options, &block)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def respond_to_missing?(name, *)
|
|
37
|
+
super
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Response
|
|
5
|
+
module Attribute
|
|
6
|
+
class Attribute < Treaty::Attribute::Base
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def apply_defaults!
|
|
10
|
+
# For response: optional by default (false).
|
|
11
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
12
|
+
@options[:required] ||= { is: false, message: nil }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def process_nested_attributes(&block)
|
|
16
|
+
return unless object_or_array?
|
|
17
|
+
|
|
18
|
+
builder = Builder.new(collection_of_attributes, @nesting_level + 1)
|
|
19
|
+
builder.instance_eval(&block)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Response
|
|
5
|
+
module Attribute
|
|
6
|
+
class Builder < Treaty::Attribute::Builder::Base
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def create_attribute(name, type, *helpers, nesting_level:, **options, &block)
|
|
10
|
+
Attribute.new(
|
|
11
|
+
name,
|
|
12
|
+
type,
|
|
13
|
+
*helpers,
|
|
14
|
+
nesting_level:,
|
|
15
|
+
**options,
|
|
16
|
+
&block
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Response
|
|
5
|
+
module Attribute
|
|
6
|
+
module Validation
|
|
7
|
+
class Orchestrator < Treaty::Attribute::Validation::Orchestrator::Base
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def collection_of_scopes
|
|
11
|
+
return Treaty::Response::Scope::Collection.new if version_factory.response_factory.nil?
|
|
12
|
+
|
|
13
|
+
version_factory.response_factory.collection_of_scopes
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def scope_data_for(name)
|
|
17
|
+
# If the scope is :_self, it's the root level.
|
|
18
|
+
return data if name == :_self
|
|
19
|
+
|
|
20
|
+
# Otherwise, fetch data from the named scope.
|
|
21
|
+
data.fetch(name, {})
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Response
|
|
5
|
+
module Attribute
|
|
6
|
+
class Validator < Treaty::Attribute::Validation::Base
|
|
7
|
+
def self.validate!(version_factory:, response_data: {})
|
|
8
|
+
new(
|
|
9
|
+
version_factory:,
|
|
10
|
+
response_data:
|
|
11
|
+
).validate!
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def initialize(version_factory:, response_data: {})
|
|
15
|
+
super(version_factory:)
|
|
16
|
+
|
|
17
|
+
@response_data = response_data
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def validate!
|
|
21
|
+
validate_response_attributes!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def validate_response_attributes!
|
|
27
|
+
return @response_data unless response_attributes_exist?
|
|
28
|
+
|
|
29
|
+
# For adapter strategy:
|
|
30
|
+
Validation::Orchestrator.validate!(
|
|
31
|
+
version_factory: @version_factory,
|
|
32
|
+
data: @response_data
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def response_attributes_exist?
|
|
37
|
+
return false if @version_factory.response_factory&.collection_of_scopes&.empty?
|
|
38
|
+
|
|
39
|
+
@version_factory.response_factory.collection_of_scopes.exists?
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Response
|
|
5
|
+
class Factory
|
|
6
|
+
attr_reader :status
|
|
7
|
+
|
|
8
|
+
def initialize(status)
|
|
9
|
+
@status = status
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def scope(name, &block)
|
|
13
|
+
@scope_factory = Scope::Factory.new(name)
|
|
14
|
+
|
|
15
|
+
@scope_factory.instance_eval(&block) if block_given?
|
|
16
|
+
|
|
17
|
+
collection_of_scopes << @scope_factory
|
|
18
|
+
|
|
19
|
+
@scope_factory = nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def collection_of_scopes
|
|
23
|
+
@collection_of_scopes ||= Scope::Collection.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##########################################################################
|
|
27
|
+
|
|
28
|
+
def method_missing(name, *, &_block)
|
|
29
|
+
# TODO: It needs to be implemented.
|
|
30
|
+
puts "Unknown response block method: #{name}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def respond_to_missing?(name, *)
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Response
|
|
5
|
+
module Scope
|
|
6
|
+
class Collection
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
def_delegators :@collection, :<<, :to_h, :each, :find, :empty?
|
|
10
|
+
|
|
11
|
+
def initialize(collection = Set.new)
|
|
12
|
+
@collection = collection
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def exists?
|
|
16
|
+
!empty?
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Response
|
|
5
|
+
module Scope
|
|
6
|
+
class Factory
|
|
7
|
+
attr_reader :name
|
|
8
|
+
|
|
9
|
+
def initialize(name)
|
|
10
|
+
@name = name
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def attribute(name, type, *helpers, **options, &block)
|
|
14
|
+
collection_of_attributes << Attribute::Attribute.new(
|
|
15
|
+
name,
|
|
16
|
+
type,
|
|
17
|
+
*helpers,
|
|
18
|
+
nesting_level: 0,
|
|
19
|
+
**options,
|
|
20
|
+
&block
|
|
21
|
+
)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def collection_of_attributes
|
|
25
|
+
@collection_of_attributes ||= Treaty::Attribute::Collection.new
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
########################################################################
|
|
29
|
+
|
|
30
|
+
def method_missing(type, *helpers, **options, &block)
|
|
31
|
+
name = helpers.shift
|
|
32
|
+
|
|
33
|
+
attribute(name, type, *helpers, **options, &block)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def respond_to_missing?(name, *)
|
|
37
|
+
super
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
class Result
|
|
5
|
+
attr_reader :data, :status
|
|
6
|
+
|
|
7
|
+
def initialize(data:, status:)
|
|
8
|
+
@data = data
|
|
9
|
+
@status = status
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def inspect
|
|
13
|
+
"#<#{self.class.name} #{draw_result}>"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def draw_result
|
|
19
|
+
"@data=#{@data.inspect}, @status=#{@status.inspect}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
class Strategy
|
|
5
|
+
DIRECT = :direct
|
|
6
|
+
ADAPTER = :adapter
|
|
7
|
+
|
|
8
|
+
LIST = [DIRECT, ADAPTER].freeze
|
|
9
|
+
|
|
10
|
+
attr_reader :code
|
|
11
|
+
|
|
12
|
+
def initialize(code)
|
|
13
|
+
@code = code
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def validate!
|
|
17
|
+
return self if LIST.include?(@code)
|
|
18
|
+
|
|
19
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
20
|
+
raise Treaty::Exceptions::Strategy, "Unknown strategy: #{@code}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def direct?
|
|
24
|
+
@code == DIRECT
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def adapter?
|
|
28
|
+
@code == ADAPTER
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "zeitwerk"
|
|
4
|
+
|
|
5
|
+
lib_dir = File.expand_path("../..", __dir__)
|
|
6
|
+
|
|
7
|
+
loader = Zeitwerk::Loader.new
|
|
8
|
+
|
|
9
|
+
loader.tag = "treaty"
|
|
10
|
+
|
|
11
|
+
loader.inflector = Zeitwerk::GemInflector.new(
|
|
12
|
+
File.expand_path("web.rb", lib_dir)
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
loader.inflector.inflect(
|
|
16
|
+
"dsl" => "DSL",
|
|
17
|
+
"version" => "VERSION"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
loader.ignore(__dir__)
|
|
21
|
+
|
|
22
|
+
loader.push_dir(lib_dir)
|
|
23
|
+
|
|
24
|
+
loader.setup
|
data/lib/treaty/version.rb
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Versions
|
|
5
|
+
class Collection
|
|
6
|
+
extend Forwardable
|
|
7
|
+
|
|
8
|
+
def_delegators :@collection, :<<, :map, :find
|
|
9
|
+
|
|
10
|
+
def initialize(collection = Set.new)
|
|
11
|
+
@collection = collection
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Versions
|
|
5
|
+
module DSL
|
|
6
|
+
def self.included(base)
|
|
7
|
+
base.extend(ClassMethods)
|
|
8
|
+
base.include(Workspace)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module ClassMethods
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def version(version, default: false, &block)
|
|
15
|
+
@version_factory = Factory.new(version:, default:)
|
|
16
|
+
|
|
17
|
+
@version_factory.instance_eval(&block)
|
|
18
|
+
|
|
19
|
+
collection_of_versions << @version_factory
|
|
20
|
+
|
|
21
|
+
@version_factory = nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def collection_of_versions
|
|
25
|
+
@collection_of_versions ||= Collection.new
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Versions
|
|
5
|
+
module Execution
|
|
6
|
+
class Request
|
|
7
|
+
def self.execute!(...)
|
|
8
|
+
new(...).execute!
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(version_factory:, validated_params:)
|
|
12
|
+
@version_factory = version_factory
|
|
13
|
+
@validated_params = validated_params
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def execute!
|
|
17
|
+
raise_executor_missing_error! if @version_factory.executor.nil?
|
|
18
|
+
|
|
19
|
+
extract_data_from_result
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def extract_data_from_result
|
|
25
|
+
return execution_result if executor.is_a?(Proc)
|
|
26
|
+
return execution_result.data if execution_result.respond_to?(:data)
|
|
27
|
+
|
|
28
|
+
execution_result
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
########################################################################
|
|
32
|
+
|
|
33
|
+
def execution_result
|
|
34
|
+
@execution_result ||=
|
|
35
|
+
if executor.is_a?(Proc)
|
|
36
|
+
execute_proc
|
|
37
|
+
elsif servactory_service?
|
|
38
|
+
execute_servactory
|
|
39
|
+
else
|
|
40
|
+
execute_regular_class
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
########################################################################
|
|
45
|
+
|
|
46
|
+
def executor
|
|
47
|
+
@executor ||= resolve_executor(@version_factory.executor.executor)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
########################################################################
|
|
51
|
+
|
|
52
|
+
def resolve_executor(executor) # rubocop:disable Metrics/MethodLength
|
|
53
|
+
return executor if executor.is_a?(Proc) || executor.is_a?(Class)
|
|
54
|
+
|
|
55
|
+
if executor.is_a?(String) || executor.is_a?(Symbol)
|
|
56
|
+
string_executor = executor.to_s
|
|
57
|
+
|
|
58
|
+
if string_executor.empty?
|
|
59
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
60
|
+
raise Treaty::Exceptions::Execution,
|
|
61
|
+
"Executor cannot be an empty string"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
constant_name = normalize_constant_name(executor)
|
|
65
|
+
|
|
66
|
+
begin
|
|
67
|
+
constant_name.constantize
|
|
68
|
+
rescue NameError
|
|
69
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
70
|
+
raise Treaty::Exceptions::Execution,
|
|
71
|
+
"Executor class `#{constant_name}` not found"
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
75
|
+
raise Treaty::Exceptions::Execution,
|
|
76
|
+
"Invalid executor type: #{executor.class}. " \
|
|
77
|
+
"Expected Proc, Class, String, or Symbol"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
########################################################################
|
|
82
|
+
|
|
83
|
+
def normalize_constant_name(name)
|
|
84
|
+
string = name.to_s
|
|
85
|
+
|
|
86
|
+
return string if string.include?("::")
|
|
87
|
+
return string.split("/").map(&:camelize).join("::") if string.include?("/")
|
|
88
|
+
|
|
89
|
+
string
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
########################################################################
|
|
93
|
+
########################################################################
|
|
94
|
+
########################################################################
|
|
95
|
+
|
|
96
|
+
def execute_proc
|
|
97
|
+
executor.call(params: @validated_params)
|
|
98
|
+
rescue StandardError => e
|
|
99
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
100
|
+
raise Treaty::Exceptions::Execution, e.message
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def execute_servactory
|
|
104
|
+
executor.call!(params: @validated_params)
|
|
105
|
+
rescue ApplicationService::Exceptions::Input => e
|
|
106
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
107
|
+
raise Treaty::Exceptions::Execution, e.message
|
|
108
|
+
rescue ApplicationService::Exceptions::Internal => e # rubocop:disable Lint/DuplicateBranch
|
|
109
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
110
|
+
raise Treaty::Exceptions::Execution, e.message
|
|
111
|
+
rescue ApplicationService::Exceptions::Output => e # rubocop:disable Lint/DuplicateBranch
|
|
112
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
113
|
+
raise Treaty::Exceptions::Execution, e.message
|
|
114
|
+
rescue ApplicationService::Exceptions::Failure => e # rubocop:disable Lint/DuplicateBranch
|
|
115
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
116
|
+
raise Treaty::Exceptions::Execution, e.message
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def execute_regular_class
|
|
120
|
+
method_name = @version_factory.executor.method
|
|
121
|
+
|
|
122
|
+
unless executor.respond_to?(method_name)
|
|
123
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
124
|
+
raise Treaty::Exceptions::Execution,
|
|
125
|
+
"Method '#{method_name}' not found in class '#{executor}'"
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
executor.public_send(method_name, params: @validated_params)
|
|
129
|
+
rescue StandardError => e
|
|
130
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
131
|
+
raise Treaty::Exceptions::Execution, e.message
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
########################################################################
|
|
135
|
+
########################################################################
|
|
136
|
+
########################################################################
|
|
137
|
+
|
|
138
|
+
def raise_executor_missing_error!
|
|
139
|
+
# TODO: It is necessary to implement a translation system (I18n).
|
|
140
|
+
raise Treaty::Exceptions::Execution,
|
|
141
|
+
"Executor is not defined for version #{@version_factory.version}"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def servactory_service?
|
|
145
|
+
executor.respond_to?(:servactory?) &&
|
|
146
|
+
executor.servactory?
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|