Monday, January 23, 2012

ENV before Ruby

When making environment variables available to a Ruby script, make sure the environment key/value pairs are declared before the call to run a Ruby script.

E.g.,

MY_ENV_VAR=test ruby show_my_env_var.rb

first things first

I probably goes without saying, but when you are starting out with a new project, it is best to get as much of the framework available to your customer up front. Stick with as much bland as possible (e.g., wire frame) so that it's obvious that colors, graphics, etc. are not the focus up front. What good is the fancy shine when there is little functionality.

I spent a good amount of time looking for a tool that I could use to create wire frames that could be easily published and couldn't find one that would generate actual RoR views that could be published. The best tool I found was only for Windows and I use a Mac. With wire frame views in place along with the ability to navigate from resource to resource, it would be very easy to prioritize the pages and add actual functionality/color/graphics to that particular resource.

Active Scaffold is very interesting and is an example of using convention to save time in creating forms based on model configuration. I realize it's asking quite a bit, but it would be nice to have a tool where controls could be drawn/resized/etc and then published to RoR views.

It might be something worth looking into.

Wednesday, January 18, 2012

the basics of textual progress bars

While running through some maintenance of some log directories, I learned a little bit about $stdout and textual progress indicators.

The app I work with logs like crazy. There are time-date-stamped log files all over, products of the much appreciated log roller we use. Obviously, log rolling helps eliminate the need to peruse through an 8+ gygabyte text file. That's good. The accumulation of so many log files, however, get's to be almost as annoying. Just like my commuter car, at some point you can't stand it anymore and it's time to do some house cleaning.

I'm a software developer, and a lazy software developer at that. If there is any reason to code something, I'll gravitate towards creating a script, even to generate lines I can run in my console to tar up log files. There are so many log files to be tarred that I found myself wanting to view the progress since it's no fun staring at a frozen screen.

I use tail -f often to watch log entries being made from the web application I'm working with.

tail -f log/development.log


I can also see what files in a directory were last touched.

ls -lat | head


Wouldn't it be nice to have a script that monitored the directory and let me see those tar archives grow? That much was pretty easy.

while(true)
puts `ls -lat log/archive | head`
sleep(1)
end


But it is ugly. You get entries that scroll you off the page. Then I start thinking about those textual progress bars. They seem to print some character that moves the cursor back to the beginning of the line so that the next print of characters over-writes the last. That would solve my problem with the scrolling.

Ok; again, I'm lazy. I did a little research, but admittedly, just enough to get the results I wanted. So here are some facts/theories:
  1. carriage returns (\r) are different from newlines (\n). When used together, the cursor shows up on the next line. If you only use a carriage return, the cursor returns to the beginning of the line it is currently on.
  2. 'puts' automatically adds a carriage return (cr) and newline (\r\n) to the outputted string. Ok; that's a step in the right direction.
  3. 'printf' may be used to print to the console without a cr or newline
  4. 'printf' automatically buffers, spitting content out to screen only when the script is finished. If we could only force a flush. Including a call to 'flush' doesn't seem to do the trick.
  5. $stdout and $stderr are built in handles to STDOUT and STDERR (go figure!). I'm not sure, but I think that 'printf' is a method associated with Kernel. I do know that calls to $stdout.printf("hello world") followed by $stdout.flush() does work.
We should have everything that is required now. Let's try this again.

while(true)
res = `ls -lat log/archive | head`
$stdout.printf("%s\r", res) #note: don't use a newline; only a carriage return
$stdout.flush() #or you won't see anything,... ever
sleep(1)
end


Ah, much better! Now, since I can't leave well enough alone, I will clean up my output, limiting the output only to the first actual file in the list.

#note: hit Ctrl-c to end the loop
while(true)
#note: there is no check for when no match was found
res = `ls -lat log/archive | head`.match(/^[^\r\n]+[\r\n]+([^\r\n]+)/)[1]

$stdout.printf("%s\r", res) #note: don't use a newline; only a carriage return
$stdout.flush() #note: flush or you won't see anything,... ever
sleep(1)
end


So to sum up, while there are several gems or plugins that offer the nice convenience of a textual progress bar, it all comes down to printing a line that ends in a carriage return (\r) only and flushing the STDOUT buffer.

Here are several references I discovered during the fun little journey I made into the world of progress bars:

http://www.ruby-forum.com/topic/175626
http://blog.dhavalparikh.co.in/2009/04/progress-bar-in-rails/
http://0xcc.net/ruby-progressbar/index.html.en
http://stackoverflow.com/questions/238073/how-to-add-a-progress-bar-to-a-bash-script
https://github.com/jfelchner/ruby-progressbar/blob/master/lib/progressbar.rb

# shortcut for doing sprintf
http://snippets.dzone.com/posts/show/5027