yerba 0.8.1-aarch64-linux-gnu → 0.9.1-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.
- checksums.yaml +4 -4
- data/README.md +170 -19
- data/exe/aarch64-linux-gnu/yerba +0 -0
- data/ext/yerba/include/yerba.h +9 -0
- data/ext/yerba/yerba.c +72 -5
- data/lib/yerba/3.2/yerba.so +0 -0
- data/lib/yerba/3.3/yerba.so +0 -0
- data/lib/yerba/3.4/yerba.so +0 -0
- data/lib/yerba/4.0/yerba.so +0 -0
- data/lib/yerba/formatting.rb +9 -13
- data/lib/yerba/map.rb +11 -8
- data/lib/yerba/sequence.rb +2 -7
- data/lib/yerba/version.rb +1 -1
- data/rust/Cargo.lock +1 -1
- data/rust/Cargo.toml +1 -1
- data/rust/src/commands/blank_lines.rs +22 -1
- data/rust/src/commands/init.rs +6 -0
- data/rust/src/commands/insert.rs +12 -6
- data/rust/src/commands/mod.rs +2 -3
- data/rust/src/commands/set.rs +15 -5
- data/rust/src/commands/ui.rs +1 -2
- data/rust/src/commands/version.rs +1 -1
- data/rust/src/document/insert.rs +23 -11
- data/rust/src/document/mod.rs +13 -1
- data/rust/src/document/set.rs +108 -34
- data/rust/src/document/style.rs +131 -11
- data/rust/src/error.rs +24 -0
- data/rust/src/ffi.rs +55 -12
- data/rust/src/lib.rs +5 -3
- data/rust/src/syntax.rs +169 -26
- data/rust/src/validation.rs +30 -0
- data/rust/src/yaml_writer.rs +7 -19
- data/rust/src/yerbafile.rs +76 -4
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 511327aa49d8c9f0e9e2c739a059d5e78dcffd11acc85a1dd2b2962f6d60f4a1
|
|
4
|
+
data.tar.gz: 5717396d5a174922f4ce7ce2050d6bb170ced9ad9b6d22c57a80680160ca9c7a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c7b4afdff3d69e24995407c42e0a7f7c775a9648435abb46bdb2a93f876486890b54fadfca20513fa26f8daf35de3e102c0ec75c2a26a5b711e4c92d08fe5d8f
|
|
7
|
+
data.tar.gz: 98308386a28b1a81680609c9b0f051090bc5f3e9eff94daafa3dad7b64aabdd8c9ebcb1873683a69945262d9d05b657a707ede983887ce4ad41f965bbc36309b
|
data/README.md
CHANGED
|
@@ -47,7 +47,7 @@ Use `yerba` as a library in your Rust project:
|
|
|
47
47
|
|
|
48
48
|
```toml
|
|
49
49
|
[dependencies]
|
|
50
|
-
yerba = "0.
|
|
50
|
+
yerba = "0.9"
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
```rust
|
|
@@ -169,34 +169,62 @@ Use `--condition` to only apply the change when a sibling field matches:
|
|
|
169
169
|
yerba set config.yml "database.host" "0.0.0.0" --condition ".port == 5432"
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
+
Over a wildcard selector the condition picks out *which* items to edit, the same way it filters in
|
|
173
|
+
`get`. Items that do not match are left alone:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
yerba set videos.yml "[].title" "New Title" --condition ".id == talk-1"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
If the condition matches more than one item the command stops rather than guessing, so add `--all`
|
|
180
|
+
when editing several is what you meant:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
yerba set videos.yml "[].published" false --plain --condition ".kind == draft" --all
|
|
184
|
+
```
|
|
185
|
+
|
|
172
186
|
Use `--all` to update all nodes matching a wildcard selector:
|
|
173
187
|
|
|
174
188
|
```bash
|
|
175
189
|
yerba set videos.yml "[].description" "" --all
|
|
176
190
|
```
|
|
177
191
|
|
|
192
|
+
Values are written in the quote style already at the path, which keeps string edits tidy. A value is quoted anyway when writing it plain would not read back as the string you passed, so `yes` becomes `"yes"` and `12345` becomes `"12345"` — whatever the field held before. Use `--plain` to write a YAML literal instead:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
yerba set config.yml "database.replica" null --plain
|
|
196
|
+
yerba set config.yml "database.ssl" true --plain
|
|
197
|
+
```
|
|
198
|
+
|
|
178
199
|
### `insert`
|
|
179
200
|
|
|
180
201
|
Insert a new key into a map or a new item into a sequence. By default, new items are appended at the end.
|
|
181
202
|
|
|
182
203
|
```bash
|
|
183
|
-
yerba insert config.yml "database.ssl" true
|
|
204
|
+
yerba insert config.yml "database.ssl" true --plain
|
|
184
205
|
yerba insert config.yml "tags" "yaml"
|
|
185
206
|
```
|
|
186
207
|
|
|
187
208
|
Control placement with `--before`, `--after`, or `--at`:
|
|
188
209
|
|
|
189
210
|
```bash
|
|
190
|
-
yerba insert config.yml "database.ssl" true --after "host"
|
|
191
|
-
yerba insert config.yml "database.ssl" true --before "port"
|
|
211
|
+
yerba insert config.yml "database.ssl" true --plain --after "host"
|
|
212
|
+
yerba insert config.yml "database.ssl" true --plain --before "port"
|
|
192
213
|
yerba insert config.yml "tags" "yaml" --at 0
|
|
193
214
|
yerba insert config.yml "tags" "yaml" --after "ruby"
|
|
194
215
|
```
|
|
195
216
|
|
|
217
|
+
Values are written as strings, and quoted whenever writing them plain would change what they mean. `"Conf 2018: A Talk"` stays one string instead of becoming a nested map, and `"12345"` stays a string instead of becoming a number. Use `--plain` to write a YAML literal or a map or sequence fragment instead:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
yerba insert config.yml "database.ssl" true --plain
|
|
221
|
+
yerba insert speakers.yml "" "name: Bob" --plain --after ".name == Alice"
|
|
222
|
+
```
|
|
223
|
+
|
|
196
224
|
For sequences of maps, use conditions to position relative to other items:
|
|
197
225
|
|
|
198
226
|
```bash
|
|
199
|
-
yerba insert speakers.yml "" "name: Bob" --after ".name == Alice"
|
|
227
|
+
yerba insert speakers.yml "" "name: Bob" --plain --after ".name == Alice"
|
|
200
228
|
yerba insert videos.yml "[0].speakers" "Diana" --before ".name == Charlie"
|
|
201
229
|
```
|
|
202
230
|
|
|
@@ -324,17 +352,17 @@ yerba quote-style videos.yml "[].description" --values literal
|
|
|
324
352
|
|
|
325
353
|
**Value styles** (`--values`):
|
|
326
354
|
|
|
327
|
-
| Style | Symbol | Example | Behavior |
|
|
328
|
-
|
|
329
|
-
| `plain` | — | `host: localhost` | Unquoted |
|
|
330
|
-
| `single` | `'` | `host: 'localhost'` | Single-quoted |
|
|
331
|
-
| `double` | `"` | `host: "localhost"` | Double-quoted, supports `\n` escapes |
|
|
332
|
-
| `literal` |
|
|
333
|
-
| `literal-clip` |
|
|
334
|
-
| `literal-keep` |
|
|
335
|
-
| `folded` | `>-` | Folds newlines to spaces | Strip trailing newline |
|
|
336
|
-
| `folded-clip` | `>` | Folds newlines to spaces | Keep one trailing newline |
|
|
337
|
-
| `folded-keep` | `>+` | Folds newlines to spaces | Keep all trailing newlines |
|
|
355
|
+
| Style | Symbol | Example | Behavior |
|
|
356
|
+
|----------------|--------|--------------------------|--------------------------------------|
|
|
357
|
+
| `plain` | — | `host: localhost` | Unquoted |
|
|
358
|
+
| `single` | `'` | `host: 'localhost'` | Single-quoted |
|
|
359
|
+
| `double` | `"` | `host: "localhost"` | Double-quoted, supports `\n` escapes |
|
|
360
|
+
| `literal` | `\|-` | Preserves newlines | Strip trailing newline |
|
|
361
|
+
| `literal-clip` | `\|` | Preserves newlines | Keep one trailing newline |
|
|
362
|
+
| `literal-keep` | `\|+` | Preserves newlines | Keep all trailing newlines |
|
|
363
|
+
| `folded` | `>-` | Folds newlines to spaces | Strip trailing newline |
|
|
364
|
+
| `folded-clip` | `>` | Folds newlines to spaces | Keep one trailing newline |
|
|
365
|
+
| `folded-keep` | `>+` | Folds newlines to spaces | Keep all trailing newlines |
|
|
338
366
|
|
|
339
367
|
Block scalars are only converted when scoped to a specific selector. An unscoped `--values double` will not touch existing block scalars.
|
|
340
368
|
|
|
@@ -348,6 +376,52 @@ yerba blank-lines videos.yml "[]" 1
|
|
|
348
376
|
yerba blank-lines config.yml "tags" 0
|
|
349
377
|
```
|
|
350
378
|
|
|
379
|
+
By default every entry after the first is adjusted. Use `--before` to set apart only certain sections of a map and leave their neighbours alone:
|
|
380
|
+
|
|
381
|
+
```bash
|
|
382
|
+
yerba blank-lines event.yml "" 1 --before "schedule,speakers"
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
```yaml
|
|
386
|
+
id: rubyconf-2024
|
|
387
|
+
name: RubyConf 2024
|
|
388
|
+
city: Chicago
|
|
389
|
+
|
|
390
|
+
schedule:
|
|
391
|
+
- day: 1
|
|
392
|
+
|
|
393
|
+
speakers:
|
|
394
|
+
- name: Alice
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
`--after` is the mirror image, separating a key from what follows it. Listing a key in both sets it apart on both sides:
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
yerba blank-lines event.yml "" 1 --before "location" --after "location"
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Keys that are not listed keep whatever spacing they already have, so these flags add separators without reflowing the rest of the document. Sequence entries have no key and are never matched by a filter, which means `--before` and `--after` on a sequence are no-ops.
|
|
404
|
+
|
|
405
|
+
Use `--skip-empty` to leave placeholder entries tucked against their neighbours. An entry counts as empty when its value is `null`, an empty collection, or an empty string:
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
yerba blank-lines event.yml "" 1 --before "location,speakers,sponsors" --after "location" --skip-empty
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
```yaml
|
|
412
|
+
id: rubyconf-2024
|
|
413
|
+
name: RubyConf 2024
|
|
414
|
+
|
|
415
|
+
location:
|
|
416
|
+
city: Chicago
|
|
417
|
+
country: US
|
|
418
|
+
|
|
419
|
+
speakers: []
|
|
420
|
+
sponsors: []
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
The match is ignored when the entry that *triggered* it is empty, not the one on the other side of the gap. That is why `--after "location"` still separates a populated `location:` block from the empty entries below it, while a bare `location: null` would stay packed. Without `--skip-empty`, every listed key gets its blank line whether or not it holds anything.
|
|
424
|
+
|
|
351
425
|
### `directives`
|
|
352
426
|
|
|
353
427
|
Add or remove the document start marker (`---`):
|
|
@@ -535,15 +609,16 @@ Available pipeline steps:
|
|
|
535
609
|
- `sequence_indent` Enforce compact or indented sequence style
|
|
536
610
|
- `sort_keys` Reorder keys to match a predefined list
|
|
537
611
|
- `sort` Sort sequence items by field(s)
|
|
538
|
-
- `blank_lines` Enforce blank lines between sequence entries
|
|
539
|
-
- `set` Set a value (supports conditions)
|
|
540
|
-
- `insert` Insert a new key or sequence item
|
|
612
|
+
- `blank_lines` Enforce blank lines between sequence entries, optionally limited to named map keys with `before` and to non-empty values with `skip_empty`
|
|
613
|
+
- `set` Set a value (supports conditions, and `plain: true` for YAML literals)
|
|
614
|
+
- `insert` Insert a new key or sequence item (`plain: true` for YAML literals and fragments)
|
|
541
615
|
- `delete` Remove a key (supports conditions)
|
|
542
616
|
- `rename` Rename a key
|
|
543
617
|
- `remove` Remove an item from a sequence
|
|
544
618
|
- `directives` Add or remove the document start marker (`---`), with optional `max` validation
|
|
545
619
|
- `unique` Find or remove duplicate items in a sequence
|
|
546
620
|
- `schema` Validate against a JSON schema (with optional `path` for scoping)
|
|
621
|
+
- `escapes` Spell escaped characters literally where the quote style can carry them (with optional `path` for scoping)
|
|
547
622
|
- `final_newline` Enforce exact number of trailing newlines (`count: 1` by default, strips extras)
|
|
548
623
|
|
|
549
624
|
This makes it easy to enforce project-wide YAML conventions in CI:
|
|
@@ -552,6 +627,36 @@ This makes it easy to enforce project-wide YAML conventions in CI:
|
|
|
552
627
|
yerba check
|
|
553
628
|
```
|
|
554
629
|
|
|
630
|
+
The `escapes` step rewrites double-quoted values in the form yerba would write them, so a character the style can carry is spelled out rather than escaped. Text that arrives from an API or a scraper often carries `\U0001F631` where an emoji belongs, or a long value wrapped across two lines. Both read back correctly either way, but neither is pleasant to review in a diff:
|
|
631
|
+
|
|
632
|
+
```yaml
|
|
633
|
+
pipeline:
|
|
634
|
+
- escapes: {}
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
```diff
|
|
638
|
+
- title: "Deploying on a Friday \U0001F631"
|
|
639
|
+
+ title: "Deploying on a Friday 😱"
|
|
640
|
+
|
|
641
|
+
- summary: "Why the deploy went out on a Friday, and
|
|
642
|
+
- what we changed afterwards"
|
|
643
|
+
+ summary: "Why the deploy went out on a Friday, and what we changed afterwards"
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
Escapes that have to stay do: a control character, a quote or a backslash is still written escaped, since the value would not read back the same otherwise. Plain, single-quoted and block scalars are left alone, and a `path` scopes the step to part of the document.
|
|
647
|
+
|
|
648
|
+
Every checked file is also scanned for control characters, whatever the pipeline says. Yerba's parser accepts them but libyaml does not, so without this a file could pass `check` in CI and then fail to load in the application that reads it. Offending characters are reported with their line and column:
|
|
649
|
+
|
|
650
|
+
```console
|
|
651
|
+
$ yerba check
|
|
652
|
+
✗ data/rubyconf-taiwan/videos.yml
|
|
653
|
+
found 2 control characters that YAML parsers reject:
|
|
654
|
+
U+0008 at line 152, column 34
|
|
655
|
+
U+0008 at line 154, column 12
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
Tabs, newlines and carriage returns are fine, and so are characters written escaped as `\xNN` inside a double-quoted value — only literal ones are reported.
|
|
659
|
+
|
|
555
660
|
## Ruby API
|
|
556
661
|
|
|
557
662
|
Yerba includes a native C extension (backed by the same Rust core) that provides a full Ruby API for YAML editing.
|
|
@@ -718,6 +823,42 @@ Insert new keys with positional control:
|
|
|
718
823
|
document["database"].insert("ssl", true, after: "host")
|
|
719
824
|
```
|
|
720
825
|
|
|
826
|
+
A `String` is written as a value, not as YAML text, and quoted whenever writing it plain would change what it means. This is the same rule the CLI's `insert` and `set` follow, so `"key: value"` stays one string instead of becoming a nested map:
|
|
827
|
+
|
|
828
|
+
```ruby
|
|
829
|
+
document["notes"] = "key: value" # => notes: "key: value"
|
|
830
|
+
document["lines"] = "line\nbreak" # => lines: "line\nbreak"
|
|
831
|
+
document["item"] = "- a" # => item: "- a"
|
|
832
|
+
document["tags"] = "[a, b]" # => tags: "[a, b]"
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
Other types are written as the YAML literal they stand for, so the value you read back is the value you wrote:
|
|
836
|
+
|
|
837
|
+
```ruby
|
|
838
|
+
document["port"] = 5432 # => port: 5432
|
|
839
|
+
document["ssl"] = true # => ssl: true
|
|
840
|
+
document["replica"] = nil # => replica: null
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
Both `set` and `insert` take `plain: true` when the value is YAML text you built yourself, to write it verbatim instead:
|
|
844
|
+
|
|
845
|
+
```ruby
|
|
846
|
+
document.set("tags", "[a, b]", plain: true) # => tags: [a, b]
|
|
847
|
+
```
|
|
848
|
+
|
|
849
|
+
```ruby
|
|
850
|
+
document.insert("tags", "- ruby\n- rails", plain: true)
|
|
851
|
+
# tags:
|
|
852
|
+
# - ruby
|
|
853
|
+
# - rails
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
Use `style:` to pick the quote style for the inserted value. A style that cannot carry the value falls back to double quotes rather than writing something that reads back differently:
|
|
857
|
+
|
|
858
|
+
```ruby
|
|
859
|
+
document.insert("city", "Berlin", style: :double) # => city: "Berlin"
|
|
860
|
+
```
|
|
861
|
+
|
|
721
862
|
Set arrays and hashes as values, they default to block style:
|
|
722
863
|
|
|
723
864
|
```ruby
|
|
@@ -823,6 +964,16 @@ scalar.quote_style # => :double
|
|
|
823
964
|
scalar.quote_style = :single
|
|
824
965
|
```
|
|
825
966
|
|
|
967
|
+
`Yerba.quote_scalar` writes a value as YAML text without needing a document, using the rule the insert APIs follow. Pass a style to ask for one, and it is honoured unless the value cannot survive it:
|
|
968
|
+
|
|
969
|
+
```ruby
|
|
970
|
+
Yerba.quote_scalar("plain") # => "plain"
|
|
971
|
+
Yerba.quote_scalar("key: value") # => "\"key: value\""
|
|
972
|
+
Yerba.quote_scalar("12345") # => "\"12345\""
|
|
973
|
+
Yerba.quote_scalar("ok", :single) # => "'ok'"
|
|
974
|
+
Yerba.quote_scalar("a\nb", :single) # => "\"a\\nb\""
|
|
975
|
+
```
|
|
976
|
+
|
|
826
977
|
### Collection Style
|
|
827
978
|
|
|
828
979
|
Read and change how collections are rendered, flow (inline) or block (multi-line):
|
data/exe/aarch64-linux-gnu/yerba
CHANGED
|
Binary file
|
data/ext/yerba/include/yerba.h
CHANGED
|
@@ -68,6 +68,8 @@ struct YerbaParseResult yerba_document_parse_file(const char *path);
|
|
|
68
68
|
|
|
69
69
|
struct YerbaParseResult yerba_document_parse(const char *content);
|
|
70
70
|
|
|
71
|
+
uint64_t yerba_document_generation(const struct Document *document);
|
|
72
|
+
|
|
71
73
|
void yerba_document_free(struct Document *document);
|
|
72
74
|
|
|
73
75
|
struct YerbaGetResult yerba_document_get(const struct Document *document, const char *path);
|
|
@@ -129,13 +131,18 @@ char *yerba_document_find(const struct Document *document,
|
|
|
129
131
|
struct YerbaResult yerba_document_set(struct Document *document,
|
|
130
132
|
const char *path,
|
|
131
133
|
const char *value,
|
|
134
|
+
uintptr_t value_length,
|
|
132
135
|
enum YerbaValueType value_type,
|
|
136
|
+
bool plain,
|
|
133
137
|
bool all);
|
|
134
138
|
|
|
135
139
|
struct YerbaResult yerba_document_insert(struct Document *document,
|
|
136
140
|
const char *path,
|
|
137
141
|
const char *value,
|
|
142
|
+
uintptr_t value_length,
|
|
138
143
|
enum YerbaValueType value_type,
|
|
144
|
+
bool plain,
|
|
145
|
+
const char *style,
|
|
139
146
|
const char *before,
|
|
140
147
|
const char *after,
|
|
141
148
|
int64_t at);
|
|
@@ -211,6 +218,8 @@ struct YerbaResult yerba_document_apply_yerbafile(struct Document *document,
|
|
|
211
218
|
|
|
212
219
|
char *yerba_document_to_string(const struct Document *document);
|
|
213
220
|
|
|
221
|
+
char *yerba_quote_scalar(const char *value, uintptr_t length, const char *style);
|
|
222
|
+
|
|
214
223
|
void yerba_string_free(char *s);
|
|
215
224
|
|
|
216
225
|
void yerba_result_free(struct YerbaResult result);
|
data/ext/yerba/yerba.c
CHANGED
|
@@ -339,6 +339,23 @@ static VALUE document_get_value(VALUE self, VALUE path) {
|
|
|
339
339
|
return rb_funcall(rb_path2class("JSON"), rb_intern("parse"), 1, json_string);
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
+
/* document.values → the whole document as Ruby objects, cached until the document changes */
|
|
343
|
+
static VALUE document_values(VALUE self) {
|
|
344
|
+
struct Document *document = get_document(self);
|
|
345
|
+
VALUE generation = ULL2NUM(yerba_document_generation(document));
|
|
346
|
+
|
|
347
|
+
if (rb_equal(rb_ivar_get(self, rb_intern("values_generation")), generation)) {
|
|
348
|
+
return rb_ivar_get(self, rb_intern("values"));
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
VALUE values = document_get_value(self, make_utf8_string(""));
|
|
352
|
+
|
|
353
|
+
rb_ivar_set(self, rb_intern("values"), values);
|
|
354
|
+
rb_ivar_set(self, rb_intern("values_generation"), generation);
|
|
355
|
+
|
|
356
|
+
return values;
|
|
357
|
+
}
|
|
358
|
+
|
|
342
359
|
/* document.selectors → ["database", "database.host", "tags", "tags[]", ...] */
|
|
343
360
|
static VALUE document_selectors(VALUE self) {
|
|
344
361
|
struct Document *document = get_document(self);
|
|
@@ -414,6 +431,31 @@ static VALUE document_resolve_selectors(VALUE self, VALUE path) {
|
|
|
414
431
|
return rb_funcall(rb_path2class("JSON"), rb_intern("parse"), 1, json_string);
|
|
415
432
|
}
|
|
416
433
|
|
|
434
|
+
/* Yerba.quote_scalar(value, style = nil) → YAML text for value, quoted when the style cannot carry it. */
|
|
435
|
+
static VALUE yerba_s_quote_scalar(int argc, VALUE *argv, VALUE self) {
|
|
436
|
+
VALUE value, style_value;
|
|
437
|
+
rb_scan_args(argc, argv, "11", &value, &style_value);
|
|
438
|
+
|
|
439
|
+
StringValue(value);
|
|
440
|
+
|
|
441
|
+
const char *style = NULL;
|
|
442
|
+
|
|
443
|
+
if (!NIL_P(style_value)) {
|
|
444
|
+
VALUE style_string = rb_obj_is_kind_of(style_value, rb_cString) ? style_value : rb_sym2str(style_value);
|
|
445
|
+
style = StringValueCStr(style_string);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
char *quoted = yerba_quote_scalar(RSTRING_PTR(value), (size_t)RSTRING_LEN(value), style);
|
|
449
|
+
|
|
450
|
+
if (quoted == NULL) return value;
|
|
451
|
+
|
|
452
|
+
VALUE result = make_utf8_string(quoted);
|
|
453
|
+
|
|
454
|
+
yerba_string_free(quoted);
|
|
455
|
+
|
|
456
|
+
return result;
|
|
457
|
+
}
|
|
458
|
+
|
|
417
459
|
/* document.get_quote_style(path) → :plain, :single, :double, :literal, etc. or nil */
|
|
418
460
|
static VALUE document_get_quote_style(VALUE self, VALUE path) {
|
|
419
461
|
struct Document *document = get_document(self);
|
|
@@ -574,6 +616,7 @@ static VALUE document_find(int argc, VALUE *argv, VALUE self) {
|
|
|
574
616
|
The caller must provide a number_buffer of at least 64 bytes. */
|
|
575
617
|
struct TypedValue {
|
|
576
618
|
const char *text;
|
|
619
|
+
size_t length;
|
|
577
620
|
YerbaValueType type;
|
|
578
621
|
};
|
|
579
622
|
|
|
@@ -598,14 +641,21 @@ static struct TypedValue ruby_to_typed_value(VALUE value, char *number_buffer) {
|
|
|
598
641
|
result.text = number_buffer;
|
|
599
642
|
result.type = YERBA_VALUE_TYPE_FLOAT;
|
|
600
643
|
} else {
|
|
601
|
-
|
|
644
|
+
StringValue(value);
|
|
645
|
+
|
|
646
|
+
result.text = RSTRING_PTR(value);
|
|
647
|
+
result.length = (size_t)RSTRING_LEN(value);
|
|
602
648
|
result.type = YERBA_VALUE_TYPE_STRING;
|
|
649
|
+
|
|
650
|
+
return result;
|
|
603
651
|
}
|
|
604
652
|
|
|
653
|
+
result.length = strlen(result.text);
|
|
654
|
+
|
|
605
655
|
return result;
|
|
606
656
|
}
|
|
607
657
|
|
|
608
|
-
/* document.set(path, value, condition: nil, if_exists: false, if_missing: false) */
|
|
658
|
+
/* document.set(path, value, condition: nil, if_exists: false, if_missing: false, plain: false, all: false) */
|
|
609
659
|
static VALUE document_set(int argc, VALUE *argv, VALUE self) {
|
|
610
660
|
VALUE path, value, opts;
|
|
611
661
|
rb_scan_args(argc, argv, "2:", &path, &value, &opts);
|
|
@@ -625,43 +675,58 @@ static VALUE document_set(int argc, VALUE *argv, VALUE self) {
|
|
|
625
675
|
char number_buffer[64];
|
|
626
676
|
struct TypedValue typed_value = ruby_to_typed_value(value, number_buffer);
|
|
627
677
|
bool all = false;
|
|
678
|
+
bool plain = false;
|
|
628
679
|
|
|
629
680
|
if (!NIL_P(opts)) {
|
|
630
681
|
VALUE v_all = rb_hash_aref(opts, ID2SYM(rb_intern("all")));
|
|
682
|
+
VALUE v_plain = rb_hash_aref(opts, ID2SYM(rb_intern("plain")));
|
|
631
683
|
|
|
632
684
|
if (RTEST(v_all)) all = true;
|
|
685
|
+
if (RTEST(v_plain)) plain = true;
|
|
633
686
|
}
|
|
634
687
|
|
|
635
|
-
YerbaResult result = yerba_document_set(document, StringValueCStr(path), typed_value.text, typed_value.type, all);
|
|
688
|
+
YerbaResult result = yerba_document_set(document, StringValueCStr(path), typed_value.text, typed_value.length, typed_value.type, plain, all);
|
|
636
689
|
check_result(result);
|
|
637
690
|
|
|
638
691
|
return self;
|
|
639
692
|
}
|
|
640
693
|
|
|
641
|
-
/* document.insert(path, value, before: nil, after: nil, at: nil) */
|
|
694
|
+
/* document.insert(path, value, before: nil, after: nil, at: nil, plain: false, style: nil) */
|
|
642
695
|
static VALUE document_insert(int argc, VALUE *argv, VALUE self) {
|
|
643
696
|
VALUE path, value, opts;
|
|
644
697
|
rb_scan_args(argc, argv, "2:", &path, &value, &opts);
|
|
645
698
|
|
|
646
699
|
const char *before = NULL;
|
|
647
700
|
const char *after = NULL;
|
|
701
|
+
const char *style = NULL;
|
|
648
702
|
long long at = -1;
|
|
703
|
+
bool plain = false;
|
|
649
704
|
|
|
650
705
|
if (!NIL_P(opts)) {
|
|
651
706
|
VALUE v_before = rb_hash_aref(opts, ID2SYM(rb_intern("before")));
|
|
652
707
|
VALUE v_after = rb_hash_aref(opts, ID2SYM(rb_intern("after")));
|
|
653
708
|
VALUE v_at = rb_hash_aref(opts, ID2SYM(rb_intern("at")));
|
|
709
|
+
VALUE v_plain = rb_hash_aref(opts, ID2SYM(rb_intern("plain")));
|
|
710
|
+
VALUE v_style = rb_hash_aref(opts, ID2SYM(rb_intern("style")));
|
|
654
711
|
|
|
655
712
|
if (!NIL_P(v_before)) before = StringValueCStr(v_before);
|
|
656
713
|
if (!NIL_P(v_after)) after = StringValueCStr(v_after);
|
|
657
714
|
if (!NIL_P(v_at)) at = NUM2LL(v_at);
|
|
715
|
+
if (RTEST(v_plain)) plain = true;
|
|
716
|
+
|
|
717
|
+
if (!NIL_P(v_style)) {
|
|
718
|
+
VALUE style_string = rb_obj_is_kind_of(v_style, rb_cString) ? v_style : rb_sym2str(v_style);
|
|
719
|
+
style = StringValueCStr(style_string);
|
|
720
|
+
}
|
|
658
721
|
}
|
|
659
722
|
|
|
660
723
|
char number_buffer[64];
|
|
661
724
|
struct TypedValue typed_value = ruby_to_typed_value(value, number_buffer);
|
|
662
725
|
|
|
663
726
|
struct Document *document = get_document(self);
|
|
664
|
-
YerbaResult result =
|
|
727
|
+
YerbaResult result =
|
|
728
|
+
yerba_document_insert(document, StringValueCStr(path), typed_value.text, typed_value.length, typed_value.type, plain, style,
|
|
729
|
+
before, after, at);
|
|
665
730
|
check_result(result);
|
|
666
731
|
|
|
667
732
|
return self;
|
|
@@ -1122,6 +1187,7 @@ void Init_yerba(void) {
|
|
|
1122
1187
|
rb_require("json");
|
|
1123
1188
|
|
|
1124
1189
|
rb_mYerba = rb_define_module("Yerba");
|
|
1190
|
+
rb_define_module_function(rb_mYerba, "quote_scalar", yerba_s_quote_scalar, -1);
|
|
1125
1191
|
rb_eError = rb_define_class_under(rb_mYerba, "Error", rb_eStandardError);
|
|
1126
1192
|
rb_ePathNotFoundError = rb_define_class_under(rb_mYerba, "PathNotFoundError", rb_eError);
|
|
1127
1193
|
rb_eParseError = rb_define_class_under(rb_mYerba, "ParseError", rb_eError);
|
|
@@ -1140,6 +1206,7 @@ void Init_yerba(void) {
|
|
|
1140
1206
|
rb_define_method(rb_cDocument, "[]", document_bracket, 1);
|
|
1141
1207
|
rb_define_method(rb_cDocument, "node_at", document_bracket, 1);
|
|
1142
1208
|
rb_define_method(rb_cDocument, "value_at", document_get_value, 1);
|
|
1209
|
+
rb_define_method(rb_cDocument, "values", document_values, 0);
|
|
1143
1210
|
rb_define_method(rb_cDocument, "get_all", document_get_all, 1);
|
|
1144
1211
|
rb_define_method(rb_cDocument, "location", document_location, -1);
|
|
1145
1212
|
rb_define_method(rb_cDocument, "locations", document_locations, 1);
|
data/lib/yerba/3.2/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/3.3/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/3.4/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/4.0/yerba.so
CHANGED
|
Binary file
|
data/lib/yerba/formatting.rb
CHANGED
|
@@ -3,16 +3,7 @@
|
|
|
3
3
|
module Yerba
|
|
4
4
|
module Formatting
|
|
5
5
|
def self.quote(value, style)
|
|
6
|
-
|
|
7
|
-
when :double
|
|
8
|
-
escaped = value.to_s.gsub("\\", "\\\\").gsub('"', '\\"')
|
|
9
|
-
"\"#{escaped}\""
|
|
10
|
-
when :single
|
|
11
|
-
escaped = value.to_s.gsub("'", "''")
|
|
12
|
-
"'#{escaped}'"
|
|
13
|
-
else
|
|
14
|
-
value.to_s
|
|
15
|
-
end
|
|
6
|
+
Yerba.quote_scalar(value.to_s, style)
|
|
16
7
|
end
|
|
17
8
|
|
|
18
9
|
def self.to_yaml_value(value)
|
|
@@ -55,9 +46,13 @@ module Yerba
|
|
|
55
46
|
return "{}" if value.empty?
|
|
56
47
|
|
|
57
48
|
value.map { |key, value|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
49
|
+
case value
|
|
50
|
+
when Array, Hash
|
|
51
|
+
if value.empty?
|
|
52
|
+
"#{prefix}#{key}: #{to_yaml_value(value)}"
|
|
53
|
+
else
|
|
54
|
+
"#{prefix}#{key}:\n#{to_block_yaml_value(value, indent + 1)}"
|
|
55
|
+
end
|
|
61
56
|
else
|
|
62
57
|
"#{prefix}#{key}: #{to_scalar_value(value)}"
|
|
63
58
|
end
|
|
@@ -72,6 +67,7 @@ module Yerba
|
|
|
72
67
|
when true then "true"
|
|
73
68
|
when false then "false"
|
|
74
69
|
when nil then "null"
|
|
70
|
+
when String then Yerba.quote_scalar(value)
|
|
75
71
|
else value.to_s
|
|
76
72
|
end
|
|
77
73
|
end
|
data/lib/yerba/map.rb
CHANGED
|
@@ -32,11 +32,11 @@ module Yerba
|
|
|
32
32
|
if connected?
|
|
33
33
|
new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
|
|
34
34
|
coerced = coerce_value(value, style: style)
|
|
35
|
-
|
|
35
|
+
|
|
36
|
+
is_collection = value.is_a?(Array) || value.is_a?(Hash)
|
|
37
|
+
is_block_value = is_collection && !coerced.start_with?("{", "[")
|
|
36
38
|
|
|
37
39
|
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
40
|
all_keys = keys
|
|
41
41
|
key_index = all_keys.index(key.to_s)
|
|
42
42
|
after_key = key_index&.positive? ? all_keys[key_index - 1] : nil
|
|
@@ -44,14 +44,14 @@ module Yerba
|
|
|
44
44
|
document.delete(new_path)
|
|
45
45
|
|
|
46
46
|
if after_key
|
|
47
|
-
document.insert(new_path, coerced, after: after_key)
|
|
47
|
+
document.insert(new_path, coerced, after: after_key, plain: true)
|
|
48
48
|
else
|
|
49
|
-
document.insert(new_path, coerced)
|
|
49
|
+
document.insert(new_path, coerced, plain: true)
|
|
50
50
|
end
|
|
51
51
|
elsif document.exists?(new_path)
|
|
52
|
-
document.set(new_path, coerced)
|
|
52
|
+
document.set(new_path, coerced, plain: is_collection)
|
|
53
53
|
else
|
|
54
|
-
document.insert(new_path, coerced)
|
|
54
|
+
document.insert(new_path, coerced, plain: is_collection)
|
|
55
55
|
end
|
|
56
56
|
else
|
|
57
57
|
@data[key] = value
|
|
@@ -62,7 +62,10 @@ module Yerba
|
|
|
62
62
|
if connected?
|
|
63
63
|
new_path = @selector.empty? ? key.to_s : "#{@selector}.#{key}"
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
coerced = coerce_value(value, style: style)
|
|
66
|
+
is_collection = value.is_a?(Array) || value.is_a?(Hash)
|
|
67
|
+
|
|
68
|
+
document.insert(new_path, coerced, before: before, after: after, plain: is_collection)
|
|
66
69
|
else
|
|
67
70
|
@data[key] = value
|
|
68
71
|
end
|
data/lib/yerba/sequence.rb
CHANGED
|
@@ -60,10 +60,9 @@ module Yerba
|
|
|
60
60
|
when Hash
|
|
61
61
|
document.insert_object(@selector, item)
|
|
62
62
|
when Scalar
|
|
63
|
-
document.insert(@selector, item.to_yaml)
|
|
63
|
+
document.insert(@selector, item.to_yaml, plain: true)
|
|
64
64
|
else
|
|
65
|
-
|
|
66
|
-
document.insert(@selector, formatted)
|
|
65
|
+
document.insert(@selector, item.to_s, style: detect_quote_style)
|
|
67
66
|
end
|
|
68
67
|
else
|
|
69
68
|
@data << item
|
|
@@ -425,10 +424,6 @@ module Yerba
|
|
|
425
424
|
current
|
|
426
425
|
end
|
|
427
426
|
|
|
428
|
-
def format_for_insert(value)
|
|
429
|
-
Formatting.quote(value, detect_quote_style)
|
|
430
|
-
end
|
|
431
|
-
|
|
432
427
|
def detect_quote_style
|
|
433
428
|
document.get_quote_style("#{@selector}[0]")
|
|
434
429
|
end
|
data/lib/yerba/version.rb
CHANGED
data/rust/Cargo.lock
CHANGED