Rails controversy – Zed Shaw gets Dreamhost support!

All hell broke loose after Zed Shaw (the guy behind Mongrel) wrote a post claiming Rails is Ghetto. In the post he points out the ugly part of “Rails Community”.

“This is that rant. It is part of my grand exit strategy from the Ruby and Rails community. I don’t want to be a ‘Ruby guy’ anymore, and will probably start getting into more Python, Factor, and Lua in the coming months. I’ve got about three or four more projects in the works that will use all of those and not much Ruby planned. This rant is full of stories about companies and people who’ve either pissed in my cheerios somehow or screwed over friends..”

Now Dreamhost (one of the biggest web hosts out there) comes with a rant on the technical problems with Ruby on Rails. Following sums up the whole post.

I don’t have anything to add to Zed Shaw’s comments about how the Rails development team operates as I don’t have any personal knowledge of that. What I do have personal knowledge of is how difficult it can be to get a Rails application up and running and to keep it running. DreamHost has over 10 years of experience running applications in most of the most popular web programming frameworks and Rails has and continues to be one of the most frustrating.

The main problems pointed out by DH blog are,

  • Performance problems
  • Poor support for shared hosting platform
  • Backward compatibility issues

Also worth noting…

It’s all good and fine to recommend that users use higher end dedicated server hosting for their commercial applications but you simply cannot ignore the fact that nearly everyone will want to use lower cost shared hosting for getting started. It’s just simple economics. Additionally, people who use systems like Ruby on Rails want to spend time programming and not time setting up servers. Recommending technologies that are not widely used or supported by any major web hosting company is putting too much of a burden on your users, the people you want to keep happy! It’s a good thing we never even tried to switch our system to support Lighttpd and SCGI, too, because 6 months later the ‘in thing’ in the Rails community had shifted to Mongrel, instead.

Advanced Ruby – Dynamic code execution

One of the advanced features of Ruby, which is behind the success of rails is the dynamic code execution. Code fragments can be executed using eval method. This is very similar to JavaScript eval function.

following is an example,

eval "x =10; puts x;" # print 10 using dynamic code execution

eval executes the code in the current context. It is also possible to execute the code in a different context.

Code can also be executed in class context using another method class_eval. class_eval can add methods due to a class during execution! In the following example, we add a method doHello to the Sample class during execution of initialize. Then we execute doHello!

class Sample
  def initialize
    Sample.class_eval "def doHello; puts 'Hello World';end"
  end
  m = Sample.new
  m.doHello
end

Now this is the technique which is behind the secret of attr_accessor used in classes. In fact attr_accessor is just a method. We will try to create a similar functionality using attr_accessor2. All the classes in Ruby are subclassed automatically from the class Class. Hence we will modify Class and add attr_accessor2 method which in turn will add getter and setter methods for the passed variable!

class Class
  def attr_accessor2(var_name)
    string_val = "def #{var_name}; "+
                 "   @#{var_name}; "+
                 "end; "+
                 "def #{var_name}=(value);"+
                 "   @#{var_name} = value;"+
                 "end; "
   self.class_eval string_val
  end
end

# Using the new attribute accessor method!
class M
  attr_accessor2 :test_var

  m = M.new
  m.test_var = "hello"
  puts m.test_var
end

Interacting with Ruby’s runtime environment

In this post I will look at various ways of interacting with a Ruby program’s runtime environment. Following sample program has methods to identify the operating system platform, environment variables in the OS and finding out the command line parameters.

class EnvSample
  
  # how to detect operating system platform
  # check presence of win32 for Windows, linux for Linux etc.
  def printOSInfo
    puts RUBY_PLATFORM # RUBY_PLATFORM constant contains OS info  
  end
  
  # how to get enviornment variable in Ruby
  # ENV constant contains a hash of enviornment variables
  def printEnvVariables
    puts ENV.inspect
  end
  
  # how to get command line parameters in Ruby
  # ARGV constant contains command line parameters
  def printCommandParams
    puts ARGV.inspect # ARGV[0] represents first parameter
  end
  
  e = EnvSample.new
  e.printOSInfo # print OS info
  e.printEnvVariables # print enviornment variables
  e.printCommandParams # print command line parameters
end

CSV processing in Ruby

Ruby is a relatively young language. One of the advantages with this is that Ruby has libraries for common programming needs. In this post, I will show you how easy it is to process CSV files in Ruby.

A CSV file contains comma separated values and is an easy way to store information in text files. In many Web applications, CSV file is generated and is output as excel filetype so that Microsoft excel program can process it.

For this example, let us consider the following CSV file. It contains exam results of 3 students.

Jayson Joseph,39,fail
Thomas Mathew,92,pass
Ravikumar,83,pass

Save this as examresults.txt. Following program shows how this can be read using Ruby. In this example, we will read the exam results, print the name of the people who failed the exam and finally add one more entry to the exam results file. All this can be achieved with minimal plumbing code!

require "csv"
class CSVExamResults
  
  def initialize(filename)
    puts "setting filename=",filename 
    @filename = filename
  end
  
  def printExamResults
    @results = CSV.read(@filename)
    puts @results.inspect
  end
  
  def printFailedGuys
    failed = @results.find_all do |r|
      r[2]=="fail"
    end
    puts "Following guys failed the exam:"
    failed.each {|m| puts m[0]}
  end
  
  def addSampleResult
    @results << ["Reema","76","pass"]
    CSV.open(@filename, 'w') do |csv|
      @results.each do |result|
        csv << result
      end
    end
  end
  
  c1 = CSVExamResults.new("examresults.txt")
  c1.printExamResults # displays CSV as two dimensional array
  c1.printFailedGuys # this prints the names of the guys who failed!
  c1.addSampleResult()
  c1.printExamResults # print updated csv file
end

Check out the documentation for complete set of methods available in csv library!

Ruby 1.9.0 development version released

A new development version of Ruby (1.9.0) was released last week. Currently this release is not intended for production use.  There are incompatibilities with 1.8.x series and 1.9.0 is more of a stepping stone for the upcoming 2.0 release.

So what is new in Ruby 1.9.0? Here is a summary,

  • Block arguments are local now. This can break existing code.
  • Introduced a new class called BasicObject.
  • Kernel and Module packages extended.
  • Regular expression engine upgraded.
  • Native threading support.
  • Offers literal hash syntax for parameters. :action = “helloworld” becomes action: “helloworld”.
  • And many more….

It is important to learn these as the next stable version 2.0 will look very much similar to 1.9.0.

Ruby code snippets : RPN Generator

The following program gives good illustration of string functions, regular expressions and blocks. This is a solution to the Reverse Polish Notation generator problem explained at http://www.spoj.pl/problems/ONP/.

Given an algebraic expression with brackets, this program will output the corresponding RPN form. For example, (a+(b+c)) becomes abc++. A good exercise will be to extend this program to use operator precedence in addition to brackets. But that would probably need a better algorithm.

# converts an infix algebraic expression to reverse polish notation (rpn)
# for example, (a+b)+c becomes cab++
# Note that braces are mandatory in this version : (a+(b+c)) works but not (a+b+c)
# This uses token replacement technique: (a+(b+c)) becomes (a+A) and then B where A = bc+ and B is aA+. 
# Finally A,B,.. etc are replaced by their original expression using a hash.
class RPNGenerator
  attr_accessor :lookup_token;
  attr_accessor :lookup_hash;
  
  @@SIMPLEST_EXP_REGEX = /[a-z|A-Z][\+\-\*\/\^][a-z|A-Z]/;
  @@ENCODED_REGEX = /[A-Z]/;
  
  def initialize
    @lookup_token = "A"; #each lowest expression tokens are replaced using this
    @lookup_hash = Hash.new
  end

  # Process the infix expression and return RPN
  # Modifies the original expression
  def process(infix_exp)
    substitute(infix_exp)
    expandRpn(infix_exp)
    infix_exp
  end
  
  # This substitutes the lowest level of expressions without braces to single capital letter tokens.
  # So final output will be a single capital letter.
  # Example -> (a+(b+c)) ->(a+A) -> B
  def substitute(infix_exp)
    simple_exp = infix_exp.scan(@@SIMPLEST_EXP_REGEX)
    simple_exp.each do
      |exp|
      rpn = exp[0].chr+exp[2].chr+exp[1].chr
      @lookup_hash[@lookup_token]=rpn
      infix_exp.sub!("("+exp+")",@lookup_token)
      @lookup_token.next! # get the next unique replacement token
    end
    substitute(infix_exp) if infix_exp.scan(@@SIMPLEST_EXP_REGEX).length > 0
  end

  # Expand the single capital letter token to RPN form using the supporting hash
  # Example -> B -> aA+ -> abc++
  def expandRpn(shortForm)
    shortForm.each_byte do |enc_char|
      enc_char = enc_char.chr
      shortForm.sub!(enc_char,@lookup_hash[enc_char]) if @lookup_hash[enc_char] !=nil
    end
    expandRpn(shortForm) if shortForm.scan(@@ENCODED_REGEX).length > 0
  end
  
  puts "Enter an infix expression: "
  infix = gets # get infix expression from user
  rpn = (RPNGenerator.new).process(infix)
  puts "Equivalent RPN expression is: #{rpn}" 
end

Ruby code snippets : fibonacci series

One of the best ways to start learning Ruby is to try out simple programming problems. Let us see how we can generate fibonacci series using Ruby,

# Generates a fixed length fibonacci series
class FibonacciGenerator
  
  # print fixed number of fibonacci series numbers specified by size
  def printFibo(size)
    x1,x2 = 0, 1
    0.upto(size){puts x1;x1+=x2; x1,x2= x2,x1} # note the swap for the next iteration
  end
  
  f = FibonacciGenerator.new
  f.printFibo(10) # print first 10 fibo numbers
  
end

This is a verbose an example. You could achieve the same in a single line!


x1,x2 = 0, 1;  0.upto(size){puts x1;x1+=x2; x1,x2= x2,x1}

Starting Ruby development – Day 1 – Install Ruby and Aptana IDE

In the following days I will cover how you can quick start your Ruby learning. Today we will start with Ruby installation and IDE setup.

The first thing you need is a decent IDE so that you can quickly try out Ruby programs. Ruby installation comes with command line tools such as “irb”. But for any real development, a good IDE is necessary. In this example, I will use Aptana IDE which is based on RadRails.

Step 1 : Download and install latest Ruby release.

Step 2: Download and install Aptana IDE.

Step 3: From Aptana IDE, install Ruby extensions (you can exclude rails extensions for faster install). From Aptana, click on Help->Software Updates->Find and Install->Search for new features for install.

Step 4 : Create a Ruby project from Aptana IDE. You can keep all the sample Ruby programs you write here.

Step 5: Write the following sample code in file named “HelloWorld.rb” and click on “Run HelloWorld.rb”. You should see your first Ruby program output!

class HelloWorld
  def doHello()
    puts "Hello World"
  end
end

HelloWorld.new().doHello()

Top 5 Ruby projects you must check out

Ruby invasion into the programming world has been swift in the last few months. Obviously one of the reasons was the elegance of the language. But more importantly ruby popularity is driven by tools written on it. It is an open secret that much of the credit goes to Ruby on Rails Web application framework by David Heinemeier Hansson. In this post, I will look at some of the influential tools written on top of Ruby.

rubyonrails.pngRuby on Rails – Arguably the most popular tool written on Ruby. Ruby on Rails is an Agile web application framework which boosts programmer productivity. It uses convention over configuration to cut down on the manual coding. The productivity boost in Rails is due to Ruby elegance and also due to automatic code generation from data model. There are numerous Web apps written on Ruby on Rails – For example, Basecamp and Shopify

typo.gifTypo – Typo is a lean blogging tools powered by Ruby and Ruby on Rails. It is also open source and free. It supports comments, trackbacks/ping, export function and full text search.

logo-big.gifRMagick –  RMagick provides an extension which provides access to ImageMagick and GraphicsMagick image processing libraries from Ruby. Supports a huge set of image formats and comprehensive image processing API.

Instiki – Instiki is a Wiki clone based on Ruby on Rails. It is also possible to use this as a lightweight CMS. David Heinemeier Hansson is one of the project admins. Instiki features all standard wiki features such as file uploads, password protection and feed support. Also provides markup choice between Textile, Markdown and Rdoc.

watir.gifWatir –  Watir is an automatic Web application testing tool written in Ruby. This tool allows you to record user actions and then replay them whenever you want to test the Web app. It also comes with developer toolbar extension for internet explorer.

Really compact Ruby quick reference guide

Hello World in Ruby

puts "Hello, world!"

General Rules
Comments start with # and ends with newline
Newlines or semicolon can be used separate expressions
Everything in Ruby is an object. This includes constants such as 5
Since even operators are methods, they can be overridden
Elegant code can be written using blocks feature

Ruby Keywords

alias   and     BEGIN   begin   break   case    class   def     defined 
do      else    elsif   END     end     ensure  false   for     if 
in      module  next    nil     not     or      redo    rescue  retry 
return  self    super   then    true    undef   unless  until   when 
while   yield

Ruby Types
Basic types are numbers, strings, ranges, regexen, symbols, arrays, and hashes.

Symbols
:symbol
Unique and comparable values that can be substituted for string keys.

Ranges
1..10 – includes last value (10)
1…10 – excludes last value (10)

Arrays
var = Array.new
var = [10,20]
var = %w (string1,string2)

Hashes
var = Hash.new
var = {1=>2, 2=>3, 3=>4}

Variable Types
$global_variables
@@class_variables
@instance_variables
CONSTANT (caps)
local_variables

Dummy Variables
self – current method’s object
nil
true,false
__FILE__
__LINE__

Predefined Variables

$!         The exception message set by raise call. 
$@         Array of backtrace of the last exception thrown. 
$&         The string matched by the last successful pattern match. 
$`         The string to the left  of the last successful match. 
$'         The string to the right of the last successful match. 
$+         The last bracket matched by the last successful match. 
$1         The Nth group of the last successful match. May be > 1. 
$~         The information about the last match. 
$=         The flag for case insensitive, nil by default. 
$/         The input record separator, newline by default. 
$         The output record separator for the print and IO#write. 
$,         The output field separator for the print and Array#join. 
$;         The default separator for String#split. 
$.         The current input line number of the last file that was read. 
$<         The virtual concatenation file of the files from command line. 
$>         The default output for print, printf. $stdout by default. 
$_         The last input line of string by gets or readline. 
$0         Contains the name of the script being executed. 
$*         Command line arguments given for the script sans args. 
$$         The process number of the Ruby running this script. 
$?         The status of the last executed child process. 
$:         Load path for scripts and binary modules by load or require. 
$"         The array contains the module names loaded by require. 
$DEBUG     The status of the -d switch. 
$FILENAME  Current input file from $<. Same as $<.filename. 
$LOAD_PATH The alias to the $:. 
$stderr    The current standard error output. 
$stdin     The current standard input. 
$stdout    The current standard output. 
$VERBOSE   The verbose flag, which is set by the -v switch.

Operator Precedence (highest to lowest)
:: .
[]
**
-(unary) +(unary) ! ~
* / %
+ –
<< >>
&
| ^
> >= < <=
<=> == === != =~ !~
&&
||
.. …
=(+=, -=…)
not
and or

Ruby Control Structures

if boolean-expression [then]
code-block
elsif boolean-expression [then]
code-block
else
code-block
end

unless boolean-expression [then]
code-block
else
code-block
end

expression if boolean-expression

expression unless boolean-expression

case target-expr
when comparison [, comparison]… [then]
code-block
when comparison [, comparison]… [then]
code-block
[else
code-block]
end

loop do
code-block
end

while boolean-expression [do]
code-block
end

until boolean-expression [do]
code-block
end

begin
code-block
end while boolean-expression

begin
code-block
end until boolean-expression

for name[, name]… in expression [do]
code-block
end

expression.each do | name[, name]… |
code-block
end

expression while boolean-expression

expression until boolean-expression

Method Invocation and Definition
method_call
object.method_call
Class::method_call

def method_name
method_body
end

Blocks
method_invocation do … end
method_invocation {

}

Exception Handling (2 forms)

begin
  code_block
rescue
  error_handler
ensure
  must_execute_even_on_error
end

catch (:label_key) do ... end
throw :label_key jumps back to matching catch.

Classes

class Name < superclass

private
  class_body

public
  class_body

protected
  class_body

end

Accessor Shortcuts
attr_reader
attr_writer
attr