yerba 0.5.1-arm-linux-gnu → 0.6.0-arm-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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04faaf878eec2699c126530d1bcaa9401c7038cc923343756dfc8c82cb823f7c
4
- data.tar.gz: e22a16868decac1b24fddef2417d9a92a088f6a9855cc7b2cfc8d14fdd117557
3
+ metadata.gz: bf42e332c712a66c4303193ff8e39cf91c499707246923168fb103ea46eecf52
4
+ data.tar.gz: c0d76d0345ebbbf8f4f07b2182d83a12a131a2388d8c0c3606a3a6b35d778a27
5
5
  SHA512:
6
- metadata.gz: af87cfab2d89ad25ecb5abc36252eef72a1b1208bf645014f5fcb53b451ff9e37acd916fb137e5236149e1d683f4809aab48440974edcae654a904e845fc74ee
7
- data.tar.gz: ed196893d5326e3b0aa87e1c3070702a568b1869efa4dadc33d518aec73fa42d7122fe46f08f1f9513356a86b8db89b6e21b0a4378d645ddebd3385d7a9b6600
6
+ metadata.gz: c8edf88e0de46be9b4781ec68b4133d0d8c8936f322724694fa8454c7fc3468f1864f2d5928c1bf0a601126b236871602a6780442369e5609cff5871548b8e1b
7
+ data.tar.gz: 215d8c085524e5b868da7849d6df18be9e735cc46753dda3d663849dad763a6272253d2c013cb3e2cd0d2833e0cc3942d26e7e2f03211ba64ae4a010acfe6146
data/README.md CHANGED
@@ -843,31 +843,7 @@ document.to_s
843
843
 
844
844
  ## Development
845
845
 
846
- After checking out the repo, run `bundle install` to install Ruby dependencies, then `bundle exec rake test` to run the test suite.
847
-
848
- ### Building from source
849
-
850
- The Rust core is in the `rust/` directory, with a workspace `Cargo.toml` at the root so all cargo commands work from the project root:
851
-
852
- ```bash
853
- cargo build
854
- cargo test
855
- ```
856
-
857
- The C extension (for the Ruby API) is compiled via `ext/yerba/extconf.rb` which invokes `cargo build` and links against the resulting static library. Running `bundle exec rake compile` will build both the Rust library and the C extension.
858
-
859
- ### Running the CLI locally
860
-
861
- ```bash
862
- cargo run -- get config.yml "database.host"
863
- ```
864
-
865
- Or build a release binary:
866
-
867
- ```bash
868
- cargo build --release
869
- ./target/release/yerba --help
870
- ```
846
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to set up the repo locally, run tests, and contribute.
871
847
 
872
848
  ## License
873
849
 
Binary file
@@ -90,6 +90,18 @@ struct YerbaResult yerba_document_set_quote_style(struct Document *document,
90
90
  const char *path,
91
91
  const char *style);
92
92
 
93
+ char *yerba_document_get_collection_style(const struct Document *document, const char *path);
94
+
95
+ struct YerbaResult yerba_document_set_collection_style(struct Document *document,
96
+ const char *path,
97
+ const char *style);
98
+
99
+ char *yerba_document_get_sequence_indent(const struct Document *document, const char *path);
100
+
101
+ struct YerbaResult yerba_document_set_sequence_indent(struct Document *document,
102
+ const char *path,
103
+ const char *style);
104
+
93
105
  bool yerba_document_evaluate_condition(const struct Document *document,
94
106
  const char *parent_path,
95
107
  const char *condition);
data/ext/yerba/yerba.c CHANGED
@@ -374,6 +374,76 @@ static VALUE document_set_quote_style(VALUE self, VALUE path, VALUE style) {
374
374
  return self;
375
375
  }
376
376
 
377
+ /* document.get_collection_style(path) → :flow, :block, or nil */
378
+ static VALUE document_get_collection_style(VALUE self, VALUE path) {
379
+ struct Document *document = get_document(self);
380
+ char *style = yerba_document_get_collection_style(document, StringValueCStr(path));
381
+
382
+ if (style == NULL) return Qnil;
383
+
384
+ VALUE symbol = ID2SYM(rb_intern(style));
385
+
386
+ yerba_string_free(style);
387
+
388
+ return symbol;
389
+ }
390
+
391
+ /* document.set_collection_style(path, style) */
392
+ static VALUE document_set_collection_style(VALUE self, VALUE path, VALUE style) {
393
+ struct Document *document = get_document(self);
394
+
395
+ const char *style_string;
396
+
397
+ if (RB_TYPE_P(style, T_SYMBOL)) {
398
+ style_string = rb_id2name(SYM2ID(style));
399
+ } else if (RB_TYPE_P(style, T_STRING)) {
400
+ style_string = StringValueCStr(style);
401
+ } else {
402
+ rb_raise(rb_eError, "Invalid collection style (expected Symbol or String)");
403
+ }
404
+
405
+ YerbaResult result = yerba_document_set_collection_style(document, StringValueCStr(path), style_string);
406
+
407
+ check_result(result);
408
+
409
+ return self;
410
+ }
411
+
412
+ /* document.get_sequence_indent(path) → :compact, :indented, or nil */
413
+ static VALUE document_get_sequence_indent(VALUE self, VALUE path) {
414
+ struct Document *document = get_document(self);
415
+ char *style = yerba_document_get_sequence_indent(document, StringValueCStr(path));
416
+
417
+ if (style == NULL) return Qnil;
418
+
419
+ VALUE symbol = ID2SYM(rb_intern(style));
420
+
421
+ yerba_string_free(style);
422
+
423
+ return symbol;
424
+ }
425
+
426
+ /* document.set_sequence_indent(path, style) */
427
+ static VALUE document_set_sequence_indent(VALUE self, VALUE path, VALUE style) {
428
+ struct Document *document = get_document(self);
429
+
430
+ const char *style_string;
431
+
432
+ if (RB_TYPE_P(style, T_SYMBOL)) {
433
+ style_string = rb_id2name(SYM2ID(style));
434
+ } else if (RB_TYPE_P(style, T_STRING)) {
435
+ style_string = StringValueCStr(style);
436
+ } else {
437
+ rb_raise(rb_eError, "Invalid sequence indent style (expected Symbol or String)");
438
+ }
439
+
440
+ YerbaResult result = yerba_document_set_sequence_indent(document, StringValueCStr(path), style_string);
441
+
442
+ check_result(result);
443
+
444
+ return self;
445
+ }
446
+
377
447
  /* document.condition?(condition, path: "") */
378
448
  static VALUE document_condition_p(int argc, VALUE *argv, VALUE self) {
379
449
  VALUE condition, opts;
@@ -965,6 +1035,10 @@ void Init_yerba(void) {
965
1035
  rb_define_method(rb_cDocument, "resolve_selectors", document_resolve_selectors, 1);
966
1036
  rb_define_method(rb_cDocument, "get_quote_style", document_get_quote_style, 1);
967
1037
  rb_define_method(rb_cDocument, "set_quote_style", document_set_quote_style, 2);
1038
+ rb_define_method(rb_cDocument, "get_collection_style", document_get_collection_style, 1);
1039
+ rb_define_method(rb_cDocument, "set_collection_style", document_set_collection_style, 2);
1040
+ rb_define_method(rb_cDocument, "get_sequence_indent", document_get_sequence_indent, 1);
1041
+ rb_define_method(rb_cDocument, "set_sequence_indent", document_set_sequence_indent, 2);
968
1042
  rb_define_method(rb_cDocument, "exists?", document_exists_p, 1);
969
1043
  rb_define_method(rb_cDocument, "valid_selector?", document_valid_selector_p, 1);
970
1044
  rb_define_method(rb_cDocument, "condition?", document_condition_p, -1);
Binary file
Binary file
Binary file
Binary file
@@ -14,5 +14,66 @@ module Yerba
14
14
  value.to_s
15
15
  end
16
16
  end
17
+
18
+ def self.to_yaml_value(value)
19
+ case value
20
+ when Array
21
+ return "[]" if value.empty?
22
+
23
+ items = value.map { |item| to_yaml_value(item) }
24
+
25
+ "[#{items.join(", ")}]"
26
+ when Hash
27
+ return "{}" if value.empty?
28
+
29
+ pairs = value.map { |key, value| "#{key}: #{to_yaml_value(value)}" }
30
+
31
+ "{#{pairs.join(", ")}}"
32
+ when true then "true"
33
+ when false then "false"
34
+ when nil then "null"
35
+ else value.to_s
36
+ end
37
+ end
38
+
39
+ def self.to_block_yaml_value(value, indent = 0)
40
+ prefix = " " * indent
41
+
42
+ case value
43
+ when Array
44
+ return "[]" if value.empty?
45
+
46
+ value.map { |item|
47
+ if item.is_a?(Hash)
48
+ inner = to_block_yaml_value(item, indent + 1)
49
+ "#{prefix}- #{inner.lstrip}"
50
+ else
51
+ "#{prefix}- #{to_scalar_value(item)}"
52
+ end
53
+ }.join("\n")
54
+ when Hash
55
+ return "{}" if value.empty?
56
+
57
+ value.map { |key, value|
58
+ if value.is_a?(Hash) || value.is_a?(Array)
59
+ inner = to_block_yaml_value(value, indent + 1)
60
+ "#{prefix}#{key}:\n#{inner}"
61
+ else
62
+ "#{prefix}#{key}: #{to_scalar_value(value)}"
63
+ end
64
+ }.join("\n")
65
+ else
66
+ to_scalar_value(value)
67
+ end
68
+ end
69
+
70
+ def self.to_scalar_value(value)
71
+ case value
72
+ when true then "true"
73
+ when false then "false"
74
+ when nil then "null"
75
+ else value.to_s
76
+ end
77
+ end
17
78
  end
18
79
  end
data/lib/yerba/map.rb CHANGED
@@ -25,24 +25,44 @@ module Yerba
25
25
  end
26
26
 
27
27
  def []=(key, value)
28
+ set(key, value)
29
+ end
30
+
31
+ def set(key, value, style: nil)
28
32
  if connected?
29
33
  new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
30
-
31
- if document.exists?(new_path)
32
- document.set(new_path, value)
34
+ coerced = coerce_value(value, style: style)
35
+ is_block_value = coerced.is_a?(String) && (coerced.include?("\n") || coerced.start_with?("- "))
36
+
37
+ if document.exists?(new_path) && is_block_value
38
+ # Block-style collections can't replace a scalar via set().
39
+ # Delete the key and re-insert at the same position.
40
+ all_keys = keys
41
+ key_index = all_keys.index(key.to_s)
42
+ after_key = key_index&.positive? ? all_keys[key_index - 1] : nil
43
+
44
+ document.delete(new_path)
45
+
46
+ if after_key
47
+ document.insert(new_path, coerced, after: after_key)
48
+ else
49
+ document.insert(new_path, coerced)
50
+ end
51
+ elsif document.exists?(new_path)
52
+ document.set(new_path, coerced)
33
53
  else
34
- document.insert(new_path, value)
54
+ document.insert(new_path, coerced)
35
55
  end
36
56
  else
37
57
  @data[key] = value
38
58
  end
39
59
  end
40
60
 
41
- def insert(key, value, before: nil, after: nil)
61
+ def insert(key, value, before: nil, after: nil, style: nil)
42
62
  if connected?
43
63
  new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
44
64
 
45
- document.insert(new_path, value, before: before, after: after)
65
+ document.insert(new_path, coerce_value(value, style: style), before: before, after: after)
46
66
  else
47
67
  @data[key] = value
48
68
  end
@@ -165,6 +185,16 @@ module Yerba
165
185
  end
166
186
  end
167
187
 
188
+ def collection_style
189
+ @collection_style || document&.get_collection_style(@selector)
190
+ end
191
+
192
+ def collection_style=(style)
193
+ document&.set_collection_style(@selector, style)
194
+
195
+ @collection_style = style
196
+ end
197
+
168
198
  private
169
199
 
170
200
  def format_value(value)
@@ -174,5 +204,19 @@ module Yerba
174
204
  else value.to_s
175
205
  end
176
206
  end
207
+
208
+ def coerce_value(value, style: nil)
209
+ case value
210
+ when Array, Hash
211
+ resolved_style = style || :block
212
+
213
+ if resolved_style == :flow
214
+ Formatting.to_yaml_value(value)
215
+ else
216
+ Formatting.to_block_yaml_value(value)
217
+ end
218
+ else value
219
+ end
220
+ end
177
221
  end
178
222
  end
@@ -293,6 +293,26 @@ module Yerba
293
293
  end
294
294
  end
295
295
 
296
+ def collection_style
297
+ @collection_style || document&.get_collection_style(@selector)
298
+ end
299
+
300
+ def collection_style=(style)
301
+ document&.set_collection_style(@selector, style)
302
+
303
+ @collection_style = style
304
+ end
305
+
306
+ def sequence_indent
307
+ @sequence_indent || document&.get_sequence_indent(@selector)
308
+ end
309
+
310
+ def sequence_indent=(style)
311
+ document&.set_sequence_indent(@selector, style)
312
+
313
+ @sequence_indent = style
314
+ end
315
+
296
316
  private
297
317
 
298
318
  def dig_into(hash, path)
data/lib/yerba/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Yerba
4
- VERSION = "0.5.1"
4
+ VERSION = "0.6.0"
5
5
  end
data/rust/Cargo.lock CHANGED
@@ -1772,7 +1772,7 @@ dependencies = [
1772
1772
 
1773
1773
  [[package]]
1774
1774
  name = "yerba"
1775
- version = "0.5.1"
1775
+ version = "0.6.0"
1776
1776
  dependencies = [
1777
1777
  "cbindgen",
1778
1778
  "clap",
data/rust/Cargo.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "yerba"
3
- version = "0.5.1"
3
+ version = "0.6.0"
4
4
  edition = "2021"
5
5
  authors = ["Marco Roth <marco.roth@intergga.ch>"]
6
6
  description = "YAML Editing and Refactoring with Better Accuracy"
@@ -43,6 +43,19 @@ impl Document {
43
43
  match last_segment {
44
44
  crate::selector::SelectorSegment::Key(last_key) => {
45
45
  let has_wildcard = selector.has_wildcard() || selector.has_brackets();
46
+
47
+ if parent_path.is_empty() && !has_wildcard {
48
+ let parent_node = self.navigate(&parent_path)?;
49
+ let map = parent_node
50
+ .descendants()
51
+ .find_map(BlockMap::cast)
52
+ .ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
53
+
54
+ let entry = find_entry_by_key(&map, last_key).ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
55
+
56
+ return self.remove_map_entry(&entry);
57
+ }
58
+
46
59
  let parent_nodes = self.navigate_all_compact(&parent_path);
47
60
 
48
61
  if parent_nodes.is_empty() {
@@ -61,7 +74,7 @@ impl Document {
61
74
 
62
75
  let entry = find_entry_by_key(&map, last_key).ok_or_else(|| YerbaError::SelectorNotFound(dot_path.to_string()))?;
63
76
 
64
- return self.remove_node(entry.syntax());
77
+ return self.remove_map_entry(&entry);
65
78
  }
66
79
 
67
80
  let mut ranges: Vec<TextRange> = Vec::new();
@@ -53,10 +53,12 @@ impl Document {
53
53
 
54
54
  let current_node = self.navigate(dot_path).ok()?;
55
55
 
56
- if current_node
57
- .descendants()
58
- .any(|child| child.kind() == SyntaxKind::BLOCK_MAP || child.kind() == SyntaxKind::BLOCK_SEQ)
59
- {
56
+ if current_node.descendants().any(|child| {
57
+ matches!(
58
+ child.kind(),
59
+ SyntaxKind::BLOCK_MAP | SyntaxKind::BLOCK_SEQ | SyntaxKind::FLOW_SEQ | SyntaxKind::FLOW_MAP
60
+ )
61
+ }) {
60
62
  return None;
61
63
  }
62
64
 
@@ -130,24 +132,11 @@ impl Document {
130
132
  }
131
133
 
132
134
  pub fn node_type(&self, dot_path: &str) -> NodeType {
133
- match self.navigate(dot_path) {
134
- Ok(node) => {
135
- if let Some(first_structural) = node
136
- .descendants()
137
- .find(|child| BlockMap::can_cast(child.kind()) || BlockSeq::can_cast(child.kind()))
138
- {
139
- if BlockMap::can_cast(first_structural.kind()) {
140
- NodeType::Map
141
- } else {
142
- NodeType::Sequence
143
- }
144
- } else if extract_scalar(&node).is_some() {
145
- NodeType::Scalar
146
- } else {
147
- NodeType::NotFound
148
- }
149
- }
150
- Err(_) => NodeType::NotFound,
135
+ match self.get_value(dot_path) {
136
+ Some(yaml_serde::Value::Mapping(_)) => NodeType::Map,
137
+ Some(yaml_serde::Value::Sequence(_)) => NodeType::Sequence,
138
+ Some(_) => NodeType::Scalar,
139
+ None => NodeType::NotFound,
151
140
  }
152
141
  }
153
142
 
@@ -397,6 +386,42 @@ impl Document {
397
386
  .collect()
398
387
  }
399
388
 
389
+ pub fn get_collection_style(&self, dot_path: &str) -> Option<&'static str> {
390
+ let current_node = self.navigate(dot_path).ok()?;
391
+
392
+ for descendant in current_node.descendants() {
393
+ match descendant.kind() {
394
+ SyntaxKind::FLOW_SEQ | SyntaxKind::FLOW_MAP => return Some("flow"),
395
+ SyntaxKind::BLOCK_SEQ | SyntaxKind::BLOCK_MAP => return Some("block"),
396
+ _ => {}
397
+ }
398
+ }
399
+
400
+ None
401
+ }
402
+
403
+ pub fn get_sequence_indent(&self, dot_path: &str) -> Option<&'static str> {
404
+ let current_node = self.navigate(dot_path).ok()?;
405
+
406
+ let sequence = current_node.descendants().find_map(BlockSeq::cast)?;
407
+ let first_entry = sequence.entries().next()?;
408
+
409
+ let entry_indent = preceding_whitespace_indent(first_entry.syntax());
410
+
411
+ let entry_node = current_node.ancestors().find(|ancestor| ancestor.kind() == SyntaxKind::BLOCK_MAP_ENTRY)?;
412
+
413
+ let source = self.root.text().to_string();
414
+ let entry_start: usize = entry_node.text_range().start().into();
415
+ let line_start = source[..entry_start].rfind('\n').map(|position| position + 1).unwrap_or(0);
416
+ let key_indent = &source[line_start..entry_start];
417
+
418
+ if entry_indent.len() > key_indent.len() {
419
+ Some("indented")
420
+ } else {
421
+ Some("compact")
422
+ }
423
+ }
424
+
400
425
  pub fn get_quote_style(&self, dot_path: &str) -> Option<&'static str> {
401
426
  let current_node = self.navigate(dot_path).ok()?;
402
427