actioncable 7.1.3.4 → 7.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -133
  3. data/app/assets/javascripts/action_cable.js +3 -3
  4. data/app/assets/javascripts/actioncable.esm.js +3 -3
  5. data/app/assets/javascripts/actioncable.js +3 -3
  6. data/lib/action_cable/channel/base.rb +98 -86
  7. data/lib/action_cable/channel/broadcasting.rb +25 -18
  8. data/lib/action_cable/channel/callbacks.rb +27 -25
  9. data/lib/action_cable/channel/naming.rb +9 -8
  10. data/lib/action_cable/channel/periodic_timers.rb +7 -7
  11. data/lib/action_cable/channel/streams.rb +77 -64
  12. data/lib/action_cable/channel/test_case.rb +112 -86
  13. data/lib/action_cable/connection/authorization.rb +4 -1
  14. data/lib/action_cable/connection/base.rb +53 -38
  15. data/lib/action_cable/connection/callbacks.rb +20 -18
  16. data/lib/action_cable/connection/client_socket.rb +3 -1
  17. data/lib/action_cable/connection/identification.rb +9 -5
  18. data/lib/action_cable/connection/internal_channel.rb +5 -2
  19. data/lib/action_cable/connection/message_buffer.rb +4 -1
  20. data/lib/action_cable/connection/stream.rb +2 -0
  21. data/lib/action_cable/connection/stream_event_loop.rb +4 -3
  22. data/lib/action_cable/connection/subscriptions.rb +6 -3
  23. data/lib/action_cable/connection/tagged_logger_proxy.rb +7 -4
  24. data/lib/action_cable/connection/test_case.rb +66 -56
  25. data/lib/action_cable/connection/web_socket.rb +10 -8
  26. data/lib/action_cable/deprecator.rb +2 -0
  27. data/lib/action_cable/engine.rb +5 -3
  28. data/lib/action_cable/gem_version.rb +6 -4
  29. data/lib/action_cable/helpers/action_cable_helper.rb +21 -19
  30. data/lib/action_cable/remote_connections.rb +19 -16
  31. data/lib/action_cable/server/base.rb +27 -15
  32. data/lib/action_cable/server/broadcasting.rb +23 -17
  33. data/lib/action_cable/server/configuration.rb +17 -14
  34. data/lib/action_cable/server/connections.rb +11 -5
  35. data/lib/action_cable/server/worker/active_record_connection_management.rb +2 -0
  36. data/lib/action_cable/server/worker.rb +4 -2
  37. data/lib/action_cable/subscription_adapter/async.rb +2 -0
  38. data/lib/action_cable/subscription_adapter/base.rb +2 -0
  39. data/lib/action_cable/subscription_adapter/channel_prefix.rb +2 -0
  40. data/lib/action_cable/subscription_adapter/inline.rb +2 -0
  41. data/lib/action_cable/subscription_adapter/postgresql.rb +4 -2
  42. data/lib/action_cable/subscription_adapter/redis.rb +5 -2
  43. data/lib/action_cable/subscription_adapter/subscriber_map.rb +2 -0
  44. data/lib/action_cable/subscription_adapter/test.rb +8 -5
  45. data/lib/action_cable/test_case.rb +2 -0
  46. data/lib/action_cable/test_helper.rb +51 -52
  47. data/lib/action_cable/version.rb +3 -1
  48. data/lib/action_cable.rb +13 -7
  49. data/lib/rails/generators/channel/channel_generator.rb +4 -2
  50. data/lib/rails/generators/test_unit/channel_generator.rb +2 -0
  51. metadata +13 -13
  52. /data/lib/rails/generators/channel/templates/application_cable/{channel.rb → channel.rb.tt} +0 -0
  53. /data/lib/rails/generators/channel/templates/application_cable/{connection.rb → connection.rb.tt} +0 -0
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module Server
5
- # = Action Cable \Server \Connections
7
+ # # Action Cable Server Connections
6
8
  #
7
- # Collection class for all the connections that have been established on this specific server. Remember, usually you'll run many Action Cable servers, so
8
- # you can't use this collection as a full list of all of the connections established against your application. Instead, use RemoteConnections for that.
9
+ # Collection class for all the connections that have been established on this
10
+ # specific server. Remember, usually you'll run many Action Cable servers, so
11
+ # you can't use this collection as a full list of all of the connections
12
+ # established against your application. Instead, use RemoteConnections for that.
9
13
  module Connections # :nodoc:
10
14
  BEAT_INTERVAL = 3
11
15
 
@@ -21,8 +25,10 @@ module ActionCable
21
25
  connections.delete connection
22
26
  end
23
27
 
24
- # WebSocket connection implementations differ on when they'll mark a connection as stale. We basically never want a connection to go stale, as you
25
- # then can't rely on being able to communicate with the connection. To solve this, a 3 second heartbeat runs on all connections. If the beat fails, we automatically
28
+ # WebSocket connection implementations differ on when they'll mark a connection
29
+ # as stale. We basically never want a connection to go stale, as you then can't
30
+ # rely on being able to communicate with the connection. To solve this, a 3
31
+ # second heartbeat runs on all connections. If the beat fails, we automatically
26
32
  # disconnect.
27
33
  def setup_heartbeat_timer
28
34
  @heartbeat_timer ||= event_loop.timer(BEAT_INTERVAL) do
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module Server
5
7
  class Worker
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/callbacks"
4
6
  require "active_support/core_ext/module/attribute_accessors_per_thread"
5
7
  require "concurrent"
@@ -25,8 +27,8 @@ module ActionCable
25
27
  )
26
28
  end
27
29
 
28
- # Stop processing work: any work that has not already started
29
- # running will be discarded from the queue
30
+ # Stop processing work: any work that has not already started running will be
31
+ # discarded from the queue
30
32
  def halt
31
33
  @executor.shutdown
32
34
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module SubscriptionAdapter
5
7
  class Async < Inline # :nodoc:
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module SubscriptionAdapter
5
7
  class Base
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module SubscriptionAdapter
5
7
  module ChannelPrefix # :nodoc:
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module SubscriptionAdapter
5
7
  class Inline < Base # :nodoc:
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  gem "pg", "~> 1.1"
4
6
  require "pg"
5
7
  require "openssl"
@@ -34,8 +36,8 @@ module ActionCable
34
36
 
35
37
  def with_subscriptions_connection(&block) # :nodoc:
36
38
  ar_conn = ActiveRecord::Base.connection_pool.checkout.tap do |conn|
37
- # Action Cable is taking ownership over this database connection, and
38
- # will perform the necessary cleanup tasks
39
+ # Action Cable is taking ownership over this database connection, and will
40
+ # perform the necessary cleanup tasks
39
41
  ActiveRecord::Base.connection_pool.remove(conn)
40
42
  end
41
43
  pg_conn = ar_conn.raw_connection
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  gem "redis", ">= 4", "< 6"
4
6
  require "redis"
5
7
 
@@ -10,8 +12,9 @@ module ActionCable
10
12
  class Redis < Base # :nodoc:
11
13
  prepend ChannelPrefix
12
14
 
13
- # Overwrite this factory method for Redis connections if you want to use a different Redis library than the redis gem.
14
- # This is needed, for example, when using Makara proxies for distributed Redis.
15
+ # Overwrite this factory method for Redis connections if you want to use a
16
+ # different Redis library than the redis gem. This is needed, for example, when
17
+ # using Makara proxies for distributed Redis.
15
18
  cattr_accessor :redis_connector, default: ->(config) do
16
19
  ::Redis.new(config.except(:adapter, :channel_prefix))
17
20
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module SubscriptionAdapter
5
7
  class SubscriberMap
@@ -1,16 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module SubscriptionAdapter
5
- # == \Test adapter for Action Cable
7
+ # ## Test adapter for Action Cable
6
8
  #
7
9
  # The test adapter should be used only in testing. Along with
8
- # ActionCable::TestHelper it makes a great tool to test your \Rails application.
10
+ # ActionCable::TestHelper it makes a great tool to test your Rails application.
9
11
  #
10
- # To use the test adapter set +adapter+ value to +test+ in your +config/cable.yml+ file.
12
+ # To use the test adapter set `adapter` value to `test` in your
13
+ # `config/cable.yml` file.
11
14
  #
12
- # NOTE: +Test+ adapter extends the +ActionCable::SubscriptionAdapter::Async+ adapter,
13
- # so it could be used in system tests too.
15
+ # NOTE: `Test` adapter extends the `ActionCable::SubscriptionAdapter::Async`
16
+ # adapter, so it could be used in system tests too.
14
17
  class Test < Async
15
18
  def broadcast(channel, payload)
16
19
  broadcasts(channel) << payload
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/test_case"
4
6
 
5
7
  module ActionCable
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  # Provides helper methods for testing Action Cable broadcasting
5
7
  module TestHelper
@@ -18,33 +20,30 @@ module ActionCable
18
20
  ActionCable.server.instance_variable_set(:@pubsub, @old_pubsub_adapter)
19
21
  end
20
22
 
21
- # Asserts that the number of broadcasted messages to the stream matches the given number.
22
- #
23
- # def test_broadcasts
24
- # assert_broadcasts 'messages', 0
25
- # ActionCable.server.broadcast 'messages', { text: 'hello' }
26
- # assert_broadcasts 'messages', 1
27
- # ActionCable.server.broadcast 'messages', { text: 'world' }
28
- # assert_broadcasts 'messages', 2
29
- # end
30
- #
31
- # If a block is passed, that block should cause the specified number of
32
- # messages to be broadcasted. It returns the messages that were broadcasted.
23
+ # Asserts that the number of broadcasted messages to the stream matches the
24
+ # given number.
33
25
  #
34
- # def test_broadcasts_again
35
- # message = assert_broadcasts('messages', 1) do
26
+ # def test_broadcasts
27
+ # assert_broadcasts 'messages', 0
36
28
  # ActionCable.server.broadcast 'messages', { text: 'hello' }
29
+ # assert_broadcasts 'messages', 1
30
+ # ActionCable.server.broadcast 'messages', { text: 'world' }
31
+ # assert_broadcasts 'messages', 2
37
32
  # end
38
- # assert_equal({ text: 'hello' }, message)
39
33
  #
40
- # messages = assert_broadcasts('messages', 2) do
41
- # ActionCable.server.broadcast 'messages', { text: 'hi' }
42
- # ActionCable.server.broadcast 'messages', { text: 'how are you?' }
34
+ # If a block is passed, that block should cause the specified number of messages
35
+ # to be broadcasted.
36
+ #
37
+ # def test_broadcasts_again
38
+ # assert_broadcasts('messages', 1) do
39
+ # ActionCable.server.broadcast 'messages', { text: 'hello' }
40
+ # end
41
+ #
42
+ # assert_broadcasts('messages', 2) do
43
+ # ActionCable.server.broadcast 'messages', { text: 'hi' }
44
+ # ActionCable.server.broadcast 'messages', { text: 'how are you?' }
45
+ # end
43
46
  # end
44
- # assert_equal 2, messages.length
45
- # assert_equal({ text: 'hi' }, messages.first)
46
- # assert_equal({ text: 'how are you?' }, messages.last)
47
- # end
48
47
  #
49
48
  def assert_broadcasts(stream, number, &block)
50
49
  if block_given?
@@ -60,23 +59,23 @@ module ActionCable
60
59
 
61
60
  # Asserts that no messages have been sent to the stream.
62
61
  #
63
- # def test_no_broadcasts
64
- # assert_no_broadcasts 'messages'
65
- # ActionCable.server.broadcast 'messages', { text: 'hi' }
66
- # assert_broadcasts 'messages', 1
67
- # end
62
+ # def test_no_broadcasts
63
+ # assert_no_broadcasts 'messages'
64
+ # ActionCable.server.broadcast 'messages', { text: 'hi' }
65
+ # assert_broadcasts 'messages', 1
66
+ # end
68
67
  #
69
68
  # If a block is passed, that block should not cause any message to be sent.
70
69
  #
71
- # def test_broadcasts_again
72
- # assert_no_broadcasts 'messages' do
73
- # # No job messages should be sent from this block
70
+ # def test_broadcasts_again
71
+ # assert_no_broadcasts 'messages' do
72
+ # # No job messages should be sent from this block
73
+ # end
74
74
  # end
75
- # end
76
75
  #
77
76
  # Note: This assertion is simply a shortcut for:
78
77
  #
79
- # assert_broadcasts 'messages', 0, &block
78
+ # assert_broadcasts 'messages', 0, &block
80
79
  #
81
80
  def assert_no_broadcasts(stream, &block)
82
81
  assert_broadcasts stream, 0, &block
@@ -84,15 +83,15 @@ module ActionCable
84
83
 
85
84
  # Returns the messages that are broadcasted in the block.
86
85
  #
87
- # def test_broadcasts
88
- # messages = capture_broadcasts('messages') do
89
- # ActionCable.server.broadcast 'messages', { text: 'hi' }
90
- # ActionCable.server.broadcast 'messages', { text: 'how are you?' }
86
+ # def test_broadcasts
87
+ # messages = capture_broadcasts('messages') do
88
+ # ActionCable.server.broadcast 'messages', { text: 'hi' }
89
+ # ActionCable.server.broadcast 'messages', { text: 'how are you?' }
90
+ # end
91
+ # assert_equal 2, messages.length
92
+ # assert_equal({ text: 'hi' }, messages.first)
93
+ # assert_equal({ text: 'how are you?' }, messages.last)
91
94
  # end
92
- # assert_equal 2, messages.length
93
- # assert_equal({ text: 'hi' }, messages.first)
94
- # assert_equal({ text: 'how are you?' }, messages.last)
95
- # end
96
95
  #
97
96
  def capture_broadcasts(stream, &block)
98
97
  new_broadcasts_from(broadcasts(stream), stream, "capture_broadcasts", &block).map { |m| ActiveSupport::JSON.decode(m) }
@@ -100,23 +99,23 @@ module ActionCable
100
99
 
101
100
  # Asserts that the specified message has been sent to the stream.
102
101
  #
103
- # def test_assert_transmitted_message
104
- # ActionCable.server.broadcast 'messages', text: 'hello'
105
- # assert_broadcast_on('messages', text: 'hello')
106
- # end
102
+ # def test_assert_transmitted_message
103
+ # ActionCable.server.broadcast 'messages', text: 'hello'
104
+ # assert_broadcast_on('messages', text: 'hello')
105
+ # end
107
106
  #
108
- # If a block is passed, that block should cause a message with the specified data to be sent.
107
+ # If a block is passed, that block should cause a message with the specified
108
+ # data to be sent.
109
109
  #
110
- # def test_assert_broadcast_on_again
111
- # assert_broadcast_on('messages', text: 'hello') do
112
- # ActionCable.server.broadcast 'messages', text: 'hello'
110
+ # def test_assert_broadcast_on_again
111
+ # assert_broadcast_on('messages', text: 'hello') do
112
+ # ActionCable.server.broadcast 'messages', text: 'hello'
113
+ # end
113
114
  # end
114
- # end
115
115
  #
116
116
  def assert_broadcast_on(stream, data, &block)
117
- # Encode to JSON and back–we want to use this value to compare
118
- # with decoded JSON.
119
- # Comparing JSON strings doesn't work due to the order if the keys.
117
+ # Encode to JSON and back–we want to use this value to compare with decoded
118
+ # JSON. Comparing JSON strings doesn't work due to the order if the keys.
120
119
  serialized_msg =
121
120
  ActiveSupport::JSON.decode(ActiveSupport::JSON.encode(data))
122
121
 
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require_relative "gem_version"
4
6
 
5
7
  module ActionCable
6
- # Returns the currently loaded version of Action Cable as a +Gem::Version+.
8
+ # Returns the currently loaded version of Action Cable as a `Gem::Version`.
7
9
  def self.version
8
10
  gem_version
9
11
  end
data/lib/action_cable.rb CHANGED
@@ -27,24 +27,30 @@ require "active_support"
27
27
  require "active_support/rails"
28
28
  require "zeitwerk"
29
29
 
30
+ # We compute lib this way instead of using __dir__ because __dir__ gives a real
31
+ # path, while __FILE__ honors symlinks. If the gem is stored under a symlinked
32
+ # directory, this matters.
33
+ lib = File.dirname(__FILE__)
34
+
30
35
  Zeitwerk::Loader.for_gem.tap do |loader|
31
36
  loader.ignore(
32
- "#{__dir__}/rails", # Contains generators, templates, docs, etc.
33
- "#{__dir__}/action_cable/gem_version.rb",
34
- "#{__dir__}/action_cable/deprecator.rb",
37
+ "#{lib}/rails", # Contains generators, templates, docs, etc.
38
+ "#{lib}/action_cable/gem_version.rb",
39
+ "#{lib}/action_cable/version.rb",
40
+ "#{lib}/action_cable/deprecator.rb",
35
41
  )
36
42
 
37
43
  loader.do_not_eager_load(
38
- "#{__dir__}/action_cable/subscription_adapter", # Adapters are required and loaded on demand.
39
- "#{__dir__}/action_cable/test_helper.rb",
40
- Dir["#{__dir__}/action_cable/**/test_case.rb"]
44
+ "#{lib}/action_cable/subscription_adapter", # Adapters are required and loaded on demand.
45
+ "#{lib}/action_cable/test_helper.rb",
46
+ Dir["#{lib}/action_cable/**/test_case.rb"]
41
47
  )
42
48
 
43
49
  loader.inflector.inflect("postgresql" => "PostgreSQL")
44
50
  end.setup
45
51
 
46
52
  # :markup: markdown
47
- # :include: actioncable/README.md
53
+ # :include: ../README.md
48
54
  module ActionCable
49
55
  require_relative "action_cable/version"
50
56
  require_relative "action_cable/deprecator"
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module Rails
4
6
  module Generators
5
7
  class ChannelGenerator < NamedBase
@@ -103,8 +105,8 @@ pin_all_from "app/javascript/channels", under: "channels"
103
105
  end
104
106
 
105
107
  def using_bun?
106
- # Cannot assume bun.lockb has been generated yet so we look for
107
- # a file known to be generated by the jsbundling-rails gem
108
+ # Cannot assume bun.lockb has been generated yet so we look for a file known to
109
+ # be generated by the jsbundling-rails gem
108
110
  @using_bun ||= using_js_runtime? && root.join("bun.config.js").exist?
109
111
  end
110
112
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module TestUnit
4
6
  module Generators
5
7
  class ChannelGenerator < ::Rails::Generators::NamedBase
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actioncable
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.3.4
4
+ version: 7.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pratik Naik
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-06-04 00:00:00.000000000 Z
12
+ date: 2024-08-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -17,28 +17,28 @@ dependencies:
17
17
  requirements:
18
18
  - - '='
19
19
  - !ruby/object:Gem::Version
20
- version: 7.1.3.4
20
+ version: 7.2.0
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - '='
26
26
  - !ruby/object:Gem::Version
27
- version: 7.1.3.4
27
+ version: 7.2.0
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: actionpack
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - '='
33
33
  - !ruby/object:Gem::Version
34
- version: 7.1.3.4
34
+ version: 7.2.0
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - '='
40
40
  - !ruby/object:Gem::Version
41
- version: 7.1.3.4
41
+ version: 7.2.0
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: nio4r
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -141,8 +141,8 @@ files:
141
141
  - lib/action_cable/version.rb
142
142
  - lib/rails/generators/channel/USAGE
143
143
  - lib/rails/generators/channel/channel_generator.rb
144
- - lib/rails/generators/channel/templates/application_cable/channel.rb
145
- - lib/rails/generators/channel/templates/application_cable/connection.rb
144
+ - lib/rails/generators/channel/templates/application_cable/channel.rb.tt
145
+ - lib/rails/generators/channel/templates/application_cable/connection.rb.tt
146
146
  - lib/rails/generators/channel/templates/channel.rb.tt
147
147
  - lib/rails/generators/channel/templates/javascript/channel.js.tt
148
148
  - lib/rails/generators/channel/templates/javascript/consumer.js.tt
@@ -154,10 +154,10 @@ licenses:
154
154
  - MIT
155
155
  metadata:
156
156
  bug_tracker_uri: https://github.com/rails/rails/issues
157
- changelog_uri: https://github.com/rails/rails/blob/v7.1.3.4/actioncable/CHANGELOG.md
158
- documentation_uri: https://api.rubyonrails.org/v7.1.3.4/
157
+ changelog_uri: https://github.com/rails/rails/blob/v7.2.0/actioncable/CHANGELOG.md
158
+ documentation_uri: https://api.rubyonrails.org/v7.2.0/
159
159
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
160
- source_code_uri: https://github.com/rails/rails/tree/v7.1.3.4/actioncable
160
+ source_code_uri: https://github.com/rails/rails/tree/v7.2.0/actioncable
161
161
  rubygems_mfa_required: 'true'
162
162
  post_install_message:
163
163
  rdoc_options: []
@@ -167,14 +167,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
167
167
  requirements:
168
168
  - - ">="
169
169
  - !ruby/object:Gem::Version
170
- version: 2.7.0
170
+ version: 3.1.0
171
171
  required_rubygems_version: !ruby/object:Gem::Requirement
172
172
  requirements:
173
173
  - - ">="
174
174
  - !ruby/object:Gem::Version
175
175
  version: '0'
176
176
  requirements: []
177
- rubygems_version: 3.3.27
177
+ rubygems_version: 3.5.11
178
178
  signing_key:
179
179
  specification_version: 4
180
180
  summary: WebSocket framework for Rails.