Get the keyname from a YAML configuration file - ruby

I would like to get the name of a key in a YAML configuration file like the following
The YAML file contains a collection of structs in structs, the organisations have a number represented as a symbol which is the key/class name. I need to retrieve this symbol
require 'yaml'
data = YAML.load(DATA)
data.organisations.each do |organisation|
organisation #<struct language="nl", name="myname">
# following line is what I need, I expect it to be :"121"
organisation.class #<Class:0x00000004fd4248>
end
__END__
--- !ruby/struct
organisations: !ruby/struct
:121: !ruby/struct
language: nl
name: organisationname
Can someone help me retrieving the name of the struct ?

I tried around a bit and found this:
data.organisations.members
=> [:"121"]
The way I found this (which is useful in other circumstances, too) is the following:
data.organisations.methods - Object.new.methods
And then I tried out every method that seemed reasonable.

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

Writing untagged YAML with Ruby Psych, then reading It

I have Ruby using Psych that writes YAML like this:
---
- !ruby/struct:Dhc::QueryEvent
time: 2018-01-02T07:45:18.470Z
hits: 2525
qtime: 13
server: search1
q: search term
searched_in:
- productA
- productB
- productC
Is there a way I can write the YAML without the "!ruby/struct:Dhc::QueryEvent" tag? I want the storage formatted so it is not dependent on my struct:Dhc::QueryEvent for reading. In other words, I want others to have the flexibility to read the YAML however they want. Currently, they get
undefined class/module Dhc:: (ArgumentError)
Then, when I'm reading the file myself, is there a configuration in Psych that allows me to read the untagged records into my Dhc::QueryEvent struct? I assume this would be something like
ar = []
Psych.parse_stream(yaml_stream) do |node|
ar << Dhc::QueryEvent.new(node.time, node.hits, etc...)
end
but maybe there is a shorter way?

How to declare a ruby constant (RMagick) in a YAML file

I am looking for a possibility to declare a Magick::StyleType constant in a .yml file and then to load this constant into a ruby file.
Or if that's not possible then I need to know how to convert a String into a Magick::StyleType constant in ruby.
Here are the details:
I am trying to write a ruby program, which places some text on a picture and I use the RMagick interface for it.
In my ruby program I have a method which specifies different properties of the text like font-family or font-style. This method includes the line:
self.font_style = ItalicStyle
Now I want to store all changeable parameters in a YAML-config file (config.yml), so this config.yml includes these lines:
#font style (like bold, italic and so on)
:font_style: ItalicStyle
Now I load the config.yml in my ruby file and the above mentioned line in my method reads now
self.font_style = config_file[:font_style]
When I run my ruby file now I get the error message:
`font_style=': wrong enumeration type - expected Magick::StyleType, got String (TypeError)
So after having searched a little about the topic I changed my config.yml first to
:font_style: !/ruby/constant ItalicStyle
which got me the same error message as above and then I tried this:
:font_style: !/ruby/symbol :ItalicStyle
and got this error message:
`font_style=': wrong enumeration type - expected Magick::StyleType, got Symbol (TypeError)
Then I checked in irb:
require 'rmagick' => true
Magick.const_get(ItalicStyle) => ItalicStyle=2
Magick.const_get(ItalicStyle).class => Magick::StyleType
So, finally I get to my question: How do I need to change the line
:font_style: !/ruby/symbol :ItalicStyle
in my config.yml file so that when loaded into my ruby file ItalicStyle will be recognized as a Magick::StyleType constant?
Or when I leave
:font_style: ItalicStyle
in the config.yml and load the ItalicStyle as a String into my ruby file: is there a possibility, to convert ItalicStyle from a String to the Magick:StyleType constant in the ruby file directly?
I would be really happy if someone could help. I have tried for days to find a solution and I really need it for my project.
I would just store a String in the YAML file, because that is easier to write and to read:
:font_style: ItalicStyle
Than I would get the constant by its name to configure Magick:
self.font_style = Object.const_get(config_file[:font_style])

ruby/hash:Chef::Node::ImmutableMash included in file when converting Chef attributes to yaml

I am trying to write a .yml file from a subset of attributes. Here's the resource definition I'm using:
file '/home/user/file.yml' do
owner 'user'
group 'user'
mode '0755'
content node['default']['properties'].to_yaml
end
When I run this, the file.yml ends up looking like this though:
--- !ruby/hash:Chef::Node::ImmutableMash
config: !ruby/hash:Chef::Node::ImmutableMash
example: value
another: value
How do I get clean yaml output without all the !ruby/hash:Chef::Node::ImmutableMash output?
Turns out all you need to do is convert the attributes to a hash explicitly before converting to yaml. Here is the working code:
file '/home/user/file.yml' do
owner 'user'
group 'user'
mode '0755'
content node['default']['properties'].to_hash.to_yaml
end
Note: you'll need to be using chef-client 11.10.0 or later, because
there used to be a bug with the to_hash method. More info here:
https://stackoverflow.com/a/14782389/1688034

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

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

Resources