Ruby (Bet you can’t do this in Java!) 6-Nov-15 “Hello World” in Ruby puts "Hello World!"
Download ReportTranscript Ruby (Bet you can’t do this in Java!) 6-Nov-15 “Hello World” in Ruby puts "Hello World!"
Ruby (Bet you can’t do
this
in Java!)
2-May-20
“Hello World” in Ruby
puts "Hello World!"
Euclid’s algorithm
def euclid x, y while x != y x if x > y then x -= y end if y > x then y -= x end end end puts "Enter two numbers: " STDOUT.flush
x = Integer(gets) y = Integer(gets) puts "The GCD of #{x} and #{y} is #{euclid x, y}“ Enter two numbers: 24 108 The GCD of 24 and 108 is 12
General principles
Everything is dynamic and may be changed All values are objects (there are no “primitives”) Variables are typeless and need not be declared Ruby avoids unnecessary punctuation A statement on a line by itself needs no semicolon Multiple statements on a line are separated by semicolons A line is continued if it ends in an operator, comma, or backslash Parameters to a method don’t usually need parentheses Conditions (in if, while, etc.) usually don’t need parentheses Correct capitalization is
required
, not optional Convention: Multiword variables use underscores, not camelCase Convention: Standard indentation is two spaces
Numbers
Numbers may be written in decimal, hexadecimal, octal, or binary Decimal: 3405691582 Hex: 0xCAFEBABE or 0XCAFEBABE Octal: 031277535276 or 0o31277535276 Binary: 0b11001010111111101011101010111110 or 0B
etc.
Numbers larger than four bytes are automatically treated as Bignum objects For readability, numbers may contain (but not begin or end with) underscores Examples: 3_405_691_582 , 0b_111_101_101 Integers may be indexed to retrieve their bits Example: 5.step(0, -1) { |i| print 6[i] } 000110
Other data types
Strings
can be singly quoted or doubly quoted Doubly quoted strings can interpolate values for #{
expression
} #@
variable
, and allow the usual escape characters In a singly quoted string, \' and for is the only recognized escape character Strings are
not
immutable
Arrays
are untyped and expandable, for example [1, 2, "hi"] Ruby has
hashes:
{ :banana 'yellow', :cherry => 'red' } Ruby has
regular expressions
,
dates
, and
times
Ruby has
ranges
, such as 1..10
Ruby has
symbols
, which stand for themselves You can think of them as immutable strings Examples are :banana and :cherry Since they are immutable, they make good keys for hashes They are also often used to refer to methods and variables: attr :do_it
Operators
Almost all the Java operators,
except
Ruby uses Ruby uses ++ and - :: to mean the same as =~ and !~ . in Java for Perl-style regular expressions ** is the exponentiation operator + is used to concatenate
strings
There is a to_s method for converting other things to strings .. is an inclusive range, ... is an exclusive range So 1..4
0..k
and 1...5
both mean is a range object, but 1, 2, 3, 4 [0..k] is an array with one element, a range defined? is a prefix operator that returns a true value or nil Ruby has both !
, Precedence is !
&& > && , || and also > || , but not not > and , and == or , or
Assignment and alias statements
Assignment statements use
=
,
+=
,
*=
, etc.
You can have multiple assignment: values of x and y x, y = y, x swaps the Ruby does
not
have the
++
and
--
operators You can create a new name for a method, operator, global variable, or regular expression backreference Syntax: alias
new_name original_name
Example: alias display puts
if statements
Multi-line version: if
condition
then
code
elsif
condition
then
code
else
code
end The “ then ” is optional at the end of a line Single-line versions: if
condition
then
code
elsif
condition
then
code
“ then ” is required to separate condition from code
statement
if
condition
else
code
end
unless statements
“
unless
” means “if not” Multi-line version: unless
condition
then
code
else
code
end The “ then ” is optional at the end of a line Single-line versions: unless
condition
then
code
else
code
end “ then ” is required to separate condition from code
statement
unless
condition
case and ===
case
expr_1
when
expr_2
then
code
when
expr_3
,
...
,
expr_n
then
code
else end
code
Cases do
not
break fall through; no is needed Comparisons use
expr_n
===
expr_1
and not the other way around
expr_n
=== meanings
expr_1
has many Simple equality test
expr_1
=~
expr_n expr_n
.kindof?
expr_1 expr_n
.include?
expr_1
The === operator has the misleading name “case equality operator”
Loops in Ruby
Ruby has several loops while
condition statements
end do begin
statements
end while
condition
until end
condition statements
begin
statements
end until
condition
for
variable statements
end in
range
do loop do
statements
end
statement
while
condition
statement
until
condition
loop {
statements
} However, loops are not used as often in Ruby as in other languages Instead, Ruby programmers use iterator methods
Loop controls
break
gets you out of loops Within a loop,
next
Within a block,
next
jumps to just before the loop test exits the block with
nil
retry
restarts the loop body after reevaluating the condition or getting the next iterated element Within a loop,
redo
restarts the loop body, but does not reevaluate the condition or get the next iterated element Within a block,
redo
restarts the
yield
or
call
Exceptions
raise raise raise
message
raises a
RuntimeError
exception exception
,
raises an error of the given type
message
rescue rescue rescue
variable ExceptionType
, ...,
ExceptionType ExceptionType
, ...,
ExceptionType
=>
Catches exceptions within a method, or within a begin...end block, or can be used as a statement suffix Example on next slide
Blocks
A block is a set of statements enclosed by begin..end
, by do..end
, or by {..} begin introduces a new scope; variables seen for the first time inside a begin..end block are local to that scope do..end and {..} are interchangeable Any block or method can include rescue or rescue/ensure begin...rescue...ensure...end
is like Java’s try...catch...finally
Example: begin
code
rescue
exception code
ensure
code
end
Defining methods
Defining an instance method: def
method_name
(
parameter1
,
statements
end
...
,
parameterN
) Defining a class method: def
Class_name
.
method_name
(
parameter1
,
statements
end
...
,
parameterN
) Parentheses are optional A method may contain explicit return and/or return
value
statements A method may return multiple values: A method which reaches the end executed (often nil ) return x, 2*x, x**2 returns the value of the last statement A method may also have a block as an (invisible) parameter The block is not mentioned in the def evaluates the yield statement line, but is executed when the method
Defining classes
class Employee < Person # ‘<‘ means “extends” @@number = 0 # class variable attr_reader :name # creates a getter for @name def initialize(name) end @name = name @@number += 1 end # this is the constructor secretary = Employee.new("William")
Calling methods
Methods may be called as in Java puts("x = #{x}") Parentheses are usually unnecessary puts "x = #{x}" All values are objects, and may have methods x = y.abs
n = "abcdefg".length
A method may be passed a block as an “invisible” parameter def twice n yield 2 * n # uses the block 99 end p = twice(7) { |y| puts "y = #{y}" } puts "p = #{p}" y = 14 p = 99
Iterators
An iterator returns values one at a time The syntax is
object
.
iterator
or
object
.
iterator statements
end { |
value
|
statement
do |
value
| }
The object is typically an array, a range, or a hash, but it can be any object with a coroutine
Iterators
In Ruby, loops are considered low-level, to be used only when there is no appropriate iterator
collection.each
– step through every element
n
.times
– do a block
n
n.downto(
limit
)
times – step from
n
down to and including
limit
n.upto(
limit
)
– step from
n
string.each_line
up to and including – get each line from a string
limit
string.each_char
– get each character (as an integer) from a string
Example use of an iterator
a = [1, 1, 2, 3, 5, 8, 13] a.each { |i| print " #{i}" } Output: 1 1 2 3 5 8 13 a.each do |i| print " #{i}" end Output: 1 1 2 3 5 8 13 In the above, each is a
method
A block is a chunk of code enclosed by {...} or by do...end
By convention, braces are used for single-line blocks, do...end
for multi-line blocks
String#each_char
In a previous slide, I had: string.each_char
– get each character (as an integer) from a string This method is described in the documentation, but doesn't seem to exist There is a method String#each_byte , however, that does what the above description says each_char does If we really want to get each
character
, we can do that class String def each_char end each_byte { |b| yield b.chr } end
Blocks again
A block is a chunk of code that can be passed as a parameter to a method A block isn’t a statement—it can’t be used alone It’s passed as an “invisible” parameter, and executed with the yield statement
Simplest use of yield
def three_times puts "---------- three_times“ yield yield yield end three_times { puts "hello" } ---------- three_times hello hello hello
My version of loop
def my_loop yield while true end
a = [1, 2, 3, 5, 8, 13, "hi"] my_loop do break if a.empty?
print a.pop
end puts "Done"
hi1385321Done
Fibonacci numbers
def fibonacci_upto n i1, i2 = 1, 1 while i1 < n end yield i1 i1, i2 = i2, i1 + i2 end
fibonacci_upto(100) { |f| print " ", f }
1 1 2 3 5 8 13 21 34 55 89
Passing a parameter to the block
def count_to n puts "---------- count_to #{n}" for i in 1..n
end yield end count_to 3 { puts "hello" } ---------- count_to 3 hello hello hello
Returning a value from a coroutine
def count_to_3 puts "---------- count_to_3" yield 1 yield 2 yield 3 end ---------- count_to_3 1 2 3 count_to_3 { |result| puts result }
Regular expressions
Ruby has regular expressions, almost identical to the way they are done in Perl Example: hamlet = "The slings and arrows of outrageous fortune." hamlet.scan(/w+/) ["The", "slings", "and", "arrows", "of", "outrageous", "fortune"]
Arrays
An array literal can be written with brackets and commas a = [1, 1, 2, 3, 5, 8, 13, "hi"] Arrays are zero based: a[2] == 2 Arrays can be expanded a = a + [21, 34] p a [1, 2, 3, 5, 8, 13, "hi", 21, 34] Arrays can be treated as stacks, with a.push(v) The join(
string
) and v = a.pop
method creates a string of the elements of the array, with the given string between each pair of elements You can take slices of arrays, sort them, find unique elements, perform set operations, transpose 2-dimensional arrays, etc.
Before you write methods to manipulate arrays, you should look to see whether the method you want has already been written
Hashes
A hash (hash table) literal can be written with braces, commas, and the
=>
arrow h = {:apple => :red, :banana => :yellow, :cherry => :red} Element access is similar to that for arrays: h[:banana] :yellow h[:apple] = :green p h {:banana=>:yellow, :cherry=>:red, :apple=>:green} You can use any types for keys and values, but the characteristics of symbols make them especially useful as keys
Adding and removing methods
def
adds a method;
undef
removes a method The only parameter to undef is the method name To add an instance method, first “open” the class Example: class String; def nchars; length; end; end There are several ways to add a class method to a class def Person.species; 'human'; end Within the Person class, you can use def self.species
You can add a method to individual objects def oscar.mood; 'grouchy' ; end
Attributes (instance variables)
Attributes (instance variables) of an object are written with an @ prefix: @name , @age , @hobbies , @favorite_language By default, attributes are private You can write getters: def name @name end You can write setters: def name=(new_name) @name = new_name end When you
define
When you
call
the setter, there is
no space
before the = in the header the setter, you can use a space: teacher.name = "Dave" Yes, we are calling the method name= !
Shorthand for getters and setters
Writing code for routine getters and setters is tedious, so in Ruby we don’t have to do it Shorthand for creating getters: attr_reader :name, :age, :hobbies Note the use of
symbols,
not variables or strings Shorthand for creating setters: attr_writer :name, :hobbies Shorthand for creating both at once: attr_accessor :name, :favorite_language By the way, these aren’t special Ruby syntax; they are
methods
that write the getters and setters for you Ruby uses lots of metaprogramming : programs that write programs
Access controls
Public methods can be called from anywhere Protected methods can be called only within the class and its subclasses Private methods cannot be called with an explicit receiver, only with an implicit
self
In Ruby, methods are
public
by default The functions
public
,
protected
, and
private
called with or without arguments can be With arguments, they set the access of the named methods Example: private :dump, :swear With no arguments, they set the default access for all subsequent methods
eval
eval
executes a string Example: eval "puts x + 2" Here’s how you
don’t
want to use this: eval gets This can be a
serious
security risk Here’s what Ruby does about this: All data that comes from the outside world, and all data derived from that data, can automatically be marked as tainted Ruby has five $SAFE levels, each of which has a long list of things you cannot do with a tainted object
printf and friends
printf
format_string
,
value
, …,
value
Formats are %
length code
for most things, %
length . fractional_digits
%d %f decimal, %o float, %s octal, string code for floats %x hex, %b binary, Negative lengths mean left justified Various other controls Example:
printf "pi = %8.4f", 3.141592
pi.=…3.1416
The (equivalent) methods
sprintf
and
format
take the same parameters as
printf
, but return the resultant string rather than printing it
Some File < IO methods
gets getc – get a line of text – get a character of text (as ASCII; use ungetc – put back a character .chr
) pos – the current character position in the input stream lineno – the number of times gets has been called pos= – move to the given position in the file rewind – move to the beginning of the file readlines – read the stream as an array of strings write(
string
) , print(
string
) , <<(
string
) – write at the current position eof?
– test if at the end of file closed?
– test if the file has been closed
Some File methods
rename(
oldname
,
newname
) read(
filename
) – rename a file – read the entire file as a single string readlines(
filename
) – read the entire file as an array of strings open(
filename, mode
) – with no block, a synonym for File.new
with a block, the file is passed to the block, and
automatically closed
block finishes Modes: "r" read, "r+" read and write, "w" write, "a" append exists?(
filename
) – test if a file with that name exists writable?(
filename
) – test if the file can be written directory?(
filename
) zero?(
filename
) – test if the file is a directory – test if the file is empty size(
filename
) – returns the size of the file mtime(
filenam
e) – returns the modification time of the file when the
Streams
The following constants refer to standard I/O streams:
STDIN
,
STDOUT
,
STDERR
The following variables are initially set to the corresponding constants:
$stdin
,
$stdout
,
$stderr
In addition,
$defout
(initially equal to
$stdout
) is where output with no specified destination is sent
Some String methods
ljust(
length
), center(
length
), rjust(
length
)
– left justify, center, or right justify the string by padding with spaces
downcase
,
upcase
,
swap
,
capitalize
– modify capitalization
include?(
s_or_c
)
– tests whether the string includes the given string or character
index(
s_or_c
[,
offset
])
– returns the index after
offset
(or
nil
) at which the gives string starts
rindex(
s_or_c
[,
limit
])
– returns the last index (before
limi
t
), or
nil
, at which the string starts
Some more String methods
strip
– remove leading and trailing spaces
chop
– remove the last character (also
chop!
is destructive)
chomp
– remove the last character if it is a newline (also
chomp!
)
tr(
chars
,
replacement
)
– replace the characters in
chars
with the corresponding characters in
replacement
; accepts
ch1-ch2
notation
Some Array methods
min
,
max
– return the smallest or largest element
uniq
– return an array with no duplicate elements
compact
– return an array with no nil elements
sort
– return a sorted array
&
– perform an intersection (only elements in both)
|
– perform a union (elements in either)
grep(
regexp
) – return elements matching the pattern
push(
element
) – add the element to the end of the array
pop
– remove and return the last element
shift
– remove and return the first element
Chaining
Nondestructive methods can usually be chained Example: x = gets.chomp.strip.downcase
Many destructive methods return nil if they make no changes in the receiver, hence cannot be chained Example: x = gets.chomp!.strip!.downcase!
will result in a runtime error
Context
def do_it a = [1, 2, 3, 5, 8, 13, "hi"] x = 4 end # local variable a.my_each { |v| print v * x, "; " } do_it 4; 8; 12; 20; 32; 52; hihihihi; Notice that the print v*x my_each statement is being executed in the method, not in the do_it method However, x is local to the do_it method How can this be?
Answer:
The block carries its context along with it
A block is a closure
More iterators
collection.each_index
– iterate over the indices of a collection collection.each_with_index
– iterate over the values in a collection, along with their indices Example: lineup.each_with_index { |man, pos| print pos, man } hash.each_key
– iterate over keys hash.each_value
– iterate over values hash.each_pair
– iterate over key-value pairs collection.select { |
v
|
condition
} – choose only items that meet the condition collection.map { |
v
|
transformation
} – create a new collection with the transformation applied to each item
Procs
A proc is a procedure that is stored in a variable Call a proc by using the variable’s call method
p = Proc.new { |x, y, z| puts 100 * x + 10 * y + z }
p.call 14, 9, 2 1492
max = Proc.new do |a, b| if a > b then a else b end end
puts max.call(0.8, 0.12) 0.8
Procs are closures, too
def scoper p x = 3 p.call
end x = 77 p = Proc.new { puts x } x = 19 scoper p 19
Procs as parameters
A block passed as a parameter to a function becomes a Proc The formal parameter must be last, and is prefixed with an ampersand def foo &b b.call
end foo { puts "Hi!" } Hi!
Reflection
The class method returns the class of an object The superclass method returns the superclass of an object The name method returns the name of a class The new method creates a new object of a class The methods method returns the methods than an object knows how to respond to The instance_variables method returns the attributes of an object There are many other methods to examine (and modify!) a Ruby program while it is executing
Undefined methods
If an undefined method is called, Ruby raises a
NoMethodError
If you supply a
method_missing
object, Ruby will call this instead method for your Example: def method_missing(name, *args) puts "Call of missing method" + " #{name}(#{args.join ', ' })" end fribble 2, :ace Call of missing method fribble(2, ace)
Adding methods to a class
To add (or replace) a method to a class, just open up the class definition again and define the method You can even do this with Ruby’s built-in classes class Array def every_other i = 0 while i < self.length
end yield self[i] i += 2 end end [1, 2, 3, 5, 8, 13].every_other {|v| print v, "; "} 1; 3; 8;
Modules
Classes in Ruby, as in Java, may extend
only one
class Example: class Enterprise < Starship other Everything in the superclass is available in the subclass A module module is defined just like a class (using the word instead of class ) Modules cannot be instantiated, but they may be
included
in a class Including a module is like
copying the code into the class
Example: class Enterprise < Starship include Location ...
Metaprogramming
Metaprogramming is
using programs to write programs
Example uses: You want to add “boilerplate” code to every method You want to “wrap” functions so that they print to a log when they are called and when they return You want to examine a database and automatically create methods to access that database You can do metaprogramming in any language, but...
In Ruby the program can make the changes
to itself, as it runs
The command line
irb
starts an interactive Ruby interpreter
ruby
starts Ruby, with input from the command line End with an end-of-file character (
^D
or
F6
) Not actually very useful
ruby
filename
.rb
ruby -e
quotedString
executes the quoted string Example: ruby -e 'puts "The time is #{Time.now}" '
ruby -v
executes the given file tells you Ruby’s version number On Unix, if the first line of a Ruby file is #!/usr/bin/ruby (or wherever ruby is located), the file can be executed by just entering the file name
Looking ahead
Ruby on Rails (or just Rails ) is the “killer app” that catapulted Ruby to prominence Web applications are extremely complex server-side programs that communicate with the user’s browser using HTML, XML, and CSS, do session management, and handle a server-side database Rails uses metaprogramming to write your web application for you It’s hard to convey just how much work this saves The downside? You still have to understand the programs that it writes
Tutorials
Your textbook has an introduction to Ruby There are many Ruby tutorials on the web--here are some of special interest http://www.tutorialspoint.com/ruby/ Very similar in style to the w3schools tutorials http://www.math.umd.edu/~dcarrera/ruby/0.3/ Short enough to read through http://www.troubleshooters.com/codecorn/ruby/basictutorial.htm
Pretty complete http://www.infoq.com/minibooks/ruby A favorite free online book http://poignantguide.net/ruby/ For something just a “little bit different” :)