treaty 0.17.0 → 0.19.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/locales/en.yml +6 -2
  4. data/lib/treaty/engine.rb +1 -1
  5. data/lib/treaty/{attribute/entity → entity/attribute}/attribute.rb +4 -4
  6. data/lib/treaty/entity/attribute/base.rb +184 -0
  7. data/lib/treaty/entity/attribute/builder/base.rb +275 -0
  8. data/lib/treaty/entity/attribute/collection.rb +67 -0
  9. data/lib/treaty/entity/attribute/dsl.rb +92 -0
  10. data/lib/treaty/entity/attribute/helper_mapper.rb +74 -0
  11. data/lib/treaty/entity/attribute/option/base.rb +190 -0
  12. data/lib/treaty/entity/attribute/option/conditionals/base.rb +92 -0
  13. data/lib/treaty/entity/attribute/option/conditionals/if_conditional.rb +136 -0
  14. data/lib/treaty/entity/attribute/option/conditionals/unless_conditional.rb +153 -0
  15. data/lib/treaty/entity/attribute/option/modifiers/as_modifier.rb +93 -0
  16. data/lib/treaty/entity/attribute/option/modifiers/cast_modifier.rb +285 -0
  17. data/lib/treaty/entity/attribute/option/modifiers/computed_modifier.rb +128 -0
  18. data/lib/treaty/entity/attribute/option/modifiers/default_modifier.rb +105 -0
  19. data/lib/treaty/entity/attribute/option/modifiers/transform_modifier.rb +114 -0
  20. data/lib/treaty/entity/attribute/option/registry.rb +157 -0
  21. data/lib/treaty/entity/attribute/option/registry_initializer.rb +117 -0
  22. data/lib/treaty/entity/attribute/option/validators/format_validator.rb +222 -0
  23. data/lib/treaty/entity/attribute/option/validators/inclusion_validator.rb +94 -0
  24. data/lib/treaty/entity/attribute/option/validators/required_validator.rb +100 -0
  25. data/lib/treaty/entity/attribute/option/validators/type_validator.rb +219 -0
  26. data/lib/treaty/entity/attribute/option_normalizer.rb +168 -0
  27. data/lib/treaty/entity/attribute/option_orchestrator.rb +192 -0
  28. data/lib/treaty/entity/attribute/validation/attribute_validator.rb +147 -0
  29. data/lib/treaty/entity/attribute/validation/base.rb +76 -0
  30. data/lib/treaty/entity/attribute/validation/nested_array_validator.rb +207 -0
  31. data/lib/treaty/entity/attribute/validation/nested_object_validator.rb +105 -0
  32. data/lib/treaty/entity/attribute/validation/nested_transformer.rb +432 -0
  33. data/lib/treaty/entity/attribute/validation/orchestrator/base.rb +262 -0
  34. data/lib/treaty/entity/base.rb +90 -0
  35. data/lib/treaty/entity/builder.rb +44 -0
  36. data/lib/treaty/{info/entity → entity/info}/builder.rb +8 -8
  37. data/lib/treaty/{info/entity → entity/info}/dsl.rb +2 -2
  38. data/lib/treaty/{info/entity → entity/info}/result.rb +2 -2
  39. data/lib/treaty/entity.rb +7 -75
  40. data/lib/treaty/request/attribute/attribute.rb +1 -1
  41. data/lib/treaty/request/attribute/builder.rb +24 -1
  42. data/lib/treaty/request/entity.rb +1 -1
  43. data/lib/treaty/request/factory.rb +6 -6
  44. data/lib/treaty/request/validator.rb +1 -1
  45. data/lib/treaty/response/attribute/attribute.rb +1 -1
  46. data/lib/treaty/response/attribute/builder.rb +24 -1
  47. data/lib/treaty/response/entity.rb +1 -1
  48. data/lib/treaty/response/factory.rb +6 -6
  49. data/lib/treaty/response/validator.rb +1 -1
  50. data/lib/treaty/version.rb +1 -1
  51. metadata +35 -34
  52. data/lib/treaty/attribute/base.rb +0 -182
  53. data/lib/treaty/attribute/builder/base.rb +0 -143
  54. data/lib/treaty/attribute/collection.rb +0 -65
  55. data/lib/treaty/attribute/dsl.rb +0 -90
  56. data/lib/treaty/attribute/entity/builder.rb +0 -23
  57. data/lib/treaty/attribute/helper_mapper.rb +0 -72
  58. data/lib/treaty/attribute/option/base.rb +0 -188
  59. data/lib/treaty/attribute/option/conditionals/base.rb +0 -90
  60. data/lib/treaty/attribute/option/conditionals/if_conditional.rb +0 -134
  61. data/lib/treaty/attribute/option/conditionals/unless_conditional.rb +0 -151
  62. data/lib/treaty/attribute/option/modifiers/as_modifier.rb +0 -91
  63. data/lib/treaty/attribute/option/modifiers/cast_modifier.rb +0 -283
  64. data/lib/treaty/attribute/option/modifiers/computed_modifier.rb +0 -126
  65. data/lib/treaty/attribute/option/modifiers/default_modifier.rb +0 -103
  66. data/lib/treaty/attribute/option/modifiers/transform_modifier.rb +0 -112
  67. data/lib/treaty/attribute/option/registry.rb +0 -155
  68. data/lib/treaty/attribute/option/registry_initializer.rb +0 -115
  69. data/lib/treaty/attribute/option/validators/format_validator.rb +0 -220
  70. data/lib/treaty/attribute/option/validators/inclusion_validator.rb +0 -92
  71. data/lib/treaty/attribute/option/validators/required_validator.rb +0 -98
  72. data/lib/treaty/attribute/option/validators/type_validator.rb +0 -217
  73. data/lib/treaty/attribute/option_normalizer.rb +0 -166
  74. data/lib/treaty/attribute/option_orchestrator.rb +0 -190
  75. data/lib/treaty/attribute/validation/attribute_validator.rb +0 -145
  76. data/lib/treaty/attribute/validation/base.rb +0 -74
  77. data/lib/treaty/attribute/validation/nested_array_validator.rb +0 -205
  78. data/lib/treaty/attribute/validation/nested_object_validator.rb +0 -103
  79. data/lib/treaty/attribute/validation/nested_transformer.rb +0 -430
  80. data/lib/treaty/attribute/validation/orchestrator/base.rb +0 -260
@@ -1,182 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- # Base class for all attribute definitions in Treaty DSL.
6
- #
7
- # ## Purpose
8
- #
9
- # Represents a single attribute defined in request/response definitions.
10
- # Handles:
11
- # - Attribute metadata (name, type, nesting level)
12
- # - Helper mode to simple mode conversion
13
- # - Simple mode to advanced mode normalization
14
- # - Nested attributes (for object and array types)
15
- #
16
- # ## Usage
17
- #
18
- # Attributes are created through DSL methods:
19
- # string :title, :required
20
- # integer :age, default: 18
21
- # object :author do
22
- # string :name
23
- # end
24
- #
25
- # ## Processing Flow
26
- #
27
- # 1. Extract helpers from arguments (`:required`, `:optional`)
28
- # 2. Convert helpers to simple mode options
29
- # 3. Merge with explicit options
30
- # 4. Normalize all options to advanced mode
31
- # 5. Apply defaults (required: true for request, false for response)
32
- # 6. Process nested attributes if block given
33
- #
34
- # ## Nested Attributes
35
- #
36
- # Object and array types can have nested attributes:
37
- # - `object` - nested attributes as direct children
38
- # - `array` - nested attributes define array element structure
39
- #
40
- # Special attribute name `:_self` is used for simple arrays:
41
- # array :tags do
42
- # string :_self # Array of strings
43
- # end
44
- class Base
45
- attr_reader :name,
46
- :type,
47
- :options,
48
- :nesting_level
49
-
50
- # Creates a new attribute instance
51
- #
52
- # @param name [Symbol] The attribute name
53
- # @param type [Symbol] The attribute type (:string, :integer, :object, :array, etc.)
54
- # @param helpers [Array<Symbol>] Helper symbols (:required, :optional)
55
- # @param nesting_level [Integer] Current nesting depth (default: 0)
56
- # @param options [Hash] Attribute options (required, default, as, etc.)
57
- # @param block [Proc] Block for defining nested attributes (for object/array types)
58
- def initialize(name, type, *helpers, nesting_level: 0, **options, &block)
59
- @name = name
60
- @type = type
61
- @nesting_level = nesting_level
62
-
63
- validate_nesting_level!
64
-
65
- # Separate helpers from non-helper symbols.
66
- @helpers = extract_helpers(helpers)
67
-
68
- # Merge helper options with explicit options.
69
- merged_options = merge_options(@helpers, options)
70
-
71
- # Normalize all options to advanced mode.
72
- @options = OptionNormalizer.normalize(merged_options)
73
-
74
- apply_defaults!
75
-
76
- # Process nested attributes for object and array types.
77
- process_nested_attributes(&block) if block_given?
78
- end
79
-
80
- # Returns collection of nested attributes for this attribute
81
- #
82
- # @return [Collection] Collection of nested attributes
83
- def collection_of_attributes
84
- @collection_of_attributes ||= Collection.new
85
- end
86
-
87
- # Checks if this attribute has nested attributes
88
- #
89
- # @return [Boolean] True if attribute is object/array with nested attributes
90
- def nested?
91
- object_or_array? && collection_of_attributes.exists?
92
- end
93
-
94
- # Checks if this attribute is an object or array type
95
- #
96
- # @return [Boolean] True if type is :object or :array
97
- def object_or_array?
98
- object? || array?
99
- end
100
-
101
- # Checks if this attribute is an object type
102
- #
103
- # @return [Boolean] True if type is :object
104
- def object?
105
- @type == :object
106
- end
107
-
108
- # Checks if this attribute is an array type
109
- #
110
- # @return [Boolean] True if type is :array
111
- def array?
112
- @type == :array
113
- end
114
-
115
- private
116
-
117
- # Validates that nesting level doesn't exceed maximum allowed depth
118
- #
119
- # @raise [Treaty::Exceptions::NestedAttributes] If nesting exceeds limit
120
- # @return [void]
121
- def validate_nesting_level!
122
- return unless @nesting_level > Treaty::Engine.config.treaty.attribute_nesting_level
123
-
124
- raise Treaty::Exceptions::NestedAttributes,
125
- I18n.t(
126
- "treaty.attributes.errors.nesting_level_exceeded",
127
- level: @nesting_level,
128
- max_level: Treaty::Engine.config.treaty.attribute_nesting_level
129
- )
130
- end
131
-
132
- # Extracts helper symbols from arguments
133
- #
134
- # @param helpers [Array] Mixed array that may contain helper symbols
135
- # @return [Array<Symbol>] Filtered array of valid helper symbols
136
- def extract_helpers(helpers)
137
- helpers.select do |helper|
138
- helper.is_a?(Symbol) && HelperMapper.helper?(helper)
139
- end
140
- end
141
-
142
- # Merges helper-derived options with explicit options
143
- #
144
- # @param helpers [Array<Symbol>] Helper symbols to convert
145
- # @param explicit_options [Hash] Explicitly provided options
146
- # @return [Hash] Merged options hash
147
- def merge_options(helpers, explicit_options)
148
- helper_options = HelperMapper.map(helpers)
149
- helper_options.merge(explicit_options)
150
- end
151
-
152
- # Applies default values for options based on context (request/response)
153
- # Must be implemented in subclasses
154
- #
155
- # @raise [Treaty::Exceptions::NotImplemented] If subclass doesn't implement
156
- # @return [void]
157
- def apply_defaults!
158
- # Must be implemented in subclasses
159
- raise Treaty::Exceptions::NotImplemented,
160
- I18n.t(
161
- "treaty.attributes.errors.apply_defaults_not_implemented",
162
- class: self.class
163
- )
164
- end
165
-
166
- # Processes nested attributes block for object/array types
167
- # Must be implemented in subclasses
168
- #
169
- # @param block [Proc] Block containing nested attribute definitions
170
- # @raise [Treaty::Exceptions::NotImplemented] If subclass doesn't implement
171
- # @return [void]
172
- def process_nested_attributes
173
- # Must be implemented in subclasses
174
- raise Treaty::Exceptions::NotImplemented,
175
- I18n.t(
176
- "treaty.attributes.errors.process_nested_not_implemented",
177
- class: self.class
178
- )
179
- end
180
- end
181
- end
182
- end
@@ -1,143 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- module Builder
6
- # Base DSL builder for defining attributes in request/response definitions.
7
- #
8
- # ## Purpose
9
- #
10
- # Provides the DSL interface for defining attributes within objects.
11
- # Handles method_missing magic to support type-based method calls.
12
- #
13
- # ## Responsibilities
14
- #
15
- # 1. **DSL Interface** - Provides clean syntax for attribute definitions
16
- # 2. **Method Dispatch** - Routes type methods (string, integer, etc.) to attribute creation
17
- # 3. **Helper Support** - Handles helper symbols in various positions
18
- # 4. **Nesting Tracking** - Tracks nesting level for nested attributes
19
- #
20
- # ## DSL Usage
21
- #
22
- # The builder enables this clean DSL syntax:
23
- #
24
- # ```ruby
25
- # request do
26
- # object :user do
27
- # string :name
28
- # integer :age, default: 18
29
- # object :profile do
30
- # string :bio
31
- # end
32
- # end
33
- # end
34
- # ```
35
- #
36
- # ## Method Dispatch
37
- #
38
- # ### Type-based Methods
39
- # When you call `string :name`, it routes through `method_missing`:
40
- # 1. `string` becomes the type
41
- # 2. `:name` becomes the attribute name
42
- # 3. Calls `attribute(:name, :string, ...)`
43
- #
44
- # ### Helper Position Handling
45
- # Handles helpers in different positions:
46
- #
47
- # ```ruby
48
- # string :required, :name # Helper first, then name
49
- # string :name, :required # Name first, then helper
50
- # ```
51
- #
52
- # Both resolve to the same attribute definition.
53
- #
54
- # ## Nesting
55
- #
56
- # Tracks nesting level for:
57
- # - Validation (enforcing maximum nesting depth)
58
- # - Error messages (showing context)
59
- #
60
- # Maximum nesting level is configured in Treaty::Engine.config.
61
- #
62
- # ## Subclass Requirements
63
- #
64
- # Subclasses must implement:
65
- # - `create_attribute` - Creates the appropriate attribute type (Request/Response)
66
- #
67
- # ## Architecture
68
- #
69
- # Used by:
70
- # - Request::Builder - For request attribute definitions
71
- # - Response::Builder - For response attribute definitions
72
- class Base
73
- attr_reader :nesting_level,
74
- :collection_of_attributes
75
-
76
- # Creates a new builder instance
77
- #
78
- # @param collection_of_attributes [Collection] Collection to add attributes to
79
- # @param nesting_level [Integer] Current nesting depth
80
- def initialize(collection_of_attributes, nesting_level)
81
- @collection_of_attributes = collection_of_attributes
82
- @nesting_level = nesting_level
83
- end
84
-
85
- # Defines an attribute with explicit type
86
- #
87
- # @param name [Symbol] The attribute name
88
- # @param type [Symbol] The attribute type
89
- # @param helpers [Array<Symbol>] Helper symbols (:required, :optional)
90
- # @param options [Hash] Attribute options
91
- # @param block [Proc] Block for nested attributes
92
- # @return [void]
93
- def attribute(name, type, *helpers, **options, &block)
94
- @collection_of_attributes << create_attribute(
95
- name,
96
- type,
97
- *helpers,
98
- nesting_level: @nesting_level,
99
- **options,
100
- &block
101
- )
102
- end
103
-
104
- # Handles DSL methods like `string :name` where method name is the type
105
- #
106
- # @param type [Symbol] The attribute type (method name)
107
- # @param name [Symbol] The attribute name (first argument)
108
- # @param helpers [Array<Symbol>] Helper symbols
109
- # @param options [Hash] Attribute options
110
- # @param block [Proc] Block for nested attributes
111
- # @return [void]
112
- def method_missing(type, name, *helpers, **options, &block)
113
- if name.is_a?(Symbol) && HelperMapper.helper?(name)
114
- helpers.unshift(name)
115
- name = helpers.shift
116
- end
117
-
118
- attribute(name, type, *helpers, **options, &block)
119
- end
120
-
121
- # Checks if method should be handled by method_missing
122
- #
123
- # @param name [Symbol] Method name
124
- # @return [Boolean]
125
- def respond_to_missing?(name, *)
126
- super
127
- end
128
-
129
- private
130
-
131
- # Creates an attribute instance (must be implemented in subclasses)
132
- #
133
- # @raise [Treaty::Exceptions::NotImplemented] If subclass doesn't implement
134
- # @return [Attribute::Base] Created attribute instance
135
- def create_attribute(*)
136
- # Must be implemented in subclasses
137
- raise Treaty::Exceptions::NotImplemented,
138
- I18n.t("treaty.attributes.builder.not_implemented", class: self.class)
139
- end
140
- end
141
- end
142
- end
143
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "forwardable"
4
-
5
- module Treaty
6
- module Attribute
7
- # Collection wrapper for sets of attributes.
8
- #
9
- # ## Purpose
10
- #
11
- # Provides a unified interface for working with collections of attributes.
12
- # Uses Ruby Set internally for uniqueness but exposes Array-like interface.
13
- #
14
- # ## Usage
15
- #
16
- # Used internally by:
17
- # - Request/Response factories (to store attributes)
18
- # - Attribute::Base (to store nested attributes)
19
- #
20
- # ## Methods
21
- #
22
- # Delegates common collection methods to internal Set:
23
- # - `<<` - Add attribute
24
- # - `each`, `map`, `select`, `reject` - Iteration
25
- # - `find`, `first` - Access
26
- # - `size`, `empty?` - Size checks
27
- # - `to_h` - Convert to hash
28
- #
29
- # Custom methods:
30
- # - `exists?` - Returns true if collection is not empty
31
- #
32
- # ## Example
33
- #
34
- # collection = Collection.new
35
- # collection << Attribute::Base.new(:name, :string)
36
- # collection << Attribute::Base.new(:age, :integer)
37
- # collection.size # => 2
38
- # collection.exists? # => true
39
- class Collection
40
- extend Forwardable
41
-
42
- def_delegators :@collection,
43
- :<<,
44
- :to_h, :map,
45
- :each_with_object, :each,
46
- :select, :reject, :size,
47
- :find, :first,
48
- :empty?
49
-
50
- # Creates a new collection instance
51
- #
52
- # @param collection [Set] Initial collection (default: empty Set)
53
- def initialize(collection = Set.new)
54
- @collection = collection
55
- end
56
-
57
- # Checks if collection has any elements
58
- #
59
- # @return [Boolean] True if collection is not empty
60
- def exists?
61
- !empty?
62
- end
63
- end
64
- end
65
- end
@@ -1,90 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- # DSL module for defining attributes in Entity-like classes.
6
- #
7
- # This module provides the class-level DSL for defining attributes.
8
- # It can be included in any class that needs attribute definition capabilities.
9
- #
10
- # ## Usage
11
- #
12
- # ```ruby
13
- # class MyEntity
14
- # include Treaty::Attribute::DSL
15
- #
16
- # string :name
17
- # integer :age
18
- # end
19
- # ```
20
- module DSL
21
- def self.included(base)
22
- base.extend(ClassMethods)
23
- end
24
-
25
- module ClassMethods
26
- # Defines an attribute with explicit type
27
- #
28
- # @param name [Symbol] The attribute name
29
- # @param type [Symbol] The attribute type
30
- # @param helpers [Array<Symbol>] Helper symbols (:required, :optional)
31
- # @param options [Hash] Attribute options
32
- # @param block [Proc] Block for nested attributes
33
- # @return [void]
34
- def attribute(name, type, *helpers, **options, &block)
35
- collection_of_attributes << create_attribute(
36
- name,
37
- type,
38
- *helpers,
39
- nesting_level: 0,
40
- **options,
41
- &block
42
- )
43
- end
44
-
45
- # Returns collection of attributes for this class
46
- #
47
- # @return [Collection] Collection of attributes
48
- def collection_of_attributes
49
- @collection_of_attributes ||= Treaty::Attribute::Collection.new
50
- end
51
-
52
- # Handles DSL methods like `string :name` where method name is the type
53
- #
54
- # @param type [Symbol] The attribute type (method name)
55
- # @param name [Symbol] The attribute name (first argument)
56
- # @param helpers [Array<Symbol>] Helper symbols
57
- # @param options [Hash] Attribute options
58
- # @param block [Proc] Block for nested attributes
59
- # @return [void]
60
- def method_missing(type, *helpers, **options, &block)
61
- name = helpers.shift
62
-
63
- # If no attribute name provided, this is not an attribute definition
64
- # Pass to super to handle it properly (e.g., for methods like 'info', 'call!', etc.)
65
- return super if name.nil?
66
-
67
- attribute(name, type, *helpers, **options, &block)
68
- end
69
-
70
- def respond_to_missing?(name, *)
71
- super
72
- end
73
-
74
- private
75
-
76
- # Creates an attribute instance (must be implemented by including class)
77
- #
78
- # @raise [Treaty::Exceptions::NotImplemented] If not implemented
79
- # @return [Attribute::Base] Created attribute instance
80
- def create_attribute(*)
81
- raise Treaty::Exceptions::NotImplemented,
82
- I18n.t(
83
- "treaty.attributes.dsl.create_attribute_not_implemented",
84
- class: self
85
- )
86
- end
87
- end
88
- end
89
- end
90
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- module Entity
6
- # Entity-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
- end
21
- end
22
- end
23
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- # Maps DSL helper symbols to their simple mode option equivalents.
6
- #
7
- # ## Purpose
8
- #
9
- # Helpers provide the most concise syntax for common options.
10
- # They are syntactic sugar that gets converted to simple mode options.
11
- #
12
- # ## Available Helpers
13
- #
14
- # - `:required` → `required: true`
15
- # - `:optional` → `required: false`
16
- #
17
- # ## Usage Examples
18
- #
19
- # Helper mode (most concise):
20
- # string :title, :required
21
- # string :bio, :optional
22
- #
23
- # Equivalent to simple mode:
24
- # string :title, required: true
25
- # string :bio, required: false
26
- #
27
- # ## Processing Flow
28
- #
29
- # 1. Helper mode: `string :title, :required`
30
- # 2. HelperMapper: `:required` → `required: true`
31
- # 3. OptionNormalizer: `required: true` → `{ is: true, message: nil }`
32
- # 4. Final: Advanced mode used internally
33
- #
34
- # ## Adding New Helpers
35
- #
36
- # To add a new helper:
37
- # ```ruby
38
- # HELPER_MAPPINGS = {
39
- # required: { required: true },
40
- # optional: { required: false },
41
- # my_helper: { my_option: :smth } # New helper example
42
- # }.freeze
43
- # ```
44
- class HelperMapper
45
- HELPER_MAPPINGS = {
46
- required: { required: true },
47
- optional: { required: false }
48
- }.freeze
49
-
50
- class << self
51
- # Maps helper symbols to their simple mode equivalents
52
- #
53
- # @param helpers [Array<Symbol>] Array of helper symbols
54
- # @return [Hash] Simple mode options hash
55
- def map(helpers)
56
- helpers.each_with_object({}) do |helper, result|
57
- mapping = HELPER_MAPPINGS.fetch(helper)
58
- result.merge!(mapping) if mapping.present?
59
- end
60
- end
61
-
62
- # Checks if a symbol is a registered helper
63
- #
64
- # @param symbol [Symbol] Symbol to check
65
- # @return [Boolean] True if symbol is a helper
66
- def helper?(symbol)
67
- HELPER_MAPPINGS.key?(symbol)
68
- end
69
- end
70
- end
71
- end
72
- end