ソースコードで学ぶWebプログラミング

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!('&','&amp;') s.gsub!('<','&lt;') s.gsub!('>','&gt;') s.gsub!('"','&quot;') s.gsub!("'",'&#39;') # 改行コードの統一 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)