y-rb 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 83927c49d6611c422184ea193f7957120cc1640b05d95c7adfdb5bd0a067b0c6
4
- data.tar.gz: 4247cf14a459e9111864f8bb15dc0d59c431d7936da89c6e57f50cc3b6ebe204
3
+ metadata.gz: 628f5eba6c401bed73e8e1ebde0d487b135535e60d659421bbea9b0474ca022e
4
+ data.tar.gz: 212aa302985cce60669f2f7f517900bc91a99739180a97ac13a502ae38aec0a1
5
5
  SHA512:
6
- metadata.gz: 26929c25cf3eff821ff685cc30e96979f98cce127b25f3d220465f5d26d90237ce579b13f5ebe949b05ffaac99d8d97026206030c38dfce50cf78363937d5508
7
- data.tar.gz: 4ef9e699bb5433aa12b5732572f75d620ce021ce3ef5ccf891bfc82d6af7f0c05f2bdc4b176c7aaa19e99900e2dd82e7421de9400ccf3ade8a93fb016b97a11b
6
+ metadata.gz: 43772fceb0b399dfa08500dfbe0b7fa0138b122d94b7d5bf9651f5c6a55024ff23bc9b40890619a7a9ef479012dcfbcf733b11d033047c12bddfd382a4ef7aae
7
+ data.tar.gz: d7e6eff2edad549f89b24f55e0427d9f8ad5b5e7512bd81c699b9825def1355c7567c03e5732d35622858f930b545f3a32dbad07a3f121ec9d0d03e3ec2a19df
data/ext/yrb/Cargo.toml CHANGED
@@ -1,19 +1,20 @@
1
1
  [package]
2
2
  name = "yrb"
3
- version = "0.4.5"
3
+ version = "0.5.0"
4
4
  authors = ["Hannes Moser <box@hannesmoser.at>", "Hannes Moser <hmoser@gitlab.com>"]
5
5
  edition = "2021"
6
6
  homepage = "https://github.com/y-crdt/yrb"
7
7
  repository = "https://github.com/y-crdt/yrb"
8
8
 
9
9
  [dependencies]
10
- lib0 = "0.16.1" # must match yrs version
11
- magnus = { git = "https://github.com/matsadler/magnus", rev = "ab982c3643421b38f3293f1fe014aa373abfd6dc" }
10
+ lib0 = "0.16.2" # must match yrs version
11
+ magnus = { git = "https://github.com/matsadler/magnus", rev = "2c2024920a403daadbe23fe63270440dfac86288" }
12
12
  thiserror = "1.0.38"
13
- yrs = "0.16.1"
13
+ yrs = "0.16.2"
14
+ y-sync = "0.2.0"
14
15
 
15
16
  [dev-dependencies]
16
- magnus = { git = "https://github.com/matsadler/magnus", rev = "ab982c3643421b38f3293f1fe014aa373abfd6dc", features = ["embed"] }
17
+ magnus = { git = "https://github.com/matsadler/magnus", rev = "2c2024920a403daadbe23fe63270440dfac86288", features = ["embed"] }
17
18
 
18
19
  [lib]
19
20
  name = "yrb"
data/ext/yrb/src/lib.rs CHANGED
@@ -7,10 +7,10 @@ use crate::ymap::YMap;
7
7
  use crate::ytext::YText;
8
8
  use crate::ytransaction::YTransaction;
9
9
  use crate::yxml_element::YXmlElement;
10
+ use crate::yxml_fragment::YXmlFragment;
10
11
  use crate::yxml_text::YXmlText;
11
12
  use magnus::{define_module, function, method, Error, Module, Object};
12
13
 
13
- mod awareness;
14
14
  mod utils;
15
15
  mod yany;
16
16
  mod yarray;
@@ -296,6 +296,12 @@ fn init() -> Result<(), Error> {
296
296
  method!(YXmlElement::yxml_element_insert_text, 3),
297
297
  )
298
298
  .expect("cannot define private method: yxml_element_insert_text");
299
+ yxml_element
300
+ .define_private_method(
301
+ "yxml_element_len",
302
+ method!(YXmlElement::yxml_element_len, 1),
303
+ )
304
+ .expect("cannot define private method: yxml_element_len");
299
305
  yxml_element
300
306
  .define_private_method(
301
307
  "yxml_element_next_sibling",
@@ -387,6 +393,71 @@ fn init() -> Result<(), Error> {
387
393
  )
388
394
  .expect("cannot define private method: yxml_element_unobserve");
389
395
 
396
+ let yxml_fragment = module
397
+ .define_class("XMLFragment", Default::default())
398
+ .expect("cannot define class: Y::XMLFragment");
399
+
400
+ yxml_fragment
401
+ .define_private_method(
402
+ "yxml_fragment_first_child",
403
+ method!(YXmlFragment::yxml_fragment_first_child, 0),
404
+ )
405
+ .expect("cannot define private method: yxml_fragment_first_child");
406
+ yxml_fragment
407
+ .define_private_method(
408
+ "yxml_fragment_get",
409
+ method!(YXmlFragment::yxml_fragment_get, 2),
410
+ )
411
+ .expect("cannot define private method: yxml_fragment_get");
412
+ yxml_fragment
413
+ .define_private_method(
414
+ "yxml_fragment_insert",
415
+ method!(YXmlFragment::yxml_fragment_insert, 3),
416
+ )
417
+ .expect("cannot define private method: yxml_fragment_insert");
418
+ yxml_fragment
419
+ .define_private_method(
420
+ "yxml_fragment_len",
421
+ method!(YXmlFragment::yxml_fragment_len, 1),
422
+ )
423
+ .expect("cannot define private method: yxml_fragment_len");
424
+ yxml_fragment
425
+ .define_private_method(
426
+ "yxml_fragment_parent",
427
+ method!(YXmlFragment::yxml_fragment_parent, 0),
428
+ )
429
+ .expect("cannot define private method: yxml_fragment_parent");
430
+ yxml_fragment
431
+ .define_private_method(
432
+ "yxml_fragment_push_back",
433
+ method!(YXmlFragment::yxml_fragment_push_back, 2),
434
+ )
435
+ .expect("cannot define private method: yxml_fragment_push_back");
436
+ yxml_fragment
437
+ .define_private_method(
438
+ "yxml_fragment_push_front",
439
+ method!(YXmlFragment::yxml_fragment_push_front, 2),
440
+ )
441
+ .expect("cannot define private method: yxml_fragment_push_front");
442
+ yxml_fragment
443
+ .define_private_method(
444
+ "yxml_fragment_remove_range",
445
+ method!(YXmlFragment::yxml_fragment_remove_range, 3),
446
+ )
447
+ .expect("cannot define private method: yxml_fragment_remove_range");
448
+ yxml_fragment
449
+ .define_private_method(
450
+ "yxml_fragment_successors",
451
+ method!(YXmlFragment::yxml_fragment_successors, 1),
452
+ )
453
+ .expect("cannot define private method: yxml_fragment_successors");
454
+ yxml_fragment
455
+ .define_private_method(
456
+ "yxml_fragment_to_s",
457
+ method!(YXmlFragment::yxml_fragment_to_s, 1),
458
+ )
459
+ .expect("cannot define private method: yxml_fragment_to_s");
460
+
390
461
  let yxml_text = module
391
462
  .define_class("XMLText", Default::default())
392
463
  .expect("cannot define class Y::XMLText");
@@ -506,12 +577,6 @@ fn init() -> Result<(), Error> {
506
577
  method!(YAwareness::yawareness_on_update, 1),
507
578
  )
508
579
  .expect("cannot define private method: yawareness_on_update");
509
- yawareness
510
- .define_private_method(
511
- "yawareness_remove_on_update",
512
- method!(YAwareness::yawareness_remove_on_update, 1),
513
- )
514
- .expect("cannot define private method: yawareness_remove_on_update");
515
580
  yawareness
516
581
  .define_private_method(
517
582
  "yawareness_remove_state",
@@ -1,12 +1,12 @@
1
- use crate::awareness::{Awareness, AwarenessUpdate, Event};
2
1
  use magnus::{block::Proc, exception, Error, Value};
3
2
  use std::borrow::Borrow;
4
3
  use std::cell::RefCell;
5
4
  use std::collections::HashMap;
5
+ use y_sync::awareness::{Awareness, AwarenessUpdate, Event, Subscription};
6
6
  use yrs::block::ClientID;
7
7
  use yrs::updates::decoder::Decode;
8
8
  use yrs::updates::encoder::Encode;
9
- use yrs::Doc;
9
+ use yrs::{Doc, OffsetKind, Options};
10
10
 
11
11
  #[magnus::wrap(class = "Y::Awareness")]
12
12
  pub(crate) struct YAwareness(pub(crate) RefCell<Awareness>);
@@ -16,7 +16,14 @@ unsafe impl Send for YAwareness {}
16
16
 
17
17
  impl YAwareness {
18
18
  pub(crate) fn yawareness_new() -> Self {
19
- let doc = Doc::new();
19
+ let mut options = Options {
20
+ offset_kind: OffsetKind::Utf32,
21
+ ..Default::default()
22
+ };
23
+ options.offset_kind = OffsetKind::Utf32;
24
+
25
+ let doc = Doc::with_options(options);
26
+
20
27
  let awareness = Awareness::new(doc);
21
28
 
22
29
  Self(RefCell::new(awareness))
@@ -48,24 +55,18 @@ impl YAwareness {
48
55
  self.0.borrow().local_state().map(|value| value.to_string())
49
56
  }
50
57
 
51
- pub(crate) fn yawareness_on_update(&self, block: Proc) -> Result<u32, Error> {
52
- let subscription_id = self
53
- .0
54
- .borrow_mut()
55
- .on_update(move |_awareness, event| {
56
- let awareness_event = YAwarenessEvent::from(event);
57
- let args = (awareness_event,);
58
- block
59
- .call::<(YAwarenessEvent,), Value>(args)
60
- .expect("cannot call block: on_update");
61
- })
62
- .into();
58
+ pub(crate) fn yawareness_on_update(&self, block: Proc) -> YAwarenessSubscription {
59
+ let subscription = self.0.borrow_mut().on_update(move |_awareness, event| {
60
+ let awareness_event = YAwarenessEvent::from(event);
61
+ let args = (awareness_event,);
62
+ block
63
+ .call::<(YAwarenessEvent,), Value>(args)
64
+ .expect("cannot call block: on_update");
65
+ });
63
66
 
64
- Ok(subscription_id)
65
- }
66
-
67
- pub(crate) fn yawareness_remove_on_update(&self, subscription_id: u32) {
68
- self.0.borrow_mut().remove_on_update(subscription_id)
67
+ // we need to make sure the event handler "survives" and is not being
68
+ // dropped after leaving this scope, so we pass it back to Ruby.
69
+ YAwarenessSubscription::from(subscription)
69
70
  }
70
71
 
71
72
  pub(crate) fn yawareness_remove_state(&self, client_id: ClientID) {
@@ -135,3 +136,16 @@ impl From<&Event> for YAwarenessEvent {
135
136
  Self(value.clone())
136
137
  }
137
138
  }
139
+
140
+ #[magnus::wrap(class = "Y::AwarenessEvent")]
141
+ pub(crate) struct YAwarenessSubscription(Subscription<Event>);
142
+
143
+ unsafe impl Send for YAwarenessSubscription {}
144
+
145
+ impl YAwarenessSubscription {}
146
+
147
+ impl From<Subscription<Event>> for YAwarenessSubscription {
148
+ fn from(v: Subscription<Event>) -> Self {
149
+ YAwarenessSubscription(v)
150
+ }
151
+ }
data/ext/yrb/src/ydoc.rs CHANGED
@@ -6,8 +6,7 @@ use crate::yxml_fragment::YXmlFragment;
6
6
  use crate::yxml_text::YXmlText;
7
7
  use crate::YTransaction;
8
8
  use magnus::block::Proc;
9
- use magnus::exception::runtime_error;
10
- use magnus::{exception, Error, Integer, RArray, Value};
9
+ use magnus::{exception::runtime_error, Error, Integer, RArray, Value};
11
10
  use std::borrow::Borrow;
12
11
  use std::cell::RefCell;
13
12
  use yrs::updates::decoder::Decode;
@@ -41,19 +40,22 @@ impl YDoc {
41
40
 
42
41
  StateVector::decode_v1(state_vector.borrow())
43
42
  .map(|sv| tx.encode_diff_v1(&sv))
44
- .map_err(|_e| Error::new(exception::runtime_error(), "cannot encode diff"))
43
+ .map_err(|_e| Error::new(runtime_error(), "cannot encode diff"))
45
44
  }
46
45
 
47
46
  pub(crate) fn ydoc_get_or_insert_array(&self, name: String) -> YArray {
48
- self.0.borrow().get_or_insert_array(name.as_str()).into()
47
+ let array_ref = self.0.borrow().get_or_insert_array(name.as_str());
48
+ YArray::from(array_ref)
49
49
  }
50
50
 
51
51
  pub(crate) fn ydoc_get_or_insert_map(&self, name: String) -> YMap {
52
- self.0.borrow().get_or_insert_map(name.as_str()).into()
52
+ let map_ref = self.0.borrow().get_or_insert_map(name.as_str());
53
+ YMap::from(map_ref)
53
54
  }
54
55
 
55
56
  pub(crate) fn ydoc_get_or_insert_text(&self, name: String) -> YText {
56
- self.0.borrow().get_or_insert_text(name.as_str()).into()
57
+ let text_ref = self.0.borrow().get_or_insert_text(name.as_str());
58
+ YText::from(text_ref)
57
59
  }
58
60
 
59
61
  pub(crate) fn ydoc_get_or_insert_xml_element(&self, name: String) -> YXmlElement {
@@ -62,14 +64,13 @@ impl YDoc {
62
64
  }
63
65
 
64
66
  pub(crate) fn ydoc_get_or_insert_xml_fragment(&self, name: String) -> YXmlFragment {
65
- self.0
66
- .borrow()
67
- .get_or_insert_xml_fragment(name.as_str())
68
- .into()
67
+ let xml_fragment_ref = self.0.borrow().get_or_insert_xml_fragment(name.as_str());
68
+ YXmlFragment::from(xml_fragment_ref)
69
69
  }
70
70
 
71
71
  pub(crate) fn ydoc_get_or_insert_xml_text(&self, name: String) -> YXmlText {
72
- self.0.borrow().get_or_insert_xml_text(name.as_str()).into()
72
+ let xml_text_ref = self.0.borrow().get_or_insert_xml_text(name.as_str());
73
+ YXmlText::from(xml_text_ref)
73
74
  }
74
75
 
75
76
  pub(crate) fn ydoc_transact<'doc>(&self) -> YTransaction {
@@ -82,6 +82,12 @@ impl YXmlElement {
82
82
 
83
83
  YXmlText::from(self.0.borrow_mut().insert(tx, index, text))
84
84
  }
85
+ pub(crate) fn yxml_element_len(&self, transaction: &YTransaction) -> u32 {
86
+ let mut tx = transaction.transaction();
87
+ let tx = tx.as_mut().unwrap();
88
+
89
+ self.0.borrow().len(tx)
90
+ }
85
91
  pub(crate) fn yxml_element_next_sibling(&self, transaction: &YTransaction) -> Option<Value> {
86
92
  let tx = transaction.transaction();
87
93
  let tx = tx.as_ref().unwrap();
@@ -1,5 +1,9 @@
1
+ use crate::ytransaction::YTransaction;
2
+ use crate::yxml_element::YXmlElement;
3
+ use crate::yxml_text::YXmlText;
4
+ use magnus::{RArray, Value};
1
5
  use std::cell::RefCell;
2
- use yrs::XmlFragmentRef;
6
+ use yrs::{GetString, XmlElementPrelim, XmlFragment, XmlFragmentRef, XmlNode};
3
7
 
4
8
  #[magnus::wrap(class = "Y::XMLFragment")]
5
9
  pub(crate) struct YXmlFragment(pub(crate) RefCell<XmlFragmentRef>);
@@ -7,7 +11,116 @@ pub(crate) struct YXmlFragment(pub(crate) RefCell<XmlFragmentRef>);
7
11
  /// SAFETY: This is safe because we only access this data when the GVL is held.
8
12
  unsafe impl Send for YXmlFragment {}
9
13
 
10
- impl YXmlFragment {}
14
+ impl YXmlFragment {
15
+ pub(crate) fn yxml_fragment_first_child(&self) -> Option<Value> {
16
+ self.0.borrow().first_child().map(|node| match node {
17
+ XmlNode::Element(element) => Value::from(YXmlElement::from(element)),
18
+ XmlNode::Fragment(fragment) => Value::from(YXmlFragment::from(fragment)),
19
+ XmlNode::Text(text) => Value::from(YXmlText::from(text)),
20
+ })
21
+ }
22
+
23
+ pub(crate) fn yxml_fragment_get(
24
+ &self,
25
+ transaction: &YTransaction,
26
+ index: u32,
27
+ ) -> Option<Value> {
28
+ let tx = transaction.transaction();
29
+ let tx = tx.as_ref().unwrap();
30
+
31
+ self.0.borrow().get(tx, index).map(|node| match node {
32
+ XmlNode::Element(element) => Value::from(YXmlElement::from(element)),
33
+ XmlNode::Fragment(fragment) => Value::from(YXmlFragment::from(fragment)),
34
+ XmlNode::Text(text) => Value::from(YXmlText::from(text)),
35
+ })
36
+ }
37
+
38
+ pub(crate) fn yxml_fragment_insert(
39
+ &self,
40
+ transaction: &YTransaction,
41
+ index: u32,
42
+ tag: String,
43
+ ) -> YXmlElement {
44
+ let mut tx = transaction.transaction();
45
+ let tx = tx.as_mut().unwrap();
46
+
47
+ let node = XmlElementPrelim::empty(tag);
48
+ YXmlElement::from(self.0.borrow_mut().insert(tx, index, node))
49
+ }
50
+
51
+ pub(crate) fn yxml_fragment_len(&self, transaction: &YTransaction) -> u32 {
52
+ let tx = transaction.transaction();
53
+ let tx = tx.as_ref().unwrap();
54
+
55
+ self.0.borrow().len(tx)
56
+ }
57
+
58
+ pub(crate) fn yxml_fragment_parent(&self) -> Option<Value> {
59
+ self.0.borrow().parent().map(|item| match item {
60
+ XmlNode::Element(el) => Value::from(YXmlElement::from(el)),
61
+ XmlNode::Fragment(fragment) => Value::from(YXmlFragment::from(fragment)),
62
+ XmlNode::Text(text) => Value::from(YXmlText::from(text)),
63
+ })
64
+ }
65
+
66
+ pub(crate) fn yxml_fragment_push_back(
67
+ &self,
68
+ transaction: &YTransaction,
69
+ tag: String,
70
+ ) -> YXmlElement {
71
+ let mut tx = transaction.transaction();
72
+ let tx = tx.as_mut().unwrap();
73
+
74
+ let node = XmlElementPrelim::empty(tag);
75
+ YXmlElement::from(self.0.borrow_mut().push_back(tx, node))
76
+ }
77
+
78
+ pub(crate) fn yxml_fragment_push_front(
79
+ &self,
80
+ transaction: &YTransaction,
81
+ tag: String,
82
+ ) -> YXmlElement {
83
+ let mut tx = transaction.transaction();
84
+ let tx = tx.as_mut().unwrap();
85
+
86
+ let node = XmlElementPrelim::empty(tag);
87
+ YXmlElement::from(self.0.borrow_mut().push_front(tx, node))
88
+ }
89
+
90
+ pub(crate) fn yxml_fragment_remove_range(
91
+ &self,
92
+ transaction: &YTransaction,
93
+ index: u32,
94
+ length: u32,
95
+ ) {
96
+ let mut tx = transaction.transaction();
97
+ let tx = tx.as_mut().unwrap();
98
+
99
+ self.0.borrow_mut().remove_range(tx, index, length);
100
+ }
101
+
102
+ pub(crate) fn yxml_fragment_successors(&self, transaction: &YTransaction) -> RArray {
103
+ let tx = transaction.transaction();
104
+ let tx = tx.as_ref().unwrap();
105
+
106
+ let fragment = self.0.borrow();
107
+
108
+ let result = fragment.successors(tx).map(|item| match item {
109
+ XmlNode::Element(el) => Value::from(YXmlElement::from(el)),
110
+ XmlNode::Fragment(fragment) => Value::from(YXmlFragment::from(fragment)),
111
+ XmlNode::Text(text) => Value::from(YXmlText::from(text)),
112
+ });
113
+
114
+ RArray::from_iter(result)
115
+ }
116
+
117
+ pub(crate) fn yxml_fragment_to_s(&self, transaction: &YTransaction) -> String {
118
+ let tx = transaction.transaction();
119
+ let tx = tx.as_ref().unwrap();
120
+
121
+ self.0.borrow().get_string(tx)
122
+ }
123
+ }
11
124
 
12
125
  impl From<XmlFragmentRef> for YXmlFragment {
13
126
  fn from(v: XmlFragmentRef) -> Self {
data/lib/y/array.rb CHANGED
@@ -38,7 +38,7 @@ module Y
38
38
 
39
39
  # Retrieves element at position
40
40
  #
41
- # @return [true|false|Float|Integer|String|Array|Hash]
41
+ # @return [true, false, Float, Integer, String, Array, Hash]
42
42
  def [](index)
43
43
  document.current_transaction { |tx| yarray_get(tx, index) }
44
44
  end
@@ -46,7 +46,7 @@ module Y
46
46
  # Inserts value at position
47
47
  #
48
48
  # @param index [Integer]
49
- # @param value [true|false|Float|Integer|String|Array|Hash]
49
+ # @param value [true, false, Float, Integer, String, Array, Hash]
50
50
  # @return [void]
51
51
  def []=(index, value)
52
52
  document.current_transaction { |tx| yarray_insert(tx, index, value) }
@@ -54,10 +54,13 @@ module Y
54
54
 
55
55
  # Adds an element to the end of the array
56
56
  #
57
- # @param value [true|false|Float|Integer|String|::Array|Hash]
57
+ # @param value [true, false, Float, Integer, String, ::Array, Hash]
58
58
  # @return [void]
59
- def <<(value)
60
- document.current_transaction { |tx| yarray_push_back(tx, value) }
59
+ def <<(value, *values)
60
+ document.current_transaction do |tx|
61
+ yarray_push_back(tx, value)
62
+ values.each { |v| yarray_push_back(tx, v) }
63
+ end
61
64
  end
62
65
 
63
66
  # Attach listener to array changes
@@ -118,21 +121,21 @@ module Y
118
121
 
119
122
  # Check if the array is empty
120
123
  #
121
- # @return [true|false]
124
+ # @return [true, false]
122
125
  def empty?
123
126
  size.zero?
124
127
  end
125
128
 
126
129
  # Returns first element in array if there is at least one
127
130
  #
128
- # @return [true|false|Float|Integer|String|::Array|Hash|nil]
131
+ # @return [true, false, Float, Integer, String, ::Array, Hash, nil]
129
132
  def first
130
133
  document.current_transaction { |tx| yarray_get(tx, 0) }
131
134
  end
132
135
 
133
136
  # Returns last element in array if there is at least one element
134
137
  #
135
- # @return [true|false|Float|Integer|String|::Array|Hash|nil]
138
+ # @return [true, false, Float, Integer, String, ::Array, Hash, nil]
136
139
  def last
137
140
  document.current_transaction do |tx|
138
141
  len = yarray_length(tx)
@@ -146,7 +149,7 @@ module Y
146
149
 
147
150
  # Removes last (n) element(s) from array
148
151
  #
149
- # @param n [Integer|nil] Number of elements to remove
152
+ # @param n [Integer, nil] Number of elements to remove
150
153
  # @return [void]
151
154
  def pop(n = nil)
152
155
  document.current_transaction do |tx|
@@ -164,7 +167,7 @@ module Y
164
167
 
165
168
  # Removes first (n) element(s) from array
166
169
  #
167
- # @param n [Integer|nil] Number of elements to remove
170
+ # @param n [Integer, nil] Number of elements to remove
168
171
  # @return [void]
169
172
  def shift(n = nil)
170
173
  document.current_transaction do |tx|
@@ -218,7 +221,7 @@ module Y
218
221
  # @return [void]
219
222
  def slice!(*args)
220
223
  document.current_transaction do |tx| # rubocop:disable Metrics/BlockLength
221
- if args.size.zero?
224
+ if args.empty?
222
225
  raise ArgumentError,
223
226
  "Provide one of `index`, `range`, `start, length` as arguments"
224
227
  end
@@ -261,7 +264,7 @@ module Y
261
264
 
262
265
  # Convert this array to a Ruby Array
263
266
  #
264
- # @return [Array<true|false|Float|Integer|String|::Array|Hash>]
267
+ # @return [Array<true, false, Float, Integer, String, ::Array, Hash>]
265
268
  def to_a
266
269
  document.current_transaction { |tx| yarray_to_a(tx) }
267
270
  end
@@ -303,7 +306,7 @@ module Y
303
306
  #
304
307
  # @param transaction [Y::Transaction]
305
308
  # @param index [Integer]
306
- # @param arr [Array<Boolean|Float|Integer|Array|Hash|Text>]
309
+ # @param arr [Array<Boolean, Float, Integer, Array, Hash, Text>]
307
310
  # @return [void]
308
311
  # @!visibility private
309
312
 
data/lib/y/awareness.rb CHANGED
@@ -93,25 +93,28 @@ module Y
93
93
  #
94
94
  # @return [Hash] All clients and their current state
95
95
  def clients
96
- yawareness_clients
96
+ transform = yawareness_clients.map do |client_id, state|
97
+ [client_id, JSON.parse!(state)]
98
+ end
99
+ transform.to_h
97
100
  end
98
101
 
99
- # Returns a JSON string state representation of a current Awareness
100
- # instance.
102
+ # Returns the state of the local Awareness instance.
101
103
  #
102
104
  # @example Create local state and inspect it
103
105
  # local_state = {
104
106
  # editing: { field: "description", pos: 0 },
105
107
  # name: "Hannes Moser"
106
- # }.to_json
108
+ # }
107
109
  #
108
110
  # awareness = Y::Awareness.new
109
111
  # awareness.local_state = local_state
110
- # local_state # "{\"editing\":{\"field\":\"description\",\"pos\":0},
112
+ # awareness.local_state # { editing: { field: "description", ...
111
113
  #
112
114
  # @return [String] The current state of the local client
113
115
  def local_state
114
- yawareness_local_state
116
+ json = yawareness_local_state
117
+ JSON.parse!(json) if json
115
118
  end
116
119
 
117
120
  # Sets a current Awareness instance state to a corresponding JSON string.
@@ -127,28 +130,23 @@ module Y
127
130
  # awareness = Y::Awareness.new
128
131
  # awareness.local_state = local_state
129
132
  #
133
+ # @param [#to_json] state
130
134
  # @return [void]
131
- def local_state=(json)
132
- yawareness_set_local_state(json)
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)
133
139
  end
134
140
 
135
141
  # Subscribes to changes
136
142
  #
137
143
  # @return [Integer] The subscription ID
138
- def attach(callback, &block)
144
+ def attach(callback = nil, &block)
139
145
  return yawareness_on_update(callback) unless callback.nil?
140
146
 
141
147
  yawareness_on_update(block.to_proc) unless block.nil?
142
148
  end
143
149
 
144
- # Unsubscribe from changes
145
- #
146
- # @param subscription_id [Integer]
147
- # @return [void]
148
- def detach(subscription_id)
149
- yawareness_remove_on_update(subscription_id)
150
- end
151
-
152
150
  # Clears out a state of a given client, effectively marking it as
153
151
  # disconnected.
154
152
  #
@@ -216,7 +214,7 @@ module Y
216
214
 
217
215
  # @!method yawareness_local_state
218
216
  #
219
- # @return [String|nil] Returns a JSON string state representation of a
217
+ # @return [String, nil] Returns a JSON string state representation of a
220
218
  # current Awareness instance.
221
219
  # @!visibility private
222
220
 
@@ -236,7 +234,7 @@ module Y
236
234
  # disconnected.
237
235
  #
238
236
  # @param client_id [Integer] A Client ID
239
- # @return [String|nil] Returns a JSON string state representation of a
237
+ # @return [String, nil] Returns a JSON string state representation of a
240
238
  # current Awareness instance.
241
239
  # @!visibility private
242
240
 
data/lib/y/doc.rb CHANGED
@@ -221,26 +221,51 @@ module Y
221
221
  # @return [Y::Transaction] The transaction object
222
222
  # @!visibility private
223
223
 
224
+ # @!method ydoc_get_or_insert_array(name)
225
+ # Creates a new array for the document
226
+ #
227
+ # @param [String] name
228
+ # @return [Y::Array]
229
+ # @!visibility private
230
+
231
+ # @!method ydoc_get_or_insert_map(name)
232
+ # Creates a new map for the document
233
+ #
234
+ # @param [String] name
235
+ # @return [Y::Map]
236
+ # @!visibility private
237
+
238
+ # @!method ydoc_get_or_insert_text(name)
239
+ # Creates a new text for the document
240
+ #
241
+ # @param [String] name
242
+ # @return [Y::Text]
243
+ # @!visibility private
244
+
224
245
  # @!method ydoc_get_or_insert_xml_element(name)
225
246
  # Creates a new XMLText for the document
226
247
  #
248
+ # @param [String] name
227
249
  # @return [Y::XMLElement]
228
250
  # @!visibility private
229
251
 
230
252
  # @!method ydoc_get_or_insert_xml_fragment(name)
231
253
  # Creates a new XMLFragment for the document
232
254
  #
255
+ # @param [String] name
233
256
  # @return [Y::XMLFragment]
234
257
  # @!visibility private
235
258
 
236
259
  # @!method ydoc_get_or_insert_xml_text(name)
237
260
  # Creates a new XMLText for the document
238
261
  #
262
+ # @param [String] name
239
263
  # @return [Y::XMLText]
240
264
  # @!visibility private
241
265
 
242
266
  # @!method ydoc_observe_update(block)
243
267
  # Creates a subscription to observe changes to the document
268
+ #
244
269
  # @param [Proc] block
245
270
  # @return [Integer]
246
271
  # @!visibility private