live_cable 0.3.0 → 0.4.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 +567 -0
- data/README.md +14 -2
- data/app/assets/javascript/controllers/live_controller.js +51 -7
- data/app/assets/javascript/live_cable.js +2 -0
- data/app/assets/javascript/loading.js +58 -6
- data/app/assets/javascript/subscriptions.js +292 -22
- data/app/channels/live_channel.rb +51 -29
- data/app/helpers/live_cable_helper.rb +31 -2
- data/lib/live_cable/action_cable_connection.rb +4 -1
- data/lib/live_cable/component/broadcasting.rb +37 -6
- data/lib/live_cable/component/dispatching.rb +36 -0
- data/lib/live_cable/component/lifecycle.rb +1 -1
- data/lib/live_cable/component/reactive_variables.rb +33 -5
- data/lib/live_cable/component/rendering.rb +30 -14
- data/lib/live_cable/component/streaming.rb +35 -4
- data/lib/live_cable/component.rb +4 -3
- data/lib/live_cable/connection/broadcasting.rb +15 -3
- data/lib/live_cable/connection/component_management.rb +12 -8
- data/lib/live_cable/connection/error_handling.rb +28 -7
- data/lib/live_cable/connection/messaging.rb +40 -52
- data/lib/live_cable/connection/state_management.rb +13 -16
- data/lib/live_cable/connection.rb +33 -0
- data/lib/live_cable/container.rb +17 -11
- data/lib/live_cable/defaults_signer.rb +95 -0
- data/lib/live_cable/delegation/array.rb +27 -1
- data/lib/live_cable/delegation/hash.rb +55 -1
- data/lib/live_cable/delegation/methods.rb +25 -1
- data/lib/live_cable/delegation/model.rb +12 -0
- data/lib/live_cable/delegator.rb +54 -6
- data/lib/live_cable/dispatch.rb +54 -0
- data/lib/live_cable/engine.rb +3 -1
- data/lib/live_cable/forbidden.rb +7 -0
- data/lib/live_cable/identity_digest.rb +27 -0
- data/lib/live_cable/model_observer.rb +37 -0
- data/lib/live_cable/observer_tracking.rb +10 -1
- data/lib/live_cable/predicate_builder.rb +13 -0
- data/lib/live_cable/render_context.rb +82 -8
- data/lib/live_cable/rendering/controller_renderer.rb +26 -0
- data/lib/live_cable/rendering/dependency_visitor.rb +68 -24
- data/lib/live_cable/rendering/handler.rb +1 -1
- data/lib/live_cable/rendering/method_analyzer.rb +18 -4
- data/lib/live_cable/rendering/method_collector.rb +13 -5
- data/lib/live_cable/rendering/partial.rb +13 -1
- data/lib/live_cable/rendering/partial_renderer.rb +59 -7
- data/lib/live_cable/rendering/render_result.rb +5 -0
- data/lib/live_cable/rendering/renderer.rb +18 -14
- data/lib/live_cable/rendering/view_buffer.rb +21 -0
- data/lib/live_cable/testing/render_state.rb +5 -3
- data/lib/live_cable/testing/test_channel.rb +6 -0
- data/lib/live_cable/testing/test_component.rb +3 -3
- data/lib/live_cable/testing.rb +9 -5
- data/lib/live_cable/version.rb +1 -1
- data/lib/live_cable.rb +32 -3
- metadata +9 -1
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LiveCable
|
|
4
|
+
module Rendering
|
|
5
|
+
# Appends to whichever buffer the view is writing to when the append happens,
|
|
6
|
+
# so a template block a view helper yields lands where plain ERB would put it.
|
|
7
|
+
class ViewBuffer
|
|
8
|
+
delegate :safe_append=, :append=, :safe_expr_append=, to: :output_buffer
|
|
9
|
+
|
|
10
|
+
def initialize(view_context)
|
|
11
|
+
@view_context = view_context
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def output_buffer
|
|
17
|
+
@view_context.output_buffer
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -6,14 +6,16 @@ module LiveCable
|
|
|
6
6
|
# mirroring what the JavaScript client does: the first refresh carries
|
|
7
7
|
# all parts, subsequent refreshes carry only the changed parts (nil
|
|
8
8
|
# means unchanged), and child components arrive as separate results
|
|
9
|
-
# referenced by <LiveCable child-live-id="..."> placeholders.
|
|
9
|
+
# referenced by <LiveCable child-live-id="..."> placeholders. Results for
|
|
10
|
+
# children at every depth arrive in the root's c, so the whole tree
|
|
11
|
+
# shares one set of child states.
|
|
10
12
|
class RenderState
|
|
11
13
|
CHILD_PLACEHOLDER = %r{<LiveCable child-live-id="(?<live_id>[^"]+)"></LiveCable>}
|
|
12
14
|
|
|
13
|
-
def initialize
|
|
15
|
+
def initialize(children = Hash.new { |hash, key| hash[key] = RenderState.new(hash) })
|
|
14
16
|
@parts_by_template = {}
|
|
15
17
|
@last_template = nil
|
|
16
|
-
@children =
|
|
18
|
+
@children = children
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
# @param refresh [Hash] A _refresh payload ({ h:, p:, c: })
|
|
@@ -12,17 +12,23 @@ module LiveCable
|
|
|
12
12
|
# @return [Array<Hash>] Payloads sent by components through this channel
|
|
13
13
|
attr_reader :transmissions
|
|
14
14
|
|
|
15
|
+
# @return [Array<Hash>] Every _refresh payload sent, including any
|
|
16
|
+
# since cleared from transmissions
|
|
17
|
+
attr_reader :refreshes
|
|
18
|
+
|
|
15
19
|
# @return [LiveCable::Testing::TestCableConnection]
|
|
16
20
|
attr_reader :connection
|
|
17
21
|
|
|
18
22
|
def initialize(identifiers = {})
|
|
19
23
|
@streams = {}
|
|
20
24
|
@transmissions = []
|
|
25
|
+
@refreshes = []
|
|
21
26
|
@connection = TestCableConnection.new(identifiers)
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
def broadcast(data)
|
|
25
30
|
@transmissions << data
|
|
31
|
+
@refreshes << data[:_refresh] if data.key?(:_refresh)
|
|
26
32
|
end
|
|
27
33
|
|
|
28
34
|
def stream_from(name, coder: nil, &block)
|
|
@@ -77,7 +77,7 @@ module LiveCable
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
# Forget previously captured broadcasts. Useful after mounting, to
|
|
80
|
-
# assert on the effects of a single action.
|
|
80
|
+
# assert on the effects of a single action. Doesn't affect rendered.
|
|
81
81
|
def clear_broadcasts
|
|
82
82
|
channel.transmissions.clear
|
|
83
83
|
end
|
|
@@ -98,8 +98,8 @@ module LiveCable
|
|
|
98
98
|
def rendered_html
|
|
99
99
|
state = RenderState.new
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
state.apply(
|
|
101
|
+
channel.refreshes.each do |refresh|
|
|
102
|
+
state.apply(refresh)
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
state.html
|
data/lib/live_cable/testing.rb
CHANGED
|
@@ -54,11 +54,15 @@ module LiveCable
|
|
|
54
54
|
|
|
55
55
|
test_component = TestComponent.new(instance, connection, TestChannel.new(identifiers))
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
begin
|
|
58
|
+
connection.add_component(instance)
|
|
59
|
+
instance.defaults = defaults
|
|
60
|
+
instance.apply_defaults
|
|
61
|
+
instance.connect(test_component.channel)
|
|
62
|
+
instance.broadcast_render(subscribed: true)
|
|
63
|
+
rescue StandardError => error
|
|
64
|
+
connection.handle_error(instance, error, channel: test_component.channel)
|
|
65
|
+
end
|
|
62
66
|
|
|
63
67
|
test_component
|
|
64
68
|
end
|
data/lib/live_cable/version.rb
CHANGED
data/lib/live_cable.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'logger'
|
|
3
4
|
require 'zeitwerk'
|
|
4
5
|
require 'herb'
|
|
5
6
|
|
|
@@ -19,18 +20,46 @@ require_relative '../app/helpers/live_cable_helper'
|
|
|
19
20
|
require_relative 'live'
|
|
20
21
|
|
|
21
22
|
module LiveCable
|
|
23
|
+
@warn_mutex = Mutex.new
|
|
24
|
+
@warned_messages = Set.new
|
|
25
|
+
|
|
26
|
+
# Log a warning through the Rails logger at most once per process for a
|
|
27
|
+
# given message. Used for performance and configuration hints (e.g. a
|
|
28
|
+
# component rendered without a .live.erb template) that would otherwise
|
|
29
|
+
# repeat on every render and flood the log.
|
|
30
|
+
def self.warn_once(message)
|
|
31
|
+
@warn_mutex.synchronize do
|
|
32
|
+
return unless @warned_messages.add?(message)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
logger.warn(message)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [Logger]
|
|
39
|
+
def self.logger
|
|
40
|
+
if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
|
41
|
+
Rails.logger
|
|
42
|
+
else
|
|
43
|
+
@fallback_logger ||= Logger.new($stderr)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
22
47
|
def self.instance_from_string(string, id)
|
|
23
48
|
klass = Live
|
|
24
49
|
klass_string = string.camelize
|
|
25
50
|
|
|
26
51
|
begin
|
|
27
52
|
klass_string.split('::').each do |part|
|
|
28
|
-
|
|
53
|
+
# inherit: false so component names that collide with a top-level
|
|
54
|
+
# constant (e.g. "string" -> ::String) don't resolve through Object's
|
|
55
|
+
# ancestry and slip past this guard, only to blow up later with a
|
|
56
|
+
# confusing NameError instead of this friendly message.
|
|
57
|
+
unless klass.const_defined?(part, false)
|
|
29
58
|
raise LiveCable::Error,
|
|
30
59
|
"Component Live::#{klass_string} not found, make sure it is located in the Live:: module"
|
|
31
60
|
end
|
|
32
61
|
|
|
33
|
-
klass = klass.const_get(part)
|
|
62
|
+
klass = klass.const_get(part, false)
|
|
34
63
|
end
|
|
35
64
|
rescue NameError
|
|
36
65
|
raise LiveCable::Error, "Invalid component name \"#{string}\" - Live::#{klass_string} not found"
|
|
@@ -38,7 +67,7 @@ module LiveCable
|
|
|
38
67
|
|
|
39
68
|
klass = "Live::#{klass_string}".safe_constantize
|
|
40
69
|
|
|
41
|
-
unless klass < LiveCable::Component
|
|
70
|
+
unless klass && klass < LiveCable::Component
|
|
42
71
|
raise LiveCable::Error, 'Components must extend LiveCable::Component'
|
|
43
72
|
end
|
|
44
73
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: live_cable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Craig Blanchette
|
|
@@ -136,6 +136,7 @@ files:
|
|
|
136
136
|
- lib/live_cable/action_cable_connection.rb
|
|
137
137
|
- lib/live_cable/component.rb
|
|
138
138
|
- lib/live_cable/component/broadcasting.rb
|
|
139
|
+
- lib/live_cable/component/dispatching.rb
|
|
139
140
|
- lib/live_cable/component/events.rb
|
|
140
141
|
- lib/live_cable/component/identification.rb
|
|
141
142
|
- lib/live_cable/component/lifecycle.rb
|
|
@@ -151,18 +152,24 @@ files:
|
|
|
151
152
|
- lib/live_cable/connection/messaging.rb
|
|
152
153
|
- lib/live_cable/connection/state_management.rb
|
|
153
154
|
- lib/live_cable/container.rb
|
|
155
|
+
- lib/live_cable/defaults_signer.rb
|
|
154
156
|
- lib/live_cable/delegation/array.rb
|
|
155
157
|
- lib/live_cable/delegation/hash.rb
|
|
156
158
|
- lib/live_cable/delegation/methods.rb
|
|
157
159
|
- lib/live_cable/delegation/model.rb
|
|
158
160
|
- lib/live_cable/delegator.rb
|
|
161
|
+
- lib/live_cable/dispatch.rb
|
|
159
162
|
- lib/live_cable/engine.rb
|
|
160
163
|
- lib/live_cable/error.rb
|
|
164
|
+
- lib/live_cable/forbidden.rb
|
|
165
|
+
- lib/live_cable/identity_digest.rb
|
|
161
166
|
- lib/live_cable/model_observer.rb
|
|
162
167
|
- lib/live_cable/observer.rb
|
|
163
168
|
- lib/live_cable/observer_tracking.rb
|
|
169
|
+
- lib/live_cable/predicate_builder.rb
|
|
164
170
|
- lib/live_cable/render_context.rb
|
|
165
171
|
- lib/live_cable/rendering/compiler.rb
|
|
172
|
+
- lib/live_cable/rendering/controller_renderer.rb
|
|
166
173
|
- lib/live_cable/rendering/dependency_visitor.rb
|
|
167
174
|
- lib/live_cable/rendering/handler.rb
|
|
168
175
|
- lib/live_cable/rendering/method_analyzer.rb
|
|
@@ -172,6 +179,7 @@ files:
|
|
|
172
179
|
- lib/live_cable/rendering/partial_renderer.rb
|
|
173
180
|
- lib/live_cable/rendering/render_result.rb
|
|
174
181
|
- lib/live_cable/rendering/renderer.rb
|
|
182
|
+
- lib/live_cable/rendering/view_buffer.rb
|
|
175
183
|
- lib/live_cable/testing.rb
|
|
176
184
|
- lib/live_cable/testing/render_state.rb
|
|
177
185
|
- lib/live_cable/testing/test_cable_connection.rb
|