Red Green Repeat Adventures of a Spec Driven Junkie

Using Variables from a File in Ruby Console

tl;dr:

  • In file basic_vars.rb, with content:
hash_of_stuff = { 'key1' => 'value1', 'keyn' => 'valuen' }
  • Load the file: vars_from_file = File.read('basic_vars.rb')
  • Evaluate the file: eval(vars_from_file) #=> {"key1"=>"value1", "keyn"=>"valuen"}
  • Done!

I want to show how to use variables in a Ruby file in the console.

I walk through setting up a Ruby file and loading it into the console, with single variable and multiple variables in the file.

You will learn how to load variables from Ruby files in the console and get them working like they were already created.

This article will take you about five minutes to read.

Viola da Gamba source and more information

Introduction

I had to modify a long list of items on production. The original was in an Microsoft Excel sheet and had over 800 items in them.

Parse Excel File

Parsing the file would be fine with a gem like: Roo. This was one-off work that I didn’t want to figure out how to work with spreadsheets on a production server.

Convert to CSV File

I could convert the Excel file to CSV and work with it that way. Definitely a good solution. There were multiple “sheets” in the Excel file, which would be n-sheets work. This is getting better.

Straight-file

I felt a bit lazier. I wanted to have the values in a file because I didn’t want to fatfinger any entries. Having the values in a file would prevent that. Imagine if I could just “load” the file that contained the data already in a variable?

Let’s try this! KISS 😉

Importing From Column?

What happens when copying from Excel and pasted to the editor? Let’s see:

3424
495
fje
1ng0
122f
xvnk

Displaying the whitespace, this looks like:

3424\n
495\n
fje\n
1ng0\n
122f\n
xvnk\n

Which really means, the content is a string with \n delimiters (hence, the new lines).

Pasting the column value between quotes will make this easier to work with in ruby.

"3424\n
495\n
fje\n
1ng0\n
122f\n
xvnk\n"

Now to get the values into a variable:

stuff_array = "3424\n
495\n
fje\n
1ng0\n
122f\n
xvnk\n"

Add a split("\n") to make sure items change to an array.

stuff_array = "3424\n
495\n
fje\n
1ng0\n
122f\n
xvnk\n".split("\n")
# => stuff_array = [ "3424", "495", "fje", "1ng0", "122f", "xvnk" ]

Awesome - adding a variable name, quotes, and a method to separate out the data we want gets us to a working array.

This works on the interactive console. How about on the server’s console?

First, save this information to a file (copy-paste, again). Transfer the file onto the server and load it. Practice on a local server first!

Load file on Console

On the console, load the file, in this case vars.rb, using File.read:

2.4.6 :001 > File.read("vars.rb")
 => "stuff_array = \"3424\\n\n495\\n\nfje\\n\n1ng0\\n\n122f\\n\nxvnk\\n\".split(\"\\n\")\n\n"

This isn’t what we want. There’s even more \.

Let’s save the contents and see what can happen.

2.4.6 :002 > file_contents = _
 => "stuff_array = \"3424\\n\n495\\n\nfje\\n\n1ng0\\n\n122f\\n\nxvnk\\n\".split(\"\\n\")\n\n"

eval to the rescue

Although this is just “text” in Ruby, there’s a special function in Ruby that can evaluate this text into code: eval.

NEVER have this in actual code - eval is powerful and one must handle its power responsibly.

I assume no responsibility of any damages from the following code.

Run the eval function on the file_contents, the result is:

2.4.6 :003 > eval(file_contents)
 => ["3424", "", "495", "", "fje", "", "1ng0", "", "122f", "", "xvnk"]

Oh, that’s exactly the desired result!

Let’s create a new variable to store it and use it in the current console:

2.4.6 :004 > stuff_array = _
 => ["3424", "", "495", "", "fje", "", "1ng0", "", "122f", "", "xvnk"]
2.4.6 :005 > stuff_array
 => ["3424", "", "495", "", "fje", "", "1ng0", "", "122f", "", "xvnk"]

Perfect, now I can get to work.

More Stuff?

When there are multiple variables in the file to load? What happens then?

vars2.rb content:

stuff_array = "3424\n
495\n
fje\n
1ng0\n
122f\n
xvnk\n".split("\n")
more_stuff = "gdssf\n
fjieo\n
3f92\n
38fsj\n".split("\n")

Reading in the file:

2.4.6 :001 > File.read("vars2.rb")
 => "stuff_array = \"3424\\n\n495\\n\nfje\\n\n1ng0\\n\n122f\\n\nxvnk\\n\".split(\"\\n\")\nmore_stuff = \"gdssf\\n\nfjieo\\n\n3f92\\n\n38fsj\\n\".split(\"\\n\")\n"

Evaluating the content:

2.4.6 :002 > file_contents = _
 => "stuff_array = \"3424\\n\n495\\n\nfje\\n\n1ng0\\n\n122f\\n\nxvnk\\n\".split(\"\\n\")\nmore_stuff = \"gdssf\\n\nfjieo\\n\n3f92\\n\n38fsj\\n\".split(\"\\n\")\n"
2.4.6 :003 > eval(file_contents)
 => ["gdssf", "", "fjieo", "", "3f92", "", "38fsj"]

If the last line is the only values desired, running the script the same way would be fine.

To handle multi-variable, you can:

  • Figure out how to split text between the variables you want (remember, you just need to get to the text)
  • Simpler approach: use ; at the end of each line. The ; doesn’t affect processing in Ruby, it is a much better delimiter than \n (or even: \n\n, or who knows!)

Example with vars3.rb as:

stuff_array = "3424\n
495\n
fje\n
1ng0\n
122f\n
xvnk\n".split("\n");
more_stuff = "gdssf\n
fjieo\n
3f92\n
38fsj\n".split("\n");

In the console:

[email protected]:~$ irb
2.4.6 :001 > File.read("vars3.rb")
 => "stuff_array = \"3424\\n\n495\\n\nfje\\n\n1ng0\\n\n122f\\n\nxvnk\\n\".split(\"\\n\");\nmore_stuff = \"gdssf\\n\nfjieo\\n\n3f92\\n\n38fsj\\n\".split(\"\\n\");\n"
2.4.6 :002 > file_contents = _
 => "stuff_array = \"3424\\n\n495\\n\nfje\\n\n1ng0\\n\n122f\\n\nxvnk\\n\".split(\"\\n\");\nmore_stuff = \"gdssf\\n\nfjieo\\n\n3f92\\n\n38fsj\\n\".split(\"\\n\");\n"
2.4.6 :003 > file_contents_split = file_contents.split(";")
 => ["stuff_array = \"3424\\n\n495\\n\nfje\\n\n1ng0\\n\n122f\\n\nxvnk\\n\".split(\"\\n\")", "\nmore_stuff = \"gdssf\\n\nfjieo\\n\n3f92\\n\n38fsj\\n\".split(\"\\n\")", "\n"]
2.4.6 :004 > file_contents_split[0]
 => "stuff_array = \"3424\\n\n495\\n\nfje\\n\n1ng0\\n\n122f\\n\nxvnk\\n\".split(\"\\n\")"
2.4.6 :005 > file_contents_split[1]
 => "\nmore_stuff = \"gdssf\\n\nfjieo\\n\n3f92\\n\n38fsj\\n\".split(\"\\n\")"
2.4.6 :006 > file_contents_split.map { |content| eval(content) }
 => [["3424", "", "495", "", "fje", "", "1ng0", "", "122f", "", "xvnk"], ["gdssf", "", "fjieo", "", "3f92", "", "38fsj"], nil]
2.4.6 :007 > desired_vars = _
 => [["3424", "", "495", "", "fje", "", "1ng0", "", "122f", "", "xvnk"], ["gdssf", "", "fjieo", "", "3f92", "", "38fsj"], nil]
2.4.6 :008 > desired_vars[0]
 => ["3424", "", "495", "", "fje", "", "1ng0", "", "122f", "", "xvnk"]
2.4.6 :009 > desired_vars[1]
 => ["gdssf", "", "fjieo", "", "3f92", "", "38fsj"]

Conclusion

Being lazy can be a good thing. Instead of working through an Excel or CSV file directly, I only work with the column data I need. From that point, wrangling text a bit and using Ruby’s powerful (and dangerous!) eval method makes any Ruby file a source of data in the console.