yerba 0.1.1 → 0.2.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +492 -15
  3. data/ext/yerba/extconf.rb +87 -30
  4. data/ext/yerba/include/yerba.h +168 -0
  5. data/ext/yerba/yerba.c +752 -0
  6. data/lib/yerba/collection.rb +31 -0
  7. data/lib/yerba/document.rb +59 -0
  8. data/lib/yerba/formatting.rb +18 -0
  9. data/lib/yerba/location.rb +5 -0
  10. data/lib/yerba/map.rb +166 -0
  11. data/lib/yerba/scalar.rb +85 -0
  12. data/lib/yerba/sequence.rb +182 -0
  13. data/lib/yerba/version.rb +1 -1
  14. data/lib/yerba.rb +30 -4
  15. data/rust/Cargo.lock +378 -2
  16. data/rust/Cargo.toml +5 -1
  17. data/rust/build.rs +11 -0
  18. data/rust/cbindgen.toml +27 -0
  19. data/rust/src/commands/apply.rs +5 -0
  20. data/rust/src/commands/blank_lines.rs +58 -0
  21. data/rust/src/commands/check.rs +5 -0
  22. data/rust/src/commands/delete.rs +35 -0
  23. data/rust/src/commands/get.rs +194 -0
  24. data/rust/src/commands/init.rs +89 -0
  25. data/rust/src/commands/insert.rs +106 -0
  26. data/rust/src/commands/mate.rs +55 -0
  27. data/rust/src/commands/mod.rs +349 -0
  28. data/rust/src/commands/move_item.rs +54 -0
  29. data/rust/src/commands/move_key.rs +87 -0
  30. data/rust/src/commands/quote_style.rs +62 -0
  31. data/rust/src/commands/remove.rs +35 -0
  32. data/rust/src/commands/rename.rs +37 -0
  33. data/rust/src/commands/set.rs +59 -0
  34. data/rust/src/commands/sort.rs +52 -0
  35. data/rust/src/commands/sort_keys.rs +62 -0
  36. data/rust/src/commands/version.rs +8 -0
  37. data/rust/src/document.rs +798 -340
  38. data/rust/src/error.rs +0 -5
  39. data/rust/src/ffi.rs +991 -0
  40. data/rust/src/json.rs +49 -90
  41. data/rust/src/lib.rs +9 -2
  42. data/rust/src/main.rs +55 -839
  43. data/rust/src/selector.rs +241 -0
  44. data/rust/src/syntax.rs +97 -21
  45. data/rust/src/yaml_writer.rs +89 -0
  46. data/rust/src/yerbafile.rs +34 -122
  47. data/yerba.gemspec +4 -0
  48. metadata +33 -1
@@ -1,6 +1,5 @@
1
1
  use rayon::prelude::*;
2
2
  use serde::Deserialize;
3
- use std::collections::HashMap;
4
3
  use std::fs;
5
4
  use std::path::{Path, PathBuf};
6
5
 
@@ -22,7 +21,6 @@ pub struct Rule {
22
21
 
23
22
  #[derive(Debug, Clone)]
24
23
  pub enum PipelineStep {
25
- Get(GetConfig),
26
24
  SortKeys(SortKeysConfig),
27
25
  QuoteStyle(QuoteStyleConfig),
28
26
  Set(SetConfig),
@@ -31,28 +29,24 @@ pub enum PipelineStep {
31
29
  Rename(RenameConfig),
32
30
  Remove(RemoveConfig),
33
31
  BlankLines(BlankLinesConfig),
32
+ Sort(SortConfig),
34
33
  }
35
34
 
36
35
  #[derive(Debug, Clone, Deserialize)]
37
- pub struct BlankLinesConfig {
36
+ pub struct SortConfig {
38
37
  #[serde(default)]
39
38
  pub path: Option<String>,
40
- pub count: usize,
39
+ #[serde(default)]
40
+ pub by: Option<String>,
41
+ #[serde(default)]
42
+ pub case_sensitive: bool,
41
43
  }
42
44
 
43
45
  #[derive(Debug, Clone, Deserialize)]
44
- pub struct GetConfig {
45
- pub path: String,
46
- #[serde(rename = "as")]
47
- pub as_name: String,
46
+ pub struct BlankLinesConfig {
48
47
  #[serde(default)]
49
- pub file: Option<String>,
50
- }
51
-
52
- #[derive(Debug, Clone)]
53
- pub enum Variable {
54
- Single(String),
55
- List(Vec<String>),
48
+ pub path: Option<String>,
49
+ pub count: usize,
56
50
  }
57
51
 
58
52
  #[derive(Debug, Clone, Deserialize)]
@@ -78,11 +72,6 @@ impl<'de> Deserialize<'de> for PipelineStep {
78
72
  {
79
73
  let mapping = serde_yaml::Mapping::deserialize(deserializer)?;
80
74
 
81
- if let Some(value) = mapping.get(serde_yaml::Value::String("get".to_string())) {
82
- let config: GetConfig = serde_yaml::from_value(value.clone()).map_err(serde::de::Error::custom)?;
83
- return Ok(PipelineStep::Get(config));
84
- }
85
-
86
75
  if let Some(value) = mapping.get(serde_yaml::Value::String("sort_keys".to_string())) {
87
76
  let config: SortKeysConfig = serde_yaml::from_value(value.clone()).map_err(serde::de::Error::custom)?;
88
77
  return Ok(PipelineStep::SortKeys(config));
@@ -123,8 +112,13 @@ impl<'de> Deserialize<'de> for PipelineStep {
123
112
  return Ok(PipelineStep::BlankLines(config));
124
113
  }
125
114
 
115
+ if let Some(value) = mapping.get(serde_yaml::Value::String("sort".to_string())) {
116
+ let config: SortConfig = serde_yaml::from_value(value.clone()).map_err(serde::de::Error::custom)?;
117
+ return Ok(PipelineStep::Sort(config));
118
+ }
119
+
126
120
  Err(serde::de::Error::custom(
127
- "unknown pipeline step: expected get, sort_keys, quote_style, set, insert, delete, rename, remove, or blank_lines",
121
+ "unknown pipeline step: expected sort_keys, quote_style, set, insert, delete, rename, remove, blank_lines, or sort",
128
122
  ))
129
123
  }
130
124
  }
@@ -322,10 +316,9 @@ impl Yerbafile {
322
316
 
323
317
  let original = document.to_string();
324
318
  let base_path = rule.path.as_deref();
325
- let mut variables: HashMap<String, Variable> = HashMap::new();
326
319
 
327
320
  for step in &rule.pipeline {
328
- if let Err(error) = execute_step(&mut document, step, base_path, &mut variables) {
321
+ if let Err(error) = execute_step(&mut document, step, base_path) {
329
322
  return RuleResult {
330
323
  file: file.to_string(),
331
324
  changed: false,
@@ -355,46 +348,8 @@ impl Yerbafile {
355
348
  }
356
349
  }
357
350
 
358
- fn execute_step(
359
- document: &mut Document,
360
- step: &PipelineStep,
361
- base_path: Option<&str>,
362
- variables: &mut HashMap<String, Variable>,
363
- ) -> Result<(), YerbaError> {
351
+ fn execute_step(document: &mut Document, step: &PipelineStep, base_path: Option<&str>) -> Result<(), YerbaError> {
364
352
  match step {
365
- PipelineStep::Get(config) => {
366
- let full_path = resolve_step_path(base_path, Some(&config.path));
367
-
368
- if let Some(file_pattern) = &config.file {
369
- let mut all_values = Vec::new();
370
-
371
- let files =
372
- glob::glob(file_pattern).map_err(|error| YerbaError::ParseError(format!("invalid glob: {}", error)))?;
373
-
374
- for entry in files.flatten() {
375
- let external_document = Document::parse_file(&entry)?;
376
- all_values.extend(external_document.get_all(&config.path));
377
- }
378
-
379
- if all_values.len() == 1 && !config.path.contains('[') {
380
- variables.insert(config.as_name.clone(), Variable::Single(all_values.remove(0)));
381
- } else {
382
- variables.insert(config.as_name.clone(), Variable::List(all_values));
383
- }
384
- } else if config.path.contains('[') {
385
- let values = document.get_all(&full_path);
386
-
387
- variables.insert(config.as_name.clone(), Variable::List(values));
388
- } else {
389
- let value = document
390
- .get(&full_path)
391
- .ok_or_else(|| YerbaError::PathNotFound(full_path.clone()))?;
392
- variables.insert(config.as_name.clone(), Variable::Single(value));
393
- }
394
-
395
- Ok(())
396
- }
397
-
398
353
  PipelineStep::QuoteStyle(config) => {
399
354
  let dot_path = config.path.as_deref();
400
355
 
@@ -420,44 +375,39 @@ fn execute_step(
420
375
 
421
376
  PipelineStep::Set(config) => {
422
377
  let full_path = resolve_step_path(base_path, Some(&config.path));
423
- let resolved_value = resolve_template(&config.value, document, base_path, variables)?;
424
378
 
425
379
  if let Some(condition) = &config.condition {
426
- let resolved_condition = resolve_template(condition, document, base_path, variables)?;
427
380
  let parent_path = full_path.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
428
381
 
429
- if !document.evaluate_condition(parent_path, &resolved_condition) {
382
+ if !document.evaluate_condition(parent_path, condition) {
430
383
  return Ok(());
431
384
  }
432
385
  }
433
386
 
434
- document.set(&full_path, &resolved_value)
387
+ document.set(&full_path, &config.value)
435
388
  }
436
389
 
437
390
  PipelineStep::Insert(config) => {
438
391
  let full_path = resolve_step_path(base_path, Some(&config.path));
439
- let resolved_value = resolve_template(&config.value, document, base_path, variables)?;
440
392
 
441
393
  if let Some(condition) = &config.condition {
442
- let resolved_condition = resolve_template(condition, document, base_path, variables)?;
443
394
  let parent_path = full_path.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
444
395
 
445
- if !document.evaluate_condition(parent_path, &resolved_condition) {
396
+ if !document.evaluate_condition(parent_path, condition) {
446
397
  return Ok(());
447
398
  }
448
399
  }
449
400
 
450
- document.insert_into(&full_path, &resolved_value, crate::InsertPosition::Last)
401
+ document.insert_into(&full_path, &config.value, crate::InsertPosition::Last)
451
402
  }
452
403
 
453
404
  PipelineStep::Delete(config) => {
454
405
  let full_path = resolve_step_path(base_path, Some(&config.path));
455
406
 
456
407
  if let Some(condition) = &config.condition {
457
- let resolved_condition = resolve_template(condition, document, base_path, variables)?;
458
408
  let parent_path = full_path.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
459
409
 
460
- if !document.evaluate_condition(parent_path, &resolved_condition) {
410
+ if !document.evaluate_condition(parent_path, condition) {
461
411
  return Ok(());
462
412
  }
463
413
  }
@@ -469,10 +419,9 @@ fn execute_step(
469
419
  let full_path = resolve_step_path(base_path, Some(&config.from));
470
420
 
471
421
  if let Some(condition) = &config.condition {
472
- let resolved_condition = resolve_template(condition, document, base_path, variables)?;
473
422
  let parent_path = full_path.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
474
423
 
475
- if !document.evaluate_condition(parent_path, &resolved_condition) {
424
+ if !document.evaluate_condition(parent_path, condition) {
476
425
  return Ok(());
477
426
  }
478
427
  }
@@ -482,18 +431,16 @@ fn execute_step(
482
431
 
483
432
  PipelineStep::Remove(config) => {
484
433
  let full_path = resolve_step_path(base_path, Some(&config.path));
485
- let resolved_value = resolve_template(&config.value, document, base_path, variables)?;
486
434
 
487
435
  if let Some(condition) = &config.condition {
488
- let resolved_condition = resolve_template(condition, document, base_path, variables)?;
489
436
  let parent_path = full_path.rsplit_once('.').map(|(parent, _)| parent).unwrap_or("");
490
437
 
491
- if !document.evaluate_condition(parent_path, &resolved_condition) {
438
+ if !document.evaluate_condition(parent_path, condition) {
492
439
  return Ok(());
493
440
  }
494
441
  }
495
442
 
496
- document.remove(&full_path, &resolved_value)
443
+ document.remove(&full_path, &config.value)
497
444
  }
498
445
 
499
446
  PipelineStep::BlankLines(config) => {
@@ -501,53 +448,18 @@ fn execute_step(
501
448
 
502
449
  document.enforce_blank_lines(&full_path, config.count)
503
450
  }
504
- }
505
- }
506
-
507
- pub fn resolve_template(
508
- template: &str,
509
- document: &Document,
510
- base_path: Option<&str>,
511
- variables: &HashMap<String, Variable>,
512
- ) -> Result<String, YerbaError> {
513
- if !template.contains("${") {
514
- return Ok(template.to_string());
515
- }
516
-
517
- let mut result = String::new();
518
- let mut rest = template;
519
-
520
- while let Some(start) = rest.find("${") {
521
- result.push_str(&rest[..start]);
522
451
 
523
- let after_dollar = &rest[start + 2..];
524
-
525
- let end = after_dollar
526
- .find('}')
527
- .ok_or_else(|| YerbaError::ParseError("unclosed ${ in template".to_string()))?;
528
-
529
- let reference = &after_dollar[..end];
530
-
531
- let resolved = if let Some(variable) = variables.get(reference) {
532
- match variable {
533
- Variable::Single(value) => value.clone(),
534
- Variable::List(values) => values.join(", "),
535
- }
536
- } else {
537
- let full_path = resolve_step_path(base_path, Some(reference));
538
-
539
- document
540
- .get(&full_path)
541
- .ok_or_else(|| YerbaError::ReferenceNotFound(reference.to_string()))?
542
- };
452
+ PipelineStep::Sort(config) => {
453
+ let full_path = resolve_step_path(base_path, config.path.as_deref());
454
+ let sort_fields = config
455
+ .by
456
+ .as_deref()
457
+ .map(crate::SortField::parse_list)
458
+ .unwrap_or_default();
543
459
 
544
- result.push_str(&resolved);
545
- rest = &after_dollar[end + 1..];
460
+ document.sort_items(&full_path, &sort_fields, config.case_sensitive)
461
+ }
546
462
  }
547
-
548
- result.push_str(rest);
549
-
550
- Ok(result)
551
463
  }
552
464
 
553
465
  fn resolve_step_path(base_path: Option<&str>, step_path: Option<&str>) -> String {
data/yerba.gemspec CHANGED
@@ -28,6 +28,10 @@ Gem::Specification.new do |spec|
28
28
  "sig/**/*.rbs",
29
29
  "exe/yerba",
30
30
  "ext/yerba/extconf.rb",
31
+ "ext/yerba/yerba.c",
32
+ "ext/yerba/include/**/*.h",
33
+ "rust/build.rs",
34
+ "rust/cbindgen.toml",
31
35
  "rust/Cargo.toml",
32
36
  "rust/Cargo.lock",
33
37
  "rust/src/**/*.rs",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yerba
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marco Roth
@@ -23,18 +23,50 @@ files:
23
23
  - README.md
24
24
  - exe/yerba
25
25
  - ext/yerba/extconf.rb
26
+ - ext/yerba/include/yerba.h
27
+ - ext/yerba/yerba.c
26
28
  - lib/yerba.rb
29
+ - lib/yerba/collection.rb
30
+ - lib/yerba/document.rb
31
+ - lib/yerba/formatting.rb
32
+ - lib/yerba/location.rb
33
+ - lib/yerba/map.rb
34
+ - lib/yerba/scalar.rb
35
+ - lib/yerba/sequence.rb
27
36
  - lib/yerba/version.rb
28
37
  - rust/Cargo.lock
29
38
  - rust/Cargo.toml
39
+ - rust/build.rs
40
+ - rust/cbindgen.toml
30
41
  - rust/rustfmt.toml
42
+ - rust/src/commands/apply.rs
43
+ - rust/src/commands/blank_lines.rs
44
+ - rust/src/commands/check.rs
45
+ - rust/src/commands/delete.rs
46
+ - rust/src/commands/get.rs
47
+ - rust/src/commands/init.rs
48
+ - rust/src/commands/insert.rs
49
+ - rust/src/commands/mate.rs
50
+ - rust/src/commands/mod.rs
51
+ - rust/src/commands/move_item.rs
52
+ - rust/src/commands/move_key.rs
53
+ - rust/src/commands/quote_style.rs
54
+ - rust/src/commands/remove.rs
55
+ - rust/src/commands/rename.rs
56
+ - rust/src/commands/set.rs
57
+ - rust/src/commands/sort.rs
58
+ - rust/src/commands/sort_keys.rs
59
+ - rust/src/commands/version.rs
31
60
  - rust/src/document.rs
32
61
  - rust/src/error.rs
62
+ - rust/src/ffi.rs
33
63
  - rust/src/json.rs
34
64
  - rust/src/lib.rs
35
65
  - rust/src/main.rs
36
66
  - rust/src/quote_style.rs
67
+ - rust/src/selector.rs
37
68
  - rust/src/syntax.rs
69
+ - rust/src/yaml_writer.rs
38
70
  - rust/src/yerbafile.rs
39
71
  - sig/yerba.rbs
40
72
  - yerba.gemspec