actioncable 7.2.2.1 → 8.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 720238323d1411f0913bcc9b65ac89d955c4fc4e708bbab5b5dd1c0c47c4cf00
4
- data.tar.gz: 10a5cd05102adeda05b151a39c40183bc55c2c55c2c63dca5a13d642fcf49f58
3
+ metadata.gz: d8d20cfcdba9f7fb62b19e8fe87bd76f7bec5926eb555dbec20770c07cda1f69
4
+ data.tar.gz: b973eb7f4378d5545d691929ce532497a5c1bf9b51b750e2829ef4d27001b5ca
5
5
  SHA512:
6
- metadata.gz: '0639a73b1efc8078fe167814911d5694e76781f618ac7fe5bb34ae8448ab495b60f598a76c6a0e8d7c9f45d9674d19564ad14eaae0ccaaf1f75b441d1318d7c8'
7
- data.tar.gz: 4988a92b2c683bc86c28d60be1d2f92d1efe36bc5d33f814da55ac7328af60597fb0313321aa663b6d5632ecd565661725d12bf1238fa48a153b18d538e6e08e
6
+ metadata.gz: 8ab7982858d2e56416eeebe5cee0802931e4e22229b5f60532932b0da160fbd70b1ca49800628570dc24603fb9f677885ae6aed3d8588e2450935c426b153065
7
+ data.tar.gz: a3277654e245484ddf50c17fe71034ae1811fd1e2520d1cc9fea1c19c12edf5ca5eb016b67ee37bc3a0064b9f33248bd36f2ea9bd790beb19ea6f92548df1139
data/CHANGELOG.md CHANGED
@@ -1,68 +1,21 @@
1
- ## Rails 7.2.2.1 (December 10, 2024) ##
1
+ ## Rails 8.1.2 (January 08, 2026) ##
2
2
 
3
3
  * No changes.
4
4
 
5
5
 
6
- ## Rails 7.2.2 (October 30, 2024) ##
6
+ ## Rails 8.1.1 (October 28, 2025) ##
7
7
 
8
8
  * No changes.
9
9
 
10
10
 
11
- ## Rails 7.2.1.2 (October 23, 2024) ##
11
+ ## Rails 8.1.0 (October 22, 2025) ##
12
12
 
13
- * No changes.
14
-
15
-
16
- ## Rails 7.2.1.1 (October 15, 2024) ##
17
-
18
- * No changes.
19
-
20
-
21
- ## Rails 7.2.1 (August 22, 2024) ##
22
-
23
- * No changes.
24
-
25
-
26
- ## Rails 7.2.0 (August 09, 2024) ##
27
-
28
- * Bring `ActionCable::Connection::TestCookieJar` in alignment with `ActionDispatch::Cookies::CookieJar` in regards to setting the cookie value.
29
-
30
- Before:
31
-
32
- ```ruby
33
- cookies[:foo] = { value: "bar" }
34
- puts cookies[:foo] # => { value: "bar" }
35
- ```
36
-
37
- After:
38
-
39
- ```ruby
40
- cookies[:foo] = { value: "bar" }
41
- puts cookies[:foo] # => "bar"
42
- ```
43
-
44
- *Justin Ko*
45
-
46
- * Record ping on every Action Cable message.
47
-
48
- Previously only `ping` and `welcome` message types were keeping the connection active.
49
- Now every Action Cable message updates the `pingedAt` value, preventing the connection
50
- from being marked as stale.
51
-
52
- *yauhenininjia*
53
-
54
- * Add two new assertion methods for Action Cable test cases: `assert_has_no_stream`
55
- and `assert_has_no_stream_for`.
13
+ * Allow passing composite channels to `ActionCable::Channel#stream_for` – e.g. `stream_for [ group, group.owner ]`
56
14
 
57
- These methods can be used to assert that a stream has been stopped, e.g. via
58
- `stop_stream` or `stop_stream_for`. They complement the already existing
59
- `assert_has_stream` and `assert_has_stream_for` methods.
15
+ *hey-leon*
60
16
 
61
- ```ruby
62
- assert_has_no_stream "messages"
63
- assert_has_no_stream_for User.find(42)
64
- ```
17
+ * Allow setting nil as subscription connection identifier for Redis.
65
18
 
66
- *Sebastian Pöll*, *Junichi Sato*
19
+ *Nguyen Nguyen*
67
20
 
68
- Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/actioncable/CHANGELOG.md) for previous changes.
21
+ Please check [8-0-stable](https://github.com/rails/rails/blob/8-0-stable/actioncable/CHANGELOG.md) for previous changes.
data/README.md CHANGED
@@ -19,6 +19,6 @@ Bug reports for the Ruby on \Rails project can be filed here:
19
19
 
20
20
  * https://github.com/rails/rails/issues
21
21
 
22
- Feature requests should be discussed on the rails-core mailing list here:
22
+ Feature requests should be discussed on the rubyonrails-core forum here:
23
23
 
24
24
  * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -2,7 +2,6 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
- require "set"
6
5
  require "active_support/rescuable"
7
6
  require "active_support/parameter_filter"
8
7
 
@@ -133,7 +132,11 @@ module ActionCable
133
132
  # Except for public instance methods of Base and its ancestors
134
133
  ActionCable::Channel::Base.public_instance_methods(true) +
135
134
  # Be sure to include shadowed public instance methods of this class
136
- public_instance_methods(false)).uniq.map(&:to_s)
135
+ public_instance_methods(false) -
136
+ # Except the internal methods
137
+ internal_methods).uniq
138
+
139
+ methods.map!(&:name)
137
140
  methods.to_set
138
141
  end
139
142
  end
@@ -151,6 +154,10 @@ module ActionCable
151
154
  super
152
155
  clear_action_methods!
153
156
  end
157
+
158
+ def internal_methods
159
+ super
160
+ end
154
161
  end
155
162
 
156
163
  def initialize(connection, identifier, params = {})
@@ -166,6 +173,7 @@ module ActionCable
166
173
 
167
174
  @reject_subscription = nil
168
175
  @subscription_confirmation_sent = nil
176
+ @unsubscribed = false
169
177
 
170
178
  delegate_connection_identifiers
171
179
  end
@@ -201,11 +209,16 @@ module ActionCable
201
209
  # cleanup with callbacks. This method is not intended to be called directly by
202
210
  # the user. Instead, override the #unsubscribed callback.
203
211
  def unsubscribe_from_channel # :nodoc:
212
+ @unsubscribed = true
204
213
  run_callbacks :unsubscribe do
205
214
  unsubscribed
206
215
  end
207
216
  end
208
217
 
218
+ def unsubscribed? # :nodoc:
219
+ @unsubscribed
220
+ end
221
+
209
222
  private
210
223
  # Called once a consumer has become a subscriber of the channel. Usually the
211
224
  # place to set up any streams you want this channel to be sending to the
@@ -309,7 +322,7 @@ module ActionCable
309
322
  unless subscription_confirmation_sent?
310
323
  logger.debug "#{self.class.name} is transmitting the subscription confirmation"
311
324
 
312
- ActiveSupport::Notifications.instrument("transmit_subscription_confirmation.action_cable", channel_class: self.class.name) do
325
+ ActiveSupport::Notifications.instrument("transmit_subscription_confirmation.action_cable", channel_class: self.class.name, identifier: @identifier) do
313
326
  connection.transmit identifier: @identifier, type: ActionCable::INTERNAL[:message_types][:confirmation]
314
327
  @subscription_confirmation_sent = true
315
328
  end
@@ -324,7 +337,7 @@ module ActionCable
324
337
  def transmit_subscription_rejection
325
338
  logger.debug "#{self.class.name} is transmitting the subscription rejection"
326
339
 
327
- ActiveSupport::Notifications.instrument("transmit_subscription_rejection.action_cable", channel_class: self.class.name) do
340
+ ActiveSupport::Notifications.instrument("transmit_subscription_rejection.action_cable", channel_class: self.class.name, identifier: @identifier) do
328
341
  connection.transmit identifier: @identifier, type: ActionCable::INTERNAL[:message_types][:rejection]
329
342
  end
330
343
  end
@@ -10,19 +10,19 @@ module ActionCable
10
10
  extend ActiveSupport::Concern
11
11
 
12
12
  module ClassMethods
13
- # Broadcast a hash to a unique broadcasting for this `model` in this channel.
14
- def broadcast_to(model, message)
15
- ActionCable.server.broadcast(broadcasting_for(model), message)
13
+ # Broadcast a hash to a unique broadcasting for this array of `broadcastables` in this channel.
14
+ def broadcast_to(broadcastables, message)
15
+ ActionCable.server.broadcast(broadcasting_for(broadcastables), message)
16
16
  end
17
17
 
18
18
  # Returns a unique broadcasting identifier for this `model` in this channel:
19
19
  #
20
20
  # CommentsChannel.broadcasting_for("all") # => "comments:all"
21
21
  #
22
- # You can pass any object as a target (e.g. Active Record model), and it would
22
+ # You can pass an array of objects as a target (e.g. Active Record model), and it would
23
23
  # be serialized into a string under the hood.
24
- def broadcasting_for(model)
25
- serialize_broadcasting([ channel_name, model ])
24
+ def broadcasting_for(broadcastables)
25
+ serialize_broadcasting([ channel_name ] + Array(broadcastables))
26
26
  end
27
27
 
28
28
  private
@@ -39,6 +39,8 @@ module ActionCable
39
39
  extend ActiveSupport::Concern
40
40
  include ActiveSupport::Callbacks
41
41
 
42
+ INTERNAL_METHODS = [:_run_subscribe_callbacks, :_run_unsubscribe_callbacks] # :nodoc:
43
+
42
44
  included do
43
45
  define_callbacks :subscribe
44
46
  define_callbacks :unsubscribe
@@ -70,6 +72,11 @@ module ActionCable
70
72
  set_callback(:unsubscribe, :after, *methods, &block)
71
73
  end
72
74
  alias_method :on_unsubscribe, :after_unsubscribe
75
+
76
+ private
77
+ def internal_methods
78
+ INTERNAL_METHODS
79
+ end
73
80
  end
74
81
  end
75
82
  end
@@ -88,6 +88,8 @@ module ActionCable
88
88
  # callback. Defaults to `coder: nil` which does no decoding, passes raw
89
89
  # messages.
90
90
  def stream_from(broadcasting, callback = nil, coder: nil, &block)
91
+ return if unsubscribed?
92
+
91
93
  broadcasting = String(broadcasting)
92
94
 
93
95
  # Don't send the confirmation until pubsub#subscribe is successful
@@ -106,15 +108,15 @@ module ActionCable
106
108
  end
107
109
  end
108
110
 
109
- # Start streaming the pubsub queue for the `model` in this channel. Optionally,
111
+ # Start streaming the pubsub queue for the `broadcastables` in this channel. Optionally,
110
112
  # you can pass a `callback` that'll be used instead of the default of just
111
113
  # transmitting the updates straight to the subscriber.
112
114
  #
113
115
  # Pass `coder: ActiveSupport::JSON` to decode messages as JSON before passing to
114
116
  # the callback. Defaults to `coder: nil` which does no decoding, passes raw
115
117
  # messages.
116
- def stream_for(model, callback = nil, coder: nil, &block)
117
- stream_from(broadcasting_for(model), callback || block, coder: coder)
118
+ def stream_for(broadcastables, callback = nil, coder: nil, &block)
119
+ stream_from(broadcasting_for(broadcastables), callback || block, coder: coder)
118
120
  end
119
121
 
120
122
  # Unsubscribes streams from the named `broadcasting`.
@@ -2,8 +2,6 @@
2
2
 
3
3
  # :markup: markdown
4
4
 
5
- require "set"
6
-
7
5
  module ActionCable
8
6
  module Connection
9
7
  module Identification
@@ -68,6 +68,7 @@ module ActionCable
68
68
  @nio ||= NIO::Selector.new
69
69
 
70
70
  @executor ||= Concurrent::ThreadPoolExecutor.new(
71
+ name: "ActionCable-streamer",
71
72
  min_threads: 1,
72
73
  max_threads: 10,
73
74
  max_queue: 0,
@@ -75,11 +75,8 @@ module ActionCable
75
75
  #
76
76
  # ## Basic example
77
77
  #
78
- # Unit tests are written as follows:
79
- #
80
- # 1. Simulate a connection attempt by calling `connect`.
81
- # 2. Assert state, e.g. identifiers, has been assigned.
82
- #
78
+ # Unit tests are written by first simulating a connection attempt by calling
79
+ # `connect` and then asserting state, e.g. identifiers, have been assigned.
83
80
  #
84
81
  # class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
85
82
  # def test_connects_with_proper_cookie
@@ -9,10 +9,10 @@ module ActionCable
9
9
  end
10
10
 
11
11
  module VERSION
12
- MAJOR = 7
13
- MINOR = 2
12
+ MAJOR = 8
13
+ MINOR = 1
14
14
  TINY = 2
15
- PRE = "1"
15
+ PRE = nil
16
16
 
17
17
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
18
18
  end
@@ -39,45 +39,44 @@ module ActionCable
39
39
  RemoteConnection.new(server, identifier)
40
40
  end
41
41
 
42
- private
43
- # # Action Cable Remote Connection
44
- #
45
- # Represents a single remote connection found via
46
- # `ActionCable.server.remote_connections.where(*)`. Exists solely for the
47
- # purpose of calling #disconnect on that connection.
48
- class RemoteConnection
49
- class InvalidIdentifiersError < StandardError; end
42
+ # # Action Cable Remote Connection
43
+ #
44
+ # Represents a single remote connection found via
45
+ # `ActionCable.server.remote_connections.where(*)`. Exists solely for the
46
+ # purpose of calling #disconnect on that connection.
47
+ class RemoteConnection
48
+ class InvalidIdentifiersError < StandardError; end
50
49
 
51
- include Connection::Identification, Connection::InternalChannel
50
+ include Connection::Identification, Connection::InternalChannel
52
51
 
53
- def initialize(server, ids)
54
- @server = server
55
- set_identifier_instance_vars(ids)
56
- end
52
+ def initialize(server, ids)
53
+ @server = server
54
+ set_identifier_instance_vars(ids)
55
+ end
57
56
 
58
- # Uses the internal channel to disconnect the connection.
59
- def disconnect(reconnect: true)
60
- server.broadcast internal_channel, { type: "disconnect", reconnect: reconnect }
61
- end
57
+ # Uses the internal channel to disconnect the connection.
58
+ def disconnect(reconnect: true)
59
+ server.broadcast internal_channel, { type: "disconnect", reconnect: reconnect }
60
+ end
62
61
 
63
- # Returns all the identifiers that were applied to this connection.
64
- redefine_method :identifiers do
65
- server.connection_identifiers
66
- end
62
+ # Returns all the identifiers that were applied to this connection.
63
+ redefine_method :identifiers do
64
+ server.connection_identifiers
65
+ end
67
66
 
68
- protected
69
- attr_reader :server
67
+ protected
68
+ attr_reader :server
70
69
 
71
- private
72
- def set_identifier_instance_vars(ids)
73
- raise InvalidIdentifiersError unless valid_identifiers?(ids)
74
- ids.each { |k, v| instance_variable_set("@#{k}", v) }
75
- end
70
+ private
71
+ def set_identifier_instance_vars(ids)
72
+ raise InvalidIdentifiersError unless valid_identifiers?(ids)
73
+ ids.each { |k, v| instance_variable_set("@#{k}", v) }
74
+ end
76
75
 
77
- def valid_identifiers?(ids)
78
- keys = ids.keys
79
- identifiers.all? { |id| keys.include?(id) }
80
- end
81
- end
76
+ def valid_identifiers?(ids)
77
+ keys = ids.keys
78
+ identifiers.all? { |id| keys.include?(id) }
79
+ end
80
+ end
82
81
  end
83
82
  end
@@ -21,10 +21,12 @@ module ActionCable
21
21
  # ActionCable.server.broadcast \
22
22
  # "web_notifications_1", { title: "New things!", body: "All that's fit for print" }
23
23
  #
24
- # # Client-side CoffeeScript, which assumes you've already requested the right to send web notifications:
25
- # App.cable.subscriptions.create "WebNotificationsChannel",
26
- # received: (data) ->
27
- # new Notification data['title'], body: data['body']
24
+ # # Client-side JavaScript, which assumes you've already requested the right to send web notifications:
25
+ # App.cable.subscriptions.create("WebNotificationsChannel", {
26
+ # received: function(data) {
27
+ # new Notification(data['title'], { body: data['body'] })
28
+ # }
29
+ # })
28
30
  module Broadcasting
29
31
  # Broadcast a hash directly to a named `broadcasting`. This will later be JSON
30
32
  # encoded.
@@ -20,7 +20,7 @@ module ActionCable
20
20
 
21
21
  def initialize(max_size: 5)
22
22
  @executor = Concurrent::ThreadPoolExecutor.new(
23
- name: "ActionCable",
23
+ name: "ActionCable-server",
24
24
  min_threads: 1,
25
25
  max_threads: max_size,
26
26
  max_queue: 0,
@@ -29,7 +29,8 @@ module ActionCable
29
29
  end
30
30
 
31
31
  def identifier
32
- @server.config.cable[:id] ||= "ActionCable-PID-#{$$}"
32
+ @server.config.cable[:id] = "ActionCable-PID-#{$$}" unless @server.config.cable.key?(:id)
33
+ @server.config.cable[:id]
33
34
  end
34
35
  end
35
36
  end
@@ -35,18 +35,17 @@ module ActionCable
35
35
  end
36
36
 
37
37
  def with_subscriptions_connection(&block) # :nodoc:
38
- ar_conn = ActiveRecord::Base.connection_pool.checkout.tap do |conn|
39
- # Action Cable is taking ownership over this database connection, and will
40
- # perform the necessary cleanup tasks
41
- ActiveRecord::Base.connection_pool.remove(conn)
42
- end
38
+ # Action Cable is taking ownership over this database connection, and will
39
+ # perform the necessary cleanup tasks.
40
+ # We purposedly avoid #checkout to not end up with a pinned connection
41
+ ar_conn = ActiveRecord::Base.connection_pool.new_connection
43
42
  pg_conn = ar_conn.raw_connection
44
43
 
45
44
  verify!(pg_conn)
46
45
  pg_conn.exec("SET application_name = #{pg_conn.escape_identifier(identifier)}")
47
46
  yield pg_conn
48
47
  ensure
49
- ar_conn.disconnect!
48
+ ar_conn&.disconnect!
50
49
  end
51
50
 
52
51
  def with_broadcast_connection(&block) # :nodoc:
@@ -164,7 +164,7 @@ module ActionCable
164
164
  begin
165
165
  conn = @adapter.redis_connection_for_subscriptions
166
166
  listen conn
167
- rescue ConnectionError
167
+ rescue *CONNECTION_ERRORS
168
168
  reset
169
169
  if retry_connecting?
170
170
  when_connected { resubscribe }
@@ -210,7 +210,7 @@ module ActionCable
210
210
  end
211
211
 
212
212
  if ::Redis::VERSION < "5"
213
- ConnectionError = ::Redis::BaseConnectionError
213
+ CONNECTION_ERRORS = [::Redis::BaseConnectionError].freeze
214
214
 
215
215
  class SubscribedClient
216
216
  def initialize(raw_client)
@@ -244,7 +244,12 @@ module ActionCable
244
244
  SubscribedClient.new(conn._client)
245
245
  end
246
246
  else
247
- ConnectionError = RedisClient::ConnectionError
247
+ CONNECTION_ERRORS = [
248
+ ::Redis::BaseConnectionError,
249
+
250
+ # Some older versions of redis-rb sometime leak underlying exceptions
251
+ RedisClient::ConnectionError,
252
+ ].freeze
248
253
 
249
254
  def extract_subscribed_client(conn)
250
255
  conn
@@ -59,17 +59,17 @@ module Rails
59
59
  def create_channel_javascript_file
60
60
  channel_js_path = File.join("app/javascript/channels", class_path, "#{file_name}_channel")
61
61
  js_template "javascript/channel", channel_js_path
62
- gsub_file "#{channel_js_path}.js", /\.\/consumer/, "channels/consumer" unless using_js_runtime?
62
+ gsub_file "#{channel_js_path}.js", /\.\/consumer/, "channels/consumer" if using_importmap?
63
63
  end
64
64
 
65
65
  def import_channels_in_javascript_entrypoint
66
66
  append_to_file "app/javascript/application.js",
67
- using_js_runtime? ? %(import "./channels"\n) : %(import "channels"\n)
67
+ using_importmap? ? %(import "channels"\n) : %(import "./channels"\n)
68
68
  end
69
69
 
70
70
  def import_channel_in_javascript_entrypoint
71
71
  append_to_file "app/javascript/channels/index.js",
72
- using_js_runtime? ? %(import "./#{file_name}_channel"\n) : %(import "channels/#{file_name}_channel"\n)
72
+ using_importmap? ? %(import "channels/#{file_name}_channel"\n) : %(import "./#{file_name}_channel"\n)
73
73
  end
74
74
 
75
75
  def install_javascript_dependencies
@@ -105,7 +105,7 @@ pin_all_from "app/javascript/channels", under: "channels"
105
105
  end
106
106
 
107
107
  def using_bun?
108
- # Cannot assume bun.lockb has been generated yet so we look for a file known to
108
+ # Cannot assume Bun lockfile has been generated yet so we look for a file known to
109
109
  # be generated by the jsbundling-rails gem
110
110
  @using_bun ||= using_js_runtime? && root.join("bun.config.js").exist?
111
111
  end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actioncable
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.2.1
4
+ version: 8.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pratik Naik
8
8
  - David Heinemeier Hansson
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2024-12-10 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: activesupport
@@ -17,28 +16,28 @@ dependencies:
17
16
  requirements:
18
17
  - - '='
19
18
  - !ruby/object:Gem::Version
20
- version: 7.2.2.1
19
+ version: 8.1.2
21
20
  type: :runtime
22
21
  prerelease: false
23
22
  version_requirements: !ruby/object:Gem::Requirement
24
23
  requirements:
25
24
  - - '='
26
25
  - !ruby/object:Gem::Version
27
- version: 7.2.2.1
26
+ version: 8.1.2
28
27
  - !ruby/object:Gem::Dependency
29
28
  name: actionpack
30
29
  requirement: !ruby/object:Gem::Requirement
31
30
  requirements:
32
31
  - - '='
33
32
  - !ruby/object:Gem::Version
34
- version: 7.2.2.1
33
+ version: 8.1.2
35
34
  type: :runtime
36
35
  prerelease: false
37
36
  version_requirements: !ruby/object:Gem::Requirement
38
37
  requirements:
39
38
  - - '='
40
39
  - !ruby/object:Gem::Version
41
- version: 7.2.2.1
40
+ version: 8.1.2
42
41
  - !ruby/object:Gem::Dependency
43
42
  name: nio4r
44
43
  requirement: !ruby/object:Gem::Requirement
@@ -154,12 +153,11 @@ licenses:
154
153
  - MIT
155
154
  metadata:
156
155
  bug_tracker_uri: https://github.com/rails/rails/issues
157
- changelog_uri: https://github.com/rails/rails/blob/v7.2.2.1/actioncable/CHANGELOG.md
158
- documentation_uri: https://api.rubyonrails.org/v7.2.2.1/
156
+ changelog_uri: https://github.com/rails/rails/blob/v8.1.2/actioncable/CHANGELOG.md
157
+ documentation_uri: https://api.rubyonrails.org/v8.1.2/
159
158
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
160
- source_code_uri: https://github.com/rails/rails/tree/v7.2.2.1/actioncable
159
+ source_code_uri: https://github.com/rails/rails/tree/v8.1.2/actioncable
161
160
  rubygems_mfa_required: 'true'
162
- post_install_message:
163
161
  rdoc_options: []
164
162
  require_paths:
165
163
  - lib
@@ -167,15 +165,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
167
165
  requirements:
168
166
  - - ">="
169
167
  - !ruby/object:Gem::Version
170
- version: 3.1.0
168
+ version: 3.2.0
171
169
  required_rubygems_version: !ruby/object:Gem::Requirement
172
170
  requirements:
173
171
  - - ">="
174
172
  - !ruby/object:Gem::Version
175
173
  version: '0'
176
174
  requirements: []
177
- rubygems_version: 3.5.22
178
- signing_key:
175
+ rubygems_version: 4.0.3
179
176
  specification_version: 4
180
177
  summary: WebSocket framework for Rails.
181
178
  test_files: []