「たのしいRuby 第4版」プログラムリスト

第1章 はじめてのRuby

List 1.1 : helloruby.rb

print("Hello, Ruby.\n")

List 1.2 : put_and_p.rb

puts "Hello,\n\tRuby."
p "Hello,\n\tRuby."

List 1.3 : kiritsubo.rb

print "いづれの御時にか女御更衣あまたさぶらいたまいけるなかに\n"
print "いとやむごとなき際にはあらぬがすぐれて時めきたまふありけり\n"

List 1.4 : area_volume.rb

x = 10
y = 20
z = 30
area = (x*y + y*z + z*x) * 2
volume = x * y * z
print "表面積=", area, "\n"
print "体積=", volume, "\n"

List 1.5 : comment_sample.rb

=begin
「たのしいRuby 第4版」サンプル
コメントの使い方の例
2006/06/16 作成
2006/07/01 一部コメントを追加
2013/04/01 第4版用に更新
=end
x = 10  # 横
y = 20  # 縦
z = 30  # 高さ
# 表面積と体積を計算する
area = (x*y + y*z + z*x) * 2
volume = x * y * z
# 出力する
print "表面積=", area, "\n"
print "体積=", volume, "\n"

List 1.6 : bigger_smaller.rb

a = 20
if a >= 10 then
  print "bigger\n"
end
if a <= 9 then
  print "smaller\n"
end

第2章 便利なオブジェクト

ファイル名のあるソースコードはありません。

第3章 コマンドを作ろう

List 3.1 : print_argv.rb

puts "最初の引数: #{ARGV[0]}"
puts "2番目の引数: #{ARGV[1]}"
puts "3番目の引数: #{ARGV[2]}"

List 3.2 : happy_birth.rb

name = ARGV[0]
print "Happy Birthday, ", name, "!\n"

List 3.3 : arg_arith.rb

num0 = ARGV[0].to_i
num1 = ARGV[1].to_i
puts "#{num0} + #{num1} = #{num0 + num1}"
puts "#{num0} - #{num1} = #{num0 - num1}"
puts "#{num0} * #{num1} = #{num0 * num1}"
puts "#{num0} / #{num1} = #{num0 / num1}"

List 3.4 : read_text.rb

filename = ARGV[0]
file = File.open(filename) # ①
text = file.read           # ②
print text                 # ③
file.close                 # ④

List 3.5 : read_text_simple.rb

filename = ARGV[0]
text = File.read(filename)
print text

List 3.6 : read_text_oneline.rb

print File.read(ARGV[0])

List 3.7 : read_line.rb

filename = ARGV[0]
file = File.open(filename)
file.each_line do |line|
  print line
end
file.close

List 3.8 : simple_grep.rb

pattern = Regexp.new(ARGV[0])
filename = ARGV[1]

file = File.open(filename)
file.each_line do |line|
  if pattern =~ line
    print line
  end
end
file.close

List 3.9 : hello_ruby2.rb

def hello
  puts "Hello, Ruby"
end

hello()

List 3.10 : grep.rb

def simple_grep(pattern, filename)
  file = File.open(filename)
  file.each_line do |line|
    if pattern =~ line
      print line
    end
  end
  file.close
end

List 3.11 : use_grep.rb

require "./grep"                # grep.rbの読み込み(「.rb」は不要)

pattern = Regexp.new(ARGV[0])
filename = ARGV[1]
simple_grep(pattern, filename)  # simple_grepメソッドの起動

第4章 オブジェクトと変数・定数

List 4.1 : scopetest.rb

$x = 0
x = 0

require "sub"

p $x   #=> 1
p x    #=> 0

List 4.2 : sub.rb

$x = 1  ## グローバル変数に代入
x = 1   ## ローカル変数に代入

第5章 条件判断

List 5.1 : ad2heisei.rb

#西暦から平成に変換する

ad = ARGV[0].to_i
heisei = ad - 1988
puts heisei

List 5.2 : if_elsif.rb

a = 10
b = 20
if a > b
  puts "aはbよりも大きい"
elsif a < b
  puts "aはbよりも小さい"
else
  puts "aはbと同じ"
end

List 5.3 : unless.rb

a = 10
b = 20
unless a > b
  puts "aはbより大きくない"
end

List 5.4 : case.rb

tags = [ "A", "IMG", "PRE" ]
tags.each do |tagname|
  case tagname
  when "P","A","I","B","BLOCKQUOTE"
    puts "#{tagname} has child."
  when "IMG", "BR"
    puts "#{tagname} has no child."
  else
    puts "#{tagname} cannot be used."
  end
end

List 5.5 : case_class.rb

array = [ "a", 1, nil ]
array.each do |item|
  case item
  when String
    puts "item is a String."
  when Numeric
    puts "item is a Numeric."
  else
    puts "item is something."
  end
end

第6章 繰り返し

List 6.1 : times.rb

7.times do
  puts "いちめんのなのはな"
end

List 6.2 : times2.rb

5.times do |i|
  puts "#{i}回目の繰り返しです。"
end

List 6.3 : times3.rb

5.times do |i|
  puts "#{i+1}回目の繰り返しです。"
end

List 6.4 : for.rb

sum = 0
for i in 1..5
  sum = sum + i
end
puts sum

List 6.5 : for_names.rb

names = ["awk", "Perl", "Python", "Ruby"]
for name in names
  puts name
end

List 6.6 : while.rb

i = 1
while i < 3
  puts i
  i += 1
end

List 6.7 : while2.rb

sum = 0
i = 1
while i <= 5
  sum += i
  i += 1
end
puts sum

List 6.8 : while3.rb

sum = 0
i = 1
while sum < 50
  sum += i
  i += 1
end
puts sum

List 6.9 : until.rb

sum = 0
i = 1
until sum >= 50
  sum += i
  i+= 1
end
puts sum

List 6.10 : while_not.rb

sum = 0
i = 1
while !(sum >= 50)
  sum += i
  i += 1
end
puts sum

List 6.11 : each_names.rb

names = ["awk","Perl","Python","Ruby"]
names.each do |name|
  puts name
end

List 6.12 : each.rb

sum = 0
(1..5).each do |i|
  sum= sum + i
end
puts sum

List 6.13 : break_next_redo.rb

puts "breakの例:"
i = 0
["Perl", "Python", "Ruby", "Scheme"].each do |lang|
  i += 1
  if i == 3
    break
  end
  p [i,lang]
end

puts "nextの例:"
i = 0
["Perl", "Python", "Ruby", "Scheme"].each do |lang|
  i += 1
  if i == 3
    next
  end
  p [i,lang]
end

puts "redoの例:"
i = 0
["Perl", "Python", "Ruby", "Scheme"].each do |lang|
  i += 1
  if i == 3
    redo
  end
  p [i,lang]
end

List 6.14 : ten_lines_grep.rb

pattern = Regexp.new(ARGV[0])
filename = ARGV[1]
max_matches = 10      # 出力する最大数
matches = 0           # マッチした行数
file = File.open(filename)
file.each_line do |line|
  if matches >= max_matches
    break
  end
  if pattern =~ line
    matches += 1
    puts line
  end
end

List 6.15 : strip.rb

file = File.open(ARGV[0])
file.each_line do |line|
  next if /^\s*$/ =~ line  # 空白行
  next if /^#/ =~ line     # シャープで始まる行
  puts line
end

List 6.16 : fact.rb

# 10の階乗を求める
ans = 1
for i in 1..10
  ans *= i
end

# 出力する
puts "10! = #{ans}"

List 6.17 : stripped_fact.rb

ans = 1
for i in 1..10
  ans *= i
end
puts "10! = #{ans}"

第7章 メソッド

List 7.1 : times_with_param.rb

5.times do |i|
  puts "#{i}回目の繰り返しです。"
end

List 7.2 : hello_with_name.rb

def hello(name)
  puts "Hello, #{name}."
end

hello("Ruby")

List 7.3 : hello_with_default.rb

def hello(name="Ruby")
  puts "Hello, #{name}."
end

hello()         # 引数を省略して呼び出す
hello("Newbie") # 引数を指定して呼び出す

List 7.4 : myloop.rb

def myloop
  while true
    yield               # ブロックを実行する
  end
end

num = 1                 # numを初期化する
myloop do
  puts "num is #{num}"  # numを表示する
  break if num > 100    # numが100を超えていたら抜ける
  num *= 2              # numを2倍する
end

第8章 クラスとモジュール

List 8.1 : hello_class.rb

class HelloWorld                   # class文
  def initialize(myname = "Ruby")  # initializeメソッド
    @name = myname                 # インスタンス変数の初期化
  end

  def hello                        # インスタンスメソッド
    puts "Hello, world. I am #{@name}."
  end
end

bob = HelloWorld.new("Bob")
alice = HelloWorld.new("Alice")
ruby = HelloWorld.new

bob.hello

List 8.2 : hello_class.rb(抜粋)

class HelloWorld
 …
  def name          # @nameを参照する
    @name
  end

  def name=(value)  # @nameを変更する
    @name = value
  end
 …
end

List 8.3 : hello_class.rb(抜粋)

class HelloWorld
  attr_accessor :name
 …
  def greet
    puts "Hi, I am #{self.name}."
  end
end
 …

List 8.4 : hello_count.rb

class HelloCount
  @@count = 0           # helloメソッドの呼び出し回数

  def HelloCount.count  # 呼び出し回数を参照するためのクラスメソッド
    @@count
  end

  def initialize(myname="Ruby")
    @name = myname
  end

  def hello
    @@count += 1        # 呼び出し回数を加算する
    puts "Hello, world. I am #{@name}.\n"
  end
end

bob = HelloCount.new("Bob")
alice = HelloCount.new("Alice")
ruby = HelloCount.new

p HelloCount.count      #=> 0
bob.hello
alice.hello
ruby.hello
p HelloCount.count      #=> 3

List 8.5 : acc_test.rb

class AccTest
  def pub
    puts "pub is a public method."
  end

  public :pub   # pubメソッドをpublicに設定(指定しなくてもよい)

  def priv
    puts "priv is a private method."
  end

  private :priv # privメソッドをprivateに設定
end

acc = AccTest.new
acc.pub
acc.priv

List 8.6 : point.rb

class Point
  attr_accessor :x, :y   # アクセスメソッドを定義する
  protected :x=, :y=     # x=とy=をprotectedにする

  def initialize(x=0.0, y=0.0)
    @x, @y = x, y
  end

  def swap(other)        # x、yの値を入れ換えるメソッド
    tmp_x, tmp_y = @x, @y
    @x, @y = other.x, other.y
    other.x, other.y = tmp_x, tmp_y   # 同一クラス内では
                                      # 呼び出すことができる
    return self
  end
end

p0 = Point.new
p1 = Point.new(1.0, 2.0)
p [ p0.x, p0.y ]         #=> [0.0, 0.0]
p [ p1.x, p1.y ]         #=> [1.0, 2.0]

p0.swap(p1)
p [ p0.x, p0.y ]         #=> [1.0, 2.0]
p [ p1.x, p1.y ]         #=> [0.0, 0.0]

p0.x = 10.0              #=> エラー(NoMethodError)

List 8.7 : ext_string.rb

class String
  def count_word
    ary = self.split(/\s+/) # レシーバを空白文字で分解する
    return ary.size         # 分解後の配列の要素数を返す
  end
end

str = "Just Another Ruby Newbie"
p str.count_word            #=> 4

List 8.8 : ring_array.rb

class RingArray < Array  # スーパークラスを指定する
  def [](i)              # 演算子 []の再定義
    idx = i % size       # 新しいインデックスを求める
    super(idx)           # スーパークラスの同名のメソッドを呼ぶ
  end
end

wday = RingArray["日", "月", "火", "水", "木", "金", "土"]
p wday[6]   #=> "土"
p wday[11]  #=> "木"
p wday[15]  #=> "月"
p wday[-1]  #=> "土"

List 8.9 : mixin_sample.rb

module MyModule
  # 共通して提供したいメソッドなど
end

class MyClass1
  include MyModule
  # MyClass1に固有のメソッドなど
end

class MyClass2
  include MyModule
  # MyClass2に固有のメソッドなど
end

List 8.10 : hello_module.rb

module HelloModule          # module文
  Version = "1.0"           # 定数の定義

  def hello(name)           # メソッドの定義
    puts "Hello, #{name}."
  end

  module_function :hello    # helloをモジュール関数として公開する
end

p HelloModule::Version      #=> "1.0"
HelloModule.hello("Alice")  #=> Hello, Alice.

include HelloModule         # インクルードしてみる
p Version                   #=> "1.0"
hello("Alice")              #=> Hello, Alice.

List 8.11 : mixin_test.rb

module M
  def meth
    "meth"
  end
end

class C
  include M  # モジュールMをインクルードする
end

c = C.new
p c.meth     #=> meth

List 8.12 : fetch_and_downcase.rb

def fetch_and_downcase(ary, index)
  if str = ary[index]
    return str.downcase
  end
end

ary = ["Boo", "Foo", "Woo"]
p fetch_and_downcase(ary, 1)  #=> "foo"

List 8.13 : http_get.rb

require "net/http"
require "uri"
url = URI.parse("http://www.ruby-lang.org/ja/")
http = Net::HTTP.start(url.host, url.port)
doc = http.get(url.path)
puts doc

第9章 演算子

List 9.1 : point.rb

class Point
  attr_accessor :x, :y

  def initialize(x=0, y=0)
    @x, @y = x, y
  end

  def inspect  # 表示用
    "(#{x}, #{y})"
  end

  def +(other)  # x、yのそれぞれを足す
    self.class.new(x + other.x, y + other.y)
  end

  def -(other)  # x、yのそれぞれを引く
    self.class.new(x - other.x, y - other.y)
  end
end

point0 = Point.new(3, 6)
point1 = Point.new(1, 8)

p point0           #=> (3, 6)
p point1           #=> (1, 8)
p point0 + point1  #=> (4, 14)
p point0 - point1  #=> (2, -2)

List 9.2 : point.rb(抜粋)

class Point
 …
  def +@
    dup                     # 自分の複製を返す
  end

  def -@
    self.class.new(-x, -y)  # x、yのそれぞれの正負を逆にする
  end

  def ~@
    self.class.new(-y, x)   # 90度反転させた座標を返す
  end
end

point = Point.new(3, 6)
p +point  #=> (3, 6)
p -point  #=> (-3, -6)
p ~point  #=> (-6, 3)

List 9.3 : point.rb(抜粋)

class Point
 …
  def [](index)
    case index
    when 0
      x
    when 1
      y
    else
      raise ArgumentError, "out of range `#{index}'"
    end
  end

  def []=(index, val)
    case index
    when 0
      self.x = val
    when 1
      self.y = val
    else
      raise ArgumentError, "out of range `#{index}'"
    end
  end
end

point = Point.new(3, 6)
p point[0]           #=> 3
p point[1] = 2       #=> 2
p point[1]           #=> 2
p point[2]           #=>エラー(ArgumentError)

第10章 エラー処理と例外

List 10.1 : wc.rb

ltotal=0                             # 行数の合計
wtotal=0                             # 単語数の合計
ctotal=0                             # 文字数の合計
ARGV.each do |file|
  begin
    input = File.open(file)          # ファイルを開く(A)
    l=0                              # file内の行数
    w=0                              # file内の単語数
    c=0                              # file内の文字数
    input.each_line do |line|
      l += 1
      c += line.size
      line.sub!(/^\s+/, "")          # 行頭の空白を削除
      ary = line.split(/\s+/)        # 空白文字で分解する
      w += ary.size
    end
    input.close                      # ファイルを閉じる
    printf("%8d %8d %8d %s\n", l, w, c, file)  # 出力を整形する
    ltotal += l
    wtotal += w
    ctotal += c
  rescue => ex
    print ex.message, "\n"           # 例外のメッセージを出力(B)
  end
end

printf("%8d %8d %8d %s\n", ltotal, wtotal, ctotal, "total")

第11章 ブロック

List 11.1 : hash_each.rb

sum = 0
outcome = {"参加費"=>1000, "ストラップ代"=>1000, "懇親会会費"=>4000}
outcome.each do |pair|
  sum += pair[1]  # 値を指定している
end
puts "合計 : #{sum}"

List 11.2 : hash_each2.rb

sum = 0
outcome = {"参加費"=>1000, "ストラップ代"=>1000, "懇親会会費"=>4000}
outcome.each do |item, price|
  sum += price
end
puts "合計 : #{sum}"

List 11.3 : file_each.rb

file = File.open("sample.txt")
file.each_line do |line|
  print line
end
file.close

List 11.4 : file_open.rb

File.open("sample.txt") do |file|
  file.each_line do |line|
    print line
  end
end

List 11.5 : file_open_no_block.rb

file = File.open("sample.txt")
begin
  file.each_line do |line|
    print line
  end
ensure
  file.close
end

List 11.6 : sort_comp_count.rb

ary = %w(
  Ruby is a open source programming language with a focus
  on simplicity and productivity. It has an elegant syntax
  that is natural to read and easy to write
)

call_num = 0    # ブロックの呼び出し回数
sorted = ary.sort do |a, b|
  call_num += 1 # ブロックの呼び出し回数を加算する
  a.length <=> b.length
end

puts "ソートの結果 #{sorted}"
puts "配列の要素数 #{ary.length}"
puts "ブロックの呼び出し回数 #{call_num}"

List 11.7 : myloop.rb

def myloop
  while true
    yield               # ブロックを実行する
  end
end

num = 1                 # numを初期化する
myloop do
  puts "num is #{num}"  # numを表示する
  break if num > 100    # numが100を越えていたら抜ける
  num *= 2              # numを2倍する
end

List 11.8 : total.rb

def total(from, to)
  result = 0                # 合計の値
  from.upto(to) do |num|    # fromからtoまで処理する
    if block_given?         #   ブロックがあれば
      result += yield(num)  #     ブロックで処理した値を足す
    else                    #   ブロックがなければ
      result += num         #     そのまま足す
    end
  end
  return result             # メソッドの結果を返す
end

p total(1, 10)                  # 1から10の和 => 55
p total(1, 10){|num| num ** 2 } # 1から10の2乗の値の和 => 385

List 11.9 : block_args_test.rb

def block_args_test
  yield()             # ブロック変数なし
  yield(1)            # ブロック変数1つ
  yield(1, 2, 3)      # ブロック変数3つ
end

puts "ブロック変数を|a|で受け取る"
block_args_test do |a|
  p [a]
end
puts

puts "ブロック変数を|a, b, c|で受け取る"
block_args_test do |a, b, c|
  p [a, b, c]
end
puts

puts "ブロック変数を|*a|で受け取る"
block_args_test do |*a|
  p [a]
end
puts

List 11.10 : param_grouping.rb

hash = {a: 100, b: 200, c: 300}
hash.each_with_index do |(key, value), index|
  p [key, value, index]
end

List 11.11 : proc1.rb

hello = Proc.new do |name|
  puts "Hello, #{name}."
end

hello.call("World")
hello.call("Ruby")

List 11.12 : total2.rb

def total2(from, to, &block)
  result = 0               # 合計の値
  from.upto(to) do |num|   # fromからtoまで処理する
    if block               #   ブロックがあれば
      result +=            #     ブロックで処理した値を足す
           block.call(num)
    else                   #   ブロックがなければ
      result += num        #     そのまま足す
    end
  end
  return result            # メソッドの結果を返す
end

p total2(1, 10)                   # 1から10の和 => 55
p total2(1, 10){|num| num ** 2 }  # 1から10の2乗の値の和 => 385

List 11.13 : call_each.rb

def call_each(ary, &block)
  ary.each(&block)
end

call_each [1, 2, 3] do |item|
  p item
end

List 11.14 : local_and_block.rb

x = 1            # xを初期化
y = 1            # yを初期化
ary = [1, 2, 3]

ary.each do |x|  # ブロック変数としてxを使用する
  y = x          # yにxを代入する
end

p [x, y]         # xとyの値を確認する

List 11.15 : local_and_block2.rb

x = y = z = 0       # xとyとzを初期化
ary = [1, 2, 3] 
ary.each do |x; y|  # ブロック変数x、ブロックローカル変数yを使用
  y = x             # ブロックローカル変数yを代入
  z = x             # ブロックローカルでない変数zを代入
  p [x, y, z]       # ブロック内のx、y、zの値を確認する
end 
puts
p [x, y, z]         # x、y、zの値を確認する

第12章 数値(Numeric)クラス

ファイル名のあるソースコードはありません。

第13章 配列(Array)クラス

List 13.1 : list.rb

list = ["a", "b", "c", "d"]
for i in 0..3
  print i+1,"番目の要素は",list[i],"です。\n"
end

List 13.2 : sum_list.rb

list = [1, 3, 5, 7, 9]
sum = 0
for i in 0..4
  sum += list[i]
end
print "合計:",sum,"\n"

List 13.3 : sum_list2.rb

list = [1, 3, 5, 7, 9]
sum = 0
list.each do |elem|
  sum += elem
end
print "合計:",sum,"\n"

List 13.4 : list2.rb

list = ["a", "b", "c", "d"]
list.each_with_index do |elem, i|
  print i+1,"番目の要素は",elem,"です。\n"
end

List 13.5 : sum_with_each.rb

ary1 = [1, 2, 3, 4, 5]
ary2 = [10, 20, 30, 40, 50]
ary3 = [100, 200, 300, 400, 500]

i = 0
result = []
while i < ary1.length
  result << ary1[i] + ary2[i] + ary3[i]
  i += 1
end
p result  #=> [111, 222, 333, 444, 555]

List 13.6 : sum_with_zip.rb

ary1 = [1, 2, 3, 4, 5]
ary2 = [10, 20, 30, 40, 50]
ary3 = [100, 200, 300, 400, 500]

result = []
ary1.zip(ary2, ary3) do |a, b, c|
  result << a + b + c
end
p result  #=> [111, 222, 333, 444, 555]

第14章 文字列(String)クラス

ファイル名のあるソースコードはありません。

第15章 ハッシュ(Hash)クラス

List 15.1 : word_count.rb

# 単語数のカウント
count = Hash.new(0)

## 単語の集計
File.open(ARGV[0]) do |f|
  f.each_line do |line|
    words = line.split
    words.each do |word|
      count[word] += 1
    end
  end
end

## 結果の出力
count.sort{|a, b|
  a[1] <=> b[1]
}.each do |key, value|
  print "#{key}: #{value}\n"
end

第16章 正規表現(Regexp)クラス

List 16.1 : scan1.rb

"abracatabra".scan(/.a/) do |matched|
  p matched
end

List 16.2 : scan2.rb

"abracatabra".scan(/(.)(a)/) do |matched|
  p matched
end

List 16.3 : scan3.rb

"abracatabra".scan(/(.)(a)/) do |a, b|
  p a+"-"+b
end

List 16.4 : url_match.rb

str = "http://www.ruby-lang.org/ja/"
%r|http://([^/]*)/| =~ str
print "server address: ", $1, "\n"

第17章 IOクラス

List 17.1 : out.rb

$stdout.print "Output to $stdout.\n"  # 標準出力 
$stderr.print "Output to $stderr.\n"  # 標準エラー出力

List 17.2 : tty.rb

if $stdin.tty? 
  print "Stdin is a TTY.\n" 
else 
  print "Stdin is not a TTY.\n" 
end

List 17.3 : stdout_put.rb

$stdout.puts "foo", "bar", "baz"

List 17.4 : stdout_putc.rb

$stdout.putc(82)  # 82は「R」のASCIIコード
$stdout.putc("Ruby")
$stdout.putc("\n")

List 17.5 : test_buffering1.rb

$stdout.print "out1 "
$stderr.print "err1 "
$stdout.print "out2 "
$stdout.print "out3 "
$stderr.print "err2\n"
$stdout.print "out4\n"

List 17.6 : test_buffering2.rb

$stdout.print "out1 "; $stdout.flush
$stderr.print "err1 "
$stdout.print "out2 "; $stdout.flush
$stdout.print "out3 "; $stdout.flush
$stderr.print "err2\n"
$stdout.print "out4\n"

List 17.7 : test_buffering3.rb

$stdout.sync = true  # 出力の同期を取る 
$stdout.print "out1 "
$stderr.print "err1 "
$stdout.print "out2 "
$stdout.print "out3 "
$stderr.print "err2\n"
$stdout.print "out4\n"

List 17.8 : simple_grep_gz.rb

pattern = Regexp.new(ARGV[0])
filename = ARGV[1]
if /.gz$/ =~ filename
  file = IO.popen("gunzip -c #{filename}")
else
  file = File.open(filename)
end
file.each_line do |text|
  if pattern =~ text
    print text
  end
end

List 17.9 : read_uri.rb

require "open-uri" 

# HTTP経由でデータを読み込む 
open("http://www.ruby-lang.org") do |io| 
  puts io.read  # Rubyのホームページをコンソールに出力する 
end 

# FTP経由でデータを読み込む
url = "ftp://www.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p0.tar.gz"
open(url) do |io| 
  open("ruby-2.0.0-p0.tar.gz", "w") do |f|  # ローカルファイルを開く
    f.write(io.read) 
  end 
end

List 17.10 : read_uri_ja.rb

require "open-uri"

options = {
  "Accept-Language" => "ja, en;q=0.5",
}
open("http://www.ruby-lang.org", options){|io|
  puts io.read
}

List 17.11 : stringio_puts.rb

require "stringio"

io = StringIO.new
io.puts("A")
io.puts("B")
io.puts("C")
io.rewind
p io.read  #=> "A\nB\nC\n"

List 17.12 : stringio_gets.rb

require "stringio"

io = StringIO.new("A\nB\nC\n")
p io.gets  #=> "A\n"
p io.gets  #=> "B\n"
p io.gets  #=> "C\n"

第18章 FileクラスとDirクラス

List 18.1 : traverse.rb

def traverse(path)
  if File.directory?(path)  # ディレクトリの場合
    dir = Dir.open(path)
    while name = dir.read
      next if name == "."   # ※
      next if name == ".."  # ※
      traverse(path + "/" + name)
    end
    dir.close
  else
    process_file(path)      # ファイルに対する処理
  end
end
def process_file(path)
  puts path                 # ひとまず出力するだけ
end

traverse(ARGV[0])

List 18.2 : traverse_by_glob.rb

def traverse(path)
  Dir.glob(["#{path}/**/*", "#{path}/**/.*"]).each do |name|
    unless File.directory?(name)
      process_file(name)
    end
  end
end

List 18.3 : listdir.rb

require 'find'

IGNORES = [ /^\./, /^CVS$/, /^RCS$/ ]

def listdir(top)
  Find.find(top) do |path|
    if FileTest.directory?(path)  # pathがディレクトリならば
      dir, base = File.split(path)
      IGNORES.each do |re|
        if re =~ base             # 無視したいディレクトリの場合
          Find.prune              # それ以下の検索を省略する
        end
      end
      puts path                   # 出力する
    end
  end
end

listdir(ARGV[0])

第19章 エンコーディング(Encoding)クラス

List 19.1 : utf8mac.rb

# encoding: utf-8
Dir.glob("*.txt") do |filename|
  if filename == "ルビー.txt"
    puts "found."; exit
  end
end
puts "not found."

List 19.2 : utf8mac_fix.rb

# encoding: utf-8
Dir.glob("*.txt") do |filename|
  if filename.encode("UTF8-MAC") == "ルビー.txt".encode("UTF8-MAC")
    puts "found."; exit
  end
end
puts "not found."

List 19.3 : utf8mac_str.rb

# encoding: utf-8
str = "ビ"
puts "size: #{str.size}"
p str.each_byte.map{|b| b.to_s(16)}
puts "size: #{str.encode("UTF8-MAC").size}"
p str.encode("UTF8-MAC").each_byte.map{|b| b.to_s(16)}

第20章 TimeクラスとDateクラス

ファイル名のあるソースコードはありません。

第21章 Procクラス

List 21.1 : power_of.rb

def power_of(n)
  lambda do |x|
    return x ** n
  end
end

cube = power_of(3)
p cube.call(5)  #=> 125

List 21.2 : prefix.rb

def prefix(ary, obj)
  result = []               # 結果の配列を初期化する
  ary.each do |item|        # 要素を1つずつ見ながら
    result << item          # 要素を結果の配列に追加する
    if item == obj          # 要素が条件に一致するものがあれば
      return result         # 結果の配列を返す
    end
  end
  return result             # すべての要素を検査し終わった場合
end

prefix([1, 2, 3, 4, 5], 3)  #=> [1, 2, 3]

List 21.3 : total2.rb

def total2(from, to, &block)
  result = 0               # 合計の値
  from.upto(to) do |num|   # fromからtoまで処理する
    if block               #   ブロックがあれば
      result +=            #     ブロックで処理した値を足す
           block.call(num)
    else                   #   ブロックがなければ
      result += num        #     そのまま足す
    end
  end
  return result            # メソッドの結果を返す
end

p total2(1, 10)                   # 1から10の和 => 55
p total2(1, 10){|num| num ** 2 }  # 1から10の2乗の値の和 => 385

List 21.4 : counter_proc.rb

def counter
  c = 0          # カウンターを初期化する
  Proc.new do    # callメソッドを呼ぶたびにカウンターに
    c += 1       # 1を足して返すProcオブジェクトを返す
  end
end

# カウンターc1を作成してカウントアップする
c1 = counter
p c1.call      #=> 1
p c1.call      #=> 2
p c1.call      #=> 3

# カウンターc2を作成してカウントアップする
c2 = counter   # カウンターc1を作成
p c2.call      #=> 1
p c2.call      #=> 2

# 再びc1をカウントアップする
p c1.call      #=> 4

List 21.5 : proc_source_location.rb

prc0 = Proc.new{ nil }
prc1 = Proc.new{|a| a }

p prc0.source_location
p prc1.source_location

第22章 テキスト処理を行う

List 22.1 : get_cathedral.rb

require "open-uri"
require "nkf"

url = "http://cruel.org/freeware/cathedral.html"
filename = "cathedral.html"

File.open(filename, "w") do |f|
  text = open(url).read
  f.write text                  # UTF-8を使う環境はこちら
  #f.write NKF.nkf("-s", text)  # Shift_JIS環境(Windows)の場合
end

List 22.2 : cut_cathedral.rb

htmlfile = "cathedral.html"
textfile = "cathedral.txt"

html = File.read(htmlfile)

File.open(textfile, "w") do |f|
  in_header = true
  html.each_line do |line|
    if in_header && /<a name="1">/ !~ line
      next
    else
      in_header = false
    end
    break if /<a name="version">/ =~ line
    f.write line
  end
end

List 22.3 : cut_cathedral2.rb

require 'cgi/util'
htmlfile = "cathedral.html"
textfile = "cathedral.txt"

html = File.read(htmlfile)

File.open(textfile, "w") do |f|
  in_header = true
  html.each_line do |line|
    if in_header && /<a name="1">/ !~ line
      next
    else
      in_header = false
    end
    break if /<a name="version">/ =~ line
    line.gsub!(/<[^>]+>/, '')
    esc_line = CGI.unescapeHTML(line)
    f.write esc_line
  end
end

List 22.4 : simple_grep.rb

pattern = Regexp.new(ARGV[0])
filename = ARGV[1]

File.open(filename) do |file|
  file.each_line do |line|
    if pattern =~ line
      print line
    end
  end
end

List 22.5 : simple_scan.rb

pattern = Regexp.new(ARGV[0])
filename = ARGV[1]

count = 0
File.open(filename) do |file|
  file.each_line do |line|
    if pattern =~ line
      line.scan(pattern) do |s|
        count += 1
      end
      print line
    end
  end
end
puts "count: #{count}"

List 22.6 : simple_count.rb

pattern = Regexp.new(ARGV[0])
filename = ARGV[1]

count = 0
File.read(filename).scan(pattern) do |s|
  count += 1
end
puts "count: #{count}"

List 22.7 : simple_match.rb

pattern = Regexp.new(ARGV[0])
filename = ARGV[1]

count = 0
File.open(filename) do |file|
  file.each_line do |line|
    if pattern =~ line
      line.scan(pattern) do |s|
        count += 1
      end
      print line.gsub(pattern){|str| "<<#{str}>>"}
    end
  end
end
puts "count: #{count}"

List 22.8 : simple_match2.rb

pattern = Regexp.new("(.{10})("+ARGV[0]+")(.{10})")
filename = ARGV[1]

count = 0
File.open(filename) do |file|
  file.each_line do |line|
    line.scan(pattern) do |s|
      puts "#{s[0]}<<#{s[1]}>>#{s[2]}"
      count += 1
    end
  end
end
puts "count: #{count}"

List 22.9 : simple_match3.rb

pattern = Regexp.new("(.{0,10})("+ARGV[0]+")(.{0,10})")
filename = ARGV[1]

count = 0
File.open(filename) do |file|
  file.each_line do |line|
    line.scan(pattern) do |s|
      prefix_len = 0
      s[0].each_char do |ch|
        if ch.ord < 128
          prefix_len += 1
        else
          prefix_len += 2
        end
      end
      space_len = 20 - prefix_len
      puts "#{" "*space_len}#{s[0]}<<#{s[1]}>>#{s[2]}"
      count += 1
    end
  end
end
puts "count: #{count}"

List 22.10 : simple_match4.rb

len = ARGV[2].to_i
pattern = Regexp.new("(.{0,#{len}})("+ARGV[0]+")(.{0,#{len}})")
filename = ARGV[1]

count = 0
File.open(filename) do |file|
  file.each_line do |line|
    line.scan(pattern) do |s|
      prefix_len = 0
      s[0].each_char do |ch|
        if ch.ord < 128
          prefix_len += 1
        else
          prefix_len += 2
        end
      end
      space_len = len * 2 - prefix_len
      puts "#{" " * space_len}#{s[0]}<<#{s[1]}>>#{s[2]}"
      count += 1
    end
  end
end
puts "count: #{count}"

第23章 郵便番号データを検索する

List 23.1 : split_zip.rb

code = ARGV[0]
start_time = Time.now    # 処理の開始時刻を取得する
File.open("KEN_ALL.CSV","r:shift_jis").each_line do |line|
  line.chomp!
  rows = line.split(/,/)
  zipcode = rows[2].gsub(/"/,'')
  if zipcode == code
    puts line.encode('utf-8')
  end
end
p Time.now - start_time  # 処理が終了した時刻との差を表示する

List 23.2 : jzipcode.rb

require 'sqlite3'

class JZipCode
  COL_ZIP = 2
  COL_PREF = 6
  COL_CITY = 7
  COL_ADDR = 8

  def initialize(dbfile)
    @dbfile = dbfile
  end

  def make_db(zipfile)
    return if File.exists?(@dbfile)
    SQLite3::Database.open(@dbfile) do |db|
      db.execute <<-SQL
        CREATE TABLE IF NOT EXISTS zips
          (code TEXT, pref TEXT, city TEXT, addr TEXT, alladdr TEXT)
      SQL

      File.open(zipfile, 'r:shift_jis') do |zip|
        db.execute "BEGIN TRANSACTION"
        zip.each_line do |line|
          columns = line.split(/,/).map{|col| col.delete('"')}
          code = columns[COL_ZIP]
          pref = columns[COL_PREF]
          city = columns[COL_CITY]
          addr = columns[COL_ADDR]
          all_addr = pref+city+addr
          db.execute "INSERT INTO zips VALUES (?,?,?,?,?)",
            [code, pref, city, addr, all_addr]
        end
        db.execute "COMMIT TRANSACTION"
      end
    end
  end

  def find_by_code(code)
    str = ""
    SQLite3::Database.open(@dbfile) do |db|
      db.execute("SELECT * FROM zips WHERE code = ?",
                 code) do |row|
        str += row[1..3].join('')
      end
    end
    str
  end

  def find_by_address(addr)
    str = ""
    SQLite3::Database.open(@dbfile) do |db|
      db.execute("SELECT * FROM zips WHERE alladdr LIKE ?", "%#{addr}%") do |row|
        str += row[0]+' '+row[1..3].join('')+"\n"
      end
    end
    str
  end
end

if __FILE__ == $0
  jzipcode = JZipCode.new("zip.db")
  jzipcode.make_db("KEN_ALL.CSV")
  puts jzipcode.find_by_code("1060031")
  puts jzipcode.find_by_address("東京都渋谷区神宮前")
end