How to write a file that is both valid ruby syntax and valid YAML syntax - ruby

In order to have only a single point of configuration for my app I need to make a YAML config file that is also valid ruby code. I.e. a mixed syntax file that can be parsed as YAML and parsed as ruby.
My application is a suite of processes managed by the god gem. I want to load a new group of maintained processes (watches) for each new configuration file.
God allows loading a new app.god (ruby) file with new watches defined, but I don't want an app.god and app.yml, just one file. Simplest might be to just have the app.god file and include the configuration within that, but I preferred the idea of a yml file that was also valid ruby code.

#I found this that might be helpful:
#This is a valid ruby and a valid YAML file
#Comments are the same in YAML and ruby
true ?true:
- <<YAML.to_i
# At this point in ruby it is the contents of a here doc (that will be
# converted to an integer and negated if true happens not to be true)
# In YAML it is a hash with the first entry having key "true ?true"
# representing a list containing the string "- <<YAML.to_i"
# If your YAML object should be a list not a hash you could remove the first line
any_valid_yaml: from here
a_list:
- or
- anything
- really
#Then mark the end of the YAML document with
---
#And YAML is done and ignores anything from here on
#Next terminate the ruby here document
YAML
#Now we're in ruby world
#this = "pure ruby"
def anything(ruby)
"here"
end

Related

Syntax for calling and how to write yaml file in ruby

Here is main.rb file (the driver of the project)
require_relative '../lib/logic'
So first of all, how to make a YAML file? Well, there are many tutorials out there to teach you the basics of a format, but a little shortcut is to just use the .to_yaml method on a Ruby object, and look at the output:
require 'yaml'
checks_to_run = [
"check_alphabetized_constants",
"check_bfr_return_emp_line"
]
puts checks_to_run.to_yaml
Which prints
---
- check_alphabetized_constants
- check_bfr_return_emp_line
--- always goes on the first line, and then you have a list of strings (quotations are optional) - simple enough.
You can write this to a file like so:
File.open("checks.yaml", "w") { |f| f.write checks_to_run.to_yaml }
You can of course write or edit the YAML file by hand as needed.
Now, to read the YAML file:
checks_to_run = YAML.load(File.read("checks.yaml"))
# => ["check_alphabetized_constants", "check_bfr_return_emp_line"]
From this point, you can loop through the checks and call the methods. There are multiple ways to do this, for example you could use send:
checks_to_run.each do |check_to_run|
check.send(check_to_run)
end
Or you could skip the metaprogramming and use something like if:
if checks_to_run.include?("check_alphabetized_constants")
check.check_alphabetized_constants
end
# repeat for the other checks as well

Replacing variable value in ruby while setting the value using "set" command

I have a .properties files as below:
user:abcd
pwd:xyz
system:test
Next, I have a ruby script with Watir for browser automation. In this script, I have statements like
browser.text_field(:id => 'identifierId').set "#{user}:variable to be replaced by its value from .properties file".
Similarly, other values need to be replaced for "pwd" and "system".
I tried the solution per below posts:
Replace properties in one file from those in another in Ruby
However, "set" command is setting whatever has been paased as arguments to it instead of replacing the variable with its value.
Please help.
You have to read the information out of the file.
Most Watir users leverage yaml files for this.
config/properties.yml:
user: abcd
pwd: xyz
system: test
Then read the yaml file & parse your data:
properties = YAML.safe_load(IO.read('config/properties.yml'))
text_field = browser.text_field(id: 'identifierId')
text_field.set properties['user']
Alternately you can take a look at Cheezy's Fig Newton gem, which is designed to work with his Page Object gem

Ruby 1.8 vs 2.3 handling YAML config arrays differently

I'm trying to upgrade a server that has ruby scripts developed by another person. I'm a perl/php developer and no little about ruby, just trying to get the scripts to work that was developed with Ruby 1.8 and the scripts seems to behave differently handling arrays in the newer version. The script was not matching iterated folders with a config file array with the folder names and I believe I've boiled it down to the way the YAML config file is converted to an array. I put together this simple script:
require 'rubygems'
require 'yaml'
config_filename = File.expand_path(File.dirname(__FILE__) + "/testruby.yml")
#config = YAML.load(File.open(config_filename))
puts #config
The YAML testruby.yml config file looks like this:
1_01:
name: Monday Show
suffix: showM
program_id: 123
segment: 1
dated: false
1_02:
name: Monday Show
suffix: showM
program_id: 123
segment: 2
dated: false
1_03:
name: Tuesday Show
suffix: showT
program_id: 124
segment: 1
dated: true
When I run this on the original server with Ruby 1.8, the result is:
1_03program_id124nameTuesday Showsegment1suffixshowTdatedtrue1_02program_id123nameMonday Showsegment2suffixshowMdatedfalse1_01program_id123nameMonday Showsegment1suffixshowMdatedfalse
But when ran on the new server with Ruby 2.3 I get a array:
{101=>{"name"=>"Monday Show", "suffix"=>"showM", "program_id"=>123, "segment"=>1, "dated"=>false}, 102=>{"name"=>"Monday Show", "suffix"=>"showM", "program_id"=>123, "segment"=>2, "dated"=>false}, 103=>{"name"=>"Tuesday Show", "suffix"=>"showT", "program_id"=>124, "segment"=>1, "dated"=>true}}
It even removes the underscore from the folder name key in the config file. For this reason, later in the script, calls to #config[1_01] does not match of course. Is there a way to get the array to build like version 1.9 so the rest of the script works as designed?
One more thing to note, not sure if it related to the issue. The require 'yaml' line was not present in the script, I added after receiving this error when ran:
testruby.rb:4:in `<main>': uninitialized constant YAML (NameError)
Well, it seems all I had to do was enclose the YAML keys in quotes and now the hash object includes the underscore in the keys and the rest of the script works!

`__FILE__` not working within `DATA`/`__END__`

I'm working on Practicing Ruby's Self-Guided Course on Stream, File Formats, and Sockets, and came across the following problem in the pre-built test for the first exercise. The following test script is supposed to change the directory to the data subdirectory of the project folder:
eval(DATA.read) # load the test helper script
... # various calls to test method defined below
__END__
dir = File.dirname(__FILE__)
Dir.chdir("#{dir}/data")
...
But this breaks because __FILE__ returns (eval) (instead of the path to the file) and File.dirname(__FILE__) returns . Why is this happening, and how should it be written to yield the intended output instead?
__END__ and DATA aren't really relevant here. You're simply passing a string to Kernel#eval. For example, a simple eval('__FILE__') also returns "(eval)" because that's the default filename. It can be changed by passing another string but as third argument:
eval('__FILE__', nil, 'hello.rb') # => "hello.rb"
Or in your case:
eval(DATA.read, nil, __FILE__)

Replace properties in one file from those in another in Ruby

I want to replace properties in one file from those in another. (I am new to ruby, and read about Ruby and YAML. I have a Java background)
Eg.
File 1
server_ip_address=$[ip]
value_threshold=$[threshold]
system_name=$[sys_name]
File 2
ip=192.168.1.1
threshold=10
sys_name=foo
The ruby script should replace the $ values by their real values (I do not know if $[] is the format used in ruby. Also do Files 1 and 2 have to be YAML files, or erb files?) and produce File 1 as :
server_ip_address=192.168.1.1
value_threshold=10
system_name=foo
I searched the web for this, but could not express it in the right keywords to find a solution/pointer to a solution/reference material on google. How can this be done by a ruby script?
Thanks
If you can switch the formats, this should be as easy as:
require 'yaml'
variables = YAML.load(File.open('file2.yaml'))
template = File.read('file1.conf')
puts template.gsub(/\$\[(\w+)\]/) { variables[$1] }
Your template can stay as-is, but the substitution file would look like:
ip: 192.168.1.1
threshold: 10
sys_name: foo
This makes it easy to read in using the YAML library.

Resources