treaty 0.0.1 → 0.2.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +106 -17
  3. data/Rakefile +4 -2
  4. data/config/locales/en.yml +96 -0
  5. data/lib/treaty/attribute/base.rb +174 -0
  6. data/lib/treaty/attribute/builder/base.rb +143 -0
  7. data/lib/treaty/attribute/collection.rb +65 -0
  8. data/lib/treaty/attribute/helper_mapper.rb +72 -0
  9. data/lib/treaty/attribute/option/base.rb +160 -0
  10. data/lib/treaty/attribute/option/modifiers/as_modifier.rb +88 -0
  11. data/lib/treaty/attribute/option/modifiers/default_modifier.rb +103 -0
  12. data/lib/treaty/attribute/option/registry.rb +128 -0
  13. data/lib/treaty/attribute/option/registry_initializer.rb +90 -0
  14. data/lib/treaty/attribute/option/validators/inclusion_validator.rb +80 -0
  15. data/lib/treaty/attribute/option/validators/required_validator.rb +92 -0
  16. data/lib/treaty/attribute/option/validators/type_validator.rb +159 -0
  17. data/lib/treaty/attribute/option_normalizer.rb +151 -0
  18. data/lib/treaty/attribute/option_orchestrator.rb +187 -0
  19. data/lib/treaty/attribute/validation/attribute_validator.rb +144 -0
  20. data/lib/treaty/attribute/validation/base.rb +92 -0
  21. data/lib/treaty/attribute/validation/nested_array_validator.rb +199 -0
  22. data/lib/treaty/attribute/validation/nested_object_validator.rb +103 -0
  23. data/lib/treaty/attribute/validation/nested_transformer.rb +246 -0
  24. data/lib/treaty/attribute/validation/orchestrator/base.rb +194 -0
  25. data/lib/treaty/base.rb +9 -0
  26. data/lib/treaty/configuration.rb +17 -0
  27. data/lib/treaty/context/callable.rb +24 -0
  28. data/lib/treaty/context/dsl.rb +12 -0
  29. data/lib/treaty/context/workspace.rb +28 -0
  30. data/lib/treaty/controller/dsl.rb +38 -0
  31. data/lib/treaty/engine.rb +37 -0
  32. data/lib/treaty/exceptions/base.rb +47 -0
  33. data/lib/treaty/exceptions/class_name.rb +50 -0
  34. data/lib/treaty/exceptions/deprecated.rb +54 -0
  35. data/lib/treaty/exceptions/execution.rb +66 -0
  36. data/lib/treaty/exceptions/method_name.rb +55 -0
  37. data/lib/treaty/exceptions/nested_attributes.rb +65 -0
  38. data/lib/treaty/exceptions/not_implemented.rb +32 -0
  39. data/lib/treaty/exceptions/strategy.rb +63 -0
  40. data/lib/treaty/exceptions/unexpected.rb +70 -0
  41. data/lib/treaty/exceptions/validation.rb +97 -0
  42. data/lib/treaty/info/builder.rb +122 -0
  43. data/lib/treaty/info/dsl.rb +26 -0
  44. data/lib/treaty/info/result.rb +13 -0
  45. data/lib/treaty/request/attribute/attribute.rb +24 -0
  46. data/lib/treaty/request/attribute/builder.rb +22 -0
  47. data/lib/treaty/request/attribute/validation/orchestrator.rb +27 -0
  48. data/lib/treaty/request/attribute/validator.rb +50 -0
  49. data/lib/treaty/request/factory.rb +32 -0
  50. data/lib/treaty/request/scope/collection.rb +21 -0
  51. data/lib/treaty/request/scope/factory.rb +42 -0
  52. data/lib/treaty/response/attribute/attribute.rb +24 -0
  53. data/lib/treaty/response/attribute/builder.rb +22 -0
  54. data/lib/treaty/response/attribute/validation/orchestrator.rb +27 -0
  55. data/lib/treaty/response/attribute/validator.rb +44 -0
  56. data/lib/treaty/response/factory.rb +38 -0
  57. data/lib/treaty/response/scope/collection.rb +21 -0
  58. data/lib/treaty/response/scope/factory.rb +42 -0
  59. data/lib/treaty/result.rb +22 -0
  60. data/lib/treaty/strategy.rb +31 -0
  61. data/lib/treaty/support/loader.rb +24 -0
  62. data/lib/treaty/version.rb +8 -1
  63. data/lib/treaty/versions/collection.rb +15 -0
  64. data/lib/treaty/versions/dsl.rb +30 -0
  65. data/lib/treaty/versions/execution/request.rb +147 -0
  66. data/lib/treaty/versions/executor.rb +14 -0
  67. data/lib/treaty/versions/factory.rb +92 -0
  68. data/lib/treaty/versions/resolver.rb +69 -0
  69. data/lib/treaty/versions/semantic.rb +22 -0
  70. data/lib/treaty/versions/workspace.rb +40 -0
  71. data/lib/treaty.rb +3 -3
  72. metadata +200 -27
  73. data/.standard.yml +0 -3
  74. data/CHANGELOG.md +0 -5
  75. data/CODE_OF_CONDUCT.md +0 -84
  76. data/LICENSE.txt +0 -21
  77. data/sig/treaty.rbs +0 -4
  78. data/treaty.gemspec +0 -35
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Info
5
+ class Result
6
+ attr_reader :versions
7
+
8
+ def initialize(builder)
9
+ @versions = builder.versions
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Request
5
+ module Attribute
6
+ class Attribute < Treaty::Attribute::Base
7
+ private
8
+
9
+ def apply_defaults!
10
+ # For request: required by default (true).
11
+ # message: nil means use I18n default message from validators
12
+ @options[:required] ||= { is: true, 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 Request
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 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
+ # message: nil means use I18n default message from validators
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
+ raise Treaty::Exceptions::Strategy,
20
+ I18n.t("treaty.versioning.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
@@ -1,5 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Treaty
4
- VERSION = "0.0.1"
4
+ module VERSION
5
+ MAJOR = 0
6
+ MINOR = 2
7
+ PATCH = 0
8
+ PRE = nil
9
+
10
+ STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
11
+ end
5
12
  end
@@ -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