y-rb 0.3.2-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ext/yrb/Cargo.toml +21 -0
- data/ext/yrb/extconf.rb +6 -0
- data/ext/yrb/src/awareness.rs +425 -0
- data/ext/yrb/src/lib.rs +505 -0
- data/ext/yrb/src/utils.rs +34 -0
- data/ext/yrb/src/yany.rs +44 -0
- data/ext/yrb/src/yarray.rs +148 -0
- data/ext/yrb/src/yattrs.rs +48 -0
- data/ext/yrb/src/yawareness.rs +131 -0
- data/ext/yrb/src/ydoc.rs +35 -0
- data/ext/yrb/src/ymap.rs +151 -0
- data/ext/yrb/src/ytext.rs +204 -0
- data/ext/yrb/src/ytransaction.rs +55 -0
- data/ext/yrb/src/yvalue.rs +231 -0
- data/ext/yrb/src/yxml_element.rs +212 -0
- data/ext/yrb/src/yxml_text.rs +136 -0
- data/lib/2.7/yrb.so +0 -0
- data/lib/3.0/yrb.so +0 -0
- data/lib/y/array.rb +354 -0
- data/lib/y/awareness.rb +266 -0
- data/lib/y/doc.rb +220 -0
- data/lib/y/map.rb +202 -0
- data/lib/y/text.rb +372 -0
- data/lib/y/transaction.rb +143 -0
- data/lib/y/version.rb +5 -0
- data/lib/y/xml.rb +870 -0
- data/lib/y-rb.rb +23 -0
- data/lib/y.rb +3 -0
- metadata +136 -0
data/lib/y/awareness.rb
ADDED
@@ -0,0 +1,266 @@
|
|
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
|
+
# }.to_json
|
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
|
+
#
|
35
|
+
class Awareness
|
36
|
+
# Applies an incoming update. This gets the local awareness instance in
|
37
|
+
# sync with changes from another client. i.e., updates the state of another
|
38
|
+
# user in the local awareness instance.
|
39
|
+
#
|
40
|
+
# @example Apply an incoming update
|
41
|
+
# update = [1,227,245,175,195,11,1,65,123, …]
|
42
|
+
#
|
43
|
+
# awareness = Y::Awareness.new
|
44
|
+
# awareness.sync(update)
|
45
|
+
#
|
46
|
+
# @param [Array<Integer>] diff A binary encoded update
|
47
|
+
# @return [void]
|
48
|
+
def sync(diff)
|
49
|
+
yawareness_apply_update(diff)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Clears out a state of a current client, effectively marking it as
|
53
|
+
# disconnected.
|
54
|
+
#
|
55
|
+
# @return [void]
|
56
|
+
def clean_local_state
|
57
|
+
yawareness_clean_local_state
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns a globally unique client ID of an underlying Doc.
|
61
|
+
#
|
62
|
+
# @return [Integer] Returns the client_id of the local user
|
63
|
+
def client_id
|
64
|
+
yawareness_client_id
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns a state map of all of the clients tracked by current Awareness
|
68
|
+
# instance. Those states are identified by their corresponding ClientIDs.
|
69
|
+
# The associated state is represented and replicated to other clients as a
|
70
|
+
# JSON string.
|
71
|
+
#
|
72
|
+
# @example Instantiate awareness instance and encode update for broadcast
|
73
|
+
# local_state = {
|
74
|
+
# editing: { field: "description", pos: 0 },
|
75
|
+
# name: "Hannes Moser"
|
76
|
+
# }.to_json
|
77
|
+
#
|
78
|
+
# awareness = Y::Awareness.new
|
79
|
+
# awareness.local_state = local_state
|
80
|
+
# awareness.clients # {312134501=>"{\"editing\":{\"field\":\"descriptio …
|
81
|
+
#
|
82
|
+
# @return [Hash] All clients and their current state
|
83
|
+
def clients
|
84
|
+
yawareness_clients
|
85
|
+
end
|
86
|
+
|
87
|
+
# Returns a JSON string state representation of a current Awareness
|
88
|
+
# instance.
|
89
|
+
#
|
90
|
+
# @example Create local state and inspect it
|
91
|
+
# local_state = {
|
92
|
+
# editing: { field: "description", pos: 0 },
|
93
|
+
# name: "Hannes Moser"
|
94
|
+
# }.to_json
|
95
|
+
#
|
96
|
+
# awareness = Y::Awareness.new
|
97
|
+
# awareness.local_state = local_state
|
98
|
+
# local_state # "{\"editing\":{\"field\":\"description\",\"pos\":0}, …
|
99
|
+
#
|
100
|
+
# @return [String] The current state of the local client
|
101
|
+
def local_state
|
102
|
+
yawareness_local_state
|
103
|
+
end
|
104
|
+
|
105
|
+
# Sets a current Awareness instance state to a corresponding JSON string.
|
106
|
+
# This state will be replicated to other clients as part of the
|
107
|
+
# AwarenessUpdate.
|
108
|
+
#
|
109
|
+
# @example Set local state
|
110
|
+
# local_state = {
|
111
|
+
# editing: { field: "description", pos: 0 },
|
112
|
+
# name: "Hannes Moser"
|
113
|
+
# }.to_json
|
114
|
+
#
|
115
|
+
# awareness = Y::Awareness.new
|
116
|
+
# awareness.local_state = local_state
|
117
|
+
#
|
118
|
+
# @return [void]
|
119
|
+
def local_state=(json)
|
120
|
+
yawareness_set_local_state(json)
|
121
|
+
end
|
122
|
+
|
123
|
+
# Subscribes to changes
|
124
|
+
#
|
125
|
+
# @return [Integer] The subscription ID
|
126
|
+
def attach(callback, &block)
|
127
|
+
return yawareness_on_update(callback) unless callback.nil?
|
128
|
+
|
129
|
+
yawareness_on_update(block.to_proc) unless block.nil?
|
130
|
+
end
|
131
|
+
|
132
|
+
# Unsubscribe from changes
|
133
|
+
#
|
134
|
+
# @param [Integer] subscription_id
|
135
|
+
# @return [void]
|
136
|
+
def detach(subscription_id)
|
137
|
+
yawareness_remove_on_update(subscription_id)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Clears out a state of a given client, effectively marking it as
|
141
|
+
# disconnected.
|
142
|
+
#
|
143
|
+
# @param [Integer] client_id Clears the state for given client_id
|
144
|
+
# @return [void]
|
145
|
+
def remove_state(client_id)
|
146
|
+
yawareness_remove_state(client_id)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns a serializable update object which is representation of a current
|
150
|
+
# Awareness state.
|
151
|
+
#
|
152
|
+
# @return [::Array<Integer>] Binary encoded update of the local instance
|
153
|
+
def diff
|
154
|
+
yawareness_update
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns a serializable update object which is representation of a current
|
158
|
+
# Awareness state. Unlike Awareness::update, this method variant allows to
|
159
|
+
# prepare update only for a subset of known clients. These clients must all
|
160
|
+
# be known to a current Awareness instance, otherwise a
|
161
|
+
# Error::ClientNotFound error will be returned.
|
162
|
+
#
|
163
|
+
# @param [::Array<Integer>] clients A list of client IDs
|
164
|
+
# @return [String] Binary encoded update including all given client IDs
|
165
|
+
def diff_with_clients(*clients)
|
166
|
+
yawareness_update_with_clients(clients)
|
167
|
+
end
|
168
|
+
|
169
|
+
# rubocop:disable Lint/UselessAccessModifier
|
170
|
+
private
|
171
|
+
|
172
|
+
# @!method yawareness_apply_update(update)
|
173
|
+
# Applies an update
|
174
|
+
#
|
175
|
+
# @param [Y::AwarenessUpdate] A structure that represents an encodable state
|
176
|
+
# of an Awareness struct.
|
177
|
+
|
178
|
+
# @!method yawareness_apply_update(update)
|
179
|
+
# Applies an update
|
180
|
+
#
|
181
|
+
# @param [Y::AwarenessUpdate] A structure that represents an encodable state
|
182
|
+
# of an Awareness struct.
|
183
|
+
|
184
|
+
# @!method yawareness_clean_local_state
|
185
|
+
# Clears out a state of a current client , effectively marking it as
|
186
|
+
# disconnected.
|
187
|
+
|
188
|
+
# @!method yawareness_client_id
|
189
|
+
# Returns a globally unique client ID of an underlying Doc.
|
190
|
+
# @return [Integer] The Client ID
|
191
|
+
|
192
|
+
# @!method yawareness_clients
|
193
|
+
# Returns a state map of all of the clients
|
194
|
+
# tracked by current Awareness instance. Those states are identified by
|
195
|
+
# their corresponding ClientIDs. The associated state is represented and
|
196
|
+
# replicated to other clients as a JSON string.
|
197
|
+
#
|
198
|
+
# @return [Hash<Integer, String>] Map of clients
|
199
|
+
|
200
|
+
# @!method yawareness_local_state
|
201
|
+
#
|
202
|
+
# @return [String|nil] Returns a JSON string state representation of a
|
203
|
+
# current Awareness instance.
|
204
|
+
|
205
|
+
# @!method yawareness_on_update(callback, &block)
|
206
|
+
#
|
207
|
+
# @param [Proc] A callback handler for updates
|
208
|
+
# @return [Integer] The subscription ID
|
209
|
+
|
210
|
+
# @!method yawareness_remove_on_update(subscription_id)
|
211
|
+
#
|
212
|
+
# @param [Integer] subscription_id The subscription id to remove
|
213
|
+
|
214
|
+
# @!method yawareness_remove_state(client_id)
|
215
|
+
# Clears out a state of a given client, effectively marking it as
|
216
|
+
# disconnected.
|
217
|
+
#
|
218
|
+
# @param [Integer] client_id A Client ID
|
219
|
+
# @return [String|nil] Returns a JSON string state representation of a
|
220
|
+
# current Awareness instance.
|
221
|
+
|
222
|
+
# @!method yawareness_set_local_state(state)
|
223
|
+
# Sets a current Awareness instance state to a corresponding JSON string.
|
224
|
+
# This state will be replicated to other clients as part of the
|
225
|
+
# AwarenessUpdate and it will trigger an event to be emitted if current
|
226
|
+
# instance was created using [Awareness::with_observer] method.
|
227
|
+
#
|
228
|
+
# @param [String] Returns a state map of all of the clients tracked by
|
229
|
+
# current Awareness instance. Those states are identified by their
|
230
|
+
# corresponding ClientIDs. The associated state is represented and
|
231
|
+
# replicated to other clients as a JSON string.
|
232
|
+
|
233
|
+
# @!method yawareness_update
|
234
|
+
# Returns a serializable update object which is representation of a
|
235
|
+
# current Awareness state.
|
236
|
+
#
|
237
|
+
# @return [Y::AwarenessUpdate] The update object
|
238
|
+
|
239
|
+
# @!method yawareness_update_with_clients(clients)
|
240
|
+
# Returns a serializable update object which is representation of a
|
241
|
+
# current Awareness state. Unlike [Y::Awareness#update], this method
|
242
|
+
# variant allows to prepare update only for a subset of known clients.
|
243
|
+
# These clients must all be known to a current Awareness instance,
|
244
|
+
# otherwise an error will be returned.
|
245
|
+
#
|
246
|
+
# @param [::Array<Integer>] clients
|
247
|
+
# @return [::Array<Integer>] A serialized (binary encoded) update object
|
248
|
+
|
249
|
+
# rubocop:enable Lint/UselessAccessModifier
|
250
|
+
end
|
251
|
+
|
252
|
+
# rubocop:disable Lint/UselessAccessModifier
|
253
|
+
class AwarenessEvent
|
254
|
+
private
|
255
|
+
|
256
|
+
# @!method added
|
257
|
+
# @return [::Array<Integer>] Added clients
|
258
|
+
|
259
|
+
# @!method updated
|
260
|
+
# @return [::Array<Integer>] Updated clients
|
261
|
+
|
262
|
+
# @!method removed
|
263
|
+
# @return [::Array<Integer>] Removed clients
|
264
|
+
end
|
265
|
+
# rubocop:enable Lint/UselessAccessModifier
|
266
|
+
end
|
data/lib/y/doc.rb
ADDED
@@ -0,0 +1,220 @@
|
|
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
|
+
# Commit current transaction
|
23
|
+
#
|
24
|
+
# This is a convenience method that invokes {Y::Transaction#commit} on the
|
25
|
+
# current transaction used by this document.
|
26
|
+
#
|
27
|
+
# @return [void]
|
28
|
+
def commit
|
29
|
+
current_transaction.commit
|
30
|
+
end
|
31
|
+
|
32
|
+
# The currently active transaction for this document
|
33
|
+
# @return [Y::Transaction]
|
34
|
+
def current_transaction
|
35
|
+
@current_transaction ||= begin
|
36
|
+
transaction = ydoc_transact
|
37
|
+
transaction.document = self
|
38
|
+
transaction
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Create a diff between this document and another document. The diff is
|
43
|
+
# created based on a state vector provided by the other document. It only
|
44
|
+
# returns the missing blocks, as binary encoded sequence.
|
45
|
+
#
|
46
|
+
# @param [::Array<Int>] state The state to create the diff against
|
47
|
+
# @return [::Array<Int>] Binary encoded diff
|
48
|
+
def diff(state = ZERO_STATE)
|
49
|
+
ydoc_encode_diff_v1(state)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Creates a full diff for the current document. It is similar to {#diff},
|
53
|
+
# but does not take a state. Instead it creates an empty state and passes it
|
54
|
+
# to the encode_diff function.
|
55
|
+
#
|
56
|
+
# @return [::Array<Int>] Binary encoded diff
|
57
|
+
def full_diff
|
58
|
+
empty_state = Y::Doc.new.state
|
59
|
+
ydoc_encode_diff_v1(empty_state)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Gets or creates a new array by name
|
63
|
+
#
|
64
|
+
# If the optional values array is present, fills the array up with elements
|
65
|
+
# from the provided array. If the array already exists and isn't
|
66
|
+
# empty, elements are pushed to the end of the array.
|
67
|
+
#
|
68
|
+
# @param [String] name The name of the structure
|
69
|
+
# @param [::Array] values Optional initial values
|
70
|
+
# @return [Y::Array]
|
71
|
+
def get_array(name, values = nil)
|
72
|
+
array = current_transaction.get_array(name)
|
73
|
+
array.document = self
|
74
|
+
array.concat(values) unless values.nil?
|
75
|
+
array
|
76
|
+
end
|
77
|
+
|
78
|
+
# Gets or creates a new map by name
|
79
|
+
#
|
80
|
+
# If the optional input hash is present, fills the map up with key-value
|
81
|
+
# pairs from the provided input hash. If the map already exists and isn't
|
82
|
+
# empty, any existing keys are overridden and new keys are added.
|
83
|
+
#
|
84
|
+
# @param [String] name The name of the structure
|
85
|
+
# @param [Hash] input Optional initial map key-value pairs
|
86
|
+
# @return [Y::Map]
|
87
|
+
def get_map(name, input = nil)
|
88
|
+
map = current_transaction.get_map(name)
|
89
|
+
map.document = self
|
90
|
+
input&.each { |key, value| map[key] = value }
|
91
|
+
map
|
92
|
+
end
|
93
|
+
|
94
|
+
# Gets or creates a new text by name
|
95
|
+
#
|
96
|
+
# If the optional input string is provided, fills a new text with the string
|
97
|
+
# at creation time. If the text isn't new and not empty, appends the input
|
98
|
+
# to the end of the text.
|
99
|
+
#
|
100
|
+
# @param [String] name The name of the structure
|
101
|
+
# @param [String] input Optional initial text value
|
102
|
+
# @return [Y::Text]
|
103
|
+
def get_text(name, input = nil)
|
104
|
+
text = current_transaction.get_text(name)
|
105
|
+
text.document = self
|
106
|
+
text << input unless input.nil?
|
107
|
+
text
|
108
|
+
end
|
109
|
+
|
110
|
+
# Gets or creates a new XMLElement by name
|
111
|
+
#
|
112
|
+
# @param [String] name The name of the structure
|
113
|
+
# @return [Y::XMLElement]
|
114
|
+
def get_xml_element(name)
|
115
|
+
xml_element = current_transaction.get_xml_element(name)
|
116
|
+
xml_element&.document = self
|
117
|
+
xml_element
|
118
|
+
end
|
119
|
+
|
120
|
+
# Gets or creates a new XMLText by name
|
121
|
+
#
|
122
|
+
# @param [String] name The name of the structure
|
123
|
+
# @param [String] input Optional initial text value
|
124
|
+
# @return [Y::XMLText]
|
125
|
+
def get_xml_text(name, input = nil)
|
126
|
+
xml_text = current_transaction.get_xml_text(name)
|
127
|
+
xml_text.document = self
|
128
|
+
xml_text << input unless input.nil?
|
129
|
+
xml_text
|
130
|
+
end
|
131
|
+
|
132
|
+
# Creates a state vector of this document. This can be used to compare the
|
133
|
+
# state of two documents with each other and to later on sync them.
|
134
|
+
#
|
135
|
+
# @return [::Array<Int>] Binary encoded state vector
|
136
|
+
def state
|
137
|
+
current_transaction.state
|
138
|
+
end
|
139
|
+
|
140
|
+
# Synchronizes this document with the diff from another document
|
141
|
+
#
|
142
|
+
# @param [::Array<Int>] diff Binary encoded update
|
143
|
+
# @return [void]
|
144
|
+
def sync(diff)
|
145
|
+
current_transaction.apply(diff)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Restores a specific document from an update that contains full state
|
149
|
+
#
|
150
|
+
# This is doing the same as {#sync}, but it exists to be explicit about
|
151
|
+
# the intent. This is the companion to {#full_diff}.
|
152
|
+
#
|
153
|
+
# @param [::Array<Int>] full_diff Binary encoded update
|
154
|
+
# @return [void]
|
155
|
+
def restore(full_diff)
|
156
|
+
current_transaction.apply(full_diff)
|
157
|
+
end
|
158
|
+
|
159
|
+
# rubocop:disable Metrics/MethodLength
|
160
|
+
|
161
|
+
# Creates a new transaction and provides it to the given block
|
162
|
+
#
|
163
|
+
# @example Insert into text
|
164
|
+
# doc = Y::Doc.new
|
165
|
+
# text = doc.get_text("my text")
|
166
|
+
#
|
167
|
+
# doc.transact do
|
168
|
+
# text << "Hello, World!"
|
169
|
+
# end
|
170
|
+
#
|
171
|
+
# @yield [transaction]
|
172
|
+
# @yieldparam [Y::Transaction] transaction
|
173
|
+
# @yieldreturn [void]
|
174
|
+
# @return [Y::Transaction]
|
175
|
+
def transact
|
176
|
+
current_transaction.commit
|
177
|
+
|
178
|
+
if block_given?
|
179
|
+
# create new transaction just for the lifetime of this block
|
180
|
+
tmp_transaction = ydoc_transact
|
181
|
+
tmp_transaction.document = self
|
182
|
+
|
183
|
+
# override transaction for the lifetime of the block
|
184
|
+
@current_transaction = tmp_transaction
|
185
|
+
|
186
|
+
yield tmp_transaction
|
187
|
+
|
188
|
+
tmp_transaction.commit
|
189
|
+
end
|
190
|
+
|
191
|
+
# create new transaction
|
192
|
+
@current_transaction = ydoc_transact
|
193
|
+
@current_transaction.document = self
|
194
|
+
|
195
|
+
current_transaction
|
196
|
+
end
|
197
|
+
|
198
|
+
# rubocop:enable Metrics/MethodLength
|
199
|
+
|
200
|
+
# @!method ydoc_encode_diff_v1
|
201
|
+
# Encodes the diff of current document state vs provided state
|
202
|
+
#
|
203
|
+
# @example Create transaction on doc
|
204
|
+
# doc = Y::Doc.new
|
205
|
+
# tx = doc.ydoc_encode_diff_v1(other_state)
|
206
|
+
#
|
207
|
+
# @return [Array<Integer>] Binary encoded update
|
208
|
+
# @!visibility private
|
209
|
+
|
210
|
+
# @!method ydoc_transact
|
211
|
+
# Creates a new transaction for the document
|
212
|
+
#
|
213
|
+
# @example Create transaction on doc
|
214
|
+
# doc = Y::Doc.new
|
215
|
+
# tx = doc.ydoc_transact
|
216
|
+
#
|
217
|
+
# @return [Y::Transaction] The transaction object
|
218
|
+
# @!visibility private
|
219
|
+
end
|
220
|
+
end
|
data/lib/y/map.rb
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module Y
|
6
|
+
# A map can be used to store and retrieve key-value pairs.
|
7
|
+
#
|
8
|
+
# The map is the replicated counterpart to a Hash. It supports a subset
|
9
|
+
# of the Hash operations, like adding, getting and deleting values by key.
|
10
|
+
#
|
11
|
+
# Someone should not instantiate a map directly, but use {Y::Doc#get_map}
|
12
|
+
# instead.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# doc = Y::Doc.new
|
16
|
+
# map = doc.get_map("my map")
|
17
|
+
#
|
18
|
+
# map[:hello] = "world"
|
19
|
+
# puts map[:hello]
|
20
|
+
class Map
|
21
|
+
include Enumerable
|
22
|
+
|
23
|
+
# @!attribute [r] document
|
24
|
+
#
|
25
|
+
# @return [Y::Doc] The document this map belongs to
|
26
|
+
attr_accessor :document
|
27
|
+
|
28
|
+
# Create a new map instance
|
29
|
+
#
|
30
|
+
# @param [Y::Doc] doc
|
31
|
+
def initialize(doc = nil)
|
32
|
+
@document = doc || Y::Doc.new
|
33
|
+
|
34
|
+
super()
|
35
|
+
end
|
36
|
+
|
37
|
+
# Attach a listener to get notified about any changes to the map
|
38
|
+
#
|
39
|
+
# @param [Proc] callback
|
40
|
+
# @param [Block] block
|
41
|
+
# @return [Integer]
|
42
|
+
def attach(callback, &block)
|
43
|
+
return ymap_observe(callback) unless callback.nil?
|
44
|
+
|
45
|
+
ymap_observe(block.to_proc) unless block.nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
# Removes all map entries
|
49
|
+
#
|
50
|
+
# @return [Self]
|
51
|
+
def clear
|
52
|
+
ymap_clear(transaction)
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# rubocop:disable Layout/LineLength
|
57
|
+
|
58
|
+
# Deletes the entry for the given key and returns its associated value.
|
59
|
+
#
|
60
|
+
# @example Deletes the entry and return associated value
|
61
|
+
#
|
62
|
+
# m = doc.get_map("my map")
|
63
|
+
# m[:bar] = 1
|
64
|
+
# m.delete(:bar) # => 1
|
65
|
+
# m # => {}
|
66
|
+
#
|
67
|
+
# @example Unknown key is handled in block
|
68
|
+
#
|
69
|
+
# m = doc.get_map("my map")
|
70
|
+
# m.delete(:nosuch) { |key| "Key #{key} not found" }# => "Key nosuch not found"
|
71
|
+
# m # => {}
|
72
|
+
#
|
73
|
+
# @param [String, Symbol] key
|
74
|
+
# @return [void]
|
75
|
+
def delete(key)
|
76
|
+
value = ymap_remove(transaction, key)
|
77
|
+
if block_given? && key?(key)
|
78
|
+
yield key
|
79
|
+
else
|
80
|
+
value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# rubocop:enable Layout/LineLength
|
85
|
+
|
86
|
+
# Detach listener
|
87
|
+
#
|
88
|
+
# @param [Integer] subscription_id
|
89
|
+
# @return [void]
|
90
|
+
def detach(subscription_id)
|
91
|
+
ymap_unobserve(subscription_id)
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [void]
|
95
|
+
def each(&block)
|
96
|
+
ymap_each(block)
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [true|false]
|
100
|
+
def key?(key)
|
101
|
+
ymap_contains(key)
|
102
|
+
end
|
103
|
+
|
104
|
+
alias has_key? key?
|
105
|
+
|
106
|
+
# @return [Object]
|
107
|
+
def [](key)
|
108
|
+
ymap_get(key)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [void]
|
112
|
+
def []=(key, val)
|
113
|
+
ymap_insert(transaction, key, val)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns size of map
|
117
|
+
#
|
118
|
+
# @return [Integer]
|
119
|
+
def size
|
120
|
+
ymap_size
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns a Hash representation of this map
|
124
|
+
#
|
125
|
+
# @return [Hash]
|
126
|
+
def to_h
|
127
|
+
ymap_to_h
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns a JSON representation of map
|
131
|
+
#
|
132
|
+
# @return [String] JSON string
|
133
|
+
def to_json(*_args)
|
134
|
+
to_h.to_json
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
# @!method ymap_clear()
|
140
|
+
# Removes all key-value pairs from Map
|
141
|
+
|
142
|
+
# @!method ymap_contains(key)
|
143
|
+
# Check if a certain key is in the Map
|
144
|
+
#
|
145
|
+
# @param [String|Symbol] key
|
146
|
+
# @return [Boolean] True, if and only if the key exists
|
147
|
+
|
148
|
+
# @!method ymap_each(proc)
|
149
|
+
# Iterates over all key-value pairs in Map by calling the provided proc
|
150
|
+
# with the key and the value as arguments.
|
151
|
+
#
|
152
|
+
# @param [Proc<String, Any>] proc A proc that is called for every element
|
153
|
+
|
154
|
+
# @!method ymap_get(key)
|
155
|
+
# Returns stored value for key or nil if none is present
|
156
|
+
#
|
157
|
+
# @param [String|Symbol] key
|
158
|
+
# @return [Any|Nil] Value or nil
|
159
|
+
|
160
|
+
# @!method ymap_insert(transaction, key, value)
|
161
|
+
# Insert value for key. In case the key already exists, the previous value
|
162
|
+
# will be overwritten.
|
163
|
+
#
|
164
|
+
# @param [Y::Transaction] transaction
|
165
|
+
# @param [String|Symbol] key
|
166
|
+
# @param [Any] value
|
167
|
+
|
168
|
+
# @!method ymap_observe(callback)
|
169
|
+
#
|
170
|
+
# @param [Proc] callback
|
171
|
+
# @return [Integer]
|
172
|
+
|
173
|
+
# @!method ymap_remove(transaction, key)
|
174
|
+
# Removes key-value pair from Map if key exists.
|
175
|
+
#
|
176
|
+
# @param [Y::Transaction] transaction
|
177
|
+
# @param [String|Symbol] key
|
178
|
+
|
179
|
+
# @!method ymap_size()
|
180
|
+
# Returns number of key-value pairs stored in map
|
181
|
+
#
|
182
|
+
# @return [Integer] Number of key-value pairs
|
183
|
+
|
184
|
+
# @!method ymap_to_h()
|
185
|
+
# Returns a Hash representation of the Map
|
186
|
+
#
|
187
|
+
# @return [Hash] Hash representation of Map
|
188
|
+
|
189
|
+
# @!method ymap_unobserve(subscription_id)
|
190
|
+
#
|
191
|
+
# @param [Integer] subscription_id
|
192
|
+
# @return [void]
|
193
|
+
|
194
|
+
# A reference to the current active transaction of the document this map
|
195
|
+
# belongs to.
|
196
|
+
#
|
197
|
+
# @return [Y::Transaction] A transaction object
|
198
|
+
def transaction
|
199
|
+
document.current_transaction
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|