LearnRuby.com

Ruby Training and Ruby on Rails Training exclusively

Ann Arbor Java Users' Group Code Examples

Here is a recap of the talk Eric gave at the February 7, 2006 Ann Arbor Java User's Group (AAJUG) meeting.

Some Links to Help You Get Started

The Southeast Michigan Ruby Users' Group has regular meetings. The web site allows you to get on the mailing list and to see a calendar of events.

The official Ruby web site has a lot of information about the Ruby language itself.

The official Ruby on Rails web site is the hub for information on Rails. In addition to having the full API, there are lots of useful how-to's in the associated wiki.

O'Reilly's Rolling with Ruby on Rails contains a brief introduction along with installation instructions.

O'Reilly's book sales charts that compare the volume of various categories of books over two years.

Additional links can be found on the Ruby Web Sites page.

Ruby Code Examples

controls.rb

Demonstrates the central control structures.
# example with cascading-if

age = 12

if age <= 1
    puts "infant"
elsif age <= 2
    puts "toddler"
elsif age <= 9
    puts "child"
elsif age <= 12
    puts "young adult"
elsif age <= 19
    puts "teenager"
elsif age <= 64
    puts "adult"
else
    puts "senior"
end


# example with cascading-if returning a value

age_category =  if age <= 1
                    "infant"
                elsif age <= 2
                    "toddler"
                elsif age <= 9
                    "child"
                elsif age <= 12
                    "young adult"
                elsif age <= 19
                    "teenager"
                elsif age <= 64
                    "adult"
                else
                    "senior"
                end


# example of if modifier

discount_percent = 15 if items_bought >= 10


# example of case statement

hour_24 = 23

case hour_24
when 1..11 then
    hour_12 = hour_24
    meridian = "am"
when 12 then
    hour_12 = hour_24
    meridian = "pm"
when 13..23 then
    hour_12 = hour_24 - 12
    meridian = "pm"
else    # hour_24 must be 0 (just past midnight)
    hour_12 = 12
    meridian = "am"
end

puts "The time is #{hour_12}:00 #{meridian}."


# example with while pre-test loop

while line = gets
    # process line
end


# example with while post-test loop

begin
    puts "What is the password?"
    password = gets.chomp
end while password != "aajug"


# example with while modifier

min_value = 83165
power_of_2 = 1
power_of_2 *= 2 while power_of_2 < min_value
puts "First power 2 two that is at least #{min_value} is #{power_of_2}."

Circle.java

A simple class written in Java.
public class Circle {
    double x, y, radius;

    public Circle (double x, double y, double r) {
        this.x = x;
        this.y = y;
        radius = r;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double newRadius) {
        radius = newRadius;
    }

    public double getArea() {
        return Math.PI * radius * radius;
    }

    public static void main(String[] arguments) {
        Circle c1 = new Circle(3, 4, 5);
        System.out.println(c1.getArea());
        c1.setRadius(8);
        System.out.println(c1.getArea());
    }
}

Circle.rb

The equivalent class written in Ruby.
class Circle
    attr_accessor :radius           # creates 2 methods: "radius" and "radius="

    def initialize(x, y, r)         # acts like a constructor
        @x, @y, @radius = x, y, r   # multiple assignment
    end

    def area
        Math::PI * @radius ** 2     # "**" is the power operator
    end
end

c1 = Circle.new(3, 4, 5)            # new instantiates then calls "initialize"
puts c1.area
c1.radius = 8
puts c1.area

blocks.rb

Demonstrates arrays and blocks in Ruby.
# define an array
stooges = ["Larry", "Moe", "Curly"]


# access the array in various ways
puts stooges           # produces: Larry Moe Curly
puts stooges[1]        # produces: Moe
puts stooges[1..2]     # produces: Moe Curly
puts stooges[-1]       # produces: Curly
puts stooges[-2..-1]   # produces: Moe Curly


# append to the end of an array
stooges << "Shemp"
puts stooges           # produces: Larry Moe Curly Shemp


# loop using for
for s in stooges
    puts "#{s} is a stooge."
end


# loop using block delineated by braces
stooges.each { |s| puts "#{s} is a stooge." }


# loop using block delineated by do/end
stooges.each do |s|
    puts "#{s} is a stooge."
end


# nested blocks example
stooges.each do |s1|
    stooges.each do |s2|
        puts "#{s1} pokes #{s2}" if s1 != s2
    end
end

blocks-loops.rb

Demonstrates some other ways to execute loops in Ruby using blocks.
# Loop a specified number of times
5.times { puts "Hello World!" }


# Loop with a counter going from 1 to 10
1.upto(10) { |i| puts "#{i}. Hello World!" }


# Loop with a counter going from 1 to 100 by 7
1.step(100, 7) { |j| puts "#{j}. Hello World!" }


# Loop from 44 to 55
(44..55).each { |k| puts "#{k}. Hello World!" }


# Read a file of numbers, one per line, and compute the mean average
count, sum = 0, 0.0
File.open("numbers.txt") do |file|
    file.each_line do |line|
        count += 1
        sum += line.to_f
    end
end
puts "Count is #{count}; total is #{sum}; mean average is #{sum / count}."

# Read a file of numbers, one per line, and compute the mean average
count, sum = 0, 0.0
open("numbers.txt") do |file|
    file.each_line do |line|
        count += 1
        sum += line.to_f
    end
end
puts "Count is #{count}; total is #{sum}; mean average is #{sum / count}."

hashes.rb

Demonstrates basic operations on a Ruby hash.
# Create a hash providing ireegular plural for various animals
$plurals = { "calf" => "calves", "deer" => "deer",
    "fish" => "fish", "fox" => "foxes", "goose" => "geese",
    "mouse" => "mice", "octopus" => "octopi", "ox" => "oxen",
    "platypus" => "platypuses", "sheep" => "sheep", "wolf" => "wolves"}


# Looking up something in a hash uses array notation
puts $plurals["octopus"]
puts $plurals["ox"]


# Adjusting data in a hash also uses array notation
$plurals["octopus"] = "octopuses"              # overwrite mapping
$plurals["hippopotamus"] = "hippopotamuses"    # add new mapping


# This method will pluralize an animal using the hash or a standard rule
def pluralize(animal)
    irregular_animal = $plurals[animal]

    if irregular_animal then return irregular_animal
    else return animal + "s"
    end
end


# Some example method calls
puts pluralize("dog")
puts pluralize("sheep")
puts pluralize("mouse")
puts pluralize("octopus")


# A block with multiple parameters
$plurals.each_pair do |key, value|
    puts "The plural of \"#{key}\" is \"#{value}\""
end

hash-parameters.rb

Demonstrates optional/named parameters through the use of a hash.
class Circle
    attr_reader :radius, :circumference, :area

    def initialize(hash)
        @radius, @circumference, @area =
             hash[:radius], hash[:circumference], hash[:area]
        if @radius then
            @circumference = 2 * Math::PI * @radius
            @area = Math::PI * @radius ** 2
        elsif @circumference then
            @radius = @circumference / (2 * Math::PI)
            @area = Math::PI * @radius ** 2
        elsif @area then
            @radius = Math::sqrt(@area / Math::PI)
            @circumference = 2 * Math::PI * @radius
        else
            @radius, @circumference, @area = 0, 0, 0
        end
    end
end

c1 = Circle.new(:radius => 5)
c2 = Circle.new(:circumference => 11)
c3 = Circle.new(:area => 25)

puts c1.inspect
puts c2.inspect
puts c3.inspect

def temp_convert(from_temp, hash = {})
    from_unit = hash[:from] || :f
    to_unit = hash[:to] || :c

    fahrenheit = case from_unit
        when :f then from_temp
        when :c then from_temp * 9.0 / 5.0 + 32
        when :k then from_temp * 9.0 / 5.0 - 459.67
        else 0
    end

    to_temp = case to_unit
        when :f then fahrenheit
        when :c then (fahrenheit - 32) * 5.0 / 9.0
        when :k then (fahrenheit + 459.67) * 5.0 / 9.0
        else 0
    end

    to_temp
end

puts temp_convert(32)
puts temp_convert(212)

puts temp_convert(32, :to => :k)

puts temp_convert(0, :from => :c, :to => :f)
puts temp_convert(100, :from => :c, :to => :f)

require 'date'

# Note: does not produce perfect ISO dates, as month and day of month should
# always be two digits, with a leading "0" for values less than 10.

def date_display(date, params = {})
    format = params[:format] || :iso
    month_format = params[:month] || :numeric

    month = date.month
    day = date.day

    if format == :iso then        # guarantee two-digits in iso
        month = ("0" + month.to_s)[-2..-1]
        day = ("0" + day.to_s)[-2..-1]
    end

    month = case month_format
        when :numeric then month
        when :short then Date::ABBR_MONTHNAMES[date.month]
        when :long then Date::MONTHNAMES[date.month]
        else return "ERROR"
    end

    case format
        when :iso then "#{date.year}-#{month}-#{day}"
        when :us then "#{month}/#{day}/#{date.year}"
        when :europe then "#{day}/#{month}/#{date.year}"
        else "ERROR"
    end
end

d1 = Date.civil(2006, 4, 2)

puts date_display(d1)
puts date_display(d1, :month => :short)
puts date_display(d1, :month => :long)
puts date_display(d1, :format => :us)
puts date_display(d1, :format => :europe)
puts date_display(d1, :format => :us, :month => :short)
puts date_display(d1, :month => :really_long)

logging.rb

Demonstrates the power of Duck Typing!
require 'date'

class Logger
    def initialize(log)
        @log = log
    end

    # the only operation performed on @log is append (<<)
    def add_message(message)
        @log << DateTime.now.to_s + ": " + message + "\n"
    end
end

# test the logger by putting the entries in an array
array_log = []
logger1 = Logger.new(array_log)
logger1.add_message("test 1")
logger1.add_message("test 2")
logger1.add_message("test 3")
puts array_log

# test the logger by putting the entries in a file
file_log = File.open("log.txt", "w")
logger2 = Logger.new(file_log)
logger2.add_message("test a")
logger2.add_message("test b")
logger2.add_message("test c")
file_log.close

# the magic of Duck Typing!

cubed.rb

Demonstrates that classes are always "open"
# add a cubed method to the Numeric class
# cubed will be inherited by Fixnum, Bignum, and Float

class Numeric
    def cubed
        self ** 3
    end
end

puts 2.cubed
puts 2.2.cubed
puts (2 ** 32).cubed

puts 2.class
puts 2.2.class
puts (2 ** 32).class

ends_with.rb

Demonstrates that classes are always "open"
# add an ends_with method to the String class

class String
    def ends_with(ending)
        reg_exp = Regexp.new("#{ending}$")
        reg_exp.match(self)
    end
end

s1 = "Hello World!"

puts "match" if s1.ends_with("!")
puts "match" if s1.ends_with("orld!")
puts "no match" unless s1.ends_with("World")

mix-in.rb

Demonstrates the power of module mix-ins.
# define a Circle class, mix-in the Comparable module, and
# define the <=> operator
class Circle
    include Comparable

    attr_accessor :radius

    def initialize(x, y, r)
        @x, @y, @radius = x, y, r
    end

    def area
        Math::PI * @radius ** 2
    end

    def <=>(other)
        return radius <=> other.radius
    end
end


# now create two Circles
c1 = Circle.new(3, 4, 5)
c2 = Circle.new(10, 11, 5.2)
c3 = Circle.new(-3, -20, 5)

puts c1 <=> c2
puts c2 <=> c1
puts c1 <=> c3



# now test the six operators defined by the Comparable mix-in
puts "c1 == c2" if c1 == c2
puts "c1 != c2" if c1 != c2
puts "c1 < c2" if c1 < c2
puts "c1 > c2" if c1 > c2
puts "c1 <= c2" if c1 <= c2
puts "c1 >= c2" if c1 >= c2