mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-13 22:38:04 +00:00
Added plain assignment
This commit is contained in:
parent
36084a60a9
commit
75044e480c
@ -1,4 +1,10 @@
|
||||
Updates the LHS using the expression on the RHS. Note that the RHS runs against the _original_ LHS value, so that you can evaluate a new value based on the old (e.g. increment).
|
||||
This operator is used to update node values. It can be used in either the:
|
||||
|
||||
### plain form: `=`
|
||||
Which will assign the LHS node values to the RHS node values. The RHS expression is run against the matching nodes in the pipeline.
|
||||
|
||||
### relative form: `|=`
|
||||
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
|
||||
## Examples
|
||||
### Update parent to be the child value
|
||||
Given a sample.yml file of:
|
||||
@ -17,6 +23,23 @@ a:
|
||||
g: foof
|
||||
```
|
||||
|
||||
### Update to be the sibling value
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
b: child
|
||||
b: sibling
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a = .b' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a: sibling
|
||||
b: sibling
|
||||
```
|
||||
|
||||
### Updated multiple paths
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
@ -36,6 +59,24 @@ c: potatoe
|
||||
```
|
||||
|
||||
### Update string value
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
b: apple
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '.a.b = "frog"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a:
|
||||
b: frog
|
||||
```
|
||||
|
||||
### Update string value via |=
|
||||
Note there is no difference between `=` and `|=` when the RHS is a scalar
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
@ -33,7 +33,7 @@ e: true
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq eval '(.. | select(tag == "!!int")) tag = "!!str"' sample.yml
|
||||
yq eval '(.. | select(tag == "!!int")) tag= "!!str"' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
|
7
pkg/yqlib/doc/headers/Assign Operator.md
Normal file
7
pkg/yqlib/doc/headers/Assign Operator.md
Normal file
@ -0,0 +1,7 @@
|
||||
This operator is used to update node values. It can be used in either the:
|
||||
|
||||
### plain form: `=`
|
||||
Which will assign the LHS node values to the RHS node values. The RHS expression is run against the matching nodes in the pipeline.
|
||||
|
||||
### relative form: `|=`
|
||||
This will do a similar thing to the plain form, however, the RHS expression is run against _the LHS nodes_. This is useful for updating values based on old values, e.g. increment.
|
@ -1 +0,0 @@
|
||||
Updates the LHS using the expression on the RHS. Note that the RHS runs against the _original_ LHS value, so that you can evaluate a new value based on the old (e.g. increment).
|
@ -37,8 +37,6 @@ var Union = &OperationType{Type: "UNION", NumArgs: 2, Precedence: 10, Handler: U
|
||||
|
||||
var Assign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignUpdateOperator}
|
||||
|
||||
// TODO: implement this
|
||||
var PlainAssign = &OperationType{Type: "ASSIGN", NumArgs: 2, Precedence: 40, Handler: AssignUpdateOperator}
|
||||
var AssignAttributes = &OperationType{Type: "ASSIGN_ATTRIBUTES", NumArgs: 2, Precedence: 40, Handler: AssignAttributesOperator}
|
||||
var AssignStyle = &OperationType{Type: "ASSIGN_STYLE", NumArgs: 2, Precedence: 40, Handler: AssignStyleOperator}
|
||||
var AssignTag = &OperationType{Type: "ASSIGN_TAG", NumArgs: 2, Precedence: 40, Handler: AssignTagOperator}
|
||||
|
@ -2,15 +2,28 @@ package yqlib
|
||||
|
||||
import "container/list"
|
||||
|
||||
type AssignOpPreferences struct {
|
||||
UpdateAssign bool
|
||||
}
|
||||
|
||||
func AssignUpdateOperator(d *dataTreeNavigator, matchingNodes *list.List, pathNode *PathTreeNode) (*list.List, error) {
|
||||
lhs, err := d.GetMatchingNodes(matchingNodes, pathNode.Lhs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
preferences := pathNode.Operation.Preferences.(*AssignOpPreferences)
|
||||
|
||||
var rhs *list.List
|
||||
if !preferences.UpdateAssign {
|
||||
rhs, err = d.GetMatchingNodes(matchingNodes, pathNode.Rhs)
|
||||
}
|
||||
|
||||
for el := lhs.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
|
||||
rhs, err := d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
if preferences.UpdateAssign {
|
||||
rhs, err = d.GetMatchingNodes(nodeToMap(candidate), pathNode.Rhs)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
@ -13,6 +13,14 @@ var assignOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (doc)::{a: {g: foof}}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Update to be the sibling value",
|
||||
document: `{a: {b: child}, b: sibling}`,
|
||||
expression: `.a = .b`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: sibling, b: sibling}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Updated multiple paths",
|
||||
document: `{a: fieldA, b: fieldB, c: fieldC}`,
|
||||
@ -24,6 +32,15 @@ var assignOperatorScenarios = []expressionScenario{
|
||||
{
|
||||
description: "Update string value",
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b = "frog"`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: {b: frog}}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Update string value via |=",
|
||||
subdescription: "Note there is no difference between `=` and `|=` when the RHS is a scalar",
|
||||
document: `{a: {b: apple}}`,
|
||||
expression: `.a.b |= "frog"`,
|
||||
expected: []string{
|
||||
"D0, P[], (doc)::{a: {b: frog}}\n",
|
||||
@ -99,5 +116,5 @@ func TestAssignOperatorScenarios(t *testing.T) {
|
||||
for _, tt := range assignOperatorScenarios {
|
||||
testScenario(t, &tt)
|
||||
}
|
||||
documentScenarios(t, "Update Assign Operator", assignOperatorScenarios)
|
||||
documentScenarios(t, "Assign Operator", assignOperatorScenarios)
|
||||
}
|
@ -112,6 +112,7 @@ func applyAssignment(d *dataTreeNavigator, pathIndexToStartFrom int, lhs *Candid
|
||||
assignmentOp := &Operation{OperationType: AssignAttributes}
|
||||
if rhs.Node.Kind == yaml.ScalarNode || rhs.Node.Kind == yaml.AliasNode {
|
||||
assignmentOp.OperationType = Assign
|
||||
assignmentOp.Preferences = &AssignOpPreferences{false}
|
||||
}
|
||||
rhsOp := &Operation{OperationType: ValueOp, CandidateNode: rhs}
|
||||
|
||||
|
@ -215,11 +215,11 @@ func initLexer() (*lex.Lexer, error) {
|
||||
lexer.Add([]byte(`collect`), opToken(Collect))
|
||||
|
||||
lexer.Add([]byte(`\s*==\s*`), opToken(Equals))
|
||||
lexer.Add([]byte(`\s*=\s*`), opToken(PlainAssign))
|
||||
lexer.Add([]byte(`\s*=\s*`), opTokenWithPrefs(Assign, nil, &AssignOpPreferences{false}))
|
||||
|
||||
lexer.Add([]byte(`del`), opToken(DeleteChild))
|
||||
|
||||
lexer.Add([]byte(`\s*\|=\s*`), opToken(Assign))
|
||||
lexer.Add([]byte(`\s*\|=\s*`), opTokenWithPrefs(Assign, nil, &AssignOpPreferences{true}))
|
||||
|
||||
lexer.Add([]byte(`\[-?[0-9]+\]`), arrayIndextoken(false))
|
||||
lexer.Add([]byte(`\.\[-?[0-9]+\]`), arrayIndextoken(true))
|
||||
@ -303,7 +303,7 @@ func (p *pathTokeniser) Tokenise(path string) ([]*Token, error) {
|
||||
|
||||
if index != len(tokens)-1 && token.AssignOperation != nil &&
|
||||
tokens[index+1].TokenType == OperationToken &&
|
||||
tokens[index+1].Operation.OperationType == PlainAssign {
|
||||
tokens[index+1].Operation.OperationType == Assign {
|
||||
token.Operation = token.AssignOperation
|
||||
skipNextToken = true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user