treaty 0.19.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/treaty/action/base.rb +11 -0
  4. data/lib/treaty/action/context/callable.rb +90 -0
  5. data/lib/treaty/action/context/dsl.rb +56 -0
  6. data/lib/treaty/action/context/workspace.rb +92 -0
  7. data/lib/treaty/action/executor/inventory.rb +136 -0
  8. data/lib/treaty/{info/rest → action/info}/builder.rb +2 -2
  9. data/lib/treaty/{info/rest → action/info}/dsl.rb +2 -2
  10. data/lib/treaty/{info/rest → action/info}/result.rb +2 -2
  11. data/lib/treaty/action/inventory/collection.rb +77 -0
  12. data/lib/treaty/action/inventory/factory.rb +108 -0
  13. data/lib/treaty/action/inventory/inventory.rb +146 -0
  14. data/lib/treaty/action/request/attribute/attribute.rb +76 -0
  15. data/lib/treaty/action/request/attribute/builder.rb +98 -0
  16. data/lib/treaty/action/request/entity.rb +78 -0
  17. data/lib/treaty/action/request/factory.rb +116 -0
  18. data/lib/treaty/action/request/validator.rb +120 -0
  19. data/lib/treaty/action/response/attribute/attribute.rb +79 -0
  20. data/lib/treaty/action/response/attribute/builder.rb +96 -0
  21. data/lib/treaty/action/response/entity.rb +79 -0
  22. data/lib/treaty/action/response/factory.rb +129 -0
  23. data/lib/treaty/action/response/validator.rb +111 -0
  24. data/lib/treaty/action/result.rb +81 -0
  25. data/lib/treaty/action/versions/collection.rb +47 -0
  26. data/lib/treaty/action/versions/dsl.rb +116 -0
  27. data/lib/treaty/action/versions/execution/request.rb +287 -0
  28. data/lib/treaty/action/versions/executor.rb +61 -0
  29. data/lib/treaty/action/versions/factory.rb +253 -0
  30. data/lib/treaty/action/versions/resolver.rb +150 -0
  31. data/lib/treaty/action/versions/semantic.rb +64 -0
  32. data/lib/treaty/action/versions/workspace.rb +106 -0
  33. data/lib/treaty/action.rb +31 -0
  34. data/lib/treaty/controller/dsl.rb +1 -1
  35. data/lib/treaty/entity/attribute/base.rb +1 -1
  36. data/lib/treaty/entity/attribute/builder/base.rb +1 -1
  37. data/lib/treaty/entity/attribute/dsl.rb +1 -1
  38. data/lib/treaty/entity/base.rb +1 -1
  39. data/lib/treaty/entity/builder.rb +62 -5
  40. data/lib/treaty/version.rb +1 -1
  41. metadata +32 -31
  42. data/lib/treaty/base.rb +0 -9
  43. data/lib/treaty/context/callable.rb +0 -26
  44. data/lib/treaty/context/dsl.rb +0 -12
  45. data/lib/treaty/context/workspace.rb +0 -32
  46. data/lib/treaty/executor/inventory.rb +0 -122
  47. data/lib/treaty/inventory/collection.rb +0 -71
  48. data/lib/treaty/inventory/factory.rb +0 -91
  49. data/lib/treaty/inventory/inventory.rb +0 -92
  50. data/lib/treaty/request/attribute/attribute.rb +0 -25
  51. data/lib/treaty/request/attribute/builder.rb +0 -46
  52. data/lib/treaty/request/entity.rb +0 -33
  53. data/lib/treaty/request/factory.rb +0 -81
  54. data/lib/treaty/request/validator.rb +0 -60
  55. data/lib/treaty/response/attribute/attribute.rb +0 -25
  56. data/lib/treaty/response/attribute/builder.rb +0 -46
  57. data/lib/treaty/response/entity.rb +0 -33
  58. data/lib/treaty/response/factory.rb +0 -87
  59. data/lib/treaty/response/validator.rb +0 -53
  60. data/lib/treaty/result.rb +0 -23
  61. data/lib/treaty/versions/collection.rb +0 -15
  62. data/lib/treaty/versions/dsl.rb +0 -42
  63. data/lib/treaty/versions/execution/request.rb +0 -177
  64. data/lib/treaty/versions/executor.rb +0 -14
  65. data/lib/treaty/versions/factory.rb +0 -112
  66. data/lib/treaty/versions/resolver.rb +0 -70
  67. data/lib/treaty/versions/semantic.rb +0 -22
  68. data/lib/treaty/versions/workspace.rb +0 -43
@@ -2,10 +2,64 @@
2
2
 
3
3
  module Treaty
4
4
  module Entity
5
- # Entity-specific attribute builder
5
+ # DSL builder for defining entity attributes.
6
+ #
7
+ # ## Purpose
8
+ #
9
+ # Provides Entity-specific implementation of the attribute builder.
10
+ # Creates Entity::Attribute::Attribute instances with **required by default**
11
+ # behavior (unlike Request/Response which have different defaults).
12
+ #
13
+ # ## Inheritance
14
+ #
15
+ # Extends Treaty::Entity::Attribute::Builder::Base which provides:
16
+ # - DSL interface (string, integer, object, array, etc.)
17
+ # - method_missing magic for type-based method calls
18
+ # - Helper support (:required, :optional)
19
+ # - Entity reuse via use_entity
20
+ #
21
+ # ## Usage
22
+ #
23
+ # Used internally by:
24
+ # - Entity::Attribute::Attribute (when processing nested object/array blocks)
25
+ #
26
+ # ## Default Behavior
27
+ #
28
+ # Entity attributes default to **required: true**, meaning all fields
29
+ # must be present unless explicitly marked `:optional`.
30
+ #
31
+ # ## DSL Example
32
+ #
33
+ # class UserEntity < Treaty::Entity::Base
34
+ # object :user do
35
+ # string :id # required by default
36
+ # string :name # required by default
37
+ # string :bio, :optional # explicitly optional
38
+ # object :profile do
39
+ # string :avatar_url
40
+ # end
41
+ # end
42
+ # end
43
+ #
44
+ # ## Methods
45
+ #
46
+ # Implements abstract methods from base class:
47
+ # - `create_attribute` - Creates Entity::Attribute::Attribute
48
+ # - `deep_copy_attribute` - Deep copies attribute for use_entity support
6
49
  class Builder < Treaty::Entity::Attribute::Builder::Base
7
50
  private
8
51
 
52
+ # Creates a new entity attribute instance
53
+ #
54
+ # Called by base class when defining attributes via DSL.
55
+ #
56
+ # @param name [Symbol] Attribute name
57
+ # @param type [Symbol] Attribute type (:string, :integer, :object, etc.)
58
+ # @param helpers [Array<Symbol>] Helper symbols (:required, :optional)
59
+ # @param nesting_level [Integer] Current nesting depth
60
+ # @param options [Hash] Attribute options (default:, format:, etc.)
61
+ # @param block [Proc] Block for nested attributes (object/array)
62
+ # @return [Treaty::Entity::Attribute::Attribute] Created attribute instance
9
63
  def create_attribute(name, type, *helpers, nesting_level:, **options, &block)
10
64
  Treaty::Entity::Attribute::Attribute.new(
11
65
  name,
@@ -17,11 +71,14 @@ module Treaty
17
71
  )
18
72
  end
19
73
 
20
- # Deep copies an attribute with adjusted nesting level for Entity context.
74
+ # Deep copies an attribute with adjusted nesting level
75
+ #
76
+ # Used when copying attributes from other Entity classes via use_entity.
77
+ # Recursively copies nested attributes for object/array types.
21
78
  #
22
- # @param source_attribute [Treaty::Entity::Attribute::Base] Attribute to copy
23
- # @param new_nesting_level [Integer] New nesting level
24
- # @return [Treaty::Entity::Attribute::Attribute] Copied attribute
79
+ # @param source_attribute [Treaty::Entity::Attribute::Base] Source attribute to copy
80
+ # @param new_nesting_level [Integer] Nesting level for copied attribute
81
+ # @return [Treaty::Entity::Attribute::Attribute] Deep copied attribute
25
82
  def deep_copy_attribute(source_attribute, new_nesting_level) # rubocop:disable Metrics/MethodLength
26
83
  copied = Treaty::Entity::Attribute::Attribute.new(
27
84
  source_attribute.name,
@@ -3,7 +3,7 @@
3
3
  module Treaty
4
4
  module VERSION
5
5
  MAJOR = 0
6
- MINOR = 19
6
+ MINOR = 20
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: treaty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.0
4
+ version: 0.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Sokolov
@@ -147,11 +147,38 @@ files:
147
147
  - Rakefile
148
148
  - config/locales/en.yml
149
149
  - lib/treaty.rb
150
- - lib/treaty/base.rb
150
+ - lib/treaty/action.rb
151
+ - lib/treaty/action/base.rb
152
+ - lib/treaty/action/context/callable.rb
153
+ - lib/treaty/action/context/dsl.rb
154
+ - lib/treaty/action/context/workspace.rb
155
+ - lib/treaty/action/executor/inventory.rb
156
+ - lib/treaty/action/info/builder.rb
157
+ - lib/treaty/action/info/dsl.rb
158
+ - lib/treaty/action/info/result.rb
159
+ - lib/treaty/action/inventory/collection.rb
160
+ - lib/treaty/action/inventory/factory.rb
161
+ - lib/treaty/action/inventory/inventory.rb
162
+ - lib/treaty/action/request/attribute/attribute.rb
163
+ - lib/treaty/action/request/attribute/builder.rb
164
+ - lib/treaty/action/request/entity.rb
165
+ - lib/treaty/action/request/factory.rb
166
+ - lib/treaty/action/request/validator.rb
167
+ - lib/treaty/action/response/attribute/attribute.rb
168
+ - lib/treaty/action/response/attribute/builder.rb
169
+ - lib/treaty/action/response/entity.rb
170
+ - lib/treaty/action/response/factory.rb
171
+ - lib/treaty/action/response/validator.rb
172
+ - lib/treaty/action/result.rb
173
+ - lib/treaty/action/versions/collection.rb
174
+ - lib/treaty/action/versions/dsl.rb
175
+ - lib/treaty/action/versions/execution/request.rb
176
+ - lib/treaty/action/versions/executor.rb
177
+ - lib/treaty/action/versions/factory.rb
178
+ - lib/treaty/action/versions/resolver.rb
179
+ - lib/treaty/action/versions/semantic.rb
180
+ - lib/treaty/action/versions/workspace.rb
151
181
  - lib/treaty/configuration.rb
152
- - lib/treaty/context/callable.rb
153
- - lib/treaty/context/dsl.rb
154
- - lib/treaty/context/workspace.rb
155
182
  - lib/treaty/controller/dsl.rb
156
183
  - lib/treaty/engine.rb
157
184
  - lib/treaty/entity.rb
@@ -203,34 +230,8 @@ files:
203
230
  - lib/treaty/exceptions/version_default_deprecated_conflict.rb
204
231
  - lib/treaty/exceptions/version_multiple_defaults.rb
205
232
  - lib/treaty/exceptions/version_not_found.rb
206
- - lib/treaty/executor/inventory.rb
207
- - lib/treaty/info/rest/builder.rb
208
- - lib/treaty/info/rest/dsl.rb
209
- - lib/treaty/info/rest/result.rb
210
- - lib/treaty/inventory/collection.rb
211
- - lib/treaty/inventory/factory.rb
212
- - lib/treaty/inventory/inventory.rb
213
- - lib/treaty/request/attribute/attribute.rb
214
- - lib/treaty/request/attribute/builder.rb
215
- - lib/treaty/request/entity.rb
216
- - lib/treaty/request/factory.rb
217
- - lib/treaty/request/validator.rb
218
- - lib/treaty/response/attribute/attribute.rb
219
- - lib/treaty/response/attribute/builder.rb
220
- - lib/treaty/response/entity.rb
221
- - lib/treaty/response/factory.rb
222
- - lib/treaty/response/validator.rb
223
- - lib/treaty/result.rb
224
233
  - lib/treaty/support/loader.rb
225
234
  - lib/treaty/version.rb
226
- - lib/treaty/versions/collection.rb
227
- - lib/treaty/versions/dsl.rb
228
- - lib/treaty/versions/execution/request.rb
229
- - lib/treaty/versions/executor.rb
230
- - lib/treaty/versions/factory.rb
231
- - lib/treaty/versions/resolver.rb
232
- - lib/treaty/versions/semantic.rb
233
- - lib/treaty/versions/workspace.rb
234
235
  homepage: https://github.com/servactory/treaty
235
236
  licenses:
236
237
  - MIT
data/lib/treaty/base.rb DELETED
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- class Base
5
- include Info::Rest::DSL
6
- include Context::DSL
7
- include Versions::DSL
8
- end
9
- end
@@ -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
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Context
5
- module DSL
6
- def self.included(base)
7
- base.extend(Callable)
8
- base.include(Workspace)
9
- end
10
- end
11
- end
12
- end
@@ -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::Entity::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