Wednesday, June 20, 2007

Making Use of Ruby's ENV Object

Ruby provides the ENV object for easy access to a variety of environment variables. ENV is not actually a hash, but you access individual values like you would a hash:


ENV['Path']

If you need to, you can convert it into a Hash using the to_hash method, so to see a complete list of keys and values stored in ENV, you could do this:

ENV.to_hash.each do |key, value|
puts("#{key}\t#{value}")
end

Many of these values you may never use, but a few are worth noting...

HOMEDRIVE returns the home drive, for example:

ENV['HOMEDRIVE'] # returns "C:"

APPDATA returns the path to the Application Data folder(ie, "C:")

ENV['APPDATA'] # returns "C:\Documents and Settings\Joe DiMaggio\Application Data"

USERPROFILE returns the user's home directory:

ENV['USERPROFILE'] # returns "C:\Documents and Settings\Joe DiMaggio"

USERNAME returns the Windows user's name or Windows login:

ENV['USERNAME'] # returns "Joe DiMaggio"

ProgramFiles returns the path to the Program Files folder:

ENV['ProgramFiles] # returns "C:\Program Files"

windir returns the path to the Program Files folder:

ENV['windir'] # returns "C:\Windows"

Writing to Environment Variables

To quote The Pickaxe:

"A Ruby program may write to the ENV object, which on most systems changes the values of the corresponding environment variables. However, this change is local to the process that makes it and to any subsequently spawned child processes. This inheritance of environment variables is illustrated in the code that follows. A subprocess changes an environment variable and this change is seen in a process that it then starts. However, the change is not visible to the original parent. (This just goes to prove that parents never really know what their children are doing.)"

A tip of the hat to reader Revence, who shared a code snippet that utilized the ENV object, reminding me of its value.

That's all for now. As always, leave a comment here or via email if you have questions or suggestions for future topics.

Thanks for stopping by!

Digg my article

6 comments:

Daniel Berger said...

After looking at hash.c, I do not understand why it isn't actually a hash. The actual implementation is overwrought for what it does.

blkperl said...

This correctly notices if the file has been redirected.

ENV['APPDATA'] # returns "C:\Documents and Settings\Joe DiMaggio\Application Data"

This does not. (Definitely a bug)

ENV['USERPROFILE'] # returns "C:\Documents and Settings\Joe DiMaggio"

On linux this returens /home/$user
but it only returns the drive letter on windows. (I think that should be considered a bug)

ENV['HOME'] # returns C:

Anonymous said...

@blkperl: ENV['APPDATA'] works here correctly. System is Windows XP, Ruby 1.8.6 patchlevel 368.

blkperl said...

@Anoymous

I believe you misread my comment. I stated that ENV['USERPROFILE'] does not work correctly.

And since posting I learned that ENV['HOMESHARE'] is what i wanted not ENV['HOME']

Anonymous said...

How would you deal with an username containing a special character? When the user name is Test [and please consider an accent on the 'e'], the ENV[APPDATA] will come back with 'Tst'. This results in the inability to write configuration files to the roaming user environment...

Anonymous said...

I'm also confused about the nature of ENV - I must be missing something about the low-level nature of Ruby processes because I can't find any justification for this adkward choice of implementation.

I'm working on a library in which objects may be converted to hashes using #to_hash, and I ran into an issue because ruby is devoid of such a method ex except for the instance method ENV#to_hash. Great. Not only is this inconsistent (XMLRPC#FaultException) but also extremely inconvenient, forcing me to work around a situation that should have been avoided. Who needs a #to_hash method on ENV when it already supports enumerable methods?

But wait, it gets worse. I of course tried to override the method in ENV, but it turns out ENV is not a class. It's a global constant. So you can't just add your own #to_hash method to the class ENV. BAD DESIGN in my opinion, and I'd personally like to get this changed.