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

第1章 はじめてのRuby

List 1.1 : helloruby.rb

print("Hello, Ruby.\n")

List 1.2 : puts_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 第5版」サンプル
コメントの使い方の例
2006/06/16 作成
2006/07/01 一部コメントを追加
2015/10/01 第5版用に更新
=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 : greater_smaller.rb

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

List 1.7 : greater_smaller_else.rb

a = 20
if a >= 10
  print "greater\n"
else
  print "smaller\n"
end

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

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

第3章 コマンドを作ろう

List 3.1 : print_argv.rb

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

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_relative "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_relative "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.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

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
file.close

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
file.close

List 6.16 : hello.rb

# Hello, world
puts("hello, world")

# 日本語
puts("こんにちは世界")

# 中文
puts("你好,世界")

List 6.17 : stripped_hello.rb

puts("hello, world")
puts("こんにちは世界")
puts("你好,世界")

第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 > 10     # numが10を超えていたら抜ける
  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.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+/) # selfを空白文字区切りで
                            # 配列に分解する
    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 : alias_sample.rb

class C1                 # C1クラスの定義
  def hello              # helloを定義
    "Hello"
  end
end

class C2 < C1            # C1クラスを継承してC2クラスを定義
  alias old_hello hello  # 別名old_helloを設定

  def hello              # helloを再定義
    "#{old_hello}, again"
  end
end

obj = C2.new
p obj.old_hello          #=> "Hello"
p obj.hello              #=> "Hello, again"

List 8.10 : mixin_sample.rb

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

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

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

List 8.11 : 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.12 : 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.13 : 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.14 : 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.body

第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  # pメソッドで「(x, y)」と表示する
    "(#{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)

第10章 エラー処理と例外

List 10.1 : wc.rb

ltotal=0                             # 行数の合計
wtotal=0                             # 単語数の合計
ctotal=0                             # 文字数の合計
ARGV.each do |file|
  begin
    input = File.open(file)          # ファイルを開く@<b>{(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>{(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

# %w(...) は各単語を要素とする配列を生成するリテラルです
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 > 10     # numが10を越えていたら抜ける
  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 : proc1.rb

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

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

List 11.11 : 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.12 : call_each.rb

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

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

List 11.13 : 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.14 : 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)クラス

List 14.1 : frozen_string.rb

# frozen-string-literal: true

str = "Ruby"
p str.upcase!

第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

3.times do |i|
  $stdout.puts "#{Random.rand}"        # 標準出力へ
  $stderr.puts "#{i+1}回出力しました"  # 標準エラー出力へ
end

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 "String", :Symbol, 1/100r

List 17.4 : stdout_putc.rb

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

List 17.5 : test_buffering1.rb

filename = "buffering.txt"
File.open(filename, "w") do |file|
  3.times do |i|
    # 5バイト書き込むごとにファイルのサイズを調べる
    file.write("a" * 5)
    puts "#{i+1}回目: #{File.size(filename)}"
  end
end
puts "終了後: #{File.size(filename)}"  # もう一度調べる
p File.read(filename)                  # 出力を確認する

List 17.6 : test_buffering2.rb

filename = "buffering.txt"
File.open(filename, "w") do |file|
  3.times do |i|
    # 5バイト書き込むごとにファイルのサイズを調べる
    file.write("a" * 5)
    file.flush                         # 出力を反映する
    puts "#{i+1}回目: #{File.size(filename)}"
  end
end
puts "終了後: #{File.size(filename)}"  # もう一度調べる
p File.read(filename)                  # 出力を確認する

List 17.7 : test_buffering3.rb

filename = "buffering.txt"
File.open(filename, "w") do |file|
  file.sync = true                     # 出力を同期させる
  3.times do |i|
    # 5バイト書き込むごとにファイルのサイズを調べる
    file.write("a" * 5)
    puts "#{i+1}回目: #{File.size(filename)}"
  end
end
puts "終了後: #{File.size(filename)}"  # もう一度調べる
p File.read(filename)                  # 出力を確認する

List 17.8 : simple_grep_gz.rb

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

List 17.9 : read_uri.rb

require "open-uri" 

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

# FTP経由でデータを読み込む
filename = "ruby-2.3.0.tar.gz"
url = "ftp://ftp.ruby-lang.org/pub/ruby/2.3/#{filename}"
open(url) do |io| 
  File.binwrite(filename, io.read)  # ファイルに書き込む
end

List 17.10 : 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.11 : 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 = [ /^\./, /^\.svn$/, /^\.git$/ ]

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)クラス

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

第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

p 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   # カウンターc2を作成
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_nisen.rb

require "open-uri"

url = "http://www.aozora.gr.jp/cards/001779/files/56647_58167.html"
filename = "nisendouka.html"

File.open(filename, "wb") do |f|
  text = open(url, "r:shift_jis").read
  f.write text                   # Shift_JIS環境(Windows)の場合
  #f.write text.encode("utf-8")  # UTF-8を使う環境はこちら
end

List 22.2 : cut_nisen.rb

htmlfile = "nisendouka.html"
textfile = "nisendouka.txt"

html = File.read(htmlfile)

File.open(textfile, "w") do |f|
  in_header = true
  html.each_line do |line|
    if in_header && /<div class="main_text">/ !~ line
      next
    else
      in_header = false
    end
    break if /<div class="bibliographical_information">/ =~ line
    f.write line
  end
end

List 22.3 : cut_nisen2.rb

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

html = File.read(htmlfile)

File.open(textfile, "w") do |f|
  in_header = true
  html.each_line do |line|
    if in_header && /<div class="main_text">/ !~ line
      next
    else
      in_header = false
    end
    break if /<div class="bibliographical_information">/ =~ 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(ARGV[0])
filename = ARGV[1]

count = 0
File.open(filename) do |file|
  file.each_line do |line|
    line.scan(pattern) do |s|
      pre = $`
      post = $'
      puts "#{pre[-10,10]}<<#{s}>>#{post[0,10]}"
      count += 1
    end
  end
end
puts "count: #{count}"

List 22.10 : simple_match4.rb

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

count = 0
File.open(filename) do |file|
  file.each_line do |line|
    line.scan(pattern) do |s|
      pre = $`
      post = $'
      puts "#{pre[-len,len]}<<#{s}>>#{post[0,len]}"
      count += 1
    end
  end
end
puts "count: #{count}"

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

List 23.1 : read_csv.rb

require "csv"            # csvライブラリを使う

code = ARGV[0]           # 引数を取り出す
start_time = Time.now    # 処理の開始時刻を取得する

# Shift_JISをUTF-8に変換する指定をしてCSVファイルを開く
CSV.open("KEN_ALL.CSV","r:Shift_JIS:UTF-8") do |csv|
  csv.each do |record|
    # 郵便番号が引数の指定と一致したらそのレコードを表示する
    puts record.join(" ") if record[2] == code
  end
end
p Time.now - start_time  # 処理が終了した時刻との差を表示する

List 23.2 23.3: jzipcode.rb

require 'sqlite3'
require "csv"

class JZipCode
  CSV_COLUMN = {code: 2, pref: 6, city: 7, addr: 8}

  def initialize(dbfile)
    @dbfile = dbfile
  end

  def create(zipfile)
    return if File.exist?(@dbfile)
    SQLite3::Database.open(@dbfile) do |db|
      db.execute(<<-SQL)
        CREATE TABLE IF NOT EXISTS zip_codes
          (code TEXT, pref TEXT, city TEXT, addr TEXT, alladdr TEXT)
      SQL
      db.execute("BEGIN TRANSACTION")
      CSV.open(zipfile, "r:Shift_JIS:UTF-8") do |csv|
        csv.each do |rec|
          data = Hash.new
          CSV_COLUMN.each{|key, index| data[key] = rec[index] }
          data[:alladdr] = data[:pref] + data[:city] + data[:addr]
          db.execute(<<-SQL, data)
            INSERT INTO zip_codes VALUES
              (:code, :pref, :city, :addr, :alladdr)
          SQL
        end
      end
      db.execute("COMMIT TRANSACTION")
    end
    return true
  end

  def find_by_code(code)
    ret = []
    SQLite3::Database.open(@dbfile) do |db|
      db.execute(<<-SQL, code){|row| ret << row.join(" ") }
        SELECT code, alladdr
          FROM zip_codes
         WHERE code = ?
      SQL
    end
    return ret.map{|line| line + "\n"}.join  
  end

  def find_by_address(addr)
    ret = []
    SQLite3::Database.open(@dbfile) do |db|
      like = "%#{addr}%"
      db.execute(<<-SQL, like){|row| ret << row.join(" ") }
        SELECT code, alladdr
          FROM zip_codes
         WHERE alladdr LIKE ?
      SQL
    end
    return ret.map{|line| line + "\n"}.join  
  end
end

if __FILE__ == $0
  dbfile = "jzipcode.db"
  jzipcode = JZipCode.new(dbfile)
  jzipcode.create("KEN_ALL.CSV")
  puts jzipcode.find_by_code("3210202")
  puts jzipcode.find_by_address("猫屋敷")
end