/text/src/test/resources/examples/ruby/pleac.in.rb
Ruby | 6368 lines | 4278 code | 927 blank | 1163 comment | 310 complexity | cbeb52b0e3a76e39866eae7fd5c5280e MD5 | raw file
Possible License(s): EPL-1.0, MPL-2.0-no-copyleft-exception
Large files files are truncated, but you can click here to view the full file
- # -*- ruby -*-
- # Local variables:
- # indent-tabs-mode: nil
- # ruby-indent-level: 4
- # End:
- # @@PLEAC@@_NAME
- # @@SKIP@@ Ruby
- # @@PLEAC@@_WEB
- # @@SKIP@@ http://www.ruby-lang.org
- # @@PLEAC@@_1.0
- string = '\n' # two characters, \ and an n
- string = 'Jon \'Maddog\' Orwant' # literal single quotes
- string = "\n" # a "newline" character
- string = "Jon \"Maddog\" Orwant" # literal double quotes
- string = %q/Jon 'Maddog' Orwant/ # literal single quotes
- string = %q[Jon 'Maddog' Orwant] # literal single quotes
- string = %q{Jon 'Maddog' Orwant} # literal single quotes
- string = %q(Jon 'Maddog' Orwant) # literal single quotes
- string = %q<Jon 'Maddog' Orwant> # literal single quotes
- a = <<"EOF"
- This is a multiline here document
- terminated by EOF on a line by itself
- EOF
- # @@PLEAC@@_1.1
- value = string[offset,count]
- value = string[offset..-1]
- string[offset,count] = newstring
- string[offset..-1] = newtail
- # in Ruby we can also specify intervals by their two offsets
- value = string[offset..offs2]
- string[offset..offs2] = newstring
- leading, s1, s2, trailing = data.unpack("A5 x3 A8 A8 A*")
- fivers = string.unpack("A5" * (string.length/5))
- chars = string.unpack("A1" * string.length)
- string = "This is what you have"
- # +012345678901234567890 Indexing forwards (left to right)
- # 109876543210987654321- Indexing backwards (right to left)
- # note that 0 means 10 or 20, etc. above
- first = string[0, 1] # "T"
- start = string[5, 2] # "is"
- rest = string[13..-1] # "you have"
- last = string[-1, 1] # "e"
- end_ = string[-4..-1] # "have"
- piece = string[-8, 3] # "you"
- string[5, 2] = "wasn't" # change "is" to "wasn't"
- string[-12..-1] = "ondrous" # "This wasn't wondrous"
- string[0, 1] = "" # delete first character
- string[-10..-1] = "" # delete last 10 characters
- if string[-10..-1] =~ /pattern/
- puts "Pattern matches in last 10 characters"
- end
- string[0, 5].gsub!(/is/, 'at')
- a = "make a hat"
- a[0, 1], a[-1, 1] = a[-1, 1], a[0, 1]
- a = "To be or not to be"
- b = a.unpack("x6 A6")
- b, c = a.unpack("x6 A2 X5 A2")
- puts "#{b}\n#{c}\n"
- def cut2fmt(*args)
- template = ''
- lastpos = 1
- for place in args
- template += "A" + (place - lastpos).to_s + " "
- lastpos = place
- end
- template += "A*"
- return template
- end
- fmt = cut2fmt(8, 14, 20, 26, 30)
- # @@PLEAC@@_1.2
- # careful! "b is true" doesn't mean "b != 0" (0 is true in Ruby)
- # thus no problem of "defined" later since only nil is false
- # the following sets to `c' if `b' is nil or false
- a = b || c
- # if you need Perl's behaviour (setting to `c' if `b' is 0) the most
- # effective way is to use Numeric#nonzero? (thanks to Dave Thomas!)
- a = b.nonzero? || c
- # you will still want to use defined? in order to test
- # for scope existence of a given object
- a = defined?(b) ? b : c
- dir = ARGV.shift || "/tmp"
- # @@PLEAC@@_1.3
- v1, v2 = v2, v1
- alpha, beta, production = %w(January March August)
- alpha, beta, production = beta, production, alpha
- # @@PLEAC@@_1.4
- num = char[0]
- char = num.chr
- # Ruby also supports having a char from character constant
- num = ?r
- char = sprintf("%c", num)
- printf("Number %d is character %c\n", num, num)
- ascii = string.unpack("C*")
- string = ascii.pack("C*")
- hal = "HAL"
- ascii = hal.unpack("C*")
- # We can't use Array#each since we can't mutate a Fixnum
- ascii.collect! { |i|
- i + 1 # add one to each ASCII value
- }
- ibm = ascii.pack("C*")
- puts ibm
- # @@PLEAC@@_1.5
- array = string.split('')
- array = string.unpack("C*")
- string.scan(/./) { |b|
- # do something with b
- }
- string = "an apple a day"
- print "unique chars are: ", string.split('').uniq.sort, "\n"
- sum = 0
- for ascval in string.unpack("C*") # or use Array#each for a pure OO style :)
- sum += ascval
- end
- puts "sum is #{sum & 0xffffffff}" # since Ruby will go Bignum if necessary
- # @@INCLUDE@@ include/ruby/slowcat.rb
- # @@PLEAC@@_1.6
- revbytes = string.reverse
- revwords = string.split(" ").reverse.join(" ")
- revwords = string.split(/(\s+)/).reverse.join
- # using the fact that IO is Enumerable, you can directly "select" it
- long_palindromes = File.open("/usr/share/dict/words").
- select { |w| w.chomp!; w.reverse == w && w.length > 5 }
- # @@PLEAC@@_1.7
- while string.sub!("\t+") { ' ' * ($&.length * 8 - $`.length % 8) }
- end
- # @@PLEAC@@_1.8
- 'You owe #{debt} to me'.gsub(/\#{(\w+)}/) { eval($1) }
- rows, cols = 24, 80
- text = %q(I am #{rows} high and #{cols} long)
- text.gsub!(/\#{(\w+)}/) { eval("#{$1}") }
- puts text
- 'I am 17 years old'.gsub(/\d+/) { 2 * $&.to_i }
- # @@PLEAC@@_1.9
- e = "bo peep".upcase
- e.downcase!
- e.capitalize!
- "thIS is a loNG liNE".gsub!(/\w+/) { $&.capitalize }
- # @@PLEAC@@_1.10
- "I have #{n+1} guanacos."
- print "I have ", n+1, " guanacos."
- # @@PLEAC@@_1.11
- var = <<'EOF'.gsub(/^\s+/, '')
- your text
- goes here
- EOF
- # @@PLEAC@@_1.12
- string = "Folding and splicing is the work of an editor,\n"+
- "not a mere collection of silicon\n"+
- "and\n"+
- "mobile electrons!"
- def wrap(str, max_size)
- all = []
- line = ''
- for l in str.split
- if (line+l).length >= max_size
- all.push(line)
- line = ''
- end
- line += line == '' ? l : ' ' + l
- end
- all.push(line).join("\n")
- end
- print wrap(string, 20)
- #=> Folding and
- #=> splicing is the
- #=> work of an editor,
- #=> not a mere
- #=> collection of
- #=> silicon and mobile
- #=> electrons!
- # @@PLEAC@@_1.13
- string = %q(Mom said, "Don't do that.")
- string.gsub(/['"]/) { '\\'+$& }
- string.gsub(/['"]/, '\&\&')
- string.gsub(/[^A-Z]/) { '\\'+$& }
- "is a test!".gsub(/\W/) { '\\'+$& } # no function like quotemeta?
- # @@PLEAC@@_1.14
- string.strip!
- # @@PLEAC@@_1.15
- def parse_csv(text)
- new = text.scan(/"([^\"\\]*(?:\\.[^\"\\]*)*)",?|([^,]+),?|,/)
- new << nil if text[-1] == ?,
- new.flatten.compact
- end
- line = %q<XYZZY,"","O'Reilly, Inc","Wall, Larry","a \"glug\" bit,",5,"Error, Core Dumped">
- fields = parse_csv(line)
- fields.each_with_index { |v,i|
- print "#{i} : #{v}\n";
- }
- # @@PLEAC@@_1.16
- # Use the soundex.rb Library from Michael Neumann.
- # http://www.s-direktnet.de/homepages/neumann/rb_prgs/Soundex.rb
- require 'Soundex'
- code = Text::Soundex.soundex(string)
- codes = Text::Soundex.soundex(array)
- # substitution function for getpwent():
- # returns an array of user entries,
- # each entry contains the username and the full name
- def login_names
- result = []
- File.open("/etc/passwd") { |file|
- file.each_line { |line|
- next if line.match(/^#/)
- cols = line.split(":")
- result.push([cols[0], cols[4]])
- }
- }
- result
- end
- puts "Lookup user: "
- user = STDIN.gets
- user.chomp!
- exit unless user
- name_code = Text::Soundex.soundex(user)
- splitter = Regexp.new('(\w+)[^,]*\b(\w+)')
- for username, fullname in login_names do
- firstname, lastname = splitter.match(fullname)[1,2]
- if name_code == Text::Soundex.soundex(username)
- || name_code == Text::Soundex.soundex(firstname)
- || name_code == Text::Soundex.soundex(lastname)
- then
- puts "#{username}: #{firstname} #{lastname}"
- end
- end
- # @@PLEAC@@_1.17
- # @@INCLUDE@@ include/ruby/fixstyle.rb
- # @@PLEAC@@_1.18
- # @@INCLUDE@@ include/ruby/psgrep.rb
- # @@PLEAC@@_2.1
- # Matz tells that you can use Integer() for strict checked conversion.
- Integer("abc")
- #=> `Integer': invalid value for Integer: "abc" (ArgumentError)
- Integer("567")
- #=> 567
- # You may use Float() for floating point stuff
- Integer("56.7")
- #=> `Integer': invalid value for Integer: "56.7" (ArgumentError)
- Float("56.7")
- #=> 56.7
- # You may also use a regexp for that
- if string =~ /^[+-]?\d+$/
- p 'is an integer'
- else
- p 'is not'
- end
- if string =~ /^-?(?:\d+(?:\.\d*)?|\.\d+)$/
- p 'is a decimal number'
- else
- p 'is not'
- end
- # @@PLEAC@@_2.2
- # equal(num1, num2, accuracy) : returns true if num1 and num2 are
- # equal to accuracy number of decimal places
- def equal(i, j, a)
- sprintf("%.#{a}g", i) == sprintf("%.#{a}g", j)
- end
- wage = 536 # $5.36/hour
- week = 40 * wage # $214.40
- printf("One week's wage is: \$%.2f\n", week/100.0)
- # @@PLEAC@@_2.3
- num.round # rounds to integer
- a = 0.255
- b = sprintf("%.2f", a)
- print "Unrounded: #{a}\nRounded: #{b}\n"
- printf "Unrounded: #{a}\nRounded: %.2f\n", a
- print "number\tint\tfloor\tceil\n"
- a = [ 3.3 , 3.5 , 3.7, -3.3 ]
- for n in a
- printf("% .1f\t% .1f\t% .1f\t% .1f\n", # at least I don't fake my output :)
- n, n.to_i, n.floor, n.ceil)
- end
- # @@PLEAC@@_2.4
- def dec2bin(n)
- [n].pack("N").unpack("B32")[0].sub(/^0+(?=\d)/, '')
- end
- def bin2dec(n)
- [("0"*32+n.to_s)[-32..-1]].pack("B32").unpack("N")[0]
- end
- # @@PLEAC@@_2.5
- for i in x .. y
- # i is set to every integer from x to y, inclusive
- end
- x.step(y,7) { |i|
- # i is set to every integer from x to y, stepsize = 7
- }
- print "Infancy is: "
- (0..2).each { |i|
- print i, " "
- }
- print "\n"
- # @@PLEAC@@_2.6
- # We can add conversion methods to the Integer class,
- # this makes a roman number just a representation for normal numbers.
- class Integer
-
- @@romanlist = [["M", 1000],
- ["CM", 900],
- ["D", 500],
- ["CD", 400],
- ["C", 100],
- ["XC", 90],
- ["L", 50],
- ["XL", 40],
- ["X", 10],
- ["IX", 9],
- ["V", 5],
- ["IV", 4],
- ["I", 1]]
-
- def to_roman
- remains = self
- roman = ""
- for sym, num in @@romanlist
- while remains >= num
- remains -= num
- roman << sym
- end
- end
- roman
- end
-
- def Integer.from_roman(roman)
- ustr = roman.upcase
- sum = 0
- for entry in @@romanlist
- sym, num = entry[0], entry[1]
- while sym == ustr[0, sym.length]
- sum += num
- ustr.slice!(0, sym.length)
- end
- end
- sum
- end
-
- end
- roman_fifteen = 15.to_roman
- puts "Roman for fifteen is #{roman_fifteen}"
- i = Integer.from_roman(roman_fifteen)
- puts "Converted back, #{roman_fifteen} is #{i}"
- # check
- for i in (1..3900)
- r = i.to_roman
- j = Integer.from_roman(r)
- if i != j
- puts "error: #{i} : #{r} - #{j}"
- end
- end
- # @@PLEAC@@_2.7
- random = rand(y-x+1)+x
- chars = ["A".."Z","a".."z","0".."9"].collect { |r| r.to_a }.join + %q(!@$%^&*)
- password = (1..8).collect { chars[rand(chars.size)] }.pack("C*")
- # @@PLEAC@@_2.8
- srand # uses a combination of the time, the process id, and a sequence number
- srand(val) # for repeatable behaviour
- # @@PLEAC@@_2.9
- # from the randomr lib:
- # http://raa.ruby-lang.org/project/randomr/
- ----> http://raa.ruby-lang.org/project/randomr/
- require 'random/mersenne_twister'
- mers = Random::MersenneTwister.new 123456789
- puts mers.rand(0) # 0.550321932544541
- puts mers.rand(10) # 2
- # using online sources of random data via the realrand package:
- # http://raa.ruby-lang.org/project/realrand/
- # **Note**
- # The following online services are used in this package:
- # http://www.random.org - source: atmospheric noise
- # http://www.fourmilab.ch/hotbits - source: radioactive decay timings
- # http://random.hd.org - source: entropy from local and network noise
- # Please visit the sites and respect the rules of each service.
- require 'random/online'
- generator1 = Random::RandomOrg.new
- puts generator1.randbyte(5).join(",")
- puts generator1.randnum(10, 1, 6).join(",") # Roll dice 10 times.
- generator2 = Random::FourmiLab.new
- puts generator2.randbyte(5).join(",")
- # randnum is not supported.
- generator3 = Random::EntropyPool.new
- puts generator3.randbyte(5).join(",")
- # randnum is not supported.
- # @@PLEAC@@_2.10
- def gaussian_rand
- begin
- u1 = 2 * rand() - 1
- u2 = 2 * rand() - 1
- w = u1*u1 + u2*u2
- end while (w >= 1)
- w = Math.sqrt((-2*Math.log(w))/w)
- [ u2*w, u1*w ]
- end
- mean = 25
- sdev = 2
- salary = gaussian_rand[0] * sdev + mean
- printf("You have been hired at \$%.2f\n", salary)
- # @@PLEAC@@_2.11
- def deg2rad(d)
- (d/180.0)*Math::PI
- end
- def rad2deg(r)
- (r/Math::PI)*180
- end
- # @@PLEAC@@_2.12
- sin_val = Math.sin(angle)
- cos_val = Math.cos(angle)
- tan_val = Math.tan(angle)
- # AFAIK Ruby's Math module doesn't provide acos/asin
- # While we're at it, let's also define missing hyperbolic functions
- module Math
- def Math.asin(x)
- atan2(x, sqrt(1 - x**2))
- end
- def Math.acos(x)
- atan2(sqrt(1 - x**2), x)
- end
- def Math.atan(x)
- atan2(x, 1)
- end
- def Math.sinh(x)
- (exp(x) - exp(-x)) / 2
- end
- def Math.cosh(x)
- (exp(x) + exp(-x)) / 2
- end
- def Math.tanh(x)
- sinh(x) / cosh(x)
- end
- end
- # The support for Complex numbers is not built-in
- y = Math.acos(3.7)
- #=> in `sqrt': square root for negative number (ArgumentError)
- # There is an implementation of Complex numbers in 'complex.rb' in current
- # Ruby distro, but it doesn't support atan2 with complex args, so it doesn't
- # solve this problem.
- # @@PLEAC@@_2.13
- log_e = Math.log(val)
- log_10 = Math.log10(val)
- def log_base(base, val)
- Math.log(val)/Math.log(base)
- end
- answer = log_base(10, 10_000)
- puts "log10(10,000) = #{answer}"
- # @@PLEAC@@_2.14
- require 'matrix.rb'
- a = Matrix[[3, 2, 3], [5, 9, 8]]
- b = Matrix[[4, 7], [9, 3], [8, 1]]
- c = a * b
- a.row_size
- a.column_size
- c.det
- a.transpose
- # @@PLEAC@@_2.15
- require 'complex.rb'
- require 'rational.rb'
- a = Complex(3, 5) # 3 + 5i
- b = Complex(2, -2) # 2 - 2i
- puts "c = #{a*b}"
- c = a * b
- d = 3 + 4*Complex::I
- printf "sqrt(#{d}) = %s\n", Math.sqrt(d)
- # @@PLEAC@@_2.16
- number = hexadecimal.hex
- number = octal.oct
- print "Gimme a number in decimal, octal, or hex: "
- num = gets.chomp
- exit unless defined?(num)
- num = num.oct if num =~ /^0/ # does both oct and hex
- printf "%d %x %o\n", num, num, num
- print "Enter file permission in octal: "
- permissions = gets.chomp
- raise "Exiting ...\n" unless defined?(permissions)
- puts "The decimal value is #{permissions.oct}"
- # @@PLEAC@@_2.17
- def commify(n)
- n.to_s =~ /([^\.]*)(\..*)?/
- int, dec = $1.reverse, $2 ? $2 : ""
- while int.gsub!(/(,|\.|^)(\d{3})(\d)/, '\1\2,\3')
- end
- int.reverse + dec
- end
- # @@PLEAC@@_2.18
- printf "It took %d hour%s\n", time, time == 1 ? "" : "s"
- # dunno if an equivalent to Lingua::EN::Inflect exists...
- # @@PLEAC@@_2.19
- #-----------------------------
- #!/usr/bin/ruby
- # bigfact - calculating prime factors
- def factorize(orig)
- factors = {}
- factors.default = 0 # return 0 instead nil if key not found in hash
- n = orig
- i = 2
- sqi = 4 # square of i
- while sqi <= n do
- while n.modulo(i) == 0 do
- n /= i
- factors[i] += 1
- # puts "Found factor #{i}"
- end
- # we take advantage of the fact that (i +1)**2 = i**2 + 2*i +1
- sqi += 2 * i + 1
- i += 1
- end
-
- if (n != 1) && (n != orig)
- factors[n] += 1
- end
- factors
- end
- def printfactorhash(orig, factorcount)
- print format("%-10d ", orig)
- if factorcount.length == 0
- print "PRIME"
- else
- # sorts after number, because the hash keys are numbers
- factorcount.sort.each { |factor,exponent|
- print factor
- if exponent > 1
- print "**", exponent
- end
- print " "
- }
- end
- puts
- end
- for arg in ARGV
- n = arg.to_i
- mfactors = factorize(n)
- printfactorhash(n, mfactors)
- end
- #-----------------------------
- # @@PLEAC@@_3.0
- puts Time.now
- print "Today is day ", Time.now.yday, " of the current year.\n"
- print "Today is day ", Time.now.day, " of the current month.\n"
- # @@PLEAC@@_3.1
- day, month, year = Time.now.day, Time.now.month, Time.now.year
- # or
- day, month, year = Time.now.to_a[3..5]
- tl = Time.now.localtime
- printf("The current date is %04d %02d %02d\n", tl.year, tl.month, tl.day)
- Time.now.localtime.strftime("%Y-%m-%d")
- # @@PLEAC@@_3.2
- Time.local(year, month, day, hour, minute, second).tv_sec
- Time.gm(year, month, day, hour, minute, second).tv_sec
- # @@PLEAC@@_3.3
- sec, min, hour, day, month, year, wday, yday, isdst, zone = Time.at(epoch_secs).to_a
- # @@PLEAC@@_3.4
- when_ = now + difference # now -> Time ; difference -> Numeric (delta in seconds)
- then_ = now - difference
- # @@PLEAC@@_3.5
- bree = 361535725
- nat = 96201950
- difference = bree - nat
- puts "There were #{difference} seconds between Nat and Bree"
- seconds = difference % 60
- difference = (difference - seconds) / 60
- minutes = difference % 60
- difference = (difference - minutes) / 60
- hours = difference % 24
- difference = (difference - hours) / 24
- days = difference % 7
- weeks = (difference - days) / 7
- puts "(#{weeks} weeks, #{days} days, #{hours}:#{minutes}:#{seconds})"
- # @@PLEAC@@_3.6
- monthday, weekday, yearday = date.mday, date.wday, date.yday
- # AFAIK the week number is not just a division since week boundaries are on sundays
- weeknum = d.strftime("%U").to_i + 1
- year = 1981
- month = "jun" # or `6' if you want to emulate a broken language
- day = 16
- t = Time.mktime(year, month, day)
- print "#{month}/#{day}/#{year} was a ", t.strftime("%A"), "\n"
- # @@PLEAC@@_3.7
- yyyy, mm, dd = $1, $2, $3 if "1998-06-25" =~ /(\d+)-(\d+)-(\d+)/
- epoch_seconds = Time.mktime(yyyy, mm, dd).tv_sec
- # dunno an equivalent to Date::Manip#ParseDate
- # @@PLEAC@@_3.8
- string = Time.at(epoch_secs)
- Time.at(1234567890).gmtime # gives: Fri Feb 13 23:31:30 UTC 2009
- time = Time.mktime(1973, "jan", 18, 3, 45, 50)
- print "In localtime it gives: ", time.localtime, "\n"
- # @@PLEAC@@_3.9
- # Ruby provides micro-seconds in Time object
- Time.now.usec
- # Ruby gives the seconds in floating format when substracting two Time objects
- before = Time.now
- line = gets
- elapsed = Time.now - before
- puts "You took #{elapsed} seconds."
- # On my Celeron-400 with Linux-2.2.19-14mdk, average for three execs are:
- # This Ruby version: average 0.00321 sec
- # Cookbook's Perl version: average 0.00981 sec
- size = 500
- number_of_times = 100
- total_time = 0
- number_of_times.times {
- # populate array
- array = []
- size.times { array << rand }
- # sort it
- begin_ = Time.now
- array.sort!
- time = Time.now - begin_
- total_time += time
- }
- printf "On average, sorting %d random numbers takes %.5f seconds\n",
- size, (total_time/Float(number_of_times))
- # @@PLEAC@@_3.10
- sleep(0.005) # Ruby is definitely not as broken as Perl :)
- # (may be interrupted by sending the process a SIGALRM)
- # @@PLEAC@@_3.11
- #!/usr/bin/ruby -w
- # hopdelta - feed mail header, produce lines
- # showing delay at each hop.
- require 'time'
- class MailHopDelta
- def initialize(mail)
- @head = mail.gsub(/\n\s+/,' ')
- @topline = %w-Sender Recipient Time Delta-
- @start_from = mail.match(/^From.*\@([^\s>]*)/)[1]
- @date = Time.parse(mail.match(/^Date:\s+(.*)/)[1])
- end
- def out(line)
- "%-20.20s %-20.20s %-20.20s %s" % line
- end
- def hop_date(day)
- day.strftime("%I:%M:%S %Y/%m/%d")
- end
- def puts_hops
- puts out(@topline)
- puts out(['Start', @start_from, hop_date(@date),''])
- @head.split(/\n/).reverse.grep(/^Received:/).each do |hop|
- hop.gsub!(/\bon (.*?) (id.*)/,'; \1')
- whence = hop.match(/;\s+(.*)$/)[1]
- unless whence
- warn "Bad received line: #{hop}"
- next
- end
- from = $+ if hop =~ /from\s+(\S+)|\((.*?)\)/
- by = $1 if hop =~ /by\s+(\S+\.\S+)/
- next unless now = Time.parse(whence).localtime
- delta = now - @date
- puts out([from, by, hop_date(now), hop_time(delta)])
- @date = now
- end
- end
- def hop_time(secs)
- sign = secs < 0 ? -1 : 1
- days, secs = secs.abs.divmod(60 * 60 * 24)
- hours,secs = secs.abs.divmod(60 * 60)
- mins, secs = secs.abs.divmod(60)
- rtn = "%3ds" % [secs * sign]
- rtn << "%3dm" % [mins * sign] if mins != 0
- rtn << "%3dh" % [hours * sign] if hours != 0
- rtn << "%3dd" % [days * sign] if days != 0
- rtn
- end
- end
- $/ = ""
- mail = MailHopDelta.new(ARGF.gets).puts_hops
- # @@PLEAC@@_4.0
- single_level = [ "this", "that", "the", "other" ]
- # Ruby directly supports nested arrays
- double_level = [ "this", "that", [ "the", "other" ] ]
- still_single_level = [ "this", "that", [ "the", "other" ] ].flatten
- # @@PLEAC@@_4.1
- a = [ "quick", "brown", "fox" ]
- a = %w(Why are you teasing me?)
- lines = <<"END_OF_HERE_DOC".gsub(/^\s*(.+)/, '\1')
- The boy stood on the burning deck,
- It was as hot as glass.
- END_OF_HERE_DOC
- bigarray = IO.readlines("mydatafile").collect { |l| l.chomp }
- name = "Gandalf"
- banner = %Q(Speak, #{name}, and welcome!)
- host_info = `host #{his_host}`
- %x(ps #{$$})
- banner = 'Costs only $4.95'.split(' ')
- rax = %w! ( ) < > { } [ ] !
- # @@PLEAC@@_4.2
- def commify_series(arr)
- return '' if not arr
- case arr.size
- when 0 then ''
- when 1 then arr[0]
- when 2 then arr.join(' and ')
- else arr[0..-2].join(', ') + ', and ' + arr[-1]
- end
- end
- array = [ "red", "yellow", "green" ]
- print "I have ", array, " marbles\n"
- # -> I have redyellowgreen marbles
- # But unlike Perl:
- print "I have #{array} marbles\n"
- # -> I have redyellowgreen marbles
- # So, needs:
- print "I have #{array.join(' ')} marbles\n"
- # -> I have red yellow green marbles
- #!/usr/bin/ruby
- # communify_series - show proper comma insertion in list output
- def commify_series(arr)
- return '' if not arr
- sepchar = arr.find { |p| p =~ /,/ } ? '; ' : ', '
- case arr.size
- when 0 then ''
- when 1 then arr[0]
- when 2 then arr.join(' and ')
- else arr[0..-2].join(sepchar) + sepchar + 'and ' + arr[-1]
- end
- end
- lists = [
- [ 'just one thing' ],
- %w(Mutt Jeff),
- %w(Peter Paul Mary),
- [ 'To our parents', 'Mother Theresa', 'God' ],
- [ 'pastrami', 'ham and cheese', 'peanut butter and jelly', 'tuna' ],
- [ 'recycle tired, old phrases', 'ponder big, happy thoughts' ],
- [ 'recycle tired, old phrases',
- 'ponder big, happy thoughts',
- 'sleep and dream peacefully' ],
- ]
- for list in lists do
- puts "The list is: #{commify_series(list)}."
- end
- # @@PLEAC@@_4.3
- # (note: AFAIK Ruby doesn't allow gory change of Array length)
- # grow the array by assigning nil to past the end of array
- ary[new_size-1] = nil
- # shrink the array by slicing it down
- ary.slice!(new_size..-1)
- # init the array with given size
- Array.new(number_of_elems)
- # assign to an element past the original end enlarges the array
- ary[index_new_last_elem] = value
- def what_about_that_array(a)
- print "The array now has ", a.size, " elements.\n"
- # Index of last element is not really interesting in Ruby
- print "Element #3 is `#{a[3]}'.\n"
- end
- people = %w(Crosby Stills Nash Young)
- what_about_that_array(people)
- # @@PLEAC@@_4.4
- # OO style
- bad_users.each { |user|
- complain(user)
- }
- # or, functional style
- for user in bad_users
- complain(user)
- end
- for var in ENV.keys.sort
- puts "#{var}=#{ENV[var]}"
- end
- for user in all_users
- disk_space = get_usage(user)
- if (disk_space > MAX_QUOTA)
- complain(user)
- end
- end
- for l in IO.popen("who").readlines
- print l if l =~ /^gc/
- end
- # we can mimic the obfuscated Perl way
- while fh.gets # $_ is set to the line just read
- chomp # $_ has a trailing \n removed, if it had one
- split.each { |w| # $_ is split on whitespace
- # but $_ is not set to each chunk as in Perl
- print w.reverse
- }
- end
- # ...or use a cleaner way
- for l in fh.readlines
- l.chomp.split.each { |w| print w.reverse }
- end
- # same drawback as in problem 1.4, we can't mutate a Numeric...
- array.collect! { |v| v - 1 }
- a = [ .5, 3 ]; b = [ 0, 1 ]
- for ary in [ a, b ]
- ary.collect! { |v| v * 7 }
- end
- puts "#{a.join(' ')} #{b.join(' ')}"
- # we can mutate Strings, cool; we need a trick for the scalar
- for ary in [ [ scalar ], array, hash.values ]
- ary.each { |v| v.strip! } # String#strip rules :)
- end
- # @@PLEAC@@_4.5
- # not relevant in Ruby since we have always references
- for item in array
- # do somethingh with item
- end
- # @@PLEAC@@_4.6
- unique = list.uniq
- # generate a list of users logged in, removing duplicates
- users = `who`.collect { |l| l =~ /(\w+)/; $1 }.sort.uniq
- puts("users logged in: #{commify_series(users)}") # see 4.2 for commify_series
- # @@PLEAC@@_4.7
- a - b
- # [ 1, 1, 2, 2, 3, 3, 3, 4, 5 ] - [ 1, 2, 4 ] -> [3, 5]
- # @@PLEAC@@_4.8
- union = a | b
- intersection = a & b
- difference = a - b
- # @@PLEAC@@_4.9
- array1.concat(array2)
- # if you will assign to another object, better use:
- new_ary = array1 + array2
- members = [ "Time", "Flies" ]
- initiates = [ "An", "Arrow" ]
- members += initiates
- members = [ "Time", "Flies" ]
- initiates = [ "An", "Arrow" ]
- members[2,0] = [ "Like", initiates ].flatten
- members[0] = "Fruit"
- members[3,2] = "A", "Banana"
- # @@PLEAC@@_4.10
- reversed = ary.reverse
- ary.reverse_each { |e|
- # do something with e
- }
- descending = ary.sort.reverse
- descending = ary.sort { |a,b| b <=> a }
- # @@PLEAC@@_4.11
- # remove n elements from front of ary (shift n)
- front = ary.slice!(0, n)
- # remove n elements from the end of ary (pop n)
- end_ = ary.slice!(-n .. -1)
- # let's extend the Array class, to make that useful
- class Array
- def shift2()
- slice!(0 .. 1) # more symetric with pop2...
- end
- def pop2()
- slice!(-2 .. -1)
- end
- end
- friends = %w(Peter Paul Mary Jim Tim)
- this, that = friends.shift2
- beverages = %w(Dew Jolt Cola Sprite Fresca)
- pair = beverages.pop2
- # @@PLEAC@@_4.12
- # use Enumerable#detect (or the synonym Enumerable#find)
- highest_eng = employees.detect { |emp| emp.category == 'engineer' }
- # @@PLEAC@@_4.13
- # use Enumerable#select (or the synonym Enumerable#find_all)
- bigs = nums.select { |i| i > 1_000_000 }
- pigs = users.keys.select { |k| users[k] > 1e7 }
- matching = `who`.select { |u| u =~ /^gnat / }
- engineers = employees.select { |e| e.position == 'Engineer' }
- secondary_assistance = applicants.select { |a|
- a.income >= 26_000 && a.income < 30_000
- }
- # @@PLEAC@@_4.14
- # normally you would have an array of Numeric (Float or
- # Fixnum or Bignum), so you would use:
- sorted = unsorted.sort
- # if you have strings representing Integers or Floats
- # you may specify another sort method:
- sorted = unsorted.sort { |a,b| a.to_f <=> b.to_f }
- # let's use the list of my own PID's
- `ps ux`.split("\n")[1..-1].
- select { |i| i =~ /^#{ENV['USER']}/ }.
- collect { |i| i.split[1] }.
- sort { |a,b| a.to_i <=> b.to_i }.each { |i| puts i }
- puts "Select a process ID to kill:"
- pid = gets.chomp
- raise "Exiting ... \n" unless pid && pid =~ /^\d+$/
- Process.kill('TERM', pid.to_i)
- sleep 2
- Process.kill('KILL', pid.to_i)
- descending = unsorted.sort { |a,b| b.to_f <=> a.to_f }
- # @@PLEAC@@_4.15
- ordered = unordered.sort { |a,b| compare(a,b) }
- precomputed = unordered.collect { |e| [compute, e] }
- ordered_precomputed = precomputed.sort { |a,b| a[0] <=> b[0] }
- ordered = ordered_precomputed.collect { |e| e[1] }
- ordered = unordered.collect { |e| [compute, e] }.
- sort { |a,b| a[0] <=> b[0] }.
- collect { |e| e[1] }
- for employee in employees.sort { |a,b| a.name <=> b.name }
- print employee.name, " earns \$ ", employee.salary, "\n"
- end
- # Beware! `0' is true in Ruby.
- # For chaining comparisons, you may use Numeric#nonzero?, which
- # returns num if num is not zero, nil otherwise
- sorted = employees.sort { |a,b| (a.name <=> b.name).nonzero? || b.age <=> a.age }
- users = []
- # getpwent is not wrapped in Ruby... let's fallback
- IO.readlines('/etc/passwd').each { |u| users << u.split(':') }
- users.sort! { |a,b| a[0] <=> b[0] }
- for user in users
- puts user[0]
- end
- sorted = names.sort { |a,b| a[1, 1] <=> b[1, 1] }
- sorted = strings.sort { |a,b| a.length <=> b.length }
- # let's show only the compact version
- ordered = strings.collect { |e| [e.length, e] }.
- sort { |a,b| a[0] <=> b[0] }.
- collect { |e| e[1] }
- ordered = strings.collect { |e| [/\d+/.match(e)[0].to_i, e] }.
- sort { |a,b| a[0] <=> b[0] }.
- collect { |e| e[1] }
- print `cat /etc/passwd`.collect { |e| [e, e.split(':').indexes(3,2,0)].flatten }.
- sort { |a,b| (a[1] <=> b[1]).nonzero? || (a[2] <=> b[2]).nonzero? || a[3] <=> b[3] }.
- collect { |e| e[0] }
- # @@PLEAC@@_4.16
- circular.unshift(circular.pop) # the last shall be first
- circular.push(circular.shift) # and vice versa
- def grab_and_rotate(l)
- l.push(ret = l.shift)
- ret
- end
- processes = [1, 2, 3, 4, 5]
- while (1)
- process = grab_and_rotate(processes)
- puts "Handling process #{process}"
- sleep 1
- end
- # @@PLEAC@@_4.17
- def fisher_yates_shuffle(a)
- (a.size-1).downto(1) { |i|
- j = rand(i+1)
- a[i], a[j] = a[j], a[i] if i != j
- }
- end
- def naive_shuffle(a)
- for i in 0...a.size
- j = rand(a.size)
- a[i], a[j] = a[j], a[i]
- end
- end
- # @@PLEAC@@_4.18
- #!/usr/bin/env ruby
- # example 4-2 words
- # words - gather lines, present in colums
- # class to encapsulate the word formatting from the input
- class WordFormatter
- def initialize(cols)
- @cols = cols
- end
- # helper to return the length of the longest word in the wordlist
- def maxlen(wordlist)
- max = 1
- for word in wordlist
- if word.length > max
- max = word.length
- end
- end
- max
- end
- # process the wordlist and print it formmated into columns
- def output(wordlist)
- collen = maxlen(wordlist) + 1
- columns = @cols / collen
- columns = 1 if columns == 0
- rows = (wordlist.length + columns - 1) / columns
- # now process each item, picking out proper piece for this position
- 0.upto(rows * columns - 1) { |item|
- target = (item % columns) * rows + (item / columns)
- eol = ((item+1) % columns == 0)
- piece = wordlist[target] || ""
- piece = piece.ljust(collen) unless eol
- print piece
- puts if eol
- }
- # no need to finish it up, because eol is always true for the last element
- end
- end
- # get nr of chars that fit in window or console, see PLEAC 15.4
- # not portable -- linux only (?)
- def getWinCharWidth()
- buf = "\0" * 8
- $stdout.ioctl(0x5413, buf)
- ws_row, ws_col, ws_xpixel, ws_ypixel = buf.unpack("$4")
- ws_col || 80
- rescue
- 80
- end
- # main program
- cols = getWinCharWidth()
- formatter = WordFormatter.new(cols)
- words = readlines()
- words.collect! { |line|
- line.chomp
- }
- formatter.output(words)
- # @@PLEAC@@_4.19
- # In ruby, Fixnum's are automatically converted to Bignum's when
- # needed, so there is no need for an extra module
- def factorial(n)
- s = 1
- while n > 0
- s *= n
- n -= 1
- end
- s
- end
- puts factorial(500)
- #---------------------------------------------------------
- # Example 4-3. tsc-permute
- # tsc_permute: permute each word of input
- def permute(items, perms)
- unless items.length > 0
- puts perms.join(" ")
- else
- for i in items
- newitems = items.dup
- newperms = perms.dup
- newperms.unshift(newitems.delete(i))
- permute(newitems, newperms)
- end
- end
- end
- # In ruby the main program must be after all definitions it is using
- permute(ARGV, [])
- #---------------------------------------------------------
- # mjd_permute: permute each word of input
- def factorial(n)
- s = 1
- while n > 0
- s *= n
- n -= 1
- end
- s
- end
- # we use a class with a class variable store the private cache
- # for the results of the factorial function.
- class Factorial
- @@fact = [ 1 ]
- def Factorial.compute(n)
- if @@fact[n]
- @@fact[n]
- else
- @@fact[n] = n * Factorial.compute(n - 1)
- end
- end
- end
- #---------------------------------------------------------
- # Example 4-4- mjd-permute
- # n2pat(n, len): produce the N-th pattern of length len
- # We must use a lower case letter as parameter N, otherwise it is
- # handled as constant Length is the length of the resulting
- # array, not the index of the last element (length -1) like in
- # the perl example.
- def n2pat(n, length)
- pat = []
- i = 1
- while i <= length
- pat.push(n % i)
- n /= i
- i += 1
- end
- pat
- end
- # pat2perm(pat): turn pattern returned by n2pat() into
- # permutation of integers.
- def pat2perm(pat)
- source = (0 .. pat.length - 1).to_a
- perm = []
- perm.push(source.slice!(pat.pop)) while pat.length > 0
- perm
- end
- def n2perm(n, len)
- pat2perm(n2pat(n,len))
- end
- # In ruby the main program must be after all definitions
- while gets
- data = split
- # the perl solution has used $#data, which is length-1
- num_permutations = Factorial.compute(data.length())
- 0.upto(num_permutations - 1) do |i|
- # in ruby we can not use an array as selector for an array
- # but by exchanging the two arrays, we can use the collect method
- # which returns an array with the result of all block invocations
- permutation = n2perm(i, data.length).collect {
- |j| data[j]
- }
- puts permutation.join(" ")
- end
- end
- # @@PLEAC@@_5.0
- age = { "Nat", 24,
- "Jules", 25,
- "Josh", 17 }
- age["Nat"] = 24
- age["Jules"] = 25
- age["Josh"] = 17
- food_color = {
- "Apple" => "red",
- "Banana" => "yellow",
- "Lemon" => "yellow",
- "Carrot" => "orange"
- }
- # In Ruby, you cannot avoid the double or simple quoting
- # while manipulatin hashes
- # @@PLEAC@@_5.1
- hash[key] = value
- food_color["Raspberry"] = "pink"
- puts "Known foods:", food_color.keys
- # @@PLEAC@@_5.2
- # does hash have a value for key ?
- if (hash.has_key?(key))
- # it exists
- else
- # it doesn't
- end
- [ "Banana", "Martini" ].each { |name|
- print name, " is a ", food_color.has_key?(name) ? "food" : "drink", "\n"
- }
- age = {}
- age['Toddler'] = 3
- age['Unborn'] = 0
- age['Phantasm'] = nil
- for thing in ['Toddler', 'Unborn', 'Phantasm', 'Relic']
- print "#{thing}: "
- print "Has-key " if age.has_key?(thing)
- print "True " if age[thing]
- print "Nonzero " if age[thing] && age[thing].nonzero?
- print "\n"
- end
- #=>
- # Toddler: Has-key True Nonzero
- # Unborn: Has-key True
- # Phantasm: Has-key
- # Relic:
- # You use Hash#has_key? when you use Perl's exists -> it checks
- # for existence of a key in a hash.
- # All Numeric are "True" in ruby, so the test doesn't have the
- # same semantics as in Perl; you would use Numeric#nonzero? to
- # achieve the same semantics (false if 0, true otherwise).
- # @@PLEAC@@_5.3
- food_color.delete("Banana")
- # @@PLEAC@@_5.4
- hash.each { |key, value|
- # do something with key and value
- }
- hash.each_key { |key|
- # do something with key
- }
- food_color.each { |food, color|
- puts "#{food} is #{color}"
- }
- food_color.each_key { |food|
- puts "#{food} is #{food_color[food]}"
- }
- # IMO this demonstrates that OO style is by far more readable
- food_color.keys.sort.each { |food|
- puts "#{food} is #{food_color[food]}."
- }
- #-----------------------------
- #!/usr/bin/ruby
- # countfrom - count number of messages from each sender
- # Default value is 0
- from = Hash.new(0)
- while gets
- /^From: (.*)/ and from[$1] += 1
- end
- # More useful to sort by number of received mail by person
- from.sort {|a,b| b[1]<=>a[1]}.each { |v|
- puts "#{v[1]}: #{v[0]}"
- }
- #-----------------------------
- # @@PLEAC@@_5.5
- # You may use the built-in 'inspect' method this way:
- p hash
- # Or do it the Cookbook way:
- hash.each { |k,v| puts "#{k} => #{v}" }
- # Sorted by keys
- hash.sort.each { |e| puts "#{e[0]} => #{e[1]}" }
- # Sorted by values
- hash.sort{|a,b| a[1]<=>b[1]}.each { |e| puts "#{e[0]} => #{e[1]}" }
- # @@PLEAC@@_5.7
- ttys = Hash.new
- for i in `who`
- user, tty = i.split
- (ttys[user] ||= []) << tty # see problems_ruby for more infos
- end
- ttys.keys.sort.each { |k|
- puts "#{k}: #{commify_series(ttys[k])}" # from 4.2
- }
- # @@PLEAC@@_5.8
- surname = { "Mickey" => "Mantle", "Babe" => "Ruth" }
- puts surname.index("Mantle")
- # If you really needed to 'invert' the whole hash, use Hash#invert
- #-----------------------------
- #!/usr/bin/ruby -w
- # foodfind - find match for food or color
- given = ARGV.shift or raise "usage: foodfind food_or_color"
- color = {
- "Apple" => "red",
- "Banana" => "yellow",
- "Lemon" => "yellow",
- "Carrot" => "orange",
- }
- if (color.has_key?(given))
- puts "#{given} is a food with color #{color[given]}."
- end
- if (color.has_value?(given))
- puts "#{color.index(given)} is a food with color #{given}."
- end
- #-----------------------------
- # @@PLEAC@@_5.9
- # Sorted by keys (Hash#sort gives an Array of pairs made of each key,value)
- food_color.sort.each { |f|
- puts "#{f[0]} is #{f[1]}."
- }
- # Sorted by values
- food_color.sort { |a,b| a[1] <=> b[1] }.each { |f|
- puts "#{f[0]} is #{f[1]}."
- }
- # Sorted by length of values
- food_color.sort { |a,b| a[1].length <=> b[1].length }.each { |f|
- puts "#{f[0]} is #{f[1]}."
- }
- # @@PLEAC@@_5.10
- merged = a.clone.update(b) # because Hash#update changes object in place
- drink_color = { "Galliano" => "yellow", "Mai Tai" => "blue" }
- ingested_color = drink_color.clone.update(food_color)
- substance_color = {}
- for i in [ food_color, drink_color ]
- i.each_key { |k|
- if substance_color.has_key?(k)
- puts "Warning: #{k} seen twice. Using the first definition."
- next
- end
- substance_color[k] = 1
- }
- end
- # @@PLEAC@@_5.11
- common = hash1.keys & hash2.keys
- this_not_that = hash1.keys - hash2.keys
- # @@PLEAC@@_5.12
- # no problem here, Ruby handles any kind of object for key-ing
- # (it takes Object#hash, which defaults to Object#id)
- # @@PLEAC@@_5.13
- # AFAIK, not possible in Ruby
- # @@PLEAC@@_5.14
- # Be careful, the following is possible only because Fixnum objects are
- # special (documentation says: there is effectively only one Fixnum object
- # instance for any given integer value).
- count = Hash.new(0)
- array.each { |e|
- count[e] += 1
- }
- # @@PLEAC@@_5.15
- father = {
- "Cain" , "Adam",
- "Abel" , "Adam",
- "Seth" , "Adam",
- "Enoch" , "Cain",
- "Irad" , "Enoch",
- "Mehujael" , "Irad",
- "Methusael" , "Mehujael",
- "Lamech" , "Methusael",
- "Jabal" , "Lamech",
- "Jubal" , "Lamech",
- "Tubalcain" , "Lamech",
- "Enos" , "Seth",
- }
- while gets
- chomp
- begin
- print $_, " "
- end while $_ = father[$_]
- puts
- end
- children = {}
- father.each { |k,v|
- (children[v] ||= []) << k
- }
- while gets
- chomp
- puts "#{$_} begat #{(children[$_] || ['Nobody']).join(', ')}.\n"
- end
- includes = {}
- files.each { |f|
- begin
- for l in IO.readlines(f)
- next unless l =~ /^\s*#\s*include\s*<([^>]+)>/
- (includes[$1] ||= []) << f
- end
- rescue SystemCallError
- $stderr.puts "#$! (skipping)"
- end
- }
- include_free = includes.values.flatten.uniq - includes.keys
- # @@PLEAC@@_5.16
- # dutree - print sorted intented rendition of du output
- #% dutree
- #% dutree /usr
- #% dutree -a
- #% dutree -a /bin
- # The DuNode class collects all information about a directory,
- # and provides some convenience methods
- class DuNode
- attr_reader :name
- attr_accessor :size
- attr_accessor :kids
- def initialize(name)
- @name = name
- @kids = []
- @size = 0
- end
- # support for sorting nodes with side
- def size_compare(node2)
- @size <=> node2.size
- end
- def basename
- @name.sub(/.*\//, "")
- end
- #returns substring before last "/", nil if not there
- def parent
- p = @name.sub(/\/[^\/]+$/,"")
- if p == @name
- nil
- else
- p
- end
- end
- end
- # The DuTree does the acdtual work of
- # getting the input, parsing it, builging up a tree
- # and format it for output
- class Dutree
- attr_reader :topdir
- def initialize
- @nodes = Hash.new
- @dirsizes = Hash.new(0)
- @kids = Hash.new([])
- end
- # get a node by name, create it if it does not exist yet
- def get_create_node(name)
- if @nodes.has_key?(name)
- @nodes[name]
- else
- node = DuNode.new(name)
- @nodes[name] = node
- node
- end
- end
- # run du, read in input, save sizes and kids
- # stores last directory read in instance variable topdir
- def input(arguments)
- name = ""
- cmd = "du " + arguments.join(" ")
- IO.popen(cmd) { |pipe|
- pipe.each { |line|
- size, name = line.chomp.split(/\s+/, 2)
- node = get_create_node(name)
- node.size = size.to_i
- @nodes[name] = node
- parent = node.parent
- if parent
- get_create_node(parent).kids.push(node)
- end
- }
- }
- @topdir = @nodes[name]
- end
- # figure out how much is taken in each directory
- # that isn't stored in the subdirectories. Add a new
- # fake kid called "." containing that much.
- def get_dots(node)
- cursize = node.size
- for kid in node.kids
- cursize -= kid.size
- get_dots(kid)
- end
- if node.size != cursize
- newnode = get_create_node(node.name + "/.")
- newnode.size = cursize
- node.kids.push(newnode)
- end
- end
- # recursively output everything
- # passing padding and number width as well
- # on recursive calls
- def output(node, prefix="", width=0)
- line = sprintf("%#{width}d %s", node.size, node.basename)
- puts(prefix + line)
- prefix += line.sub(/\d /, "| ")
- prefix.gsub!(/[^|]/, " ")
- if node.kids.length > 0 # not a bachelor node
- kids = node.kids
- kids.sort! { |a,b|
- b.size_compare(a)
- }
- width = kids[0].size.to_s.length
- for kid in kids
- output(kid, prefix, width)
- end
- end
- end
- end
- tree = Dutree.new
- tree.input(ARGV)
- tree.get_dots(tree.topdir)
- tree.output(tree.topdir)
- # @@PLEAC@@_6.0
- # The verbose version are match, sub, gsub, sub! and gsub!;
- # pattern needs to be a Regexp object; it yields a MatchData
- # object.
- pattern.match(string)
- string.sub(pattern, replacement)
- string.gsub(pattern, replacement)
- # As usual in Ruby, sub! does the same as sub but also modifies
- # the object, the same for gsub!/gsub.
- # Sugared syntax yields the position of the match (or nil if no
- # match). Note that the object at the right of the operator needs
- # not to be a Regexp object (it can be a String). The "dont
- # match" operator yields true or false.
- meadow =~ /sheep/ # position of the match, nil if no match
- meadow !~ /sheep/ # true if doesn't match, false if it does
- # There is no sugared version for the substitution
- meadow =~ /\bovines?\b/i and print "Here be sheep!"
- string = "good food"
- string.sub!(/o*/, 'e')
- # % echo ababacaca | ruby -ne 'puts $& if /(a|ba|b)+(a|ac)+/'
- # ababa
- # The "global" (or "multiple") match is handled by String#scan
- scan (/(\d+)/) {
- puts "Found number #{$1}"
- }
- # String#scan yields an Array if not used with a block
- numbers = scan(/\d+/)
- digits = "123456789"
- nonlap = digits.scan(/(\d\d\d)/)
- yeslap = digits.scan(/(?=(\d\d\d))/)
- puts "Non-overlapping: #{nonlap.join(' ')}"
- puts "Overlapping: #{yeslap.join(' ')}";
- # Non-overlapping: 123 456 789
- # Overlapping: 123 234 345 456 567 678 789
- string = "And little lambs eat ivy"
- string =~ /l[^s]*s/
- puts "(#$`) (#$&) (#$')"
- # (And ) (little lambs) ( eat ivy)
- # @@PLEAC@@_6.1
- # Ruby doesn't have the same problem:
- dst = src.sub('this', 'that')
- progname = $0.sub('^.*/', '')
- bindirs = %w(/usr/bin /bin /usr/local/bin)
- libdirs = bindirs.map { |l| l.sub('bin', 'lib') }
- # @@PLEAC@@_6.3
- /\S+/ # as many non-whitespace bytes as possible
- /[A-Za-z'-]+/ # as many letters, apostrophes, and hyphens
- /\b([A-Za-z]+)\b/ # usually best
- /\s([A-Za-z]+)\s/ # fails at ends or w/ punctuation
- # @@PLEAC@@_6.4
- require 'socket'
- str = 'www.ruby-lang.org and www.rubygarden.org'
- re = /
- ( # capture the hostname in $1
- (?: # these parens for grouping only
- (?! [-_] ) # lookahead for neither underscore nor dash
- [\w-] + # hostname component
- \. # and the domain dot
- ) + # now repeat that whole thing a bunch of times
- [A-Za-z] # next must be a letter
- [\w-] + # now trailing domain part
- ) # end of $1 capture
- /x # /x for nice formatting
- str.gsub! re do # pass a block to execute replacement
- host = TCPsocket.gethostbyname($1)
- "#{$1} [#{host[3]}]"
- end
- puts str
- #-----------------------------
- # to match whitespace or #-characters in an extended re you need to escape
- # them.
- foo = 42
- str = 'blah #foo# blah'
- str.gsub! %r/ # replace
- \# # a pound sign
- (\w+) # the variable name
- \# # another pound sign
- /x do
- eval $1 # with the value of a local variable
- end
- puts str # => blah 42 blah
- # @@PLEAC@@_6.5
- # The 'g' modifier doesn't exist in Ruby, a regexp can't be used
- # directly in a while loop; instead, use String#scan { |match| .. }
- fish = 'One fish two fish red fish blue fish'
- WANT = 3
- count = 0
- fish.scan(/(\w+)\s+fish\b/i) {
- if (count += 1) == WANT
- puts "The third fish is a #{$1} one."
- end
- }
- if fish =~ /(?:\w+\s+fish\s+){2}(\w+)\s+fish/i
- puts "The third fish is a #{$1} one."
- end
- pond = 'One fish two fish red fish blue fish'
- # String#scan without a block gives an array of matches, each match
- # being an array of all the specified groups
- colors = pond.scan(/(\w+)\s+fish\b/i).flatten # get all matches
- color = colors[2] # then the one we want
- # or without a temporary array
- color = pond.scan(/(\w+)\s+fish\b/i).flatten[2] # just grab element 3
- puts "The third fish in the pond is #{color}."
- count = 0
- fishes = 'One fish two fish red fish blue fish'
- evens = fishes.scan(/(\w+)\s+fish\b/i).select { (count+=1) % 2 == 0 }
- print "Even numbered fish are #{evens.join(' ')}."
- count = 0
- fishes.gsub(/
- \b # makes next \w more efficient
- ( \w+ ) # this is what we\'ll be changing
- (
- \s+ fish \b
- )
- /x) {
- if (count += 1) == 4
- 'sushi' + $2
- else
- $1 + $2
- end
- }
- pond = 'One fish two fish red fish blue fish swim here.'
- puts "Last fish is #{pond.scan(/\b(\w+)\s+fish\b/i).flatten[-1]}"
- /
- A # find some pattern A
- (?! # mustn\'t be able to find
- .* # something
- A # and A
- )
- $ # through the end of the string
- /x
- # The "s" perl modifier is "m" in Ruby (not very nice since there is
- # also an "m" in perl..)
- pond = "One fish two fish red fish blue fish swim here."
- if (pond =~ /
- \b ( \w+) \s+ fish \b
- (?! .* \b fish \b )
- /mix)
- puts "Last fish is #{$1}."
- else
- puts "Failed!"
- end
- # @@PLEAC@@_6.6
- #-----------------------------
- #!/usr/bin/ruby -w
- # killtags - very bad html killer
- $/ = nil; # each read is whole file
- while file = gets() do
- file.gsub!(/<.*?>/m,''); # strip tags (terribly)
- puts file # print file to STDOUT
- end
- #-----------------------------
- #!/usr/bin/ruby -w
- #headerfy - change certain chapter headers to html
- $/ = ''
- while file = gets() do
- pattern = /
- \A # start of record
- ( # capture in $1
- Chapter # text string
- \s+ # mandatory whitespace
- \d+ # decimal number
- \s* # optional whitespace
- : # a real colon
- . * # anything not a newline till end of line
- )
- /x
- puts file.gsub(pattern,'<H1>\1</H1>')
- end
- #-----------------------------
- #% ruby -00pe "gsub!(/\A(Chapter\s+\d+\s*:.*)/,'<H1>\1</H1>')" datafile
- #!/usr/bin/ruby -w
- #-----------------------------
- for file in ARGV
- file = File.open(ARGV.shift)
- while file.gets('') do # each read is a paragraph
- print "chunk #{$.} in $ARGV has <<#{$1}>>\n" while /^START(.*?)^END/m
- end # /m activates the multiline mode
- end
- #-----------------------------
- # @@PLEAC@@_6.7
- #-----------------------------
- $/ = nil;
- file = File.open("datafile")
- chunks = file.gets.split(/pattern/)
- #-----------------------------
- # .Ch, .Se and .Ss divide chunks of STDIN
- chunks = gets(nil).split(/^\.(Ch|Se|Ss)$/)
- print "I read #{chunks.size} chunks.\n"
- #-----------------------------
- # @@PLEAC@@_6.8
- while gets
- if ~/BEGIN/ .. ~/END/
- # line falls between BEGIN and END inclusive
- end
- end
- while gets
- if ($. == firstnum) .. ($. == lastnum)
- # operate between firstnum and lastnum line number
- end
- end
- # in ruby versions prior to 1.8, the above two conditional
- # expressions could be shortened to:
- # if /BEGIN/ .. /END/
- # and
- # if firstnum .. lastnum
- # but these now only work this way from the command line
- #-----------------------------
- while gets
- if ~/BEGIN/ ... ~/END/
- # line falls between BEGIN and END on different lines
- end
- end
- while gets
- if ($. == first) ... ($. == last)
- # operate between first and last line number on different lines
- end
- end
- #----------------------------…
Large files files are truncated, but you can click here to view the full file