yerba 0.2.2-aarch64-linux-gnu → 0.4.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 +167 -12
  3. data/exe/aarch64-linux-gnu/yerba +0 -0
  4. data/ext/yerba/extconf.rb +39 -12
  5. data/ext/yerba/include/yerba.h +21 -10
  6. data/ext/yerba/yerba.c +91 -25
  7. data/lib/yerba/3.2/yerba.so +0 -0
  8. data/lib/yerba/3.3/yerba.so +0 -0
  9. data/lib/yerba/3.4/yerba.so +0 -0
  10. data/lib/yerba/4.0/yerba.so +0 -0
  11. data/lib/yerba/collection.rb +35 -0
  12. data/lib/yerba/document.rb +16 -0
  13. data/lib/yerba/sequence.rb +169 -1
  14. data/lib/yerba/version.rb +1 -1
  15. data/lib/yerba.rb +7 -2
  16. data/rust/Cargo.lock +1 -1
  17. data/rust/Cargo.toml +2 -2
  18. data/rust/cbindgen.toml +1 -0
  19. data/rust/rustfmt.toml +1 -1
  20. data/rust/src/commands/blank_lines.rs +1 -4
  21. data/rust/src/commands/delete.rs +9 -4
  22. data/rust/src/commands/directives.rs +61 -0
  23. data/rust/src/commands/get.rs +52 -26
  24. data/rust/src/commands/insert.rs +8 -4
  25. data/rust/src/commands/mod.rs +71 -9
  26. data/rust/src/commands/move_item.rs +2 -1
  27. data/rust/src/commands/move_key.rs +2 -1
  28. data/rust/src/commands/quote_style.rs +12 -6
  29. data/rust/src/commands/remove.rs +8 -4
  30. data/rust/src/commands/rename.rs +8 -4
  31. data/rust/src/commands/selectors.rs +158 -0
  32. data/rust/src/commands/set.rs +33 -16
  33. data/rust/src/commands/sort.rs +342 -10
  34. data/rust/src/didyoumean.rs +53 -0
  35. data/rust/src/document/condition.rs +139 -0
  36. data/rust/src/document/delete.rs +91 -0
  37. data/rust/src/document/get.rs +262 -0
  38. data/rust/src/document/insert.rs +314 -0
  39. data/rust/src/document/mod.rs +784 -0
  40. data/rust/src/document/set.rs +90 -0
  41. data/rust/src/document/sort.rs +607 -0
  42. data/rust/src/document/style.rs +473 -0
  43. data/rust/src/error.rs +35 -7
  44. data/rust/src/ffi.rs +213 -520
  45. data/rust/src/json.rs +1 -7
  46. data/rust/src/lib.rs +89 -2
  47. data/rust/src/main.rs +2 -0
  48. data/rust/src/quote_style.rs +83 -7
  49. data/rust/src/selector.rs +2 -7
  50. data/rust/src/syntax.rs +41 -21
  51. data/rust/src/yerbafile.rs +39 -18
  52. metadata +13 -3
  53. data/rust/src/document.rs +0 -2237
@@ -11,7 +11,7 @@ static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
11
11
  yerba quote-style config.yml --keys plain
12
12
  yerba quote-style config.yml --keys plain --values double
13
13
  yerba quote-style config.yml "[].speakers" --values plain
14
- yerba quote-style "data/**/*.yml" --keys plain --values double
14
+ yerba quote-style "data/**/*.yml" --keys plain --values double
15
15
  "#})
16
16
  });
17
17
 
@@ -25,12 +25,12 @@ pub struct Args {
25
25
  file: String,
26
26
  /// Selector to scope the operation (optional — omit for whole file)
27
27
  selector: Option<String>,
28
- /// Quote style for values (plain, single, double, literal, folded)
28
+ /// Quote style for keys
29
29
  #[arg(long)]
30
- values: Option<yerba::QuoteStyle>,
31
- /// Quote style for keys (plain, single, double)
30
+ keys: Option<yerba::KeyStyle>,
31
+ /// Quote style for values
32
32
  #[arg(long)]
33
- keys: Option<yerba::QuoteStyle>,
33
+ values: Option<yerba::QuoteStyle>,
34
34
  #[arg(long)]
35
35
  dry_run: bool,
36
36
  }
@@ -53,7 +53,13 @@ impl Args {
53
53
  }
54
54
 
55
55
  if let Some(style) = &self.values {
56
- let _ = document.enforce_quotes_at(style, selector);
56
+ if let Ok(warnings) = document.enforce_quotes_at(style, selector) {
57
+ for warning in warnings {
58
+ use super::color::*;
59
+
60
+ eprintln!("{YELLOW}Warning:{RESET} {} — {}", resolved_file, warning);
61
+ }
62
+ }
57
63
  }
58
64
 
59
65
  output(&resolved_file, &document, self.dry_run);
@@ -3,7 +3,7 @@ use std::sync::LazyLock;
3
3
  use indoc::indoc;
4
4
 
5
5
  use super::colorize_examples;
6
- use super::{output, parse_file, run_op};
6
+ use super::{output, parse_file, resolve_files, run_op};
7
7
 
8
8
  static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
9
9
  colorize_examples(indoc! {r#"
@@ -28,8 +28,12 @@ pub struct Args {
28
28
 
29
29
  impl Args {
30
30
  pub fn run(self) {
31
- let mut document = parse_file(&self.file);
32
- run_op(|| document.remove(&self.selector, &self.value));
33
- output(&self.file, &document, self.dry_run);
31
+ for resolved_file in resolve_files(&self.file) {
32
+ let mut document = parse_file(&resolved_file);
33
+ let result = document.remove(&self.selector, &self.value);
34
+
35
+ run_op(&resolved_file, &document, result);
36
+ output(&resolved_file, &document, self.dry_run);
37
+ }
34
38
  }
35
39
  }
@@ -3,7 +3,7 @@ use std::sync::LazyLock;
3
3
  use indoc::indoc;
4
4
 
5
5
  use super::colorize_examples;
6
- use super::{output, parse_file, run_op};
6
+ use super::{output, parse_file, resolve_files, run_op};
7
7
 
8
8
  static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
9
9
  colorize_examples(indoc! {r#"
@@ -30,8 +30,12 @@ pub struct Args {
30
30
 
31
31
  impl Args {
32
32
  pub fn run(self) {
33
- let mut document = parse_file(&self.file);
34
- run_op(|| document.rename(&self.source, &self.destination));
35
- output(&self.file, &document, self.dry_run);
33
+ for resolved_file in resolve_files(&self.file) {
34
+ let mut document = parse_file(&resolved_file);
35
+ let result = document.rename(&self.source, &self.destination);
36
+
37
+ run_op(&resolved_file, &document, result);
38
+ output(&resolved_file, &document, self.dry_run);
39
+ }
36
40
  }
37
41
  }
@@ -0,0 +1,158 @@
1
+ use std::collections::BTreeMap;
2
+ use std::sync::LazyLock;
3
+
4
+ use indoc::indoc;
5
+
6
+ use super::colorize_examples;
7
+ use super::{color, parse_file, resolve_files};
8
+
9
+ static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
10
+ colorize_examples(indoc! {r#"
11
+ yerba selectors config.yml
12
+ yerba selectors config.yml "database"
13
+ yerba selectors videos.yml "[]"
14
+ yerba selectors videos.yml "[].speakers"
15
+ yerba selectors "data/**/videos.yml"
16
+ yerba selectors "data/**/videos.yml" "[].talks"
17
+ "#})
18
+ });
19
+
20
+ #[derive(clap::Args)]
21
+ #[command(
22
+ about = "Show all valid selectors in a YAML file",
23
+ arg_required_else_help = true,
24
+ after_help = EXAMPLES.as_str()
25
+ )]
26
+ pub struct Args {
27
+ file: String,
28
+ /// Show selectors starting from this path
29
+ selector: Option<String>,
30
+ /// Sort selectors alphabetically (default: document order)
31
+ #[arg(long)]
32
+ sorted: bool,
33
+ }
34
+
35
+ #[derive(Debug, Default)]
36
+ struct SelectorInfo {
37
+ min_count: Option<usize>,
38
+ max_count: Option<usize>,
39
+ order: usize,
40
+ }
41
+
42
+ impl SelectorInfo {
43
+ fn record_count(&mut self, count: usize) {
44
+ self.min_count = Some(self.min_count.map_or(count, |min| min.min(count)));
45
+ self.max_count = Some(self.max_count.map_or(count, |max| max.max(count)));
46
+ }
47
+
48
+ fn count_label(&self) -> Option<String> {
49
+ match (self.min_count, self.max_count) {
50
+ (Some(0), Some(0)) => Some("empty".to_string()),
51
+
52
+ (Some(min), Some(max)) if min == max => {
53
+ if max <= 5 {
54
+ let indices: Vec<String> = (0..max).map(|i| format!("[{}]", i)).collect();
55
+
56
+ Some(indices.join(", "))
57
+ } else {
58
+ Some(format!("[0]..[{}]", max - 1))
59
+ }
60
+ }
61
+
62
+ (Some(min), Some(max)) => {
63
+ if max <= 5 {
64
+ let indices: Vec<String> = (0..max).map(|i| format!("[{}]", i)).collect();
65
+
66
+ Some(format!("{} ({}-{} items)", indices.join(", "), min, max))
67
+ } else {
68
+ Some(format!("[0]..[{}] ({}-{} items)", max - 1, min, max))
69
+ }
70
+ }
71
+ _ => None,
72
+ }
73
+ }
74
+ }
75
+
76
+ impl Args {
77
+ pub fn run(self) {
78
+ let mut all_selectors: BTreeMap<String, SelectorInfo> = BTreeMap::new();
79
+ let mut counter: usize = 1;
80
+ let selector = self.selector.as_deref().unwrap_or("");
81
+
82
+ for resolved_file in resolve_files(&self.file) {
83
+ let document = parse_file(&resolved_file);
84
+ let prefix = if selector.is_empty() { String::new() } else { selector.to_string() };
85
+
86
+ let values = if selector.is_empty() {
87
+ document.get_value("").into_iter().collect::<Vec<_>>()
88
+ } else {
89
+ document.get_values(selector)
90
+ };
91
+
92
+ for value in values {
93
+ collect_selectors(&value, &prefix, &mut all_selectors, &mut counter);
94
+ }
95
+ }
96
+
97
+ let mut entries: Vec<(&String, &SelectorInfo)> = all_selectors.iter().collect();
98
+
99
+ if self.sorted {
100
+ entries.sort_by_key(|(name, _)| name.to_string());
101
+ } else {
102
+ entries.sort_by_key(|(_, info)| info.order);
103
+ }
104
+
105
+ let max_selector_len = entries.iter().map(|(selector, _)| selector.len()).max().unwrap_or(0);
106
+
107
+ for (selector, info) in &entries {
108
+ if let Some(label) = info.count_label() {
109
+ let padding = max_selector_len - selector.len() + 2;
110
+
111
+ println!("{}{}{}{}{}", selector, " ".repeat(padding), color::DIM, label, color::RESET);
112
+ } else {
113
+ println!("{}", selector);
114
+ }
115
+ }
116
+ }
117
+ }
118
+
119
+ fn collect_selectors(value: &serde_yaml::Value, prefix: &str, selectors: &mut BTreeMap<String, SelectorInfo>, counter: &mut usize) {
120
+ match value {
121
+ serde_yaml::Value::Mapping(map) => {
122
+ for (key, child) in map {
123
+ if let serde_yaml::Value::String(key_string) = key {
124
+ let selector = if prefix.is_empty() {
125
+ key_string.clone()
126
+ } else {
127
+ format!("{}.{}", prefix, key_string)
128
+ };
129
+
130
+ let entry = selectors.entry(selector.clone()).or_default();
131
+ if entry.order == 0 {
132
+ entry.order = *counter;
133
+ *counter += 1;
134
+ }
135
+
136
+ collect_selectors(child, &selector, selectors, counter);
137
+ }
138
+ }
139
+ }
140
+
141
+ serde_yaml::Value::Sequence(sequence) => {
142
+ let bracket_prefix = format!("{}[]", prefix);
143
+
144
+ let entry = selectors.entry(bracket_prefix.clone()).or_default();
145
+ entry.record_count(sequence.len());
146
+ if entry.order == 0 {
147
+ entry.order = *counter;
148
+ *counter += 1;
149
+ }
150
+
151
+ for item in sequence {
152
+ collect_selectors(item, &bracket_prefix, selectors, counter);
153
+ }
154
+ }
155
+
156
+ _ => {}
157
+ }
158
+ }
@@ -3,7 +3,7 @@ use std::sync::LazyLock;
3
3
  use indoc::indoc;
4
4
 
5
5
  use super::colorize_examples;
6
- use super::{output, parse_file, run_op};
6
+ use super::{output, parse_file, resolve_files, run_op_with_hint};
7
7
 
8
8
  static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
9
9
  colorize_examples(indoc! {r#"
@@ -12,6 +12,7 @@ static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
12
12
  yerba set config.yml "database.host" "0.0.0.0" --condition ".port == 5432"
13
13
  yerba set videos.yml "[0].title" "New Title"
14
14
  yerba set "data/**/event.yml" "website" "" --if-exists
15
+ yerba set videos.yml "[].description" "" --all
15
16
  "#})
16
17
  });
17
18
 
@@ -32,28 +33,44 @@ pub struct Args {
32
33
  #[arg(long)]
33
34
  condition: Option<String>,
34
35
  #[arg(long)]
36
+ all: bool,
37
+ #[arg(long)]
35
38
  dry_run: bool,
36
39
  }
37
40
 
38
41
  impl Args {
39
42
  pub fn run(self) {
40
- let mut document = parse_file(&self.file);
41
43
  let parent_path = self.selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
42
44
 
43
- let should_set = if self.if_exists {
44
- document.exists(&self.selector)
45
- } else if self.if_missing {
46
- !document.exists(&self.selector)
47
- } else if let Some(condition) = &self.condition {
48
- document.evaluate_condition(parent_path, condition)
49
- } else {
50
- true
51
- };
52
-
53
- if should_set {
54
- run_op(|| document.set(&self.selector, &self.value));
55
- }
45
+ for resolved_file in resolve_files(&self.file) {
46
+ let mut document = parse_file(&resolved_file);
47
+
48
+ let should_set = if self.if_exists {
49
+ document.exists(&self.selector)
50
+ } else if self.if_missing {
51
+ !document.exists(&self.selector)
52
+ } else if let Some(condition) = &self.condition {
53
+ document.evaluate_condition(parent_path, condition)
54
+ } else {
55
+ true
56
+ };
56
57
 
57
- output(&self.file, &document, self.dry_run);
58
+ if should_set {
59
+ let result = if self.all {
60
+ document.set_all(&self.selector, &self.value)
61
+ } else {
62
+ document.set(&self.selector, &self.value)
63
+ };
64
+
65
+ run_op_with_hint(
66
+ &resolved_file,
67
+ &document,
68
+ result,
69
+ Some("Use --if-exists to skip files where the selector is missing"),
70
+ );
71
+ }
72
+
73
+ output(&resolved_file, &document, self.dry_run);
74
+ }
58
75
  }
59
76
  }