300 likes | 428 Views
A quick Ruby Tutorial, Part 3. COMP313 Source: Programming Ruby, The Pragmatic Programmers’ Guide by Dave Thomas, Chad Fowler, and Andy Hunt. Index by each word. class WordIndex def initialize @index = {} end def add_to_index(obj, *phrases) phrases.each do |phrase|
E N D
A quick Ruby Tutorial, Part 3 COMP313 Source: Programming Ruby, The Pragmatic Programmers’ Guide by Dave Thomas, Chad Fowler, and Andy Hunt
Index by each word class WordIndex def initialize @index = {} end def add_to_index(obj, *phrases) phrases.each do |phrase| phrase.scan(/\w[-\w']+/) do |word| # extract each word word.downcase! @index[word] = [] if @index[word].nil? @index[word].push(obj) end end end def lookup(word) @index[word.downcase] end end
Add full index to SongList class SongList def initialize @songs = Array.new @index = WordIndex.new end def append(song) @songs.push(song) @index.add_to_index(song, song.name, song.artist) self end def lookup(word) @index.lookup(word) end end
Ranges 1..10 'a'..'z' my_array = [ 1, 2, 3 ] 0...my_array.length (1..10).to_a → [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ('bar'..'bat').to_a → ["bar", "bas", "bat"] digits = 0..9 digits.include?(5) → true digits.min → 0 digits.max → 9 digits.reject {|i| i < 5 } → [5, 6, 7, 8, 9] digits.each {|digit| dial(digit) } → 0..9
Range example: VU meter class VU include Comparable attr :volume def initialize(volume) # 0..9 @volume = volume end def inspect '#' * @volume end # Support for ranges def <=>(other) self.volume <=> other.volume end def succ raise(IndexError, "Volume too big") if @volume >= 9 VU.new(@volume.succ) end end
VU Ranges / Ranges in conditions medium_volume = VU.new(4)..VU.new(7) medium_volume.to_a → [####, #####, ######, #######] medium_volume.include?(VU.new(3)) → false (1..10) === 5 → true (1..10) === 15 → false (1..10) === 3.14159 → true ('a'..'j') === 'c' → true ('a'..'j') === 'z' → false
Regular expressions a = Regexp.new('^\s*[a-z]') → /^\s*[a-z]/ b = /^\s*[a-z]/ → /^\s*[a-z]/ c = %r{^\s*[a-z]} → /^\s*[a-z]/ name = "Fats Waller" name =~ /a/ → 1 name =~ /z/ → nil /a/ =~ name → 1
Special vars $` $& $’ def show_regexp(a, re) if a =~ re "#{$`}<<#{$&}>>#{$'}" else "no match" end end show_regexp('very interesting', /t/) → very in<<t>>eresting show_regexp('Fats Waller', /a/) → F<<a>>ts Waller show_regexp('Fats Waller', /ll/) → Fats Wa<<ll>>er show_regexp('Fats Waller', /z/) → no match
Special chars, anchors ., |, (, ), [, ], {, }, +, \, ^, $, *, and ? show_regexp('kangaroo', /angar/) → k<<angar>>oo show_regexp('!@%&-_=+', /%&/) → !@<<%&>>-_=+ show_regexp("this is\nthe time", /^the/) → this is\n<<the>> time show_regexp("this is\nthe time", /is$/) → this <<is>>\nthe time show_regexp("this is\nthe time", /\Athis/) → <<this>> is\nthe time show_regexp("this is\nthe time", /\Athe/)no match
More RegExps show_regexp('Price $12.', /[aeiou]/) → Pr<<i>>ce $12. show_regexp('Price $12.', /[\s]/) → Price<< >>$12. show_regexp('Price $12.', /[[:digit:]]/) → Price $<<1>>2. show_regexp('Price $12.', /[[:space:]]/) → Price<< >>$12. show_regexp('Price $12.', /[[:punct:]aeiou]/) → Pr<<i>>ce $12. a = 'see [Design Patterns-page 123]' show_regexp(a, /[A-F]/) → see [<<D>>esign Patterns-page 123] show_regexp(a, /[A-Fa-f]/) → s<<e>>e [Design Patterns-page 123] show_regexp(a, /[0-9]/) → see [Design Patterns-page <<1>>23] show_regexp(a, /[0-9][0-9]/) → see [Design Patterns-page <<12>>3]
character classes \d[0-9] Digit character \D[^0-9] Any character except a digit \s[ \t\r\n\f] Whitespace character \S[^ \t\r\n\f] Any character except whitespace \w[A-Za-z0-9_] Word character \W[^A-Za-z0-9_] Any character except a word character
Repetition r*matches zero or more occurrences ofr. r+matches one or more occurrences ofr. r?matches zero or one occurrence ofr. r{m,n}matches at least m and at most n occurrences ofr. r{m,}matches at least m occurrences ofr. r{m}matches exactly m occurrences ofr. /ab+/ matches ab, abb, abbbb, … /(ab)+/ matches ab, abab, ababab, … /a*/ matches everything (why?)
Greedy matching/Alternatives a = "The moon is made of cheese" show_regexp(a, /\w+/) → <<The>> moon is made of cheese show_regexp(a, /\s.*\s/) → The<< moon is made of >>cheese show_regexp(a, /\s.*?\s/) → The<< moon >>is made of cheese show_regexp(a, /[aeiou]{2,99}/) → The m<<oo>>n is made of cheese a = "red ball blue sky" show_regexp(a, /d|e/) → r<<e>>d ball blue sky show_regexp(a, /al|lu/) → red b<<al>>l blue sky show_regexp(a, /red ball|angry sky/) → <<red ball>> blue sky
Groupings show_regexp('banana', /an*/) → b<<an>>ana show_regexp('banana', /(an)*/) → <<>>banana show_regexp('banana', /(an)+/) → b<<anan>>a a = 'red ball blue sky' show_regexp(a, /blue|red/) → <<red>> ball blue sky show_regexp(a, /(blue|red) \w+/) → <<red ball>> blue sky show_regexp(a, /(red|blue) \w+/) → <<red ball>> blue sky show_regexp(a, /red|blue \w+/) → <<red>> ball blue sky show_regexp(a, /red (ball|angry) sky/) → no match a = 'the red angry sky' show_regexp(a, /red (ball|angry) sky/) → the <<red angry sky>>
Groupings collect matches "12:50am" =~ /(\d\d):(\d\d)(..)/ → 0 "Hour is #$1, minute #$2" → "Hour is 12, minute 50" "12:50am" =~ /((\d\d):(\d\d))(..)/ → 0 "Time is #$1" → "Time is 12:50" "Hour is #$2, minute #$3" → "Hour is 12, minute 50" "AM/PM is #$4" → "AM/PM is am"
Match inside with \1,… # match duplicated letter show_regexp('He said "Hello"', /(\w)\1/) → He said "He<<ll>>o" # match duplicated substrings show_regexp('Mississippi', /(\w+)\1/) → M<<ississ>>ippi show_regexp('He said "Hello"', /(["']).*?\1/) → He said <<"Hello">> show_regexp("He said 'Hello'", /(["']).*?\1/) → He said <<'Hello'>>
Substitute patterns a = "the quick brown fox" a.sub(/[aeiou]/, '*') → "th* quick brown fox" a.gsub(/[aeiou]/, '*') → "th* q**ck br*wn f*x" a.sub(/\s\S+/, '') → "the brown fox" a.gsub(/\s\S+/, '') → "the" a.sub(/^./) {|match| match.upcase } → "The quick brown fox" a.gsub(/[aeiou]/) {|vowel| vowel.upcase } → "thE qUIck brOwn fOx"
Upcase every first char def mixed_case(name) name.gsub(/\b\w/) {|word| word.upcase } end mixed_case("fats waller") → "Fats Waller" mixed_case("louis armstrong") → "Louis Armstrong" mixed_case("strength in numbers") → "Strength In Numbers"
Classes behind regexps re = /(\d+):(\d+)/ # match a time hh:mm re.class -> Regexp md = re.match("Time: 12:34am") md.class → MatchData md[0] → "12:34" # $& md[1] → "12" # $1 md[2] → "34" # $2 md.pre_match → "Time: ” # $` md.post_match → "am" # $’
optional args for methods def cool_dude(arg1="Miles", arg2="Coltrane", arg3="Roach") "#{arg1}, #{arg2}, #{arg3}." end cool_dude → "Miles, Coltrane, Roach." cool_dude("Bart") → "Bart, Coltrane, Roach." cool_dude("Bart", "Elwood") → "Bart, Elwood, Roach." cool_dude("Bart", "Elwood", "Linus") → "Bart, Elwood, Linus."
Variable number of args def varargs(arg1, *rest) "Got #{arg1} and #{rest.join(', ')}" end varargs("one") → "Got one and " varargs("one", "two") → "Got one and two" varargs "one", "two", "three" → "Got one and two, three"
code blocks again def take_block(p1) if block_given? yield(p1) else p1 end end take_block("no block") → "no block" take_block("no block") {|s| s.sub(/no /, ‘’) } → "block"
Capture block explicitly class TaxCalculator def initialize(name, &block) @name, @block = name, block end def get_tax(amount) "#@name on #{amount} = #{ @block.call(amount) }" end end tc = TaxCalculator.new("Sales tax") {|amt| amt * 0.075 } tc.get_tax(100) → "Sales tax on 100 = 7.5" tc.get_tax(250) → "Sales tax on 250 = 18.75"
Calling a method connection.download_MP3("jitterbug") {|p| show_progress(p) } File.size("testfile") → 66 Math.sin(Math::PI/4) → 0.707106781186548 self.class → Object self.frozen? → false frozen? → false self.object_id → 969948 object_id → 969948
Multiple return values def some_method 100.times do |num| square = num*num return num, square if square > 1000 end end some_method → [32, 1024] num, square = some_method num → 32 square → 1024
Expanding arrays into args def five(a, b, c, d, e) "I was passed #{a} #{b} #{c} #{d} #{e}" end five(1, 2, 3, 4, 5 ) → "I was passed 1 2 3 4 5" five(1, 2, 3, *['a', 'b']) → "I was passed 1 2 3 a b" five(*(10..14).to_a) → "I was passed 10 11 12 13 14"
& for procedure objects print "(t)imes or (p)lus: " times = gets print "number: " number = Integer(gets) if times =~ /^t/ calc = lambda {|n| n*number } else calc = lambda {|n| n+number } end puts((1..10).collect(&calc).join(", ")) (t)imes or (p)lus: t number: 2 2, 4, 6, 8, 10, 12, 14, 16, 18, 20
Keyword args: use Hash class SongList def create_search(name, params) # ... end end list.create_search("short jazz songs", { 'genre' => "jazz", 'duration_less_than' => 270 }) list.create_search('short jazz songs', 'genre' => 'jazz', 'duration_less_than' => 270)
Expression fun a = b = c = 0 → 0 [ 3, 1, 7, 0 ].sort.reverse → [7, 3, 1, 0] song_type = if song.mp3_type == MP3::Jazz if song.written < Date.new(1935, 1, 1) Song::TradJazz else Song::Jazz end else Song::Other end
More expressions rating = case votes_cast when 0...10 then Rating::SkipThisOne when 10...50 then Rating::CouldDoBetter else Rating::Rave end command expressions: `date` → "Mon Jan 16 22:32:17 CST 2006\n"