treaty 0.18.0 → 0.20.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 +1 -1
- data/config/locales/en.yml +3 -3
- data/lib/treaty/action/base.rb +11 -0
- data/lib/treaty/action/context/callable.rb +90 -0
- data/lib/treaty/action/context/dsl.rb +56 -0
- data/lib/treaty/action/context/workspace.rb +92 -0
- data/lib/treaty/action/executor/inventory.rb +136 -0
- data/lib/treaty/{info/rest → action/info}/builder.rb +2 -2
- data/lib/treaty/{info/rest → action/info}/dsl.rb +2 -2
- data/lib/treaty/{info/rest → action/info}/result.rb +2 -2
- data/lib/treaty/action/inventory/collection.rb +77 -0
- data/lib/treaty/action/inventory/factory.rb +108 -0
- data/lib/treaty/action/inventory/inventory.rb +146 -0
- data/lib/treaty/action/request/attribute/attribute.rb +76 -0
- data/lib/treaty/action/request/attribute/builder.rb +98 -0
- data/lib/treaty/action/request/entity.rb +78 -0
- data/lib/treaty/action/request/factory.rb +116 -0
- data/lib/treaty/action/request/validator.rb +120 -0
- data/lib/treaty/action/response/attribute/attribute.rb +79 -0
- data/lib/treaty/action/response/attribute/builder.rb +96 -0
- data/lib/treaty/action/response/entity.rb +79 -0
- data/lib/treaty/action/response/factory.rb +129 -0
- data/lib/treaty/action/response/validator.rb +111 -0
- data/lib/treaty/action/result.rb +81 -0
- data/lib/treaty/action/versions/collection.rb +47 -0
- data/lib/treaty/action/versions/dsl.rb +116 -0
- data/lib/treaty/action/versions/execution/request.rb +287 -0
- data/lib/treaty/action/versions/executor.rb +61 -0
- data/lib/treaty/action/versions/factory.rb +253 -0
- data/lib/treaty/action/versions/resolver.rb +150 -0
- data/lib/treaty/action/versions/semantic.rb +64 -0
- data/lib/treaty/action/versions/workspace.rb +106 -0
- data/lib/treaty/action.rb +31 -0
- data/lib/treaty/controller/dsl.rb +1 -1
- data/lib/treaty/engine.rb +1 -1
- data/lib/treaty/{attribute/entity → entity/attribute}/attribute.rb +4 -4
- data/lib/treaty/entity/attribute/base.rb +184 -0
- data/lib/treaty/entity/attribute/builder/base.rb +275 -0
- data/lib/treaty/entity/attribute/collection.rb +67 -0
- data/lib/treaty/entity/attribute/dsl.rb +92 -0
- data/lib/treaty/entity/attribute/helper_mapper.rb +74 -0
- data/lib/treaty/entity/attribute/option/base.rb +190 -0
- data/lib/treaty/entity/attribute/option/conditionals/base.rb +92 -0
- data/lib/treaty/entity/attribute/option/conditionals/if_conditional.rb +136 -0
- data/lib/treaty/entity/attribute/option/conditionals/unless_conditional.rb +153 -0
- data/lib/treaty/entity/attribute/option/modifiers/as_modifier.rb +93 -0
- data/lib/treaty/entity/attribute/option/modifiers/cast_modifier.rb +285 -0
- data/lib/treaty/entity/attribute/option/modifiers/computed_modifier.rb +128 -0
- data/lib/treaty/entity/attribute/option/modifiers/default_modifier.rb +105 -0
- data/lib/treaty/entity/attribute/option/modifiers/transform_modifier.rb +114 -0
- data/lib/treaty/entity/attribute/option/registry.rb +157 -0
- data/lib/treaty/entity/attribute/option/registry_initializer.rb +117 -0
- data/lib/treaty/entity/attribute/option/validators/format_validator.rb +222 -0
- data/lib/treaty/entity/attribute/option/validators/inclusion_validator.rb +94 -0
- data/lib/treaty/entity/attribute/option/validators/required_validator.rb +100 -0
- data/lib/treaty/entity/attribute/option/validators/type_validator.rb +219 -0
- data/lib/treaty/entity/attribute/option_normalizer.rb +168 -0
- data/lib/treaty/entity/attribute/option_orchestrator.rb +192 -0
- data/lib/treaty/entity/attribute/validation/attribute_validator.rb +147 -0
- data/lib/treaty/entity/attribute/validation/base.rb +76 -0
- data/lib/treaty/entity/attribute/validation/nested_array_validator.rb +207 -0
- data/lib/treaty/entity/attribute/validation/nested_object_validator.rb +105 -0
- data/lib/treaty/entity/attribute/validation/nested_transformer.rb +432 -0
- data/lib/treaty/entity/attribute/validation/orchestrator/base.rb +262 -0
- data/lib/treaty/entity/base.rb +90 -0
- data/lib/treaty/entity/builder.rb +101 -0
- data/lib/treaty/{info/entity → entity/info}/builder.rb +8 -8
- data/lib/treaty/{info/entity → entity/info}/dsl.rb +2 -2
- data/lib/treaty/{info/entity → entity/info}/result.rb +2 -2
- data/lib/treaty/entity.rb +7 -79
- data/lib/treaty/version.rb +1 -1
- metadata +66 -64
- data/lib/treaty/attribute/base.rb +0 -182
- data/lib/treaty/attribute/builder/base.rb +0 -273
- data/lib/treaty/attribute/collection.rb +0 -65
- data/lib/treaty/attribute/dsl.rb +0 -90
- data/lib/treaty/attribute/entity/builder.rb +0 -46
- data/lib/treaty/attribute/helper_mapper.rb +0 -72
- data/lib/treaty/attribute/option/base.rb +0 -188
- data/lib/treaty/attribute/option/conditionals/base.rb +0 -90
- data/lib/treaty/attribute/option/conditionals/if_conditional.rb +0 -134
- data/lib/treaty/attribute/option/conditionals/unless_conditional.rb +0 -151
- data/lib/treaty/attribute/option/modifiers/as_modifier.rb +0 -91
- data/lib/treaty/attribute/option/modifiers/cast_modifier.rb +0 -283
- data/lib/treaty/attribute/option/modifiers/computed_modifier.rb +0 -126
- data/lib/treaty/attribute/option/modifiers/default_modifier.rb +0 -103
- data/lib/treaty/attribute/option/modifiers/transform_modifier.rb +0 -112
- data/lib/treaty/attribute/option/registry.rb +0 -155
- data/lib/treaty/attribute/option/registry_initializer.rb +0 -115
- data/lib/treaty/attribute/option/validators/format_validator.rb +0 -220
- data/lib/treaty/attribute/option/validators/inclusion_validator.rb +0 -92
- data/lib/treaty/attribute/option/validators/required_validator.rb +0 -98
- data/lib/treaty/attribute/option/validators/type_validator.rb +0 -217
- data/lib/treaty/attribute/option_normalizer.rb +0 -166
- data/lib/treaty/attribute/option_orchestrator.rb +0 -190
- data/lib/treaty/attribute/validation/attribute_validator.rb +0 -145
- data/lib/treaty/attribute/validation/base.rb +0 -74
- data/lib/treaty/attribute/validation/nested_array_validator.rb +0 -205
- data/lib/treaty/attribute/validation/nested_object_validator.rb +0 -103
- data/lib/treaty/attribute/validation/nested_transformer.rb +0 -430
- data/lib/treaty/attribute/validation/orchestrator/base.rb +0 -260
- data/lib/treaty/base.rb +0 -9
- data/lib/treaty/context/callable.rb +0 -26
- data/lib/treaty/context/dsl.rb +0 -12
- data/lib/treaty/context/workspace.rb +0 -32
- data/lib/treaty/executor/inventory.rb +0 -122
- data/lib/treaty/inventory/collection.rb +0 -71
- data/lib/treaty/inventory/factory.rb +0 -91
- data/lib/treaty/inventory/inventory.rb +0 -92
- data/lib/treaty/request/attribute/attribute.rb +0 -25
- data/lib/treaty/request/attribute/builder.rb +0 -46
- data/lib/treaty/request/entity.rb +0 -33
- data/lib/treaty/request/factory.rb +0 -81
- data/lib/treaty/request/validator.rb +0 -60
- data/lib/treaty/response/attribute/attribute.rb +0 -25
- data/lib/treaty/response/attribute/builder.rb +0 -46
- data/lib/treaty/response/entity.rb +0 -33
- data/lib/treaty/response/factory.rb +0 -87
- data/lib/treaty/response/validator.rb +0 -53
- data/lib/treaty/result.rb +0 -23
- data/lib/treaty/versions/collection.rb +0 -15
- data/lib/treaty/versions/dsl.rb +0 -42
- data/lib/treaty/versions/execution/request.rb +0 -177
- data/lib/treaty/versions/executor.rb +0 -14
- data/lib/treaty/versions/factory.rb +0 -112
- data/lib/treaty/versions/resolver.rb +0 -70
- data/lib/treaty/versions/semantic.rb +0 -22
- data/lib/treaty/versions/workspace.rb +0 -43
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Context
|
|
5
|
-
module Callable
|
|
6
|
-
def call!(version:, params:, context: nil, inventory: nil)
|
|
7
|
-
treaty_instance = send(:new)
|
|
8
|
-
|
|
9
|
-
_call!(treaty_instance, context:, inventory:, version:, params:)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
def _call!(treaty_instance, context:, inventory:, version:, params:)
|
|
15
|
-
treaty_instance.send(
|
|
16
|
-
:_call!,
|
|
17
|
-
context:,
|
|
18
|
-
inventory:,
|
|
19
|
-
version:,
|
|
20
|
-
params:,
|
|
21
|
-
collection_of_versions:
|
|
22
|
-
)
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
data/lib/treaty/context/dsl.rb
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Context
|
|
5
|
-
module Workspace
|
|
6
|
-
private
|
|
7
|
-
|
|
8
|
-
def _call!(
|
|
9
|
-
context:,
|
|
10
|
-
inventory:,
|
|
11
|
-
version:,
|
|
12
|
-
params:,
|
|
13
|
-
collection_of_versions:
|
|
14
|
-
)
|
|
15
|
-
call!(
|
|
16
|
-
context:,
|
|
17
|
-
inventory:,
|
|
18
|
-
version:,
|
|
19
|
-
params:,
|
|
20
|
-
collection_of_versions:
|
|
21
|
-
)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def call!(
|
|
25
|
-
collection_of_versions:,
|
|
26
|
-
**
|
|
27
|
-
)
|
|
28
|
-
@collection_of_versions = collection_of_versions
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Executor
|
|
5
|
-
# Inventory wrapper that provides method-based access to inventory items.
|
|
6
|
-
#
|
|
7
|
-
# ## Purpose
|
|
8
|
-
#
|
|
9
|
-
# Wraps inventory collection and controller context, providing lazy evaluation
|
|
10
|
-
# of inventory items through method calls. This encapsulates all inventory logic
|
|
11
|
-
# within the class and provides a clean API for services.
|
|
12
|
-
#
|
|
13
|
-
# ## Usage
|
|
14
|
-
#
|
|
15
|
-
# ```ruby
|
|
16
|
-
# # Created internally by Treaty
|
|
17
|
-
# inventory = Treaty::Executor::Inventory.new(inventory_collection, controller_context)
|
|
18
|
-
#
|
|
19
|
-
# # Access via method calls - evaluates lazily
|
|
20
|
-
# inventory.posts # => Calls controller method or evaluates proc
|
|
21
|
-
# inventory.current_user # => Returns evaluated value
|
|
22
|
-
#
|
|
23
|
-
# # Raises exception for missing items
|
|
24
|
-
# inventory.missing_item # => Treaty::Exceptions::Inventory
|
|
25
|
-
#
|
|
26
|
-
# # Convert to hash - evaluates all items
|
|
27
|
-
# inventory.to_h # => { posts: [...], current_user: ... }
|
|
28
|
-
# ```
|
|
29
|
-
#
|
|
30
|
-
# ## Architecture
|
|
31
|
-
#
|
|
32
|
-
# The class encapsulates:
|
|
33
|
-
# - Inventory collection (from controller's treaty block)
|
|
34
|
-
# - Controller context (for method calls and proc evaluation)
|
|
35
|
-
# - Lazy evaluation logic (items evaluated on access)
|
|
36
|
-
#
|
|
37
|
-
# ## Error Handling
|
|
38
|
-
#
|
|
39
|
-
# If an inventory item is not found, raises `Treaty::Exceptions::Inventory` with
|
|
40
|
-
# an I18n-translated error message listing available items.
|
|
41
|
-
class Inventory
|
|
42
|
-
# Creates a new inventory instance
|
|
43
|
-
#
|
|
44
|
-
# @param inventory [Treaty::Inventory::Collection] Collection of inventory items
|
|
45
|
-
# @param context [Object] Controller instance for evaluation
|
|
46
|
-
def initialize(inventory, context)
|
|
47
|
-
@inventory = inventory
|
|
48
|
-
@context = context
|
|
49
|
-
@evaluated_cache = {}
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Provides method-based access to inventory items with lazy evaluation
|
|
53
|
-
#
|
|
54
|
-
# @param method_name [Symbol] The inventory item name
|
|
55
|
-
# @param _args [Array] Arguments (not used, for compatibility)
|
|
56
|
-
# @return [Object] The evaluated inventory item value
|
|
57
|
-
# @raise [Treaty::Exceptions::Inventory] If item not found
|
|
58
|
-
def method_missing(method_name, *_args)
|
|
59
|
-
# Check cache first
|
|
60
|
-
return @evaluated_cache[method_name] if @evaluated_cache.key?(method_name)
|
|
61
|
-
|
|
62
|
-
# Find inventory item
|
|
63
|
-
item = find_inventory_item(method_name)
|
|
64
|
-
|
|
65
|
-
# Evaluate and cache
|
|
66
|
-
@evaluated_cache[method_name] = item.evaluate(@context)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# Checks if inventory responds to a method
|
|
70
|
-
#
|
|
71
|
-
# @param method_name [Symbol] The method name to check
|
|
72
|
-
# @param include_private [Boolean] Whether to include private methods
|
|
73
|
-
# @return [Boolean] True if inventory has the item
|
|
74
|
-
def respond_to_missing?(method_name, include_private = false)
|
|
75
|
-
return false if @inventory.nil?
|
|
76
|
-
|
|
77
|
-
@inventory.names.include?(method_name) || super
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# Converts inventory to hash, evaluating all items
|
|
81
|
-
#
|
|
82
|
-
# @return [Hash] Hash of all evaluated inventory items
|
|
83
|
-
def to_h
|
|
84
|
-
return {} if @inventory.nil?
|
|
85
|
-
|
|
86
|
-
@inventory.evaluate(@context)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Returns string representation
|
|
90
|
-
#
|
|
91
|
-
# @return [String] Inventory description
|
|
92
|
-
def inspect
|
|
93
|
-
items = @inventory&.names || []
|
|
94
|
-
"#<Treaty::Executor::Inventory items=#{items.inspect}>"
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
private
|
|
98
|
-
|
|
99
|
-
# Finds inventory item by name
|
|
100
|
-
#
|
|
101
|
-
# @param name [Symbol] Inventory item name
|
|
102
|
-
# @return [Treaty::Inventory::Inventory] The inventory item
|
|
103
|
-
# @raise [Treaty::Exceptions::Inventory] If not found or inventory is nil
|
|
104
|
-
def find_inventory_item(name)
|
|
105
|
-
# Use find method for cleaner search
|
|
106
|
-
item = @inventory&.find { |item| item.name == name }
|
|
107
|
-
|
|
108
|
-
return item if item
|
|
109
|
-
|
|
110
|
-
# Item not found - list available items
|
|
111
|
-
available = @inventory&.names || []
|
|
112
|
-
|
|
113
|
-
raise Treaty::Exceptions::Inventory,
|
|
114
|
-
I18n.t(
|
|
115
|
-
"treaty.executor.inventory.item_not_found",
|
|
116
|
-
name:,
|
|
117
|
-
available: available.join(", ")
|
|
118
|
-
)
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
end
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Inventory
|
|
5
|
-
# Collection wrapper for sets of inventory items.
|
|
6
|
-
#
|
|
7
|
-
# ## Purpose
|
|
8
|
-
#
|
|
9
|
-
# Provides a unified interface for working with collections of inventory items.
|
|
10
|
-
# Uses Ruby Set internally for uniqueness but exposes Array-like interface.
|
|
11
|
-
#
|
|
12
|
-
# ## Usage
|
|
13
|
-
#
|
|
14
|
-
# Used internally by:
|
|
15
|
-
# - Inventory::Factory (to store inventory items during DSL processing)
|
|
16
|
-
#
|
|
17
|
-
# ## Methods
|
|
18
|
-
#
|
|
19
|
-
# Delegates common collection methods to internal Set:
|
|
20
|
-
# - `<<` - Add inventory item
|
|
21
|
-
# - `empty?` - Check if collection is empty
|
|
22
|
-
#
|
|
23
|
-
# Custom methods:
|
|
24
|
-
# - `exists?` - Returns true if collection is not empty
|
|
25
|
-
# - `evaluate` - Evaluates all inventory items with context
|
|
26
|
-
#
|
|
27
|
-
# ## Example
|
|
28
|
-
#
|
|
29
|
-
# collection = Collection.new
|
|
30
|
-
# collection << Inventory.new(name: :posts, source: :load_posts)
|
|
31
|
-
# collection << Inventory.new(name: :meta, source: -> { { count: 10 } })
|
|
32
|
-
# collection.size # => 2
|
|
33
|
-
# collection.exists? # => true
|
|
34
|
-
class Collection
|
|
35
|
-
extend Forwardable
|
|
36
|
-
|
|
37
|
-
def_delegators :@collection, :<<, :each_with_object, :find, :empty?
|
|
38
|
-
|
|
39
|
-
# Creates a new collection instance
|
|
40
|
-
#
|
|
41
|
-
# @param collection [Set] Initial collection (default: empty Set)
|
|
42
|
-
def initialize(collection = Set.new)
|
|
43
|
-
@collection = collection
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Checks if collection has any elements
|
|
47
|
-
#
|
|
48
|
-
# @return [Boolean] True if collection is not empty
|
|
49
|
-
def exists?
|
|
50
|
-
!empty?
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
# Returns array of all inventory item names
|
|
54
|
-
#
|
|
55
|
-
# @return [Array<Symbol>] Array of inventory item names
|
|
56
|
-
def names
|
|
57
|
-
@collection.each_with_object([]) { |item, names| names << item.name }
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Evaluates all inventory items with the given context
|
|
61
|
-
#
|
|
62
|
-
# @param context [Object] The controller instance to call methods on
|
|
63
|
-
# @return [Hash{Symbol => Object}] Hash of inventory name => resolved value
|
|
64
|
-
def evaluate(context)
|
|
65
|
-
@collection.each_with_object({}) do |inventory_item, hash|
|
|
66
|
-
hash[inventory_item.name] = inventory_item.evaluate(context)
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Inventory
|
|
5
|
-
# Factory for building inventory collections via DSL.
|
|
6
|
-
#
|
|
7
|
-
# ## Purpose
|
|
8
|
-
#
|
|
9
|
-
# Provides the `provide` DSL method for defining inventory items in controller blocks.
|
|
10
|
-
# Captures calls like `provide :posts, from: :load_posts` and builds a collection.
|
|
11
|
-
#
|
|
12
|
-
# ## Usage
|
|
13
|
-
#
|
|
14
|
-
# Used internally by Controller::DSL when processing treaty blocks:
|
|
15
|
-
#
|
|
16
|
-
# ```ruby
|
|
17
|
-
# treaty :index do
|
|
18
|
-
# provide :posts, from: :load_posts # Explicit source
|
|
19
|
-
# provide :meta, from: -> { { count: 10 } } # Lambda source
|
|
20
|
-
# provide :current_user # Shorthand: uses :current_user as source
|
|
21
|
-
# end
|
|
22
|
-
# ```
|
|
23
|
-
#
|
|
24
|
-
# ## Valid Sources
|
|
25
|
-
#
|
|
26
|
-
# - Symbol: Method name to call on controller (e.g., `:load_posts`)
|
|
27
|
-
# - Proc/Lambda: Callable object (e.g., `-> { Post.all }`)
|
|
28
|
-
# - Direct value: String, number, or any other value (e.g., `"Welcome"`)
|
|
29
|
-
# - Omitted: Uses inventory name as source (e.g., `provide :posts` → `from: :posts`)
|
|
30
|
-
#
|
|
31
|
-
# ## Invalid Sources
|
|
32
|
-
#
|
|
33
|
-
# - Direct method calls without symbol/proc (e.g., `from: load_posts`)
|
|
34
|
-
# - Explicit nil values (e.g., `from: nil`)
|
|
35
|
-
class Factory
|
|
36
|
-
attr_reader :collection
|
|
37
|
-
|
|
38
|
-
def initialize(action_name)
|
|
39
|
-
@action_name = action_name
|
|
40
|
-
@collection = Collection.new
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Handles the `provide` DSL method via method_missing
|
|
44
|
-
#
|
|
45
|
-
# @param method_name [Symbol] Should be :provide
|
|
46
|
-
# @param args [Array] First argument is the inventory name
|
|
47
|
-
# @param options [Hash] Optional :from key with source (defaults to inventory name)
|
|
48
|
-
# @return [Collection] The collection being built
|
|
49
|
-
# @raise [Treaty::Exceptions::Inventory] For invalid method or missing parameters
|
|
50
|
-
def method_missing(method_name, *args, **options, &_block) # rubocop:disable Metrics/MethodLength
|
|
51
|
-
# Only handle 'provide' method
|
|
52
|
-
unless method_name == :provide
|
|
53
|
-
raise Treaty::Exceptions::Inventory,
|
|
54
|
-
I18n.t(
|
|
55
|
-
"treaty.inventory.unknown_method",
|
|
56
|
-
method: method_name,
|
|
57
|
-
action: @action_name
|
|
58
|
-
)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Extract inventory name
|
|
62
|
-
inventory_name = args.first
|
|
63
|
-
|
|
64
|
-
unless inventory_name.is_a?(Symbol)
|
|
65
|
-
raise Treaty::Exceptions::Inventory,
|
|
66
|
-
I18n.t(
|
|
67
|
-
"treaty.inventory.name_must_be_symbol",
|
|
68
|
-
name: inventory_name.inspect
|
|
69
|
-
)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# Extract source from options (default to inventory name if not provided)
|
|
73
|
-
source = if options.key?(:from)
|
|
74
|
-
options.fetch(:from)
|
|
75
|
-
else
|
|
76
|
-
inventory_name
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# Create and add inventory item to collection
|
|
80
|
-
@collection << Inventory.new(name: inventory_name, source:)
|
|
81
|
-
|
|
82
|
-
# Return collection for potential chaining
|
|
83
|
-
@collection
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def respond_to_missing?(method_name, *)
|
|
87
|
-
method_name == :provide || super
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Inventory
|
|
5
|
-
# Represents a single inventory item that provides data to the treaty execution.
|
|
6
|
-
#
|
|
7
|
-
# An inventory item has a name and a source. The source can be:
|
|
8
|
-
# - Symbol: A method name to call on the controller (e.g., :load_posts)
|
|
9
|
-
# - Proc/Lambda: A callable object (e.g., -> { Post.all })
|
|
10
|
-
# - Direct value: Any other value to pass directly (e.g., "text", 42)
|
|
11
|
-
#
|
|
12
|
-
# ## Usage
|
|
13
|
-
#
|
|
14
|
-
# ```ruby
|
|
15
|
-
# # In controller
|
|
16
|
-
# treaty :index do
|
|
17
|
-
# provide :posts, from: :load_posts
|
|
18
|
-
# provide :meta, from: -> { { count: 10 } }
|
|
19
|
-
# provide :title, from: "Welcome"
|
|
20
|
-
# end
|
|
21
|
-
# ```
|
|
22
|
-
class Inventory
|
|
23
|
-
attr_reader :name, :source
|
|
24
|
-
|
|
25
|
-
def initialize(name:, source:)
|
|
26
|
-
validate_name!(name)
|
|
27
|
-
validate_source!(source)
|
|
28
|
-
|
|
29
|
-
@name = name
|
|
30
|
-
@source = source
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Evaluates the inventory source with the given context
|
|
34
|
-
#
|
|
35
|
-
# @param context [Object] The controller instance to call methods on
|
|
36
|
-
# @return [Object] The resolved value
|
|
37
|
-
# @raise [Treaty::Exceptions::Inventory] If evaluation fails
|
|
38
|
-
def evaluate(context) # rubocop:disable Metrics/MethodLength
|
|
39
|
-
case source
|
|
40
|
-
when Symbol
|
|
41
|
-
evaluate_symbol(context)
|
|
42
|
-
when Proc
|
|
43
|
-
evaluate_proc(context)
|
|
44
|
-
else
|
|
45
|
-
source
|
|
46
|
-
end
|
|
47
|
-
rescue StandardError => e
|
|
48
|
-
raise Treaty::Exceptions::Inventory,
|
|
49
|
-
I18n.t(
|
|
50
|
-
"treaty.inventory.evaluation_error",
|
|
51
|
-
name: @name,
|
|
52
|
-
error: e.message
|
|
53
|
-
)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
private
|
|
57
|
-
|
|
58
|
-
# Evaluates Symbol source by calling method on context
|
|
59
|
-
#
|
|
60
|
-
# @param context [Object] The controller instance
|
|
61
|
-
# @return [Object] The method return value
|
|
62
|
-
def evaluate_symbol(context)
|
|
63
|
-
context.send(source)
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
# Evaluates Proc source within controller context
|
|
67
|
-
#
|
|
68
|
-
# @param context [Object] The controller instance
|
|
69
|
-
# @return [Object] The proc return value
|
|
70
|
-
def evaluate_proc(context)
|
|
71
|
-
# Execute proc in controller context to access instance variables and methods
|
|
72
|
-
context.instance_exec(&source)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def validate_name!(name)
|
|
76
|
-
return if name.is_a?(Symbol) && !name.to_s.empty?
|
|
77
|
-
|
|
78
|
-
raise Treaty::Exceptions::Inventory,
|
|
79
|
-
I18n.t("treaty.inventory.invalid_name", name: name.inspect)
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def validate_source!(source)
|
|
83
|
-
# Source must be Symbol, Proc, or any other direct value
|
|
84
|
-
# We don't allow nil as it's likely a mistake
|
|
85
|
-
return unless source.nil?
|
|
86
|
-
|
|
87
|
-
raise Treaty::Exceptions::Inventory,
|
|
88
|
-
I18n.t("treaty.inventory.source_required")
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
end
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Request
|
|
5
|
-
module Attribute
|
|
6
|
-
# Request-specific attribute that defaults to required: true
|
|
7
|
-
class Attribute < Treaty::Attribute::Base
|
|
8
|
-
private
|
|
9
|
-
|
|
10
|
-
def apply_defaults!
|
|
11
|
-
# For request: required by default (true).
|
|
12
|
-
# message: nil means use I18n default message from validators
|
|
13
|
-
@options[:required] ||= { is: true, message: nil }
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def process_nested_attributes(&block)
|
|
17
|
-
return unless object_or_array?
|
|
18
|
-
|
|
19
|
-
builder = Builder.new(collection_of_attributes, @nesting_level + 1)
|
|
20
|
-
builder.instance_eval(&block)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Request
|
|
5
|
-
module Attribute
|
|
6
|
-
# Request-specific attribute builder
|
|
7
|
-
class Builder < Treaty::Attribute::Builder::Base
|
|
8
|
-
private
|
|
9
|
-
|
|
10
|
-
def create_attribute(name, type, *helpers, nesting_level:, **options, &block)
|
|
11
|
-
Attribute.new(
|
|
12
|
-
name,
|
|
13
|
-
type,
|
|
14
|
-
*helpers,
|
|
15
|
-
nesting_level:,
|
|
16
|
-
**options,
|
|
17
|
-
&block
|
|
18
|
-
)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
# Deep copies an attribute with adjusted nesting level for Request context.
|
|
22
|
-
#
|
|
23
|
-
# @param source_attribute [Treaty::Attribute::Base] Attribute to copy
|
|
24
|
-
# @param new_nesting_level [Integer] New nesting level
|
|
25
|
-
# @return [Request::Attribute::Attribute] Copied attribute
|
|
26
|
-
def deep_copy_attribute(source_attribute, new_nesting_level) # rubocop:disable Metrics/MethodLength
|
|
27
|
-
copied = Attribute.new(
|
|
28
|
-
source_attribute.name,
|
|
29
|
-
source_attribute.type,
|
|
30
|
-
nesting_level: new_nesting_level,
|
|
31
|
-
**deep_copy_options(source_attribute.options)
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
return copied unless source_attribute.nested?
|
|
35
|
-
|
|
36
|
-
source_attribute.collection_of_attributes.each do |nested_source|
|
|
37
|
-
nested_copied = deep_copy_attribute(nested_source, new_nesting_level + 1)
|
|
38
|
-
copied.collection_of_attributes << nested_copied
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
copied
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Request
|
|
5
|
-
# Entity class for request definitions.
|
|
6
|
-
# Attributes are required by default.
|
|
7
|
-
#
|
|
8
|
-
# This class is used internally when defining request blocks.
|
|
9
|
-
# When you write a request block, Treaty creates an anonymous
|
|
10
|
-
# class based on Request::Entity.
|
|
11
|
-
class Entity
|
|
12
|
-
include Treaty::Attribute::DSL
|
|
13
|
-
|
|
14
|
-
class << self
|
|
15
|
-
private
|
|
16
|
-
|
|
17
|
-
# Creates a Request::Attribute::Attribute for this Request::Entity class
|
|
18
|
-
#
|
|
19
|
-
# @return [Request::Attribute::Attribute] Created attribute instance
|
|
20
|
-
def create_attribute(name, type, *helpers, nesting_level:, **options, &block)
|
|
21
|
-
Attribute::Attribute.new(
|
|
22
|
-
name,
|
|
23
|
-
type,
|
|
24
|
-
*helpers,
|
|
25
|
-
nesting_level:,
|
|
26
|
-
**options,
|
|
27
|
-
&block
|
|
28
|
-
)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Request
|
|
5
|
-
# Factory for creating request definitions.
|
|
6
|
-
#
|
|
7
|
-
# Supports two modes:
|
|
8
|
-
# 1. Block mode: Creates an anonymous Request::Entity class with the block
|
|
9
|
-
# 2. Entity mode: Uses a provided Entity class directly
|
|
10
|
-
#
|
|
11
|
-
# ## Block Mode
|
|
12
|
-
#
|
|
13
|
-
# ```ruby
|
|
14
|
-
# request do
|
|
15
|
-
# object :post do
|
|
16
|
-
# string :title
|
|
17
|
-
# end
|
|
18
|
-
# end
|
|
19
|
-
# ```
|
|
20
|
-
#
|
|
21
|
-
# ## Entity Mode
|
|
22
|
-
#
|
|
23
|
-
# ```ruby
|
|
24
|
-
# request Posts::Create::RequestEntity
|
|
25
|
-
# ```
|
|
26
|
-
class Factory
|
|
27
|
-
# Uses a provided Entity class
|
|
28
|
-
#
|
|
29
|
-
# @param entity_class [Class] Entity class to use
|
|
30
|
-
# @return [void]
|
|
31
|
-
# @raise [Treaty::Exceptions::Validation] if entity_class is not a valid Treaty::Entity subclass
|
|
32
|
-
def use_entity(entity_class)
|
|
33
|
-
validate_entity_class!(entity_class)
|
|
34
|
-
@entity_class = entity_class
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Returns collection of attributes from the entity class
|
|
38
|
-
#
|
|
39
|
-
# @return [Collection] Collection of attributes
|
|
40
|
-
def collection_of_attributes
|
|
41
|
-
return Treaty::Attribute::Collection.new if @entity_class.nil?
|
|
42
|
-
|
|
43
|
-
@entity_class.collection_of_attributes
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Handles DSL methods for defining attributes
|
|
47
|
-
#
|
|
48
|
-
# This allows the factory to be used with method_missing
|
|
49
|
-
# for backwards compatibility with direct method calls.
|
|
50
|
-
# Creates an anonymous Request::Entity class on first use.
|
|
51
|
-
def method_missing(type, *helpers, **options, &block)
|
|
52
|
-
# If no entity class yet, create one
|
|
53
|
-
@entity_class ||= Class.new(Entity)
|
|
54
|
-
|
|
55
|
-
# Call the method on the entity class
|
|
56
|
-
@entity_class.public_send(type, *helpers, **options, &block)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def respond_to_missing?(name, *)
|
|
60
|
-
super
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
private
|
|
64
|
-
|
|
65
|
-
# Validates that the provided entity_class is a valid Treaty::Entity subclass
|
|
66
|
-
#
|
|
67
|
-
# @param entity_class [Class] Entity class to validate
|
|
68
|
-
# @raise [Treaty::Exceptions::Validation] if entity_class is not a valid Treaty::Entity subclass
|
|
69
|
-
def validate_entity_class!(entity_class)
|
|
70
|
-
return if entity_class.is_a?(Class) && entity_class < Treaty::Entity
|
|
71
|
-
|
|
72
|
-
raise Treaty::Exceptions::Validation,
|
|
73
|
-
I18n.t(
|
|
74
|
-
"treaty.request.factory.invalid_entity_class",
|
|
75
|
-
type: entity_class.class,
|
|
76
|
-
value: entity_class
|
|
77
|
-
)
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Treaty
|
|
4
|
-
module Request
|
|
5
|
-
# Validator for request data
|
|
6
|
-
class Validator
|
|
7
|
-
class << self
|
|
8
|
-
# Validates request parameters against the request definition
|
|
9
|
-
#
|
|
10
|
-
# @param params [Hash] Request parameters to validate
|
|
11
|
-
# @param version_factory [Versions::Factory] Version factory with request definition
|
|
12
|
-
# @return [Hash] Validated and transformed parameters
|
|
13
|
-
def validate!(params:, version_factory:)
|
|
14
|
-
new(params:, version_factory:).validate!
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def initialize(params:, version_factory:)
|
|
19
|
-
@params = params
|
|
20
|
-
@version_factory = version_factory
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def validate!
|
|
24
|
-
validate_request_attributes!
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
def request_data
|
|
30
|
-
@request_data ||= begin
|
|
31
|
-
@params.to_unsafe_h
|
|
32
|
-
rescue NoMethodError
|
|
33
|
-
@params
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def validate_request_attributes!
|
|
38
|
-
return request_data unless request_attributes_exist?
|
|
39
|
-
|
|
40
|
-
# Validate request attributes with orchestrator:
|
|
41
|
-
orchestrator_class = Class.new(Treaty::Attribute::Validation::Orchestrator::Base) do
|
|
42
|
-
define_method(:collection_of_attributes) do
|
|
43
|
-
@version_factory.request_factory.collection_of_attributes
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
orchestrator_class.validate!(
|
|
48
|
-
version_factory: @version_factory,
|
|
49
|
-
data: request_data
|
|
50
|
-
)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def request_attributes_exist?
|
|
54
|
-
return false if @version_factory.request_factory&.collection_of_attributes&.empty?
|
|
55
|
-
|
|
56
|
-
@version_factory.request_factory.collection_of_attributes.exists?
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|