Download ruby2

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
A quick Ruby Tutorial, Part 2
COMP313
Source: Programming Ruby, The Pragmatic
Programmers’ Guide by Dave Thomas, Chad
Fowler, and Andy Hunt
Writing attributes
class Song def
duration=(new_duration)
@duration = new_duration
end
end
song = Song.new("Bicylops", "Fleck", 260)
song.duration → 260
song.duration = 257 # set attribute with updated value
song.duration → 257
Simpler
class Song
attr_writer :duration
end
song = Song.new("Bicylops", "Fleck", 260)
song.duration = 257
Virtual attributes
class Song
def duration_in_minutes
@duration/60.0 # force floating point
end
def duration_in_minutes=(new_duration)
@duration = (new_duration*60).to_i
end
end
song = Song.new("Bicylops", "Fleck", 260)
song.duration_in_minutes → 4.33333333333333
song.duration_in_minutes = 4.2
song.duration → 252
Class variables
class Song
@@plays = 0
def initialize(name, artist, duration)
@name = name
@artist = artist
@duration = duration
@plays = 0
end
def play
@plays += 1
@@plays += 1
"This song: #@plays plays. Total #@@plays plays."
end
end
Class methods
class Example
def instance_method # instance method
end
def Example.class_method # class method
end
end
#uses:
Example.class_method
Example.new
Singleton class example
class MyLogger
private_class_method :new
@@logger = nil
def MyLogger.create
@@logger = new unless @@logger
@@logger
end
end
Access control
• public: default for all methods (except
initialize), accessible by everyone
• protected: access within class and all
subclasses (!= Java)
• private: only the current object (again !=
Java)
• checked at runtime only!
How to define access
class MyClass
def method1 # default is 'public'
#...
end
protected # subsequent methods will be 'protected'
def method2 # will be 'protected'
#...
end
private # subsequent methods will be 'private'
def method3 # will be 'private'
#...
end
public # subsequent methods will be 'public'
def method4 # and this will be 'public'
#...
end
end
Alternatively
class MyClass
def method1
end
# ... and so on
public :method1, :method4
protected :method2
private :method3
end
Account example
class Accounts
def initialize(checking, savings)
@checking = checking
@savings = savings
end
private def debit(account, amount)
account.balance -= amount
end
def credit(account, amount)
account.balance += amount
end
public #...
def transfer_to_savings(amount)
debit(@checking, amount)
credit(@savings, amount)
end
#...
end
Protected example
class Account
attr_reader :balance # accessor method 'balance'
protected :balance # and make it protected
def greater_balance_than(other)
return @balance > other.balance
end
end
Assignment semantics (like Java)
person1 = "Tim"
person2 = person1
person1[0] = 'J'
person1 → "Jim"
person2 → "Jim”
person1 = "Tim"
person2 = person1.dup
person1[0] = "J"
person1 → "Jim"
person2 → "Tim"
“freeze” objects
person1 = "Tim"
person2 = person1
person1.freeze # prevent modifications to the object
person2[0] = "J" produces:
prog.rb:4:in `[]=': can't modify frozen string (TypeError)
from prog.rb:4
Array access (again)
a = [ 1, 3, 5, 7, 9 ]
a[-1] → 9
a[-2] → 7
a[-99] → nil
a[1, 3] → [3, 5, 7]
a[3, 1] → [7]
a[-3, 2] → [5, 7]
a[1..3] → [3, 5, 7]
a[1...3] → [3, 5]
a[3..3] → [7]
a[-3..-1] → [5, 7, 9]
Implement own sample container
class SongList
def initialize
@songs = Array.new
end
def append(song)
@songs.push(song)
self
end
def delete_first
@songs.shift
end
def delete_last
@songs.pop
end
end
Defining array-like access
class SongList
def [](index)
@songs[index]
end
end
Unit testing
require 'test/unit'
class TestSongList < Test::Unit::TestCase
def test_delete
list = SongList.new
s1 = Song.new('title1', 'artist1', 1)
s2 = Song.new('title2', 'artist2', 2) list.append(s1).append(s2)
assert_equal(s1, list[0])
assert_equal(s2, list[1])
assert_nil(list[9])
assert_equal(s2, list.delete_last)
assert_equal(s1, list.delete_first)
assert_nil(list.delete_last)
end
end
Finding songs by title
class SongList
def with_title(title)
for i in [email protected]
return @songs[i] if title == @songs[i].name
end
return nil
end
end
Finding songs by title (the Ruby way)
class SongList
def with_title(title)
@songs.find {|song| title == song.name }
end
end
Hypothetical find in Array
class Array
def find
for i in 0...size
value = self[i]
return value if yield(value)
end
return nil
end
end
[1, 3, 5, 7, 9].find {|v| v*v > 30 } → 7
inject iterator
[1,3,5,7].inject(0) {|sum, element| sum+element} → 16
[1,3,5,7].inject(1) {|product, element| product*element}
→ 105
[1,3,5,7].inject {|sum, element| sum+element} → 16
[1,3,5,7].inject {|product, element| product*element} →
105
Iterators in Ruby
• are “internal”, I.e. just another method
• Java et.al.: “external”, I.e. explicit
additional object
• pros and cons
more on code blocks
class File
def File.my_open(*args)
result = file = File.new(*args)
# If there's a block, pass in the file and close it on returns
if block_given?
result = yield file
file.close
end
return result
end
end
proc and lambda
def n_times(thing)
return lambda {|n| thing * n }
end
p1 = n_times(23)
p1.call(3) → 69
p1.call(4) → 92
p2 = n_times("Hello ")
p2.call(3) → "Hello Hello Hello "
Numbers
• ints are either in -2^30 to 2^30-1 (or -2^62 to
2^62-1) or arbitrarily large BigNums
num = 81
6.times do
puts "#{num.class}: #{num}"
num *= num
end
Loops using numbers
3.times { print "X " }
1.upto(5) {|i| print i, " " }
99.downto(95) {|i| print i, " " }
50.step(80, 5) {|i| print i, " " }
Strings to numbers
• 1.to_i or Integer(1)
some_file = File.new(“xyz”,”r”)
some_file.each { |line|
v1, v2 = line.split
print v1.to_i + v2.to_i, " ”
}
Song database
/jazz/j00132.mp3 | 3:45 | Fats
Waller | Ain't
Misbehavin'
/jazz/j00319.mp3 | 2:58 | Louis Armstrong | Wonderful
World
/bgrass/bg0732.mp3| 4:09 | Strength in Numbers |
Texas Red
break lines into fields
convert runtime into seconds
remove extra spaces in artists’ names
Song database: code
File.open("songdata") do |song_file|
songs = SongList.new
song_file.each do |line|
file, length, name, title = line.chomp.split(/\s*\|\s*/)
name.squeeze(“ “)
mins, secs = length.scan(/\d+/)
songs.append(Song.new(title, name, mins.to_i*60+secs.to_i))
end
songs
end
Related documents