servactory 3.0.0 → 3.1.0.rc2

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/lib/servactory/actions/action.rb +2 -2
  3. data/lib/servactory/actions/collection.rb +1 -1
  4. data/lib/servactory/actions/stages/collection.rb +1 -1
  5. data/lib/servactory/configuration/option_helpers/option_helpers_collection.rb +60 -2
  6. data/lib/servactory/context/warehouse/inputs.rb +2 -2
  7. data/lib/servactory/context/workspace/inputs.rb +22 -10
  8. data/lib/servactory/context/workspace/internals.rb +35 -13
  9. data/lib/servactory/context/workspace/outputs.rb +12 -6
  10. data/lib/servactory/dsl.rb +1 -1
  11. data/lib/servactory/info/builder.rb +2 -3
  12. data/lib/servactory/inputs/collection.rb +14 -21
  13. data/lib/servactory/inputs/input.rb +6 -103
  14. data/lib/servactory/inputs/tools/validation.rb +32 -57
  15. data/lib/servactory/inputs/validations/required.rb +3 -2
  16. data/lib/servactory/internals/collection.rb +5 -24
  17. data/lib/servactory/internals/internal.rb +4 -112
  18. data/lib/servactory/maintenance/attributes/base.rb +135 -0
  19. data/lib/servactory/maintenance/attributes/collection.rb +109 -0
  20. data/lib/servactory/maintenance/attributes/option_helper.rb +33 -12
  21. data/lib/servactory/maintenance/{attributes/options_collection.rb → options/collection.rb} +6 -7
  22. data/lib/servactory/maintenance/{attributes → options}/define_conflict.rb +1 -1
  23. data/lib/servactory/maintenance/{attributes → options}/define_method.rb +1 -1
  24. data/lib/servactory/maintenance/options/helper.rb +23 -0
  25. data/lib/servactory/maintenance/{attributes → options}/option.rb +50 -27
  26. data/lib/servactory/maintenance/options/registrar.rb +200 -0
  27. data/lib/servactory/maintenance/{attributes/validations → validations/checkers}/must.rb +25 -8
  28. data/lib/servactory/maintenance/{attributes/validations → validations/checkers}/type.rb +6 -5
  29. data/lib/servactory/maintenance/validations/concerns/error_builder.rb +50 -0
  30. data/lib/servactory/maintenance/validations/performer.rb +57 -0
  31. data/lib/servactory/maintenance/validations/support/type_validator.rb +36 -0
  32. data/lib/servactory/maintenance/{attributes → validations}/translator/must.rb +1 -1
  33. data/lib/servactory/maintenance/{attributes → validations}/translator/type.rb +1 -1
  34. data/lib/servactory/outputs/collection.rb +5 -24
  35. data/lib/servactory/outputs/output.rb +4 -112
  36. data/lib/servactory/result.rb +12 -18
  37. data/lib/servactory/tool_kit/dynamic_options/must.rb +2 -2
  38. data/lib/servactory/tool_kit/dynamic_options/schema.rb +5 -5
  39. data/lib/servactory/utils.rb +0 -8
  40. data/lib/servactory/version.rb +2 -2
  41. metadata +16 -13
  42. data/lib/servactory/maintenance/attributes/options/registrar.rb +0 -183
  43. data/lib/servactory/maintenance/attributes/tools/validation.rb +0 -84
  44. data/lib/servactory/maintenance/attributes/validations/concerns/error_builder.rb +0 -52
  45. data/lib/servactory/maintenance/validations/types.rb +0 -34
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b84875a142c1878a68ea71f3874019a8028bc8eff3836706d3079107b06761b
4
- data.tar.gz: 2a47fd738513716831e2fd491266e1c122a1200bcff9737d90a47087e95f2f64
3
+ metadata.gz: 6a7c9b4d9ad2e7d15265ba278d740eb34e6df33590bf517a0b42d914dad46e22
4
+ data.tar.gz: 21ad5c1814f6bd2c62221057547f5388cf928fd1f937f37131dab041d6325983
5
5
  SHA512:
6
- metadata.gz: 502fdff740f4a46378ee1b8664279fbc2cebfb7fe4fa01025a30499d3504ae1ae84b1ead432e28b1e23d59a572ba685690c88e681633bcb02020df5756e6328d
7
- data.tar.gz: 14482adc188d556373eaa482502f2bd59533ca5a8e3d6b590109cb6cf18755c9ae34a77df79baa7d654fd0657b7202821d2983447c8485525b62445bd4ac7898
6
+ metadata.gz: 9f231bf3c0662ec8285125cacd138d765622eb1ebad7e9eae5d95ae2dd84ad48f80a65783e208b3b9752e40e9bc755ca245bcf2f3b1c68b3724ca13a68d1f6a5
7
+ data.tar.gz: 8fb3f9f3bcf2a49f26d4cff76885537559ba4173c78585c2432fc7bf814a8e587303dc941c36a7992800bff1c561661cc04ae20beffbc17dac4d5a0af64de387
@@ -13,11 +13,11 @@ module Servactory
13
13
  @position = position
14
14
 
15
15
  @is_condition_opposite = false
16
- @condition = options.fetch(:if, nil)
16
+ @condition = options[:if]
17
17
 
18
18
  return unless @condition.nil?
19
19
 
20
- @condition = options.fetch(:unless, nil)
20
+ @condition = options[:unless]
21
21
 
22
22
  @is_condition_opposite = true unless @condition.nil?
23
23
  end
@@ -67,7 +67,7 @@ module Servactory
67
67
  # sorted = actions.sorted_by_position
68
68
  # sorted.each { |action| puts action.position }
69
69
  def sorted_by_position
70
- Collection.new(sort_by(&:position))
70
+ @sorted_by_position ||= Collection.new(sort_by(&:position))
71
71
  end
72
72
  end
73
73
  end
@@ -13,7 +13,7 @@ module Servactory
13
13
  end
14
14
 
15
15
  def sorted_by_position
16
- Collection.new(sort_by(&:position))
16
+ @sorted_by_position ||= Collection.new(sort_by(&:position))
17
17
  end
18
18
  end
19
19
  end
@@ -3,26 +3,84 @@
3
3
  module Servactory
4
4
  module Configuration
5
5
  module OptionHelpers
6
+ # Collection wrapper for managing option helper objects.
7
+ #
8
+ # ## Purpose
9
+ #
10
+ # OptionHelpersCollection provides a unified interface for storing and
11
+ # querying Helper instances used by the configuration system.
12
+ # It wraps a Set to ensure uniqueness and delegates common enumeration methods.
13
+ #
14
+ # ## Usage
15
+ #
16
+ # The collection is used internally by the configuration system
17
+ # to manage registered option helpers:
18
+ #
19
+ # ```ruby
20
+ # collection = OptionHelpersCollection.new
21
+ # collection << helper
22
+ #
23
+ # collection.find_by(name: :must) # => helper instance
24
+ # collection.dynamic_options # => filtered OptionHelpersCollection
25
+ # ```
26
+ #
27
+ # ## Performance
28
+ #
29
+ # The collection uses memoization for frequently accessed data:
30
+ # - `helpers_index` - cached hash for O(1) lookups by name
31
+ #
6
32
  class OptionHelpersCollection
7
33
  extend Forwardable
8
34
 
9
- def_delegators :@collection, :<<, :filter, :map, :find, :merge
35
+ def_delegators :@collection,
36
+ :<<,
37
+ :filter,
38
+ :each_with_object,
39
+ :map,
40
+ :merge
10
41
 
42
+ # Initializes the collection with an optional pre-built Set.
43
+ #
44
+ # @param collection [Set] initial set of helpers
45
+ # @return [OptionHelpersCollection]
11
46
  def initialize(collection = Set.new)
12
47
  @collection = collection
13
48
  end
14
49
 
50
+ # Duplicates the collection, resetting memoized caches.
51
+ #
52
+ # @param original [OptionHelpersCollection] the collection being duplicated
53
+ # @return [void]
15
54
  def initialize_dup(original)
16
55
  super
17
56
  @collection = original.instance_variable_get(:@collection).dup
57
+ @helpers_index = nil
18
58
  end
19
59
 
60
+ # Returns a new collection containing only dynamic option helpers.
61
+ #
62
+ # @return [OptionHelpersCollection] filtered collection of dynamic helpers
20
63
  def dynamic_options
21
64
  OptionHelpersCollection.new(filter(&:dynamic_option?))
22
65
  end
23
66
 
67
+ # Finds a helper by its name using indexed lookup.
68
+ #
69
+ # @param name [Symbol] the helper name to find
70
+ # @return [Maintenance::Options::Helper, nil] the found helper or nil
24
71
  def find_by(name:)
25
- find { |helper| helper.name == name }
72
+ helpers_index[name]
73
+ end
74
+
75
+ private
76
+
77
+ # Builds and caches a hash index for O(1) helper lookups.
78
+ #
79
+ # @return [Hash{Symbol => Maintenance::Options::Helper}] helper names mapped to Helper instances
80
+ def helpers_index
81
+ @helpers_index ||= each_with_object({}) do |helper, index|
82
+ index[helper.name] = helper
83
+ end
26
84
  end
27
85
  end
28
86
  end
@@ -57,10 +57,10 @@ module Servactory
57
57
  # Checks if method corresponds to stored input.
58
58
  #
59
59
  # @param name [Symbol] Method name to check
60
- # @param _include_private [Boolean] Include private methods in check
61
60
  # @return [Boolean] True if input exists for this method
62
61
  def respond_to_missing?(name, *)
63
- @arguments.fetch(name) { raise_error_for(name) }
62
+ input_name = name.to_s.chomp("?").to_sym
63
+ @arguments.key?(input_name) || @arguments.key?(name) || super
64
64
  end
65
65
 
66
66
  private
@@ -32,13 +32,12 @@ module Servactory
32
32
  end
33
33
 
34
34
  def respond_to_missing?(name, *)
35
- @collection_of_inputs.names.include?(name) || super
35
+ resolve_input(name) || super
36
36
  end
37
37
 
38
38
  private
39
39
 
40
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Lint/UnusedMethodArgument
41
- def fetch_with(name:, &block)
40
+ def fetch_with(name:, &_block)
42
41
  predicate = @context.config.predicate_methods_enabled && name.end_with?("?")
43
42
 
44
43
  input_name = predicate ? name.to_s.chomp("?").to_sym : name
@@ -47,18 +46,31 @@ module Servactory
47
46
 
48
47
  return yield if input.nil?
49
48
 
50
- input_value = @context.send(:servactory_service_warehouse).fetch_input(input.name)
49
+ value = fetch_value(attribute: input)
51
50
 
52
- if input.optional? && !input.default.nil? && !Servactory::Utils.value_present?(input_value)
53
- input_value = input.default
51
+ predicate ? Servactory::Utils.query_attribute(value) : value
52
+ end
53
+
54
+ def fetch_value(attribute:)
55
+ value = @context.send(:servactory_service_warehouse).fetch_input(attribute.name)
56
+
57
+ if attribute.optional? && !attribute.default.nil? && !Servactory::Utils.value_present?(value)
58
+ value = attribute.default
54
59
  end
55
60
 
56
- input_prepare = input.prepare[:in]
57
- input_value = input_prepare.call(value: input_value) if input_prepare
61
+ prepare = attribute.prepare[:in]
62
+ value = prepare.call(value:) if prepare
63
+
64
+ value
65
+ end
66
+
67
+ def resolve_input(name)
68
+ return true if @collection_of_inputs.find_by(name:)
58
69
 
59
- predicate ? Servactory::Utils.query_attribute(input_value) : input_value
70
+ @context.config.predicate_methods_enabled &&
71
+ name.to_s.end_with?("?") &&
72
+ @collection_of_inputs.find_by(name: name.to_s.chomp("?").to_sym)
60
73
  end
61
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Lint/UnusedMethodArgument
62
74
 
63
75
  def raise_error_for(type, name)
64
76
  message_text = @context.send(:servactory_service_info).translate(
@@ -32,28 +32,34 @@ module Servactory
32
32
  end
33
33
 
34
34
  def respond_to_missing?(name, *)
35
- @collection_of_internals.names.include?(name) || super
35
+ resolve_internal(name) || super
36
36
  end
37
37
 
38
38
  private
39
39
 
40
- def assign_with(prepared_name:, value:, &block) # rubocop:disable Lint/UnusedMethodArgument
41
- return yield unless @collection_of_internals.names.include?(prepared_name)
40
+ def validated_attributes
41
+ @validated_attributes ||= Set.new
42
+ end
42
43
 
43
- internal = @collection_of_internals.find_by(name: prepared_name) # ::Servactory::Internals::Internal
44
+ def assign_with(prepared_name:, value:, &_block)
45
+ internal = @collection_of_internals.find_by(name: prepared_name)
44
46
 
45
47
  return yield if internal.nil?
46
48
 
47
- Servactory::Maintenance::Attributes::Tools::Validation.validate!(
49
+ validated_attributes.delete(internal.name)
50
+
51
+ Servactory::Maintenance::Validations::Performer.validate!(
48
52
  context: @context,
49
53
  attribute: internal,
50
54
  value:
51
55
  )
52
56
 
53
57
  @context.send(:servactory_service_warehouse).assign_internal(internal.name, value)
58
+
59
+ validated_attributes << internal.name
54
60
  end
55
61
 
56
- def fetch_with(name:, &block) # rubocop:disable Metrics/MethodLength, Lint/UnusedMethodArgument
62
+ def fetch_with(name:, &_block)
57
63
  predicate = @context.config.predicate_methods_enabled && name.end_with?("?")
58
64
 
59
65
  internal_name = predicate ? name.to_s.chomp("?").to_sym : name
@@ -61,17 +67,33 @@ module Servactory
61
67
 
62
68
  return yield if internal.nil?
63
69
 
64
- internal_value = @context.send(:servactory_service_warehouse).fetch_internal(internal.name)
65
-
66
- Servactory::Maintenance::Attributes::Tools::Validation.validate!(
67
- context: @context,
68
- attribute: internal,
69
- value: internal_value
70
- )
70
+ internal_value = fetch_value(attribute: internal)
71
71
 
72
72
  predicate ? Servactory::Utils.query_attribute(internal_value) : internal_value
73
73
  end
74
74
 
75
+ def fetch_value(attribute:)
76
+ value = @context.send(:servactory_service_warehouse).fetch_internal(attribute.name)
77
+
78
+ if validated_attributes.exclude?(attribute.name)
79
+ Servactory::Maintenance::Validations::Performer.validate!(
80
+ context: @context,
81
+ attribute:,
82
+ value:
83
+ )
84
+ end
85
+
86
+ value
87
+ end
88
+
89
+ def resolve_internal(name)
90
+ return true if @collection_of_internals.find_by(name:)
91
+
92
+ @context.config.predicate_methods_enabled &&
93
+ name.to_s.end_with?("?") &&
94
+ @collection_of_internals.find_by(name: name.to_s.chomp("?").to_sym)
95
+ end
96
+
75
97
  def raise_error_for(type, name)
76
98
  message_text = @context.send(:servactory_service_info).translate(
77
99
  "internals.undefined.for_#{type}",
@@ -32,19 +32,17 @@ module Servactory
32
32
  end
33
33
 
34
34
  def respond_to_missing?(name, *)
35
- @collection_of_outputs.names.include?(name) || super
35
+ resolve_output(name) || super
36
36
  end
37
37
 
38
38
  private
39
39
 
40
- def assign_with(prepared_name:, value:, &block) # rubocop:disable Lint/UnusedMethodArgument
41
- return yield unless @collection_of_outputs.names.include?(prepared_name)
42
-
40
+ def assign_with(prepared_name:, value:, &_block)
43
41
  output = @collection_of_outputs.find_by(name: prepared_name)
44
42
 
45
43
  return yield if output.nil?
46
44
 
47
- Servactory::Maintenance::Attributes::Tools::Validation.validate!(
45
+ Servactory::Maintenance::Validations::Performer.validate!(
48
46
  context: @context,
49
47
  attribute: output,
50
48
  value:
@@ -53,7 +51,7 @@ module Servactory
53
51
  @context.send(:servactory_service_warehouse).assign_output(output.name, value)
54
52
  end
55
53
 
56
- def fetch_with(name:, &block) # rubocop:disable Lint/UnusedMethodArgument
54
+ def fetch_with(name:, &_block)
57
55
  predicate = @context.config.predicate_methods_enabled && name.end_with?("?")
58
56
 
59
57
  output_name = predicate ? name.to_s.chomp("?").to_sym : name
@@ -66,6 +64,14 @@ module Servactory
66
64
  predicate ? Servactory::Utils.query_attribute(output_value) : output_value
67
65
  end
68
66
 
67
+ def resolve_output(name)
68
+ return true if @collection_of_outputs.find_by(name:)
69
+
70
+ @context.config.predicate_methods_enabled &&
71
+ name.to_s.end_with?("?") &&
72
+ @collection_of_outputs.find_by(name: name.to_s.chomp("?").to_sym)
73
+ end
74
+
69
75
  def raise_error_for(type, name)
70
76
  message_text = @context.send(:servactory_service_info).translate(
71
77
  "outputs.undefined.for_#{type}",
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Servactory
4
4
  module DSL
5
- STROMA = Stroma::Matrix.define(:my_lib) do
5
+ STROMA = Stroma::Matrix.define(:servactory) do
6
6
  register(:configuration, Configuration::DSL)
7
7
  register(:info, Info::DSL)
8
8
  register(:context, Context::DSL)
@@ -138,15 +138,14 @@ module Servactory
138
138
  end
139
139
 
140
140
  def extract_message_from_value(value:)
141
- value.is_a?(Hash) ? value.fetch(:message, nil) : nil
141
+ value.is_a?(Hash) ? value[:message] : nil
142
142
  end
143
143
 
144
144
  def enrich_options_with_common_fields(attribute:, options:)
145
- actor = attribute.class::Actor.new(attribute)
146
145
  must = attribute.collection_of_options.find_by(name: :must)
147
146
 
148
147
  options.merge(
149
- actor:,
148
+ actor: attribute.actor,
150
149
  types: attribute.types,
151
150
  must: must&.value
152
151
  )
@@ -2,29 +2,22 @@
2
2
 
3
3
  module Servactory
4
4
  module Inputs
5
- class Collection
6
- extend Forwardable
5
+ # Specialized collection for Input attributes.
6
+ #
7
+ # Overrides `lookup_name` to use `internal_name` instead of `name`,
8
+ # supporting the `as:` parameter that renames inputs internally.
9
+ # Adds `flat_map` delegation for input-specific enumeration needs.
10
+ class Collection < Servactory::Maintenance::Attributes::Collection
11
+ def_delegators :@collection, :flat_map
7
12
 
8
- def_delegators :@collection, :<<, :filter, :each, :map, :flat_map, :to_h, :merge, :find
13
+ private
9
14
 
10
- def initialize(collection = Set.new)
11
- @collection = collection
12
- end
13
-
14
- def only(*names)
15
- Collection.new(filter { |input| names.include?(input.internal_name) })
16
- end
17
-
18
- def except(*names)
19
- Collection.new(filter { |input| names.exclude?(input.internal_name) })
20
- end
21
-
22
- def names
23
- map(&:name)
24
- end
25
-
26
- def find_by(name:)
27
- find { |input| input.internal_name == name }
15
+ # Returns `internal_name` for indexing, supporting the `as:` parameter.
16
+ #
17
+ # @param attribute [Object] the input attribute
18
+ # @return [Symbol] the internal name used for lookup
19
+ def lookup_name(attribute)
20
+ attribute.internal_name
28
21
  end
29
22
  end
30
23
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Servactory
4
4
  module Inputs
5
- class Input # rubocop:disable Metrics/ClassLength
5
+ class Input < Servactory::Maintenance::Attributes::Base
6
6
  class Actor
7
7
  attr_reader :name,
8
8
  :internal_name,
@@ -38,22 +38,19 @@ module Servactory
38
38
  # The methods below are required to support the internal work.
39
39
 
40
40
  def input?
41
- true
41
+ @attribute.input?
42
42
  end
43
43
 
44
44
  def internal?
45
- false
45
+ @attribute.internal?
46
46
  end
47
47
 
48
48
  def output?
49
- false
49
+ @attribute.output?
50
50
  end
51
51
  end
52
52
 
53
- attr_reader :name,
54
- :internal_name,
55
- :collection_of_options,
56
- :options
53
+ attr_reader :internal_name
57
54
 
58
55
  # rubocop:disable Style/KeywordParametersOrder
59
56
  def initialize(
@@ -63,49 +60,16 @@ module Servactory
63
60
  option_helpers:,
64
61
  **options
65
62
  )
66
- @name = name
67
63
  @internal_name = as.presence || name
68
- @option_helpers = option_helpers
69
64
 
70
- register_options(helpers:, options:)
65
+ super(name, *helpers, option_helpers:, **options)
71
66
  end
72
67
  # rubocop:enable Style/KeywordParametersOrder
73
68
 
74
- def method_missing(name, *args, &block)
75
- option = @collection_of_options.find_by(name:)
76
- return super if option.nil?
77
-
78
- option.body
79
- end
80
-
81
- def respond_to_missing?(name, *)
82
- @collection_of_options.names.include?(name) || super
83
- end
84
-
85
- def register_options(helpers:, options:)
86
- merged_options = augment_options_with_helpers(helpers:, options:)
87
- options_registrar = create_options_registrar(options: merged_options)
88
-
89
- @options = merged_options
90
- @collection_of_options = options_registrar.collection
91
- end
92
-
93
- def options_for_checks
94
- @collection_of_options.options_for_checks
95
- end
96
-
97
69
  def conflict_code
98
70
  @collection_of_options.defined_conflict_code
99
71
  end
100
72
 
101
- def system_name
102
- self.class.name.demodulize.downcase.to_sym
103
- end
104
-
105
- def i18n_name
106
- system_name.to_s.pluralize
107
- end
108
-
109
73
  def with_conflicts?
110
74
  conflict_code.present?
111
75
  end
@@ -114,24 +78,8 @@ module Servactory
114
78
  true
115
79
  end
116
80
 
117
- def internal?
118
- false
119
- end
120
-
121
- def output?
122
- false
123
- end
124
-
125
81
  private
126
82
 
127
- def create_options_registrar(options:)
128
- Servactory::Maintenance::Attributes::Options::Registrar.register(
129
- attribute: self,
130
- options:,
131
- features: available_feature_options
132
- )
133
- end
134
-
135
83
  def available_feature_options
136
84
  {
137
85
  required: true,
@@ -141,51 +89,6 @@ module Servactory
141
89
  prepare: true
142
90
  }
143
91
  end
144
-
145
- def augment_options_with_helpers(helpers:, options:)
146
- result_options = options.dup
147
- merge_standard_helpers_into(target_options: result_options, helpers:) if helpers.present?
148
- merge_advanced_helpers_into(target_options: result_options, source_options: options)
149
- result_options
150
- end
151
-
152
- def merge_standard_helpers_into(target_options:, helpers:)
153
- standard_helpers_result = transform_helpers_to_options(helpers:)
154
- target_options.deep_merge!(standard_helpers_result)
155
- end
156
-
157
- def merge_advanced_helpers_into(target_options:, source_options:)
158
- advanced_helpers = filter_advanced_helpers(options: source_options)
159
- return if advanced_helpers.blank?
160
-
161
- advanced_helpers_result = transform_helpers_to_options(helpers: advanced_helpers)
162
- target_options.deep_merge!(advanced_helpers_result)
163
- end
164
-
165
- def filter_advanced_helpers(options:)
166
- reserved_options = Servactory::Maintenance::Attributes::Options::Registrar::RESERVED_OPTIONS
167
- options.except(*reserved_options)
168
- end
169
-
170
- def transform_helpers_to_options(helpers:)
171
- helpers.each_with_object({}) do |(helper_name, values), result|
172
- helper = @option_helpers.find_by(name: helper_name)
173
- next if helper.blank?
174
-
175
- transformed_option = transform_helper_to_option(helper:, values:)
176
- result.deep_merge!(transformed_option) if transformed_option.present?
177
- end
178
- end
179
-
180
- def transform_helper_to_option(helper:, values:)
181
- return helper.equivalent unless helper.equivalent.is_a?(Proc)
182
-
183
- if values.is_a?(Hash)
184
- helper.equivalent.call(**values)
185
- else
186
- helper.equivalent.call(values)
187
- end
188
- end
189
92
  end
190
93
  end
191
94
  end