yerba 0.9.2-aarch64-linux-gnu → 0.10.0-aarch64-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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +34 -17
  3. data/exe/aarch64-linux-gnu/yerba +0 -0
  4. data/ext/yerba/include/yerba.h +56 -34
  5. data/ext/yerba/yerba.c +268 -186
  6. data/lib/yerba/3.2/yerba.so +0 -0
  7. data/lib/yerba/3.3/yerba.so +0 -0
  8. data/lib/yerba/3.4/yerba.so +0 -0
  9. data/lib/yerba/4.0/yerba.so +0 -0
  10. data/lib/yerba/collection.rb +4 -4
  11. data/lib/yerba/document.rb +134 -0
  12. data/lib/yerba/formatting.rb +1 -0
  13. data/lib/yerba/location.rb +8 -1
  14. data/lib/yerba/map.rb +16 -6
  15. data/lib/yerba/node.rb +41 -0
  16. data/lib/yerba/query_result.rb +33 -10
  17. data/lib/yerba/scalar.rb +29 -0
  18. data/lib/yerba/selector.rb +3 -1
  19. data/lib/yerba/sequence.rb +38 -33
  20. data/lib/yerba/version.rb +1 -1
  21. data/rust/Cargo.lock +1 -1
  22. data/rust/Cargo.toml +1 -1
  23. data/rust/src/commands/get.rs +12 -12
  24. data/rust/src/commands/init.rs +8 -8
  25. data/rust/src/commands/insert.rs +4 -18
  26. data/rust/src/commands/location.rs +2 -0
  27. data/rust/src/commands/mod.rs +34 -6
  28. data/rust/src/commands/move_item.rs +1 -1
  29. data/rust/src/commands/move_key.rs +8 -8
  30. data/rust/src/commands/rename.rs +1 -1
  31. data/rust/src/commands/selectors.rs +1 -1
  32. data/rust/src/commands/set.rs +14 -6
  33. data/rust/src/document/condition.rs +25 -25
  34. data/rust/src/document/delete.rs +57 -43
  35. data/rust/src/document/get.rs +91 -82
  36. data/rust/src/document/insert.rs +77 -77
  37. data/rust/src/document/mod.rs +138 -64
  38. data/rust/src/document/nodes.rs +162 -0
  39. data/rust/src/document/schema.rs +8 -8
  40. data/rust/src/document/set.rs +49 -26
  41. data/rust/src/document/sort.rs +54 -54
  42. data/rust/src/document/style.rs +50 -49
  43. data/rust/src/document/unique.rs +5 -5
  44. data/rust/src/error.rs +8 -4
  45. data/rust/src/ffi.rs +218 -106
  46. data/rust/src/json.rs +62 -2
  47. data/rust/src/lib.rs +2 -1
  48. data/rust/src/main.rs +2 -1
  49. data/rust/src/selector.rs +48 -7
  50. data/rust/src/syntax.rs +449 -56
  51. data/rust/src/validation.rs +5 -3
  52. data/rust/src/yerbafile.rs +124 -76
  53. metadata +3 -2
data/rust/src/json.rs CHANGED
@@ -1,5 +1,63 @@
1
1
  use crate::selector::{Selector, SelectorSegment};
2
2
 
3
+ /// Serializes `value` as JSON, writing non-finite floats as `NaN`, `Infinity` and `-Infinity`
4
+ /// (which Ruby's `JSON.parse` reads with `allow_nan: true`) instead of dropping them to `null`.
5
+ pub fn yaml_to_json_string_allowing_nan(value: &yaml_serde::Value) -> String {
6
+ let mut output = String::new();
7
+ write_json_allowing_nan(value, &mut output);
8
+ output
9
+ }
10
+
11
+ fn write_json_allowing_nan(value: &yaml_serde::Value, output: &mut String) {
12
+ match value {
13
+ yaml_serde::Value::Number(number) if number.is_nan() => output.push_str("NaN"),
14
+ yaml_serde::Value::Number(number) if number.is_infinite() => output.push_str(if number.as_f64().is_some_and(f64::is_sign_negative) {
15
+ "-Infinity"
16
+ } else {
17
+ "Infinity"
18
+ }),
19
+
20
+ yaml_serde::Value::Sequence(sequence) => {
21
+ output.push('[');
22
+
23
+ for (index, item) in sequence.iter().enumerate() {
24
+ if index > 0 {
25
+ output.push(',');
26
+ }
27
+
28
+ write_json_allowing_nan(item, output);
29
+ }
30
+
31
+ output.push(']');
32
+ }
33
+
34
+ yaml_serde::Value::Mapping(mapping) => {
35
+ output.push('{');
36
+
37
+ for (index, (key, item)) in mapping.iter().enumerate() {
38
+ if index > 0 {
39
+ output.push(',');
40
+ }
41
+
42
+ let key = match key {
43
+ yaml_serde::Value::String(string) => string.clone(),
44
+ _ => format!("{:?}", key),
45
+ };
46
+
47
+ output.push_str(&serde_json::Value::String(key).to_string());
48
+ output.push(':');
49
+ write_json_allowing_nan(item, output);
50
+ }
51
+
52
+ output.push('}');
53
+ }
54
+
55
+ yaml_serde::Value::Tagged(tagged) => write_json_allowing_nan(&tagged.value, output),
56
+
57
+ _ => output.push_str(&yaml_to_json(value).to_string()),
58
+ }
59
+ }
60
+
3
61
  pub fn yaml_to_json(value: &yaml_serde::Value) -> serde_json::Value {
4
62
  match value {
5
63
  yaml_serde::Value::Null => serde_json::Value::Null,
@@ -8,6 +66,8 @@ pub fn yaml_to_json(value: &yaml_serde::Value) -> serde_json::Value {
8
66
  yaml_serde::Value::Number(number) => {
9
67
  if let Some(integer) = number.as_i64() {
10
68
  serde_json::Value::Number(integer.into())
69
+ } else if let Some(integer) = number.as_u64() {
70
+ serde_json::Value::Number(integer.into())
11
71
  } else if let Some(float) = number.as_f64() {
12
72
  serde_json::json!(float)
13
73
  } else {
@@ -77,9 +137,9 @@ pub fn resolve_select_field(value: &yaml_serde::Value, field: &str) -> serde_jso
77
137
  }
78
138
  }
79
139
 
80
- SelectorSegment::Index(index) => {
140
+ SelectorSegment::Index(_) | SelectorSegment::IndexFromEnd(_) => {
81
141
  if let yaml_serde::Value::Sequence(sequence) = current {
82
- if let Some(item) = sequence.get(*index) {
142
+ if let Some(item) = segment.sequence_index(sequence.len()).and_then(|index| sequence.get(index)) {
83
143
  next_values.push(item.clone());
84
144
  }
85
145
  }
data/rust/src/lib.rs CHANGED
@@ -22,7 +22,8 @@ pub use quote_style::{KeyStyle, QuoteStyle};
22
22
  pub use selector::Selector;
23
23
  pub use syntax::{
24
24
  detect_yaml_type, escape_double_quoted, is_control_character, is_flow_collection, is_inline_scalar_safe, is_plain_safe, is_plain_safe_in_flow,
25
- is_quoted_scalar, is_single_quotable, needs_quoting, needs_quoting_in_flow, quote_scalar, quote_scalar_styled, ScalarValue, YerbaValueType,
25
+ is_quoted_scalar, is_single_quotable, needs_quoting, needs_quoting_in_flow, quote_scalar, quote_scalar_styled, resolve_plain_scalar, PlainScalar,
26
+ ScalarValue, YerbaValueType,
26
27
  };
27
28
  pub use validation::{find_control_characters, ControlCharacter};
28
29
  pub use yaml_writer::json_to_yaml_text;
data/rust/src/main.rs CHANGED
@@ -17,9 +17,10 @@ static HELP: LazyLock<String> = LazyLock::new(|| {
17
17
  commands::colorize_help(indoc! {r#"
18
18
  Selectors:
19
19
  key A single key "database.host"
20
- key.nested Nested key path "database.settings.pool"
20
+ key.nested Nested keys "database.settings.pool"
21
21
  [] All items in array "[].title"
22
22
  [N] Item at index "[0].title"
23
+ [-N] Item from the end "[-1].title"
23
24
  * All values in a map "database.*"
24
25
  [].key[].nested Nested array access "[].speakers[].name"
25
26
 
data/rust/src/selector.rs CHANGED
@@ -23,6 +23,17 @@ pub enum SelectorSegment {
23
23
  AllItems,
24
24
  AllKeys,
25
25
  Index(usize),
26
+ IndexFromEnd(usize),
27
+ }
28
+
29
+ impl SelectorSegment {
30
+ pub(crate) fn sequence_index(&self, length: usize) -> Option<usize> {
31
+ match self {
32
+ SelectorSegment::Index(index) => (*index < length).then_some(*index),
33
+ SelectorSegment::IndexFromEnd(offset) => (*offset <= length).then(|| length - offset),
34
+ _ => None,
35
+ }
36
+ }
26
37
  }
27
38
 
28
39
  impl Selector {
@@ -59,14 +70,17 @@ impl Selector {
59
70
  }
60
71
 
61
72
  pub fn ends_with_bracket(&self) -> bool {
62
- matches!(self.segments().last(), Some(SelectorSegment::AllItems | SelectorSegment::Index(_)))
73
+ matches!(
74
+ self.segments().last(),
75
+ Some(SelectorSegment::AllItems | SelectorSegment::Index(_) | SelectorSegment::IndexFromEnd(_))
76
+ )
63
77
  }
64
78
 
65
79
  pub fn has_brackets(&self) -> bool {
66
80
  self
67
81
  .segments()
68
82
  .iter()
69
- .any(|s| matches!(s, SelectorSegment::AllItems | SelectorSegment::Index(_)))
83
+ .any(|s| matches!(s, SelectorSegment::AllItems | SelectorSegment::Index(_) | SelectorSegment::IndexFromEnd(_)))
70
84
  }
71
85
 
72
86
  pub fn has_wildcard(&self) -> bool {
@@ -88,7 +102,7 @@ impl Selector {
88
102
 
89
103
  let last_bracket = segments
90
104
  .iter()
91
- .rposition(|s| matches!(s, SelectorSegment::AllItems | SelectorSegment::Index(_)));
105
+ .rposition(|s| matches!(s, SelectorSegment::AllItems | SelectorSegment::Index(_) | SelectorSegment::IndexFromEnd(_)));
92
106
 
93
107
  match last_bracket {
94
108
  Some(position) => {
@@ -110,7 +124,9 @@ impl Selector {
110
124
  pub fn split_at_first_bracket(&self) -> (Selector, Selector) {
111
125
  let segments = self.segments();
112
126
 
113
- let first_bracket = segments.iter().position(|s| matches!(s, SelectorSegment::AllItems | SelectorSegment::Index(_)));
127
+ let first_bracket = segments
128
+ .iter()
129
+ .position(|s| matches!(s, SelectorSegment::AllItems | SelectorSegment::Index(_) | SelectorSegment::IndexFromEnd(_)));
114
130
 
115
131
  match first_bracket {
116
132
  Some(position) => {
@@ -178,13 +194,17 @@ impl Selector {
178
194
  SelectorSegment::Index(i) => {
179
195
  result.push_str(&format!("[{}]", i));
180
196
  }
197
+
198
+ SelectorSegment::IndexFromEnd(i) => {
199
+ result.push_str(&format!("[-{}]", i));
200
+ }
181
201
  }
182
202
  }
183
203
 
184
204
  result
185
205
  }
186
206
 
187
- pub fn parent_path(&self) -> String {
207
+ pub fn parent_selector(&self) -> String {
188
208
  let segments = self.segments();
189
209
 
190
210
  if segments.len() <= 1 {
@@ -212,8 +232,10 @@ fn parse_segments(input: &str) -> Vec<SelectorSegment> {
212
232
 
213
233
  if inner.is_empty() {
214
234
  segments.push(SelectorSegment::AllItems);
215
- } else if let Ok(index) = inner.parse::<usize>() {
216
- segments.push(SelectorSegment::Index(index));
235
+ } else if let Some(index) = parse_index(inner) {
236
+ segments.push(index);
237
+ } else {
238
+ segments.push(SelectorSegment::Key(rest[..=close].to_string()));
217
239
  }
218
240
 
219
241
  rest = &rest[close + 1..];
@@ -222,6 +244,8 @@ fn parse_segments(input: &str) -> Vec<SelectorSegment> {
222
244
  rest = &rest[1..];
223
245
  }
224
246
  } else {
247
+ segments.push(SelectorSegment::Key(rest.to_string()));
248
+
225
249
  break;
226
250
  }
227
251
  } else {
@@ -266,3 +290,20 @@ fn parse_segments(input: &str) -> Vec<SelectorSegment> {
266
290
 
267
291
  segments
268
292
  }
293
+
294
+ fn parse_index(input: &str) -> Option<SelectorSegment> {
295
+ if input.bytes().all(|byte| byte.is_ascii_digit()) {
296
+ return Some(SelectorSegment::Index(input.parse::<usize>().unwrap_or(usize::MAX)));
297
+ }
298
+
299
+ let digits = input.strip_prefix('-')?;
300
+
301
+ if digits.is_empty() || !digits.bytes().all(|byte| byte.is_ascii_digit()) {
302
+ return None;
303
+ }
304
+
305
+ match digits.parse::<usize>().unwrap_or(usize::MAX) {
306
+ 0 => Some(SelectorSegment::Index(0)),
307
+ offset => Some(SelectorSegment::IndexFromEnd(offset)),
308
+ }
309
+ }