Rubyプログラミングの基礎
Rubyは、スクリプト言語なので多くのレンタルサーバで利用可能です。またオブジェクト指向言語なので知識や慣れが必要となりますが、少ないコーディングで効率良く開発を行えます。このページでは、Web開発を行なう上で、習得しておきたいコーディング方法やイディオムを重点的に説明しています。
目次
Rubyの変数について
Rubyでは、変数の種類としてローカル変数、グローバル変数、クラス変数、インスタンス変数があります。ローカル変数とは、ブロック内のみで有効な変数で、グローバル変数はどのブロックでも利用可能な変数です。インスタンス変数はそのインスタンスのみで有効な変数で、クラス変数は、同クラスのインスタンスで共有される変数となります。
Rubyの定数は、大文字から初めて定義します。一般的なプログラミング言語の定数とは異なり、変更と再代入が可能です。定数への変更はfreezeメソッドで防げますが、再代入は警告発生だけで再代入は行われます。
Rubyでは、数値や文字列もオブジェクトになっているため、所属するクラスのメソッドが使えます。クラスには整数、浮動小数点、文字列、配列、ハッシュ(連想配列)などがあります。またオブジェクトの親クラスとしてObjectがあり、さらに上位クラスのBasicObjectがあります。つまりすべてのオブジェクトでObject、BasicObjectのメソッドが使えます。
# コメント
# ローカル変数
s = 'a'
# グローバル変数
$s = 'A'
class C
# クラス変数
@@name = 'C'
def initialize(x=0)
# インスタンス変数
@v = x
end
# インスタンス変数を返す
def v
@v += 1
return @v
end
# クラス変数を返す
def name
@@name += @v.to_s
return @@name
end
end
c = C.new()
puts c.v #1
puts c.name #C1
c2 = C.new()
puts c2.v #1
puts c2.name #C11
# グローバル変数を確認
p global_variables()
# 定数
DB_NAME = ''
# 変更制限 再代入はできる
DB_NAME.freeze
#整数オブジェクトの文字列に変換するメソッド
s = 10.to_s
# 型を確認 クラス名を取得
s.class
# クラス名で判定
if s.kind_of?(String)
if s.is_a?(String)
# クラスのインスタンスか判定
if s.instance_of?(String)
Rubyで文字列を扱う方法
Rubyでは、文字列もオブジェクトとなるため、代入前からメソッドを利用できます。メソッドには変数自体を書き換える破壊的メソッドと、書き換えたデータを戻り値として返す非破壊的メソッドがあります。破壊的メソッドには、基本的にメソッドの最後に!が付きます。
Rubyでの文字列の連結は、<<が利用されます。また[]で正規表現を用いた部分文字列の切り出しが行えます。また文字列と数値を結合する場合、数値を文字列に変換する必要があります。
# 文字列を作成
s = 'a'
s = 'a' * 5 #aaaaa
s = %(aa'bb'aa"cc")
# 文字列を結合する
s = 'a' + 'b'
s += 'c'
s = 'a' 'b' #スペースあり、なしでも結合
# 繰り返し結合する場合、こちらが高速
s = 'a' << 'b'
s <<= 'c'
s = 'a'.concat('b')
# 数値と文字列を結合
s = 'a' + 10.to_s #a10
# 文字列を数値にする
n = '10'.to_i * 2 #20
# 文字列の挿入
s = 'aa11bb22'.insert('zz') #aazz1bb22
# 文字列の再代入
s1 = 'aaa'
s2 = s1
s1.replace('bbb')
print s1,s2,"\n" #s1=bbb,s2=bbb
s1 = 'ccc' #別インスタンスに
print s1,s2,"\n" #s1=ccc,s2=bbb
s1.replace('aaa')
print s1,s2,"\n" #s1=aaa,s2=bbb
# 文字列の一部取り出し
s = 'abcde'[1] #b
# [開始,長さ]
s = 'abcde'[2,2] #cd
s = 'abcde'.slice(2,2) #cd
# [開始..終了]
s = 'abcde'[2..3] #cd
# [正規表現]
s = 'abc123def'[/\d+/] #123
# [正規表現, マッチ番号]
s = 'abc123def'[/([a-zA-Z]+)\d+([a-zA-Z]+)/,1] #abc
# [文字列] ない場合 nil
s = 'abcdef'[bce] #bcd
# インデックスで置換
s = 'aa11bb22'
s[2] = 'zz' #aazz1bb22
# 文字列の一部を削除 インデックス指定
s = 'aabbcc'
s.slice!(2,2) #aacc 変数を書き換え
# 適合する文字を削除
s = 'aabbcc'
s.delete!('a') #bbcc 変数を書き換え
# 正規表現で一度だけ置換
s = 'aa11bb22'
s[/[a-zA-Z]+/] = '' #11bb22
s = 'a1b2c3'.sub(/\d/,'') #ab2c3
# マッチした文字列をブロック処理
s = 'a1b2c3'.sub(/\d/){|m| m*3 } #a111b2c3
# 対象を置換する
s = 'aa11bb22'
s.sub!(/\d+/,'zz') #aazzbb22 変数を書き換え
# 正規表現ですべてを置換
s = 'a1b2c3'.gsub(/\d/,'') #abc
# 対象を置換する
s = 'aa11bb22'
s.gsub!(/\d+/,'zz') #aazzbbzz 変数を書き換え
# 文字列をリストで置換
s = '123456789'
r = s.tr('1-9','a-i')
# 文字列を正規表現で判定 $& $1 $2などにセット
if s =~ /(\d+)/
puts $1
end
# 文字列の長さ
n = s.length
n = s.size
# 含まれる文字の数を調べる
n = s.count('a')
n = s.count('a-z','^x') #範囲指定可、複数で「かつ」
# 文字列が含まれるか判定
if s.include?('')
# 末尾の改行を除去
s = s.rstrip
s.rstrip!
# 文字列を区切り文字で配列に
a = 'abc,edf'.split(',')
Rubyで配列、連想配列(ハッシュ)を扱う方法
Rubyでは、配列もオブジェクトとなっているため、多数のメソッドを利用することができます。配列は、複数のデータを格納し、順番に処理する場合などに利用されます。配列の要素には、配列や連想配列を入れることもでき、多次元配列と呼ばれます。
# 配列の作成
a = ['a','b','c']
a = Array.new(5, 1) #[1,1,1,1,1]
a = %w(a b c) #['a','b','c']
a = %i(a b c) #[:a, :b, :c] シンボルの配列
# 配列から取り出す
e = a[1]
# 指定位置から取り出す
e = a.at(1)
# [開始,長さ]
a = a[2,2]
# 開始[開始..最後]
a = a[3..4]
# 配列の結合
a = a1 + a2
a += b
# 配列の要素から配列の要素を引く 差集合
a = ['a','b','c','d']
b = ['b','e']
c = a - b #['a','c','d']
# 配列の共通要素を取得 積集合
c = a & b #['b']
# 配列を合わせた全要素を取得 和集合
c = a | b #['a','b','c','d','e']
# 配列の最後に要素を追加
a.push('1','2')
a << b
# 配列の最後に配列の要素を追加
a.concat(b)
# 配列の先頭に要素を追加
a.unshift('1')
# 配列の最後の要素を除去して取り出す
e = a.pop
b = a.pop(2) #2個とりだし
# 配列の先頭から要素を除去して取り出す
e = a.shfit
b = a.shift(2) #2個とりだし
# 配列から条件で配列を取得
a = [1,2,3,4,5,6]
b = a.select{|i| i%2==0 } #[2,4,6] 適合する要素の配列
b = a.reject{|i| i%2==0 } #[1,3,5] 不適合の要素の配列
# 配列の要素数
a = ['a','b','c','d']
n = a.count
# 該当する文字の数
n = a.count('a')
# 配列を順番に処理
a = ['a','b','c']
a.each do |i|
puts i
end
# do .. end か {}
a.each{|i|
puts i
}
# 配列の要素を処理ブロックに通す
a = [1,2,3]
b = a.map{|i| i*2 } #[2,4,6]
# 配列からランダムに要素を取得
e = a.sample
e = a.sample(2) #2個とりだし
# 配列をランダムに入替え
a = a.shuffle
a.shuffle!
# 配列の要素をずらす 先頭から指定位置までを末尾に追加
a = [1,2,3,4,5]
b = a.rotate(2) #[3,4,5,1,2]
a.rotate!(2) #変数を書き換え
# 配列を区切り文字で結合して文字列に
s = a.join(',')
連想配列(ハッシュ)は、キー(文字列)で要素を特定できるものです。配列のように順番がないため、順序が必要な場合は、キーの配列を用意する必要があります。Rubyでは、キーとしてより高速な処理が行えるシンボルを使うことができます。シンボルは、:の後に英数字とアンダースコアで表現されます。※先頭は数値以外
# 連想配列(ハッシュ)の作成
h = {'a'=>10, 'b'=>'xx'}
# キーで取り出す
v = h['a'] #10
# 追加する
h['c'] = 30
# シンボルで作成 こちらが高速
h = {a:10, b:'xx'}
h = {:a=>10, :b=>'xx'}
# シンボルで取り出す
v = h[:a] #10
# 追加する
h[:c] = 30
# 配列からハッシュを作成
keys = ['a','b']
vals = [1,2]
h = Hash[keys.zip(vals)]
# ハッシュから要素を削除する
h.delete(:a)
# ハッシュを初期化する
h.clear
# ハッシュを結合する 上書きマージ
c = a.merge(b)
a.merge!(b)
# ハッシュから条件でハッシュを取得
r = h.select{|key,val| 50 < val } #適合する要素のハッシュ
r = h.reject{|key,val| 50 < val } #不適合の要素のハッシュ
# ハッシュのキーと値を入れ替える
h = {a:10, b:20}
r = h.invert #{10=>:a, 20=>:b}
# ハッシュのキーの存在判定
if h.key?(:a)
# 多次元ハッシュから取得 高次のキーがない場合にエラーにならない v2.3
e = h.dig(:a, :b)
# ハッシュの要素の数
n = h.length
n = h.size
# ハッシュの要素を処理
h.each do |key, val|
処理
end
# ハッシュのキーリスト(配列)を取得する
a = h.keys
# ハッシュの値リスト(配列)を取得する
a = h.values
# ハッシュのキーと値の対応リストの配列を取得する
h = {a:'1',b:'2'}
a = h.to_a #[[:a,'a'], [:b, '2']]
Rubyの制御構文
Rubyでは、数値演算として++(インクリメント)、--(ディクリメント)がないため、別の方法で記述します。ループ処理を行なう際はforでは範囲指定、特定の長さではtimes、upto、downtoが利用できます。Rubyのインデント(字下げ)は、スペース2つが一般的なようです。
# 数値
i = 0
i += 1
i -= 1
# 条件分岐
if A
Aの処理
elsif B
Bの処理
else
A,B以外
end
# 否定条件
unless A
A以外の処理
end
# 後置条件
s = '真' if A
s = '偽' unless A
# 文字列の比較
if '100'=='100'
if '100'==100 #false
# 整数の比較
if 100==100.0 #true
# オブジェクトの比較
if s1.equal?(s2)
# 三項演算子 Aの時B、A以外の時C
v = A ? B: C
# 繰り返し処理 doは省略可
for i in 1..10 do
puts i
end
# do .. end または {}
(1..5).each do |i|
処理
end
# 回数指定 0-4
5.times do |i|
puts i
end
# 方向指定 増加
1.upto(5) do |i|
puts i
end
# 方向指定 減少
5.downto(1) do |i|
puts i
end
# 条件が真の時、繰り返し
while A do
処理
end
# breakされるまで繰り返し
loop do
break if A
end
# case文
case 変数
when 'A'
Aの時
when 'B'
Bの時
else
A,B以外
end
# 例外処理
begin
# エラーを検出する処理
# 例外を起こす場合 raise
raise
rescue
# $! 例外オブジェクト
# $@ バックトレースの配列
end
# 一行で例外処理
v = 処理 rescue エラー時の処理
Rubyでデータ取得を行なう方法
Rubyで、保存したファイルや標準クラス、モジュールからデータを取得する方法です。CGIなどのWebプログラムでは、環境変数や標準入力からユーザーの入力を受け取ることが出来ます。
# ファイル名を定数に
FILE_NAME = 'file.txt'
# データ用変数
lines_t = ''
lines_a = []
# ファイルから一行ずつ読み込む
File.open(FILE_NAME,'r') do |f|
f.each_line do |line|
lines_t << line
end
end
# ファイルから一行ずつ読み込む
File.foreach(FILE_NAME,'r') do |line|
lines_t << line
end
# ファイルから一気に読み込む
File.open(FILE_NAME,'r') do |f|
lines_t = f.read
end
# ファイルから行ごとの配列に読み込む
File.open(FILE_NAME,'r') do |f|
lines_a = f.readlines
end
# Shift_JISのcsvファイルを読み込む
File.open(FILE_NAME, 'r', encoding: 'cp932:utf-8') do |f|
end
# ファイル情報の取得
info = File::Stat.new(FILE_NAME)
# ファイルの最終更新日時
mtime = info.mtime
# ディレクトリ内のファイル一覧
files = []
Dir.foreach('./') do |f|
files << f
end
# ファイルを検索する
files = Dir.glob('*.txt')
# 標準入力から読み込む
s = STDIN.read
# 標準入力から一行ずつ読み込む
STDIN.each_line do |line|
end
# 環境変数から取り出す
ua = ENV['HTTP_USER_AGENT']
# Unixタイムスタンプを取得する
time = Time.now.to_i
# 日時を取得する
date = Time.now.strftime("%Y-%m-%d %H:%M:%S")
# ランダムな数値を取得する
n = rand(10) #0-9
n = rand(5..10) #5-10
n = [*1..5].sample
# 外部コマンドの実行結果から取得する
require 'open3'
r = []
Open3.popen3('ls -l') do |i,o,e,t|
# 標準入力として渡す場合
i.write('')
# 閉じてから結果取得
i.close
# 結果を配列に代入
o.each do |line| r << line.rstrip end
end
# コマンドラインの引数を取得
ARGV #配列 ARGV[0],ARGV[1]
# プログラム名
$0
# スクリプト上の行番号
__LINE__
# スクリプトのファイル名
__FILE__
Rubyでデータ変換を行なう方法
Rubyで入力されたデータを出力するために、適切なフォーマットに変換する処理です。標準で使える組み込みライブラリ以外にも、requireで読み込むことでインストールすることなく使えるライブラリがあります。
# 特定の文字列を除去する
# カンマを除去
s.tr!(',','')
# タブ文字を除去
s.tr!("\t",'')
# HTMLエスケープする
s.gsub!('&','&')
s.gsub!('<','<')
s.gsub!('>','>')
s.gsub!('"','"')
s.gsub!("'",''')
# 改行コードの統一
s.gsub!("\r\n","\n")
s.gsub!("\r","\n")
# 末尾の改行や空白を除去
s.rstrip!
# 改行のみを除去
s.chomp!
# URLデコードする
s.tr!('+',' ')
s.gsub!(/%([a-fA-F0-9][a-fA-F0-9])/){|t| [$1].pack('H2') }
# URLエンコードする
s.gsub!(/[^a-zA-Z0-9 ]/){|t| '%' << t.unpack('H2')[0].upcase }
s.tr!(' ','+')
# 文字コードを変換する
# Shift_JISの文字列をUTF-8に
s = s.encode('UTF-8','Shift_JIS')
# UTF-8の文字列をShift_JISに
s = s.encode('Shift_JIS','UTF-8')
# Unixタイムスタンプから日時に変換
date = Time.at(time).strftime("%Y-%m-%d %H:%M:%S")
# 日時からタイムスタンプに変換
require 'time'
time = Time.strptime(date,"%Y-%m-%d %H:%M:%S").to_i
# md5値を求める
require 'digest/md5'
# 文字列のmd5値
md5 = Digest::MD5.digest(s)
# ファイルのmd5値
md5 = Digest::MD5.file('FILE')
# 変数を保存用に文字列にする
# シリアライズ
h = {a:10}
se = Marshal.dump(h)
# 文字列を変数に復元する
h = Marshal.load(se)
# JSONデータを変換する
require 'json'
# JSON文字列を変数に
j = '{"result":[{"x":20},{"x":50}]}'
h = JSON.parse(j)
# 変数をJSON文字列に
j = JSON.generate(h)
# ファイル名の変更、移動
File.rename('old','new')
Rubyでデータ出力を行なう方法
Rubyで処理結果をデータとしてファイル保存したり、画面やブラウザに出力表示する方法です。CGIなどのWebプログラムでは、ヘッダーを出力後、コンテンツ部分を出力します。
# ファイル名を定数に
FILE_NAME = 'file.txt'
# 保存するデータ
lines_t = ''
lines_a = []
# ファイルに保存する 新規書込、上書き
File.open(FILE_NAME, 'w') do |f|
f.write(lines_t)
end
# ファイルに追記する 末尾に追加
File.open(FILE_NAME, 'a') do |f|
f.write(lines_t)
end
# 読み込んでから保存する ファイルロック
File.open(FILE_NAME,'r+') do |f|
# ファイルロック
f.flock File::LOCK_EX
f.each_line do |line|
# 文字列に代入
lines_t << line
# 配列に入れる場合
lines_a << line
end
# 書込位置を先頭に
f.seek(0, 0)
# 文字列を保存
f.write(lines_t)
# 配列を書き込む場合
f.write(lines_a.join(''))
# ファイルサイズを整える
f.flush
f.truncate(f.pos)
end
# 変数を文字列と一緒に出力する場合 式展開
puts "日時:#{date}"
# 標準出力に表示
# 改行しない
print "Hi\n"
# 改行する
puts 'Hi'
# オブジェクトを表示
p s
# ブラウザに出力
puts "Content-Type: text/plain\n"
puts 'Hi'
Rubyの関数、クラス、モジュールの作り方
Rubyでは、一般的なユーザー定義関数以外にも、ブロック単位での処理の受け渡しやクロージャーなどが作成できます。処理ブロックはProcでオブジェクト化が行え、callメソッドで任意のタイミングで実行させることができます。
クロージャーとは、ブロック内の変数の状態を保持している関数です。
# 関数の作り方
def add(x)
return x +1
end
p add(5) #6
# 引数の個数を限定しない 配列
def mul(*a)
return a.inject(&:*)
end
p mul(2,3,4) #24
# 引数の個数を限定しない ハッシュ v2.0以降
def usort(**h)
return Hash[ h.sort_by{|_,v| v } ]
end
p usort(a:10,b:5,c:8)
# 関数にブロックを渡す
def block
# ブロック実行
yield
end
block{ p "a" }
# 関数の引数にブロックを渡す
def block(&b)
b.call
end
block{p "a"}
# ブロックをオブジェクト化
b = Proc.new{|i| p i }
b.call(5)
# ラムダ式
h = {
add: lambda{|a,b| a + b },
sub: lambda{|a,b| a - b },
mul: lambda{|a,b| a * b },
div: lambda{|a,b| a / b.to_f },
mod: lambda{|a,b| a % b }
}
p h[:add].call(1,2)
p h[:sub].call(1,2)
p h[:mul].call(1,2)
p h[:div].call(1,2)
p h[:mod].call(1,2)
# アロー演算子
a = [
->(x){ x+x },
->(x){ x*x }
]
p a[0][5]
p a[1][5]
# クロージャー
def c
n = 0
->{ n += 1 }
end
f = c
p f.call
p f.call
Rubyでは、オブジェクト指向のクラスを簡単に作成できます。インスタンス変数にアクセスするゲッターやセッターは、attr_accessorで設定するだけで作成されます。他にattr_reader(参照のみ)、attr_writer(更新のみ)があります。クラス変数は、インスタンスで共有され、書き換えると継承元も含めて、全体で更新されます。
# クラスの作り方
class Base
# アクセサ
attr_accessor :v
# クラス変数
@@name = 'A'
# コンストラクタ
def initialize
# インスタンス変数
@v = 0
end
# クラス変数への参照
def name
return @@name
end
end
# クラスの継承
class Child < Base
def rename(n)
@@name = n
end
end
# インスタンスを作成
b = Base.new
p b.name #A
b.v = 5
p b.v #5
# インスタンスを作成
c = Child.new
p c.name #A
p c.v #0
c.rename('B')
p c.name #B
# 継承元のクラス変数も書き換わる
p b.name #B
Rubyには、クラスとは異なるモジュールオブジェクトがあります。モジュールは、インスタンス化はできませんが、メソッドを定義でき、クラスからのincludeにより多重継承を行えます。extendでクラスメソッドとしての追加も行えます。
またモジュールをライブラリとして作成しインクルードすることで、定義したメソッドを関数のように利用することも出来ます。
# モジュールの作り方
module Mod
# メソッド
def fA(x)
return x + 1
end
# モジュール関数
def fB(x)
return x + 2
end
# モジュール関数として登録
module_function :fB
# クラスメソッド
def self.fC(x)
return x + 3
end
end
class C
# インスタンスメソッドとしてインクルード
include Mod
def fD(x)
# fA(),fB()が使える
# モジュール関数
return fB(x)
end
end
# インスタンスを作成
# fA(),fD()が使える
c = C.new
p c.fA(1)
p c.fD(1)
# モジュールのメソッド
# fB(),fC()が使える
p Mod.fB(1)
p Mod.fC(1)
class D
# クラスメソッドとしてインクルード
extend Mod
def fD(x)
# fA(),fB()は使えない
return x
end
end
# クラスメソッド
# fA()が使える
p D.fA(1)
# インスタンスを作成
# fD()が使える
d = D.new
p d.fD(1)