y-rb 0.3.2-x64-mingw32
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/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
|