y-rb 0.6.0-x86_64-linux-gnu
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 +7 -0
- data/ext/yrb/Cargo.toml +21 -0
- data/ext/yrb/extconf.rb +6 -0
- data/ext/yrb/src/lib.rs +649 -0
- data/ext/yrb/src/utils.rs +64 -0
- data/ext/yrb/src/yany.rs +46 -0
- data/ext/yrb/src/yarray.rs +191 -0
- data/ext/yrb/src/yattrs.rs +39 -0
- data/ext/yrb/src/yawareness.rs +151 -0
- data/ext/yrb/src/ydiff.rs +19 -0
- data/ext/yrb/src/ydoc.rs +113 -0
- data/ext/yrb/src/ymap.rs +175 -0
- data/ext/yrb/src/ytext.rs +235 -0
- data/ext/yrb/src/ytransaction.rs +127 -0
- data/ext/yrb/src/yvalue.rs +256 -0
- data/ext/yrb/src/yxml_element.rs +280 -0
- data/ext/yrb/src/yxml_fragment.rs +129 -0
- data/ext/yrb/src/yxml_text.rs +177 -0
- data/lib/3.1/yrb.so +0 -0
- data/lib/3.2/yrb.so +0 -0
- data/lib/3.3/yrb.so +0 -0
- data/lib/3.4/yrb.so +0 -0
- data/lib/y/array.rb +371 -0
- data/lib/y/awareness.rb +290 -0
- data/lib/y/diff.rb +38 -0
- data/lib/y/doc.rb +313 -0
- data/lib/y/map.rb +199 -0
- data/lib/y/text.rb +383 -0
- data/lib/y/transaction.rb +189 -0
- data/lib/y/version.rb +5 -0
- data/lib/y/xml.rb +1141 -0
- data/lib/y-rb.rb +24 -0
- data/lib/y.rb +3 -0
- metadata +143 -0
data/lib/y/awareness.rb
ADDED
@@ -0,0 +1,290 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Y
|
4
|
+
# The Awareness class implements a simple shared state protocol that can be
|
5
|
+
# used for non-persistent data like awareness information (cursor, username,
|
6
|
+
# status, ..). Each client can update its own local state and listen to state
|
7
|
+
# changes of remote clients.
|
8
|
+
#
|
9
|
+
# Each client is identified by a unique client id (something we borrow from
|
10
|
+
# doc.client_id). A client can override its own state by propagating a message
|
11
|
+
# with an increasing timestamp (clock). If such a message is received, it is
|
12
|
+
# applied if the known state of that client is older than the new state
|
13
|
+
# (`clock < new_clock`). If a client thinks that a remote client is offline,
|
14
|
+
# it may propagate a message with `{ clock, state: null, client }`. If such a
|
15
|
+
# message is received, and the known clock of that client equals the received
|
16
|
+
# clock, it will clean the state.
|
17
|
+
#
|
18
|
+
# Before a client disconnects, it should propagate a null state with an
|
19
|
+
# updated clock.
|
20
|
+
#
|
21
|
+
# Awareness is an integral part of collaborative applications, you can read
|
22
|
+
# more about the concept here: https://docs.yjs.dev/getting-started/adding-awareness
|
23
|
+
#
|
24
|
+
# @example Instantiate awareness instance and encode update for broadcast
|
25
|
+
# local_state = {
|
26
|
+
# editing: { field: "description", pos: 0 },
|
27
|
+
# name: "Hannes Moser"
|
28
|
+
# }
|
29
|
+
#
|
30
|
+
# awareness = Y::Awareness.new
|
31
|
+
# awareness.local_state = local_state
|
32
|
+
# awareness.diff # [1,227,245,175,195,11,1,65,123, …]
|
33
|
+
#
|
34
|
+
# @example Two connected clients
|
35
|
+
# local_state_a = { name: "User A" }
|
36
|
+
#
|
37
|
+
# client_a = Y::Awareness.new
|
38
|
+
# client_a.local_state = local_state
|
39
|
+
#
|
40
|
+
# local_state_b = { name: "User B" }
|
41
|
+
#
|
42
|
+
# client_b = Y::Awareness.new
|
43
|
+
# client_b.local_state = local_state_b
|
44
|
+
#
|
45
|
+
# client_a.sync(client_b.diff)
|
46
|
+
# client_a.clients # {1242157267=>"{\"name\":\"User A\"}", 2401067547=>…
|
47
|
+
class Awareness
|
48
|
+
# Applies an incoming update. This gets the local awareness instance in
|
49
|
+
# sync with changes from another client. i.e., updates the state of another
|
50
|
+
# user in the local awareness instance.
|
51
|
+
#
|
52
|
+
# @example Apply an incoming update
|
53
|
+
# update = [1,227,245,175,195,11,1,65,123, …]
|
54
|
+
#
|
55
|
+
# awareness = Y::Awareness.new
|
56
|
+
# awareness.sync(update)
|
57
|
+
#
|
58
|
+
# @param diff [Array<Integer>] A binary encoded update
|
59
|
+
# @return [void]
|
60
|
+
def sync(diff)
|
61
|
+
yawareness_apply_update(diff)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Clears out a state of a current client, effectively marking it as
|
65
|
+
# disconnected.
|
66
|
+
#
|
67
|
+
# @return [void]
|
68
|
+
def clean_local_state
|
69
|
+
yawareness_clean_local_state
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns a globally unique client ID of an underlying Doc.
|
73
|
+
#
|
74
|
+
# @return [Integer] Returns the client_id of the local user
|
75
|
+
def client_id
|
76
|
+
yawareness_client_id
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns a state map of all of the clients tracked by current Awareness
|
80
|
+
# instance. Those states are identified by their corresponding ClientIDs.
|
81
|
+
# The associated state is represented and replicated to other clients as a
|
82
|
+
# JSON string.
|
83
|
+
#
|
84
|
+
# @example Instantiate awareness instance and encode update for broadcast
|
85
|
+
# local_state = {
|
86
|
+
# editing: { field: "description", pos: 0 },
|
87
|
+
# name: "Hannes Moser"
|
88
|
+
# }
|
89
|
+
#
|
90
|
+
# awareness = Y::Awareness.new
|
91
|
+
# awareness.local_state = local_state
|
92
|
+
# awareness.clients # {312134501=>"{\"editing\":{\"field\":\"descriptio …
|
93
|
+
#
|
94
|
+
# @return [Hash] All clients and their current state
|
95
|
+
def clients
|
96
|
+
transform = yawareness_clients.map do |client_id, state|
|
97
|
+
[client_id, JSON.parse!(state)]
|
98
|
+
end
|
99
|
+
transform.to_h
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns the state of the local Awareness instance.
|
103
|
+
#
|
104
|
+
# @example Create local state and inspect it
|
105
|
+
# local_state = {
|
106
|
+
# editing: { field: "description", pos: 0 },
|
107
|
+
# name: "Hannes Moser"
|
108
|
+
# }
|
109
|
+
#
|
110
|
+
# awareness = Y::Awareness.new
|
111
|
+
# awareness.local_state = local_state
|
112
|
+
# awareness.local_state # { editing: { field: "description", ...
|
113
|
+
#
|
114
|
+
# @return [String] The current state of the local client
|
115
|
+
def local_state
|
116
|
+
json = yawareness_local_state
|
117
|
+
JSON.parse!(json) if json
|
118
|
+
end
|
119
|
+
|
120
|
+
# Sets a current Awareness instance state to a corresponding JSON string.
|
121
|
+
# This state will be replicated to other clients as part of the
|
122
|
+
# AwarenessUpdate.
|
123
|
+
#
|
124
|
+
# @example Set local state
|
125
|
+
# local_state = {
|
126
|
+
# editing: { field: "description", pos: 0 },
|
127
|
+
# name: "Hannes Moser"
|
128
|
+
# }
|
129
|
+
#
|
130
|
+
# awareness = Y::Awareness.new
|
131
|
+
# awareness.local_state = local_state
|
132
|
+
#
|
133
|
+
# @param [#to_json] state
|
134
|
+
# @return [void]
|
135
|
+
def local_state=(state)
|
136
|
+
raise "state cannot be encoded to JSON" unless state.respond_to? :to_json
|
137
|
+
|
138
|
+
yawareness_set_local_state(state.to_json)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Subscribes to changes
|
142
|
+
#
|
143
|
+
# @return [Integer] The subscription ID
|
144
|
+
def attach(callback = nil, &block)
|
145
|
+
return yawareness_on_update(callback) unless callback.nil?
|
146
|
+
|
147
|
+
yawareness_on_update(block.to_proc) unless block.nil?
|
148
|
+
end
|
149
|
+
|
150
|
+
# Clears out a state of a given client, effectively marking it as
|
151
|
+
# disconnected.
|
152
|
+
#
|
153
|
+
# @param client_id [Integer] Clears the state for given client_id
|
154
|
+
# @return [void]
|
155
|
+
def remove_state(client_id)
|
156
|
+
yawareness_remove_state(client_id)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns a serializable update object which is representation of a current
|
160
|
+
# Awareness state.
|
161
|
+
#
|
162
|
+
# @return [::Array<Integer>] Binary encoded update of the local instance
|
163
|
+
def diff
|
164
|
+
yawareness_update
|
165
|
+
end
|
166
|
+
|
167
|
+
# Returns a serializable update object which is representation of a current
|
168
|
+
# Awareness state. Unlike Awareness::update, this method variant allows to
|
169
|
+
# prepare update only for a subset of known clients. These clients must all
|
170
|
+
# be known to a current Awareness instance, otherwise a
|
171
|
+
# Error::ClientNotFound error will be returned.
|
172
|
+
#
|
173
|
+
# @param clients [::Array<Integer>] A list of client IDs
|
174
|
+
# @return [String] Binary encoded update including all given client IDs
|
175
|
+
def diff_with_clients(*clients)
|
176
|
+
yawareness_update_with_clients(clients)
|
177
|
+
end
|
178
|
+
|
179
|
+
# rubocop:disable Lint/UselessAccessModifier
|
180
|
+
private
|
181
|
+
|
182
|
+
# @!method yawareness_apply_update(update)
|
183
|
+
# Applies an update
|
184
|
+
#
|
185
|
+
# @param A [Y::AwarenessUpdate] Structure that represents an encodable state
|
186
|
+
# of an Awareness struct.
|
187
|
+
# @!visibility private
|
188
|
+
|
189
|
+
# @!method yawareness_apply_update(update)
|
190
|
+
# Applies an update
|
191
|
+
#
|
192
|
+
# @param A [Y::AwarenessUpdate] Structure that represents an encodable state
|
193
|
+
# of an Awareness struct.
|
194
|
+
# @!visibility private
|
195
|
+
|
196
|
+
# @!method yawareness_clean_local_state
|
197
|
+
# Clears out a state of a current client , effectively marking it as
|
198
|
+
# disconnected.
|
199
|
+
# @!visibility private
|
200
|
+
|
201
|
+
# @!method yawareness_client_id
|
202
|
+
# Returns a globally unique client ID of an underlying Doc.
|
203
|
+
# @return [Integer] The Client ID
|
204
|
+
# @!visibility private
|
205
|
+
|
206
|
+
# @!method yawareness_clients
|
207
|
+
# Returns a state map of all of the clients
|
208
|
+
# tracked by current Awareness instance. Those states are identified by
|
209
|
+
# their corresponding ClientIDs. The associated state is represented and
|
210
|
+
# replicated to other clients as a JSON string.
|
211
|
+
#
|
212
|
+
# @return [Hash<Integer, String>] Map of clients
|
213
|
+
# @!visibility private
|
214
|
+
|
215
|
+
# @!method yawareness_local_state
|
216
|
+
#
|
217
|
+
# @return [String, nil] Returns a JSON string state representation of a
|
218
|
+
# current Awareness instance.
|
219
|
+
# @!visibility private
|
220
|
+
|
221
|
+
# @!method yawareness_on_update(callback, &block)
|
222
|
+
#
|
223
|
+
# @param callback [callback]
|
224
|
+
# @return [Integer] The subscription ID
|
225
|
+
# @!visibility private
|
226
|
+
|
227
|
+
# @!method yawareness_remove_on_update(subscription_id)
|
228
|
+
#
|
229
|
+
# @param subscription_id [Integer] The subscription id to remove
|
230
|
+
# @!visibility private
|
231
|
+
|
232
|
+
# @!method yawareness_remove_state(client_id)
|
233
|
+
# Clears out a state of a given client, effectively marking it as
|
234
|
+
# disconnected.
|
235
|
+
#
|
236
|
+
# @param client_id [Integer] A Client ID
|
237
|
+
# @return [String, nil] Returns a JSON string state representation of a
|
238
|
+
# current Awareness instance.
|
239
|
+
# @!visibility private
|
240
|
+
|
241
|
+
# @!method yawareness_set_local_state(state)
|
242
|
+
# Sets a current Awareness instance state to a corresponding JSON string.
|
243
|
+
# This state will be replicated to other clients as part of the
|
244
|
+
# AwarenessUpdate and it will trigger an event to be emitted if current
|
245
|
+
# instance was created using [Awareness::with_observer] method.
|
246
|
+
#
|
247
|
+
# @param Returns [String] A state map of all of the clients tracked by
|
248
|
+
# current Awareness instance. Those states are identified by their
|
249
|
+
# corresponding ClientIDs. The associated state is represented and
|
250
|
+
# replicated to other clients as a JSON string.
|
251
|
+
# @!visibility private
|
252
|
+
|
253
|
+
# @!method yawareness_update
|
254
|
+
# Returns a serializable update object which is representation of a
|
255
|
+
# current Awareness state.
|
256
|
+
#
|
257
|
+
# @return [Y::AwarenessUpdate] The update object
|
258
|
+
# @!visibility private
|
259
|
+
|
260
|
+
# @!method yawareness_update_with_clients(clients)
|
261
|
+
# Returns a serializable update object which is representation of a
|
262
|
+
# current Awareness state. Unlike [Y::Awareness#update], this method
|
263
|
+
# variant allows to prepare update only for a subset of known clients.
|
264
|
+
# These clients must all be known to a current Awareness instance,
|
265
|
+
# otherwise an error will be returned.
|
266
|
+
#
|
267
|
+
# @param clients [::Array<Integer>]
|
268
|
+
# @return [::Array<Integer>] A serialized (binary encoded) update object
|
269
|
+
# @!visibility private
|
270
|
+
|
271
|
+
# rubocop:enable Lint/UselessAccessModifier
|
272
|
+
end
|
273
|
+
|
274
|
+
# @!visibility private
|
275
|
+
class AwarenessEvent
|
276
|
+
private # rubocop:disable Lint/UselessAccessModifier
|
277
|
+
|
278
|
+
# @!method added
|
279
|
+
# @return [::Array<Integer>] Added clients
|
280
|
+
# @!visibility private
|
281
|
+
|
282
|
+
# @!method updated
|
283
|
+
# @return [::Array<Integer>] Updated clients
|
284
|
+
# @!visibility private
|
285
|
+
|
286
|
+
# @!method removed
|
287
|
+
# @return [::Array<Integer>] Removed clients
|
288
|
+
# @!visibility private
|
289
|
+
end
|
290
|
+
end
|
data/lib/y/diff.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Y
|
4
|
+
# A representation of an uniformly-formatted chunk of rich context stored by
|
5
|
+
# Text or XmlText. It contains a value (which could be a string, embedded
|
6
|
+
# object or another shared type) with optional formatting attributes wrapping
|
7
|
+
# around this chunk.
|
8
|
+
class Diff
|
9
|
+
# @return [Object]
|
10
|
+
def insert
|
11
|
+
ydiff_insert
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Hash]
|
15
|
+
def attrs
|
16
|
+
ydiff_attrs
|
17
|
+
end
|
18
|
+
|
19
|
+
# Convert the diff to a Hash representation
|
20
|
+
#
|
21
|
+
# @return [Hash]
|
22
|
+
def to_h
|
23
|
+
{
|
24
|
+
insert: ydiff_insert,
|
25
|
+
attrs: ydiff_attrs
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
# @!method ydiff_insert()
|
30
|
+
# Returns string representation of text
|
31
|
+
#
|
32
|
+
# @return [Object]
|
33
|
+
|
34
|
+
# @!method ydiff_attrs()
|
35
|
+
#
|
36
|
+
# @return [Hash]
|
37
|
+
end
|
38
|
+
end
|
data/lib/y/doc.rb
ADDED
@@ -0,0 +1,313 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "transaction"
|
4
|
+
|
5
|
+
module Y
|
6
|
+
# @example Create a local and remote doc and syncs the diff
|
7
|
+
# local = Y::Doc.new
|
8
|
+
# local_map = local.get_map("my map")
|
9
|
+
# local_map[:hello] = "world"
|
10
|
+
#
|
11
|
+
# remote = Y::Doc.new
|
12
|
+
#
|
13
|
+
# diff = local.diff(remote.state)
|
14
|
+
# remote.sync(diff)
|
15
|
+
#
|
16
|
+
# remote_map = remote.get_map("my_map")
|
17
|
+
# pp remote_map.to_h #=> {hello: "world"}
|
18
|
+
class Doc
|
19
|
+
ZERO_STATE = [0].freeze
|
20
|
+
private_constant :ZERO_STATE
|
21
|
+
|
22
|
+
ZERO_STATE_V2 = [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0].freeze
|
23
|
+
private_constant :ZERO_STATE_V2
|
24
|
+
|
25
|
+
# Attach a listener to document changes. If one of the data structures is
|
26
|
+
# changes, the block is called with the update as its only argument.
|
27
|
+
#
|
28
|
+
# @yield [update] Called when document is updated
|
29
|
+
# @yieldparam [Array<Integer>] update The encoded document updates
|
30
|
+
|
31
|
+
# Example: Attach listener to document changes
|
32
|
+
# doc = described_class.new
|
33
|
+
# doc.attach { |update| pp update }
|
34
|
+
#
|
35
|
+
# text = doc.get_text("my text")
|
36
|
+
# text << "1"
|
37
|
+
def attach(&block)
|
38
|
+
ydoc_observe_update(block)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Commit current transaction
|
42
|
+
#
|
43
|
+
# This is a convenience method that invokes {Y::Transaction#commit} on the
|
44
|
+
# current transaction used by this document.
|
45
|
+
#
|
46
|
+
# @return [void]
|
47
|
+
def commit
|
48
|
+
current_transaction(&:commit)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Create a diff between this document and another document. The diff is
|
52
|
+
# created based on a state vector provided by the other document. It only
|
53
|
+
# returns the missing blocks, as binary encoded sequence.
|
54
|
+
#
|
55
|
+
# @param state [::Array<Integer>] The state to create the diff against
|
56
|
+
# @return [::Array<Integer>] Binary encoded diff
|
57
|
+
def diff(state = ZERO_STATE)
|
58
|
+
current_transaction { |tx| ydoc_encode_diff_v1(tx, state) }
|
59
|
+
end
|
60
|
+
|
61
|
+
# Create a v2 diff between this document and another document. The diff is
|
62
|
+
# created based on a state vector provided by the other document. It only
|
63
|
+
# returns the missing blocks, as binary encoded sequence.
|
64
|
+
#
|
65
|
+
# @param state [::Array<Integer>] The state to create the diff against
|
66
|
+
# @return [::Array<Integer>] Binary encoded diff
|
67
|
+
def diff_v2(state = ZERO_STATE_V2)
|
68
|
+
current_transaction { |tx| ydoc_encode_diff_v2(tx, state) }
|
69
|
+
end
|
70
|
+
|
71
|
+
# Creates a full diff for the current document. It is similar to {#diff},
|
72
|
+
# but does not take a state. Instead it creates an empty state and passes it
|
73
|
+
# to the encode_diff function.
|
74
|
+
#
|
75
|
+
# @return [::Array<Integer>] Binary encoded diff
|
76
|
+
def full_diff
|
77
|
+
diff
|
78
|
+
end
|
79
|
+
|
80
|
+
# Gets or creates a new array by name
|
81
|
+
#
|
82
|
+
# If the optional values array is present, fills the array up with elements
|
83
|
+
# from the provided array. If the array already exists and isn't
|
84
|
+
# empty, elements are pushed to the end of the array.
|
85
|
+
#
|
86
|
+
# @param name [String] The name of the structure
|
87
|
+
# @param values [::Array] Optional initial values
|
88
|
+
# @return [Y::Array]
|
89
|
+
def get_array(name, values = nil)
|
90
|
+
array = ydoc_get_or_insert_array(name)
|
91
|
+
array.document = self
|
92
|
+
array.concat(values) unless values.nil?
|
93
|
+
array
|
94
|
+
end
|
95
|
+
|
96
|
+
# Gets or creates a new map by name
|
97
|
+
#
|
98
|
+
# If the optional input hash is present, fills the map up with key-value
|
99
|
+
# pairs from the provided input hash. If the map already exists and isn't
|
100
|
+
# empty, any existing keys are overridden and new keys are added.
|
101
|
+
#
|
102
|
+
# @param name [String] The name of the structure
|
103
|
+
# @param input [Hash] Optional initial map key-value pairs
|
104
|
+
# @return [Y::Map]
|
105
|
+
def get_map(name, input = nil)
|
106
|
+
map = ydoc_get_or_insert_map(name)
|
107
|
+
map.document = self
|
108
|
+
input&.each { |key, value| map[key] = value }
|
109
|
+
map
|
110
|
+
end
|
111
|
+
|
112
|
+
# Gets or creates a new text by name
|
113
|
+
#
|
114
|
+
# If the optional input string is provided, fills a new text with the string
|
115
|
+
# at creation time. If the text isn't new and not empty, appends the input
|
116
|
+
# to the end of the text.
|
117
|
+
#
|
118
|
+
# @param name [String] The name of the structure
|
119
|
+
# @param input [String] Optional initial text value
|
120
|
+
# @return [Y::Text]
|
121
|
+
def get_text(name, input = nil)
|
122
|
+
text = ydoc_get_or_insert_text(name)
|
123
|
+
text.document = self
|
124
|
+
text << input unless input.nil?
|
125
|
+
text
|
126
|
+
end
|
127
|
+
|
128
|
+
# Gets or creates a new XMLElement by name
|
129
|
+
#
|
130
|
+
# @param name [String] The name of the structure
|
131
|
+
# @return [Y::XMLElement]
|
132
|
+
def get_xml_element(name)
|
133
|
+
xml_element = ydoc_get_or_insert_xml_element(name)
|
134
|
+
xml_element.document = self
|
135
|
+
xml_element
|
136
|
+
end
|
137
|
+
|
138
|
+
# Gets or creates a new XMLFragment by name
|
139
|
+
#
|
140
|
+
# @param name [String] The name of the fragment
|
141
|
+
# @return [Y::XMLFragment]
|
142
|
+
def get_xml_fragment(name)
|
143
|
+
xml_fragment = ydoc_get_or_insert_xml_fragment(name)
|
144
|
+
xml_fragment.document = self
|
145
|
+
xml_fragment
|
146
|
+
end
|
147
|
+
|
148
|
+
# Gets or creates a new XMLText by name
|
149
|
+
#
|
150
|
+
# @param name [String] The name of the structure
|
151
|
+
# @param input [String] Optional initial text value
|
152
|
+
# @return [Y::XMLText]
|
153
|
+
def get_xml_text(name, input = nil)
|
154
|
+
xml_text = ydoc_get_or_insert_xml_text(name)
|
155
|
+
xml_text.document = self
|
156
|
+
xml_text << input unless input.nil?
|
157
|
+
xml_text
|
158
|
+
end
|
159
|
+
|
160
|
+
# Creates a state vector of this document. This can be used to compare the
|
161
|
+
# state of two documents with each other and to later on sync them.
|
162
|
+
#
|
163
|
+
# @return [::Array<Integer>] Binary encoded state vector
|
164
|
+
def state
|
165
|
+
current_transaction(&:state)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Creates a v2 state vector of this document. This can be used to compare
|
169
|
+
# the state of two documents with each other and to later on sync them.
|
170
|
+
#
|
171
|
+
# @return [::Array<Integer>] Binary encoded state vector
|
172
|
+
def state_v2
|
173
|
+
current_transaction(&:state_v2)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Synchronizes this document with the diff from another document
|
177
|
+
#
|
178
|
+
# @param diff [::Array<Integer>] Binary encoded update
|
179
|
+
# @return [void]
|
180
|
+
def sync(diff)
|
181
|
+
current_transaction { |tx| tx.apply(diff) }
|
182
|
+
end
|
183
|
+
|
184
|
+
# Synchronizes this document with the v2 diff from another document
|
185
|
+
#
|
186
|
+
# @param diff [::Array<Integer>] Binary encoded update
|
187
|
+
# @return [void]
|
188
|
+
def sync_v2(diff)
|
189
|
+
current_transaction { |tx| tx.apply_v2(diff) }
|
190
|
+
end
|
191
|
+
|
192
|
+
# Restores a specific document from an update that contains full state
|
193
|
+
#
|
194
|
+
# This is doing the same as {#sync}, but it exists to be explicit about
|
195
|
+
# the intent. This is the companion to {#full_diff}.
|
196
|
+
#
|
197
|
+
# @param full_diff [::Array<Integer>] Binary encoded update
|
198
|
+
# @return [void]
|
199
|
+
def restore(full_diff)
|
200
|
+
current_transaction { |tx| tx.apply(full_diff) }
|
201
|
+
end
|
202
|
+
|
203
|
+
# Creates a new transaction
|
204
|
+
def transact
|
205
|
+
# 1. release potentially existing transaction
|
206
|
+
if @current_transaction
|
207
|
+
@current_transaction.free
|
208
|
+
@current_transaction = nil
|
209
|
+
end
|
210
|
+
|
211
|
+
# 2. store new transaction in instance variable
|
212
|
+
@current_transaction = ydoc_transact
|
213
|
+
@current_transaction.document = self
|
214
|
+
|
215
|
+
# 3. call block with reference to current_transaction
|
216
|
+
yield @current_transaction
|
217
|
+
ensure
|
218
|
+
@current_transaction&.free
|
219
|
+
@current_transaction = nil
|
220
|
+
end
|
221
|
+
|
222
|
+
# @!visibility private
|
223
|
+
def current_transaction(&block)
|
224
|
+
raise "provide a block" unless block
|
225
|
+
|
226
|
+
# 1. instance variable is set, just use it
|
227
|
+
return yield @current_transaction if @current_transaction
|
228
|
+
|
229
|
+
# 2. forward block to transact
|
230
|
+
transact(&block) unless @current_transaction
|
231
|
+
end
|
232
|
+
|
233
|
+
# @!method ydoc_encode_diff_v1(tx, state_vector)
|
234
|
+
# Encodes the diff of current document state vs provided state
|
235
|
+
#
|
236
|
+
# @example Create transaction on doc
|
237
|
+
# doc = Y::Doc.new
|
238
|
+
# tx = doc.ydoc_encode_diff_v1(other_state)
|
239
|
+
#
|
240
|
+
# @return [Array<Integer>] Binary encoded update
|
241
|
+
# @!visibility private
|
242
|
+
|
243
|
+
# @!method ydoc_encode_diff_v2(tx, state_vector)
|
244
|
+
# Encodes the diff of current document state vs provided state in the v2
|
245
|
+
# format
|
246
|
+
#
|
247
|
+
# @example Create transaction on doc
|
248
|
+
# doc = Y::Doc.new
|
249
|
+
# tx = doc.ydoc_encode_diff_v2(other_state)
|
250
|
+
#
|
251
|
+
# @return [Array<Integer>] Binary encoded update
|
252
|
+
# @!visibility private
|
253
|
+
|
254
|
+
# @!method ydoc_transact
|
255
|
+
# Creates a new transaction for the document
|
256
|
+
#
|
257
|
+
# @example Create transaction on doc
|
258
|
+
# doc = Y::Doc.new
|
259
|
+
# tx = doc.ydoc_transact
|
260
|
+
#
|
261
|
+
# @return [Y::Transaction] The transaction object
|
262
|
+
# @!visibility private
|
263
|
+
|
264
|
+
# @!method ydoc_get_or_insert_array(name)
|
265
|
+
# Creates a new array for the document
|
266
|
+
#
|
267
|
+
# @param [String] name
|
268
|
+
# @return [Y::Array]
|
269
|
+
# @!visibility private
|
270
|
+
|
271
|
+
# @!method ydoc_get_or_insert_map(name)
|
272
|
+
# Creates a new map for the document
|
273
|
+
#
|
274
|
+
# @param [String] name
|
275
|
+
# @return [Y::Map]
|
276
|
+
# @!visibility private
|
277
|
+
|
278
|
+
# @!method ydoc_get_or_insert_text(name)
|
279
|
+
# Creates a new text for the document
|
280
|
+
#
|
281
|
+
# @param [String] name
|
282
|
+
# @return [Y::Text]
|
283
|
+
# @!visibility private
|
284
|
+
|
285
|
+
# @!method ydoc_get_or_insert_xml_element(name)
|
286
|
+
# Creates a new XMLText for the document
|
287
|
+
#
|
288
|
+
# @param [String] name
|
289
|
+
# @return [Y::XMLElement]
|
290
|
+
# @!visibility private
|
291
|
+
|
292
|
+
# @!method ydoc_get_or_insert_xml_fragment(name)
|
293
|
+
# Creates a new XMLFragment for the document
|
294
|
+
#
|
295
|
+
# @param [String] name
|
296
|
+
# @return [Y::XMLFragment]
|
297
|
+
# @!visibility private
|
298
|
+
|
299
|
+
# @!method ydoc_get_or_insert_xml_text(name)
|
300
|
+
# Creates a new XMLText for the document
|
301
|
+
#
|
302
|
+
# @param [String] name
|
303
|
+
# @return [Y::XMLText]
|
304
|
+
# @!visibility private
|
305
|
+
|
306
|
+
# @!method ydoc_observe_update(block)
|
307
|
+
# Creates a subscription to observe changes to the document
|
308
|
+
#
|
309
|
+
# @param [Proc] block
|
310
|
+
# @return [Integer]
|
311
|
+
# @!visibility private
|
312
|
+
end
|
313
|
+
end
|