310 likes | 402 Views
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
E N D
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
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 # warning!! end def empty_2 @balance = 0.0 # OK end def empty_3 self.balance = 0.0 # also ok, but different end end
REMEMBER! • a.b means: call method b on object a • a is the receiver to which you sendthe method call, assuming a will respond tothat 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.
Here’s how to use it... Block of arity 1 "Armando" "Will" "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, includeComparable 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 • 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