yerba 0.7.5-arm-linux-gnu → 0.8.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 +4 -4
- data/README.md +67 -2
- data/exe/arm-linux-gnu/yerba +0 -0
- data/ext/yerba/include/yerba.h +8 -0
- data/ext/yerba/yerba.c +70 -8
- 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/map.rb +15 -10
- data/lib/yerba/node.rb +2 -2
- data/lib/yerba/sequence.rb +13 -1
- data/lib/yerba/version.rb +1 -1
- data/rust/Cargo.lock +1 -1
- data/rust/Cargo.toml +1 -1
- data/rust/src/commands/get.rs +12 -2
- data/rust/src/commands/rename.rs +3 -3
- data/rust/src/commands/set.rs +11 -1
- data/rust/src/document/condition.rs +89 -32
- data/rust/src/document/delete.rs +6 -1
- data/rust/src/document/get.rs +94 -26
- data/rust/src/document/insert.rs +22 -0
- data/rust/src/document/mod.rs +67 -18
- data/rust/src/document/set.rs +81 -0
- data/rust/src/document/style.rs +12 -0
- data/rust/src/error.rs +14 -0
- data/rust/src/ffi.rs +71 -9
- data/rust/src/json.rs +10 -1
- data/rust/src/lib.rs +14 -6
- data/rust/src/main.rs +1 -0
- data/rust/src/selector.rs +19 -3
- data/rust/src/syntax.rs +46 -25
- data/rust/src/yerbafile.rs +111 -7
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8b256e8dec330b8482fdce4da57059551a551e8c78bd8c1f4be7bf972832f95d
|
|
4
|
+
data.tar.gz: c29e07dbce9b96e2cccb615854e3eb2407bd8ddd8d4b70f2f7b99e91e975f3d1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 172e0f2c8d79a5829fc93b4907749350596b38e013f3f954ec14589227a9beea6006d3aa7079349580afe268c9a973c9d3f100c18415639ad989778cc2831165
|
|
7
|
+
data.tar.gz: a8f855a4d2ad3e532c7c5305524b85ec19c82ca61bcf6efe1c916afc6fa2e1d799b08139bdc2131056f668606b019a9863227f89787f60867e3eadd543df2ba2
|
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.8"
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
```rust
|
|
@@ -96,8 +96,11 @@ Selectors let you address any node in a YAML document:
|
|
|
96
96
|
| `key.nested` | Nested key path | `"database.settings.pool"` |
|
|
97
97
|
| `[]` | All items in array | `"[].title"` |
|
|
98
98
|
| `[N]` | Item at index | `"[0].title"` |
|
|
99
|
+
| `*` | All values in a map | `"database.*"` |
|
|
99
100
|
| `[].key[].nested` | Nested array access | `"[].speakers[].name"` |
|
|
100
101
|
|
|
102
|
+
`[]` and `*` are the same idea applied to the two collection types: `[]` matches every item of a sequence, `*` matches every value of a map. Both can be combined with the other patterns, as in `"[].*"` or `"*.city"`.
|
|
103
|
+
|
|
101
104
|
### Conditions
|
|
102
105
|
|
|
103
106
|
Conditions filter which items a command operates on:
|
|
@@ -109,6 +112,8 @@ Conditions filter which items a command operates on:
|
|
|
109
112
|
| `.key contains val` | Substring or member | `".title contains Ruby"` |
|
|
110
113
|
| `.key not_contains val` | Negated contains | `".title not_contains test"` |
|
|
111
114
|
|
|
115
|
+
The selector is relative to each item and starts with `.`. A condition that is malformed, or that uses an absolute selector where each item is tested, is rejected rather than matching nothing, so a typo is an error instead of a command that quietly does nothing.
|
|
116
|
+
|
|
112
117
|
---
|
|
113
118
|
|
|
114
119
|
### `get`
|
|
@@ -539,6 +544,7 @@ Available pipeline steps:
|
|
|
539
544
|
- `directives` Add or remove the document start marker (`---`), with optional `max` validation
|
|
540
545
|
- `unique` Find or remove duplicate items in a sequence
|
|
541
546
|
- `schema` Validate against a JSON schema (with optional `path` for scoping)
|
|
547
|
+
- `final_newline` Enforce exact number of trailing newlines (`count: 1` by default, strips extras)
|
|
542
548
|
|
|
543
549
|
This makes it easy to enforce project-wide YAML conventions in CI:
|
|
544
550
|
|
|
@@ -700,6 +706,12 @@ Set all matching nodes at once with `all: true`:
|
|
|
700
706
|
document.set("[].description", "", all: true)
|
|
701
707
|
```
|
|
702
708
|
|
|
709
|
+
Setting a scalar over a key whose value is a collection replaces the collection:
|
|
710
|
+
|
|
711
|
+
```ruby
|
|
712
|
+
document.root["venue"] = "none" # => venue: none
|
|
713
|
+
```
|
|
714
|
+
|
|
703
715
|
Insert new keys with positional control:
|
|
704
716
|
|
|
705
717
|
```ruby
|
|
@@ -828,6 +840,24 @@ document["database"].collection_style = :flow # => database: {host: localhost,
|
|
|
828
840
|
document["database"].collection_style = :block # => database:\n host: localhost\n port: 5432
|
|
829
841
|
```
|
|
830
842
|
|
|
843
|
+
Flow collections are read and iterated like block ones, and their scalars can be
|
|
844
|
+
changed in place:
|
|
845
|
+
|
|
846
|
+
```ruby
|
|
847
|
+
document = Yerba::Document.parse("tags: [ruby, rails]\n")
|
|
848
|
+
|
|
849
|
+
document["tags"].map(&:value) # => ["ruby", "rails"]
|
|
850
|
+
document["tags[1]"].value = "crystal" # => tags: [ruby, crystal]
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
Adding or removing entries is not supported yet, and raises rather than
|
|
854
|
+
reformatting the collection. Switch to block style first:
|
|
855
|
+
|
|
856
|
+
```ruby
|
|
857
|
+
document["tags"].collection_style = :block
|
|
858
|
+
document.delete("tags[0]")
|
|
859
|
+
```
|
|
860
|
+
|
|
831
861
|
### Sequence Indent
|
|
832
862
|
|
|
833
863
|
Control whether sequence items are indented under their key or at the same level:
|
|
@@ -892,17 +922,52 @@ document.locations("[].speakers[]")
|
|
|
892
922
|
|
|
893
923
|
### Wildcard Access
|
|
894
924
|
|
|
895
|
-
When `[]` receives a wildcard selector
|
|
925
|
+
When `[]` receives a wildcard selector, it returns an array of nodes instead of a single node. `[]` matches every item of a sequence and `*` matches every value of a map:
|
|
896
926
|
|
|
897
927
|
```ruby
|
|
898
928
|
document["[].title"] # => [Yerba::Scalar, Yerba::Scalar, ...]
|
|
899
929
|
document["[].speakers[]"] # => [Yerba::Scalar, Yerba::Scalar, ...]
|
|
900
930
|
document["items[].name"] # => [Yerba::Scalar, Yerba::Scalar, ...]
|
|
901
931
|
|
|
932
|
+
document["database.*"] # => [Yerba::Scalar, Yerba::Scalar, ...]
|
|
933
|
+
document["*"] # => every value of the root map
|
|
934
|
+
document["[].*"] # => every value of every item
|
|
935
|
+
|
|
902
936
|
document["[].title"].each { |scalar| puts scalar.value }
|
|
903
937
|
document["[].title"].each { |scalar| scalar.value = "Updated" }
|
|
904
938
|
```
|
|
905
939
|
|
|
940
|
+
Each node knows the key it belongs to, which is how a map value can be traced back to its name:
|
|
941
|
+
|
|
942
|
+
```ruby
|
|
943
|
+
document["database.*"].map { |node| [node.key.value, node.value] }
|
|
944
|
+
# => [["host", "localhost"], ["port", 5432]]
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
`get_all` resolves the same selectors in a single walk of the document, rather than looking each node up separately. It is the faster choice when reading many nodes, and returns nodes that are still connected to the document:
|
|
948
|
+
|
|
949
|
+
```ruby
|
|
950
|
+
document.get_all("[].title") # => [Yerba::Scalar, Yerba::Scalar, ...]
|
|
951
|
+
document.get_all("database.*") # => [Yerba::Scalar, Yerba::Scalar, ...]
|
|
952
|
+
|
|
953
|
+
document.get_all("[].title").first.value = "Updated"
|
|
954
|
+
document.save!
|
|
955
|
+
```
|
|
956
|
+
|
|
957
|
+
Reading values rather than nodes keeps a positional `nil` where a branch does not match, while resolving nodes skips it:
|
|
958
|
+
|
|
959
|
+
```ruby
|
|
960
|
+
document.value_at("*.city") # => [nil, "Berlin", nil]
|
|
961
|
+
document.get_all("*.city").map(&:value) # => ["Berlin"]
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
Wildcards address more than one node, so they cannot be written through. `set`, `insert` and `delete` raise rather than change every match at once:
|
|
965
|
+
|
|
966
|
+
```ruby
|
|
967
|
+
document.set("database.*", "x") # => raises Yerba::Error
|
|
968
|
+
document.delete("database.*") # => raises Yerba::Error
|
|
969
|
+
```
|
|
970
|
+
|
|
906
971
|
### Collections
|
|
907
972
|
|
|
908
973
|
Operate on multiple files matching a glob pattern:
|
data/exe/arm-linux-gnu/yerba
CHANGED
|
Binary file
|
data/ext/yerba/include/yerba.h
CHANGED
|
@@ -89,6 +89,10 @@ char *yerba_document_selectors(const struct Document *document);
|
|
|
89
89
|
|
|
90
90
|
char *yerba_document_resolve_selectors(const struct Document *document, const char *path);
|
|
91
91
|
|
|
92
|
+
bool yerba_selector_has_wildcard(const char *path);
|
|
93
|
+
|
|
94
|
+
char *yerba_document_keys(const struct Document *document, const char *path);
|
|
95
|
+
|
|
92
96
|
char *yerba_document_get_quote_style(const struct Document *document, const char *path);
|
|
93
97
|
|
|
94
98
|
struct YerbaResult yerba_document_set_quote_style(struct Document *document,
|
|
@@ -107,6 +111,8 @@ struct YerbaResult yerba_document_set_sequence_indent(struct Document *document,
|
|
|
107
111
|
const char *path,
|
|
108
112
|
const char *style);
|
|
109
113
|
|
|
114
|
+
char *yerba_validate_condition(const char *condition, bool item_context);
|
|
115
|
+
|
|
110
116
|
bool yerba_document_evaluate_condition(const struct Document *document,
|
|
111
117
|
const char *parent_path,
|
|
112
118
|
const char *condition);
|
|
@@ -213,6 +219,8 @@ void yerba_get_result_free(struct YerbaGetResult result);
|
|
|
213
219
|
|
|
214
220
|
struct YerbaTypedList yerba_glob_get(const char *glob_pattern, const char *path);
|
|
215
221
|
|
|
222
|
+
struct YerbaTypedList yerba_document_get_all(const struct Document *document, const char *path);
|
|
223
|
+
|
|
216
224
|
struct YerbaTypedList yerba_glob_find(const char *glob_pattern,
|
|
217
225
|
const char *path,
|
|
218
226
|
const char *condition,
|
data/ext/yerba/yerba.c
CHANGED
|
@@ -98,6 +98,19 @@ static VALUE typed_value_to_ruby(YerbaTypedValue typed_value) {
|
|
|
98
98
|
return result;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
static void check_condition(const char *condition, bool item_context) {
|
|
102
|
+
if (!condition) return;
|
|
103
|
+
|
|
104
|
+
char *error = yerba_validate_condition(condition, item_context);
|
|
105
|
+
|
|
106
|
+
if (!error) return;
|
|
107
|
+
|
|
108
|
+
VALUE message = make_utf8_string(error);
|
|
109
|
+
yerba_string_free(error);
|
|
110
|
+
|
|
111
|
+
rb_raise(rb_eError, "%s", StringValueCStr(message));
|
|
112
|
+
}
|
|
113
|
+
|
|
101
114
|
static int should_proceed(struct Document *document, VALUE opts) {
|
|
102
115
|
if (NIL_P(opts)) return 1;
|
|
103
116
|
VALUE v_condition = rb_hash_aref(opts, ID2SYM(rb_intern("condition")));
|
|
@@ -106,6 +119,8 @@ static int should_proceed(struct Document *document, VALUE opts) {
|
|
|
106
119
|
VALUE v_path = rb_hash_aref(opts, ID2SYM(rb_intern("condition_path")));
|
|
107
120
|
const char *parent_path = NIL_P(v_path) ? "" : StringValueCStr(v_path);
|
|
108
121
|
|
|
122
|
+
check_condition(StringValueCStr(v_condition), parent_path[0] != '\0');
|
|
123
|
+
|
|
109
124
|
return yerba_document_evaluate_condition(document, parent_path, StringValueCStr(v_condition));
|
|
110
125
|
}
|
|
111
126
|
|
|
@@ -256,8 +271,7 @@ static VALUE document_bracket(VALUE self, VALUE path) {
|
|
|
256
271
|
|
|
257
272
|
const char *selector = StringValueCStr(path);
|
|
258
273
|
|
|
259
|
-
|
|
260
|
-
if (strstr(selector, "[]") != NULL) {
|
|
274
|
+
if (yerba_selector_has_wildcard(selector)) {
|
|
261
275
|
char *json = yerba_document_resolve_selectors(document, selector);
|
|
262
276
|
|
|
263
277
|
if (!json) return rb_ary_new();
|
|
@@ -338,6 +352,19 @@ static VALUE document_selectors(VALUE self) {
|
|
|
338
352
|
return rb_funcall(rb_path2class("JSON"), rb_intern("parse"), 1, json_string);
|
|
339
353
|
}
|
|
340
354
|
|
|
355
|
+
/* document.keys_at(selector) → ["host", "port", ...] */
|
|
356
|
+
static VALUE document_keys_at(VALUE self, VALUE path) {
|
|
357
|
+
struct Document *document = get_document(self);
|
|
358
|
+
char *json = yerba_document_keys(document, StringValueCStr(path));
|
|
359
|
+
|
|
360
|
+
if (!json) return rb_ary_new();
|
|
361
|
+
|
|
362
|
+
VALUE json_string = make_utf8_string(json);
|
|
363
|
+
yerba_string_free(json);
|
|
364
|
+
|
|
365
|
+
return rb_funcall(rb_path2class("JSON"), rb_intern("parse"), 1, json_string);
|
|
366
|
+
}
|
|
367
|
+
|
|
341
368
|
/* document.locations(selector) → [Yerba::Location, ...] */
|
|
342
369
|
static VALUE document_locations(VALUE self, VALUE path) {
|
|
343
370
|
struct Document *document = get_document(self);
|
|
@@ -508,6 +535,8 @@ static VALUE document_condition_p(int argc, VALUE *argv, VALUE self) {
|
|
|
508
535
|
|
|
509
536
|
struct Document *document = get_document(self);
|
|
510
537
|
|
|
538
|
+
check_condition(StringValueCStr(condition), parent_path[0] != '\0');
|
|
539
|
+
|
|
511
540
|
return yerba_document_evaluate_condition(document, parent_path, StringValueCStr(condition)) ? Qtrue : Qfalse;
|
|
512
541
|
}
|
|
513
542
|
|
|
@@ -528,6 +557,9 @@ static VALUE document_find(int argc, VALUE *argv, VALUE self) {
|
|
|
528
557
|
}
|
|
529
558
|
|
|
530
559
|
struct Document *document = get_document(self);
|
|
560
|
+
|
|
561
|
+
check_condition(condition, true);
|
|
562
|
+
|
|
531
563
|
char *json = yerba_document_find(document, StringValueCStr(path), condition, select);
|
|
532
564
|
|
|
533
565
|
if (!json) return rb_ary_new();
|
|
@@ -959,12 +991,7 @@ static VALUE document_path(VALUE self) {
|
|
|
959
991
|
return rb_iv_get(self, "@path");
|
|
960
992
|
}
|
|
961
993
|
|
|
962
|
-
|
|
963
|
-
static VALUE collection_s_get(VALUE self, VALUE pattern, VALUE path) {
|
|
964
|
-
(void) self;
|
|
965
|
-
|
|
966
|
-
YerbaTypedList result = yerba_glob_get(StringValueCStr(pattern), StringValueCStr(path));
|
|
967
|
-
|
|
994
|
+
static VALUE located_list_to_ruby(YerbaTypedList result, VALUE document) {
|
|
968
995
|
if (!result.json) return rb_ary_new();
|
|
969
996
|
|
|
970
997
|
VALUE json_string = make_utf8_string(result.json);
|
|
@@ -992,6 +1019,23 @@ static VALUE collection_s_get(VALUE self, VALUE pattern, VALUE path) {
|
|
|
992
1019
|
if (!NIL_P(file_path)) rb_hash_aset(kwargs, ID2SYM(rb_intern("file_path")), file_path);
|
|
993
1020
|
if (!NIL_P(line)) rb_hash_aset(kwargs, ID2SYM(rb_intern("line")), line);
|
|
994
1021
|
if (!NIL_P(location)) rb_hash_aset(kwargs, ID2SYM(rb_intern("location")), location);
|
|
1022
|
+
if (!NIL_P(document)) rb_hash_aset(kwargs, ID2SYM(rb_intern("document")), document);
|
|
1023
|
+
|
|
1024
|
+
VALUE key_name = rb_hash_aref(item, rb_str_new_cstr("key_name"));
|
|
1025
|
+
|
|
1026
|
+
if (!NIL_P(key_name)) {
|
|
1027
|
+
VALUE key_location = rb_hash_aref(item, rb_str_new_cstr("key_location"));
|
|
1028
|
+
VALUE key_kwargs = rb_hash_new();
|
|
1029
|
+
|
|
1030
|
+
rb_hash_aset(key_kwargs, ID2SYM(rb_intern("selector")), Qnil);
|
|
1031
|
+
rb_hash_aset(key_kwargs, ID2SYM(rb_intern("value")), key_name);
|
|
1032
|
+
if (!NIL_P(key_location)) rb_hash_aset(key_kwargs, ID2SYM(rb_intern("location")), key_location);
|
|
1033
|
+
|
|
1034
|
+
VALUE key_args[1] = { key_kwargs };
|
|
1035
|
+
VALUE key = rb_funcallv_kw(rb_path2class("Yerba::Scalar"), rb_intern("from"), 1, key_args, RB_PASS_KEYWORDS);
|
|
1036
|
+
|
|
1037
|
+
rb_hash_aset(kwargs, ID2SYM(rb_intern("key")), key);
|
|
1038
|
+
}
|
|
995
1039
|
|
|
996
1040
|
if (strcmp(type_str, "scalar") == 0) {
|
|
997
1041
|
VALUE text = rb_hash_aref(item, rb_str_new_cstr("text"));
|
|
@@ -1015,6 +1059,20 @@ static VALUE collection_s_get(VALUE self, VALUE pattern, VALUE path) {
|
|
|
1015
1059
|
return array;
|
|
1016
1060
|
}
|
|
1017
1061
|
|
|
1062
|
+
/* Collection.get(glob, selector) → [Yerba::Scalar|Map|Sequence, ...] */
|
|
1063
|
+
static VALUE collection_s_get(VALUE self, VALUE pattern, VALUE path) {
|
|
1064
|
+
(void) self;
|
|
1065
|
+
|
|
1066
|
+
return located_list_to_ruby(yerba_glob_get(StringValueCStr(pattern), StringValueCStr(path)), Qnil);
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/* document.get_all(selector) → [Yerba::Scalar|Map|Sequence, ...] */
|
|
1070
|
+
static VALUE document_get_all(VALUE self, VALUE path) {
|
|
1071
|
+
struct Document *document = get_document(self);
|
|
1072
|
+
|
|
1073
|
+
return located_list_to_ruby(yerba_document_get_all(document, StringValueCStr(path)), self);
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1018
1076
|
/* Collection.find(glob, path, condition: nil, select: nil) */
|
|
1019
1077
|
static VALUE collection_s_find(int argc, VALUE *argv, VALUE self) {
|
|
1020
1078
|
(void)self;
|
|
@@ -1032,6 +1090,8 @@ static VALUE collection_s_find(int argc, VALUE *argv, VALUE self) {
|
|
|
1032
1090
|
if (!NIL_P(v_select)) select = StringValueCStr(v_select);
|
|
1033
1091
|
}
|
|
1034
1092
|
|
|
1093
|
+
check_condition(condition, true);
|
|
1094
|
+
|
|
1035
1095
|
YerbaTypedList result = yerba_glob_find(StringValueCStr(pattern), StringValueCStr(path), condition, select);
|
|
1036
1096
|
|
|
1037
1097
|
if (!result.json) return rb_ary_new();
|
|
@@ -1080,9 +1140,11 @@ void Init_yerba(void) {
|
|
|
1080
1140
|
rb_define_method(rb_cDocument, "[]", document_bracket, 1);
|
|
1081
1141
|
rb_define_method(rb_cDocument, "node_at", document_bracket, 1);
|
|
1082
1142
|
rb_define_method(rb_cDocument, "value_at", document_get_value, 1);
|
|
1143
|
+
rb_define_method(rb_cDocument, "get_all", document_get_all, 1);
|
|
1083
1144
|
rb_define_method(rb_cDocument, "location", document_location, -1);
|
|
1084
1145
|
rb_define_method(rb_cDocument, "locations", document_locations, 1);
|
|
1085
1146
|
rb_define_method(rb_cDocument, "selectors", document_selectors, 0);
|
|
1147
|
+
rb_define_method(rb_cDocument, "keys_at", document_keys_at, 1);
|
|
1086
1148
|
rb_define_method(rb_cDocument, "resolve_selectors", document_resolve_selectors, 1);
|
|
1087
1149
|
rb_define_method(rb_cDocument, "get_quote_style", document_get_quote_style, 1);
|
|
1088
1150
|
rb_define_method(rb_cDocument, "set_quote_style", document_set_quote_style, 2);
|
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/map.rb
CHANGED
|
@@ -77,24 +77,29 @@ module Yerba
|
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
def keys
|
|
80
|
-
|
|
81
|
-
results = document.find(@selector)
|
|
82
|
-
return [] unless results.is_a?(Array) && results.first.is_a?(Hash)
|
|
80
|
+
return @data.keys unless connected?
|
|
83
81
|
|
|
84
|
-
|
|
85
|
-
else
|
|
86
|
-
@data.keys
|
|
87
|
-
end
|
|
82
|
+
document.keys_at(@selector)
|
|
88
83
|
end
|
|
89
84
|
|
|
90
85
|
def each(&)
|
|
91
86
|
return enum_for(:each) unless block_given?
|
|
92
87
|
|
|
93
|
-
|
|
94
|
-
keys.each { |key| yield key, self[key] }
|
|
95
|
-
else
|
|
88
|
+
unless connected?
|
|
96
89
|
@data.each(&)
|
|
90
|
+
return self
|
|
97
91
|
end
|
|
92
|
+
|
|
93
|
+
names = keys
|
|
94
|
+
values = document.get_all(@selector.empty? ? "*" : "#{@selector}.*")
|
|
95
|
+
|
|
96
|
+
if values.length == names.length && values.all?(&:key)
|
|
97
|
+
values.each { |value| yield value.key.value, value }
|
|
98
|
+
else
|
|
99
|
+
names.each { |key| yield key, self[key] }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
self
|
|
98
103
|
end
|
|
99
104
|
|
|
100
105
|
def fetch(key)
|
data/lib/yerba/node.rb
CHANGED
|
@@ -36,10 +36,10 @@ module Yerba
|
|
|
36
36
|
instance
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
def from(
|
|
39
|
+
def from(selector:, file_path: nil, line: nil, location: nil, document: nil, key: nil, **attributes)
|
|
40
40
|
instance = allocate
|
|
41
41
|
|
|
42
|
-
instance.send(:init_node,
|
|
42
|
+
instance.send(:init_node, document, selector, coerce_location(location), key, file_path, line)
|
|
43
43
|
instance.send(:init_from, **attributes) if instance.respond_to?(:init_from, true)
|
|
44
44
|
|
|
45
45
|
instance
|
data/lib/yerba/sequence.rb
CHANGED
|
@@ -90,10 +90,22 @@ module Yerba
|
|
|
90
90
|
self
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
-
def each
|
|
93
|
+
def each(&)
|
|
94
94
|
return enum_for(:each) unless block_given?
|
|
95
95
|
|
|
96
|
+
if connected?
|
|
97
|
+
items = document.get_all("#{@selector}[]")
|
|
98
|
+
|
|
99
|
+
if items.length == length
|
|
100
|
+
items.each(&)
|
|
101
|
+
|
|
102
|
+
return self
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
96
106
|
length.times { |index| yield self[index] }
|
|
107
|
+
|
|
108
|
+
self
|
|
97
109
|
end
|
|
98
110
|
|
|
99
111
|
def find_by(selector = nil, value = nil, **criteria)
|
data/lib/yerba/version.rb
CHANGED
data/rust/Cargo.lock
CHANGED
data/rust/Cargo.toml
CHANGED
data/rust/src/commands/get.rs
CHANGED
|
@@ -62,6 +62,16 @@ impl Args {
|
|
|
62
62
|
condition.clone()
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
+
if let Some(condition) = &normalized_condition {
|
|
66
|
+
if let Err(error) = yerba::validate_item_condition(condition) {
|
|
67
|
+
use super::color::*;
|
|
68
|
+
|
|
69
|
+
eprintln!("{RED}Error:{RESET} {}", error);
|
|
70
|
+
|
|
71
|
+
process::exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
65
75
|
let search_path_string = search_path.to_selector_string();
|
|
66
76
|
let mut all_results: Vec<serde_json::Value> = Vec::new();
|
|
67
77
|
let files = resolve_files(&self.file);
|
|
@@ -114,7 +124,7 @@ impl Args {
|
|
|
114
124
|
|
|
115
125
|
let (values, selectors, lines): (Vec<yaml_serde::Value>, Vec<String>, Vec<usize>) = if select_fields.is_some() {
|
|
116
126
|
if let Some(condition) = &normalized_condition {
|
|
117
|
-
let triples = document.filter_with_selectors(&search_path_string, condition);
|
|
127
|
+
let triples = document.filter_with_selectors(&search_path_string, condition).unwrap_or_default();
|
|
118
128
|
let (values, rest): (Vec<_>, Vec<_>) = triples.into_iter().map(|(v, s, l)| (v, (s, l))).unzip();
|
|
119
129
|
let (selectors, lines): (Vec<_>, Vec<_>) = rest.into_iter().unzip();
|
|
120
130
|
|
|
@@ -129,7 +139,7 @@ impl Args {
|
|
|
129
139
|
(values, selectors, lines)
|
|
130
140
|
}
|
|
131
141
|
} else if let Some(condition) = &normalized_condition {
|
|
132
|
-
(document.filter(&search_path_string, condition), Vec::new(), Vec::new())
|
|
142
|
+
(document.filter(&search_path_string, condition).unwrap_or_default(), Vec::new(), Vec::new())
|
|
133
143
|
} else {
|
|
134
144
|
(document.get_values(&search_path_string), Vec::new(), Vec::new())
|
|
135
145
|
};
|
data/rust/src/commands/rename.rs
CHANGED
|
@@ -8,15 +8,15 @@ use super::{output, parse_file, resolve_files, run_op};
|
|
|
8
8
|
static EXAMPLES: LazyLock<String> = LazyLock::new(|| {
|
|
9
9
|
colorize_examples(indoc! {r#"
|
|
10
10
|
yerba rename config.yml "database.host" "database.hostname"
|
|
11
|
-
yerba rename config.yml "database.host" "hostname"
|
|
12
|
-
yerba rename config.yml "database.host" "settings.db_host"
|
|
13
11
|
yerba rename videos.yml "[0].old_name" "[0].name"
|
|
12
|
+
yerba rename config.yml "database.host" "settings.db_host" # moves the key to another map
|
|
13
|
+
yerba rename config.yml "database.host" "hostname" # moves the key to the document root
|
|
14
14
|
"#})
|
|
15
15
|
});
|
|
16
16
|
|
|
17
17
|
#[derive(clap::Args)]
|
|
18
18
|
#[command(
|
|
19
|
-
about = "Rename a key
|
|
19
|
+
about = "Rename a key, or move it to another map (the destination is a full selector path)",
|
|
20
20
|
arg_required_else_help = true,
|
|
21
21
|
after_help = EXAMPLES.as_str()
|
|
22
22
|
)]
|
data/rust/src/commands/set.rs
CHANGED
|
@@ -42,6 +42,16 @@ impl Args {
|
|
|
42
42
|
pub fn run(self) {
|
|
43
43
|
let parent_path = self.selector.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
|
|
44
44
|
|
|
45
|
+
if let Some(condition) = &self.condition {
|
|
46
|
+
if let Err(error) = yerba::validate_condition(condition) {
|
|
47
|
+
use super::color::*;
|
|
48
|
+
|
|
49
|
+
eprintln!("{RED}Error:{RESET} {}", error);
|
|
50
|
+
|
|
51
|
+
std::process::exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
45
55
|
for resolved_file in resolve_files(&self.file) {
|
|
46
56
|
let mut document = parse_file(&resolved_file);
|
|
47
57
|
|
|
@@ -50,7 +60,7 @@ impl Args {
|
|
|
50
60
|
} else if self.if_missing {
|
|
51
61
|
!document.exists(&self.selector)
|
|
52
62
|
} else if let Some(condition) = &self.condition {
|
|
53
|
-
document.evaluate_condition(parent_path, condition)
|
|
63
|
+
document.evaluate_condition(parent_path, condition).unwrap_or(false)
|
|
54
64
|
} else {
|
|
55
65
|
true
|
|
56
66
|
};
|