live 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f33999c1164c25bd9fccfac8d7be846b6ad536ae04da0302b450662a7db1624f
4
- data.tar.gz: 0bbd2f3b7b06819b9ae5cb8b057277a1885fe7d44598238a46d21704eb62173c
3
+ metadata.gz: a836ae392c3fb38c18c6317e94786d0ad943d01afe1486026333148531bb681b
4
+ data.tar.gz: e5f9ecb4911b74fbecad809d068d8a076d8cd4d93c8d015f9d709ccb737c5b76
5
5
  SHA512:
6
- metadata.gz: a5bcd37c979d0155cd70b822f7959ae7d97661c7652f2e945cc9b9ff6ff4a099600894f8348b0b135abeb90dd1156e724ed2b063b68c2c908c5823240b41af3c
7
- data.tar.gz: 68aae390d5d46ca5e81d4f333a40d3db1e9fbf8394d41600576dace4b0a2bd2df5c94ab8795cbdd156bab01e07ecc0b372d84853c5e99c965481b4fb1f9a0ce6
6
+ metadata.gz: b896681bad42c651744baaef703204ef112e226446ce3ca530453f4247053f0dde771897d898a45b0a2c5ff64e3291e0e1a856d8e05041dcc5424d28e093aed1
7
+ data.tar.gz: bb53aa53e263bcbc03ae22dc8280c21cdc388e261430ac9e70533f6a551a360341bbffa255a0271cc1e88cd4d7c1d2757b185fd057b75d0e224920d2205d74ff
data/lib/live/element.rb CHANGED
@@ -23,7 +23,10 @@
23
23
  require 'json'
24
24
 
25
25
  module Live
26
+ # Represents a single dynamic content area on the page.
26
27
  class Element
28
+ # @parameter id [String] The unique identifier within the page.
29
+ # @parameter data [Hash] The data associated with the element, typically stored as `data-` attributes.
27
30
  def initialize(id, **data)
28
31
  @id = id
29
32
  @data = data
@@ -32,8 +35,11 @@ module Live
32
35
  @page = nil
33
36
  end
34
37
 
38
+ # The unique id within the bound page.
35
39
  attr :id
36
40
 
41
+ # Generate a JavaScript string which forwards the specified event to the server.
42
+ # @parameter details [Hash] The details associated with the forwarded event.
37
43
  def forward(details = nil)
38
44
  if details
39
45
  "live.forward(#{JSON.dump(@id)}, event, #{JSON.dump(details)})"
@@ -42,13 +48,25 @@ module Live
42
48
  end
43
49
  end
44
50
 
51
+ # Bind this tag to a dynamically updating page.
52
+ # @parameter page [Live::Page]
45
53
  def bind(page)
46
54
  @page = page
47
55
  end
48
56
 
49
- def handle(event, details)
57
+ def close
58
+ @page = nil
59
+ end
60
+
61
+ # Handle a client event, typically as triggered by {#forward}.
62
+ # @parameter event [String] The type of the event.
63
+ # @parameter details [Hash] The associated details if any.
64
+ def handle(event, details = nil)
50
65
  end
51
66
 
67
+ # Enqueue a remote procedure call to the currently bound page.
68
+ # @parameter method [Symbol] The name of the remote functio to invoke.
69
+ # @parameter arguments [Array]
52
70
  def rpc(method, arguments)
53
71
  # This update might not be sent right away. Therefore, mutable arguments may be serialized to JSON at a later time (or never). This could be a race condition:
54
72
  @page.updates.enqueue([method, arguments])
data/lib/live/page.rb CHANGED
@@ -27,7 +27,9 @@ require 'async'
27
27
  require 'async/queue'
28
28
 
29
29
  module Live
30
+ # Represents a connected client page with bound dynamic content areas.
30
31
  class Page
32
+ # @parameter resolver [Live::Resolver] Used to resolve client-side elements to server-side element instances.
31
33
  def initialize(resolver)
32
34
  @resolver = resolver
33
35
 
@@ -35,18 +37,30 @@ module Live
35
37
  @updates = Async::Queue.new
36
38
  end
37
39
 
40
+ # The queue of outstanding events to be sent to the client.
38
41
  attr :updates
39
42
 
43
+ # Bind a client-side element to a server side element.
44
+ # @parameter element [Live::Element] The element to bind.
40
45
  def bind(element)
41
46
  @elements[element.id] = element
42
47
 
43
48
  element.bind(self)
44
49
  end
45
50
 
51
+ # Resolve a client-side element to a server side instance.
52
+ # @parameter id [String] The unique identifier within the page.
53
+ # @parameter data [Hash] The data associated with the element, typically stored as `data-` attributes.
46
54
  def resolve(id, data)
47
55
  @resolver.call(id, data)
48
56
  end
49
57
 
58
+ # Handle an event from the client. If the element could not be found, it is silently ignored.
59
+ # @parameter id [String] The unique identifier of the element which forwarded the event.
60
+ # @parameter event [String] The type of the event.
61
+ # @parameter details [Hash] The associated details if any.
62
+ # @returns [Object] The result of the element handler, if the element was found.
63
+ # @returns [Nil] If the element could not be found.
50
64
  def handle(id, event, details)
51
65
  if element = @elements[id]
52
66
  return element.handle(event, details)
@@ -57,39 +71,42 @@ module Live
57
71
  return nil
58
72
  end
59
73
 
60
- def run(connection)
61
- reader_task = start_reader(connection)
62
-
63
- while update = @updates.dequeue
64
- Console.logger.debug(self, "Sending update:", update)
65
-
66
- connection.write(update)
67
- connection.flush if @updates.empty?
74
+ def close
75
+ @elements.each do |id, element|
76
+ element.close
68
77
  end
69
- ensure
70
- reader_task&.stop
71
78
  end
72
79
 
73
- private
74
-
75
- def start_reader(connection)
76
- Async do
77
- while message = connection.read
78
- Console.logger.debug(self, "Reading message:", message)
80
+ # Run the event handling loop with the given websocket connection.
81
+ # @parameter connection [Async::WebSocket::Connection]
82
+ def run(connection)
83
+ queue_task = Async do
84
+ while update = @updates.dequeue
85
+ Console.logger.debug(self, "Sending update:", update)
79
86
 
80
- if id = message[:bind] and data = message[:data]
81
- if element = self.resolve(id, data)
82
- self.bind(element)
83
- else
84
- Console.logger.warn(self, "Could not resolve element:", message)
85
- end
86
- elsif id = message[:id]
87
- self.handle(id, message[:event], message[:details])
87
+ connection.write(update)
88
+ connection.flush if @updates.empty?
89
+ end
90
+ end
91
+
92
+ while message = connection.read
93
+ Console.logger.debug(self, "Reading message:", message)
94
+
95
+ if id = message[:bind] and data = message[:data]
96
+ if element = self.resolve(id, data)
97
+ self.bind(element)
88
98
  else
89
- Console.logger.warn(self, "Unhandled message:", message)
99
+ Console.logger.warn(self, "Could not resolve element:", message)
90
100
  end
101
+ elsif id = message[:id]
102
+ self.handle(id, message[:event], message[:details])
103
+ else
104
+ Console.logger.warn(self, "Unhandled message:", message)
91
105
  end
92
106
  end
107
+ ensure
108
+ self.close
109
+ queue_task&.stop
93
110
  end
94
111
  end
95
112
  end
data/lib/live/resolver.rb CHANGED
@@ -34,6 +34,7 @@ module Live
34
34
  @allowed = {}
35
35
  end
36
36
 
37
+ # @attribute [Hash(String, Class)] A map of allowed class names.
37
38
  attr :allowed
38
39
 
39
40
  def freeze
data/lib/live/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Live
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/live/view.rb CHANGED
@@ -24,22 +24,31 @@ require_relative 'element'
24
24
  require 'trenni/builder'
25
25
 
26
26
  module Live
27
+ # Represents a single division of content on the page an provides helpers for rendering the content.
27
28
  class View < Element
29
+ # Replace the content of the client-side element by rendering this view.
28
30
  def replace!
29
31
  rpc(:replace, [@id, self.to_html])
30
32
  end
31
33
 
32
- def append!(node)
33
- rpc(:append, [@id, node.to_html])
34
+ # Append to the content of the client-side element by appending the specified element.
35
+ # @parameter node [Live::Element] The element to append.
36
+ def append!(element)
37
+ rpc(:append, [@id, element.to_html])
34
38
  end
35
39
 
36
- def prepend!(node)
37
- rpc(:prepend, [@id, node.to_html])
40
+ # Prepend to the content of the client-side element by appending the specified element.
41
+ # @parameter node [Live::Element] The element to prepend.
42
+ def prepend!(element)
43
+ rpc(:prepend, [@id, element.to_html])
38
44
  end
39
45
 
46
+ # Render the element.
47
+ # @parameter builder [Trenni::Builder] The HTML builder.
40
48
  def render(builder)
41
49
  end
42
50
 
51
+ # @returns [Object] The generated HTML.
43
52
  def to_html
44
53
  Trenni::Builder.fragment do |builder|
45
54
  builder.tag :div, id: @id, class: 'live', data: @data do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: live
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-19 00:00:00.000000000 Z
11
+ date: 2021-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: trenni