How to iterate through a yaml hash structure in ruby? - ruby-on-rails

I have a hash mapping in my yaml file as below. How Can I iterate through it in simple ruby script? I would like to store the key in a variable and value in another variable in my ruby program during the iteration.
source_and_target_cols_map:
-
com_id: community_id
report_dt: note_date
sitesection: site_section
visitor_cnt: visitors
visit_cnt: visits
view_cnt: views
new_visitor_cnt: new_visitors
the way i am getting the data from the yaml file is below:
#!/usr/bin/env ruby
require 'yaml'
config_options = YAML.load_file(file_name)
#source_and_target_cols_map = config_options['source_and_target_cols_map']
puts #source_and_target_cols_map

The YAML.load_file method should return a ruby hash, so you can iterate over it in the same way you would normally, using the each method:
require 'yaml'
config_options = YAML.load_file(file_name)
config_options.each do |key, value|
# do whatever you want with key and value here
end

As per your yaml file it you should get the below Hash from the line config_options = YAML.load_file(file_name)
config_options = { 'source_and_target_cols_map' =>
[ { 'com_id' => 'community_id',
'report_dt' => 'note_date',
'sitesection' => 'site_section',
'visitor_cnt' => 'visitors',
'visit_cnt' => 'visits',
'view_cnt' => 'views',
'new_visitor_cnt' => 'new_visitors' }
]}
Then to iterate through you can take the below approach:
config_options['source_and_target_cols_map'][0].each {|k,v| key = k,value = v}

Related

How to generate .yml file from Ruby on Rails?

I would like generate the following result in a .yml file from Ruby on Rails:
include:
- template: ./my_folder/my_file.txt
But I am generating the following result with single quote (''):
include:
- 'template: ./my_folder/my_file.txt'
I have tried generate the .yml file with this ruby code:
my_variable = {"include" => ["template: ./my_folder/my_file.txt"]}
I would do this:
my_variable = { "include" => [{ "template" => "./my_folder/my_file.txt" }] }
my_variable.to_yaml
# ---
# include:
# - template: "./my_folder/my_file.txt"
my_variable = {"include" => ["template: ./my_folder/my_file.txt"]}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The Array contains a String, not a Hash. It will produce a YAML array with a single string value, not an array with a key/value pair.
Either you have a typo in your data, or you need to split the values in the Array on : to produce a Hash.

Function that accepts a hash key and returns multiple values?

I am working on a practice question that asks me to create a group_by_owners function that
"Accepts a hash containing the file owner name for each file name.
Returns a hash containing an array of file names for each owner name, in any order.
For example, for hash
{'Input.txt' => 'Randy', 'Code.py' => 'Stan', 'Output.txt' => 'Randy'}
the group_by_owners method should return
{'Randy' => ['Input.txt', 'Output.txt']`, `'Stan' => ['Code.py']}
So far, I could not get anything to pass. I expect that i am supposed to take in a hash so I implemented a new files = {} has and put in the appropriate values. But all I get is a syntax error
module FileOwners
def self.group_by_owners(files)
files = {}
files['Randy'] << 'Input.txt' << 'Output.txt'
files['Stan'] << 'Code.py'
end
end
puts FileOwners.group_by_owner(files)
I have tried other practices including
module FileOwners
def self.group_by_owners(files)
files = {
'Randy' => 'Input.txt',
'Randy' => 'Output.txt'
'Stan' => 'Code.py'
}
end
end
puts FileOwners.group_by_owners(files['Randy'])
But I am still met with errors. I'm completely stuck. I'm obviously fairly new to Ruby, so bear with me. Does anyone know a better solution?
The point is: method accepts the hash, you do not have to build a hash, you just pass it to method. Your method has to just work with the argument passed.
When I was staring coding I was thinking the same way as you are now ;)
def group_by_owners(files)
better_hash = Hash.new { |hash, key| hash[key] = [] }
files.each_with_object(better_hash) {|(k, v), hash| hash[v] << k}
end
group_by_owners({'Input.txt' => 'Randy', 'Code.py' => 'Stan', 'Output.txt' => 'Randy'})
#=> {"Randy"=>["Input.txt", "Output.txt"], "Stan"=>["Code.py"]}

why won't Ruby OptionParser read all of my arguments?

This is my code:
#!/usr/bin/env ruby
# OptionParser
require 'optparse'
options = {}
optparse = OptionParser.new do|opts|
opts.banner = '...'
# This option inputs ...
options[:Lap1] = []
opts.on('-1', '--Lap1 filepath1,width1,height1,a1,first1,last1', String, '...') do|l1|
options[:Lap1] = l1.split(',')
end
end
optparse.parse!
My goal is to have an array of the separate inputs separated by commas. However this code only outputs the first variable $filepath1.
The output of:
puts(options[:Lap1])
and
puts(options[:Lap1][0]
is just the the first variable filepath1.
puts(options[:Lap1][1])
is nil, when it should be the variable width1.
Any suggestions or potential fixes would be helpful, thank you.
You need to call the parse! method on your OptionParser object after declaring all the options.
optparse.parse!
I'd write that code a bit differently:
require 'optparse'
require 'pp'
options = {
:Lap1 => []
}
optparse = OptionParser.new do |opts|
opts.banner = '...'
# This option inputs ...
opts.on(
'-1', '--Lap1 filepath1,width1,height1,a1,first1,last1',
Array,
'...'
) { |l1| options[:Lap1] = l1 }
end.parse!
pp options
Running that at the command-line:
ruby test.rb -1 filepath1,width1,height1,a1,first1,last1
Results in:
{:Lap1=>["filepath1", "width1", "height1", "a1", "first1", "last1"]}
Testing using --Lap1 results in:
ruby test.rb --Lap1 filepath1,width1,height1,a1,first1,last1
And:
{:Lap1=>["filepath1", "width1", "height1", "a1", "first1", "last1"]}
In my opinion, you should set your defaults when you define your options hash.
options = {
:Lap1 => []
}
Also, notice the use of Array instead of String. OptionParser will automatically split a comma-delimited string into an array of individual elements if you use Array, saving you that split step, and avoiding a bit of confusing code. See the documentation for OptionParser's make_switch method for more information.

Rails what is the oppsite of the to_query method?

I have turned, have turned a hash to params using the to_query method.
How to turn it back into a hash?
I have tried this:
require 'rack'
#tester = Rack::Utils.parse_nested_query(params[:search])
In view: <%= #tester.class %>
Which gives NilClass.
The parameters are:
"search"=>"fields%5B%5D=exhb_0&fields%5B%5D=exh0_1&fields%5B%5
D=t_g_a&fields%5B%5D=hp_1&fields%5B%5D=s1&fields%5B%5D=overflade_0&railing%5B%5D
=A-3&railing_m=0&type%5B%5D=ltrappa&wood%5B%5D=wood_6"
This is a duplicate of this questions: Just use:
Rack::Utils.parse_query(my_query_string)
In order to decode the line in your example, be sure to unescape the string first:
require 'rack'
my_string = 'fields%5B%5D=exhb_0&fields%5B%5D=exh0_1&fields%5B%5D=t_g_a&fields%5B%5D=hp_1&fields%5B%5D=s1&fields%5B%5D=overflade_0&railing%5B%5D=A-3&railing_m=0&type%5B%5D=ltrappa&wood%5B%5D=wood_6'
unescaped_string = URI.unescape(my_string)
# => "fields[]=exhb_0&fields[]=exh0_1&fields[]=t_g_a&fields[]=hp_1&fields[]=s1&fields[]=overflade_0&railing[]=A-3&railing_m=0&type[]=ltrappa&wood[]=wood_6"
params_hash = Rack::Utils.parse_query(unescaped_string)
# => {"fields[]"=>["exhb_0", "exh0_1", "t_g_a", "hp_1", "s1", "overflade_0"], "railing[]"=>"A-3", "railing_m"=>"0", "type[]"=>"ltrappa", "wood[]"=>"wood_6"}

Handling a hash as a function argument

I am using Ruby on Rails 3 and I am trying to handle a hash as a function argument.
For example, if I state a function this way:
def function_name(options = {})
...
end
I would like to pass to the function_name a hash like
{"key1"=>"value_1", "key2"=>"value2", "..." => "..."}
and then use that inside the function.
What is the best\common (Rails) way to do that?
P.S.: I have seen the extract_option! method somewhere, but I don't know where I can find some documentation and whether I need that in order to accomplish what I aim.
Simply use the definition you provided:
def function_name(options = {})
puts options["key1"]
end
Call it with:
function_name "key1" => "value1", "key2" => "value2"
or
function_name({"key1" => "value1", "key2" => "value2"})
Array#extract_options! is simply used with methods that have variable method arguments like this:
def function_name(*args)
puts args.inspect
options = args.extract_options!
puts options["key1"]
puts args.inspect
end
function_name "example", "second argument", "key1" => "value"
# prints
["example", "second argument", { "key1" => "value" }]
value
["example", "second argument"]
Another useful method is Hash#symbolize_keys! which lets you not care about whether you pass in strings or symbols to your function so that you can always access things like this options[:key1].
The way you have it declared in your example will work fine.
def function(options = {})
item = options[:item]
need_milk = options[:milk] || false
cow = options[:bovine]
end
function(:item => "Something")
In the case above, item == "Something", need_milk == false and cow == nil.
extract_options is simply an addition to the Array and Hash class via Rails.
def function(something, else, *args)
options = args.extract_options! # returns Hash
end
It is useful if you plan on having many different types of parameters in args but if you only want Hash options, your original way is fine.
Here's a Gist of the code in Rails for extract_options! I personally use it in my code at work by just writing it to an external file and requiring it into my project.
Ruby makes this easy, and you were already doing it right.
Here is a poetry-mode (minimal, DSL-style) example:
def f x = {}
p x
end
f :a => :b
{:a=>:b}
f
{}
f :a => :b, :c => :d
{:a=>:b, :c=>:d}

Resources