cable_ready 4.5.0 → 5.0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +2 -376
- data/Gemfile +4 -1
- data/Gemfile.lock +146 -144
- data/README.md +54 -20
- data/Rakefile +8 -8
- data/app/assets/javascripts/cable_ready.js +1269 -0
- data/app/assets/javascripts/cable_ready.umd.js +1190 -0
- data/app/channels/cable_ready/stream.rb +14 -0
- data/app/helpers/cable_ready/view_helper.rb +58 -0
- data/app/jobs/cable_ready/broadcast_job.rb +15 -0
- data/app/models/concerns/cable_ready/updatable/collection_updatable_callbacks.rb +21 -0
- data/app/models/concerns/cable_ready/updatable/collections_registry.rb +59 -0
- data/app/models/concerns/cable_ready/updatable/memory_cache_debounce_adapter.rb +24 -0
- data/app/models/concerns/cable_ready/updatable/model_updatable_callbacks.rb +33 -0
- data/app/models/concerns/cable_ready/updatable.rb +211 -0
- data/app/models/concerns/extend_has_many.rb +15 -0
- data/bin/standardize +1 -1
- data/cable_ready.gemspec +20 -6
- data/lib/cable_ready/broadcaster.rb +4 -3
- data/lib/cable_ready/cable_car.rb +19 -0
- data/lib/cable_ready/channel.rb +29 -31
- data/lib/cable_ready/channels.rb +4 -5
- data/lib/cable_ready/compoundable.rb +11 -0
- data/lib/cable_ready/config.rb +28 -1
- data/lib/cable_ready/engine.rb +59 -0
- data/lib/cable_ready/identifiable.rb +48 -0
- data/lib/cable_ready/importmap.rb +4 -0
- data/lib/cable_ready/installer.rb +224 -0
- data/lib/cable_ready/operation_builder.rb +80 -0
- data/lib/cable_ready/sanity_checker.rb +63 -0
- data/lib/cable_ready/stream_identifier.rb +13 -0
- data/lib/cable_ready/version.rb +1 -1
- data/lib/cable_ready.rb +23 -10
- data/lib/cable_ready_helper.rb +13 -0
- data/lib/generators/cable_ready/channel_generator.rb +110 -0
- data/lib/generators/cable_ready/templates/app/javascript/channels/consumer.js.tt +6 -0
- data/lib/generators/cable_ready/templates/app/javascript/channels/index.js.esbuild.tt +4 -0
- data/lib/generators/cable_ready/templates/app/javascript/channels/index.js.importmap.tt +2 -0
- data/lib/generators/cable_ready/templates/app/javascript/channels/index.js.shakapacker.tt +5 -0
- data/lib/generators/cable_ready/templates/app/javascript/channels/index.js.vite.tt +1 -0
- data/lib/generators/cable_ready/templates/app/javascript/channels/index.js.webpacker.tt +5 -0
- data/lib/generators/cable_ready/templates/app/javascript/config/cable_ready.js.tt +4 -0
- data/lib/generators/cable_ready/templates/app/javascript/config/index.js.tt +1 -0
- data/lib/generators/cable_ready/templates/app/javascript/config/mrujs.js.tt +9 -0
- data/lib/generators/cable_ready/templates/app/javascript/controllers/%file_name%_controller.js.tt +38 -0
- data/lib/generators/cable_ready/templates/app/javascript/controllers/application.js.tt +11 -0
- data/lib/generators/cable_ready/templates/app/javascript/controllers/index.js.esbuild.tt +7 -0
- data/lib/generators/cable_ready/templates/app/javascript/controllers/index.js.importmap.tt +5 -0
- data/lib/generators/cable_ready/templates/app/javascript/controllers/index.js.shakapacker.tt +5 -0
- data/lib/generators/cable_ready/templates/app/javascript/controllers/index.js.vite.tt +5 -0
- data/lib/generators/cable_ready/templates/app/javascript/controllers/index.js.webpacker.tt +5 -0
- data/lib/generators/cable_ready/templates/config/initializers/cable_ready.rb +27 -0
- data/lib/generators/cable_ready/templates/esbuild.config.mjs.tt +94 -0
- data/lib/install/action_cable.rb +144 -0
- data/lib/install/broadcaster.rb +109 -0
- data/lib/install/bundle.rb +54 -0
- data/lib/install/compression.rb +51 -0
- data/lib/install/config.rb +39 -0
- data/lib/install/development.rb +34 -0
- data/lib/install/esbuild.rb +101 -0
- data/lib/install/importmap.rb +96 -0
- data/lib/install/initializers.rb +15 -0
- data/lib/install/mrujs.rb +121 -0
- data/lib/install/npm_packages.rb +13 -0
- data/lib/install/shakapacker.rb +65 -0
- data/lib/install/spring.rb +54 -0
- data/lib/install/updatable.rb +34 -0
- data/lib/install/vite.rb +66 -0
- data/lib/install/webpacker.rb +93 -0
- data/lib/install/yarn.rb +56 -0
- data/lib/tasks/cable_ready/cable_ready.rake +247 -0
- data/package.json +42 -13
- data/rollup.config.mjs +57 -0
- data/web-test-runner.config.mjs +12 -0
- data/yarn.lock +3252 -327
- metadata +138 -9
- data/tags +0 -62
data/lib/cable_ready/config.rb
CHANGED
|
@@ -11,9 +11,32 @@ module CableReady
|
|
|
11
11
|
include Observable
|
|
12
12
|
include Singleton
|
|
13
13
|
|
|
14
|
+
attr_accessor :on_failed_sanity_checks, :broadcast_job_queue, :precompile_assets, :updatable_debounce_time
|
|
15
|
+
attr_writer :verifier_key
|
|
16
|
+
|
|
17
|
+
def on_new_version_available
|
|
18
|
+
warn "NOTICE: The `config.on_new_version_available` option has been removed from the CableReady initializer. You can safely remove this option from your initializer."
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def on_new_version_available=(_)
|
|
22
|
+
warn "NOTICE: The `config.on_new_version_available` option has been removed from the CableReady initializer. You can safely remove this option from your initializer."
|
|
23
|
+
end
|
|
24
|
+
|
|
14
25
|
def initialize
|
|
15
26
|
super
|
|
16
27
|
@operation_names = Set.new(default_operation_names)
|
|
28
|
+
@on_failed_sanity_checks = :exit
|
|
29
|
+
@broadcast_job_queue = :default
|
|
30
|
+
@precompile_assets = true
|
|
31
|
+
@updatable_debounce_time = 0.1.seconds
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def observers
|
|
35
|
+
@observer_peers&.keys || []
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def verifier_key
|
|
39
|
+
@verifier_key || Rails.application.key_generator.generate_key("cable_ready/verifier_key")
|
|
17
40
|
end
|
|
18
41
|
|
|
19
42
|
def operation_names
|
|
@@ -33,6 +56,7 @@ module CableReady
|
|
|
33
56
|
append
|
|
34
57
|
clear_storage
|
|
35
58
|
console_log
|
|
59
|
+
console_table
|
|
36
60
|
dispatch_event
|
|
37
61
|
go
|
|
38
62
|
graft
|
|
@@ -42,9 +66,10 @@ module CableReady
|
|
|
42
66
|
morph
|
|
43
67
|
notification
|
|
44
68
|
outer_html
|
|
45
|
-
play_sound
|
|
46
69
|
prepend
|
|
47
70
|
push_state
|
|
71
|
+
redirect_to
|
|
72
|
+
reload
|
|
48
73
|
remove
|
|
49
74
|
remove_attribute
|
|
50
75
|
remove_css_class
|
|
@@ -56,10 +81,12 @@ module CableReady
|
|
|
56
81
|
set_cookie
|
|
57
82
|
set_dataset_property
|
|
58
83
|
set_focus
|
|
84
|
+
set_meta
|
|
59
85
|
set_property
|
|
60
86
|
set_storage_item
|
|
61
87
|
set_style
|
|
62
88
|
set_styles
|
|
89
|
+
set_title
|
|
63
90
|
set_value
|
|
64
91
|
text_content
|
|
65
92
|
]).freeze
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/engine"
|
|
4
|
+
|
|
5
|
+
module CableReady
|
|
6
|
+
class Engine < Rails::Engine
|
|
7
|
+
# If you don't want to precompile CableReady's assets (eg. because you're using webpack),
|
|
8
|
+
# you can do this in an initializer:
|
|
9
|
+
#
|
|
10
|
+
# config.after_initialize do
|
|
11
|
+
# config.assets.precompile -= CableReady::Engine::PRECOMPILE_ASSETS
|
|
12
|
+
# end
|
|
13
|
+
PRECOMPILE_ASSETS = %w[
|
|
14
|
+
cable_ready.js
|
|
15
|
+
cable_ready.umd.js
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
initializer "cable_ready.assets" do |app|
|
|
19
|
+
if app.config.respond_to?(:assets) && CableReady.config.precompile_assets
|
|
20
|
+
app.config.assets.precompile += PRECOMPILE_ASSETS
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
initializer "cable_ready.sanity_check" do
|
|
25
|
+
SanityChecker.check! unless Rails.env.production?
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
initializer "cable_ready.mimetype" do
|
|
29
|
+
Mime::Type.register "text/vnd.cable-ready.json", :cable_ready
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
initializer "cable_ready.renderer" do
|
|
33
|
+
ActiveSupport.on_load(:action_controller) do
|
|
34
|
+
ActionController::Renderers.add :operations do |operations, options|
|
|
35
|
+
warn "DEPRECATED: CableReady's `render operations:` call has been renamed to `render cable_ready:`. Please update your render call."
|
|
36
|
+
|
|
37
|
+
response.content_type ||= Mime[:cable_ready]
|
|
38
|
+
response.headers["X-Cable-Ready-Version"] = CableReady::VERSION
|
|
39
|
+
|
|
40
|
+
render json: operations.respond_to?(:dispatch) ? operations.dispatch : operations
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
ActionController::Renderers.add :cable_ready do |operations, options|
|
|
44
|
+
response.content_type ||= Mime[:cable_ready]
|
|
45
|
+
response.headers["X-Cable-Ready-Version"] = CableReady::VERSION
|
|
46
|
+
|
|
47
|
+
render json: operations.respond_to?(:dispatch) ? operations.dispatch : operations
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
initializer "cable_ready.importmap", before: "importmap" do |app|
|
|
53
|
+
if app.config.respond_to?(:importmap)
|
|
54
|
+
app.config.importmap.paths << Engine.root.join("lib/cable_ready/importmap.rb")
|
|
55
|
+
app.config.importmap.cache_sweepers << Engine.root.join("app/assets/javascripts")
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "action_view"
|
|
4
|
+
|
|
5
|
+
module CableReady
|
|
6
|
+
module Identifiable
|
|
7
|
+
def dom_id(record, prefix = nil)
|
|
8
|
+
return record.to_dom_selector if record.respond_to?(:to_dom_selector)
|
|
9
|
+
|
|
10
|
+
prefix = prefix.to_s.strip if prefix
|
|
11
|
+
|
|
12
|
+
id = if record.respond_to?(:to_dom_id)
|
|
13
|
+
record.to_dom_id
|
|
14
|
+
elsif ar_relation?(record)
|
|
15
|
+
[prefix, record.model_name.plural].compact.join("_")
|
|
16
|
+
elsif ar_base?(record)
|
|
17
|
+
ActionView::RecordIdentifier.dom_id(record, prefix)
|
|
18
|
+
else
|
|
19
|
+
[prefix, record.to_s.strip].compact.join("_")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
"##{id}".squeeze("#").strip.downcase
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def identifiable?(obj)
|
|
26
|
+
(
|
|
27
|
+
obj.respond_to?(:to_dom_selector) ||
|
|
28
|
+
obj.respond_to?(:to_dom_id) ||
|
|
29
|
+
ar_relation?(obj) ||
|
|
30
|
+
ar_base?(obj)
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def ar_relation?(obj)
|
|
37
|
+
return false if defined?(ActiveRecord).nil? || defined?(ActiveRecord::Relation).nil?
|
|
38
|
+
|
|
39
|
+
obj.is_a?(ActiveRecord::Relation)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def ar_base?(obj)
|
|
43
|
+
return false if defined?(ActiveRecord).nil? || defined?(ActiveRecord::Base).nil?
|
|
44
|
+
|
|
45
|
+
obj.is_a?(ActiveRecord::Base)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cable_ready/version"
|
|
4
|
+
|
|
5
|
+
### general utilities
|
|
6
|
+
|
|
7
|
+
def fetch(step_path, file)
|
|
8
|
+
relative_path = step_path + file
|
|
9
|
+
location = template_src + relative_path
|
|
10
|
+
|
|
11
|
+
Pathname.new(location)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def complete_step(step)
|
|
15
|
+
create_file "tmp/cable_ready_installer/#{step}", verbose: false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create_or_append(path, *args, &block)
|
|
19
|
+
FileUtils.touch(path)
|
|
20
|
+
append_file(path, *args, &block)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def current_template
|
|
24
|
+
ENV["LOCATION"].split("/").last.gsub(".rb", "")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def pack_path_missing?
|
|
28
|
+
return false unless pack_path.nil?
|
|
29
|
+
halt "#{friendly_pack_path} is missing. You need a valid application pack file to proceed."
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def halt(message)
|
|
33
|
+
say "❌ #{message}", :red
|
|
34
|
+
create_file "tmp/cable_ready_installer/halt", verbose: false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def backup(path, delete: false)
|
|
38
|
+
if !path.exist?
|
|
39
|
+
yield
|
|
40
|
+
return
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
backup_path = Pathname.new("#{path}.bak")
|
|
44
|
+
old_path = path.relative_path_from(Rails.root).to_s
|
|
45
|
+
filename = path.to_path.split("/").last
|
|
46
|
+
|
|
47
|
+
if backup_path.exist?
|
|
48
|
+
if backup_path.read == path.read
|
|
49
|
+
path.delete if delete
|
|
50
|
+
yield
|
|
51
|
+
return
|
|
52
|
+
end
|
|
53
|
+
backup_path.delete
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
copy_file(path, backup_path, verbose: false)
|
|
57
|
+
path.delete if delete
|
|
58
|
+
|
|
59
|
+
yield
|
|
60
|
+
|
|
61
|
+
if path.read != backup_path.read
|
|
62
|
+
create_or_append(backups_path, "#{old_path}\n", verbose: false)
|
|
63
|
+
end
|
|
64
|
+
say "📦 #{old_path} backed up as #{filename}.bak"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def add_gem(name)
|
|
68
|
+
create_or_append(add_gem_list, "#{name}\n", verbose: false)
|
|
69
|
+
say "☑️ Added #{name} to the Gemfile"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def remove_gem(name)
|
|
73
|
+
create_or_append(remove_gem_list, "#{name}\n", verbose: false)
|
|
74
|
+
say "❎ Removed #{name} from Gemfile"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def add_package(name)
|
|
78
|
+
create_or_append(package_list, "#{name}\n", verbose: false)
|
|
79
|
+
say "☑️ Enqueued #{name} to be added to dependencies"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def add_dev_package(name)
|
|
83
|
+
create_or_append(dev_package_list, "#{name}\n", verbose: false)
|
|
84
|
+
say "☑️ Enqueued #{name} to be added to dev dependencies"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def drop_package(name)
|
|
88
|
+
create_or_append(drop_package_list, "#{name}\n", verbose: false)
|
|
89
|
+
say "❎ Enqueued #{name} to be removed from dependencies"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def gemfile_hash
|
|
93
|
+
Digest::MD5.hexdigest(gemfile_path.read)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
### memoized values
|
|
97
|
+
|
|
98
|
+
def cr_npm_version
|
|
99
|
+
@cr_npm_version ||= CableReady::VERSION.gsub(".pre", "-pre")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def package_json
|
|
103
|
+
@package_json ||= Rails.root.join("package.json")
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def entrypoint
|
|
107
|
+
@entrypoint ||= File.read("tmp/cable_ready_installer/entrypoint")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def bundler
|
|
111
|
+
@bundler ||= File.read("tmp/cable_ready_installer/bundler")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def config_path
|
|
115
|
+
@config_path ||= Rails.root.join(entrypoint, "config")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def importmap_path
|
|
119
|
+
@importmap_path ||= Rails.root.join("config/importmap.rb")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def friendly_importmap_path
|
|
123
|
+
@friendly_importmap_path ||= importmap_path.relative_path_from(Rails.root).to_s
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def pack
|
|
127
|
+
@pack ||= pack_path.read
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def friendly_pack_path
|
|
131
|
+
@friendly_pack_path ||= pack_path.relative_path_from(Rails.root).to_s
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def pack_path
|
|
135
|
+
@pack_path ||= [
|
|
136
|
+
Rails.root.join(entrypoint, "application.js"),
|
|
137
|
+
Rails.root.join(entrypoint, "packs/application.js"),
|
|
138
|
+
Rails.root.join(entrypoint, "entrypoints/application.js")
|
|
139
|
+
].find(&:exist?)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def package_list
|
|
143
|
+
@package_list ||= Rails.root.join("tmp/cable_ready_installer/npm_package_list")
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def dev_package_list
|
|
147
|
+
@dev_package_list ||= Rails.root.join("tmp/cable_ready_installer/npm_dev_package_list")
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def drop_package_list
|
|
151
|
+
@drop_package_list ||= Rails.root.join("tmp/cable_ready_installer/drop_npm_package_list")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def template_src
|
|
155
|
+
@template_src ||= File.read("tmp/cable_ready_installer/template_src")
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def controllers_path
|
|
159
|
+
@controllers_path ||= Rails.root.join(entrypoint, "controllers")
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def gemfile_path
|
|
163
|
+
@gemfile_path ||= Rails.root.join("Gemfile")
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def gemfile
|
|
167
|
+
@gemfile ||= gemfile_path.read
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def prefix
|
|
171
|
+
# standard:disable Style/RedundantStringEscape
|
|
172
|
+
@prefix ||= {
|
|
173
|
+
"vite" => "..\/",
|
|
174
|
+
"webpacker" => "",
|
|
175
|
+
"shakapacker" => "",
|
|
176
|
+
"importmap" => "",
|
|
177
|
+
"esbuild" => ".\/"
|
|
178
|
+
}[bundler]
|
|
179
|
+
# standard:enable Style/RedundantStringEscape
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def application_record_path
|
|
183
|
+
@application_record_path ||= Rails.root.join("app/models/application_record.rb")
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def action_cable_initializer_path
|
|
187
|
+
@action_cable_initializer_path ||= Rails.root.join("config/initializers/action_cable.rb")
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def action_cable_initializer_working_path
|
|
191
|
+
@action_cable_initializer_working_path ||= Rails.root.join(working, "action_cable.rb")
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def development_path
|
|
195
|
+
@development_path ||= Rails.root.join("config/environments/development.rb")
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def development_working_path
|
|
199
|
+
@development_working_path ||= Rails.root.join(working, "development.rb")
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def backups_path
|
|
203
|
+
@backups_path ||= Rails.root.join("tmp/cable_ready_installer/backups")
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def add_gem_list
|
|
207
|
+
@add_gem_list ||= Rails.root.join("tmp/cable_ready_installer/add_gem_list")
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def remove_gem_list
|
|
211
|
+
@remove_gem_list ||= Rails.root.join("tmp/cable_ready_installer/remove_gem_list")
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def options_path
|
|
215
|
+
@options_path ||= Rails.root.join("tmp/cable_ready_installer/options")
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def options
|
|
219
|
+
@options ||= YAML.safe_load(File.read(options_path))
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def working
|
|
223
|
+
@working ||= Rails.root.join("tmp/cable_ready_installer/working")
|
|
224
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CableReady
|
|
4
|
+
class OperationBuilder
|
|
5
|
+
include Identifiable
|
|
6
|
+
attr_reader :identifier, :previous_selector
|
|
7
|
+
|
|
8
|
+
def self.finalizer_for(identifier)
|
|
9
|
+
proc {
|
|
10
|
+
channel = CableReady.config.observers.find { |o| o.try(:identifier) == identifier }
|
|
11
|
+
CableReady.config.delete_observer channel if channel
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(identifier)
|
|
16
|
+
@identifier = identifier
|
|
17
|
+
|
|
18
|
+
reset!
|
|
19
|
+
CableReady.config.operation_names.each { |name| add_operation_method name }
|
|
20
|
+
CableReady.config.add_observer self, :add_operation_method
|
|
21
|
+
ObjectSpace.define_finalizer self, self.class.finalizer_for(identifier)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def add_operation_method(name)
|
|
25
|
+
return if respond_to?(name)
|
|
26
|
+
singleton_class.public_send :define_method, name, ->(*args) {
|
|
27
|
+
if args.one? && args.first.respond_to?(:to_operation_options) && [Array, Hash].include?(args.first.to_operation_options.class)
|
|
28
|
+
case args.first.to_operation_options
|
|
29
|
+
when Array
|
|
30
|
+
selector, options = nil, args.first.to_operation_options
|
|
31
|
+
.select { |e| e.is_a?(Symbol) && args.first.respond_to?("to_#{e}".to_sym) }
|
|
32
|
+
.each_with_object({}) { |option, memo| memo[option.to_s] = args.first.send("to_#{option}".to_sym) }
|
|
33
|
+
when Hash
|
|
34
|
+
selector, options = nil, args.first.to_operation_options
|
|
35
|
+
else
|
|
36
|
+
raise TypeError, ":to_operation_options returned an #{args.first.to_operation_options.class.name}. Must be an Array or Hash."
|
|
37
|
+
end
|
|
38
|
+
else
|
|
39
|
+
selector, options = nil, args.first || {} # 1 or 0 params
|
|
40
|
+
selector, options = options, {} unless options.is_a?(Hash) # swap if only selector provided
|
|
41
|
+
selector, options = args[0, 2] if args.many? # 2 or more params
|
|
42
|
+
options.stringify_keys!
|
|
43
|
+
options.each { |key, value| options[key] = value.send("to_#{key}".to_sym) if value.respond_to?("to_#{key}".to_sym) }
|
|
44
|
+
end
|
|
45
|
+
options["selector"] = selector if selector && options.exclude?("selector")
|
|
46
|
+
options["selector"] = previous_selector if previous_selector && options.exclude?("selector")
|
|
47
|
+
if options.include?("selector")
|
|
48
|
+
@previous_selector = options["selector"]
|
|
49
|
+
options["selector"] = identifiable?(previous_selector) ? dom_id(previous_selector) : previous_selector
|
|
50
|
+
end
|
|
51
|
+
options["operation"] = name.to_s.camelize(:lower)
|
|
52
|
+
@enqueued_operations << options
|
|
53
|
+
self
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def to_json(*args)
|
|
58
|
+
@enqueued_operations.to_json(*args)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def apply!(operations = "[]")
|
|
62
|
+
operations = begin
|
|
63
|
+
JSON.parse(operations.is_a?(String) ? operations : operations.to_json)
|
|
64
|
+
rescue JSON::ParserError
|
|
65
|
+
{}
|
|
66
|
+
end
|
|
67
|
+
@enqueued_operations.concat(Array.wrap(operations))
|
|
68
|
+
self
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def operations_payload
|
|
72
|
+
@enqueued_operations.map { |operation| operation.deep_transform_keys! { |key| key.to_s.camelize(:lower) } }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def reset!
|
|
76
|
+
@enqueued_operations = []
|
|
77
|
+
@previous_selector = nil
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CableReady::SanityChecker
|
|
4
|
+
LATEST_VERSION_FORMAT = /^(\d+\.\d+\.\d+)$/
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
def check!
|
|
8
|
+
return if ENV["SKIP_SANITY_CHECK"]
|
|
9
|
+
return if CableReady.config.on_failed_sanity_checks == :ignore
|
|
10
|
+
return if called_by_generate_config?
|
|
11
|
+
return if called_by_rake?
|
|
12
|
+
|
|
13
|
+
new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def called_by_generate_config?
|
|
19
|
+
ARGV.include?("cable_ready:initializer")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def called_by_rake?
|
|
23
|
+
File.basename($PROGRAM_NAME) == "rake"
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def initializer_missing?
|
|
30
|
+
File.exist?(Rails.root.join("config", "initializers", "cable_ready.rb")) == false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def warn_and_exit(text)
|
|
34
|
+
puts
|
|
35
|
+
puts "Heads up! 🔥"
|
|
36
|
+
puts
|
|
37
|
+
puts text
|
|
38
|
+
puts
|
|
39
|
+
if CableReady.config.on_failed_sanity_checks == :exit
|
|
40
|
+
puts <<~INFO
|
|
41
|
+
To ignore any warnings and start the application anyway, you can set the SKIP_SANITY_CHECK environment variable:
|
|
42
|
+
|
|
43
|
+
SKIP_SANITY_CHECK=true rails
|
|
44
|
+
|
|
45
|
+
To do this permanently, add the following directive to the CableReady initializer:
|
|
46
|
+
|
|
47
|
+
CableReady.configure do |config|
|
|
48
|
+
config.on_failed_sanity_checks = :warn
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
INFO
|
|
52
|
+
if initializer_missing?
|
|
53
|
+
puts <<~INFO
|
|
54
|
+
You can create a CableReady initializer with the command:
|
|
55
|
+
|
|
56
|
+
bundle exec rails generate cable_ready:initializer
|
|
57
|
+
|
|
58
|
+
INFO
|
|
59
|
+
end
|
|
60
|
+
exit false if Rails.env.test? == false
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module CableReady
|
|
4
|
+
module StreamIdentifier
|
|
5
|
+
def verified_stream_identifier(signed_stream_identifier)
|
|
6
|
+
CableReady.signed_stream_verifier.verified signed_stream_identifier
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def signed_stream_identifier(compoundable)
|
|
10
|
+
CableReady.signed_stream_verifier.generate compoundable
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
data/lib/cable_ready/version.rb
CHANGED
data/lib/cable_ready.rb
CHANGED
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "
|
|
4
|
-
require "active_support/
|
|
5
|
-
require "cable_ready/
|
|
3
|
+
require "open-uri"
|
|
4
|
+
require "active_support/message_verifier"
|
|
5
|
+
require "cable_ready/identifiable"
|
|
6
|
+
require "cable_ready/operation_builder"
|
|
6
7
|
require "cable_ready/config"
|
|
7
8
|
require "cable_ready/broadcaster"
|
|
9
|
+
require "cable_ready/engine"
|
|
10
|
+
require "cable_ready/sanity_checker"
|
|
11
|
+
require "cable_ready/compoundable"
|
|
12
|
+
require "cable_ready/channel"
|
|
13
|
+
require "cable_ready/channels"
|
|
14
|
+
require "cable_ready/cable_car"
|
|
15
|
+
require "cable_ready/stream_identifier"
|
|
16
|
+
require "cable_ready/version"
|
|
17
|
+
require "cable_ready_helper"
|
|
8
18
|
|
|
9
19
|
module CableReady
|
|
10
|
-
class
|
|
11
|
-
|
|
20
|
+
class << self
|
|
21
|
+
def config
|
|
22
|
+
CableReady::Config.instance
|
|
23
|
+
end
|
|
12
24
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
25
|
+
def configure
|
|
26
|
+
yield config
|
|
27
|
+
end
|
|
16
28
|
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
def signed_stream_verifier
|
|
30
|
+
@signed_stream_verifier ||= ActiveSupport::MessageVerifier.new(config.verifier_key, digest: "SHA256", serializer: JSON)
|
|
31
|
+
end
|
|
19
32
|
end
|
|
20
33
|
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# TODO: remove me once CableReady 5.0 was released
|
|
4
|
+
|
|
5
|
+
require_relative "../app/helpers/cable_ready/view_helper"
|
|
6
|
+
|
|
7
|
+
module CableReadyHelper
|
|
8
|
+
def self.included(base)
|
|
9
|
+
warn "NOTICE: `CableReadyHelper` was renamed to `CableReady::ViewHelper`. Please update your include accordingly."
|
|
10
|
+
|
|
11
|
+
base.include(::CableReady::ViewHelper)
|
|
12
|
+
end
|
|
13
|
+
end
|