Thursday, July 29, 2010

Ruby and RVM

  So I've been having trouble installing RVM and having it work correctly. Yesterday, a coworker of mine shared some insight as to why I've been having issues. I would install it as root or using sudo which would give me the binaries in my /usr/local/bin directory. The problem with that is I could install all the rubies I want but couldn't use them. It would say it's using them, but it's a lie. ruby -v would give me nothing.
  He pointed out that I might try installing RVM as a regular user and sudo ln -s the binaries into the /usr/local/bin directory. It works! I install it like that and run the rest of the steps from http://rvm.beginrescueend.com/rvm/install/ and viola, it verks :) RVM is awesome. I hope you find it as enjoiable as I have.

Pidof

pidof is a wonderful tool in linux that displays the pids of a given process. Unfortunately, MacOS doesn't come with this nifty tool so we need to create our own and add it to our ~/.profile. Here's the code, just add it to the end of your ~/.profile
pidof () { 
  ps -Ac | egrep -i chrome | awk '{printf $1;printf " "}';
  echo ""; 
}
Here's the results of this being run,
~$ pidof chrome
20867 83814 83833 83849 83850 83851 83852 83853 
~$ 

Tuesday, July 13, 2010

Currency Exchange and Open URI

So I have a website that allows me to see how the dollar is doing compared with other currencies. Currently, the website pulls the information from google. I just discovered a better way;
>> require 'open-uri'
=> true
>> open("http://xurrency.com/api/eur/gbp/1.5").gets
=> "{"result":{"value":1.25715,"target":"gbp","base":"eur"},"status":"ok"}"

Awesome!! Thanks xurrency!!
This will expand the possibilities of my site exponentially :)

Friday, July 9, 2010

Retry on Exception

I got this little snippet from this website,
def retryable(options = {}, &block)
  opts = { :tries => 1, :on => Exception }.merge(options)

  retry_exception, retries = opts[:on], opts[:tries]

  begin
    return yield
  rescue retry_exception
    retry if (retries -= 1) > 0
  end

  yield
end

If I modify this just a little bit, I can avoid the double yield while retrying and eventually failing. Here's the modified version:
def do_it_over_again(options = {}, &block)
  opts = { :tries => 1, :on => Exception }.merge(options)

  retry_exception, retries = opts[:on], opts[:tries]

  begin
    return yield
  rescue retry_exception
    retry if (retries -= 1) > 0
    raise opts[:on]
  end
end

Notice that I raise the exception we're trying to avoid instead of yielding one more time than we expect it to.

Now, instead of this:
jruby-1.5.1 > do_it_over_again(:tries => 5, :on => CustomExceptions::RejectedLoginException) do
  puts "hey" 
  raise CustomExceptions::RejectedLoginException
end
hey
hey
hey
hey
hey
hey
CustomExceptions::RejectedLoginException: CustomExceptions::RejectedLoginException
 from (irb):28


I get this:
jruby-1.5.1 > do_it_over_again(:tries => 5, :on => CustomExceptions::RejectedLoginException) do 
  puts "hey"
  raise CustomExceptions::RejectedLoginException
end
hey
hey
hey
hey
hey
CustomExceptions::RejectedLoginException: CustomExceptions::RejectedLoginException
 from (irb):10:in `do_it_over_again'
 from (irb):17

Notice that it runs only five times in the modified code instead of six. It's definitely worth it to check out that post though, so go ahead..

Loompa!

There's a nifty little library called Loompa (http://rubygems.org/gems/loompa) that allows one to manage a mess of forks in a fork poolish sort of way. Basically, I would start up Loompa with the number of forks to be run and what method of logging to use
loompa = Loompa.new(fork_num)
After this, I would call the start method and pass it a block, like so,
loompa.start do
  puts "I'm running"
  sleep 10;
end

The code will block and continuously print "I'm running" until I press ^C. The Loompa spawn will print the message, sleep ten seconds, then unregister itself with the parent process and die. The parent process will start up a new child process to fill in the gap left by the vacated spawn.

The Loompa spawn will be listening for the INT, TERM, and HUP signals and will die if it receives any one of them. Along with this, the parent and each child shares two IO pipes to connect them in which they will be listening for each other. If the parent process dies, the children will not have received a "ping" from it and will commit sepuku as soon as their block is done executing.

The library still has a ways to go. If you have a long running block and the parent process dies, the children will continue to execute. If you have something like Monit keeping processes alive, it will recognize that the parent process is gone and will start a completely new stack. You could easily run into a situation where your memory disappears and the CPU load goes into the 400s. The best thing to do is make sure your processes don't run for more than, say, 10 minutes. The situation still exists but it may be minimized by that.

You can also start Loompa with a logging module/class
loompa = Loompa.new(fork_num, Logger)
It expects the logger to have at least three methods, info, debug, and error. Here's the default logger included in Loompa:
module DefaultLogger
  def DefaultLogger.info(msg)
    STDOUT.puts msg
  end
  
  def DefaultLogger.debug(msg)
    STDOUT.puts msg
  end
  
  def DefaultLogger.error(msg)
    STDOUT.puts msg
  end
end

Good luck :)

Thursday, July 8, 2010

RVM

I've been trying to get RVM to work for about three hours now. The problem I was having is that I can install and view all the different rubies I have installed but I can't seem to be able to use any of them. I had installed it using the root user on an Ubuntu 4.4.3-4ubuntu5 system.
rvm use 1.9.1

info: Using ruby 1.9.1 p378
Doesn't work. It would still stick with my default ruby.
ruby -v
ruby 1.8.7 (2010-04-19 patchlevel 253) [x86_64-linux], MBARI 0x6770,
Ruby Enterprise Edition 2010.02

It turns out I needed to add this little line to my /etc/profile,
if [ -s "$HOME/.rvm/scripts/rvm" ] ; then
  . "$HOME/.rvm/scripts/rvm"
elif [ -s "/usr/local/rvm/scripts/rvm" ] ; then
  . "/usr/local/rvm/scripts/rvm"
fi
Then source it;
root@socialstats:~# source /etc/profile
root@socialstats:~#

Viola! I have rubies that work now!
root@socialstats:~# rvm use 1.9.1

info: Using ruby 1.9.1 p378
root@socialstats:~# ruby -v
ruby 1.9.1p378 (2010-01-10 revision 26273) [x86_64-linux]
root@socialstats:~# 

There's an entire script out there that you can run. Just do a search for "rvm use"

Wednesday, July 7, 2010

XML Builder

I've been using a nifty little thing called XML Builder at work lately. It takes a hash and turns it into XML. I'm using it for FusionCharts. It's actually extremely nice, demonstration:
xml = Builder::XmlMarkup.new
xml.sample(:escaped=>"This&That", :unescaped=>:"Here&There")
xml.target!  =>
  <sample escaped="This&That" unescaped="Here&There"></sample>
I got that one from this website
Basically, what I do is build a hash, say, like this:
hash = [{:label => "a label"}, {:value => "value1"}]
Then, I begin building the xml markup like so:
xml = Builder::XmlMarkup.new
xml.chart(:xAxis => "xaxis", :yAxis => "yaxis") do
  xml.label = hash[0][:label]
  xml.value = hash[1][:value]
end

This is the result:
<chart xAxis="xaxis" yAxis="yaxis">
  <label>a label</label>
  <value>value1</value>
</chart>


That little bit of xml up there fits nicely into some of those charts in Fusion Charts. With a bit of modification, it can be made to fit into any of the charts in Fusion Charts.

Ruby In Your Website

Apparently you can run Ruby as a client side script just like Javascript. Check out this site, http://hotruby.yukoba.jp/

I haven't had the opportunity to check this out in depth but it sounds like an awesome idea. I'll try and look into it later and post more information on it.

I did find, however, that you can use Ruby code to generate your own swf files using Ming, http://mingruby.rubyforge.org/
Again, it looks awesome but I haven't delved in yet.

Tuesday, July 6, 2010

Ruby Strings

It turns out there are several ways to create strings. Here's the ones I know:
  • heredoc
  • String.new
  • String("")
  • String('')
  • using single quotes
  • using double quotes
  • General delimited strings
  • %Q, %q, %x
And now, a bit more on each of these

Heredocs are pretty common across different scripting languages. An example would be this,
a_string = <<HEREDOC
this is some text that
keeps whatever formatting
I give it. Including new lines and tabs
HEREDOC

The last HEREDOC must be on its own line. You can use anything you want. Example:
a_string = <<ANYTHING_YOU_WANT
a string using a heredoc with anything you want

ANYTHING_YOU_WANT

Enough about heredocs.

Next I listed would be the String.new method. All it does is initialize an empty string
str = String.new
puts str
""

str = String; str = ''; str = ""; str = String(''); str = String("")
Same as String.new

A note about single vs double quotes. Single quotes translate the string literally whereas double quotes translate the escaped characters into tabs, newlines, etc.
str = 'a string\nwith a newline character'
puts str
a string\nwith a newline character

str = "a string\nwith a newline character"
puts str
a string
with a newline character

General delimited strings!! These are nice. Those other methods are just.. hm.. but delimited strings, what power!
Demonstration:
str = %^this is a string^
puts str
this is a string

You can use whatever delimiter (nearly) you want to use.
%Q acts the same as double quotes and %q acts the same as single quotes.
%x acts just like backticks, ``. That means you can wrap system commands in %x instead of using backticks :)

You can always checkout strings from ruby-doc.org

Bye

Blog Purpose

I figured you'd want to know the purpose of this blog. It's not quite a blog to impart my knowledge to others but I don't mind sharing what I learn. I'm starting this blog as a sort of journal of what I learn in Ruby. Feel free to use the information I post to your advantage :)