Ruby Tutorial For Beginners
Ruby Tutorial For Beginners
"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".
puts "Howdy!"
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. printf formats numbers like me. 3.14, and strings like
5. Functions 1. Our first Ruby function 'def' starts the definition of a method, and 'end' ends it - no cute little curly braces.
def welcome(name) puts "howdy #{name}" evaluate the variable end welcome("nana") # inside double quotes, #{ } will # traditional parens
This Produces:
howdy nana
3. def welcome(name) 4. puts "howdy #{name}" evaluate the variable 5. end 6. welcome "visitor"
This Produces:
howdy visitor
7. How to return values from a function We can use the faithful 'return'
def multiply(a,b) product = a * b return product end puts multiply(2,3)
=>6
Oddly enough you can leave out the "return" statement, and Ruby 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 the contents of the last expression:
def mult(a,b) a * b
=>9
8. Optional argument values Ruby 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
9. Extra arguments Extra arguments are gathered into the last variable if preceded with a "*". ("each" is an iterator that loops over its members).
def test(a=1,b=2,*c) puts "#{a},#{b}" c.each{|x| print " #{x}, "} soon. I promise. end test 3, 6, 9, 12, 15, 18
This produces:
3,6 9, 12, 15, 18,
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 Classes You 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 decide you need a new string function, you can add it yourself.
class String def NullOrEmpty? (self == nil || self == "") end
Is this way cool? Yes. Is this very dangerous? Yes. Remember, Ruby is a chainsaw. 7. Variable naming Ok, let's slow down and learn some basics about variable names Global variables start with '$' Class variables start with '@@' Instance variables start with '@' Local variables, method names, and method parameters start with a lower case letter 5. Class names, module names and constants start with an uppercase letter 6. Variables names are composed of letters, numbers and underscores 7. Method names may end with "?", "!", or "=". Methods ending with a "?" imply a boolean operation (eg, "instance_of?"). Methods ending with "!" imply something dangerous, like strings being modified in place (eg, "upcase!") 8. Interesting tidbits about Ruby, 1. '#' is the line comment character, all characters after this are ignored. Confusingly '#' can appear within quotes with a different meaning. 2. No semi-colons are needed to end lines, but may be used to separate statements on the same line 3. A backslash (\) at the end of a line is used for continuation 4. Indenting is not significant, unlike python 5. Types of variables do not need to be declared 6. Lines between =begin and =end are ignored 7. Lines following "__END__" on its own line with no white space, are ignored 8. A tiny demonstration of these:
9. # sample program showing special characters like comments 10. # I'm a comment line 11. a = 1 #notice no semicolon and no type declaration 12. b = 2; c = 3 #notice two statements on one line 13. name = "Abraham \ 14. Lincoln" # a line continued by trailing \ 15. puts "#{name}" 16. =begin 17. I'm ignored. 18. So am I. 19. =end 20. puts "goodbye" 21. __END__ 22. 1 23. 2 24. 3 25. 4 26. Abraham Lincoln 27. goodbye
1. 2. 3. 4.
9. Variable Types In Ruby, variables don't have a specific type associated with them. All variables are objects, so we only play with pointers to those objects, and those pointers are type agnostic.
10. bat = "Louisville slugger"
12. 13. Quotes Like 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 typical values. The #{name} construct is converted to its value. With single quotes, no special characters are interpreted. Examples:
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)
14. Objects A great thing about Ruby is that numbers and strings are real objects.
1.5.floor() => "1"
We can write
if x.between?(7,12) do ...
Produces:
2 2 2 2 2 2 2 2 ** ** ** ** ** ** ** ** 1 2 3 4 5 6 7 8 = = = = = = = = 2 4 8 16 32 64 128 256
2 ** 9 = 512 2 ** 10 = 1024 ... 2 ** 1000 = 107150860718626732094842504906000181056140481170553360744375038837035105 112493612249319837881569585812759467291755314682518714528569231404 359845775746985748039345677748242309854210746050623711418779541821530464 749835819412673987675591655439460770629145711964776865421676604298316526 243868 37205668069376
16. Parallel Assignment You 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 values first. 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
17. Collections 1. Arrays 1. An array of known objects can be created by enclosing them in square brackets.
2. nums = [1, 2.0, "three"] 3. puts nums[2] => three
Ruby arrays, like all right-thinking collections, are zero based. 4. You can use negative indexes to start from the end of the array
5. nums = [1, 2.0, "three", "four"] 6. puts nums[-1] => four
Using "-1" is so much more concise than "nums[nums.length()-1]". 7. You can even use the handy "first" and "last" methods.
8. [1,2,3].last => 3 9. [1,2,3].first => 1
10. length To get the count, or size, of an array, use the "length" method.
11. %w shortcut Since many arrays are composed of single words and all those commas and quote marks are troublesome, Ruby provides a handy shortcut, %w:
mystuff = %w{tivo nokia ipaq} # make a string array
12. inspect To look at contents of an object use the "inspect" method. Even more convenient is to use "p" as a shorthand for "puts obj.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]
# - removes items from the first array that appear in the second 21. puts [1,2,3] - [3,4,5] # prints 1,2 22. 23. # pop returns the last element and removes it from the array 24. alpha = ["a","b","c","d","e","f"] 25. puts "pop="+alpha.pop # pop=f 26. puts alpha.inspect # ["a", "b", "c", "d", "e"] 27. 28. # push appends elements to the end of an array 29. alpha = ["a","b","c"] 30. alpha.push("x","y","z") 31. puts alpha.inspect # ["a", "b", "c", "x", "y", "z"] 32. 33. # shift returns the first element and removes it from the array 34. alpha = ["a","b","c","d","e","f"] 35. puts "shift="+alpha.shift # shift=a 36. puts alpha.inspect # ["b", "c", "d", "e", "f"] 37. 38. # unshift appends elements to the beginning of an array 39. alpha = ["a","b","c"]
2. Hashes This type of collection is also called a dictionary or an associative array. 1. Simple hash of cars and their makers
2. 3. 4. 5. 6. 7. cars = { 'altima' => 'nissan', 'camry' => 'toyota', 'rx7' => 'mazda' } puts cars['rx7'] =>
mazda
9. dict = {} # create a new dictionary 10. dict['H'] = 'Hydrogen' #associate the key 'H' to the value 'Hydrogen' 11. dict['He'] = 'Helium' 12. dict['Li'] = 'Lithium' 13. p dict['H'] # prints "Hydrogen" 14. p dict.length # prints 3 15. p dict.values # prints ["Lithium", "Helium", "Hydrogen"] 16. p dict.keys # prints ["Li", "He", "H"] 17. p dict # prints {"Li"=>"Lithium", "He"=>"Helium", "H"=>"Hydrogen"}
18. Hash[] You can also create Hashes with square brackets by prefixing with "Hash":
toppings = Hash["pancakes","syrup","Pizza","Pepper","Cereal","Sugar"] puts toppings.inspect
Produces:
{"Pizza"=>"Pepper", "Cereal"=>"Sugar", "pancakes"=>"syrup"}
19. each The "each" method is a wonderful way to iterate over the keys
toppings = Hash["pancakes","syrup","Pizza","Pepper","Cereal","Sugar"] toppings.each{|key, value| puts "#{key} points to #{value}"}
Produces:
Pizza points to Pepper Cereal points to Sugar pancakes points to syrup
20. select The "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.5] salaries.inspect mySalaryArray = salaries.select{|name,salary| salary > 7.0} puts mySalaryArray.inspect => [["larry", 7.5], ["bob", 10.9]]
3. Ranges Ranges 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 the last element.:
1 2
18. Control Statements 1. if In an "if" statement anything but the two special values, "false" and "nil" are considered true. Even zero is true for all you C/C++ programmers.
2. income = 30000.00 3. if income < 10000 4. rate = 0.02 5. elsif income < 30000 6. rate = 0.28 7. else 8. rate = 0.5 9. end 10. puts rate
11. case
12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 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}" for i in 1..4 puts "hi #{i}" end
24. for
25. 26. 27.
28. exit
29. 30. 31. 32. 33. lines = IO.readlines("data.txt") if lines.length < 100 exit 2 end puts lines.length
19. Statement modifiers These are just syntatic sugar. 1. if The "if" clause may be placed at the end of a statement
balance = -10.0 puts "Bankrupt" if balance < 0.0
5. puts i 6. end
7. "times"
8. n = 10 9. n.times { |i| print i}
Produces:
0123456789
10. "each"
11. 12. 13. 15. 16. 18. 19. 20.
animals = %w(lions tigers bears) animals.each{|kind| print kind} lionstigersbears ('m'..'z').each {|ch| print ch} mnopqrstuvwxyz n=0 ; max=7 n.upto(max) {|num| print num} 01234567
21. You gotta have class. 1. Classes Class definitions start with "class" and end with "end". Remember that class names start with a capital letter. Notice the syntax is "object.new" for creating an object and that the "initialize" method contains code normally found in the constructor. 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>
Produces:
Produces:
Person: Augustus Bondi, CFO
But why is that? We've printed variables a zillion times up til now and it's always worked. What changed? Up until now we've created variables in a program without classes (actually all are variables were members of a default object that were accessable inside itself). Now we are using real classes and that brings up the point of visibility of members outside the class. We now have to 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"
end employee = Employee.new("Augustus","Bondi","CFO") puts employee puts employee.fname employee.position = "CEO" puts employee
22. Regular Expressions Strings can be compared to a regular expression with "=~". Regular expressions are surrounded by "//" or "%r{}". Anything but the two special values, "false" and "nil" are considered true. Expression /a/ =~ "All Gaul is divided into three parts" %r{a} =~ "All Gaul is divided into three parts" /ree/ =~ "All Gaul is divided into three parts" /^a/ =~ "All Gaul is divided into three parts" /^A/ =~ "All Gaul is divided into three parts" /s$/ =~ "All Gaul is divided into three parts" /p.r/ =~ "All Gaul is divided into three parts" 23. Blocks And now to one of the coolest things about Ruby - blocks. Blocks are nameless chunks of code that may be passed as an argument to a function. Result 5 5 27 nil 0 35 31 Description finds the first "a" at position 5 same thing with alternate syntax finds "ree" at position 27 "^" implies at the beginning of a line. nil is false. case-sensitive, remember that "0" is true "$" implies at the end of a line "." matches any character
1. Simple Example
2. def whereisit 3. yield 4. yield 5. yield 6. end 7. 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 called a block. That chunk of code is passed to the method "whereisit" and executed each time the "yield" statement is executed. You can think of the "yield" being replaced by the block of code. 8. Blocks can take arguments Here the method "cubes" takes the max value.
def cubes(max) i=1 while i < max yield i**3 i += 1 end end cubes(8) { |x| print x, ", "} sum = 0 cubes(8) { |y| sum += y} print "\nsum=",sum product = 1 cubes(8) { |z| product *= z} print "\nproduct=",product
=> 1, 8, 27, 64, 125, 216, 343, => sum=784 => product=128024064000
Think of the "yield i**3" in the function cubes as being replaced with the block, '|x| print x, ", "'. The value following the "yield" is passed as the value "x" to the block. 9. Multiple arguments may be passed to blocks.
10. 11. def employee(empId) #next 2 lines simulated from calling a database on the empId 12. lastname = "Croton" 13. firstname = "Milo" 14. yield lastname,firstname #multiple arguments sent to block 15. end 16. employee(4) { |last,first| print "employee ",": ",first, " ",last}
Produces:
employee : Milo Croton
Produces:
tip should be: 1.5
18. Blocks are built in to many objects in ruby 1. each iterates through each item of a collection
[1,2,3,4].each{|x| print x**2," "}
Produces:
1 4 9 16
5. inject "inject" is the "fold" or "reducer" function in Ruby. "inject" loops over an enumerable and performs an operation on each 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+prime} puts sum =>40 #we pass in no initial value, so inject uses the first element product = primes.inject{|cummulative,prime| cummulative*prime} puts 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+n} puts 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}
4. Read an entire file into an array of lines 7. Read a file line by line
5. lines = IO.readlines("data.txt") 6. puts lines[0] #prints the first line 8. file = File.open("res.txt") 9. while line = file.gets 10. puts line 11. end
12. Read a file line by line You 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
13. Read only a few bytes at a time The 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
14. Reads a large XML file and inserts line breaks Uses TruncatedDataError to grab the last few slacker bytes from the end.
# 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
25. method_missing - a wonderful idea In most languages when a method cannot be found and error is thrown and your program stops. In ruby you can actually catch those errors and perhaps do something intelligent with the situation. A trivial example:
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
26. While the ruby program is loading, you can execute code inside a special block labeled "BEGIN" - pretty nifty. After the interpretor has loaded the code, but before execution, you can execute code in the "END" block.
27. 28. 29. 30. 31. 32. 33. puts "main program running" END { puts "program ending" } BEGIN { puts "I'm loading" }
Produces:
I'm loading main program running
program ending
34. converting between strings and ints Use the to_i and to_s methods
"3".to_i 3.to_s #return an integer # returns a string
35. Using XML Dom Parser REXML 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 }
36. Run a few lines directly from the command line with the "-e" option
37. 38. 39. 40. 41. 42. 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
43. Editing files in place Ruby 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 over the files, the "-i" is the backup extension. With this command we are changing all the documentation from version 1.5 to 1.6, but the original 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 C:\home\mfincher\ruby>more v2.txt.bak Regarding version 1.5 ... .... version 1.5 is easy to install
45. #prints duplicate lines in sorted files in the file passed in as first arg 46. file = File.open(ARGV[0]) 47. lastLine = "" 48. counter = 0 49. while line = file.gets 50. counter += 1 51. if lastLine == line 52. puts "#{counter-1}: #{line}#{counter}: #{line}\r\n"
53. end 54. lastLine = line 55. end 56. puts "done. Processed #{counter} lines"
73. Example to remove "funny" characters from a filename Example 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. 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 }
100.
Using 'require'
require will let your access code from other files. 'require' looks in directories specified in $LOAD_PATH to find the files. The environmental 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/site_ruby", "c:/opt/ruby/lib/ruby/1.8", "c:/opt/ruby/lib/ruby/1.8/i386-mswin32", "."] => nil
You can put a library like 'startClicker.rb' in any of those directories and ruby will find it.
require 'startClicker'
101.
With the "eval" method you can create your own interpreter language and run it during execution.
irb(main):007:0> => 6 irb(main):008:0> => 7 irb(main):009:0> => 13 irb(main):010:0> 13 a = 6 b = 7 eval "c=a+b" puts c
102.
You 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 :name end p = Person.new("Alfred",34)
Produces:
Janie Alfred
103.
Testing
Ruby 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
104.
This will read a file of urls and print all to the screen:
#Reads first argument as file containing urls and prints them #usage: ruby wget.rb wget.txt require 'open-uri' IO.foreach(ARGV[0]) { |line| open(line){ |f| print f.read } }
105.
106.
Ruby comes with an REPL (Read Eval Print Loop) utility to let you try ruby interactively. ("inf-ruby.el" provides an internal shell in emacs for 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", "__send__", "private_method_defined?", "equal?", "taint", "frozen?", "instance_variable_get", "constants", "kind_of?", "to_a", "instance_eval", "require", "ancestors", "const_missing", "type", "instance_methods", "protected_methods", "extend", "protected_method_defined?", "eql?", "public_class_method", "const_get", "instance_variable_set", "hash", "is_a?", "autoload", "to_s", "class_variables", "class", "tainted?", "private_methods", "public_instance_methods", "instance_method", "untaint", "included_modules", "private_class_method", "const_set", "id", "<", "inspect", "<=>", "==", "method_defined?", ">", "===", "clone", "public_methods", "protected_instance_methods", "require_gem", ">=", "respond_to?", "display", "freeze", "<=", "module_eval", "autoload?", "allocate", "__id__", "=~", "methods", "gem", "method", "public_method_defined?", "superclass", "nil?", "dup", "private_instance_methods", "instance_variables", "include?", "const_defined?", "instance_of?"] irb(main):003:0>
107.
You 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
108.
Ruby on Rails 1. How to write a log message You can use logger's methods "warn", "info", "error", and "fatal".
logger.info("request.remote_ip"+request.remote_ip);
2. Field names ending with "_at" are assumed to be datetime fields and are filled in automagically by rails for ActiveRecord objects. The suffix "_on" are assumed to be dates. 3. Console to dubug applications it's convenient to use the console script
myapp>ruby script/console
4. debug method You can use the debug() method inside web pages to dump info about an object.
5. How to Freeze a version Since your hosting company may upgrade the rails version you need to "freeze" the current version. The following copies all the 1.2.6 libraries from the shared directory to your own private one.
rake rails:freeze:edge TAG=rel_1-2-6
2. def self.suitable_jokes(sort_key) 3. if sort_key == "Newest" 4. find(:all, 5. :conditions => "suitable = \"1\"", 6. :order => "entry_date DESC" 7. ) 8. elsif sort_key == "Worst" 9. find(:all, 10. :conditions => "suitable = \"1\"", 11. :order => "entry_date ASC" 12. ) 13. else 14. find(:all, 15. :conditions => "suitable = \"1\"", 16. :order => "current_rating DESC" 17. ) 18. end 19. end
The first argument to find can also be ":first" or ":last". 20. Find the count of records meeting a criteria
21. 22. 23. 24. 25. 26. def self.waiting_jokes() count("suitable = \"0\"") end def self.total() count("suitable = \"1\"") end
27. Pagination The ":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",
def getAverageRatingAndCount record = Rating.find_by_sql(["select count(*) as count,avg(rating) as average from ratings WHERE joke_id = ?",id]); 31. return record[0].average.to_f , record[0].count.to_i 32. end
33. The "create" method in ActiveRecord will do "new" and "save" operations simultanously.
34. 35. 36. 37. mydog = Dog.create( :name => "Fido" :breed => "Collie" )
7. Watir Watir 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/" ie.link(:text, "Images").flash #flash the item text "Images" ie.link(:text, "Images").click #click on the link to the images search page ie.text.include? "The most comprehensive image search on the web" #test to make sure it worked searchTerm = "kittens" #set a variable to hold our search term ie.text_field(:name, "q").set(searchTerm) # q is the name of the search field ie.button(:name, "btnG").click # "btnG" is the name of the google button if 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
$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 # "OK" or whatever the name on the button is w.clickWindowsButton_hwnd( hwnd, "#{button}" ) # # this is just cleanup w=nil end end
namespace SurveyDirector.Test.Watir { /// <summary> /// from http://www.hanselman.com/blog/IntegratingRubyAndWatirWithNUnit.asp x /// with small hacks from Liz Buenker /// </summary> public class WatirAssert { public static void TestPassed(string rubyFileName, string directoryPath) { 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>\d+) assertions, (?<failures>\d+) failures, (? <errors>\d+) errors", RegexOptions.Compiled); Match m = reg.Match(output); try { int tests = int.Parse(m.Groups["tests"].Value); int assertions = int.Parse(m.Groups["assertions"].Value); 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}", failures)); } else if (errors > 0) { Assert.Fail(String.Format("WatirAssert: Errors {0}", errors)); } } catch (Exception e) { Assert.Fail("WatirAssert EXCEPTION: " + e.ToString()); } } } }
} }
109.
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." -Mitch Fincher