Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ENV['FOO'] = true raise an exception in Ruby?

Tags:

ruby

ENV['FOO'] = true

Raises no implicit conversion of true into String

puts ENV.class
Object < BasicObject

Array access methods are not part of BasicObject.

Not sure if this is coming from Rack, Rack Test or another gem.

ruby 2.2.3p173
rack (1.6.0)
rack-test (0.6.3)

like image 594
B Seven Avatar asked Aug 27 '26 21:08

B Seven


2 Answers

Because the ENV class isn't just an object or an hash: ENV is a hash-like accessor for environment variables.

It is obvious that it is not a real heash, because the setter method (ENV[name] = value) tries to cast the value to string.

Furthermore it is worth noting that it is missing many methods a normal hash would have.

like image 170
spickermann Avatar answered Aug 30 '26 13:08

spickermann


It's important to understand what ENV is: It's the variables defined in your shell, which lies beneath your script and Ruby, and will be made available to your running script or to any sub-shells you create.

That environment only knows about strings, values expressed as 'true' or 'false', not as objects like Ruby's true or false.

Saying ENV['foo'] = true is an attempt to assign a Ruby object and fails. Use ENV['foo'] = 'true' instead.

Here's a little example of how you can use it. I have a single line of Ruby code in a file called "test.rb":

puts ENV['foo']

If I run that code using the following command in a shell:

foo=bar ruby test.rb

The Ruby script outputs the value of ENV['foo']:

bar

That's because foo=bar initialized the system environment variable foo to 'bar' prior to handing off control to Ruby.

I can use that same variable to look at the value in a sub-shell also. Changing the Ruby script to:

ENV['foo'] = 'baz'
puts `echo $foo`

and running it sets the environment variable 'foo' to 'bar' prior to giving Ruby control, then Ruby changes it to 'baz' then executes the sub-shell to echo the output of the variable, which Ruby captures because I'm using backticks:

foo=bar ruby test.rb

resulting in:

baz

being printed. Even though I'd originally set the variable to 'bar', the script set it to 'baz', which only the sub-shell could see.

I think a good argument could be made that writing to ENV should automatically use to_s to avoid this, but it's one of many gotcha's found in any programming language.

like image 45
the Tin Man Avatar answered Aug 30 '26 13:08

the Tin Man