graphql 1.10.10 → 1.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/object_generator.rb +50 -8
  3. data/lib/graphql.rb +3 -3
  4. data/lib/graphql/execution/interpreter.rb +1 -1
  5. data/lib/graphql/execution/interpreter/arguments.rb +1 -5
  6. data/lib/graphql/execution/interpreter/runtime.rb +20 -24
  7. data/lib/graphql/execution/multiplex.rb +1 -2
  8. data/lib/graphql/introspection/schema_type.rb +3 -3
  9. data/lib/graphql/invalid_null_error.rb +18 -0
  10. data/lib/graphql/pagination/connection.rb +13 -6
  11. data/lib/graphql/pagination/connections.rb +5 -4
  12. data/lib/graphql/query.rb +1 -2
  13. data/lib/graphql/schema.rb +26 -3
  14. data/lib/graphql/schema/argument.rb +6 -0
  15. data/lib/graphql/schema/build_from_definition.rb +7 -12
  16. data/lib/graphql/schema/enum.rb +9 -1
  17. data/lib/graphql/schema/field.rb +68 -80
  18. data/lib/graphql/schema/field/connection_extension.rb +2 -1
  19. data/lib/graphql/schema/input_object.rb +1 -3
  20. data/lib/graphql/schema/interface.rb +5 -0
  21. data/lib/graphql/schema/member.rb +1 -0
  22. data/lib/graphql/schema/member/has_arguments.rb +6 -0
  23. data/lib/graphql/schema/member/has_fields.rb +1 -1
  24. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  25. data/lib/graphql/schema/object.rb +7 -0
  26. data/lib/graphql/schema/resolver.rb +14 -0
  27. data/lib/graphql/schema/subscription.rb +1 -1
  28. data/lib/graphql/schema/union.rb +6 -0
  29. data/lib/graphql/schema/warden.rb +0 -1
  30. data/lib/graphql/subscriptions.rb +41 -8
  31. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +49 -5
  32. data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
  33. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  34. data/lib/graphql/subscriptions/event.rb +16 -1
  35. data/lib/graphql/subscriptions/subscription_root.rb +13 -3
  36. data/lib/graphql/tracing.rb +1 -27
  37. data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
  38. data/lib/graphql/tracing/platform_tracing.rb +39 -15
  39. data/lib/graphql/tracing/scout_tracing.rb +11 -0
  40. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  41. data/lib/graphql/types/iso_8601_date.rb +1 -1
  42. data/lib/graphql/types/iso_8601_date_time.rb +17 -13
  43. data/lib/graphql/version.rb +1 -1
  44. metadata +6 -2
@@ -43,9 +43,7 @@ module GraphQL
43
43
  when GraphQL::Language::Nodes::EnumTypeDefinition
44
44
  types[definition.name] = build_enum_type(definition, type_resolver)
45
45
  when GraphQL::Language::Nodes::ObjectTypeDefinition
46
- is_subscription_root = (definition.name == "Subscription" && (schema_definition.nil? || schema_definition.subscription.nil?)) || (schema_definition && (definition.name == schema_definition.subscription))
47
- should_extend_subscription_root = is_subscription_root && interpreter
48
- types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve, extend_subscription_root: should_extend_subscription_root)
46
+ types[definition.name] = build_object_type(definition, type_resolver, default_resolve: default_resolve)
49
47
  when GraphQL::Language::Nodes::InterfaceTypeDefinition
50
48
  types[definition.name] = build_interface_type(definition, type_resolver)
51
49
  when GraphQL::Language::Nodes::UnionTypeDefinition
@@ -204,7 +202,7 @@ module GraphQL
204
202
  end
205
203
  end
206
204
 
207
- def build_object_type(object_type_definition, type_resolver, default_resolve:, extend_subscription_root:)
205
+ def build_object_type(object_type_definition, type_resolver, default_resolve:)
208
206
  builder = self
209
207
  type_def = nil
210
208
  typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
@@ -214,10 +212,6 @@ module GraphQL
214
212
  graphql_name(object_type_definition.name)
215
213
  description(object_type_definition.description)
216
214
  ast_node(object_type_definition)
217
- if extend_subscription_root
218
- # This has to come before `field ...` configurations since it modifies them
219
- extend Subscriptions::SubscriptionRoot
220
- end
221
215
 
222
216
  object_type_definition.interfaces.each do |interface_name|
223
217
  interface_defn = type_resolver.call(interface_name)
@@ -303,7 +297,7 @@ module GraphQL
303
297
 
304
298
  field_definitions.map do |field_definition|
305
299
  type_name = resolve_type_name(field_definition.type)
306
-
300
+ resolve_method_name = "resolve_field_#{field_definition.name}"
307
301
  owner.field(
308
302
  field_definition.name,
309
303
  description: field_definition.description,
@@ -315,14 +309,15 @@ module GraphQL
315
309
  ast_node: field_definition,
316
310
  method_conflict_warning: false,
317
311
  camelize: false,
312
+ resolver_method: resolve_method_name,
318
313
  ) do
319
314
  builder.build_arguments(self, field_definition.arguments, type_resolver)
320
315
 
321
316
  # Don't do this for interfaces
322
317
  if default_resolve
323
- # TODO fragile hack. formalize this API?
324
- define_singleton_method :resolve_field_method do |obj, args, ctx|
325
- default_resolve.call(self, obj.object, args, ctx)
318
+ owner.send(:define_method, resolve_method_name) do |**args|
319
+ field_instance = self.class.get_field(field_definition.name)
320
+ default_resolve.call(field_instance, object, args, context)
326
321
  end
327
322
  end
328
323
  end
@@ -23,6 +23,9 @@ module GraphQL
23
23
  extend GraphQL::Schema::Member::AcceptsDefinition
24
24
  extend GraphQL::Schema::Member::ValidatesInput
25
25
 
26
+ class UnresolvedValueError < GraphQL::EnumType::UnresolvedValueError
27
+ end
28
+
26
29
  class << self
27
30
  # Define a value for this enum
28
31
  # @param graphql_name [String, Symbol] the GraphQL value for this, usually `SCREAMING_CASE`
@@ -94,7 +97,7 @@ module GraphQL
94
97
  if enum_value
95
98
  enum_value.graphql_name
96
99
  else
97
- raise(GraphQL::EnumType::UnresolvedValueError, "Can't resolve enum #{graphql_name} for #{value.inspect}")
100
+ raise(self::UnresolvedValueError, "Can't resolve enum #{graphql_name} for #{value.inspect}")
98
101
  end
99
102
  end
100
103
 
@@ -112,6 +115,11 @@ module GraphQL
112
115
  end
113
116
  end
114
117
 
118
+ def inherited(child_class)
119
+ child_class.const_set(:UnresolvedValueError, Class.new(Schema::Enum::UnresolvedValueError))
120
+ super
121
+ end
122
+
115
123
  private
116
124
 
117
125
  def own_values
@@ -36,9 +36,18 @@ module GraphQL
36
36
  # @return [Symbol] The method on the type to look up
37
37
  attr_reader :resolver_method
38
38
 
39
- # @return [Class] The type that this field belongs to
39
+ # @return [Class] The thing this field was defined on (type, mutation, resolver)
40
40
  attr_accessor :owner
41
41
 
42
+ # @return [Class] The GraphQL type this field belongs to. (For fields defined on mutations, it's the payload type)
43
+ def owner_type
44
+ @owner_type ||= if owner < GraphQL::Schema::Mutation
45
+ owner.payload_type
46
+ else
47
+ owner
48
+ end
49
+ end
50
+
42
51
  # @return [Symbol] the original name of the field, passed in by the user
43
52
  attr_reader :original_name
44
53
 
@@ -191,9 +200,10 @@ module GraphQL
191
200
  # @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
192
201
  # @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
193
202
  # @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
203
+ # @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
194
204
  # @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
195
205
  # @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
196
- def initialize(type: nil, name: nil, owner: nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras: [], extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, arguments: EMPTY_HASH, &definition_block)
206
+ def initialize(type: nil, name: nil, owner: nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, ast_node: nil, extras: [], extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: nil, arguments: EMPTY_HASH, &definition_block)
197
207
  if name.nil?
198
208
  raise ArgumentError, "missing first `name` argument or keyword `name:`"
199
209
  end
@@ -237,8 +247,8 @@ module GraphQL
237
247
  end
238
248
 
239
249
  # TODO: I think non-string/symbol hash keys are wrongly normalized (eg `1` will not work)
240
- method_name = method || hash_key || @underscored_name
241
- resolver_method ||= @underscored_name.to_sym
250
+ method_name = method || hash_key || name_s
251
+ resolver_method ||= name_s.to_sym
242
252
 
243
253
  @method_str = method_name.to_s
244
254
  @method_sym = method_name.to_sym
@@ -251,6 +261,7 @@ module GraphQL
251
261
  @max_page_size = max_page_size == :not_given ? nil : max_page_size
252
262
  @introspection = introspection
253
263
  @extras = extras
264
+ @broadcastable = broadcastable
254
265
  @resolver_class = resolver_class
255
266
  @scope = scope
256
267
  @trace = trace
@@ -295,6 +306,13 @@ module GraphQL
295
306
  end
296
307
  end
297
308
 
309
+ # If true, subscription updates with this field can be shared between viewers
310
+ # @return [Boolean, nil]
311
+ # @see GraphQL::Subscriptions::BroadcastAnalyzer
312
+ def broadcastable?
313
+ @broadcastable
314
+ end
315
+
298
316
  # @param text [String]
299
317
  # @return [String]
300
318
  def description(text = nil)
@@ -534,7 +552,7 @@ module GraphQL
534
552
  @resolve_proc.call(extended_obj, args, ctx)
535
553
  end
536
554
  else
537
- public_send_field(after_obj, ruby_args, ctx)
555
+ public_send_field(after_obj, ruby_args, query_ctx)
538
556
  end
539
557
  else
540
558
  err = GraphQL::UnauthorizedFieldError.new(object: inner_obj, type: obj.class, context: ctx, field: self)
@@ -556,34 +574,13 @@ module GraphQL
556
574
  begin
557
575
  # Unwrap the GraphQL object to get the application object.
558
576
  application_object = object.object
559
- if self.authorized?(application_object, args, ctx)
560
- # Apply field extensions
561
- with_extensions(object, args, ctx) do |extended_obj, extended_args|
562
- field_receiver = if @resolver_class
563
- resolver_obj = if extended_obj.is_a?(GraphQL::Schema::Object)
564
- extended_obj.object
565
- else
566
- extended_obj
567
- end
568
- @resolver_class.new(object: resolver_obj, context: ctx, field: self)
569
- else
570
- extended_obj
571
- end
572
-
573
- if field_receiver.respond_to?(@resolver_method)
574
- # Call the method with kwargs, if there are any
575
- if extended_args.any?
576
- field_receiver.public_send(@resolver_method, **extended_args)
577
- else
578
- field_receiver.public_send(@resolver_method)
579
- end
580
- else
581
- resolve_field_method(field_receiver, extended_args, ctx)
582
- end
577
+ ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
578
+ if is_authorized
579
+ public_send_field(object, args, ctx)
580
+ else
581
+ err = GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
582
+ ctx.schema.unauthorized_field(err)
583
583
  end
584
- else
585
- err = GraphQL::UnauthorizedFieldError.new(object: application_object, type: object.class, context: ctx, field: self)
586
- ctx.schema.unauthorized_field(err)
587
584
  end
588
585
  rescue GraphQL::UnauthorizedFieldError => err
589
586
  err.field ||= self
@@ -595,43 +592,6 @@ module GraphQL
595
592
  err
596
593
  end
597
594
 
598
- # Find a way to resolve this field, checking:
599
- #
600
- # - Hash keys, if the wrapped object is a hash;
601
- # - A method on the wrapped object;
602
- # - Or, raise not implemented.
603
- #
604
- # This can be overridden by defining a method on the object type.
605
- # @param obj [GraphQL::Schema::Object]
606
- # @param ruby_kwargs [Hash<Symbol => Object>]
607
- # @param ctx [GraphQL::Query::Context]
608
- def resolve_field_method(obj, ruby_kwargs, ctx)
609
- if obj.object.is_a?(Hash)
610
- inner_object = obj.object
611
- if inner_object.key?(@method_sym)
612
- inner_object[@method_sym]
613
- else
614
- inner_object[@method_str]
615
- end
616
- elsif obj.object.respond_to?(@method_sym)
617
- if ruby_kwargs.any?
618
- obj.object.public_send(@method_sym, **ruby_kwargs)
619
- else
620
- obj.object.public_send(@method_sym)
621
- end
622
- else
623
- raise <<-ERR
624
- Failed to implement #{@owner.graphql_name}.#{@name}, tried:
625
-
626
- - `#{obj.class}##{@resolver_method}`, which did not exist
627
- - `#{obj.object.class}##{@method_sym}`, which did not exist
628
- - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
629
-
630
- To implement this field, define one of the methods above (and check for typos)
631
- ERR
632
- end
633
- end
634
-
635
595
  # @param ctx [GraphQL::Query::Context::FieldResolutionContext]
636
596
  def fetch_extra(extra_name, ctx)
637
597
  if extra_name != :path && extra_name != :ast_node && respond_to?(extra_name)
@@ -702,24 +662,52 @@ module GraphQL
702
662
  end
703
663
  end
704
664
 
705
- def public_send_field(obj, ruby_kwargs, field_ctx)
706
- query_ctx = field_ctx.query.context
707
- with_extensions(obj, ruby_kwargs, query_ctx) do |extended_obj, extended_args|
665
+ def public_send_field(unextended_obj, unextended_ruby_kwargs, query_ctx)
666
+ with_extensions(unextended_obj, unextended_ruby_kwargs, query_ctx) do |obj, ruby_kwargs|
708
667
  if @resolver_class
709
- if extended_obj.is_a?(GraphQL::Schema::Object)
710
- extended_obj = extended_obj.object
668
+ if obj.is_a?(GraphQL::Schema::Object)
669
+ obj = obj.object
711
670
  end
712
- extended_obj = @resolver_class.new(object: extended_obj, context: query_ctx, field: self)
671
+ obj = @resolver_class.new(object: obj, context: query_ctx, field: self)
713
672
  end
714
673
 
715
- if extended_obj.respond_to?(@resolver_method)
716
- if extended_args.any?
717
- extended_obj.public_send(@resolver_method, **extended_args)
674
+ # Find a way to resolve this field, checking:
675
+ #
676
+ # - A method on the type instance;
677
+ # - Hash keys, if the wrapped object is a hash;
678
+ # - A method on the wrapped object;
679
+ # - Or, raise not implemented.
680
+ #
681
+ if obj.respond_to?(@resolver_method)
682
+ # Call the method with kwargs, if there are any
683
+ if ruby_kwargs.any?
684
+ obj.public_send(@resolver_method, **ruby_kwargs)
685
+ else
686
+ obj.public_send(@resolver_method)
687
+ end
688
+ elsif obj.object.is_a?(Hash)
689
+ inner_object = obj.object
690
+ if inner_object.key?(@method_sym)
691
+ inner_object[@method_sym]
718
692
  else
719
- extended_obj.public_send(@resolver_method)
693
+ inner_object[@method_str]
694
+ end
695
+ elsif obj.object.respond_to?(@method_sym)
696
+ if ruby_kwargs.any?
697
+ obj.object.public_send(@method_sym, **ruby_kwargs)
698
+ else
699
+ obj.object.public_send(@method_sym)
720
700
  end
721
701
  else
722
- resolve_field_method(extended_obj, extended_args, query_ctx)
702
+ raise <<-ERR
703
+ Failed to implement #{@owner.graphql_name}.#{@name}, tried:
704
+
705
+ - `#{obj.class}##{@resolver_method}`, which did not exist
706
+ - `#{obj.object.class}##{@method_sym}`, which did not exist
707
+ - Looking up hash key `#{@method_sym.inspect}` or `#{@method_str.inspect}` on `#{obj.object}`, but it wasn't a Hash
708
+
709
+ To implement this field, define one of the methods above (and check for typos)
710
+ ERR
723
711
  end
724
712
  end
725
713
  end
@@ -31,6 +31,7 @@ module GraphQL
31
31
  elsif value.is_a?(GraphQL::Pagination::Connection)
32
32
  # update the connection with some things that may not have been provided
33
33
  value.context ||= context
34
+ value.parent ||= object.object
34
35
  value.first_value ||= arguments[:first]
35
36
  value.after_value ||= arguments[:after]
36
37
  value.last_value ||= arguments[:last]
@@ -41,7 +42,7 @@ module GraphQL
41
42
  value
42
43
  elsif context.schema.new_connections?
43
44
  wrappers = context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
44
- context.schema.connections.wrap(field, value, arguments, context, wrappers: wrappers)
45
+ context.schema.connections.wrap(field, object.object, value, arguments, context, wrappers: wrappers)
45
46
  else
46
47
  if object.is_a?(GraphQL::Schema::Object)
47
48
  object = object.object
@@ -21,10 +21,8 @@ module GraphQL
21
21
  @ruby_style_hash = @arguments.to_kwargs
22
22
  end
23
23
  # Apply prepares, not great to have it duplicated here.
24
- @arguments_by_keyword = {}
25
24
  maybe_lazies = []
26
- self.class.arguments.each do |name, arg_defn|
27
- @arguments_by_keyword[arg_defn.keyword] = arg_defn
25
+ self.class.arguments.each_value do |arg_defn|
28
26
  ruby_kwargs_key = arg_defn.keyword
29
27
 
30
28
  if @ruby_style_hash.key?(ruby_kwargs_key)
@@ -14,6 +14,7 @@ module GraphQL
14
14
  include GraphQL::Schema::Member::RelayShortcuts
15
15
  include GraphQL::Schema::Member::Scoped
16
16
  include GraphQL::Schema::Member::HasAstNode
17
+ include GraphQL::Schema::Member::HasUnresolvedTypeError
17
18
 
18
19
  # Methods defined in this block will be:
19
20
  # - Added as class methods to this interface
@@ -74,6 +75,10 @@ module GraphQL
74
75
  if overridden_graphql_name
75
76
  child_class.graphql_name(overridden_graphql_name)
76
77
  end
78
+ # If interfaces are mixed into each other, only define this class once
79
+ if !child_class.const_defined?(:UnresolvedTypeError, false)
80
+ add_unresolved_type_error(child_class)
81
+ end
77
82
  elsif child_class < GraphQL::Schema::Object
78
83
  # This is being included into an object type, make sure it's using `implements(...)`
79
84
  backtrace_line = caller(0, 10).find { |line| line.include?("schema/object.rb") && line.include?("in `implements'")}
@@ -5,6 +5,7 @@ require 'graphql/schema/member/cached_graphql_definition'
5
5
  require 'graphql/schema/member/graphql_type_names'
6
6
  require 'graphql/schema/member/has_ast_node'
7
7
  require 'graphql/schema/member/has_path'
8
+ require 'graphql/schema/member/has_unresolved_type_error'
8
9
  require 'graphql/schema/member/relay_shortcuts'
9
10
  require 'graphql/schema/member/scoped'
10
11
  require 'graphql/schema/member/type_system_helpers'
@@ -135,6 +135,12 @@ module GraphQL
135
135
  end
136
136
  end
137
137
 
138
+ def arguments_statically_coercible?
139
+ return @arguments_statically_coercible if defined?(@arguments_statically_coercible)
140
+
141
+ @arguments_statically_coercible = arguments.each_value.all?(&:statically_coercible?)
142
+ end
143
+
138
144
  module ArgumentClassAccessor
139
145
  def argument_class(new_arg_class = nil)
140
146
  if new_arg_class
@@ -47,7 +47,7 @@ module GraphQL
47
47
  # A list of GraphQL-Ruby keywords.
48
48
  #
49
49
  # @api private
50
- GRAPHQL_RUBY_KEYWORDS = [:context, :object, :method]
50
+ GRAPHQL_RUBY_KEYWORDS = [:context, :object, :method, :raw_value]
51
51
 
52
52
  # A list of field names that we should advise users to pick a different
53
53
  # resolve method name.
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ class Schema
5
+ class Member
6
+ # Set up a type-specific error to make debugging & bug tracker integration better
7
+ module HasUnresolvedTypeError
8
+ private
9
+ def add_unresolved_type_error(child_class)
10
+ child_class.const_set(:UnresolvedTypeError, Class.new(GraphQL::UnresolvedTypeError))
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -71,6 +71,13 @@ module GraphQL
71
71
  end
72
72
 
73
73
  class << self
74
+ # Set up a type-specific invalid null error to use when this object's non-null fields wrongly return `nil`.
75
+ # It should help with debugging and bug tracker integrations.
76
+ def inherited(child_class)
77
+ child_class.const_set(:InvalidNullError, GraphQL::InvalidNullError.subclass_for(child_class))
78
+ super
79
+ end
80
+
74
81
  def implements(*new_interfaces, **options)
75
82
  new_memberships = []
76
83
  new_interfaces.each do |int|
@@ -250,6 +250,19 @@ module GraphQL
250
250
  @complexity || (superclass.respond_to?(:complexity) ? superclass.complexity : 1)
251
251
  end
252
252
 
253
+ def broadcastable(new_broadcastable)
254
+ @broadcastable = new_broadcastable
255
+ end
256
+
257
+ # @return [Boolean, nil]
258
+ def broadcastable?
259
+ if defined?(@broadcastable)
260
+ @broadcastable
261
+ else
262
+ (superclass.respond_to?(:broadcastable?) ? superclass.broadcastable? : nil)
263
+ end
264
+ end
265
+
253
266
  def field_options
254
267
  {
255
268
  type: type_expr,
@@ -261,6 +274,7 @@ module GraphQL
261
274
  null: null,
262
275
  complexity: complexity,
263
276
  extensions: extensions,
277
+ broadcastable: broadcastable?,
264
278
  }
265
279
  end
266
280
 
@@ -93,11 +93,11 @@ module GraphQL
93
93
  raise UnsubscribedError
94
94
  end
95
95
 
96
+ READING_SCOPE = ::Object.new
96
97
  # Call this method to provide a new subscription_scope; OR
97
98
  # call it without an argument to get the subscription_scope
98
99
  # @param new_scope [Symbol]
99
100
  # @return [Symbol]
100
- READING_SCOPE = ::Object.new
101
101
  def self.subscription_scope(new_scope = READING_SCOPE)
102
102
  if new_scope != READING_SCOPE
103
103
  @subscription_scope = new_scope