yerba 0.3.0 → 0.4.0
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 +90 -8
- data/ext/yerba/extconf.rb +22 -3
- data/ext/yerba/include/yerba.h +19 -9
- data/ext/yerba/yerba.c +83 -24
- data/lib/yerba/collection.rb +35 -0
- data/lib/yerba/document.rb +16 -0
- data/lib/yerba/sequence.rb +169 -1
- data/lib/yerba/version.rb +1 -1
- data/rust/Cargo.lock +1 -0
- data/rust/Cargo.toml +1 -1
- data/rust/cbindgen.toml +1 -0
- data/rust/rustfmt.toml +1 -1
- data/rust/src/commands/blank_lines.rs +1 -4
- data/rust/src/commands/directives.rs +61 -0
- data/rust/src/commands/get.rs +5 -22
- data/rust/src/commands/mod.rs +5 -10
- data/rust/src/commands/quote_style.rs +12 -6
- data/rust/src/commands/selectors.rs +3 -19
- data/rust/src/commands/sort.rs +22 -157
- data/rust/src/didyoumean.rs +2 -4
- data/rust/src/document/condition.rs +139 -0
- data/rust/src/document/delete.rs +91 -0
- data/rust/src/document/get.rs +262 -0
- data/rust/src/document/insert.rs +314 -0
- data/rust/src/document/mod.rs +784 -0
- data/rust/src/document/set.rs +90 -0
- data/rust/src/document/sort.rs +607 -0
- data/rust/src/document/style.rs +473 -0
- data/rust/src/error.rs +24 -6
- data/rust/src/ffi.rs +208 -520
- data/rust/src/json.rs +1 -7
- data/rust/src/lib.rs +88 -2
- data/rust/src/quote_style.rs +83 -7
- data/rust/src/selector.rs +2 -7
- data/rust/src/syntax.rs +41 -21
- data/rust/src/yerbafile.rs +39 -18
- metadata +10 -2
- data/rust/Cargo.lock +0 -805
- data/rust/src/document.rs +0 -2304
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8e77d3cce1f16b9adf15e44b0dec51f2182ab12eeeacea0e0d6d1223d7a1f23b
|
|
4
|
+
data.tar.gz: 7abd1edd2196ce73d22dab4b05dbb2f2af47cb04e1cff756bd8df5a678dcbe9e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d22690ae793eb147848050793e22eeeeb8614d942d258e685b4bbea3094d0c118ac72d93c4beb56044bad8d7a3ce9a37947fac8870c302755d4777075a191ca
|
|
7
|
+
data.tar.gz: 3c4d9c7159d665b55355c965f5f2a41b5962b17dde6f29aa5a57006e33fc9b64c987fe833872e102d5bf4882eb11673f67c1001d857011213b2012ce5648344a
|
data/README.md
CHANGED
|
@@ -47,13 +47,15 @@ Use `yerba` as a library in your Rust project:
|
|
|
47
47
|
|
|
48
48
|
```toml
|
|
49
49
|
[dependencies]
|
|
50
|
-
yerba = "0.
|
|
50
|
+
yerba = "0.4"
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
```rust
|
|
54
54
|
let mut document = yerba::parse_file("config.yml")?;
|
|
55
55
|
document.set("database.host", "0.0.0.0")?;
|
|
56
|
-
|
|
56
|
+
|
|
57
|
+
document.save()?; // saves to original path
|
|
58
|
+
document.save_to("output.yml")?; // saves to new path
|
|
57
59
|
```
|
|
58
60
|
|
|
59
61
|
### Ruby Gem
|
|
@@ -286,7 +288,7 @@ yerba sort-keys "data/**/videos.yml" "[]" "id,title,speakers"
|
|
|
286
288
|
|
|
287
289
|
### `quote-style`
|
|
288
290
|
|
|
289
|
-
Enforce a consistent quote style across keys and/or values
|
|
291
|
+
Enforce a consistent quote style across keys and/or values:
|
|
290
292
|
|
|
291
293
|
```bash
|
|
292
294
|
yerba quote-style config.yml --values double
|
|
@@ -301,6 +303,36 @@ yerba quote-style config.yml "[].speakers" --values plain
|
|
|
301
303
|
yerba quote-style "data/**/*.yml" --keys plain --values double
|
|
302
304
|
```
|
|
303
305
|
|
|
306
|
+
Use block scalar styles to enforce multiline formatting on specific fields:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
yerba quote-style videos.yml "[].description" --values literal
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Key styles** (`--keys`):
|
|
313
|
+
|
|
314
|
+
| Style | Symbol | Example |
|
|
315
|
+
|-------|--------|---------|
|
|
316
|
+
| `plain` | — | `host: value` |
|
|
317
|
+
| `single` | `'` | `'host': value` |
|
|
318
|
+
| `double` | `"` | `"host": value` |
|
|
319
|
+
|
|
320
|
+
**Value styles** (`--values`):
|
|
321
|
+
|
|
322
|
+
| Style | Symbol | Example | Behavior |
|
|
323
|
+
|-------|--------|---------|----------|
|
|
324
|
+
| `plain` | — | `host: localhost` | Unquoted |
|
|
325
|
+
| `single` | `'` | `host: 'localhost'` | Single-quoted |
|
|
326
|
+
| `double` | `"` | `host: "localhost"` | Double-quoted, supports `\n` escapes |
|
|
327
|
+
| `literal` | `\|-` | Preserves newlines | Strip trailing newline |
|
|
328
|
+
| `literal-clip` | `\|` | Preserves newlines | Keep one trailing newline |
|
|
329
|
+
| `literal-keep` | `\|+` | Preserves newlines | Keep all trailing newlines |
|
|
330
|
+
| `folded` | `>-` | Folds newlines to spaces | Strip trailing newline |
|
|
331
|
+
| `folded-clip` | `>` | Folds newlines to spaces | Keep one trailing newline |
|
|
332
|
+
| `folded-keep` | `>+` | Folds newlines to spaces | Keep all trailing newlines |
|
|
333
|
+
|
|
334
|
+
Block scalars are only converted when scoped to a specific selector. An unscoped `--values double` will not touch existing block scalars.
|
|
335
|
+
|
|
304
336
|
### `blank-lines`
|
|
305
337
|
|
|
306
338
|
Enforce a consistent number of blank lines between sequence entries:
|
|
@@ -311,6 +343,16 @@ yerba blank-lines videos.yml "[]" 1
|
|
|
311
343
|
yerba blank-lines config.yml "tags" 0
|
|
312
344
|
```
|
|
313
345
|
|
|
346
|
+
### `directives`
|
|
347
|
+
|
|
348
|
+
Add or remove the document start marker (`---`):
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
yerba directives config.yml --ensure
|
|
352
|
+
yerba directives config.yml --remove
|
|
353
|
+
yerba directives "data/**/*.yml" --ensure
|
|
354
|
+
```
|
|
355
|
+
|
|
314
356
|
### `selectors`
|
|
315
357
|
|
|
316
358
|
Show all valid selectors for a YAML file. Useful for discovering the structure of a file and knowing which selectors you can use with other commands:
|
|
@@ -425,6 +467,7 @@ Available pipeline steps:
|
|
|
425
467
|
- `delete` Remove a key (supports conditions)
|
|
426
468
|
- `rename` Rename a key
|
|
427
469
|
- `remove` Remove an item from a sequence
|
|
470
|
+
- `directives` Add or remove the document start marker (`---`)
|
|
428
471
|
- `get` Read a value and store it as a variable for subsequent steps
|
|
429
472
|
|
|
430
473
|
This makes it easy to enforce project-wide YAML conventions in CI:
|
|
@@ -514,7 +557,44 @@ tags = document["tags"]
|
|
|
514
557
|
tags << "yaml"
|
|
515
558
|
tags << { name: "Rust", version: "1.80" }
|
|
516
559
|
tags.remove("obsolete")
|
|
517
|
-
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### Sorting
|
|
563
|
+
|
|
564
|
+
Sort sequences in place. Works on both the document and sequence level:
|
|
565
|
+
|
|
566
|
+
```ruby
|
|
567
|
+
document.sort(by: :name)
|
|
568
|
+
document.sort(by: :name, order: :desc)
|
|
569
|
+
document.sort(by: :name, order: ["Charlie", "Bob", "Alice"])
|
|
570
|
+
document.sort("tags")
|
|
571
|
+
document.sort("tags", order: :desc)
|
|
572
|
+
document.sort("tags", order: ["rust", "ruby", "go"])
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
The `by:` option accepts symbols, strings, or dot-prefixed strings (`:name`, `"name"`, `".name"`).
|
|
576
|
+
|
|
577
|
+
### Querying
|
|
578
|
+
|
|
579
|
+
Find and filter items in sequences with `find_by`, `where`, and `pluck`:
|
|
580
|
+
|
|
581
|
+
```ruby
|
|
582
|
+
document.find_by(name: "Alice")
|
|
583
|
+
document.where(role: "admin")
|
|
584
|
+
document.pluck(:name)
|
|
585
|
+
|
|
586
|
+
document.find_by(speakers: { name: "Alice" })
|
|
587
|
+
document.where(tags: ["ruby"])
|
|
588
|
+
document.find_by("database.host": "localhost")
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
These methods work on `Document` (delegates to root), `Sequence`, and `Collection` (searches across files):
|
|
592
|
+
|
|
593
|
+
```ruby
|
|
594
|
+
collection = Yerba.files("data/**/*.yml")
|
|
595
|
+
collection.find_by(name: "Alice")
|
|
596
|
+
collection.where(kind: "talk")
|
|
597
|
+
collection.pluck(:name)
|
|
518
598
|
```
|
|
519
599
|
|
|
520
600
|
### Quote Style Control
|
|
@@ -523,7 +603,7 @@ Read and set the quote style on individual scalars:
|
|
|
523
603
|
|
|
524
604
|
```ruby
|
|
525
605
|
scalar = document["database.host"]
|
|
526
|
-
scalar.quote_style
|
|
606
|
+
scalar.quote_style # => :double
|
|
527
607
|
scalar.quote_style = :single
|
|
528
608
|
```
|
|
529
609
|
|
|
@@ -547,6 +627,10 @@ collection.each do |document|
|
|
|
547
627
|
puts document.get("[0].title")
|
|
548
628
|
end
|
|
549
629
|
|
|
630
|
+
collection.find_by(name: "Alice")
|
|
631
|
+
collection.where(kind: "talk")
|
|
632
|
+
collection.pluck(:name)
|
|
633
|
+
|
|
550
634
|
collection.apply! do |document|
|
|
551
635
|
document.set("status", "published")
|
|
552
636
|
end
|
|
@@ -572,10 +656,9 @@ After checking out the repo, run `bundle install` to install Ruby dependencies,
|
|
|
572
656
|
|
|
573
657
|
### Building from source
|
|
574
658
|
|
|
575
|
-
The Rust core is in the `rust/` directory:
|
|
659
|
+
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:
|
|
576
660
|
|
|
577
661
|
```bash
|
|
578
|
-
cd rust
|
|
579
662
|
cargo build
|
|
580
663
|
cargo test
|
|
581
664
|
```
|
|
@@ -591,7 +674,6 @@ cargo run -- get config.yml "database.host"
|
|
|
591
674
|
Or build a release binary:
|
|
592
675
|
|
|
593
676
|
```bash
|
|
594
|
-
cd rust
|
|
595
677
|
cargo build --release
|
|
596
678
|
./target/release/yerba --help
|
|
597
679
|
```
|
data/ext/yerba/extconf.rb
CHANGED
|
@@ -44,22 +44,41 @@ if cross_compiling && target_platform.nil?
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
workspace_target_dir = File.join(root_dir, "target")
|
|
48
|
+
crate_target_dir = File.join(rust_dir, "target")
|
|
49
|
+
|
|
47
50
|
if target_platform
|
|
48
51
|
puts "yerba: Cross-compiling Rust for target: #{target_platform}"
|
|
49
52
|
system("rustup target add #{target_platform}") || warn("yerba: Failed to add Rust target #{target_platform}")
|
|
50
53
|
|
|
51
54
|
cargo_args = "--release --target #{target_platform}"
|
|
52
|
-
lib_dir =
|
|
55
|
+
lib_dir = [workspace_target_dir, crate_target_dir]
|
|
56
|
+
.map { |dir| File.join(dir, target_platform, "release") }
|
|
57
|
+
.find { |dir| Dir.exist?(dir) } || File.join(crate_target_dir, target_platform, "release")
|
|
53
58
|
else
|
|
54
59
|
puts "yerba: Compiling Rust library for native platform..."
|
|
60
|
+
|
|
55
61
|
cargo_args = "--release"
|
|
56
|
-
|
|
62
|
+
|
|
63
|
+
lib_dir = [workspace_target_dir, crate_target_dir]
|
|
64
|
+
.map { |dir| File.join(dir, "release") }
|
|
65
|
+
.find { |dir| Dir.exist?(dir) } || File.join(crate_target_dir, "release")
|
|
57
66
|
end
|
|
58
67
|
|
|
59
|
-
unless system("cd #{
|
|
68
|
+
unless system("cd #{root_dir} && cargo build #{cargo_args}")
|
|
60
69
|
abort "ERROR: Failed to compile yerba from Rust source."
|
|
61
70
|
end
|
|
62
71
|
|
|
72
|
+
lib_dir = if target_platform
|
|
73
|
+
[workspace_target_dir, crate_target_dir]
|
|
74
|
+
.map { |dir| File.join(dir, target_platform, "release") }
|
|
75
|
+
.find { |dir| Dir.exist?(dir) } || lib_dir
|
|
76
|
+
else
|
|
77
|
+
[workspace_target_dir, crate_target_dir]
|
|
78
|
+
.map { |dir| File.join(dir, "release") }
|
|
79
|
+
.find { |dir| Dir.exist?(dir) } || lib_dir
|
|
80
|
+
end
|
|
81
|
+
|
|
63
82
|
if target_platform
|
|
64
83
|
platform_key = ENV.fetch("RCD_PLATFORM", "")
|
|
65
84
|
else
|
data/ext/yerba/include/yerba.h
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
#ifndef YERBA_H
|
|
8
8
|
#define YERBA_H
|
|
9
9
|
|
|
10
|
-
typedef enum
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
10
|
+
typedef enum NodeType {
|
|
11
|
+
NODE_TYPE_SCALAR = 0,
|
|
12
|
+
NODE_TYPE_MAP = 1,
|
|
13
|
+
NODE_TYPE_SEQUENCE = 2,
|
|
14
|
+
NODE_TYPE_NOT_FOUND = 3,
|
|
15
|
+
} NodeType;
|
|
16
16
|
|
|
17
17
|
typedef enum YerbaValueType {
|
|
18
18
|
YERBA_VALUE_TYPE_NULL = 0,
|
|
@@ -50,7 +50,7 @@ typedef struct YerbaLocation {
|
|
|
50
50
|
|
|
51
51
|
typedef struct YerbaGetResult {
|
|
52
52
|
bool is_list;
|
|
53
|
-
enum
|
|
53
|
+
enum NodeType node_type;
|
|
54
54
|
struct YerbaTypedValue single;
|
|
55
55
|
struct YerbaTypedList list;
|
|
56
56
|
struct YerbaLocation location;
|
|
@@ -82,11 +82,11 @@ char *yerba_document_get_value(const struct Document *document, const char *path
|
|
|
82
82
|
*/
|
|
83
83
|
char *yerba_document_get_values(const struct Document *document, const char *path);
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
char *yerba_document_get_quote_style(const struct Document *document, const char *path);
|
|
86
86
|
|
|
87
87
|
struct YerbaResult yerba_document_set_quote_style(struct Document *document,
|
|
88
88
|
const char *path,
|
|
89
|
-
|
|
89
|
+
const char *style);
|
|
90
90
|
|
|
91
91
|
bool yerba_document_evaluate_condition(const struct Document *document,
|
|
92
92
|
const char *parent_path,
|
|
@@ -129,6 +129,11 @@ struct YerbaResult yerba_document_remove_at(struct Document *document,
|
|
|
129
129
|
const char *path,
|
|
130
130
|
uintptr_t index);
|
|
131
131
|
|
|
132
|
+
struct YerbaResult yerba_document_move_item(struct Document *document,
|
|
133
|
+
const char *path,
|
|
134
|
+
uintptr_t from,
|
|
135
|
+
uintptr_t to);
|
|
136
|
+
|
|
132
137
|
struct YerbaResult yerba_document_rename(struct Document *document,
|
|
133
138
|
const char *source,
|
|
134
139
|
const char *dest);
|
|
@@ -138,6 +143,11 @@ struct YerbaResult yerba_document_sort(struct Document *document,
|
|
|
138
143
|
const char *by,
|
|
139
144
|
bool case_sensitive);
|
|
140
145
|
|
|
146
|
+
struct YerbaResult yerba_document_reorder(struct Document *document,
|
|
147
|
+
const char *path,
|
|
148
|
+
const char *by,
|
|
149
|
+
const char *order_csv);
|
|
150
|
+
|
|
141
151
|
struct YerbaResult yerba_document_sort_keys(struct Document *document,
|
|
142
152
|
const char *path,
|
|
143
153
|
const char *order);
|
data/ext/yerba/yerba.c
CHANGED
|
@@ -230,7 +230,7 @@ static VALUE document_bracket(VALUE self, VALUE path) {
|
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
switch (result.node_type) {
|
|
233
|
-
case
|
|
233
|
+
case NODE_TYPE_SCALAR: {
|
|
234
234
|
VALUE klass = rb_path2class("Yerba::Scalar");
|
|
235
235
|
VALUE value = typed_value_to_ruby(result.single);
|
|
236
236
|
yerba_get_result_free(result);
|
|
@@ -240,7 +240,7 @@ static VALUE document_bracket(VALUE self, VALUE path) {
|
|
|
240
240
|
return instance;
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
case
|
|
243
|
+
case NODE_TYPE_MAP: {
|
|
244
244
|
yerba_get_result_free(result);
|
|
245
245
|
VALUE klass = rb_path2class("Yerba::Map");
|
|
246
246
|
|
|
@@ -249,7 +249,7 @@ static VALUE document_bracket(VALUE self, VALUE path) {
|
|
|
249
249
|
return instance;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
case
|
|
252
|
+
case NODE_TYPE_SEQUENCE: {
|
|
253
253
|
yerba_get_result_free(result);
|
|
254
254
|
VALUE klass = rb_path2class("Yerba::Sequence");
|
|
255
255
|
|
|
@@ -298,35 +298,35 @@ static VALUE document_get_values(VALUE self, VALUE path) {
|
|
|
298
298
|
return rb_funcall(rb_path2class("JSON"), rb_intern("parse"), 1, json_string);
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
-
/* document.get_quote_style(path) → :plain, :single, :double, or nil */
|
|
301
|
+
/* document.get_quote_style(path) → :plain, :single, :double, :literal, etc. or nil */
|
|
302
302
|
static VALUE document_get_quote_style(VALUE self, VALUE path) {
|
|
303
303
|
struct Document *document = get_document(self);
|
|
304
|
-
|
|
304
|
+
char *style = yerba_document_get_quote_style(document, StringValueCStr(path));
|
|
305
305
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
306
|
+
if (style == NULL) return Qnil;
|
|
307
|
+
|
|
308
|
+
VALUE symbol = ID2SYM(rb_intern(style));
|
|
309
|
+
|
|
310
|
+
yerba_string_free(style);
|
|
311
|
+
|
|
312
|
+
return symbol;
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
/* document.set_quote_style(path, style) */
|
|
315
316
|
static VALUE document_set_quote_style(VALUE self, VALUE path, VALUE style) {
|
|
316
317
|
struct Document *document = get_document(self);
|
|
317
318
|
|
|
318
|
-
|
|
319
|
+
const char *style_string;
|
|
320
|
+
|
|
319
321
|
if (RB_TYPE_P(style, T_SYMBOL)) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
else if (style_id == rb_intern("double")) style_int = 2;
|
|
324
|
-
else rb_raise(rb_eError, "Invalid quote style (use :plain, :single, or :double)");
|
|
322
|
+
style_string = rb_id2name(SYM2ID(style));
|
|
323
|
+
} else if (RB_TYPE_P(style, T_STRING)) {
|
|
324
|
+
style_string = StringValueCStr(style);
|
|
325
325
|
} else {
|
|
326
|
-
|
|
326
|
+
rb_raise(rb_eError, "Invalid quote style (expected Symbol or String)");
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
YerbaResult result = yerba_document_set_quote_style(document, StringValueCStr(path),
|
|
329
|
+
YerbaResult result = yerba_document_set_quote_style(document, StringValueCStr(path), style_string);
|
|
330
330
|
|
|
331
331
|
check_result(result);
|
|
332
332
|
|
|
@@ -533,24 +533,83 @@ static VALUE document_rename(VALUE self, VALUE source, VALUE destination) {
|
|
|
533
533
|
return self;
|
|
534
534
|
}
|
|
535
535
|
|
|
536
|
-
/* document.sort(path, by: nil, case_sensitive: false) */
|
|
536
|
+
/* document.sort(path = "", by: nil, order: nil, case_sensitive: false) */
|
|
537
537
|
static VALUE document_sort(int argc, VALUE *argv, VALUE self) {
|
|
538
538
|
VALUE path, opts;
|
|
539
|
-
rb_scan_args(argc, argv, "
|
|
539
|
+
rb_scan_args(argc, argv, "01:", &path, &opts);
|
|
540
|
+
|
|
541
|
+
if (NIL_P(path)) path = rb_str_new_cstr("");
|
|
540
542
|
|
|
541
543
|
const char *by = NULL;
|
|
542
544
|
bool case_sensitive = false;
|
|
545
|
+
VALUE v_order = Qnil;
|
|
543
546
|
|
|
544
547
|
if (!NIL_P(opts)) {
|
|
545
548
|
VALUE v_by = rb_hash_aref(opts, ID2SYM(rb_intern("by")));
|
|
549
|
+
v_order = rb_hash_aref(opts, ID2SYM(rb_intern("order")));
|
|
546
550
|
VALUE v_case_sensitive = rb_hash_aref(opts, ID2SYM(rb_intern("case_sensitive")));
|
|
547
551
|
|
|
548
|
-
if (
|
|
549
|
-
|
|
552
|
+
if (SYMBOL_P(v_by)) {
|
|
553
|
+
VALUE by_string = rb_sym2str(v_by);
|
|
554
|
+
by = StringValueCStr(by_string);
|
|
555
|
+
} else if (!NIL_P(v_by)) {
|
|
556
|
+
by = StringValueCStr(v_by);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (RTEST(v_case_sensitive)) {
|
|
560
|
+
case_sensitive = true;
|
|
561
|
+
}
|
|
550
562
|
}
|
|
551
563
|
|
|
552
564
|
struct Document *document = get_document(self);
|
|
553
|
-
|
|
565
|
+
const char *path_string = StringValueCStr(path);
|
|
566
|
+
|
|
567
|
+
if (RB_TYPE_P(v_order, T_ARRAY)) {
|
|
568
|
+
VALUE order_csv = rb_ary_join(v_order, rb_str_new_cstr(","));
|
|
569
|
+
const char *order_string = StringValueCStr(order_csv);
|
|
570
|
+
const char *reorder_path = StringValueCStr(path);
|
|
571
|
+
const char *reorder_by;
|
|
572
|
+
|
|
573
|
+
if (by) {
|
|
574
|
+
VALUE reorder_by_value = rb_hash_aref(opts, ID2SYM(rb_intern("by")));
|
|
575
|
+
|
|
576
|
+
if (SYMBOL_P(reorder_by_value)) {
|
|
577
|
+
reorder_by_value = rb_sym2str(reorder_by_value);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
reorder_by = StringValueCStr(reorder_by_value);
|
|
581
|
+
} else {
|
|
582
|
+
reorder_by = ".";
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
YerbaResult result = yerba_document_reorder(document, reorder_path, reorder_by, order_string);
|
|
586
|
+
check_result(result);
|
|
587
|
+
|
|
588
|
+
return self;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const char *order = NULL;
|
|
592
|
+
|
|
593
|
+
if (SYMBOL_P(v_order)) {
|
|
594
|
+
VALUE order_string = rb_sym2str(v_order);
|
|
595
|
+
order = StringValueCStr(order_string);
|
|
596
|
+
} else if (!NIL_P(v_order)) {
|
|
597
|
+
order = StringValueCStr(v_order);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
VALUE by_with_order = Qnil;
|
|
601
|
+
|
|
602
|
+
if (order && strcmp(order, "desc") == 0) {
|
|
603
|
+
if (by) {
|
|
604
|
+
by_with_order = rb_sprintf("%s:desc", by);
|
|
605
|
+
} else {
|
|
606
|
+
by_with_order = rb_str_new_cstr(":desc");
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
by = StringValueCStr(by_with_order);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
YerbaResult result = yerba_document_sort(document, path_string, by, case_sensitive);
|
|
554
613
|
|
|
555
614
|
check_result(result);
|
|
556
615
|
|
data/lib/yerba/collection.rb
CHANGED
|
@@ -20,6 +20,41 @@ module Yerba
|
|
|
20
20
|
self.class.find(@glob, path, condition: condition, select: select)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
def find_by(...)
|
|
24
|
+
each do |document|
|
|
25
|
+
next unless document.sequence?
|
|
26
|
+
|
|
27
|
+
result = document.root.find_by(...)
|
|
28
|
+
return result if result
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def where(...)
|
|
35
|
+
results = []
|
|
36
|
+
|
|
37
|
+
each do |document|
|
|
38
|
+
next unless document.sequence?
|
|
39
|
+
|
|
40
|
+
results.concat(document.root.where(...))
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
results
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def pluck(...)
|
|
47
|
+
results = []
|
|
48
|
+
|
|
49
|
+
each do |document|
|
|
50
|
+
next unless document.sequence?
|
|
51
|
+
|
|
52
|
+
results.concat(document.root.pluck(...))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
results
|
|
56
|
+
end
|
|
57
|
+
|
|
23
58
|
def apply!
|
|
24
59
|
each do |document|
|
|
25
60
|
yield document
|
data/lib/yerba/document.rb
CHANGED
|
@@ -48,6 +48,22 @@ module Yerba
|
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
+
def find_by(...)
|
|
52
|
+
root.find_by(...)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def where(...)
|
|
56
|
+
root.where(...)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def pluck(...)
|
|
60
|
+
root.pluck(...)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def <<(item)
|
|
64
|
+
root << item
|
|
65
|
+
end
|
|
66
|
+
|
|
51
67
|
def inspect
|
|
52
68
|
if path
|
|
53
69
|
"#<Yerba::Document path=#{path.inspect}>"
|