graphql 1.10.8 → 1.11.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/object_generator.rb +50 -8
  3. data/lib/graphql.rb +4 -4
  4. data/lib/graphql/execution/instrumentation.rb +1 -1
  5. data/lib/graphql/execution/interpreter.rb +1 -1
  6. data/lib/graphql/execution/interpreter/arguments.rb +2 -5
  7. data/lib/graphql/execution/interpreter/runtime.rb +18 -23
  8. data/lib/graphql/execution/multiplex.rb +1 -2
  9. data/lib/graphql/introspection/schema_type.rb +3 -3
  10. data/lib/graphql/object_type.rb +1 -1
  11. data/lib/graphql/pagination/connection.rb +13 -6
  12. data/lib/graphql/pagination/connections.rb +5 -4
  13. data/lib/graphql/query.rb +1 -2
  14. data/lib/graphql/schema.rb +26 -3
  15. data/lib/graphql/schema/argument.rb +6 -0
  16. data/lib/graphql/schema/build_from_definition.rb +7 -12
  17. data/lib/graphql/schema/enum.rb +9 -1
  18. data/lib/graphql/schema/field.rb +60 -79
  19. data/lib/graphql/schema/field/connection_extension.rb +2 -1
  20. data/lib/graphql/schema/input_object.rb +1 -3
  21. data/lib/graphql/schema/interface.rb +5 -0
  22. data/lib/graphql/schema/list.rb +2 -1
  23. data/lib/graphql/schema/loader.rb +3 -0
  24. data/lib/graphql/schema/member.rb +1 -0
  25. data/lib/graphql/schema/member/has_arguments.rb +6 -0
  26. data/lib/graphql/schema/member/has_fields.rb +1 -1
  27. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  28. data/lib/graphql/schema/object.rb +7 -0
  29. data/lib/graphql/schema/resolver.rb +14 -0
  30. data/lib/graphql/schema/subscription.rb +1 -1
  31. data/lib/graphql/schema/union.rb +6 -0
  32. data/lib/graphql/schema/warden.rb +7 -2
  33. data/lib/graphql/subscriptions.rb +41 -8
  34. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +49 -4
  35. data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
  36. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  37. data/lib/graphql/subscriptions/event.rb +16 -1
  38. data/lib/graphql/subscriptions/subscription_root.rb +13 -3
  39. data/lib/graphql/tracing.rb +0 -27
  40. data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
  41. data/lib/graphql/tracing/platform_tracing.rb +14 -0
  42. data/lib/graphql/tracing/scout_tracing.rb +11 -0
  43. data/lib/graphql/types/iso_8601_date.rb +2 -2
  44. data/lib/graphql/types/iso_8601_date_time.rb +19 -15
  45. data/lib/graphql/version.rb +1 -1
  46. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 13caa4920df03f81232a23cf9fe5707ee3602a6c42bedace93870645f35d1248
4
- data.tar.gz: 597cbe2fd51c36a0e0de158d51c70d1d057a2712d44a34c71872ef0586a9c3d9
3
+ metadata.gz: 5fa7fb8135053075bd0575c9248d4e98521d0591fa26fbddc910125b1b8ea5d6
4
+ data.tar.gz: 982e434c521e7989f65364b7dd3e1540857a5110fc589e55b94196d802b6c6b0
5
5
  SHA512:
6
- metadata.gz: ca5468c4b6632a4028f4bebf226c7a3aee5bb6786096b1b5a843b2ae476043160b1fe52111ae70d62c5a35cc66f9edd2d903128ebb2412c87054b9040f2a55aa
7
- data.tar.gz: e9ad2d87cb3898d849266bb743251d922024541ee9d08090cb4f7898331fa15962697a87f386011b7450ca9af3c730c23ff74ca4d2191af6c319d3168add1bdd
6
+ metadata.gz: 10d507db573e239973114d7ef6cdff1d3532165f408dc0e93e5f63e0247ec552dbf3c93d53a85df1f8d00325126e1c101d9aae8e38879771d1aaa4f7238b98da
7
+ data.tar.gz: 127f3b84714f80ca41196d2ebc415f694164283d52e3cbacea25a6ec164deac88e70f4447a6af340a3ce8599ebf50489d490522fa509e112bf44d1d33eaf0fba
@@ -15,20 +15,62 @@ module Graphql
15
15
  desc "Create a GraphQL::ObjectType with the given name and fields"
16
16
  source_root File.expand_path('../templates', __FILE__)
17
17
 
18
- argument :fields,
19
- type: :array,
20
- default: [],
21
- banner: "name:type name:type ...",
22
- desc: "Fields for this object (type may be expressed as Ruby or GraphQL)"
18
+ argument :custom_fields,
19
+ type: :array,
20
+ default: [],
21
+ banner: "name:type name:type ...",
22
+ desc: "Fields for this object (type may be expressed as Ruby or GraphQL)"
23
23
 
24
24
  class_option :node,
25
- type: :boolean,
26
- default: false,
27
- desc: "Include the Relay Node interface"
25
+ type: :boolean,
26
+ default: false,
27
+ desc: "Include the Relay Node interface"
28
28
 
29
29
  def create_type_file
30
30
  template "object.erb", "#{options[:directory]}/types/#{type_file_name}.rb"
31
31
  end
32
+
33
+ def fields
34
+ columns = []
35
+ columns += klass.columns.map { |c| generate_column_string(c) } if class_exists?
36
+ columns + custom_fields
37
+ end
38
+
39
+ def self.normalize_type_expression(type_expression, mode:, null: true)
40
+ case type_expression
41
+ when "Text"
42
+ ["String", null]
43
+ when "DateTime", "Datetime"
44
+ ["GraphQL::Types::ISO8601DateTime", null]
45
+ when "Date"
46
+ ["GraphQL::Types::ISO8601Date", null]
47
+ else
48
+ super
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def generate_column_string(column)
55
+ name = column.name
56
+ required = column.null ? "" : "!"
57
+ type = column_type_string(column)
58
+ "#{name}:#{required}#{type}"
59
+ end
60
+
61
+ def column_type_string(column)
62
+ column.name == "id" ? "ID" : column.type.to_s.camelize
63
+ end
64
+
65
+ def class_exists?
66
+ klass.is_a?(Class) && klass.ancestors.include?(ActiveRecord::Base)
67
+ rescue NameError
68
+ return false
69
+ end
70
+
71
+ def klass
72
+ @klass ||= Module.const_get(type_name.camelize)
73
+ end
32
74
  end
33
75
  end
34
76
  end
@@ -89,12 +89,15 @@ require "graphql/name_validator"
89
89
  require "graphql/language"
90
90
  require "graphql/analysis"
91
91
  require "graphql/tracing"
92
- require "graphql/execution"
93
92
  require "graphql/dig"
93
+ require "graphql/execution"
94
94
  require "graphql/schema"
95
95
  require "graphql/query"
96
96
  require "graphql/directive"
97
97
  require "graphql/execution"
98
+ require "graphql/runtime_type_error"
99
+ require "graphql/unresolved_type_error"
100
+ require "graphql/invalid_null_error"
98
101
  require "graphql/types"
99
102
  require "graphql/relay"
100
103
  require "graphql/boolean_type"
@@ -109,10 +112,7 @@ require "graphql/introspection"
109
112
 
110
113
  require "graphql/analysis_error"
111
114
  require "graphql/coercion_error"
112
- require "graphql/runtime_type_error"
113
- require "graphql/invalid_null_error"
114
115
  require "graphql/invalid_name_error"
115
- require "graphql/unresolved_type_error"
116
116
  require "graphql/integer_encoding_error"
117
117
  require "graphql/string_encoding_error"
118
118
  require "graphql/internal_representation"
@@ -77,7 +77,7 @@ module GraphQL
77
77
  end
78
78
 
79
79
  def call_after_hooks(instrumenters, object, after_hook_name, ex)
80
- instrumenters.reverse.each do |instrumenter|
80
+ instrumenters.reverse_each do |instrumenter|
81
81
  begin
82
82
  instrumenter.public_send(after_hook_name, object)
83
83
  rescue => e
@@ -26,7 +26,7 @@ module GraphQL
26
26
  schema_class.query_execution_strategy(GraphQL::Execution::Interpreter)
27
27
  schema_class.mutation_execution_strategy(GraphQL::Execution::Interpreter)
28
28
  schema_class.subscription_execution_strategy(GraphQL::Execution::Interpreter)
29
-
29
+ schema_class.add_subscription_extension_if_necessary
30
30
  GraphQL::Schema::Object.include(HandlesRawValue)
31
31
  end
32
32
 
@@ -8,6 +8,7 @@ module GraphQL
8
8
  # @see GraphQL::Query#arguments_for to get access to these objects.
9
9
  class Arguments
10
10
  extend Forwardable
11
+ include GraphQL::Dig
11
12
 
12
13
  # The Ruby-style arguments hash, ready for a resolver.
13
14
  # This hash is the one used at runtime.
@@ -20,15 +21,11 @@ module GraphQL
20
21
  @argument_values = argument_values
21
22
  end
22
23
 
23
- # Yields `ArgumentValue` instances which contain detailed metadata about each argument.
24
- def each_value
25
- argument_values.each { |arg_v| yield(arg_v) }
26
- end
27
-
28
24
  # @return [Hash{Symbol => ArgumentValue}]
29
25
  attr_reader :argument_values
30
26
 
31
27
  def_delegators :@keyword_arguments, :key?, :[], :keys, :each, :values
28
+ def_delegators :@argument_values, :each_value
32
29
 
33
30
  def inspect
34
31
  "#<#{self.class} @keyword_arguments=#{keyword_arguments.inspect}>"
@@ -182,8 +182,6 @@ module GraphQL
182
182
 
183
183
  kwarg_arguments = resolved_arguments.keyword_arguments
184
184
 
185
- # It might turn out that making arguments for every field is slow.
186
- # If we have to cache them, we'll need a more subtle approach here.
187
185
  field_defn.extras.each do |extra|
188
186
  case extra
189
187
  when :ast_node
@@ -256,7 +254,7 @@ module GraphQL
256
254
  def continue_value(path, value, field, is_non_null, ast_node)
257
255
  if value.nil?
258
256
  if is_non_null
259
- err = GraphQL::InvalidNullError.new(field.owner, field, value)
257
+ err = field.owner::InvalidNullError.new(field.owner, field, value)
260
258
  write_invalid_null_in_response(path, err)
261
259
  else
262
260
  write_in_response(path, nil)
@@ -306,18 +304,21 @@ module GraphQL
306
304
  write_in_response(path, r)
307
305
  r
308
306
  when "UNION", "INTERFACE"
309
- resolved_type_or_lazy = resolve_type(type, value, path)
307
+ resolved_type_or_lazy, resolved_value = resolve_type(type, value, path)
308
+ resolved_value ||= value
309
+
310
310
  after_lazy(resolved_type_or_lazy, owner: type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false) do |resolved_type|
311
311
  possible_types = query.possible_types(type)
312
312
 
313
313
  if !possible_types.include?(resolved_type)
314
314
  parent_type = field.owner
315
- type_error = GraphQL::UnresolvedTypeError.new(value, field, parent_type, resolved_type, possible_types)
315
+ err_class = type::UnresolvedTypeError
316
+ type_error = err_class.new(resolved_value, field, parent_type, resolved_type, possible_types)
316
317
  schema.type_error(type_error, context)
317
318
  write_in_response(path, nil)
318
319
  nil
319
320
  else
320
- continue_field(path, value, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments)
321
+ continue_field(path, resolved_value, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments)
321
322
  end
322
323
  end
323
324
  when "OBJECT"
@@ -459,7 +460,13 @@ module GraphQL
459
460
  end
460
461
 
461
462
  def arguments(graphql_object, arg_owner, ast_node)
462
- query.arguments_for(ast_node, arg_owner, parent_object: graphql_object)
463
+ # Don't cache arguments if field extras are requested since extras mutate the argument data structure
464
+ if arg_owner.arguments_statically_coercible? && (!arg_owner.is_a?(GraphQL::Schema::Field) || arg_owner.extras.empty?)
465
+ query.arguments_for(ast_node, arg_owner)
466
+ else
467
+ # The arguments must be prepared in the context of the given object
468
+ query.arguments_for(ast_node, arg_owner, parent_object: graphql_object)
469
+ end
463
470
  end
464
471
 
465
472
  def write_invalid_null_in_response(path, invalid_null_error)
@@ -499,23 +506,11 @@ module GraphQL
499
506
  # at previous parts of the response.
500
507
  # This hash matches the response
501
508
  def type_at(path)
502
- t = @types_at_paths
503
- path.each do |part|
504
- t = t[part] || (raise("Invariant: #{part.inspect} not found in #{t}"))
505
- end
506
- t = t[:__type]
507
- t
509
+ @types_at_paths.fetch(path)
508
510
  end
509
511
 
510
512
  def set_type_at_path(path, type)
511
- types = @types_at_paths
512
- path.each do |part|
513
- types = types[part] ||= {}
514
- end
515
- # Use this magic key so that the hash contains:
516
- # - string keys for nested fields
517
- # - :__type for the object type of a selection
518
- types[:__type] ||= type
513
+ @types_at_paths[path] = type
519
514
  nil
520
515
  end
521
516
 
@@ -545,7 +540,7 @@ module GraphQL
545
540
 
546
541
  def resolve_type(type, value, path)
547
542
  trace_payload = { context: context, type: type, object: value, path: path }
548
- resolved_type = query.trace("resolve_type", trace_payload) do
543
+ resolved_type, resolved_value = query.trace("resolve_type", trace_payload) do
549
544
  query.resolve_type(type, value)
550
545
  end
551
546
 
@@ -556,7 +551,7 @@ module GraphQL
556
551
  end
557
552
  end
558
553
  else
559
- resolved_type
554
+ [resolved_type, resolved_value]
560
555
  end
561
556
  end
562
557
 
@@ -34,8 +34,7 @@ module GraphQL
34
34
  @schema = schema
35
35
  @queries = queries
36
36
  @context = context
37
- # TODO remove support for global tracers
38
- @tracers = schema.tracers + GraphQL::Tracing.tracers + (context[:tracers] || [])
37
+ @tracers = schema.tracers + (context[:tracers] || [])
39
38
  # Support `context: {backtrace: true}`
40
39
  if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
41
40
  @tracers << GraphQL::Backtrace::Tracer
@@ -9,9 +9,9 @@ module GraphQL
9
9
  "query, mutation, and subscription operations."
10
10
 
11
11
  field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false
12
- field :queryType, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
13
- field :mutationType, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at.", null: true
14
- field :subscriptionType, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at.", null: true
12
+ field :query_type, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
13
+ field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at.", null: true
14
+ field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at.", null: true
15
15
  field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false
16
16
 
17
17
  def types
@@ -88,7 +88,7 @@ module GraphQL
88
88
  interfaces.each do |iface|
89
89
  iface = BaseType.resolve_related_type(iface)
90
90
  if iface.is_a?(GraphQL::InterfaceType)
91
- type_memberships << iface.type_membership_class.new(iface, self, options)
91
+ type_memberships << iface.type_membership_class.new(iface, self, **options)
92
92
  end
93
93
  end
94
94
  end
@@ -26,6 +26,9 @@ module GraphQL
26
26
  # @return [GraphQL::Query::Context]
27
27
  attr_accessor :context
28
28
 
29
+ # @return [Object] the object this collection belongs to
30
+ attr_accessor :parent
31
+
29
32
  # Raw access to client-provided values. (`max_page_size` not applied to first or last.)
30
33
  attr_accessor :before_value, :after_value, :first_value, :last_value
31
34
 
@@ -49,13 +52,15 @@ module GraphQL
49
52
 
50
53
  # @param items [Object] some unpaginated collection item, like an `Array` or `ActiveRecord::Relation`
51
54
  # @param context [Query::Context]
55
+ # @param parent [Object] The object this collection belongs to
52
56
  # @param first [Integer, nil] The limit parameter from the client, if it provided one
53
57
  # @param after [String, nil] A cursor for pagination, if the client provided one
54
58
  # @param last [Integer, nil] Limit parameter from the client, if provided
55
59
  # @param before [String, nil] A cursor for pagination, if the client provided one.
56
60
  # @param max_page_size [Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given.
57
- def initialize(items, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil)
61
+ def initialize(items, parent: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil)
58
62
  @items = items
63
+ @parent = parent
59
64
  @context = context
60
65
  @first_value = first
61
66
  @after_value = after
@@ -185,17 +190,19 @@ module GraphQL
185
190
  # A wrapper around paginated items. It includes a {cursor} for pagination
186
191
  # and could be extended with custom relationship-level data.
187
192
  class Edge
188
- def initialize(item, connection)
193
+ attr_reader :node
194
+
195
+ def initialize(node, connection)
189
196
  @connection = connection
190
- @item = item
197
+ @node = node
191
198
  end
192
199
 
193
- def node
194
- @item
200
+ def parent
201
+ @connection.parent
195
202
  end
196
203
 
197
204
  def cursor
198
- @connection.cursor_for(@item)
205
+ @cursor ||= @connection.cursor_for(@node)
199
206
  end
200
207
  end
201
208
  end
@@ -65,21 +65,22 @@ module GraphQL
65
65
 
66
66
  # Used by the runtime to wrap values in connection wrappers.
67
67
  # @api Private
68
- def wrap(field, object, arguments, context, wrappers: all_wrappers)
68
+ def wrap(field, parent, items, arguments, context, wrappers: all_wrappers)
69
69
  impl = nil
70
70
 
71
- object.class.ancestors.each { |cls|
71
+ items.class.ancestors.each { |cls|
72
72
  impl = wrappers[cls]
73
73
  break if impl
74
74
  }
75
75
 
76
76
  if impl.nil?
77
- raise ImplementationMissingError, "Couldn't find a connection wrapper for #{object.class} during #{field.path} (#{object.inspect})"
77
+ raise ImplementationMissingError, "Couldn't find a connection wrapper for #{items.class} during #{field.path} (#{items.inspect})"
78
78
  end
79
79
 
80
80
  impl.new(
81
- object,
81
+ items,
82
82
  context: context,
83
+ parent: parent,
83
84
  max_page_size: field.max_page_size || context.schema.default_max_page_size,
84
85
  first: arguments[:first],
85
86
  after: arguments[:after],
@@ -96,8 +96,7 @@ module GraphQL
96
96
  @fragments = nil
97
97
  @operations = nil
98
98
  @validate = validate
99
- # TODO: remove support for global tracers
100
- @tracers = schema.tracers + GraphQL::Tracing.tracers + (context ? context.fetch(:tracers, []) : [])
99
+ @tracers = schema.tracers + (context ? context.fetch(:tracers, []) : [])
101
100
  # Support `ctx[:backtrace] = true` for wrapping backtraces
102
101
  if context && context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
103
102
  @tracers << GraphQL::Backtrace::Tracer
@@ -1075,6 +1075,7 @@ module GraphQL
1075
1075
  raise GraphQL::Error, "Second definition of `subscription(...)` (#{new_subscription_object.inspect}) is invalid, already configured with #{@subscription_object.inspect}"
1076
1076
  else
1077
1077
  @subscription_object = new_subscription_object
1078
+ add_subscription_extension_if_necessary
1078
1079
  add_type_and_traverse(new_subscription_object, root: true)
1079
1080
  nil
1080
1081
  end
@@ -1389,7 +1390,7 @@ module GraphQL
1389
1390
  # rubocop:disable Lint/DuplicateMethods
1390
1391
  module ResolveTypeWithType
1391
1392
  def resolve_type(type, obj, ctx)
1392
- first_resolved_type = if type.is_a?(Module) && type.respond_to?(:resolve_type)
1393
+ first_resolved_type, resolved_value = if type.is_a?(Module) && type.respond_to?(:resolve_type)
1393
1394
  type.resolve_type(obj, ctx)
1394
1395
  else
1395
1396
  super
@@ -1397,7 +1398,11 @@ module GraphQL
1397
1398
 
1398
1399
  after_lazy(first_resolved_type) do |resolved_type|
1399
1400
  if resolved_type.nil? || (resolved_type.is_a?(Module) && resolved_type.respond_to?(:kind)) || resolved_type.is_a?(GraphQL::BaseType)
1400
- resolved_type
1401
+ if resolved_value
1402
+ [resolved_type, resolved_value]
1403
+ else
1404
+ resolved_type
1405
+ end
1401
1406
  else
1402
1407
  raise ".resolve_type should return a type definition, but got #{resolved_type.inspect} (#{resolved_type.class}) from `resolve_type(#{type}, #{obj}, #{ctx})`"
1403
1408
  end
@@ -1506,7 +1511,11 @@ module GraphQL
1506
1511
 
1507
1512
  # @return [GraphQL::Execution::Errors, Class<GraphQL::Execution::Errors::NullErrorHandler>]
1508
1513
  def error_handler
1509
- @error_handler ||= GraphQL::Execution::Errors::NullErrorHandler
1514
+ if defined?(@error_handler)
1515
+ @error_handler
1516
+ else
1517
+ find_inherited_value(:error_handler, GraphQL::Execution::Errors::NullErrorHandler)
1518
+ end
1510
1519
  end
1511
1520
 
1512
1521
  def lazy_resolve(lazy_class, value_method)
@@ -1640,6 +1649,20 @@ module GraphQL
1640
1649
  end
1641
1650
  end
1642
1651
 
1652
+ # @api private
1653
+ def add_subscription_extension_if_necessary
1654
+ if interpreter? && !defined?(@subscription_extension_added) && subscription && self.subscriptions
1655
+ @subscription_extension_added = true
1656
+ if subscription.singleton_class.ancestors.include?(Subscriptions::SubscriptionRoot)
1657
+ warn("`extend Subscriptions::SubscriptionRoot` is no longer required; you may remove it from #{self}'s `subscription` root type (#{subscription}).")
1658
+ else
1659
+ subscription.fields.each do |name, field|
1660
+ field.extension(Subscriptions::DefaultSubscriptionResolveExtension)
1661
+ end
1662
+ end
1663
+ end
1664
+ end
1665
+
1643
1666
  private
1644
1667
 
1645
1668
  def lazy_methods
@@ -154,6 +154,12 @@ module GraphQL
154
154
  raise ArgumentError, "Couldn't build type for Argument #{@owner.name}.#{name}: #{err.class.name}: #{err.message}", err.backtrace
155
155
  end
156
156
 
157
+ def statically_coercible?
158
+ return @statically_coercible if defined?(@statically_coercible)
159
+
160
+ @statically_coercible = !@prepare.is_a?(String) && !@prepare.is_a?(Symbol)
161
+ end
162
+
157
163
  # Apply the {prepare} configuration to `value`, using methods from `obj`.
158
164
  # Used by the runtime.
159
165
  # @api private