PageRenderTime 59ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/text/src/test/resources/examples/ruby/pleac.in.rb

https://github.com/rimolive/core
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

  1. # -*- ruby -*-
  2. # Local variables:
  3. # indent-tabs-mode: nil
  4. # ruby-indent-level: 4
  5. # End:
  6. # @@PLEAC@@_NAME
  7. # @@SKIP@@ Ruby
  8. # @@PLEAC@@_WEB
  9. # @@SKIP@@ http://www.ruby-lang.org
  10. # @@PLEAC@@_1.0
  11. string = '\n' # two characters, \ and an n
  12. string = 'Jon \'Maddog\' Orwant' # literal single quotes
  13. string = "\n" # a "newline" character
  14. string = "Jon \"Maddog\" Orwant" # literal double quotes
  15. string = %q/Jon 'Maddog' Orwant/ # literal single quotes
  16. string = %q[Jon 'Maddog' Orwant] # literal single quotes
  17. string = %q{Jon 'Maddog' Orwant} # literal single quotes
  18. string = %q(Jon 'Maddog' Orwant) # literal single quotes
  19. string = %q<Jon 'Maddog' Orwant> # literal single quotes
  20. a = <<"EOF"
  21. This is a multiline here document
  22. terminated by EOF on a line by itself
  23. EOF
  24. # @@PLEAC@@_1.1
  25. value = string[offset,count]
  26. value = string[offset..-1]
  27. string[offset,count] = newstring
  28. string[offset..-1] = newtail
  29. # in Ruby we can also specify intervals by their two offsets
  30. value = string[offset..offs2]
  31. string[offset..offs2] = newstring
  32. leading, s1, s2, trailing = data.unpack("A5 x3 A8 A8 A*")
  33. fivers = string.unpack("A5" * (string.length/5))
  34. chars = string.unpack("A1" * string.length)
  35. string = "This is what you have"
  36. # +012345678901234567890 Indexing forwards (left to right)
  37. # 109876543210987654321- Indexing backwards (right to left)
  38. # note that 0 means 10 or 20, etc. above
  39. first = string[0, 1] # "T"
  40. start = string[5, 2] # "is"
  41. rest = string[13..-1] # "you have"
  42. last = string[-1, 1] # "e"
  43. end_ = string[-4..-1] # "have"
  44. piece = string[-8, 3] # "you"
  45. string[5, 2] = "wasn't" # change "is" to "wasn't"
  46. string[-12..-1] = "ondrous" # "This wasn't wondrous"
  47. string[0, 1] = "" # delete first character
  48. string[-10..-1] = "" # delete last 10 characters
  49. if string[-10..-1] =~ /pattern/
  50. puts "Pattern matches in last 10 characters"
  51. end
  52. string[0, 5].gsub!(/is/, 'at')
  53. a = "make a hat"
  54. a[0, 1], a[-1, 1] = a[-1, 1], a[0, 1]
  55. a = "To be or not to be"
  56. b = a.unpack("x6 A6")
  57. b, c = a.unpack("x6 A2 X5 A2")
  58. puts "#{b}\n#{c}\n"
  59. def cut2fmt(*args)
  60. template = ''
  61. lastpos = 1
  62. for place in args
  63. template += "A" + (place - lastpos).to_s + " "
  64. lastpos = place
  65. end
  66. template += "A*"
  67. return template
  68. end
  69. fmt = cut2fmt(8, 14, 20, 26, 30)
  70. # @@PLEAC@@_1.2
  71. # careful! "b is true" doesn't mean "b != 0" (0 is true in Ruby)
  72. # thus no problem of "defined" later since only nil is false
  73. # the following sets to `c' if `b' is nil or false
  74. a = b || c
  75. # if you need Perl's behaviour (setting to `c' if `b' is 0) the most
  76. # effective way is to use Numeric#nonzero? (thanks to Dave Thomas!)
  77. a = b.nonzero? || c
  78. # you will still want to use defined? in order to test
  79. # for scope existence of a given object
  80. a = defined?(b) ? b : c
  81. dir = ARGV.shift || "/tmp"
  82. # @@PLEAC@@_1.3
  83. v1, v2 = v2, v1
  84. alpha, beta, production = %w(January March August)
  85. alpha, beta, production = beta, production, alpha
  86. # @@PLEAC@@_1.4
  87. num = char[0]
  88. char = num.chr
  89. # Ruby also supports having a char from character constant
  90. num = ?r
  91. char = sprintf("%c", num)
  92. printf("Number %d is character %c\n", num, num)
  93. ascii = string.unpack("C*")
  94. string = ascii.pack("C*")
  95. hal = "HAL"
  96. ascii = hal.unpack("C*")
  97. # We can't use Array#each since we can't mutate a Fixnum
  98. ascii.collect! { |i|
  99. i + 1 # add one to each ASCII value
  100. }
  101. ibm = ascii.pack("C*")
  102. puts ibm
  103. # @@PLEAC@@_1.5
  104. array = string.split('')
  105. array = string.unpack("C*")
  106. string.scan(/./) { |b|
  107. # do something with b
  108. }
  109. string = "an apple a day"
  110. print "unique chars are: ", string.split('').uniq.sort, "\n"
  111. sum = 0
  112. for ascval in string.unpack("C*") # or use Array#each for a pure OO style :)
  113. sum += ascval
  114. end
  115. puts "sum is #{sum & 0xffffffff}" # since Ruby will go Bignum if necessary
  116. # @@INCLUDE@@ include/ruby/slowcat.rb
  117. # @@PLEAC@@_1.6
  118. revbytes = string.reverse
  119. revwords = string.split(" ").reverse.join(" ")
  120. revwords = string.split(/(\s+)/).reverse.join
  121. # using the fact that IO is Enumerable, you can directly "select" it
  122. long_palindromes = File.open("/usr/share/dict/words").
  123. select { |w| w.chomp!; w.reverse == w && w.length > 5 }
  124. # @@PLEAC@@_1.7
  125. while string.sub!("\t+") { ' ' * ($&.length * 8 - $`.length % 8) }
  126. end
  127. # @@PLEAC@@_1.8
  128. 'You owe #{debt} to me'.gsub(/\#{(\w+)}/) { eval($1) }
  129. rows, cols = 24, 80
  130. text = %q(I am #{rows} high and #{cols} long)
  131. text.gsub!(/\#{(\w+)}/) { eval("#{$1}") }
  132. puts text
  133. 'I am 17 years old'.gsub(/\d+/) { 2 * $&.to_i }
  134. # @@PLEAC@@_1.9
  135. e = "bo peep".upcase
  136. e.downcase!
  137. e.capitalize!
  138. "thIS is a loNG liNE".gsub!(/\w+/) { $&.capitalize }
  139. # @@PLEAC@@_1.10
  140. "I have #{n+1} guanacos."
  141. print "I have ", n+1, " guanacos."
  142. # @@PLEAC@@_1.11
  143. var = <<'EOF'.gsub(/^\s+/, '')
  144. your text
  145. goes here
  146. EOF
  147. # @@PLEAC@@_1.12
  148. string = "Folding and splicing is the work of an editor,\n"+
  149. "not a mere collection of silicon\n"+
  150. "and\n"+
  151. "mobile electrons!"
  152. def wrap(str, max_size)
  153. all = []
  154. line = ''
  155. for l in str.split
  156. if (line+l).length >= max_size
  157. all.push(line)
  158. line = ''
  159. end
  160. line += line == '' ? l : ' ' + l
  161. end
  162. all.push(line).join("\n")
  163. end
  164. print wrap(string, 20)
  165. #=> Folding and
  166. #=> splicing is the
  167. #=> work of an editor,
  168. #=> not a mere
  169. #=> collection of
  170. #=> silicon and mobile
  171. #=> electrons!
  172. # @@PLEAC@@_1.13
  173. string = %q(Mom said, "Don't do that.")
  174. string.gsub(/['"]/) { '\\'+$& }
  175. string.gsub(/['"]/, '\&\&')
  176. string.gsub(/[^A-Z]/) { '\\'+$& }
  177. "is a test!".gsub(/\W/) { '\\'+$& } # no function like quotemeta?
  178. # @@PLEAC@@_1.14
  179. string.strip!
  180. # @@PLEAC@@_1.15
  181. def parse_csv(text)
  182. new = text.scan(/"([^\"\\]*(?:\\.[^\"\\]*)*)",?|([^,]+),?|,/)
  183. new << nil if text[-1] == ?,
  184. new.flatten.compact
  185. end
  186. line = %q<XYZZY,"","O'Reilly, Inc","Wall, Larry","a \"glug\" bit,",5,"Error, Core Dumped">
  187. fields = parse_csv(line)
  188. fields.each_with_index { |v,i|
  189. print "#{i} : #{v}\n";
  190. }
  191. # @@PLEAC@@_1.16
  192. # Use the soundex.rb Library from Michael Neumann.
  193. # http://www.s-direktnet.de/homepages/neumann/rb_prgs/Soundex.rb
  194. require 'Soundex'
  195. code = Text::Soundex.soundex(string)
  196. codes = Text::Soundex.soundex(array)
  197. # substitution function for getpwent():
  198. # returns an array of user entries,
  199. # each entry contains the username and the full name
  200. def login_names
  201. result = []
  202. File.open("/etc/passwd") { |file|
  203. file.each_line { |line|
  204. next if line.match(/^#/)
  205. cols = line.split(":")
  206. result.push([cols[0], cols[4]])
  207. }
  208. }
  209. result
  210. end
  211. puts "Lookup user: "
  212. user = STDIN.gets
  213. user.chomp!
  214. exit unless user
  215. name_code = Text::Soundex.soundex(user)
  216. splitter = Regexp.new('(\w+)[^,]*\b(\w+)')
  217. for username, fullname in login_names do
  218. firstname, lastname = splitter.match(fullname)[1,2]
  219. if name_code == Text::Soundex.soundex(username)
  220. || name_code == Text::Soundex.soundex(firstname)
  221. || name_code == Text::Soundex.soundex(lastname)
  222. then
  223. puts "#{username}: #{firstname} #{lastname}"
  224. end
  225. end
  226. # @@PLEAC@@_1.17
  227. # @@INCLUDE@@ include/ruby/fixstyle.rb
  228. # @@PLEAC@@_1.18
  229. # @@INCLUDE@@ include/ruby/psgrep.rb
  230. # @@PLEAC@@_2.1
  231. # Matz tells that you can use Integer() for strict checked conversion.
  232. Integer("abc")
  233. #=> `Integer': invalid value for Integer: "abc" (ArgumentError)
  234. Integer("567")
  235. #=> 567
  236. # You may use Float() for floating point stuff
  237. Integer("56.7")
  238. #=> `Integer': invalid value for Integer: "56.7" (ArgumentError)
  239. Float("56.7")
  240. #=> 56.7
  241. # You may also use a regexp for that
  242. if string =~ /^[+-]?\d+$/
  243. p 'is an integer'
  244. else
  245. p 'is not'
  246. end
  247. if string =~ /^-?(?:\d+(?:\.\d*)?|\.\d+)$/
  248. p 'is a decimal number'
  249. else
  250. p 'is not'
  251. end
  252. # @@PLEAC@@_2.2
  253. # equal(num1, num2, accuracy) : returns true if num1 and num2 are
  254. # equal to accuracy number of decimal places
  255. def equal(i, j, a)
  256. sprintf("%.#{a}g", i) == sprintf("%.#{a}g", j)
  257. end
  258. wage = 536 # $5.36/hour
  259. week = 40 * wage # $214.40
  260. printf("One week's wage is: \$%.2f\n", week/100.0)
  261. # @@PLEAC@@_2.3
  262. num.round # rounds to integer
  263. a = 0.255
  264. b = sprintf("%.2f", a)
  265. print "Unrounded: #{a}\nRounded: #{b}\n"
  266. printf "Unrounded: #{a}\nRounded: %.2f\n", a
  267. print "number\tint\tfloor\tceil\n"
  268. a = [ 3.3 , 3.5 , 3.7, -3.3 ]
  269. for n in a
  270. printf("% .1f\t% .1f\t% .1f\t% .1f\n", # at least I don't fake my output :)
  271. n, n.to_i, n.floor, n.ceil)
  272. end
  273. # @@PLEAC@@_2.4
  274. def dec2bin(n)
  275. [n].pack("N").unpack("B32")[0].sub(/^0+(?=\d)/, '')
  276. end
  277. def bin2dec(n)
  278. [("0"*32+n.to_s)[-32..-1]].pack("B32").unpack("N")[0]
  279. end
  280. # @@PLEAC@@_2.5
  281. for i in x .. y
  282. # i is set to every integer from x to y, inclusive
  283. end
  284. x.step(y,7) { |i|
  285. # i is set to every integer from x to y, stepsize = 7
  286. }
  287. print "Infancy is: "
  288. (0..2).each { |i|
  289. print i, " "
  290. }
  291. print "\n"
  292. # @@PLEAC@@_2.6
  293. # We can add conversion methods to the Integer class,
  294. # this makes a roman number just a representation for normal numbers.
  295. class Integer
  296. @@romanlist = [["M", 1000],
  297. ["CM", 900],
  298. ["D", 500],
  299. ["CD", 400],
  300. ["C", 100],
  301. ["XC", 90],
  302. ["L", 50],
  303. ["XL", 40],
  304. ["X", 10],
  305. ["IX", 9],
  306. ["V", 5],
  307. ["IV", 4],
  308. ["I", 1]]
  309. def to_roman
  310. remains = self
  311. roman = ""
  312. for sym, num in @@romanlist
  313. while remains >= num
  314. remains -= num
  315. roman << sym
  316. end
  317. end
  318. roman
  319. end
  320. def Integer.from_roman(roman)
  321. ustr = roman.upcase
  322. sum = 0
  323. for entry in @@romanlist
  324. sym, num = entry[0], entry[1]
  325. while sym == ustr[0, sym.length]
  326. sum += num
  327. ustr.slice!(0, sym.length)
  328. end
  329. end
  330. sum
  331. end
  332. end
  333. roman_fifteen = 15.to_roman
  334. puts "Roman for fifteen is #{roman_fifteen}"
  335. i = Integer.from_roman(roman_fifteen)
  336. puts "Converted back, #{roman_fifteen} is #{i}"
  337. # check
  338. for i in (1..3900)
  339. r = i.to_roman
  340. j = Integer.from_roman(r)
  341. if i != j
  342. puts "error: #{i} : #{r} - #{j}"
  343. end
  344. end
  345. # @@PLEAC@@_2.7
  346. random = rand(y-x+1)+x
  347. chars = ["A".."Z","a".."z","0".."9"].collect { |r| r.to_a }.join + %q(!@$%^&*)
  348. password = (1..8).collect { chars[rand(chars.size)] }.pack("C*")
  349. # @@PLEAC@@_2.8
  350. srand # uses a combination of the time, the process id, and a sequence number
  351. srand(val) # for repeatable behaviour
  352. # @@PLEAC@@_2.9
  353. # from the randomr lib:
  354. # http://raa.ruby-lang.org/project/randomr/
  355. ----> http://raa.ruby-lang.org/project/randomr/
  356. require 'random/mersenne_twister'
  357. mers = Random::MersenneTwister.new 123456789
  358. puts mers.rand(0) # 0.550321932544541
  359. puts mers.rand(10) # 2
  360. # using online sources of random data via the realrand package:
  361. # http://raa.ruby-lang.org/project/realrand/
  362. # **Note**
  363. # The following online services are used in this package:
  364. # http://www.random.org - source: atmospheric noise
  365. # http://www.fourmilab.ch/hotbits - source: radioactive decay timings
  366. # http://random.hd.org - source: entropy from local and network noise
  367. # Please visit the sites and respect the rules of each service.
  368. require 'random/online'
  369. generator1 = Random::RandomOrg.new
  370. puts generator1.randbyte(5).join(",")
  371. puts generator1.randnum(10, 1, 6).join(",") # Roll dice 10 times.
  372. generator2 = Random::FourmiLab.new
  373. puts generator2.randbyte(5).join(",")
  374. # randnum is not supported.
  375. generator3 = Random::EntropyPool.new
  376. puts generator3.randbyte(5).join(",")
  377. # randnum is not supported.
  378. # @@PLEAC@@_2.10
  379. def gaussian_rand
  380. begin
  381. u1 = 2 * rand() - 1
  382. u2 = 2 * rand() - 1
  383. w = u1*u1 + u2*u2
  384. end while (w >= 1)
  385. w = Math.sqrt((-2*Math.log(w))/w)
  386. [ u2*w, u1*w ]
  387. end
  388. mean = 25
  389. sdev = 2
  390. salary = gaussian_rand[0] * sdev + mean
  391. printf("You have been hired at \$%.2f\n", salary)
  392. # @@PLEAC@@_2.11
  393. def deg2rad(d)
  394. (d/180.0)*Math::PI
  395. end
  396. def rad2deg(r)
  397. (r/Math::PI)*180
  398. end
  399. # @@PLEAC@@_2.12
  400. sin_val = Math.sin(angle)
  401. cos_val = Math.cos(angle)
  402. tan_val = Math.tan(angle)
  403. # AFAIK Ruby's Math module doesn't provide acos/asin
  404. # While we're at it, let's also define missing hyperbolic functions
  405. module Math
  406. def Math.asin(x)
  407. atan2(x, sqrt(1 - x**2))
  408. end
  409. def Math.acos(x)
  410. atan2(sqrt(1 - x**2), x)
  411. end
  412. def Math.atan(x)
  413. atan2(x, 1)
  414. end
  415. def Math.sinh(x)
  416. (exp(x) - exp(-x)) / 2
  417. end
  418. def Math.cosh(x)
  419. (exp(x) + exp(-x)) / 2
  420. end
  421. def Math.tanh(x)
  422. sinh(x) / cosh(x)
  423. end
  424. end
  425. # The support for Complex numbers is not built-in
  426. y = Math.acos(3.7)
  427. #=> in `sqrt': square root for negative number (ArgumentError)
  428. # There is an implementation of Complex numbers in 'complex.rb' in current
  429. # Ruby distro, but it doesn't support atan2 with complex args, so it doesn't
  430. # solve this problem.
  431. # @@PLEAC@@_2.13
  432. log_e = Math.log(val)
  433. log_10 = Math.log10(val)
  434. def log_base(base, val)
  435. Math.log(val)/Math.log(base)
  436. end
  437. answer = log_base(10, 10_000)
  438. puts "log10(10,000) = #{answer}"
  439. # @@PLEAC@@_2.14
  440. require 'matrix.rb'
  441. a = Matrix[[3, 2, 3], [5, 9, 8]]
  442. b = Matrix[[4, 7], [9, 3], [8, 1]]
  443. c = a * b
  444. a.row_size
  445. a.column_size
  446. c.det
  447. a.transpose
  448. # @@PLEAC@@_2.15
  449. require 'complex.rb'
  450. require 'rational.rb'
  451. a = Complex(3, 5) # 3 + 5i
  452. b = Complex(2, -2) # 2 - 2i
  453. puts "c = #{a*b}"
  454. c = a * b
  455. d = 3 + 4*Complex::I
  456. printf "sqrt(#{d}) = %s\n", Math.sqrt(d)
  457. # @@PLEAC@@_2.16
  458. number = hexadecimal.hex
  459. number = octal.oct
  460. print "Gimme a number in decimal, octal, or hex: "
  461. num = gets.chomp
  462. exit unless defined?(num)
  463. num = num.oct if num =~ /^0/ # does both oct and hex
  464. printf "%d %x %o\n", num, num, num
  465. print "Enter file permission in octal: "
  466. permissions = gets.chomp
  467. raise "Exiting ...\n" unless defined?(permissions)
  468. puts "The decimal value is #{permissions.oct}"
  469. # @@PLEAC@@_2.17
  470. def commify(n)
  471. n.to_s =~ /([^\.]*)(\..*)?/
  472. int, dec = $1.reverse, $2 ? $2 : ""
  473. while int.gsub!(/(,|\.|^)(\d{3})(\d)/, '\1\2,\3')
  474. end
  475. int.reverse + dec
  476. end
  477. # @@PLEAC@@_2.18
  478. printf "It took %d hour%s\n", time, time == 1 ? "" : "s"
  479. # dunno if an equivalent to Lingua::EN::Inflect exists...
  480. # @@PLEAC@@_2.19
  481. #-----------------------------
  482. #!/usr/bin/ruby
  483. # bigfact - calculating prime factors
  484. def factorize(orig)
  485. factors = {}
  486. factors.default = 0 # return 0 instead nil if key not found in hash
  487. n = orig
  488. i = 2
  489. sqi = 4 # square of i
  490. while sqi <= n do
  491. while n.modulo(i) == 0 do
  492. n /= i
  493. factors[i] += 1
  494. # puts "Found factor #{i}"
  495. end
  496. # we take advantage of the fact that (i +1)**2 = i**2 + 2*i +1
  497. sqi += 2 * i + 1
  498. i += 1
  499. end
  500. if (n != 1) && (n != orig)
  501. factors[n] += 1
  502. end
  503. factors
  504. end
  505. def printfactorhash(orig, factorcount)
  506. print format("%-10d ", orig)
  507. if factorcount.length == 0
  508. print "PRIME"
  509. else
  510. # sorts after number, because the hash keys are numbers
  511. factorcount.sort.each { |factor,exponent|
  512. print factor
  513. if exponent > 1
  514. print "**", exponent
  515. end
  516. print " "
  517. }
  518. end
  519. puts
  520. end
  521. for arg in ARGV
  522. n = arg.to_i
  523. mfactors = factorize(n)
  524. printfactorhash(n, mfactors)
  525. end
  526. #-----------------------------
  527. # @@PLEAC@@_3.0
  528. puts Time.now
  529. print "Today is day ", Time.now.yday, " of the current year.\n"
  530. print "Today is day ", Time.now.day, " of the current month.\n"
  531. # @@PLEAC@@_3.1
  532. day, month, year = Time.now.day, Time.now.month, Time.now.year
  533. # or
  534. day, month, year = Time.now.to_a[3..5]
  535. tl = Time.now.localtime
  536. printf("The current date is %04d %02d %02d\n", tl.year, tl.month, tl.day)
  537. Time.now.localtime.strftime("%Y-%m-%d")
  538. # @@PLEAC@@_3.2
  539. Time.local(year, month, day, hour, minute, second).tv_sec
  540. Time.gm(year, month, day, hour, minute, second).tv_sec
  541. # @@PLEAC@@_3.3
  542. sec, min, hour, day, month, year, wday, yday, isdst, zone = Time.at(epoch_secs).to_a
  543. # @@PLEAC@@_3.4
  544. when_ = now + difference # now -> Time ; difference -> Numeric (delta in seconds)
  545. then_ = now - difference
  546. # @@PLEAC@@_3.5
  547. bree = 361535725
  548. nat = 96201950
  549. difference = bree - nat
  550. puts "There were #{difference} seconds between Nat and Bree"
  551. seconds = difference % 60
  552. difference = (difference - seconds) / 60
  553. minutes = difference % 60
  554. difference = (difference - minutes) / 60
  555. hours = difference % 24
  556. difference = (difference - hours) / 24
  557. days = difference % 7
  558. weeks = (difference - days) / 7
  559. puts "(#{weeks} weeks, #{days} days, #{hours}:#{minutes}:#{seconds})"
  560. # @@PLEAC@@_3.6
  561. monthday, weekday, yearday = date.mday, date.wday, date.yday
  562. # AFAIK the week number is not just a division since week boundaries are on sundays
  563. weeknum = d.strftime("%U").to_i + 1
  564. year = 1981
  565. month = "jun" # or `6' if you want to emulate a broken language
  566. day = 16
  567. t = Time.mktime(year, month, day)
  568. print "#{month}/#{day}/#{year} was a ", t.strftime("%A"), "\n"
  569. # @@PLEAC@@_3.7
  570. yyyy, mm, dd = $1, $2, $3 if "1998-06-25" =~ /(\d+)-(\d+)-(\d+)/
  571. epoch_seconds = Time.mktime(yyyy, mm, dd).tv_sec
  572. # dunno an equivalent to Date::Manip#ParseDate
  573. # @@PLEAC@@_3.8
  574. string = Time.at(epoch_secs)
  575. Time.at(1234567890).gmtime # gives: Fri Feb 13 23:31:30 UTC 2009
  576. time = Time.mktime(1973, "jan", 18, 3, 45, 50)
  577. print "In localtime it gives: ", time.localtime, "\n"
  578. # @@PLEAC@@_3.9
  579. # Ruby provides micro-seconds in Time object
  580. Time.now.usec
  581. # Ruby gives the seconds in floating format when substracting two Time objects
  582. before = Time.now
  583. line = gets
  584. elapsed = Time.now - before
  585. puts "You took #{elapsed} seconds."
  586. # On my Celeron-400 with Linux-2.2.19-14mdk, average for three execs are:
  587. # This Ruby version: average 0.00321 sec
  588. # Cookbook's Perl version: average 0.00981 sec
  589. size = 500
  590. number_of_times = 100
  591. total_time = 0
  592. number_of_times.times {
  593. # populate array
  594. array = []
  595. size.times { array << rand }
  596. # sort it
  597. begin_ = Time.now
  598. array.sort!
  599. time = Time.now - begin_
  600. total_time += time
  601. }
  602. printf "On average, sorting %d random numbers takes %.5f seconds\n",
  603. size, (total_time/Float(number_of_times))
  604. # @@PLEAC@@_3.10
  605. sleep(0.005) # Ruby is definitely not as broken as Perl :)
  606. # (may be interrupted by sending the process a SIGALRM)
  607. # @@PLEAC@@_3.11
  608. #!/usr/bin/ruby -w
  609. # hopdelta - feed mail header, produce lines
  610. # showing delay at each hop.
  611. require 'time'
  612. class MailHopDelta
  613. def initialize(mail)
  614. @head = mail.gsub(/\n\s+/,' ')
  615. @topline = %w-Sender Recipient Time Delta-
  616. @start_from = mail.match(/^From.*\@([^\s>]*)/)[1]
  617. @date = Time.parse(mail.match(/^Date:\s+(.*)/)[1])
  618. end
  619. def out(line)
  620. "%-20.20s %-20.20s %-20.20s %s" % line
  621. end
  622. def hop_date(day)
  623. day.strftime("%I:%M:%S %Y/%m/%d")
  624. end
  625. def puts_hops
  626. puts out(@topline)
  627. puts out(['Start', @start_from, hop_date(@date),''])
  628. @head.split(/\n/).reverse.grep(/^Received:/).each do |hop|
  629. hop.gsub!(/\bon (.*?) (id.*)/,'; \1')
  630. whence = hop.match(/;\s+(.*)$/)[1]
  631. unless whence
  632. warn "Bad received line: #{hop}"
  633. next
  634. end
  635. from = $+ if hop =~ /from\s+(\S+)|\((.*?)\)/
  636. by = $1 if hop =~ /by\s+(\S+\.\S+)/
  637. next unless now = Time.parse(whence).localtime
  638. delta = now - @date
  639. puts out([from, by, hop_date(now), hop_time(delta)])
  640. @date = now
  641. end
  642. end
  643. def hop_time(secs)
  644. sign = secs < 0 ? -1 : 1
  645. days, secs = secs.abs.divmod(60 * 60 * 24)
  646. hours,secs = secs.abs.divmod(60 * 60)
  647. mins, secs = secs.abs.divmod(60)
  648. rtn = "%3ds" % [secs * sign]
  649. rtn << "%3dm" % [mins * sign] if mins != 0
  650. rtn << "%3dh" % [hours * sign] if hours != 0
  651. rtn << "%3dd" % [days * sign] if days != 0
  652. rtn
  653. end
  654. end
  655. $/ = ""
  656. mail = MailHopDelta.new(ARGF.gets).puts_hops
  657. # @@PLEAC@@_4.0
  658. single_level = [ "this", "that", "the", "other" ]
  659. # Ruby directly supports nested arrays
  660. double_level = [ "this", "that", [ "the", "other" ] ]
  661. still_single_level = [ "this", "that", [ "the", "other" ] ].flatten
  662. # @@PLEAC@@_4.1
  663. a = [ "quick", "brown", "fox" ]
  664. a = %w(Why are you teasing me?)
  665. lines = <<"END_OF_HERE_DOC".gsub(/^\s*(.+)/, '\1')
  666. The boy stood on the burning deck,
  667. It was as hot as glass.
  668. END_OF_HERE_DOC
  669. bigarray = IO.readlines("mydatafile").collect { |l| l.chomp }
  670. name = "Gandalf"
  671. banner = %Q(Speak, #{name}, and welcome!)
  672. host_info = `host #{his_host}`
  673. %x(ps #{$$})
  674. banner = 'Costs only $4.95'.split(' ')
  675. rax = %w! ( ) < > { } [ ] !
  676. # @@PLEAC@@_4.2
  677. def commify_series(arr)
  678. return '' if not arr
  679. case arr.size
  680. when 0 then ''
  681. when 1 then arr[0]
  682. when 2 then arr.join(' and ')
  683. else arr[0..-2].join(', ') + ', and ' + arr[-1]
  684. end
  685. end
  686. array = [ "red", "yellow", "green" ]
  687. print "I have ", array, " marbles\n"
  688. # -> I have redyellowgreen marbles
  689. # But unlike Perl:
  690. print "I have #{array} marbles\n"
  691. # -> I have redyellowgreen marbles
  692. # So, needs:
  693. print "I have #{array.join(' ')} marbles\n"
  694. # -> I have red yellow green marbles
  695. #!/usr/bin/ruby
  696. # communify_series - show proper comma insertion in list output
  697. def commify_series(arr)
  698. return '' if not arr
  699. sepchar = arr.find { |p| p =~ /,/ } ? '; ' : ', '
  700. case arr.size
  701. when 0 then ''
  702. when 1 then arr[0]
  703. when 2 then arr.join(' and ')
  704. else arr[0..-2].join(sepchar) + sepchar + 'and ' + arr[-1]
  705. end
  706. end
  707. lists = [
  708. [ 'just one thing' ],
  709. %w(Mutt Jeff),
  710. %w(Peter Paul Mary),
  711. [ 'To our parents', 'Mother Theresa', 'God' ],
  712. [ 'pastrami', 'ham and cheese', 'peanut butter and jelly', 'tuna' ],
  713. [ 'recycle tired, old phrases', 'ponder big, happy thoughts' ],
  714. [ 'recycle tired, old phrases',
  715. 'ponder big, happy thoughts',
  716. 'sleep and dream peacefully' ],
  717. ]
  718. for list in lists do
  719. puts "The list is: #{commify_series(list)}."
  720. end
  721. # @@PLEAC@@_4.3
  722. # (note: AFAIK Ruby doesn't allow gory change of Array length)
  723. # grow the array by assigning nil to past the end of array
  724. ary[new_size-1] = nil
  725. # shrink the array by slicing it down
  726. ary.slice!(new_size..-1)
  727. # init the array with given size
  728. Array.new(number_of_elems)
  729. # assign to an element past the original end enlarges the array
  730. ary[index_new_last_elem] = value
  731. def what_about_that_array(a)
  732. print "The array now has ", a.size, " elements.\n"
  733. # Index of last element is not really interesting in Ruby
  734. print "Element #3 is `#{a[3]}'.\n"
  735. end
  736. people = %w(Crosby Stills Nash Young)
  737. what_about_that_array(people)
  738. # @@PLEAC@@_4.4
  739. # OO style
  740. bad_users.each { |user|
  741. complain(user)
  742. }
  743. # or, functional style
  744. for user in bad_users
  745. complain(user)
  746. end
  747. for var in ENV.keys.sort
  748. puts "#{var}=#{ENV[var]}"
  749. end
  750. for user in all_users
  751. disk_space = get_usage(user)
  752. if (disk_space > MAX_QUOTA)
  753. complain(user)
  754. end
  755. end
  756. for l in IO.popen("who").readlines
  757. print l if l =~ /^gc/
  758. end
  759. # we can mimic the obfuscated Perl way
  760. while fh.gets # $_ is set to the line just read
  761. chomp # $_ has a trailing \n removed, if it had one
  762. split.each { |w| # $_ is split on whitespace
  763. # but $_ is not set to each chunk as in Perl
  764. print w.reverse
  765. }
  766. end
  767. # ...or use a cleaner way
  768. for l in fh.readlines
  769. l.chomp.split.each { |w| print w.reverse }
  770. end
  771. # same drawback as in problem 1.4, we can't mutate a Numeric...
  772. array.collect! { |v| v - 1 }
  773. a = [ .5, 3 ]; b = [ 0, 1 ]
  774. for ary in [ a, b ]
  775. ary.collect! { |v| v * 7 }
  776. end
  777. puts "#{a.join(' ')} #{b.join(' ')}"
  778. # we can mutate Strings, cool; we need a trick for the scalar
  779. for ary in [ [ scalar ], array, hash.values ]
  780. ary.each { |v| v.strip! } # String#strip rules :)
  781. end
  782. # @@PLEAC@@_4.5
  783. # not relevant in Ruby since we have always references
  784. for item in array
  785. # do somethingh with item
  786. end
  787. # @@PLEAC@@_4.6
  788. unique = list.uniq
  789. # generate a list of users logged in, removing duplicates
  790. users = `who`.collect { |l| l =~ /(\w+)/; $1 }.sort.uniq
  791. puts("users logged in: #{commify_series(users)}") # see 4.2 for commify_series
  792. # @@PLEAC@@_4.7
  793. a - b
  794. # [ 1, 1, 2, 2, 3, 3, 3, 4, 5 ] - [ 1, 2, 4 ] -> [3, 5]
  795. # @@PLEAC@@_4.8
  796. union = a | b
  797. intersection = a & b
  798. difference = a - b
  799. # @@PLEAC@@_4.9
  800. array1.concat(array2)
  801. # if you will assign to another object, better use:
  802. new_ary = array1 + array2
  803. members = [ "Time", "Flies" ]
  804. initiates = [ "An", "Arrow" ]
  805. members += initiates
  806. members = [ "Time", "Flies" ]
  807. initiates = [ "An", "Arrow" ]
  808. members[2,0] = [ "Like", initiates ].flatten
  809. members[0] = "Fruit"
  810. members[3,2] = "A", "Banana"
  811. # @@PLEAC@@_4.10
  812. reversed = ary.reverse
  813. ary.reverse_each { |e|
  814. # do something with e
  815. }
  816. descending = ary.sort.reverse
  817. descending = ary.sort { |a,b| b <=> a }
  818. # @@PLEAC@@_4.11
  819. # remove n elements from front of ary (shift n)
  820. front = ary.slice!(0, n)
  821. # remove n elements from the end of ary (pop n)
  822. end_ = ary.slice!(-n .. -1)
  823. # let's extend the Array class, to make that useful
  824. class Array
  825. def shift2()
  826. slice!(0 .. 1) # more symetric with pop2...
  827. end
  828. def pop2()
  829. slice!(-2 .. -1)
  830. end
  831. end
  832. friends = %w(Peter Paul Mary Jim Tim)
  833. this, that = friends.shift2
  834. beverages = %w(Dew Jolt Cola Sprite Fresca)
  835. pair = beverages.pop2
  836. # @@PLEAC@@_4.12
  837. # use Enumerable#detect (or the synonym Enumerable#find)
  838. highest_eng = employees.detect { |emp| emp.category == 'engineer' }
  839. # @@PLEAC@@_4.13
  840. # use Enumerable#select (or the synonym Enumerable#find_all)
  841. bigs = nums.select { |i| i > 1_000_000 }
  842. pigs = users.keys.select { |k| users[k] > 1e7 }
  843. matching = `who`.select { |u| u =~ /^gnat / }
  844. engineers = employees.select { |e| e.position == 'Engineer' }
  845. secondary_assistance = applicants.select { |a|
  846. a.income >= 26_000 && a.income < 30_000
  847. }
  848. # @@PLEAC@@_4.14
  849. # normally you would have an array of Numeric (Float or
  850. # Fixnum or Bignum), so you would use:
  851. sorted = unsorted.sort
  852. # if you have strings representing Integers or Floats
  853. # you may specify another sort method:
  854. sorted = unsorted.sort { |a,b| a.to_f <=> b.to_f }
  855. # let's use the list of my own PID's
  856. `ps ux`.split("\n")[1..-1].
  857. select { |i| i =~ /^#{ENV['USER']}/ }.
  858. collect { |i| i.split[1] }.
  859. sort { |a,b| a.to_i <=> b.to_i }.each { |i| puts i }
  860. puts "Select a process ID to kill:"
  861. pid = gets.chomp
  862. raise "Exiting ... \n" unless pid && pid =~ /^\d+$/
  863. Process.kill('TERM', pid.to_i)
  864. sleep 2
  865. Process.kill('KILL', pid.to_i)
  866. descending = unsorted.sort { |a,b| b.to_f <=> a.to_f }
  867. # @@PLEAC@@_4.15
  868. ordered = unordered.sort { |a,b| compare(a,b) }
  869. precomputed = unordered.collect { |e| [compute, e] }
  870. ordered_precomputed = precomputed.sort { |a,b| a[0] <=> b[0] }
  871. ordered = ordered_precomputed.collect { |e| e[1] }
  872. ordered = unordered.collect { |e| [compute, e] }.
  873. sort { |a,b| a[0] <=> b[0] }.
  874. collect { |e| e[1] }
  875. for employee in employees.sort { |a,b| a.name <=> b.name }
  876. print employee.name, " earns \$ ", employee.salary, "\n"
  877. end
  878. # Beware! `0' is true in Ruby.
  879. # For chaining comparisons, you may use Numeric#nonzero?, which
  880. # returns num if num is not zero, nil otherwise
  881. sorted = employees.sort { |a,b| (a.name <=> b.name).nonzero? || b.age <=> a.age }
  882. users = []
  883. # getpwent is not wrapped in Ruby... let's fallback
  884. IO.readlines('/etc/passwd').each { |u| users << u.split(':') }
  885. users.sort! { |a,b| a[0] <=> b[0] }
  886. for user in users
  887. puts user[0]
  888. end
  889. sorted = names.sort { |a,b| a[1, 1] <=> b[1, 1] }
  890. sorted = strings.sort { |a,b| a.length <=> b.length }
  891. # let's show only the compact version
  892. ordered = strings.collect { |e| [e.length, e] }.
  893. sort { |a,b| a[0] <=> b[0] }.
  894. collect { |e| e[1] }
  895. ordered = strings.collect { |e| [/\d+/.match(e)[0].to_i, e] }.
  896. sort { |a,b| a[0] <=> b[0] }.
  897. collect { |e| e[1] }
  898. print `cat /etc/passwd`.collect { |e| [e, e.split(':').indexes(3,2,0)].flatten }.
  899. sort { |a,b| (a[1] <=> b[1]).nonzero? || (a[2] <=> b[2]).nonzero? || a[3] <=> b[3] }.
  900. collect { |e| e[0] }
  901. # @@PLEAC@@_4.16
  902. circular.unshift(circular.pop) # the last shall be first
  903. circular.push(circular.shift) # and vice versa
  904. def grab_and_rotate(l)
  905. l.push(ret = l.shift)
  906. ret
  907. end
  908. processes = [1, 2, 3, 4, 5]
  909. while (1)
  910. process = grab_and_rotate(processes)
  911. puts "Handling process #{process}"
  912. sleep 1
  913. end
  914. # @@PLEAC@@_4.17
  915. def fisher_yates_shuffle(a)
  916. (a.size-1).downto(1) { |i|
  917. j = rand(i+1)
  918. a[i], a[j] = a[j], a[i] if i != j
  919. }
  920. end
  921. def naive_shuffle(a)
  922. for i in 0...a.size
  923. j = rand(a.size)
  924. a[i], a[j] = a[j], a[i]
  925. end
  926. end
  927. # @@PLEAC@@_4.18
  928. #!/usr/bin/env ruby
  929. # example 4-2 words
  930. # words - gather lines, present in colums
  931. # class to encapsulate the word formatting from the input
  932. class WordFormatter
  933. def initialize(cols)
  934. @cols = cols
  935. end
  936. # helper to return the length of the longest word in the wordlist
  937. def maxlen(wordlist)
  938. max = 1
  939. for word in wordlist
  940. if word.length > max
  941. max = word.length
  942. end
  943. end
  944. max
  945. end
  946. # process the wordlist and print it formmated into columns
  947. def output(wordlist)
  948. collen = maxlen(wordlist) + 1
  949. columns = @cols / collen
  950. columns = 1 if columns == 0
  951. rows = (wordlist.length + columns - 1) / columns
  952. # now process each item, picking out proper piece for this position
  953. 0.upto(rows * columns - 1) { |item|
  954. target = (item % columns) * rows + (item / columns)
  955. eol = ((item+1) % columns == 0)
  956. piece = wordlist[target] || ""
  957. piece = piece.ljust(collen) unless eol
  958. print piece
  959. puts if eol
  960. }
  961. # no need to finish it up, because eol is always true for the last element
  962. end
  963. end
  964. # get nr of chars that fit in window or console, see PLEAC 15.4
  965. # not portable -- linux only (?)
  966. def getWinCharWidth()
  967. buf = "\0" * 8
  968. $stdout.ioctl(0x5413, buf)
  969. ws_row, ws_col, ws_xpixel, ws_ypixel = buf.unpack("$4")
  970. ws_col || 80
  971. rescue
  972. 80
  973. end
  974. # main program
  975. cols = getWinCharWidth()
  976. formatter = WordFormatter.new(cols)
  977. words = readlines()
  978. words.collect! { |line|
  979. line.chomp
  980. }
  981. formatter.output(words)
  982. # @@PLEAC@@_4.19
  983. # In ruby, Fixnum's are automatically converted to Bignum's when
  984. # needed, so there is no need for an extra module
  985. def factorial(n)
  986. s = 1
  987. while n > 0
  988. s *= n
  989. n -= 1
  990. end
  991. s
  992. end
  993. puts factorial(500)
  994. #---------------------------------------------------------
  995. # Example 4-3. tsc-permute
  996. # tsc_permute: permute each word of input
  997. def permute(items, perms)
  998. unless items.length > 0
  999. puts perms.join(" ")
  1000. else
  1001. for i in items
  1002. newitems = items.dup
  1003. newperms = perms.dup
  1004. newperms.unshift(newitems.delete(i))
  1005. permute(newitems, newperms)
  1006. end
  1007. end
  1008. end
  1009. # In ruby the main program must be after all definitions it is using
  1010. permute(ARGV, [])
  1011. #---------------------------------------------------------
  1012. # mjd_permute: permute each word of input
  1013. def factorial(n)
  1014. s = 1
  1015. while n > 0
  1016. s *= n
  1017. n -= 1
  1018. end
  1019. s
  1020. end
  1021. # we use a class with a class variable store the private cache
  1022. # for the results of the factorial function.
  1023. class Factorial
  1024. @@fact = [ 1 ]
  1025. def Factorial.compute(n)
  1026. if @@fact[n]
  1027. @@fact[n]
  1028. else
  1029. @@fact[n] = n * Factorial.compute(n - 1)
  1030. end
  1031. end
  1032. end
  1033. #---------------------------------------------------------
  1034. # Example 4-4- mjd-permute
  1035. # n2pat(n, len): produce the N-th pattern of length len
  1036. # We must use a lower case letter as parameter N, otherwise it is
  1037. # handled as constant Length is the length of the resulting
  1038. # array, not the index of the last element (length -1) like in
  1039. # the perl example.
  1040. def n2pat(n, length)
  1041. pat = []
  1042. i = 1
  1043. while i <= length
  1044. pat.push(n % i)
  1045. n /= i
  1046. i += 1
  1047. end
  1048. pat
  1049. end
  1050. # pat2perm(pat): turn pattern returned by n2pat() into
  1051. # permutation of integers.
  1052. def pat2perm(pat)
  1053. source = (0 .. pat.length - 1).to_a
  1054. perm = []
  1055. perm.push(source.slice!(pat.pop)) while pat.length > 0
  1056. perm
  1057. end
  1058. def n2perm(n, len)
  1059. pat2perm(n2pat(n,len))
  1060. end
  1061. # In ruby the main program must be after all definitions
  1062. while gets
  1063. data = split
  1064. # the perl solution has used $#data, which is length-1
  1065. num_permutations = Factorial.compute(data.length())
  1066. 0.upto(num_permutations - 1) do |i|
  1067. # in ruby we can not use an array as selector for an array
  1068. # but by exchanging the two arrays, we can use the collect method
  1069. # which returns an array with the result of all block invocations
  1070. permutation = n2perm(i, data.length).collect {
  1071. |j| data[j]
  1072. }
  1073. puts permutation.join(" ")
  1074. end
  1075. end
  1076. # @@PLEAC@@_5.0
  1077. age = { "Nat", 24,
  1078. "Jules", 25,
  1079. "Josh", 17 }
  1080. age["Nat"] = 24
  1081. age["Jules"] = 25
  1082. age["Josh"] = 17
  1083. food_color = {
  1084. "Apple" => "red",
  1085. "Banana" => "yellow",
  1086. "Lemon" => "yellow",
  1087. "Carrot" => "orange"
  1088. }
  1089. # In Ruby, you cannot avoid the double or simple quoting
  1090. # while manipulatin hashes
  1091. # @@PLEAC@@_5.1
  1092. hash[key] = value
  1093. food_color["Raspberry"] = "pink"
  1094. puts "Known foods:", food_color.keys
  1095. # @@PLEAC@@_5.2
  1096. # does hash have a value for key ?
  1097. if (hash.has_key?(key))
  1098. # it exists
  1099. else
  1100. # it doesn't
  1101. end
  1102. [ "Banana", "Martini" ].each { |name|
  1103. print name, " is a ", food_color.has_key?(name) ? "food" : "drink", "\n"
  1104. }
  1105. age = {}
  1106. age['Toddler'] = 3
  1107. age['Unborn'] = 0
  1108. age['Phantasm'] = nil
  1109. for thing in ['Toddler', 'Unborn', 'Phantasm', 'Relic']
  1110. print "#{thing}: "
  1111. print "Has-key " if age.has_key?(thing)
  1112. print "True " if age[thing]
  1113. print "Nonzero " if age[thing] && age[thing].nonzero?
  1114. print "\n"
  1115. end
  1116. #=>
  1117. # Toddler: Has-key True Nonzero
  1118. # Unborn: Has-key True
  1119. # Phantasm: Has-key
  1120. # Relic:
  1121. # You use Hash#has_key? when you use Perl's exists -> it checks
  1122. # for existence of a key in a hash.
  1123. # All Numeric are "True" in ruby, so the test doesn't have the
  1124. # same semantics as in Perl; you would use Numeric#nonzero? to
  1125. # achieve the same semantics (false if 0, true otherwise).
  1126. # @@PLEAC@@_5.3
  1127. food_color.delete("Banana")
  1128. # @@PLEAC@@_5.4
  1129. hash.each { |key, value|
  1130. # do something with key and value
  1131. }
  1132. hash.each_key { |key|
  1133. # do something with key
  1134. }
  1135. food_color.each { |food, color|
  1136. puts "#{food} is #{color}"
  1137. }
  1138. food_color.each_key { |food|
  1139. puts "#{food} is #{food_color[food]}"
  1140. }
  1141. # IMO this demonstrates that OO style is by far more readable
  1142. food_color.keys.sort.each { |food|
  1143. puts "#{food} is #{food_color[food]}."
  1144. }
  1145. #-----------------------------
  1146. #!/usr/bin/ruby
  1147. # countfrom - count number of messages from each sender
  1148. # Default value is 0
  1149. from = Hash.new(0)
  1150. while gets
  1151. /^From: (.*)/ and from[$1] += 1
  1152. end
  1153. # More useful to sort by number of received mail by person
  1154. from.sort {|a,b| b[1]<=>a[1]}.each { |v|
  1155. puts "#{v[1]}: #{v[0]}"
  1156. }
  1157. #-----------------------------
  1158. # @@PLEAC@@_5.5
  1159. # You may use the built-in 'inspect' method this way:
  1160. p hash
  1161. # Or do it the Cookbook way:
  1162. hash.each { |k,v| puts "#{k} => #{v}" }
  1163. # Sorted by keys
  1164. hash.sort.each { |e| puts "#{e[0]} => #{e[1]}" }
  1165. # Sorted by values
  1166. hash.sort{|a,b| a[1]<=>b[1]}.each { |e| puts "#{e[0]} => #{e[1]}" }
  1167. # @@PLEAC@@_5.7
  1168. ttys = Hash.new
  1169. for i in `who`
  1170. user, tty = i.split
  1171. (ttys[user] ||= []) << tty # see problems_ruby for more infos
  1172. end
  1173. ttys.keys.sort.each { |k|
  1174. puts "#{k}: #{commify_series(ttys[k])}" # from 4.2
  1175. }
  1176. # @@PLEAC@@_5.8
  1177. surname = { "Mickey" => "Mantle", "Babe" => "Ruth" }
  1178. puts surname.index("Mantle")
  1179. # If you really needed to 'invert' the whole hash, use Hash#invert
  1180. #-----------------------------
  1181. #!/usr/bin/ruby -w
  1182. # foodfind - find match for food or color
  1183. given = ARGV.shift or raise "usage: foodfind food_or_color"
  1184. color = {
  1185. "Apple" => "red",
  1186. "Banana" => "yellow",
  1187. "Lemon" => "yellow",
  1188. "Carrot" => "orange",
  1189. }
  1190. if (color.has_key?(given))
  1191. puts "#{given} is a food with color #{color[given]}."
  1192. end
  1193. if (color.has_value?(given))
  1194. puts "#{color.index(given)} is a food with color #{given}."
  1195. end
  1196. #-----------------------------
  1197. # @@PLEAC@@_5.9
  1198. # Sorted by keys (Hash#sort gives an Array of pairs made of each key,value)
  1199. food_color.sort.each { |f|
  1200. puts "#{f[0]} is #{f[1]}."
  1201. }
  1202. # Sorted by values
  1203. food_color.sort { |a,b| a[1] <=> b[1] }.each { |f|
  1204. puts "#{f[0]} is #{f[1]}."
  1205. }
  1206. # Sorted by length of values
  1207. food_color.sort { |a,b| a[1].length <=> b[1].length }.each { |f|
  1208. puts "#{f[0]} is #{f[1]}."
  1209. }
  1210. # @@PLEAC@@_5.10
  1211. merged = a.clone.update(b) # because Hash#update changes object in place
  1212. drink_color = { "Galliano" => "yellow", "Mai Tai" => "blue" }
  1213. ingested_color = drink_color.clone.update(food_color)
  1214. substance_color = {}
  1215. for i in [ food_color, drink_color ]
  1216. i.each_key { |k|
  1217. if substance_color.has_key?(k)
  1218. puts "Warning: #{k} seen twice. Using the first definition."
  1219. next
  1220. end
  1221. substance_color[k] = 1
  1222. }
  1223. end
  1224. # @@PLEAC@@_5.11
  1225. common = hash1.keys & hash2.keys
  1226. this_not_that = hash1.keys - hash2.keys
  1227. # @@PLEAC@@_5.12
  1228. # no problem here, Ruby handles any kind of object for key-ing
  1229. # (it takes Object#hash, which defaults to Object#id)
  1230. # @@PLEAC@@_5.13
  1231. # AFAIK, not possible in Ruby
  1232. # @@PLEAC@@_5.14
  1233. # Be careful, the following is possible only because Fixnum objects are
  1234. # special (documentation says: there is effectively only one Fixnum object
  1235. # instance for any given integer value).
  1236. count = Hash.new(0)
  1237. array.each { |e|
  1238. count[e] += 1
  1239. }
  1240. # @@PLEAC@@_5.15
  1241. father = {
  1242. "Cain" , "Adam",
  1243. "Abel" , "Adam",
  1244. "Seth" , "Adam",
  1245. "Enoch" , "Cain",
  1246. "Irad" , "Enoch",
  1247. "Mehujael" , "Irad",
  1248. "Methusael" , "Mehujael",
  1249. "Lamech" , "Methusael",
  1250. "Jabal" , "Lamech",
  1251. "Jubal" , "Lamech",
  1252. "Tubalcain" , "Lamech",
  1253. "Enos" , "Seth",
  1254. }
  1255. while gets
  1256. chomp
  1257. begin
  1258. print $_, " "
  1259. end while $_ = father[$_]
  1260. puts
  1261. end
  1262. children = {}
  1263. father.each { |k,v|
  1264. (children[v] ||= []) << k
  1265. }
  1266. while gets
  1267. chomp
  1268. puts "#{$_} begat #{(children[$_] || ['Nobody']).join(', ')}.\n"
  1269. end
  1270. includes = {}
  1271. files.each { |f|
  1272. begin
  1273. for l in IO.readlines(f)
  1274. next unless l =~ /^\s*#\s*include\s*<([^>]+)>/
  1275. (includes[$1] ||= []) << f
  1276. end
  1277. rescue SystemCallError
  1278. $stderr.puts "#$! (skipping)"
  1279. end
  1280. }
  1281. include_free = includes.values.flatten.uniq - includes.keys
  1282. # @@PLEAC@@_5.16
  1283. # dutree - print sorted intented rendition of du output
  1284. #% dutree
  1285. #% dutree /usr
  1286. #% dutree -a
  1287. #% dutree -a /bin
  1288. # The DuNode class collects all information about a directory,
  1289. # and provides some convenience methods
  1290. class DuNode
  1291. attr_reader :name
  1292. attr_accessor :size
  1293. attr_accessor :kids
  1294. def initialize(name)
  1295. @name = name
  1296. @kids = []
  1297. @size = 0
  1298. end
  1299. # support for sorting nodes with side
  1300. def size_compare(node2)
  1301. @size <=> node2.size
  1302. end
  1303. def basename
  1304. @name.sub(/.*\//, "")
  1305. end
  1306. #returns substring before last "/", nil if not there
  1307. def parent
  1308. p = @name.sub(/\/[^\/]+$/,"")
  1309. if p == @name
  1310. nil
  1311. else
  1312. p
  1313. end
  1314. end
  1315. end
  1316. # The DuTree does the acdtual work of
  1317. # getting the input, parsing it, builging up a tree
  1318. # and format it for output
  1319. class Dutree
  1320. attr_reader :topdir
  1321. def initialize
  1322. @nodes = Hash.new
  1323. @dirsizes = Hash.new(0)
  1324. @kids = Hash.new([])
  1325. end
  1326. # get a node by name, create it if it does not exist yet
  1327. def get_create_node(name)
  1328. if @nodes.has_key?(name)
  1329. @nodes[name]
  1330. else
  1331. node = DuNode.new(name)
  1332. @nodes[name] = node
  1333. node
  1334. end
  1335. end
  1336. # run du, read in input, save sizes and kids
  1337. # stores last directory read in instance variable topdir
  1338. def input(arguments)
  1339. name = ""
  1340. cmd = "du " + arguments.join(" ")
  1341. IO.popen(cmd) { |pipe|
  1342. pipe.each { |line|
  1343. size, name = line.chomp.split(/\s+/, 2)
  1344. node = get_create_node(name)
  1345. node.size = size.to_i
  1346. @nodes[name] = node
  1347. parent = node.parent
  1348. if parent
  1349. get_create_node(parent).kids.push(node)
  1350. end
  1351. }
  1352. }
  1353. @topdir = @nodes[name]
  1354. end
  1355. # figure out how much is taken in each directory
  1356. # that isn't stored in the subdirectories. Add a new
  1357. # fake kid called "." containing that much.
  1358. def get_dots(node)
  1359. cursize = node.size
  1360. for kid in node.kids
  1361. cursize -= kid.size
  1362. get_dots(kid)
  1363. end
  1364. if node.size != cursize
  1365. newnode = get_create_node(node.name + "/.")
  1366. newnode.size = cursize
  1367. node.kids.push(newnode)
  1368. end
  1369. end
  1370. # recursively output everything
  1371. # passing padding and number width as well
  1372. # on recursive calls
  1373. def output(node, prefix="", width=0)
  1374. line = sprintf("%#{width}d %s", node.size, node.basename)
  1375. puts(prefix + line)
  1376. prefix += line.sub(/\d /, "| ")
  1377. prefix.gsub!(/[^|]/, " ")
  1378. if node.kids.length > 0 # not a bachelor node
  1379. kids = node.kids
  1380. kids.sort! { |a,b|
  1381. b.size_compare(a)
  1382. }
  1383. width = kids[0].size.to_s.length
  1384. for kid in kids
  1385. output(kid, prefix, width)
  1386. end
  1387. end
  1388. end
  1389. end
  1390. tree = Dutree.new
  1391. tree.input(ARGV)
  1392. tree.get_dots(tree.topdir)
  1393. tree.output(tree.topdir)
  1394. # @@PLEAC@@_6.0
  1395. # The verbose version are match, sub, gsub, sub! and gsub!;
  1396. # pattern needs to be a Regexp object; it yields a MatchData
  1397. # object.
  1398. pattern.match(string)
  1399. string.sub(pattern, replacement)
  1400. string.gsub(pattern, replacement)
  1401. # As usual in Ruby, sub! does the same as sub but also modifies
  1402. # the object, the same for gsub!/gsub.
  1403. # Sugared syntax yields the position of the match (or nil if no
  1404. # match). Note that the object at the right of the operator needs
  1405. # not to be a Regexp object (it can be a String). The "dont
  1406. # match" operator yields true or false.
  1407. meadow =~ /sheep/ # position of the match, nil if no match
  1408. meadow !~ /sheep/ # true if doesn't match, false if it does
  1409. # There is no sugared version for the substitution
  1410. meadow =~ /\bovines?\b/i and print "Here be sheep!"
  1411. string = "good food"
  1412. string.sub!(/o*/, 'e')
  1413. # % echo ababacaca | ruby -ne 'puts $& if /(a|ba|b)+(a|ac)+/'
  1414. # ababa
  1415. # The "global" (or "multiple") match is handled by String#scan
  1416. scan (/(\d+)/) {
  1417. puts "Found number #{$1}"
  1418. }
  1419. # String#scan yields an Array if not used with a block
  1420. numbers = scan(/\d+/)
  1421. digits = "123456789"
  1422. nonlap = digits.scan(/(\d\d\d)/)
  1423. yeslap = digits.scan(/(?=(\d\d\d))/)
  1424. puts "Non-overlapping: #{nonlap.join(' ')}"
  1425. puts "Overlapping: #{yeslap.join(' ')}";
  1426. # Non-overlapping: 123 456 789
  1427. # Overlapping: 123 234 345 456 567 678 789
  1428. string = "And little lambs eat ivy"
  1429. string =~ /l[^s]*s/
  1430. puts "(#$`) (#$&) (#$')"
  1431. # (And ) (little lambs) ( eat ivy)
  1432. # @@PLEAC@@_6.1
  1433. # Ruby doesn't have the same problem:
  1434. dst = src.sub('this', 'that')
  1435. progname = $0.sub('^.*/', '')
  1436. bindirs = %w(/usr/bin /bin /usr/local/bin)
  1437. libdirs = bindirs.map { |l| l.sub('bin', 'lib') }
  1438. # @@PLEAC@@_6.3
  1439. /\S+/ # as many non-whitespace bytes as possible
  1440. /[A-Za-z'-]+/ # as many letters, apostrophes, and hyphens
  1441. /\b([A-Za-z]+)\b/ # usually best
  1442. /\s([A-Za-z]+)\s/ # fails at ends or w/ punctuation
  1443. # @@PLEAC@@_6.4
  1444. require 'socket'
  1445. str = 'www.ruby-lang.org and www.rubygarden.org'
  1446. re = /
  1447. ( # capture the hostname in $1
  1448. (?: # these parens for grouping only
  1449. (?! [-_] ) # lookahead for neither underscore nor dash
  1450. [\w-] + # hostname component
  1451. \. # and the domain dot
  1452. ) + # now repeat that whole thing a bunch of times
  1453. [A-Za-z] # next must be a letter
  1454. [\w-] + # now trailing domain part
  1455. ) # end of $1 capture
  1456. /x # /x for nice formatting
  1457. str.gsub! re do # pass a block to execute replacement
  1458. host = TCPsocket.gethostbyname($1)
  1459. "#{$1} [#{host[3]}]"
  1460. end
  1461. puts str
  1462. #-----------------------------
  1463. # to match whitespace or #-characters in an extended re you need to escape
  1464. # them.
  1465. foo = 42
  1466. str = 'blah #foo# blah'
  1467. str.gsub! %r/ # replace
  1468. \# # a pound sign
  1469. (\w+) # the variable name
  1470. \# # another pound sign
  1471. /x do
  1472. eval $1 # with the value of a local variable
  1473. end
  1474. puts str # => blah 42 blah
  1475. # @@PLEAC@@_6.5
  1476. # The 'g' modifier doesn't exist in Ruby, a regexp can't be used
  1477. # directly in a while loop; instead, use String#scan { |match| .. }
  1478. fish = 'One fish two fish red fish blue fish'
  1479. WANT = 3
  1480. count = 0
  1481. fish.scan(/(\w+)\s+fish\b/i) {
  1482. if (count += 1) == WANT
  1483. puts "The third fish is a #{$1} one."
  1484. end
  1485. }
  1486. if fish =~ /(?:\w+\s+fish\s+){2}(\w+)\s+fish/i
  1487. puts "The third fish is a #{$1} one."
  1488. end
  1489. pond = 'One fish two fish red fish blue fish'
  1490. # String#scan without a block gives an array of matches, each match
  1491. # being an array of all the specified groups
  1492. colors = pond.scan(/(\w+)\s+fish\b/i).flatten # get all matches
  1493. color = colors[2] # then the one we want
  1494. # or without a temporary array
  1495. color = pond.scan(/(\w+)\s+fish\b/i).flatten[2] # just grab element 3
  1496. puts "The third fish in the pond is #{color}."
  1497. count = 0
  1498. fishes = 'One fish two fish red fish blue fish'
  1499. evens = fishes.scan(/(\w+)\s+fish\b/i).select { (count+=1) % 2 == 0 }
  1500. print "Even numbered fish are #{evens.join(' ')}."
  1501. count = 0
  1502. fishes.gsub(/
  1503. \b # makes next \w more efficient
  1504. ( \w+ ) # this is what we\'ll be changing
  1505. (
  1506. \s+ fish \b
  1507. )
  1508. /x) {
  1509. if (count += 1) == 4
  1510. 'sushi' + $2
  1511. else
  1512. $1 + $2
  1513. end
  1514. }
  1515. pond = 'One fish two fish red fish blue fish swim here.'
  1516. puts "Last fish is #{pond.scan(/\b(\w+)\s+fish\b/i).flatten[-1]}"
  1517. /
  1518. A # find some pattern A
  1519. (?! # mustn\'t be able to find
  1520. .* # something
  1521. A # and A
  1522. )
  1523. $ # through the end of the string
  1524. /x
  1525. # The "s" perl modifier is "m" in Ruby (not very nice since there is
  1526. # also an "m" in perl..)
  1527. pond = "One fish two fish red fish blue fish swim here."
  1528. if (pond =~ /
  1529. \b ( \w+) \s+ fish \b
  1530. (?! .* \b fish \b )
  1531. /mix)
  1532. puts "Last fish is #{$1}."
  1533. else
  1534. puts "Failed!"
  1535. end
  1536. # @@PLEAC@@_6.6
  1537. #-----------------------------
  1538. #!/usr/bin/ruby -w
  1539. # killtags - very bad html killer
  1540. $/ = nil; # each read is whole file
  1541. while file = gets() do
  1542. file.gsub!(/<.*?>/m,''); # strip tags (terribly)
  1543. puts file # print file to STDOUT
  1544. end
  1545. #-----------------------------
  1546. #!/usr/bin/ruby -w
  1547. #headerfy - change certain chapter headers to html
  1548. $/ = ''
  1549. while file = gets() do
  1550. pattern = /
  1551. \A # start of record
  1552. ( # capture in $1
  1553. Chapter # text string
  1554. \s+ # mandatory whitespace
  1555. \d+ # decimal number
  1556. \s* # optional whitespace
  1557. : # a real colon
  1558. . * # anything not a newline till end of line
  1559. )
  1560. /x
  1561. puts file.gsub(pattern,'<H1>\1</H1>')
  1562. end
  1563. #-----------------------------
  1564. #% ruby -00pe "gsub!(/\A(Chapter\s+\d+\s*:.*)/,'<H1>\1</H1>')" datafile
  1565. #!/usr/bin/ruby -w
  1566. #-----------------------------
  1567. for file in ARGV
  1568. file = File.open(ARGV.shift)
  1569. while file.gets('') do # each read is a paragraph
  1570. print "chunk #{$.} in $ARGV has <<#{$1}>>\n" while /^START(.*?)^END/m
  1571. end # /m activates the multiline mode
  1572. end
  1573. #-----------------------------
  1574. # @@PLEAC@@_6.7
  1575. #-----------------------------
  1576. $/ = nil;
  1577. file = File.open("datafile")
  1578. chunks = file.gets.split(/pattern/)
  1579. #-----------------------------
  1580. # .Ch, .Se and .Ss divide chunks of STDIN
  1581. chunks = gets(nil).split(/^\.(Ch|Se|Ss)$/)
  1582. print "I read #{chunks.size} chunks.\n"
  1583. #-----------------------------
  1584. # @@PLEAC@@_6.8
  1585. while gets
  1586. if ~/BEGIN/ .. ~/END/
  1587. # line falls between BEGIN and END inclusive
  1588. end
  1589. end
  1590. while gets
  1591. if ($. == firstnum) .. ($. == lastnum)
  1592. # operate between firstnum and lastnum line number
  1593. end
  1594. end
  1595. # in ruby versions prior to 1.8, the above two conditional
  1596. # expressions could be shortened to:
  1597. # if /BEGIN/ .. /END/
  1598. # and
  1599. # if firstnum .. lastnum
  1600. # but these now only work this way from the command line
  1601. #-----------------------------
  1602. while gets
  1603. if ~/BEGIN/ ... ~/END/
  1604. # line falls between BEGIN and END on different lines
  1605. end
  1606. end
  1607. while gets
  1608. if ($. == first) ... ($. == last)
  1609. # operate between first and last line number on different lines
  1610. end
  1611. end
  1612. #----------------------------

Large files files are truncated, but you can click here to view the full file