ruby tutorial with code samples

31
12/14/2015 Ruby Tutorial with Code Samples http://www.fincher.org/tips/Languages/Ruby/ 1/31 Ruby for the Attention Deficit Disorder Programmer let's start learning Ruby fast! "Java is a pair of scissors, Ruby is a chainsaw." 1. Install Ruby For windows you can download Ruby from http://rubyforge.org/frs/?group_id=167 for Linux try http://www.rpmfind.net . 2. Our first program Enter the following into the file, "test.rb". ɑŠɑ At the C: prompt enter, :> . This produces: Howdy! OK, daylight's burning, let's move on. 3. Output in Ruby "puts" writes to the screen with a carriage return at the end. "print" does the same thing without the carriage return. "printf" formats variables like in C and Java 5. ɑ ɑ ɑ Ŝɑ ɑ ɑ ɑ Ŝɑ (ɑɎɎ ʩɮŜɩř %.ɑřɪŜɨɫɨɬɭřɑɑƀ This produces: puts works with line breaks. print works with no line breaks.

Upload: saree

Post on 29-Jan-2016

37 views

Category:

Documents


0 download

DESCRIPTION

ruby programming

TRANSCRIPT

Page 1: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 1/31

Ruby for the Attention Deficit Disorder Programmer ­ let's start learningRuby fast!

"Java is a pair of scissors, Ruby is a chainsaw."

1. Install RubyFor windows you can download Ruby from

http://rubyforge.org/frs/?group_id=167 for Linux tryhttp://www.rpmfind.net.

2. Our first programEnter the following into the file, "test.rb".

puts "Howdy!"

At the C: prompt enter,

C:>ruby test.rb

This produces:

Howdy!

OK, daylight's burning, let's move on.

3. Output in Ruby

"puts" writes to the screen with a carriage return at the end. "print" does the same thing without the carriage return. "printf" formats variables like in C and Java 5.

puts "puts works" puts " with line breaks."

print "print works" print " with no line breaks."

printf("\n\nprintf formats numbers like %7.2f, and strings like %s.",3.14156,"me")

This produces:

puts works with line breaks.

print works with no line breaks.

Page 2: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 2/31

print works with no line breaks. printf formats numbers like 3.14, and strings like me.

4. Reading from the ConsoleUse "gets"

puts "What is your name?" $name = STDIN.gets puts "Hi "+$name

5. FunctionsA. Our first Ruby function

'def' starts the definition of a method, and 'end' ends it ­ nocute little curly braces.

def welcome(name) puts "howdy #name" # inside double quotes, # will evaluate the variableend welcome("nana") # traditional parens

This Produces:

howdy nana

B. Parentheses are optional

def welcome(name) puts "howdy #name" # inside double quotes, # will evaluate the variableend welcome "visitor" #look, ma, no parentheses

This Produces:

howdy visitor

The same is true of methods without arguments

"hello".upcase() => "HELLO" "hello".upcase => "HELLO"

C. How to return values from a functionWe can use the faithful 'return'

Page 3: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 3/31

def multiply(a,b) product = a * b return product end puts multiply(2,3) =>6

Oddly enough you can leave out the "return" statement, andRuby will helpfully return the last expression:

def mult(a,b) product = a * b end puts mult(2,3)

or even simpler, leave out "product" and ruby returns thecontents of the last expression:

def mult(a,b) a * b end puts mult(3,3) =>9

D. Optional argument valuesRuby lets you assign values to arguments which may, or may

not be supplied as shown below:

def test(a=1,b=2,c=a+b) puts "#a,#b,#c" end test => 1,2,3 test 5 => 5,2,7 test 4, 6 => 4,6,10 test 3, 4, 6 => 3,4,6

E. Extra argumentsExtra arguments are gathered into the last variable if

preceded with a "*". ("each" is an iterator that loops over itsmembers).

def test(a=1,b=2,*c) puts "#a,#b" c.each|x| print " #x, " # We will learn about "each" very soon. I promise.end test 3, 6, 9, 12, 15, 18

This produces:

3,6 9, 12, 15, 18,

Page 4: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 4/31

F. Multiple return values

def getCostAndMpg cost = 30000 # some fancy db calls go here mpg = 30 return cost,mpg end AltimaCost, AltimaMpg = getCostAndMpg puts "AltimaCost = #AltimaCost, AltimaMpg = #AltimaMpg"

Produces:

AltimaCost = 30000, AltimaMpg = 30

6. Open ClassesYou can add methods to existing library classes. For example, in

C# 2.0, Microsoft added the very helpful string function,IsNullOrEmpty() which replaces the unwieldly construct: if(mystring != null && mystring != "") In Ruby you don't have to wait for the mavens in Redmond to decideyou need a new string function, you can add it yourself.

class String def NullOrEmpty? (self == nil || self == "") end end puts "test".NullOrEmpty? puts "".NullOrEmpty?

Is this way cool? Yes. Is this very dangerous? Yes. Remember,Ruby is a chainsaw.

7. Variable namingOk, let's slow down and learn some basics about variable names

A. Global variables start with '$'B. Class variables start with '@@'C. Instance variables start with '@'D. Local variables, method names, and method parameters start

with a lower case letterE. Class names, module names and constants start with an

uppercase letterF. Variables names are composed of letters, numbers and

underscoresG. Method names may end with "?", "!", or "=". Methods ending

with a "?" imply a boolean operation (eg, "instance_of?").Methods ending with "!" imply something dangerous, likestrings being modified in place (eg, "upcase!")

8. Interesting tidbits about Ruby,

Page 5: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 5/31

A. '#' is the line comment character, all characters after this areignored. Confusingly '#' can appear within quotes with adifferent meaning.

B. No semi­colons are needed to end lines, but may be used toseparate statements on the same line

C. A backslash (\) at the end of a line is used for continuationD. Indenting is not significant, unlike pythonE. Types of variables do not need to be declaredF. Lines between =begin and =end are ignoredG. Lines following "__END__" on its own line with no white

space, are ignoredH. A tiny demonstration of these:

# sample program showing special characters like comments # I'm a comment line a = 1 #notice no semicolon and no type declarationb = 2; c = 3 #notice two statements on one line name = "Abraham \ Lincoln" # a line continued by trailing \ puts "#name" =begin I'm ignored. So am I. =end puts "goodbye" __END__ 1 2 3 4

Abraham Lincoln goodbye

9. Variable TypesIn Ruby, variables don't have a specific type associated with them.

All variables are objects, so we only play with pointers to thoseobjects, and those pointers are type agnostic.

bat = "Louisville slugger" bat = 1.23

11. QuotesLike in Perl, single quotes and double quotes have different

meanings.Double quotes means "please interpret special characters in this

string". Things like backslash n ('\n') are converted to their typicalvalues. The #name construct is converted to its value.

With single quotes, no special characters are interpreted.Examples:

Page 6: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 6/31

name="Mike" puts "hi #name" =>hi Mike puts "hi\n #name" => hi (carriage return)Mike puts 'hi\n #name' => hi\n #name (no substitutions are made since using single quote)

The braces are optional for global and instance variables

$myname="Ishmael" puts "hi #$myname" =>hi Ishmael

12. ObjectsA great thing about Ruby is that numbers and strings are real

objects.

1.5.floor() => "1"

This lets us do some cool things. Instead of

if( x > 7 && x < 12 ) ...

We can write

if x.between?(7,12) do ...

13. Big NumbersRuby automatically increases the precision of variables

for i in 1..1000 puts "2 ** #i = #2**i" end

Produces:

2 ** 1 = 2 2 ** 2 = 4 2 ** 3 = 8 2 ** 4 = 16 2 ** 5 = 32 2 ** 6 = 64 2 ** 7 = 128 2 ** 8 = 256 2 ** 9 = 512 2 ** 10 = 1024 ... 2 ** 1000 = 10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376

Page 7: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 7/31

Ruby will increase the precision of the number, or decrease it asneeded:

x = 1000000 puts "#x "+x.class.to_s => 1000000 Fixnum x = x * x puts "#x "+x.class.to_s => 1000000000000 Bignum x = x / 1000000 puts "#x "+x.class.to_s => 1000000 Fixnum

14. Parallel AssignmentYou can swap the values in variables without the use of a temp

variable. Remember your first programming class: Swap the values in"i" and "j"? You had to use a "t" variable to store one of the valuesfirst. Not needed in Ruby.

i = 0 j = 1 puts "i = #i, j=#j" i,j = j,i puts "i = #i, j=#j"

Produces:

i = 0, j=1 i = 1, j=0

15. CollectionsA. Arrays

a. An array of known objects can be created by enclosing themin square brackets.

nums = [1, 2.0, "three"] puts nums[2] => three

Ruby arrays, like all right­thinking collections, are zerobased.

b. You can use negative indexes to start from the end of thearray

nums = [1, 2.0, "three", "four"] puts nums[­1] => four

Using "­1" is so much more concise than"nums[nums.length()­1]".

c. You can even use the handy "first" and "last" methods.

Page 8: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 8/31

[1,2,3].last => 3 [1,2,3].first => 1

d. lengthTo get the count, or size, of an array, use the "length"

method.

mystuff = ["tivo","nokia", "ipaq"] # make a string array puts mystuff.length => 3

e. %w shortcutSince many arrays are composed of single words and all

those commas and quote marks are troublesome, Rubyprovides a handy shortcut, %w:

mystuff = %wtivo nokia ipaq # make a string array

f. inspectTo look at contents of an object use the "inspect" method.

Even more convenient is to use "p" as a shorthand for "putsobj.inspect"

myarray = [1,2,5,7,11] puts myarray puts myarray.inspect p myarray

Produces:

1 2 5 7 11 [1, 2, 5, 7, 11] [1, 2, 5, 7, 11]

g. Arrays can act like queues and sets

# & is the intersection operator puts [1,2,3] & [3,4,5] # prints 3

# + is the addition operator puts [1,2,3]+ [3,4,5] # prints 1,2,3,3,4,5

# ­ removes items from the first array that appear in the second puts [1,2,3] ­ [3,4,5] # prints 1,2

# pop returns the last element and removes it from the array alpha = ["a","b","c","d","e","f"] puts "pop="+alpha.pop # pop=f

Page 9: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 9/31

puts alpha.inspect # ["a", "b", "c", "d", "e"]

# push appends elements to the end of an array alpha = ["a","b","c"] alpha.push("x","y","z")puts alpha.inspect # ["a", "b", "c", "x", "y", "z"]

# shift returns the first element and removes it from the array alpha = ["a","b","c","d","e","f"] puts "shift="+alpha.shift # shift=a puts alpha.inspect # ["b", "c", "d", "e", "f"]

# unshift appends elements to the beginning of an array alpha = ["a","b","c"] alpha.unshift("x","y","z") puts alpha.inspect # ["x", "y", "z", "a", "b", "c"]

B. HashesThis type of collection is also called a dictionary or an

associative array.a. Simple hash of cars and their makers

cars = 'altima' => 'nissan', 'camry' => 'toyota', 'rx7' => 'mazda' puts cars['rx7'] => mazda

b. You can create a hash and fill it dynamically

dict = # create a new dictionary dict['H'] = 'Hydrogen' #associate the key 'H' to the value 'Hydrogen'dict['He'] = 'Helium' dict['Li'] = 'Lithium' p dict['H'] # prints "Hydrogen" p dict.length # prints 3 p dict.values # prints ["Lithium", "Helium", "Hydrogen"] p dict.keys # prints ["Li", "He", "H"] p dict # prints "Li"=>"Lithium", "He"=>"Helium", "H"=>"Hydrogen"

c. Hash[]You can also create Hashes with square brackets by

prefixing with "Hash":

toppings = Hash["pancakes","syrup","Pizza","Pepper","Cereal"puts toppings.inspect

Produces:

"Pizza"=>"Pepper", "Cereal"=>"Sugar", "pancakes"=>"syrup"

Page 10: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 10/31

d. eachThe "each" method is a wonderful way to iterate over the

keys

toppings = Hash["pancakes","syrup","Pizza","Pepper","Cereal"toppings.each|key, value| puts "#key points to #value"

Produces:

Pizza points to PepperCereal points to Sugarpancakes points to syrup

e. selectThe "select" method populates a new array with

members which meet a criteria

salaries = Hash["bob",10.9,"larry",7.5,"jimmy",6.0,"jerry",6.5salaries.inspect mySalaryArray = salaries.select|name,salary| salary > 7.0puts mySalaryArray.inspect #prints [["larry", 7.5], ["bob", 10.9]]

C. RangesRanges are composed of expr..expr or expr...expr. Two dots

includes the last element, three dots excludes it.

('a'..'g').each |letter| puts letter

Produces:

a b c d e f g

(1...3).each |num| puts num

Produces only two numbers since "..." does not include thelast element.:

1 2

Page 11: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 11/31

16. Control StatementsA. if In an "if" statement anything but the two special values,

"false" and "nil" are considered true. Even zero is true for allyou C/C++ programmers.

income = 30000.00 if income < 10000 rate = 0.02 elsif income < 30000 rate = 0.28 else rate = 0.5 end puts rate

B. case

grade = 10 school = case grade when 0..5 "elementary" when 6..8 "middle school" when 9..12 "high school" else "college" end puts "grade #grade is in #school"

C. for

for i in 1..4 puts "hi #i" end

The ranges can of course have variables

top = 6 for i in 1..top puts "hi #i" end

D. exit

lines = IO.readlines("data.txt") if lines.length < 100 exit 2 end puts lines.length

Page 12: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 12/31

E. loopiterates over code until a "break" or eternity ends

i=0 loop do break if i > 5 puts i i += 1 end

17. Statement modifiersThese are just syntatic sugar.

A. ifThe "if" clause may be placed at the end of a statement

balance = ­10.0 puts "Bankrupt" if balance < 0.0

B. unless"unless" is placed at the end of a statement

balance = ­10.0 puts "Bankrupt" unless balance > 0.0

C. while"while" may be after its block

f=2 puts f=f+2 while f < 10 =>4 =>6 =>8 =>10

18. IteratorsA. while

i = 0 while i < 5 i = i+1 puts i end

B. "times"

n = 10 n.times |i| print i

Page 13: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 13/31

Produces:

0123456789

C. "each"

animals = %w(lions tigers bears) animals.each|kind| print kind

lionstigersbears

D. "each" with ranges

('m'..'z').each |ch| print ch

mnopqrstuvwxyz

E. "upto"

n=0 ; max=7 n.upto(max) |num| print num

01234567

19. You gotta have class.A. Classes

Class definitions start with "class" and end with "end".Remember that class names start with a capital letter. Notice thesyntax is "object.new" for creating an object and that the"initialize" method contains code normally found in theconstructor. Here's a small example:

class Person def initialize(fname, lname) @fname = fname @lname = lname end end person = Person.new("Augustus","Bondi") print person

Produces:

#<Person:0x257c020>

Page 14: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 14/31

which is true, but not helpful.

B. The "ToString" method, to_s

class Person def initialize(fname, lname) @fname = fname @lname = lname end def to_s "Person: #@fname #@lname" end end person = Person.new("Augustus","Bondi") print person

Produces:

Person: Augustus Bondi

C. SubclassingIn Ruby subclassing is done with the "<" character

class Employee < Person def initialize(fname, lname, position) super(fname,lname) @position = position end def to_s super + ", #@position" end end employee = Employee.new("Augustus","Bondi","CFO") print employee

Produces:

Person: Augustus Bondi, CFO

if we try to print the first name directly like

print employee.fname

we get the error message,

CFOtest.rb:21: undefined method 'fname'

But why is that? We've printed variables a zillion times up tilnow and it's always worked. What changed? Up until now we'vecreated variables in a program without classes (actually all arevariables were members of a default object that were accessable

Page 15: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 15/31

inside itself). Now we are using real classes and that brings upthe point of visibility of members outside the class. We now haveto specify if a variable is open to the outside, like "public","private", "protected", "internal" in other languages.

To grant access to read a variable we declare it after"attr_reader". attribute with the following:

attr_reader :fname, :lname

then

print employee.fname => "Augustus"

To allow writing to a variable use "attr_writer",

class Employee < Person def initialize(fname, lname, position) super(fname,lname) @position = position end def to_s super + ", #@position" end attr_writer :position end employee = Employee.new("Augustus","Bondi","CFO") puts employee puts employee.fnameemployee.position = "CEO" puts employee

D. Virtual Attributes

class Employee < Person def initialize(fname, lname, position) super(fname,lname) @position = position end def to_s super + ", #@position" end attr_writer :position def etype if @position == "CEO" || @position == "CFO" "executive" else "staff" end end end employee = Employee.new("Augustus","Bondi","CFO") employee.position = "CEO" puts employee.etype => executive employee.position = "Engineer"

Page 16: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 16/31

puts employee.etype => staff

20. Regular ExpressionsStrings can be compared to a regular expression with "=~".

Regular expressions are surrounded by "//" or "%r". Anything but thetwo special values, "false" and "nil" are considered true.Expression Result Description

/a/ =~ "All Gaul is dividedinto three parts" 5 finds the first "a" at position

5

%ra =~ "All Gaul is dividedinto three parts" 5 same thing with alternate

syntax

/ree/ =~ "All Gaul is dividedinto three parts" 27 finds "ree" at position 27

/^a/ =~ "All Gaul is dividedinto three parts" nil "^" implies at the beginning

of a line. nil is false.

/^A/ =~ "All Gaul is dividedinto three parts" 0 case­sensitive, remember

that "0" is true

/s$/ =~ "All Gaul is dividedinto three parts" 35 "$" implies at the end of a

line

/p.r/ =~ "All Gaul is dividedinto three parts" 31 "." matches any character

21. BlocksAnd now to one of the coolest things about Ruby ­ blocks. Blocks

are nameless chunks of code that may be passed as an argument toa function.

A. Simple Example

def whereisit yield yield yield end whereisit puts "where is the money?"

Produces:

where is the money? where is the money? where is the money?

In the above example 'puts "where is the money?"' is calleda block. That chunk of code is passed to the method "whereisit"and executed each time the "yield" statement is executed. Youcan think of the "yield" being replaced by the block of code.

B. Blocks can take argumentsHere the method "cubes" takes the max value.

Page 17: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 17/31

def cubes(max) i=1 while i < max yield i**3 i += 1 end end cubes(8) |x| print x, ", " => 1, 8, 27, 64, 125, 216, 343, sum = 0 cubes(8) |y| sum += y print "\nsum=",sum => sum=784 product = 1 cubes(8) |z| product *= z print "\nproduct=",product => product=128024064000

Think of the "yield i**3" in the function cubes as beingreplaced with the block, '|x| print x, ", "'. The value following the"yield" is passed as the value "x" to the block.

C. Multiple arguments may be passed to blocks.

def employee(empId) #next 2 lines simulated from calling a database on the empId lastname = "Croton" firstname = "Milo" yield lastname,firstname #multiple arguments sent to blockend employee(4) |last,first| print "employee ",": ",first, " ",last

Produces:

employee : Milo Croton

D. Local variables can be shared with a blockEven though rate is a local variable, it is used inside the

block.

def tip(mealCost) yield mealCost end rate = 0.15 mytip = tip(10.0) |cost| cost * rate print "tip should be: ",mytip

Produces:

tip should be: 1.5

E. Blocks are built in to many objects in rubya. each

Page 18: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 18/31

iterates through each item of a collection

[1,2,3,4].each|x| print x**2," "

Produces:

1 4 9 16

b. detectreturns the first item matching a logical expression

numbers = [1,3,5,8,10,14] firstDoubleDigit = numbers.detect |x| x > 9 print firstDoubleDigit => 10

c. selectreturns all items matching a logical expression

numbers = [1,2,3,4,5,6,7]; evens = numbers.select|x| x % 2 == 0 p evens => [2, 4, 6]

d. collectreturns an array created by doing the operation on each

element.

[1,2,3,4].collect|x| x**3 => [1, 8, 27, 64] ["the","quick","brown", "lox"].collect|x| x.upcase => ["THE"

e. inject"inject" is the "fold" or "reducer" function in Ruby. "inject"

loops over an enumerable and performs an operation oneach object and returns a single value.

primes = [1,3,5,7,11,13]; #using "inject" to sum. We pass in "0" as the initial value sum = primes.inject(0)|cummulative,prime| cummulative+primeputs sum =>40 #we pass in no initial value, so inject uses the first element product = primes.inject|cummulative,prime| cummulative*primeputs product =>15015 #just for fun let's sum all the numbers from 1 to, oh, say a million sum = (1..1000000).inject(0)|cummulative,n| cummulative+nputs sum =>500000500000 #you can do interesting things like build hashes hash = primes.inject() |s,e| s.merge( e.to_s => e ) p hash # => "11"=>11, "7"=>7, "13"=>13, "1"=>1, "3"=>3, "5"=>5

Page 19: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 19/31

22. File I/OA. Read an entire file into a string

file = File.new( "t1.php" ) mytext = file.read

B. Read an entire file into an array of lines

lines = IO.readlines("data.txt") puts lines[0] #prints the first line

C. Read a file line by line

file = File.open("res.txt") while line = file.gets puts line end

Or you can use the IO class

IO.foreach("data.txt") |line| puts line

D. Read a file line by lineYou should ensure the file is closed as well.

begin file = File.open("res.txt") while line = file.gets puts line end ensure file.close end

E. Read only a few bytes at a timeThe following snippet of code reads a file which may have no

line breaks and chops it into 80 character lines

require 'readbytes' file = File.new( "C:/installs/myapp_log.xml" ) while bytes = file.readbytes(80) print bytes+"\r\n" end file.close

F. Reads a large XML file and inserts line breaksUses TruncatedDataError to grab the last few slacker bytes

from the end.

Page 20: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 20/31

# reads an xml file without line breaks and puts a line break before each '<'require 'readbytes' file = File.new( "C:/installs/SurveyDirector_log.xml" ) begin while bytes = file.readbytes(80) print bytes.gsub(/</,"\r\n<") end rescue TruncatedDataError #the last read had less chars than specified #print the rest of the data. $! is the exception. # ".data" has the extra bytes print $!.data.gsub(/</,"\r\n<") ensure file.close unless file.nil? end

23. method_missing ­ a wonderful ideaIn most languages when a method cannot be found and error is

thrown and your program stops. In ruby you can actually catch thoseerrors and perhaps do something intelligent with the situation. A trivialexample:

class MathWiz def add(a,b) return a+b end def method_missing(name, *args) puts "I don't know the method #name" end end mathwiz = MathWiz.new puts mathwiz.add(1,4) puts mathwiz.subtract(4,2)

Produces:

5 I don't know the method subtract nil

24. While the ruby program is loading, you can execute code inside aspecial block labeled "BEGIN" ­ pretty nifty. After the interpretor hasloaded the code, but before execution, you can execute code in the"END" block.

puts "main program running" END puts "program ending" BEGIN puts "I'm loading"

Page 21: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 21/31

Produces:

I'm loading main program running program ending

25. converting between strings and intsUse the to_i and to_s methods

"3".to_i #return an integer 3.to_s # returns a string

26. Using XML Dom ParserREXML goes standard with Ruby 1.8. Sample to print all "div"

elements whose "class" attribute is set to "entry".

require "rexml/document" file = File.new( "t0.xml" ) doc = REXML::Document.new file doc.elements.each("//div[@class='entry']") |element| puts element

27. Run a few lines directly from the command line with the "­e"option

c:\home\mfincher>ruby ­e 'sleep 2' c:\home\mfincher>ruby ­e 'puts 3*4' 12 c:\home\mfincher>ruby ­e 'puts 3*4; puts 4*4' 12 16

28. Editing files in placeRuby offers a simple way to make a string substitution in many

files all at once with a single line of code. The "­p" option loops overthe files, the "­i" is the backup extension. With this command we arechanging all the documentation from version 1.5 to 1.6, but theoriginal files are renamed to ".bak".

C:\home\mfincher\ruby>more v2.txt Regarding version 1.5 ... .... version 1.5 is easy to install

C:\home\mfincher\ruby>ruby ­pi.bak ­e "gsub(/1.5/,'1.6')" v*.txt

C:\home\mfincher\ruby>more v2.txt Regarding version 1.6 ... .... version 1.6 is easy to install

Page 22: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 22/31

C:\home\mfincher\ruby>more v2.txt.bak Regarding version 1.5 ... .... version 1.5 is easy to install

29. Example of printing duplicate lines in sorted file.

#prints duplicate lines in sorted files in the file passed in as first arg file = File.open(ARGV[0]) lastLine = "" counter = 0 while line = file.gets counter += 1 if lastLine == line puts "#counter-1: #line#counter: #line\r\n" end lastLine = line end puts "done. Processed #counter lines"

30. Ruby has its own interpreted shell, irb.

C:\home\mfincher>irb irb(main):001:0> puts "Hello World" Hello World=> nil irb(main):002:0> a=1 => 1 irb(main):003:0> a*2 => 2 irb(main):004:0>

31. ruby can take input from stdin

echo 'puts "hello"' | ruby

32. to pass a string on the url it needs to be "escape"'d first.

require 'uri' ... URI.escape("some string...")

33. Example to remove "funny" characters from a filenameExample of iterating over the filenames in a directory, using

regular expression substitution in strings, and renaming files.

#replaces any "funny" characters in a filename in the current directory with an underscore#if the new file name already exists, this skips it.

Page 23: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 23/31

Dir.foreach(".") |f| print "testing \"#f\"" if f =~ /[^\w\-\.]/ #filename contains something other than letters, numbers, _,­, or . puts "\r\n name with funny characters: #f" newName = f.gsub(/[^\w\.\-]/,"_") # \w is any word character, letter,num or _ if File.exist?(newName) puts " File #newName already exists. Not renaming." else puts " renaming #f to #newName" File.rename(f,newName) end else puts " it's ok." end

34. Looping over list of arguments

ARGV.each |f| puts f counter = 0 file = File.open(f,"r") ftmp = f+".tmp" tmp = File.open(ftmp,"w") while line = file.gets if line =~ /pid="2"/ counter += 1 line = line.gsub(/pid="2"/,"pid=\"#f:#counter\"") puts line end tmp.print line end file.close tmp.close puts "renaming #ftmp to #f" File.rename(ftmp,f)

35. Miscellanous Commandscommand description example result

global_variables returns all global variables

local_variables returns all local variables

sleep seconds sleeps specified seconds

rand returns a random numberbetween 0 and 1

rand(max) returns int between 0 and max

warn like print, but writes to STDERR

Interesting string functionscommand description example result

Page 24: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 24/31

center centers string "City".center(20) "________City________"

ljust left justifies "State".ljust(30) "State_________________________"

rjust right justifies "State".rjust(30) "_________________________State"

include?does the stringinclude thissubstring

"this is a test".include?('is') true

gsub global regexreplacesments

"this is atest".gsub(/[aeiou]/,'_\1') th_s _s _ t_st

tr translates "The greatest of theseis".tr('aeiou','*') Th* gr**t*st *f th*s* *s

each splits anditerates

"one:two:three".each(':')|x| puts x

one: two: three

36. DateTime

puts DateTime.now #prints 2006­11­25T14:26:15­0600 puts Date.today #prints 2006­11­25 puts Time.now #prints Sat Nov 25 14:29:57 Central Standard Time 2006

37. Using 'require'require will let your access code from other files. 'require' looks in

directories specified in $LOAD_PATH to find the files. Theenvironmental variable RUBYLIB can be used to load paths into$LOAD_PATH.

C:\home\mfincher\ruby>irb irb(main):001:0> p $LOAD_PATH ["c:/opt/ruby/lib/ruby/site_ruby/1.8", "c:/opt/ruby/lib/ruby/site_ruby/1.8/i386-msvcrt" "c:/opt/ruby/lib/ruby/1.8/i386-mswin32", "."] => nil

You can put a library like 'startClicker.rb' in any of those directoriesand ruby will find it.

require 'startClicker'

38. BuiltIn Command InterpreterWith the "eval" method you can create your own interpreter

language and run it during execution.

irb(main):007:0> a = 6 => 6 irb(main):008:0> b = 7 => 7 irb(main):009:0> eval "c=a+b"

Page 25: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 25/31

=> 13 irb(main):010:0> puts c 13

39. Introspection with ObjectSpaceYou can find all the objects in your program of a particular type

using ObjectSpace.each_object.

class Person def initialize(name,age) @name = name @age = age end attr_reader :nameend p = Person.new("Alfred",34) p2 = Person.new("Janie",31) ObjectSpace.each_object(Person) |s| puts s.name

Produces:

Janie Alfred

40. TestingRuby comes right out of the box with a testing framework. Here's a

quick example:

require 'test/unit'

class TestMe < Test::Unit::TestCase

def test_add s = 1 + 1 assert_equal(2, s) end

end

41. Read a URL and print the web page to the screen.This will get a particular page and print to the screen:

require 'open-uri' open('http://www.fincher.org/Misc/Pennies') |f| print f.read

This will read a file of urls and print all to the screen:

#Reads first argument as file containing urls and prints them

Page 26: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 26/31

#usage: ruby wget.rb wget.txt require 'open-uri' IO.foreach(ARGV[0]) |line| open(line) |f| print f.read

42. Example of drawing a line on a canvas in TkTk is a graphical subsystem used in languages like Perl and Tcl.

#draws a single line on a big canvas require 'tk' include Math

TkRoot.new do |root| title "Solo Line" geometry "600x600" canvas2 = TkCanvas.new(root) do |canvas| width 600 height 600 pack('side' => 'top', 'fill'=>'both', 'expand'=>'yes') points = [] end TkcLine.new(canvas2, 0,0,100,100) end Tk.mainloop

43. irb ­ interactive rubyRuby comes with an REPL (Read Eval Print Loop) utility to let you

try ruby interactively. ("inf­ruby.el" provides an internal shell in emacsfor irb).

C:>irb irb(main):001:0> puts "hello" puts "hello" hello nil irb(main):002:0> Object.methods Object.methods ["send", "name", "class_eval", "object_id", "new", "singleton_methods"irb(main):003:0>

44. RubyGems a ruby package installerYou can download RubyGems from http://rubyforge.org. Unzip the

files (eg, C:\opt\ruby) then install by entering:

C:>cd C:\opt\ruby\rubygems­0.9.0 C:\opt\ruby\rubygems­0.9.0>ruby setup.rb all

45. Ruby on RailsA. How to write a log message

You can use logger's methods "warn", "info", "error", and"fatal".

Page 27: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 27/31

logger.info("request.remote_ip"+request.remote_ip);

B. Field names ending with "_at" are assumed to be datetimefields and are filled in automagically by rails for ActiveRecordobjects. The suffix "_on" are assumed to be dates.

C. Consoleto dubug applications it's convenient to use the console script

myapp>ruby script/console

D. debug methodYou can use the debug() method inside web pages to dump

info about an object.

<p>Thanks for visiting</p> <%= debug(@myobject) %>

E. How to Freeze a versionSince your hosting company may upgrade the rails version

you need to "freeze" the current version. The following copies allthe 1.2.6 libraries from the shared directory to your own privateone.

rake rails:freeze:edge TAG=rel_1­2­6

F. Active record notesa. Find all records meeting a criteria

def self.suitable_jokes(sort_key) if sort_key == "Newest" find(:all, :conditions => "suitable = \"1\"", :order => "entry_date DESC" ) elsif sort_key == "Worst" find(:all, :conditions => "suitable = \"1\"", :order => "entry_date ASC" ) else find(:all, :conditions => "suitable = \"1\"", :order => "current_rating DESC" ) end end

The first argument to find can also be ":first" or ":last".b. Find the count of records meeting a criteria

Page 28: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 28/31

def self.waiting_jokes() count("suitable = \"0\"") end def self.total() count("suitable = \"1\"") end

Find the total number of items

count = Joke.count

Find the total number of items meeting a criteria

count = Joke.count(["suitable = \"1\""])

c. PaginationThe ":limit" and ":offset" options allow easy pagination.To return the fifth page of items use the following:

find(:all, :conditions => "suitable = \"1\"", :order => "current_rating DESC", :limit => 10, :offset => 40 )

d. Use raw SQL and return two values

def getAverageRatingAndCount record = Rating.find_by_sql(["select count(*) as count,avg(rating) as average from ratings WHERE joke_id = ?" return record[0].average.to_f , record[0].count.to_i end

e. The "create" method in ActiveRecord will do "new" and"save" operations simultanously.

mydog = Dog.create( :name => "Fido" :breed => "Collie" )

G. WatirWatir is a GUI testing tool written in Ruby. Here is a script to

open Google and search for pictures of kittens.

require "watir" ie = Watir::IE.new #create an object to drive the browser ie.goto "http://www.google.com/" ie.url == "http://www.google.com/"

Page 29: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 29/31

ie.link(:text, "Images").flash #flash the item text "Images" ie.link(:text, "Images").click #click on the link to the images search pageie.text.include? "The most comprehensive image search on the web"searchTerm = "kittens" #set a variable to hold our search term ie.text_field(:name, "q").set(searchTerm) # q is the name of the search fieldie.button(:name, "btnG").click # "btnG" is the name of the google buttonif ie.contains_text(searchTerm) puts "Test Passed. Found the test string: #searchTerm. Actual Results match Expected Results."else puts "Test Failed! Could not find: #searchTerm" end

H. Selecting a JavaScript popup boxstolen from http://wiki.openqa.org/display/WTR/FAQ

#Watir script to show clicking a JavaScript popup box require "watir" require 'watir\contrib\enabled_popup' require 'startClicker' require 'net/http' require 'net/https'

$ie = Watir::IE.new #create an object to drive the browser $ie.goto "http://mydomain.com/ListGroups.aspx" if $ie.contains_text("Log In") $ie.text_field(:name, "Login1$UserName").set("fincherm") $ie.text_field(:name, "Login1$Password").set("mitch") $ie.button(:name, "Login1$LoginButton").click end $ie.link(:text, "Baseline").click $ie.link(:text, "MoonManC").click def setDdlPriority(priority) ddlPriority = $ie.select_list( :name , /ddlPriority/) puts ddlPriority ddlPriority.select(priority) puts ddlPriority $ie.button(:name, "ctl00$btnSave").click_no_wait startClicker( "OK", 4 , "User Input" ) sleep 1 end setDdlPriority("2") setDdlPriority("9")

startClicker.rb:

#method startClicker from http://wiki.openqa.org/display/WTR/FAQ def startClicker( button , waitTime= 9, user_input=nil ) # get a handle if one exists hwnd = $ie.enabled_popup(waitTime) if (hwnd) # yes there is a popup w = WinClicker.new if ( user_input ) w.setTextValueForFileNameField( hwnd, "#user_input" end # I put this in to see the text being input it is not necessary to work sleep 3

Page 30: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 30/31

# "OK" or whatever the name on the button is w.clickWindowsButton_hwnd( hwnd, "#button" ) # # this is just cleanup w=nil end end

I. How to use Watir with NUnitHere is an example of connecting it to NUnit.

using System; using System.Diagnostics; using System.Text.RegularExpressions; using NUnit.Framework;

namespace SurveyDirector.Test.Watir /// <summary> /// from http://www.hanselman.com/blog/IntegratingRubyAndWatirWithNUnit.aspx /// with small hacks from Liz Buenker /// </summary> public class WatirAssert public static void TestPassed(string rubyFileName, string string output = String.Empty; using (Process p = new Process()) p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.FileName = "ruby.exe"; p.StartInfo.Arguments = rubyFileName + " -b" p.StartInfo.WorkingDirectory = directoryPath p.Start(); output = p.StandardOutput.ReadToEnd(); p.WaitForExit(); Console.Write(output); Trace.Write(output); Regex reg = new Regex(@"(?<tests>\d+) tests, (?<assertions> Match m = reg.Match(output); try int tests = int.Parse(m.Groups["tests"].Value); int assertions = int.Parse(m.Groups["assertions" int failures = int.Parse(m.Groups["failures"].Value int errors = int.Parse(m.Groups["errors"].Value if (tests > 0 && failures > 0) Assert.Fail(String.Format("WatirAssert: Failures 0" else if (errors > 0) Assert.Fail(String.Format("WatirAssert: Errors 0" catch (Exception e)

Page 31: Ruby Tutorial With Code Samples

12/14/2015 Ruby Tutorial with Code Samples

http://www.fincher.org/tips/Languages/Ruby/ 31/31

Assert.Fail("WatirAssert EXCEPTION: " + e.ToString

The above code would be used by something like this:

using System; using NUnit.Framework;

namespace SurveyDirector.Test.Watir [TestFixture] public class WatirTest private static readonly string testDir = Utilities.Properties public WatirTest() [Test] public void Sd01Test() WatirAssert.TestPassed("sd01_test.rb",testDir); [Test] public void Sd02Test() WatirAssert.TestPassed("sd02_test.rb",testDir);

46. Ruby Quotes:

"Ruby is a language for clever people." ­Matz "Ruby is the perlification of Lisp." ­Matz "Type Declarations are the Maginot line of programming." ­MitchFincher