たのしいRuby第1版練習問題回答

Stringは後回し。

追記

  • 2007-11-18 celsius.rbを修正


■第10章 Numericクラス

(1)fahr2celsius.rb

def fahr2celsius(f)
  5.0 * (f - 32.0) / 9.0
end


if __FILE__ == $0
  printf("%11s %11s\n", 'Fahr', 'Celsius')
  0.step(100, 5) do |fahr|
    printf("%11.6f %11.6f\n", fahr, fahr2celsius(fahr))
  end
end

(2)celsius.rb

class Celsius
  def initialize(c)
    @value = c.to_f
  end
  
  attr_reader :value
  protected :value
  
  def fahr2celsius(f)
    5.0 * (f - 32.0) / 9.0
  end
  private :fahr2celsius
  
  def to_celsius
    value
  end
  
  def to_fahr
    fahr2celsius(value)
  end
  
  def +(other)
    self.class.new(value + other.value)
    self
  end
end



if __FILE__ == $0
  c1  = Celsius.new(27.3)
  c2  = Celsius.new(50)
  c12 = c1 + c2
  [c1, c2, c12].each do |c|
    p c.to_celsius
    p c.to_fahr
  end
end

(3)prime_p.rb

def prime?(num)
  num > 1 &&
    (2 ... num).select{|x| (num % x).zero? }.empty?
end


if __FILE__ == $0
  0.upto(9) do |n|
    p n if prime?(n)
  end
end

(4)round_diff.rb

#doubt
a = 0.1 + 0.2
p a
b = (a == 0.3)
p b

#answer
[a, 0.3].each do |x|
  printf("%.64f\n", x)
end

■第11章 Arrayクラス

(1)square.rb

def main
  if __FILE__ == $0
    nums = [1, 2, 4, 6]
    p square(nums)
    puts '-'*60
  end
end

# # # # #


def square(nums)
  nums.collect{|n| n * n }
end

main


def square(nums)
  sq = []
  nums.each{|n| sq.push(n * n) }
  sq
end

main


def square(nums)
  sq = []
  i = 0
  until i == nums.size
    sq.push(nums[i] ** 2)
    i += 1
  end
  sq
end

main

(2)sum_array.rb

def sum_array(nums1, nums2)
  if nums2.size > nums1.size
    nums1, nums2 = nums2, nums1
  end
  nums1.zip(nums2).map{|x, y| x + (y || 0) }
end


if __FILE__ == $0
  p sum_array([1, 2, 3], [4, 6, 8])
end

(3)balanced_p.rb

def balanced?(parens)
  tbl = {
    '(' => ')',
    '{' => '}',
    '[' => ']'
  }
  stack = []
  parens.each do |x|
    case
    when tbl.key?(x)
      stack.push(x)
    when tbl.value?(x)
      tbl[stack.pop] == x or return false
    end
  end
  stack.empty?
end


if __FILE__ == $0
  parens1 = '({{}()}())'.split(//)
  parens2 = '({{}(}))'.split(//)
  [parens1, parens2].each do |parens|
    p balanced?(parens)
  end
end

■第13章 Hashクラス

(1)str2hash.rb

def str2hash(str)
  h = {}
  temp = str.strip.split(/\s+/)
  until temp.empty?
    k = temp.shift
    v = temp.shift
    h[k] = v if k
  end
  h
end



if __FILE__ == $0
  $KCODE = 'sjis'
  p str2hash("blue 青 while 白\nread 赤")
end

(2)orderedhash.rb

class OrderedHash
  include Enumerable
  
  def initialize
    @body = []
  end
  
  attr_reader :body
  protected :body
  
  def each(&block)
    body.each(&block)
  end
  
  def [](key)
    body.assoc(key)[1]
  end
  
  def []=(key, value)
    hit = body.assoc(key)
    if hit
      hit[1] = value
    else
      body << [key, value]
    end
  end
  
  def key?(k)
    body.assoc(k) ? true : false
  end
  
  def value?(v)
    body.rassoc(v) ? true : false
  end
  
end



if __FILE__ == $0
  [Hash, OrderedHash].each do |klass|
    h = klass.new
    h['hoge'] = 'piyo'
    h[:foo] = :bar
    h['ruby'] = :wonderful
    h.each do |k, v|
      p k, v
    end
    puts '-'*60
  end
end

■第14章 Regexpクラス

(1)mail_addr.rb

addr = 'shionist@yahoo.co.jp'


/\A(.*?)@(.*?)\Z/ =~ addr


local, domain = $1, $2
puts "local:  #{$1}"
puts "domain: #{$2}"

(2)gsub.rb

#!ruby -Ks

str = "オブジェクト指向は難しい! なんて難しいんだ!"
puts str
puts str.gsub(/難しい(んだ)?/){|m|
  "簡単#{$1 ? 'なん' : ''}"
}

(3)word_capitalize.rb

def word_capitalize(str)
  str.split('-').map{|w|
    w.gsub(/[a-zA-Z]+/){|m| m.capitalize }
  }.join('-')
end


if __FILE__ == $0
  ['in-reply-to', 'X-MAILER'].each do |s|
    p word_capitalize(s)
  end
end

■第15章 IOクラス

(1)copy.rb

def copy(from, dest)
  File.open(from, 'rb') do |f|
    File.open(dest, 'wb') do |w|
      w.print f.read
    end
  end
end



if __FILE__ == $0
  copy $0, "#{$0}.copy~"
end

(2)tail.rb

def tail(n, file)
  queue = []
  IO.foreach(file) do |line|
    queue << line
    queue.shift if queue.size > n
  end
  puts queue
end


if __FILE__ == $0
  tail(3, $0)
end

■第16章 FileクラスとDirクラス

(1)printlibrary.rb

require 'rbconfig'

def print_library
  exts = ['rb', Config::CONFIG['DLEXT'], Config::CONFIG['DLEXT2']]
  puts $:.map{|path|
    Dir.entries(path).select{|file|
      File.file?(File.join(path, file)) and
        exts.include?(file.split('.').last)
    }
  }
end

alias printLibrary print_library


if __FILE__ == $0
  printLibrary
end

(2)dircopy.rb

require 'find'
require 'fileutils'

def dircopy(from, dest)
  from, dest = [from, dest].map{|dir|
    m = dir.match(/#{File::SEPARATOR}\Z/o)
    m ? m.pre_match : dir
  }
  
  Find.find(from) do |path|
    next unless File.directory?(path)
    FileUtils.mkpath(
      File.join(dest, path.match(/\A#{from}/).post_match)
    )
  end
  
  Find.find(from) do |path|
    next if File.directory?(path)
    FileUtils.cp(
      File.join(from, path.match(/\A#{from}/).post_match),
      File.join(dest, path.match(/\A#{from}/).post_match)
    )
  end
end



if __FILE__== $0
  dircopy './From/', './Dest'
end

(3)du.rb

require 'find'

def du_sub(dir)
  total = 0
  Dir.foreach(dir) do |path|
    next if path == '.' || path == '..'
    path = File.join(dir, path)
    if File.directory?(path)
      total += du_sub(path)
    else
      total += File.size(path)
    end
  end
  total
end

def du(dir)
  puts du_sub(dir)
end



if __FILE__ == $0
  du('..')
end

■第17章 Timeクラス

(1)jparsedate.rb

#!ruby -Ks

def jparsedate(str)
  Time.local(
    *str.gsub(/(午前|午後)/){|m|
      {
        '午前' => '00+',
        '午後' => '12+'
      }[m] || ''
    }.scan(/[\d\+]+\D/s).map{|x|
      n = 0
      if /\A[\d\+]+/ =~ x
        n += eval($&)
      end
      n
    }
  )
end



if __FILE__ == $0
  t = jparsedate("2001年12月23日午後8時17分50秒")
  puts t.strftime("%Y/%m/%d %H:%M:%S")
end

(2)ls_t.rb

def ls_t(dir)
  puts (Dir.entries(dir) - ['.', '..']).map{|path|
    File.join(dir, path)
  }.sort{|x, y| File.ctime(y) <=> File.ctime(x) }
end


if __FILE__ == $0
  ls_t('.')
end