CS 98/198: Web 2.0 Applications Using Ruby on Rails

Download Report

Transcript CS 98/198: Web 2.0 Applications Using Ruby on Rails

UC Berkeley
Hello (Again) Ruby
Things to Review
• Syntax & conventions
• Class methods/variables vs.
Instance methods/variables
• Mix-ins and Modules
• Closures, Yield, and Blocks
CS61A Keywords of the Day
• Symbol
• Environment
Review: Naming
Conventions & Syntax
• ClassNames
class NewRubyProgrammer ...
end
• method_names and variable_names
def learn_conventions
...
end
• predicate_like_methods?
def is_faculty_member?
...
end
• dangerous_methods!
def brainwash_with_ruby!
...
end
• :symbols
favorite_framework = :rails
– Symbol or string? use to_sym and to_s to convert between.
• SOME_CONSTANTS or OtherConstants
– result in warning if reassigned after init
Review: Syntax
• Syntax features
–
–
–
–
Whitespace is not significant (unlike Python)
Statements separated by semicolons or newlines
Statement can span a newline*
Parentheses can often be omitted*
* when unambiguous to parser; use caution!!
 raise "D'oh!" unless valid(arg)
 raise "D'oh!" unless
valid arg
 raise "D'oh!"
unless valid(arg)
• Advice: use a good text editor
Review: Hashes
h = {"key" => 1, :value => "foo" }
h.has_key?("key") => true
h["not a key"] => nil (not an error!)
h.delete(:value) => {"key" => 1 }
h.merge( {:key2 => "3", "hi" => :blah} )
=> {"key"=> 1, "key2" => 3, “hi” => :blah}
• Ruby & Rails idioms
– omitting braces when a function takes a hash as its last
argument
– omitting parens around function arguments
link_to "Edit student", :controller=>'students',
:action=>'edit'
link_to("Edit student", {:controller=>'students',
:action=>'edit'})
• Warning! if ambiguous parse...better safe than sorry!
Administrivia Break
•
•
•
•
5um signup
Lab 0
Self-diagnostic quiz on web page
Books - see course homepage too
– more or less required: Agile Web Development
with Rails, 2nd ed.
– Programming Ruby (free, online at
rubycentral.org/book)
– or The Ruby Way by Fulton
Reminder: Using ri and irb
from the shell
• irb, interactive Ruby interpreter
– follow along with the examples!
• ri (Ruby info) is like man
– ri Comparable
– ri gsub
– ri String#gsub
• Note, need to be in a shell that has PATH and
environment variables set correctly
• See www.ruby-doc.org for more good
documents
UC Berkeley
EVERYTHING IS AN
OBJECT
Everything is an object; (almost)
everything is a method call
• Everything is an object
– Even integers (try 57.methods)
– Even nil (try nil.respond_to?(:to_s))
• (almost) every “operator” is really a method call
– my_str.length => my_str.send(:length)
– mymethod(“foo”) =>
self.send(:mymethod, “foo”)
– 1 + 2 => 1.send(:+, 2)
– arr[4] => arr.send(:[ ], 4)
– arr[3] = “foo” => arr.send(:[ ]=, 3, “foo”)
– if (x == 3) => if (x.send(:==, 3))
Nanoquiz
• What happens?
x="foo"
puts 5+x
puts "5"+x
Classes & Methods
# Methods for MyBank.com
class Account
@@bank_name = "MyBank.com"
# constructor is always called initialize
def initialize(starting_balance=0)
@balance = starting_balance
end
# instance methods
def balance
@balance
end
def deposit(amount)
@balance += amount
end
def withdraw(amount)
@balance -= amount
end
# A class method
def self.bank_name
@@bank_name
end
end
Instance methods, not
instance variables
• Let’s try a few...
my_account.@balance
my_account.balance
my_account.balance = 100
@@bank_name
other_account = Account.new(0)
other_account.bank_name
Account.bank_name
• ...got it?
Instance variables: shortcut
class Foo
def initialize(bar,baz)
@bar,@baz=bar,baz
end
def bar ; @bar ; end
def baz ; @baz; end
def bar=(newbar) ; @bar=newbar ;
end
def baz=(newbaz) ; @baz=newbaz; end
end
Instance variables: shortcut
class Foo
def initialize(bar,baz)
@bar,@baz=bar,baz
end
attr_accessor :bar, :baz
end
Pitfall
class Account
def empty_1
balance = 0.0
end
# warning!!
def empty_2
@balance = 0.0
# OK
end
def empty_3
self.balance = 0.0
different
end
end
# also ok, but
REMEMBER!
• a.b means: call method b on object a
– a is the receiver to which you send the method call, assuming a
will respond to that method
 does not mean: b is an instance variable of a
 does not mean: a is some kind of structure of which b is
a member
Understanding this distinction will save you from much grief
and confusion
There are (almost) no Loops
• “Objects manage their own traversal”
• (1..10).each {|x| ... }
=> range traversal
• my_array.each {|elt| ... }
=> array traversal
• hsh.each_key {|key| ... }
hsh.each_pair {|key,val| .. }
=> hash traversal
• 10.times {...} => iterator of arity zero
• 10.times do
...
end
{...} is a synonym for do...end
Iterators
• Consider a simple linear array...
– you can enumerate its elements
– you can perform operations on the collection
(find, delete_if, sort elements, etc.)
• Now consider a BinaryTree data structure
– instance vars: left child, right child
– each child is either a BinaryTree or something
else—a leaf node
– in principle, should support many of same
operations as array!
Ruby-think
• How would you go about coding a library to
support operations like find, delete_if, sort, etc.?
• Hint 1 (bad): how does sort() library function
work in ANSI C?
• Hint 2 (good): what properties of an Array allow
you to do these things?
– it’s enumerable
– its enumerability gives rise to all the other stuff
• Can we do that in a generic way for a
BinaryTree as well?
Ruby-think, cont.
• The problem in thinking imperatively is that
we don’t know what we will want to do with
the elements when we enumerate them.
• An iterator separates the concept of
“enumerate the elements” from the
concept of “doing something” inside that
loop.
How iterators solve this
problem
Here’s how to use it...
"Armando"
"Will"
Block of arity 1
"Arthur"
• The iterator
yields a value to
the block
• The block
executes in the
environment in
which it was
originally defined
• The block is
called a closure
How about sorting, find, ...?
• Simple! just include the module Enumerable
– Module methods get mixed in to BinaryTree
class
– Contract: module expects BinaryTree objects
to respond_to :each, and it provides the other
methods
• If you want sorting, include Comparable and
make sure the things to be compared
respond_to :<=>
Mix-in example: Comparable
• Example: Define <=> method for your class
• include Comparable
– methods in Comparable get mixed in (added to) the
target class that did the include
– methods in Comparable assume that objects of target
class respond to <=>
– doesn’t actually matter what the class is!
• Now, get < <= => > == between? for free
– and, your class can now be sorted (by mixing in
Enumerable...what do you suppose it assumes?)
– Enumerable also provides all?, any?, collect,
find, include?, inject, map, partition, ....
Duck Typing Makes it Possible
• Ruby type = set of values +
set of operations
• A ruby module defines...
– a collection of behaviors
– that depend only on the
presence of one or more
specific existing behaviors
QuickTime™ and a
TIFF (Uncompressed) decompressor
are needed to see this picture.
• i.e.: If it looks like a duck and walks like a duck
=> it responds to the same methods as a duck.
• Note, a module ≠ a class
– but module methods can get mixed in to classes
Blocks
• Iterators are just one use of closures
• For other interesting ones, check out:
– open method of File class
– form_tag helper method in Rails
• Exercise: implement times in a module
n=3
n.times { print "Ho" }
=> HoHoHo
How would you go about this?
Summary: Ruby’s
Distinguishing Features
• Object-oriented with single inheritance
– everything is an object
– almost everything is a method call
– Modules play a role similar to Java’s
interfaces and enable “duck typing”
• Dynamically typed
– Objects have types; variables don’t
– very few operators in the language; most are
defined as instance methods on objects
• Idiomatically, {} and () sometimes optional
Variables & Methods
• Variables have no type; objects do
– variables spring into existence on first assignment
• nil,false are Boolean false; everything else true
• Everything* is passed-by-reference
– can use clone method to effect pass-by-value
*except Fixnums...
• Defining methods
def foo(x); [x,x+1]; end
def foo(x)
[x,x+1]
end
def foo(x)
return [x,x+1]
end
Arrays
x = [3, 'a', "third", :blah, :last]
x[0] => 3
x[-1] => :last
x[-2] => :blah
x[-3..-1] => ["third", :blah, :last]
y = [1,2]
y += [3,4] => [1,2,3,4]
y << 5 => [1,2,3,4,5]
y << [6,7] => [1,2,3,4,5,[6,7]]
• Note! These are nearly all instance methods of Array—
not language operators!
Hashes and function calls
• Immediate hash (any object can be a key, any object can
be an attribute)
my_hsh = {:foo => 1, "x" => nil, 3 => ['a',4]}
my_hsh[:nonexistent_key] returns nil
• Parens can be omitted from function calls if parsing is
unambiguous
x = foo(3, "no")  x = foo 3, "no"
• Braces can be omitted from hash if parsing is
unambiguous
x = foo( {:a=>1,:b=>2})  x = foo(:a=>1,:b=>2)
– easy way to do keyword arguments
– Caveat: passing immediates to a function that accepts multiple
hashes as its arguments