actioncable 7.0.8 → 7.1.3.4

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/CHANGELOG.md +75 -103
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +4 -4
  5. data/app/assets/javascripts/action_cable.js +27 -6
  6. data/app/assets/javascripts/actioncable.esm.js +27 -6
  7. data/app/assets/javascripts/actioncable.js +27 -6
  8. data/lib/action_cable/channel/base.rb +17 -5
  9. data/lib/action_cable/channel/broadcasting.rb +3 -1
  10. data/lib/action_cable/channel/callbacks.rb +37 -0
  11. data/lib/action_cable/channel/naming.rb +4 -2
  12. data/lib/action_cable/channel/streams.rb +2 -0
  13. data/lib/action_cable/channel/test_case.rb +6 -1
  14. data/lib/action_cable/connection/authorization.rb +1 -1
  15. data/lib/action_cable/connection/base.rb +18 -5
  16. data/lib/action_cable/connection/callbacks.rb +55 -0
  17. data/lib/action_cable/connection/internal_channel.rb +3 -1
  18. data/lib/action_cable/connection/stream.rb +1 -3
  19. data/lib/action_cable/connection/stream_event_loop.rb +0 -1
  20. data/lib/action_cable/connection/subscriptions.rb +2 -0
  21. data/lib/action_cable/connection/tagged_logger_proxy.rb +6 -4
  22. data/lib/action_cable/connection/test_case.rb +3 -1
  23. data/lib/action_cable/connection/web_socket.rb +2 -0
  24. data/lib/action_cable/deprecator.rb +7 -0
  25. data/lib/action_cable/engine.rb +13 -5
  26. data/lib/action_cable/gem_version.rb +4 -4
  27. data/lib/action_cable/remote_connections.rb +11 -2
  28. data/lib/action_cable/server/base.rb +3 -0
  29. data/lib/action_cable/server/broadcasting.rb +2 -0
  30. data/lib/action_cable/server/configuration.rb +12 -2
  31. data/lib/action_cable/server/connections.rb +3 -1
  32. data/lib/action_cable/server/worker.rb +0 -1
  33. data/lib/action_cable/subscription_adapter/async.rb +0 -2
  34. data/lib/action_cable/subscription_adapter/postgresql.rb +0 -1
  35. data/lib/action_cable/subscription_adapter/redis.rb +3 -6
  36. data/lib/action_cable/subscription_adapter/test.rb +3 -5
  37. data/lib/action_cable/test_helper.rb +53 -22
  38. data/lib/action_cable/version.rb +1 -1
  39. data/lib/action_cable.rb +24 -12
  40. data/lib/rails/generators/channel/USAGE +14 -8
  41. data/lib/rails/generators/channel/channel_generator.rb +21 -7
  42. metadata +26 -14
  43. data/lib/action_cable/channel.rb +0 -17
  44. data/lib/action_cable/connection.rb +0 -22
  45. data/lib/action_cable/server.rb +0 -16
  46. data/lib/action_cable/subscription_adapter.rb +0 -12
@@ -29,30 +29,33 @@ module ActionCable
29
29
  # end
30
30
  #
31
31
  # If a block is passed, that block should cause the specified number of
32
- # messages to be broadcasted.
32
+ # messages to be broadcasted. It returns the messages that were broadcasted.
33
33
  #
34
34
  # def test_broadcasts_again
35
- # assert_broadcasts('messages', 1) do
35
+ # message = assert_broadcasts('messages', 1) do
36
36
  # ActionCable.server.broadcast 'messages', { text: 'hello' }
37
37
  # end
38
+ # assert_equal({ text: 'hello' }, message)
38
39
  #
39
- # assert_broadcasts('messages', 2) do
40
+ # messages = assert_broadcasts('messages', 2) do
40
41
  # ActionCable.server.broadcast 'messages', { text: 'hi' }
41
42
  # ActionCable.server.broadcast 'messages', { text: 'how are you?' }
42
43
  # end
44
+ # assert_equal 2, messages.length
45
+ # assert_equal({ text: 'hi' }, messages.first)
46
+ # assert_equal({ text: 'how are you?' }, messages.last)
43
47
  # end
44
48
  #
45
49
  def assert_broadcasts(stream, number, &block)
46
50
  if block_given?
47
- original_count = broadcasts_size(stream)
48
- _assert_nothing_raised_or_warn("assert_broadcasts", &block)
49
- new_count = broadcasts_size(stream)
50
- actual_count = new_count - original_count
51
+ new_messages = new_broadcasts_from(broadcasts(stream), stream, "assert_broadcasts", &block)
52
+
53
+ actual_count = new_messages.size
54
+ assert_equal number, actual_count, "#{number} broadcasts to #{stream} expected, but #{actual_count} were sent"
51
55
  else
52
- actual_count = broadcasts_size(stream)
56
+ actual_count = broadcasts(stream).size
57
+ assert_equal number, actual_count, "#{number} broadcasts to #{stream} expected, but #{actual_count} were sent"
53
58
  end
54
-
55
- assert_equal number, actual_count, "#{number} broadcasts to #{stream} expected, but #{actual_count} were sent"
56
59
  end
57
60
 
58
61
  # Asserts that no messages have been sent to the stream.
@@ -79,6 +82,22 @@ module ActionCable
79
82
  assert_broadcasts stream, 0, &block
80
83
  end
81
84
 
85
+ # Returns the messages that are broadcasted in the block.
86
+ #
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?' }
91
+ # 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
+ #
97
+ def capture_broadcasts(stream, &block)
98
+ new_broadcasts_from(broadcasts(stream), stream, "capture_broadcasts", &block).map { |m| ActiveSupport::JSON.decode(m) }
99
+ end
100
+
82
101
  # Asserts that the specified message has been sent to the stream.
83
102
  #
84
103
  # def test_assert_transmitted_message
@@ -103,20 +122,22 @@ module ActionCable
103
122
 
104
123
  new_messages = broadcasts(stream)
105
124
  if block_given?
106
- old_messages = new_messages
107
- clear_messages(stream)
108
-
109
- _assert_nothing_raised_or_warn("assert_broadcast_on", &block)
110
- new_messages = broadcasts(stream)
111
- clear_messages(stream)
112
-
113
- # Restore all sent messages
114
- (old_messages + new_messages).each { |m| pubsub_adapter.broadcast(stream, m) }
125
+ new_messages = new_broadcasts_from(new_messages, stream, "assert_broadcast_on", &block)
115
126
  end
116
127
 
117
128
  message = new_messages.find { |msg| ActiveSupport::JSON.decode(msg) == serialized_msg }
118
129
 
119
- assert message, "No messages sent with #{data} to #{stream}"
130
+ error_message = "No messages sent with #{data} to #{stream}"
131
+
132
+ if new_messages.any?
133
+ error_message = new_messages.inject("#{error_message}\nMessage(s) found:\n") do |error_message, new_message|
134
+ error_message + "#{ActiveSupport::JSON.decode(new_message)}\n"
135
+ end
136
+ else
137
+ error_message = "#{error_message}\nNo message found for #{stream}"
138
+ end
139
+
140
+ assert message, error_message
120
141
  end
121
142
 
122
143
  def pubsub_adapter # :nodoc:
@@ -126,8 +147,18 @@ module ActionCable
126
147
  delegate :broadcasts, :clear_messages, to: :pubsub_adapter
127
148
 
128
149
  private
129
- def broadcasts_size(channel)
130
- broadcasts(channel).size
150
+ def new_broadcasts_from(current_messages, stream, assertion, &block)
151
+ old_messages = current_messages
152
+ clear_messages(stream)
153
+
154
+ _assert_nothing_raised_or_warn(assertion, &block)
155
+ new_messages = broadcasts(stream)
156
+ clear_messages(stream)
157
+
158
+ # Restore all sent messages
159
+ (old_messages + new_messages).each { |m| pubsub_adapter.broadcast(stream, m) }
160
+
161
+ new_messages
131
162
  end
132
163
  end
133
164
  end
@@ -3,7 +3,7 @@
3
3
  require_relative "gem_version"
4
4
 
5
5
  module ActionCable
6
- # Returns the currently loaded version of Action Cable as a <tt>Gem::Version</tt>.
6
+ # Returns the currently loaded version of Action Cable as a +Gem::Version+.
7
7
  def self.version
8
8
  gem_version
9
9
  end
data/lib/action_cable.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2015-2022 Basecamp, LLC
4
+ # Copyright (c) 37signals LLC
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -25,10 +25,29 @@
25
25
 
26
26
  require "active_support"
27
27
  require "active_support/rails"
28
- require "action_cable/version"
28
+ require "zeitwerk"
29
29
 
30
+ Zeitwerk::Loader.for_gem.tap do |loader|
31
+ loader.ignore(
32
+ "#{__dir__}/rails", # Contains generators, templates, docs, etc.
33
+ "#{__dir__}/action_cable/gem_version.rb",
34
+ "#{__dir__}/action_cable/deprecator.rb",
35
+ )
36
+
37
+ 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"]
41
+ )
42
+
43
+ loader.inflector.inflect("postgresql" => "PostgreSQL")
44
+ end.setup
45
+
46
+ # :markup: markdown
47
+ # :include: actioncable/README.md
30
48
  module ActionCable
31
- extend ActiveSupport::Autoload
49
+ require_relative "action_cable/version"
50
+ require_relative "action_cable/deprecator"
32
51
 
33
52
  INTERNAL = {
34
53
  message_types: {
@@ -41,7 +60,8 @@ module ActionCable
41
60
  disconnect_reasons: {
42
61
  unauthorized: "unauthorized",
43
62
  invalid_request: "invalid_request",
44
- server_restart: "server_restart"
63
+ server_restart: "server_restart",
64
+ remote: "remote"
45
65
  },
46
66
  default_mount_path: "/cable",
47
67
  protocols: ["actioncable-v1-json", "actioncable-unsupported"].freeze
@@ -51,12 +71,4 @@ module ActionCable
51
71
  module_function def server
52
72
  @server ||= ActionCable::Server::Base.new
53
73
  end
54
-
55
- autoload :Server
56
- autoload :Connection
57
- autoload :Channel
58
- autoload :RemoteConnections
59
- autoload :SubscriptionAdapter
60
- autoload :TestHelper
61
- autoload :TestCase
62
74
  end
@@ -1,13 +1,19 @@
1
1
  Description:
2
- ============
3
2
  Generates a new cable channel for the server (in Ruby) and client (in JavaScript).
4
3
  Pass the channel name, either CamelCased or under_scored, and an optional list of channel actions as arguments.
5
4
 
6
- Example:
7
- ========
8
- bin/rails generate channel Chat speak
5
+ Examples:
6
+ `bin/rails generate channel notification`
9
7
 
10
- creates a Chat channel class, test and JavaScript asset:
11
- Channel: app/channels/chat_channel.rb
12
- Test: test/channels/chat_channel_test.rb
13
- Assets: $JAVASCRIPT_PATH/channels/chat_channel.js
8
+ creates a notification channel class, test and JavaScript asset:
9
+ Channel: app/channels/notification_channel.rb
10
+ Test: test/channels/notification_channel_test.rb
11
+ Assets: $JAVASCRIPT_PATH/channels/notification_channel.js
12
+
13
+ `bin/rails generate channel chat speak`
14
+
15
+ creates a chat channel with a speak action.
16
+
17
+ `bin/rails generate channel comments --no-assets`
18
+
19
+ creates a comments channel without JavaScript assets.
@@ -24,7 +24,7 @@ module Rails
24
24
 
25
25
  if using_importmap?
26
26
  pin_javascript_dependencies
27
- elsif using_node?
27
+ elsif using_js_runtime?
28
28
  install_javascript_dependencies
29
29
  end
30
30
  end
@@ -57,22 +57,26 @@ module Rails
57
57
  def create_channel_javascript_file
58
58
  channel_js_path = File.join("app/javascript/channels", class_path, "#{file_name}_channel")
59
59
  js_template "javascript/channel", channel_js_path
60
- gsub_file "#{channel_js_path}.js", /\.\/consumer/, "channels/consumer" unless using_node?
60
+ gsub_file "#{channel_js_path}.js", /\.\/consumer/, "channels/consumer" unless using_js_runtime?
61
61
  end
62
62
 
63
63
  def import_channels_in_javascript_entrypoint
64
64
  append_to_file "app/javascript/application.js",
65
- using_node? ? %(import "./channels"\n) : %(import "channels"\n)
65
+ using_js_runtime? ? %(import "./channels"\n) : %(import "channels"\n)
66
66
  end
67
67
 
68
68
  def import_channel_in_javascript_entrypoint
69
69
  append_to_file "app/javascript/channels/index.js",
70
- using_node? ? %(import "./#{file_name}_channel"\n) : %(import "channels/#{file_name}_channel"\n)
70
+ using_js_runtime? ? %(import "./#{file_name}_channel"\n) : %(import "channels/#{file_name}_channel"\n)
71
71
  end
72
72
 
73
73
  def install_javascript_dependencies
74
74
  say "Installing JavaScript dependencies", :green
75
- run "yarn add @rails/actioncable"
75
+ if using_bun?
76
+ run "bun add @rails/actioncable"
77
+ elsif using_node?
78
+ run "yarn add @rails/actioncable"
79
+ end
76
80
  end
77
81
 
78
82
  def pin_javascript_dependencies
@@ -82,7 +86,6 @@ pin_all_from "app/javascript/channels", under: "channels"
82
86
  RUBY
83
87
  end
84
88
 
85
-
86
89
  def file_name
87
90
  @_file_name ||= super.sub(/_channel\z/i, "")
88
91
  end
@@ -95,8 +98,19 @@ pin_all_from "app/javascript/channels", under: "channels"
95
98
  @using_javascript ||= options[:assets] && root.join("app/javascript").exist?
96
99
  end
97
100
 
101
+ def using_js_runtime?
102
+ @using_js_runtime ||= root.join("package.json").exist?
103
+ end
104
+
105
+ 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
+ @using_bun ||= using_js_runtime? && root.join("bun.config.js").exist?
109
+ end
110
+
98
111
  def using_node?
99
- @using_node ||= root.join("package.json").exist?
112
+ # Bun is the only runtime that _isn't_ node.
113
+ @using_node ||= using_js_runtime? && !root.join("bun.config.js").exist?
100
114
  end
101
115
 
102
116
  def using_importmap?
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.0.8
4
+ version: 7.1.3.4
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: 2023-09-09 00:00:00.000000000 Z
12
+ date: 2024-06-04 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.0.8
20
+ version: 7.1.3.4
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.0.8
27
+ version: 7.1.3.4
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.0.8
34
+ version: 7.1.3.4
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.0.8
41
+ version: 7.1.3.4
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: nio4r
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -67,6 +67,20 @@ dependencies:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  version: 0.6.1
70
+ - !ruby/object:Gem::Dependency
71
+ name: zeitwerk
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '2.6'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '2.6'
70
84
  description: Structure many real-time application concerns into channels over a single
71
85
  WebSocket connection.
72
86
  email:
@@ -83,7 +97,6 @@ files:
83
97
  - app/assets/javascripts/actioncable.esm.js
84
98
  - app/assets/javascripts/actioncable.js
85
99
  - lib/action_cable.rb
86
- - lib/action_cable/channel.rb
87
100
  - lib/action_cable/channel/base.rb
88
101
  - lib/action_cable/channel/broadcasting.rb
89
102
  - lib/action_cable/channel/callbacks.rb
@@ -91,9 +104,9 @@ files:
91
104
  - lib/action_cable/channel/periodic_timers.rb
92
105
  - lib/action_cable/channel/streams.rb
93
106
  - lib/action_cable/channel/test_case.rb
94
- - lib/action_cable/connection.rb
95
107
  - lib/action_cable/connection/authorization.rb
96
108
  - lib/action_cable/connection/base.rb
109
+ - lib/action_cable/connection/callbacks.rb
97
110
  - lib/action_cable/connection/client_socket.rb
98
111
  - lib/action_cable/connection/identification.rb
99
112
  - lib/action_cable/connection/internal_channel.rb
@@ -104,18 +117,17 @@ files:
104
117
  - lib/action_cable/connection/tagged_logger_proxy.rb
105
118
  - lib/action_cable/connection/test_case.rb
106
119
  - lib/action_cable/connection/web_socket.rb
120
+ - lib/action_cable/deprecator.rb
107
121
  - lib/action_cable/engine.rb
108
122
  - lib/action_cable/gem_version.rb
109
123
  - lib/action_cable/helpers/action_cable_helper.rb
110
124
  - lib/action_cable/remote_connections.rb
111
- - lib/action_cable/server.rb
112
125
  - lib/action_cable/server/base.rb
113
126
  - lib/action_cable/server/broadcasting.rb
114
127
  - lib/action_cable/server/configuration.rb
115
128
  - lib/action_cable/server/connections.rb
116
129
  - lib/action_cable/server/worker.rb
117
130
  - lib/action_cable/server/worker/active_record_connection_management.rb
118
- - lib/action_cable/subscription_adapter.rb
119
131
  - lib/action_cable/subscription_adapter/async.rb
120
132
  - lib/action_cable/subscription_adapter/base.rb
121
133
  - lib/action_cable/subscription_adapter/channel_prefix.rb
@@ -142,10 +154,10 @@ licenses:
142
154
  - MIT
143
155
  metadata:
144
156
  bug_tracker_uri: https://github.com/rails/rails/issues
145
- changelog_uri: https://github.com/rails/rails/blob/v7.0.8/actioncable/CHANGELOG.md
146
- documentation_uri: https://api.rubyonrails.org/v7.0.8/
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/
147
159
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
148
- source_code_uri: https://github.com/rails/rails/tree/v7.0.8/actioncable
160
+ source_code_uri: https://github.com/rails/rails/tree/v7.1.3.4/actioncable
149
161
  rubygems_mfa_required: 'true'
150
162
  post_install_message:
151
163
  rdoc_options: []
@@ -162,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
174
  - !ruby/object:Gem::Version
163
175
  version: '0'
164
176
  requirements: []
165
- rubygems_version: 3.4.18
177
+ rubygems_version: 3.3.27
166
178
  signing_key:
167
179
  specification_version: 4
168
180
  summary: WebSocket framework for Rails.
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActionCable
4
- module Channel
5
- extend ActiveSupport::Autoload
6
-
7
- eager_autoload do
8
- autoload :Base
9
- autoload :Broadcasting
10
- autoload :Callbacks
11
- autoload :Naming
12
- autoload :PeriodicTimers
13
- autoload :Streams
14
- autoload :TestCase
15
- end
16
- end
17
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActionCable
4
- module Connection
5
- extend ActiveSupport::Autoload
6
-
7
- eager_autoload do
8
- autoload :Authorization
9
- autoload :Base
10
- autoload :ClientSocket
11
- autoload :Identification
12
- autoload :InternalChannel
13
- autoload :MessageBuffer
14
- autoload :Stream
15
- autoload :StreamEventLoop
16
- autoload :Subscriptions
17
- autoload :TaggedLoggerProxy
18
- autoload :TestCase
19
- autoload :WebSocket
20
- end
21
- end
22
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActionCable
4
- module Server
5
- extend ActiveSupport::Autoload
6
-
7
- eager_autoload do
8
- autoload :Base
9
- autoload :Broadcasting
10
- autoload :Connections
11
- autoload :Configuration
12
-
13
- autoload :Worker
14
- end
15
- end
16
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActionCable
4
- module SubscriptionAdapter
5
- extend ActiveSupport::Autoload
6
-
7
- autoload :Base
8
- autoload :Test
9
- autoload :SubscriberMap
10
- autoload :ChannelPrefix
11
- end
12
- end