Ruby
There are many languages used to generate dynamic web content. We’re going to start with Ruby on Rails. In order to break up the long evening, we’re going to do some Ruby for a while.
- Why Ruby?
- Has all the major advantages of php and perl without many of the disadvantages
- Designed from the ground up as OO, thereby avoiding the awkwardness
- Has a number of aspects of functional programming built in.
- When used properly, these make your programs easier to write / more elegant.
- When most people think of functional programming they think of lisp (or, perhaps scheme).
- What does LISP stand for?
- Lots of stupid parenthesis
- At one time functional programming had a bad name, because pure functional programming can make simple things difficult.
- In my opinion, Ruby gives the best of both worlds:
- OO when it is helpful
- functional when it is helpful
- Functional programming paradigms are slowly making their way into other languages
- Javascript
- C#
- Java (albeit poorly)
- What does LISP stand for?
- Learning Ruby will help you effectively utilize newer language features.
- Ruby has a different way of writing code. This is called “idiomatic”
Ruby. Although you can write familiar Java-style code,
- You will miss out on opportunities for better code
- People might laugh at you.
- Key Ruby ideas
-
Basics are not too different from what you’ve seen before:
puts "Hello, World" x = 5 y = 6 z = x + y puts "5 + 6 = #{z}" if z % 2 == 0 puts "#{z} is even" else puts "#{z} is odd" end
- variables don’t need type
- variables don’t need
$
- variables use underscores (e.g.,
multi_word_variable_name
) not “camel-case” (e.g.,doNotNameVariablesLikeThis
) - Can interpolate variables into strings using the
#{}
construct-
Interpolation is done in double quotes only:
q = 44 puts 'No Interpolation in single quotes: #{q}'
-
Can place code inside brackets
x = 10 y = 15 puts "#{x} + #{y} = #{x + y}" name = 'bob' puts "Hello, #{name.capitalize}"
-
- Symbols and Hashes
- Symbols are like immutable strings.
- They are typically used wherever you would use a constant string and/or enum in Java or C.
- method parameters that select options by name
build_distribution(:uniform)
orbuild_distribution(:normal)
- passing method and/or variable name as parameters (you’ll see examples of this in Rails.)
- keys for hashes (i.e., associative arrays)
- method parameters that select options by name
- Hashes are associative arrays: arrays where the index doesn’t have to be an integer.
-
Keys for hashes can be anything; but, symbols are most common
# The "key: value" syntax here is a short-cut for initializing hashes. # The old syntax was ":key => value" my_dog = { name: "Spot", age: 4, weight: 14 } # Add a year to the age # Notice the use of a symbol for the hash key. my_dog[:age] += 1 puts "My dog, #{my_dog[:name]} is now #{my_dog[:age]} years old." # Sometimes you will want an empty hash to fill later empty_hash = {} empty_hash[:january] = 31 empty_hash[:feb] = 28
-
- Classes and methods
- Constructor is always named
initialize
- Instance variables begin with
@
and do not need to be explicitly declared. - Method parameters do not need types
- Why do some languages (e.g., Java) require types?
- Last expression of a method becomes its return value
- Don’t use explicit
return
statement unless necessary.
- Don’t use explicit
- Constructor is always named
-
class Stats
# constructor is named "initialize"
def initialize
# instance variables begin with "@"
@values = [] # create an empty array
@sum = 0
@sum_sq = 0
end
# Notice that parameters don't need a type
def add(value)
@values << value
@sum += value
@sum_sq += value * value
end
def mean
# value of last expression becomes return value for the method
@sum.to_f / @values.count # to_f is "to float"
end
def median
sorted_values = @values.sort
mid = @values.count / 2
# notice that the if statement takes the value of the
# last line of the block that is run
if (@values.count % 2 == 0)
(@values[mid] + @values[mid - 1]) / 2.0
else
@values[mid]
end
end # method median
end # class Stats
s1 = Stats.new
s1.add(8)
s1.add(6)
s1.add(7)
puts "Mean is #{s1.mean}. Median: #{s1.median}"
s1.add(5)
puts "Mean is #{s1.mean}. Median: #{s1.median}"
Code blocks
- It is often helpful to be able to pass blocks of code (or methods) as parameters to other methods.
- Think about button handlers in Java Swing: When calling
button.addEventListener(...)
what you really want is to specify the code to be executed when the button is clicked.- The obnoxious “Anonymous inner class” syntax in Java is what was was used before Java added lambdas in Java 1.8.
-
Think about the selection sort algorithm
def traditional_selection_sort(values) # Don't write for loops this way! Use the idiomatic values.each I'll show you in a minute. for i in 0..(values.count - 1) min_loc = i for j in (i + 1)..(values.count - 1) # It would be nice to make the "<" a parameter so you can # compare objects using any algorithm. min_loc = j if values[j] < values[min_loc] end # swap values[i] and values[min_loc] temp = values[i] values[i] = values[min_loc] values[min_loc] = temp end values end p traditional_selection_sort([8, 6, 7, 5, 3, 0, 9])
- The code above will only sort numbers in ascending order.
- Sorting in descending order requires cutting-and-pasting the code and changing one character ‘<’ to ‘>’
- The code to sort more complex objects (e.g., Students by GPA) is 99% the same.
- How would we modify the code to sort Students?
- Code blocks allows us to use one method for storing and pass in the comparison algorithm.
- Think about button handlers in Java Swing: When calling
def selection_sort(values)
# Don't write for loops this way! Use the idiomatic values.each I'll show you in a minute.
for i in 0..(values.count - 1)
min_loc = i
for j in (i + 1)..(values.count - 1)
min_loc = j if yield(values[j], values[min_loc])
end
# swap values[i] and values[min_loc]
temp = values[i]
values[i] = values[min_loc]
values[min_loc] = temp
end
values
end
# Sorted low to high
p selection_sort([8, 6, 7, 5, 3, 0, 9]) { |a, b| a < b}
# Sorted high to low
p selection_sort([8, 6, 7, 5, 3, 0, 9]) { |a, b| a > b}
# Sort dogs by age
dog1 = {name: 'Fido', age: 14, weight: 6}
dog2 = {name: 'Spot', age: 4, weight: 12}
dog3 = {name: 'Rover', age: 12, weight: 22}
p selection_sort([dog1, dog2, dog3]) {|a, b| a[:age] < b[:age]}
- Ruby makes heavy use of the block syntax.
- Most loops use it.
- Don’t do this:
for i in 0..(array.count - 1)
. You will get lauged at. - Idiomatic ruby uses blocks:
array.each { |i| ... }
- Don’t do this:
- In the rare case you also need the loop index, use
each_with_index
array.each_with_index { |item, index| puts "Item number #{index} is #{item}"}
- Use
{}
syntax when block fits on one line. -
Use
do-end
syntax when block needs more than one line:array.each_with_index do |item, index| puts "Item number #{index} is #{item}" end
- The
map
method converts one array into another:
array = [1, 2, 3, 4, 5, 6, 7]
squared = array.map { |i| i * i }
p squared
names = [
{ first: 'George', last: 'Washington' },
{ first: 'John', last: 'Adams' },
{ first: 'Thomas', last: 'Jefferson' },
{ first: 'James', last: 'Madison' },
{ first: 'James', last: 'Monroe' }
]
full_names = names.map { |i| "#{i[:last]}, #{i[:first]}"}
p full_names
- Open classes
-
You can add methods to classes
class String def first self[0] end end puts "Hello".first
- Can also add methods to specific objet instances.
- Rails does this a lot; but,
- Don’t overuse it.
-
- Misc.
- Method names are allowed to end in ‘?’ and ‘!’
- Characters have no semantic value; but, by convention
- ’?’ methods used for methods that ask questions:
nil?
,has_key?
- ’!’ methods used for methods that modify an object
sort
vssort!
- ’?’ methods used for methods that ask questions:
Array
comes with a lot of useful methods:- API
select
include?
compact
count
first
last
select
max
min
push
pop
reject
reverse
slice
uniq
- Sample Ruby files:
- For more practice