I have a YAML file:
DATA_SVC_GEN_CONF_ATTR:
-
-
-
name: validationCodeNum
value: 1
-
name: validationCodeSymbol
value: "val1"
-
name: sql
value: Test
-
name: sqlByGridArea
value: Test1
I want to replace the value of the key sql
from "Test" to "Select * from table".
What I am trying is:
asset.getAttributes.getList.each{|a|
if a.getName == "sqlByGridArea"
a.setValue "Select * from table"
(attrib_defs).map!{|a| a.map{|k,v| "#{k}=#{v}"}.join(',')}
end
asset.with_attributes attrib_defs
Here's how to test whether your YAML is valid, and how I generate YAML for use in files or elsewhere:
require 'yaml'
str = <<EOT
DATA_SVC_GEN_CONF_ATTR:
-
-
-
name: validationCodeNum
value: 1
-
name: validationCodeSymbol
value: "val1"
-
name: sql
value: Test
-
name: sqlByGridArea
value: Test1
EOT
data = YAML.load(str)
# => {"DATA_SVC_GEN_CONF_ATTR"=>
# [[[{"name"=>"validationCodeNum", "value"=>1},
# {"name"=>"validationCodeSymbol", "value"=>"val1"},
# {"name"=>"sql", "value"=>"Test"},
# {"name"=>"sqlByGridArea", "value"=>"Test1"}]]]}
YAML would complain if it couldn't parse the data. If it could and the data wasn't what you expect the output help you diagnose the problem.
When I want to create a YAML file, especially one that's complex, I start with the actual data structure and let YAML generate the serialized version of it:
data = {
'DATA_SVC_GEN_CONF_ATTR' =>
[
[
[
{
'name' => 'validationCodeNum',
'value' => 1
},
{
'name' => 'validationCodeSymbol',
'value' => 'val1'
},
{
'name' => 'sql',
'value' => 'Test'
},
{
'name' => 'sqlByGridArea',
'value' => 'Test1'
}
]
]
]
}
puts data.to_yaml
# >> ---
# >> DATA_SVC_GEN_CONF_ATTR:
# >> - - - name: validationCodeNum
# >> value: 1
# >> - name: validationCodeSymbol
# >> value: val1
# >> - name: sql
# >> value: Test
# >> - name: sqlByGridArea
# >> value: Test1
Moving on... To change elements in a YAML file you can treat the file as text, read it line-by-line, read it by slurping it, or have YAML open it and change the resulting object then have YAML rewrite it.
Slurping files is OK if you're sure the data will fit in memory and you can easily find the section you want to change. Reading it line-by-line often makes it easier to find specific text because you're dealing with individual lines, not the whole file.
Using YAML is the easiest I think as it reduces the change of a badly written regex doing the wrong thing.
data = <<EOT
---
DATA_SVC_GEN_CONF_ATTR:
- - - name: validationCodeNum
value: 1
- name: validationCodeSymbol
value: val1
- name: sql
value: Test
- name: sqlByGridArea
value: Test1
EOT
Pretending that data
was the content of a YAML file on disk, it'd be loaded and parsed using YAML.load_file
. In this example I'm loading as a string so I have to use load
:
object = YAML.load(data)
The data is now parsed so it can be manipulated easily:
object['DATA_SVC_GEN_CONF_ATTR'].first.first[2]['name'] = "Select * from table"
Then it can be written back out:
puts object.to_yaml # => nil
# >> ---
# >> DATA_SVC_GEN_CONF_ATTR:
# >> - - - name: validationCodeNum
# >> value: 1
# >> - name: validationCodeSymbol
# >> value: val1
# >> - name: Select * from table
# >> value: Test
# >> - name: sqlByGridArea
# >> value: Test1
If this is a mission-critical (production) file, you'd want to do the appropriate rename, write, delete steps to protect the data in-case of errors, but that's the gist of it.
Your data structure is very questionable though. You're using a nested array-of-array-of-array just to hold your hashes, which is not very common or easily understood. Instead it should be reduced to a single array:
data = <<EOT
---
DATA_SVC_GEN_CONF_ATTR:
- name: validationCodeNum
value: 1
- name: validationCodeSymbol
value: val1
- name: sql
value: Test
- name: sqlByGridArea
value: Test1
EOT
object = YAML.load(data)
# => {"DATA_SVC_GEN_CONF_ATTR"=>
# [{"name"=>"validationCodeNum", "value"=>1},
# {"name"=>"validationCodeSymbol", "value"=>"val1"},
# {"name"=>"sql", "value"=>"Test"},
# {"name"=>"sqlByGridArea", "value"=>"Test1"}]}
object['DATA_SVC_GEN_CONF_ATTR'][2]['name'] = "Select * from table"