A quick Ruby Tutorial, Part 3
300 likes | 443 Vues
Dive deeper into Ruby programming with this tutorial that covers advanced concepts such as creating a Word Index class, handling ranges, and using regular expressions. Learn how to build an index for songs, manipulate ranges to filter values, and utilize regex for efficient string matching. This tutorial is designed to enhance your programming skills while giving practical examples that illustrate the power of Ruby. Join us and expand your knowledge of this versatile language!
A quick Ruby Tutorial, Part 3
E N D
Presentation Transcript
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"