モジュールと標準ライブラリ
Ruby
Comparable・Enumerable・File・JSON・Regexp
モジュールの活用
名前空間・Comparable・Enumerable の実装
# 名前空間としてのモジュール
module MyApp
module Models
class User
attr_accessor :name, :age
def initialize(name, age)
@name, @age = name, age
end
end
end
module Services
class UserService
def find(id)
# ...
end
end
end
end
user = MyApp::Models::User.new('Alice', 30)
# Comparable を include してソート可能にする
class Box
include Comparable
attr_accessor :volume
def initialize(volume) = (@volume = volume)
# <=> を定義するだけで ==, <, >, <=, >=, between?, clamp が使える
def <=>(other)
volume <=> other.volume
end
end
boxes = [Box.new(10), Box.new(5), Box.new(20)]
boxes.sort # volume の昇順
boxes.min # volume 5 の Box
boxes.max # volume 20 の Box
# Enumerable を include してコレクションを作る
class NumberSet
include Enumerable
def initialize(*nums) = (@nums = nums)
# each を定義するだけで map, select, sort, min, max... 全て使える
def each(&block) = @nums.each(&block)
end
ns = NumberSet.new(3, 1, 4, 1, 5, 9, 2, 6)
ns.sort # [1,1,2,3,4,5,6,9]
ns.select(&:odd?) # [3,1,1,5,9]
ns.map { |x| x * 2 } # [6,2,8,2,10,18,4,12]ファイル I/O
File・Dir・Pathname・CSV・JSON
require 'json'
require 'csv'
require 'pathname'
# ファイルの読み書き
File.write('hello.txt', 'Hello, World!') # 書き込み
content = File.read('hello.txt') # 全体読み込み
lines = File.readlines('data.txt', chomp: true) # 行ごと
# ブロック形式(確実にクローズ)
File.open('output.txt', 'w') do |f|
f.puts 'line 1'
f.puts 'line 2'
end
File.foreach('data.txt') { |line| puts line.chomp } # 大きなファイルに
# ファイル情報
File.exist?('file.txt') # true/false
File.size('file.txt') # バイト数
File.mtime('file.txt') # 更新時刻
File.basename('/path/to/file.txt') # 'file.txt'
File.extname('file.txt') # '.txt'
File.dirname('/path/to/file.txt') # '/path/to'
File.join('dir', 'sub', 'file.txt') # 'dir/sub/file.txt'
# Pathname(オブジェクト指向なパス操作)
path = Pathname.new('dir/sub/file.txt')
path.basename # Pathname('file.txt')
path.extname # '.txt'
path.parent # Pathname('dir/sub')
path.read # ファイルの内容
# Dir
Dir.mkdir('new_dir')
Dir.glob('**/*.rb') # 再帰的にRubyファイルを取得
Dir.entries('.') # ファイル一覧(.と..含む)
Dir.each_child('.') { |f| puts f } # .と..を除く
# JSON
data = { name: 'Alice', scores: [95, 87] }
json_str = JSON.generate(data)
json_str = JSON.pretty_generate(data) # 整形
parsed = JSON.parse(json_str, symbolize_names: true) # キーをシンボルに
File.write('data.json', JSON.pretty_generate(data))
parsed = JSON.parse(File.read('data.json'), symbolize_names: true)
# CSV
CSV.foreach('data.csv', headers: true) do |row|
puts row['name'] # ヘッダーでアクセス
end
CSV.open('output.csv', 'w', headers: %w[name age], write_headers: true) do |csv|
csv << ['Alice', 30]
csv << ['Bob', 25]
endよく使う標準ライブラリ
Struct・OpenStruct・SecureRandom・Benchmark
require 'securerandom'
require 'benchmark'
equire 'ostruct'
require 'set'
# Struct(軽量なデータクラス)
Point = Struct.new(:x, :y) do
def distance_to(other)
Math.sqrt((x - other.x)**2 + (y - other.y)**2)
end
end
p1 = Point.new(0, 0)
p2 = Point.new(3, 4)
p1.distance_to(p2) # 5.0
p1.to_a # [0, 0]
p1.to_h # {x: 0, y: 0}
Point.members # [:x, :y]
# Data(Ruby 3.2+、イミュータブルなStruct)
Measurement = Data.define(:value, :unit)
m = Measurement.new(value: 100, unit: 'kg')
# m.value = 200 # FrozenError!
# Set
require 'set'
set = Set.new([1, 2, 3])
set.add(4)
set.include?(3) # true
set1 = Set.new([1,2,3])
set2 = Set.new([2,3,4])
set1 | set2 # Set{1,2,3,4}(和集合)
set1 & set2 # Set{2,3}(積集合)
# SecureRandom
SecureRandom.uuid # 'f47ac10b-58cc-4372-...'
SecureRandom.hex(16) # '3a7f...'(32文字の16進数)
SecureRandom.base64(12) # ランダムなBase64文字列
# Benchmark
Benchmark.bm do |x|
x.report('sort:') { (1..10000).to_a.shuffle.sort }
x.report('sort!:') { arr = (1..10000).to_a.shuffle; arr.sort! }
end
# Comparable で <=> を実装するだけで sort が使える
# Benchmark.measure { heavy_computation }.real # 秒数