メモ:プロを目指す人のためのRuby入門
はじめに
『プロを目指す人のためのRuby入門』を進める中で、用語や気になった記法をメモする。
第2章 Railsの基礎を理解する
・rubyでは全てがオブジェクト
・メソッドの呼び出し
オブジェクト.メソッド(引数1,引数2,引数3)
カッコはなくてもOK
オブジェクト.メソッド 引数1,引数2,引数3
引数がない場合もある
オブジェクト.メソッド
・改行が文の区切り。セミコロン(;)による区切りも可能だが使う頻度は少ない
・カッコのなかで改行しても、文の区切りとはならない
10.to_s( 16 ) #=>"a"
・識別子 = 変数やクラスやメソッドにつける名前のこと
・予約語 = 識別子として使用できない単語
・空白文字 = 識別子や予約語を区切るために使われる
半角スペースやタブなど。
いくつ連続しても、違いはない。
演算子は前後に空白文字がなくても正常に動作する。
(入れたほうが見やすい)
(5 + 12)* 3 def add (a,b) a+ b end add( 4, 5 )
・リテラル = ソースコードに埋め込む値のこと
(数値、文字列、配列、ハッシュ、正規表現など)
・変数(ローカル変数)
宣言と代入は同時に行う。
s = 'Hello'
変数を宣言するだけの構文はない。
#変数を宣言する目的で変数名だけ書くと、エラーになる x #=>NameError:undefinedlocalvariableormethod`x'formain:Object
・変数はアフファベットの小文字とスネークケースで書くのが慣習
・文字列
シングルクオートかダブルクオートを使う。
ダブルクオートは式展開や改行が使える。
・文字列の比較は==と!=を使う
'ruby'=='ruby' #=>true 'ruby'=='Ruby' #=>false 'ruby'!='perl' #=>true 'ruby'!='ruby' #=>false
〜数値〜
・3, 4.2, -3. -3.8など使ってOK
・変数の前に-をつけると正負を反転できる
-n = 2 #=> -2
・整数同士の割算の答えは整数になる(小数点以下切り捨て)
(小数点以下が必要な時は5.0など小数点以下も記載する)
・整数が入っている変数にはn.to_fで小数に変更できる
・割算の余りを求めるには%を使う
・演算子は色々あり、優先順位が定められている
・小数点の値の計算には注意
コンピュータは10進数を2進数に変換して計算するため、丸め誤差が生じる。
これにより想定と異なる比較結果が出てくることがある。
〜真偽値と条件分岐〜
・ルールは以下
falseかnilであれば偽。
それ以外は全て真。
・論理演算子
&& = かつ
|| = または
ここでも注意すべきは演算子の優先順位。
&&は||よりも優先順位が高い。
優先順位を変えたければ()を使う。
・!演算子 = 真偽値を反転させる
t1 = true !t1 #=> false
・if文
if 条件A 条件Aが真の場合だった時の処理 elsif 条件B 条件Bが真の場合だった時の処理 else それ以外の場合の処理 end
・メソッド
def メソッド名(引数1, 引数2) 必要な処理 end
・メソッド名のルールは変数名と同じ
・メソッドの戻り値 Rubyでは最後に評価された式がメソッドの戻り値になる
・returnを使うとメソッドを途中で脱出できる
defgreeting(country) #countryがnilならメッセージを返してメソッドを抜ける #(nil?はオブジェクトがnilの場合にtrueを返すメソッド) return 'countryを入力してください' if country.nil? if country == 'japan' 'こんにちは' else 'hello' end end greeting(nil) #=>"countryを入力してください" greeting('japan') #=>"こんにちは"
・引数のない場合はdef メソッド()の()は省略可能
〜文字列〜
・文字列はStringクラスのオブジェクト
・%記法を使うとシングルクオート/ダブルクオートがそのまま使える
#%q! !はシングルクオートで囲んだことと同じになる puts %q!He said, "Don'tspeak."! #=>He said, "Don't speak." #%Q! !はダブルクオートで囲んだことと同じになる(改行文字や式展開が使える) something="Hello." puts %Q!He said, "#{something}"! #=>He said, "Hello." #%! !もダブルクオートで囲んだことと同じになる something="Bye." puts %!He said, "#{something}"! #=>He said,"Bye."
・ヒアドキュメント
複数行に渡る長い文章を書く時はヒアドキュメントを使うと便利。
a = <<TEXT ここに文章を書きます。 改行もしっかりできます。 TEXT
なお、TEXTを識別子として使ったが、文章の中に含まれていない文字列ならなんでも良い。
・<<-TEXTを使うと最後のTEXTをインデントさせられる
・ヒアドキュメントの中では式展開が有効
・Stringクラスに用意されている様々なメソッドを使って、文字列の表示方法をコントロールできる
〜数値 アゲイン〜
・ビット演算・指数表現・integer・float・有理数・複素数など、どの種類の数値を扱うのかを意識する必要がある
〜真偽値と条件分岐 アゲイン〜
・Rubyでは論理式を評価する場合、式全体が真または偽出ることを決定するまで順番に評価していく。
真偽が決定すると、評価を終了して、最後に評価した式の値を返す。
・&&とand、||とor。それぞれ使いどころがある
・unless文は条件が偽の時だけ処理を実行する
unless分にはelsifのようなものはないが、elseは使える。
・case分
複数の条件を指定する場合にelseifよりも見やすくかける
case 対象のオブジェクトや式 when 値1 値1に一致する場合の処理 when 値2 値2に一致する場合の処理 when 値3 値3に一致する場合の処理 else どれにも一致しない場合の処理 end
式 ? 真だった時の処理 : 偽だった時の処理
〜メソッド アゲイン〜
・メソッドの引数にはデフォルト値をつけれる
def greeting(coutry = '日本')
こうすることで引数なしでメソッドを使ってもエラーにならない。
・デフォルト値あり、なしの引数の混在も可能
・?で終わるメソッド = 真偽値を返す
・!で終わるメソッド = 使用する際には注意
・破壊的メソッド = 呼び出したオブジェクトの状態を変更してしまうメソッド
〜その他の基礎知識〜
・ガベージコレクション
使用されなくなったオブジェクトを自動的に回収し、メモリを解放する。
(これによりプログラマはメモリ管理を意識する必要なし)
・エイリアスメソッド
全く同じ処理をするが、名前が違うメソッド
・式(Expression)と文(statment)
式 = 値を返す
文 = 値を返さない
・擬似変数
true, false, nil, self, FILE, など。
擬似変数は文法上、変数のように見えるが代入するとエラーが発生する。
・参照
Rubyの変数にはオブジェクトそのものではなく、オブジェクトへの参照が格納されている
・組み込みライブラリ、標準ライブラリ、gem
・requireで標準ライブラリやgemを読み込む
(自分で作成したRubyプログラムも)
・loadは何回でもプログラムを読み込める
・require_relativeを使えばファイルのある場所がパス参照の起点になる
・puts = 改行あり
・print = 改行なし
これらは配列の表示の仕方も違う
第3章 テストを自動化する
・クラス名とファイル名は合わせる
クラス名 = キャメルケース
class JapaneseCalenderTest < Minitest::Test ~~~ end
ファイル名 = スネークケース
japanese_calender_test.rb
・Minitestはtest_で始まるメソッドを探して実行する
def test_sample end
・クラス内では複数のtestメソッドを作成して良い
Minitestはクラス内の全てのtestで始まるメソッドを実行する
・Minitestが提供しているメソッドを使ってテストする
assert_equal 期待する結果, テスト対象となる値や式
・この本で使うテストメソッドは以下の3つ
#aとbの値は等しければバスする assert_equal b, a #aが真であればパスする assert a #aが偽であればパスする refute b
配列や繰り返し処理を理解する
・配列内のデータは順番に並んでいて添字を指定することでデータを取り出せる
・配列は[]を使って作成する
[要素1, 要素2, 要素3]
・配列はArrayクラスのオブジェクト
・変数に代入する書き方
a = [1, 2, 3] a[0] #=> 1 a[1] #=> 2 a[2] #=> 3 b = [ 4, 5, 6 ]
・配列には数値以外でもどんなオブジェクトでも格納できる
・素材しない添字を指定したらnilが返る
・要素の変更
配列[添字] = 新しい値
・元の大きさよりも大きい添字を指定すると、間の値はnilで埋まる
・配列の最後に要素を追加する
a = [] a << 1 a << 2 a << 3 a #=> [1, 2, 3]
・配列の中の特定の要素を削除するdelete_atメソッド
a = [1, 2, 3] a.delete_at(1) a #=> [1, 3]
・配列を使った多重代入ができる
a, b = [1, 2] a #=> 1 b #=> 2
・ブロックはメソッドの引数として渡せる処理のかたまり
・繰り返し処理
・他の言語ではforで実行する繰り返し処理をRubyではeachを使って行う
・each = 配列の要素を最初から最後まで順番に取り出す
・eachで要素を取り出して、その要素をどう扱うかをブロックに記述する
numbers = [1, 2, 3, 4] sum = 0 numbers.each do |n| sum += n end
・|n|はブロック引数
配列から取り出された要素が順番に格納される
・ブロックの中で初めて定義した変数は、ブロックの中だけでしか呼び出せない
・ブロックの外で定義したローカル変数は、ブロックの中でも呼び出せる
・ブロックはdo..endと{}の何でも書くことができる
numbers.each { |n| sum += n }
・mapメソッド(collectメソッド)
配列使うメソッド。
各要素の対してブロックを評価した結果を新しい配列にして返す。
numbers = [1, 2, 3, 4] new_numbers = numbers.map { |n| n * 10 } print new_numbers #=> [10, 20, 30, 40]
・selectメソッド(find_allメソッド)
各要素に対してブロックを評価し、その戻り値が真の要素を集めた配列を返すメソッド。
numbers = [1, 2, 3, 4, 5, 6] even_numbers = numbers.select { |n| n.even? } print even_numbers #=> [2, 4, 6]
・rejectメソッドはselectメソッドの反対
・findメソッド(detectメソッド)
ブロックの戻り値が真になった最初の要素を取り出す
numbers = [1, 2, 3, 4, 5, 6] even_numbers = numbers.select { |n| n.even? } print even_numbers #=> 2
・injectメソッド(reduceメソッド) たたみ込み演算を行うメソッド
numbers = ['Mon', 'Tue', 'Wed', 'Thu'] sum = numbers.inject('Sun') { |result, n | result + n} print sum #=> SunMonTueWedThu
・範囲(Range)オブジェクト
最初の値..最後の値(最後の値を含む) 最初の値...最後の値(最後の値を含まない)
・範囲オブジェクトの使いどころ
#配列の一部を取り出す a = [1 ,2, 3, 4] a[1..2] #=> [2, 3] #2文字目から4文字目を取り出す a = 'abcdef' a[2..4] #=> cde
このように「X以上、Y以下(未満)」といった時に使うと便利
・文字列の配列の場合[]ではなく%wや%Wを使える
(各要素をシングルクオートやダブルクオートで挟まなくてよくなる)
%w!apple melon orange! #=> ["apple", "melon", "orange"] %w(apple melon orange) #=> ["apple", "melon", "orange"]
・配列、ブロック、繰り返し処理には様々なメソッドが用意されていて、値の操作の仕方や書き方が多様に存在している
ハッシュやシンボル
・ハッシュはキーと値の組み合わせでデータを管理するオブジェクト
#空のハッシュを作る {} #キーと値の組み合わせを3つ格納するハッシュ { キー1 => 値1, キー2 => 値2, キー3 => 値3}
・ハッシュの{}とブロックの{}は同じ書き方
・後から新しいキーと値を追加する
#ハッシュ[キー] = 値 currencies = {'japan' => 'yen', 'us' => 'doller'} currencies['italy'] = 'euro' #すでに存在しているキーの場合は上書きされる currencies #=> {"japan"=>"yen", "us"=>"doller", "italy"=>"euro"}
・ハッシュからキーを取り出す
#ハッシュ[キー] currencies = {'japan' => 'yen', 'us' => 'doller'} currencies['japan']
・ハッシュを使った繰り返し処理
eachメソッドを使うとキーと値の組み合わせを順に取得できる
currencies = {'japan' => 'yen', 'us' => 'doller'} currencies.each { |key, value| puts "#{key} : #{value}" } #=> japan : yen us : doller
・引数を1つだけにするとキーと要素が配列に格納される
・ハッシュの同値比較
全てのキーと値が同じであれば並び順に関わらずtrueが返る。
・ハッシュの要素数の取得 = sizeメソッド、lengthメソッド
・ハッシュの要素の削除 = deleteメソッド
・ハッシュリテラルの注意点
→ハッシュリテラルがメソッドの第一引数になる場合は、引数の()を省略できない
→これは、ハッシュの{}がブロックの{}だと認識されてエラーが出るから
→第二引数以降であれば、()なしでハッシュを使える
〜シンボル〜
・:シンボル、'文字列'
・シンボルは何個作ってもオブジェクトIDは同じ
=>メモリ効率が良い
・シンボルはイミュータブルなので、破壊的な変更はできない
・ハッシュのキーではシンボルが好んで使われる
=> 文字列よりも高速に値を取り出せる
・シンボルを使ったハッシュの書き方
currencies = {:japan => 'yen', :us => 'doller'} currencies = {japan: 'yen', us: 'doller'} #どちらの書き方でもOK
・キーも値もシンボルの場合
currencies = {:japan => :yen, :us => :doller} currencies = {japan: :yen, us: :doller}
・ハッシュのキーは文字列、シンボルの混在OK
=>非推奨
・ハッシュの値は文字列、シンボルがよく混在される
・メソッドのキーワード引数
def buy_burger(menu, drink: true, potate: true)
=>キーワード引数は省略可能で順番前後のOK
=>キーワード引数のデフォルト値を省略することも可能
・キーワード引数を使うメソッドを呼び出す場合、キーワード引数に一致するハッシュを引数として渡せる
params{drink: true, potate: true) def buy_burger('fish', params)
・キーワード引数の値をメソッドの中で呼び出すときは、シンボルを記述するのではなく変数のように記述するだけ
def convert_length(length, from:, to: ) units = {m: 1.0, ft: 3.28, in: 39.37} (length/units[from]*units[to]).round(2) end
〜ハッシュアゲイン〜
・ハッシュでよく使うメソッド
keysメソッド = ハッシュのキーを配列として返す
n = {japan: 'yen', us: 'doller'} n.keys #=> [:japan, :us]
valuesメソッド = ハッシュの値を配列として返す
n = {japan: 'yen', us: 'doller'} n.values #=> ["yen", "doller"]
has_keys?メソッド = ハッシュの中に指定したキーがあるか確認する
n = {japan: 'yen', us: 'doller'} n.has_key?(:japan) #=>true #keys?, inclueds?, members?は全てhas_keys?のエイリアスメソッド
・**を使うとハッシュ内で他のハッシュのキーと値を式展開
h = {india: 'rupee'} n = {japan: 'yen', us: 'doller', **h} #=> {:japan=>"yen", :us=>"doller", :india=>"rupee"} # ハッシュのmergeメソッドでも同じことができる
〜コラム:よく使うイディオム〜
・&.演算子を使ってメソッドを呼び出すとオブジェクトがnilだった場合にエラーではなくnilを返す
・||=を使うと変数がfalseかnilの時にリテラルを代入する
limit ||= 10
・!!を使うとtrue/falseを簡単に返せる
!!1 #=> true !!false #=> false !!nil #=> false limit = 10 !!limit => true
正規表現
・正規表現と文字列を比較する場合は=~をよく使う
真の場合、0が返る。
偽の場合、nilが返る。
なお、0が返るのは文字列中の正規表現がマッチした文字列の位置が返るから。
・比較に!~を使うとマッチすればtrue、マッチしなければfalse
・正規表現のキャプチャを使うとマッチした文字列を連番で抜き出せるようになる
正規表現は、後に回すことにする。理解が苦しいのと、必要に迫られていない
クラスの作成を定義する
・クラスは内部にデータを保持し、自分が保持するデータを利用する独自のメソッドを持つことができます
(データをメソッドを一緒に持ち運べる)
・オブジェクト = インスタンス = レシーバ →クラスをもとに作られたデータのかたまり
・メソッド = メッセージ
→オブジェクトが持つ動作・振る舞い・処理のこと
・オブジェクトの状態 = オブジェクトの各データ
・オブジェクトから取得したり、設定したりできる値のことを属性・アトリビュート・プロパティと呼ぶ
alice = User.new(Alice, Jackson, 30) alice.first_name #<= 取得してる alice.first_name = "アリス" #<= 設定してる #first_nameの部分はattr_accessorで定義される = 値 #使い方はメソッドと似ているが、別物
・クラス名は必ず大文字で始める
class User end class OrderItem end
・クラスからオブジェクトを作成する = newメソッド
user = User.new
・newメソッドを使った時、initializeメソッドが呼び出される
→必要であればクラス内で定義しておく
class User def initialize puts 'initialized' end end User.new #=> initialized
・initializeメソッドは特殊で、外部から呼び出せない
(デフォルトでprivateメソッド)
・initializeメソッドに引数をつけると、newメソッドを呼ぶ時にも引数が必須になる
class User def initialize(name, age) puts "name :#{name}, age: #{age}" end end user = User.new #=> wrong number of arguments (given 0, expected 2) (ArgumentError)
・インスタンスメソッド = クラスの内部で定義されたメソッド →そのクラスのインスタンスに対して呼び出すことができる
・クラスの内部ではインスタンス変数を定義できる
→インスタンス変数は@で始める
→インスタンス変数は同じインスタンスの内部で共有される
class User def initialize(name) #インスタンス作成時に渡された名前をインスタンス変数に保存する @name = name end def hello puts "Hello, #{@name}." end end user = User.new('Alice') puts user.hello #=> Hello, Alice.
・メソッドやブロックの中で作成される変数 = ローカル変数
→ローカル変数はメソッドやブロックの内部でのみ有効
→メソッドやブロックが呼び出されるたびに毎回作り直される
・ローカル変数は参照する前に必ず値を代入しないとエラーになる
・インスタンス変数は値が代入されずに参照されてもエラーにならず、nilが返る
class User def initialize(name) #インスタンス作成時に渡された名前をインスタンス変数に保存する #@name = name end def hello puts "Hello, #{@name}." end end user = User.new('Alice') user.hello #@name部分が空で帰ってくる #=>Hello, .
つまり、インスタンス変数をタイプミスするとエラーにもならず不具合につながる
class User def initialize(name) #インスタンス作成時に渡された名前をインスタンス変数に保存する @name = name end def hello puts "Hello, #{@mame}." end end user = User.new('Alice') user.hello #@mameになってもうてるやん! #=>Hello, .
・インスタンス変数は、通常は外部から参照できない →参照する必要がある場合は、参照用のメソッドを作る
class User def initialize(name) @name = name end #@nameを外部から参照するためのメソッド def name @name end end user = User.new('Alice') puts user.name
・インスタンス変数の値を外部から変更する場合も変更用のメソッドを定義する
class User def initialize(name) @name = name end def name @name end #@nameを外部から変更するためのメソッド def name=(value) @name = value end end
・アクセサメソッド = インスタンス変数を読み書きするメソッド
(他の言語では「ゲッターメソッド」や「セッターメソッド」)
・attr_accessorを使えばアクセサメソッドの定義を省略できる
(外部から読み書きさせるよ〜、のおまじない的な)
class User attr_accessor :name def initialize(name) @name = name end end user = User.new('Alice') user.name ='bob' puts user.name
・attr_reader = 読み込み専用
→参照はできるが、変更はできない
・attr_writer = 書き込み専用
→変更はできるが、参照はできない
・シンボルをカンマで区切ると複数のインスタンス変数へのアクセサメソッドを作成できる
class User attr_accessor :name, :age def initialize(name, age) @name = name @age = age end end
・インスタンスメソッド
→インスタンスに含まれるデータの読み書きのために使う
・クラスメソッド
→そのクラスと関係は深いがが、一つ一つのインスタンスのデータはつかはない場合
→書き方は以下の二つ
class クラス名 def self.クラスメソッド 処理 end end
もしくは
class クラス名 class << self def クラスメソッド 処理 end end end
→クラスメソッドをたくさん定義する場合は、後者の方が便利
・String#to_i = Stringクラスのto_iというインスタンスメソッド
・File.exist? == File::exist? == Fileクラスのexist?というクラスメソッド
・クラスの中では定数を定義することができる
class User DEFAULT_PRICE = 0 attr_accessor :name, :price def initialize(name, price = DEFAULT_PRICE) @name = name @price = price end end user = User.new('Nintendo Switch') puts user.name puts user.price #=> Nintendo Switch => 0
・Rubyはクラス名も定数の一つ
・同じクラス内のメソッドを呼び出す方法
name self.name
→これらはいずれも同じ
→ただし、セッターメソッドを呼び出す場合は、selfをつけないとローカル変数への代入だと解釈されてしまう
・クラスメソッドの中ではインスタンスメソッドを呼び出せない
・インスタンスメソッドの中ではselfを使ってクラスメソッドは呼び出せない
→(クラス名.クラスメソッド名とちゃんと書かないといけない)
〜継承〜 / ・サブクラスのメソッド内でsuperを使うとスーパークラスの同名のメソッドを呼び出せる
・サブクラスで同名のメソッドを定義しなおすと、スーパークラスのメソッドをオーバーライドできる
・サブクラスではスーパークラスのインスタンス変数も共有される
→サブクラスで同名のインスタンス変数を定義するとオーバライドされてしまい、ややこしくなる
〜メソッドの公開レベル〜
・3つの公開レベルpublic/ protexted/ private
・publicメソッドはクラスの外部からでも自由に呼び出せる
→initializeメソッド以外のインスタンスメソッドはデフォルトでpublic
・privateメソッドはクラスの外から呼び出せず、クラスの内部だけで呼び出せる
→クラス内でprivateを定義すると、その下はprivateメソッドに
→クラスの内部であっても、self.メソッド名では呼び出せない
(privateメソッドは厳密にはレシーバを指定してメソッドを呼び出せないというルール)
・Rubyではそのクラスだけでなく、サブクラスからでもprivateメソッドを呼び出せる
・クラスメソッドはprivateの下に書いてもprivateメソッドにならない
・クラスメソッドをprivateにする書き方は以下
class User class << self private #ここに処理を書けばprivateなクラスメソッド end end
もしくは
private_class_method :クラスメソッド名
で定義する
・protectedメソッドは、そのクラスとサブクラスの中でだけレシーバ付きで呼び出せるメソッド
〜定数 アゲイン〜
・定数はクラスの外部からでも呼び出せる
クラス名::定数名
・定数はメソッドの内部では定義できない
→必ずクラス構文の直下で定義
・定数は後から再代入することは可能
(警告エラーはでる)
class User FIRST_NAME = 'Yamada' def say_hello puts self.hello end end User::FIRST_NAME = "Sato" #warning: already initialized constant User::FIRST_NAME #=> Sato
・クラスを凍結すれば定数の再代入を禁止できる
class User FIRST_NAME = 'Yamada' def say_hello puts self.hello end User.freeze end User::FIRST_NAME = "Sato" #`<class:User>': can't modify frozen class (FrozenError)
モジュール
・モジュールの作り方
module モジュール名 #メソッドや定数 end
例えば
module Greeter def hello 'hello' end end
・モジュールからインスタンスを作成することはできない
・モジュールは、他のモジュールやクラスを継承することはで機内
・クラスの継承が使えない場合に、モジュールのincludeを使えば共通のメソッドを再利用できるようになる
→ミックスインと呼ぶ
module Loggable def log(text) puts "[LOG] #{text}" end end class Product include Loggable def title log 'title is called' 'A great movie' end end
・1つのクラスに複数のモジュールをミックスインすることも可能
・モジュールの中でprivateメソッドにしておけば、ミックスインしたクラスの中でもprivateメソッドになる
・extendを使うと、そのモジュールの中のメソッドをそのクラスの特異メソッド(クラスメソッド)にすることができる
module Loggable def log(text) puts "[LOG] #{text}" end end class Product extend Loggable def self.create_products(names) #logメソッドをクラスメソッド内で呼び出す #つまり、logメソッドもクラスメソッドとなる log 'create_products is called' end end
・UFO演算子 <=>
・名前空間によりクラス名の重複を回避する
→モジュールの中にクラスを定義することで、「そのモジュールに属するクラス」という定義ができる
→これはモジュールをクラス名の衝突を避けるための名前空間として利用している
→モジュールに属するクラスを参照する方法は以下
モジュール名::クラス名 Baseball::Second.new(’Alice', 13)
・大規模なブログラムになるとクラス名の重複が普通に起こるので、名前空間を作ってクラスを作成するのが普通
・ネストなしで名前空間付きのクラスを定義できる
module Baseball end class Baseball::Second end
・モジュールに定義したメソッドをそのまま呼び出すこともできる →モジュール内で特異メソッドを作っておく
module Loggable def self.log(text) "[LOG] #{text}" end end Loggable.log('test') #=> "[LOG] test"
・モジュールはインスタンスを作れないので、単なるメソッドの集まりを作りたいときにモジュールの特異メソッドを作る
(newする必要が全くないとき)
・モジュールでも以下の書き方OK
module Loggable class << self def log(text) "[LOG] #{text}" end #他の特異メソッド end end
・モジュール関数 = ミックスインとしても、特異メソッドとしてもどちらでも使えるメソッド
→module_functionメソッドで定義する
→ミックスインした場合は自動的にprivateメソッドになる
例外処理
・Rubyでは例外も例外クラスのインスタンス(例外オブジェクト)
Traceback (most recent call last): 2: from /Users/naoki/.rbenv/versions/2.5.0/bin/irb:11:in `<main>' 1: from (irb):14 NoMethodError (undefined method `new' for Loggable:Module)
→NoMethodErrorは発生した例外のクラス名
・何もしなければ例外が発生した時点でプログラムが終了して、それ以下の処理は実行されない
・例外が発生しても、処理を続けさせることもできる
begin #例外が起こりうる処理 rescue #例外が発生した場合の処理 end
・例外が捕捉されない場合、プログラムは以上終了する
def method_1 puts 'method_1 start' begin method_2 rescue puts '例外が発生しました' end puts 'method_1 end' end def method_2 puts 'method_2 start' method_3 puts 'method_2 end' end def method_3 puts 'method_3 start' 1/0 puts 'method_3 end' end method_1
→この場合、method2の中のmethod3でエラーが発生し、method3/method2の順番で処理が終了し、method1で例外が捕捉される
・例外オブジェクトのメソッドを使って、例外に関する情報を取得することができる
begin 1/0 rescue => e puts "エラークラス:#{e.class}" puts "エラーメッセージ:#{e.message}" puts "バックトレース____" puts e.backtrace puts "-----" end #=> エラークラス:ZeroDivisionError エラーメッセージ:divided by 0 バックトレース____ ./lib/practice.rb:2:in `/' ./lib/practice.rb:2:in `<main>' -----
→変数eに例外オブジェクトを格納してメソッドを呼び出す
・捕捉するクラスを指定することができる
・例外クラスもスーパークラス・サブクラスの継承関係にある
・rescueの中でretryを使用すれば処理をやり直すことができる
→ カウンタをつけてリトライ回数も指定できる
・raiseを使って意図的に例外を発生させられる
def currency_of(country) case country when :japan 'yen' when :us 'dollar' when :india 'rupee' else raise "無効な国名です。#{country}" end end
→デフォルトではRunTimeErrorクラスの例外
→その他の例外クラスを指定することも可能
→例外クラスのインスタンスを渡すことも可能
〜例外処理のベストプラクティス〜
・安易にrescueを使わない
→例外はあくまで例外であって、一度処理を止めるのが普通
(RailsのようなWebフレームワークでは例外処理を実装してくれてる)
・rescueするなら必ず情報を残す
→例外クラス/メッセージ/バックトレースは最低でも
・例外処理を書く場合は対象範囲と対象クラスをできるだけ絞る
→処理を続行させることを予測している例外だけを対象に
→その他で例外が出たら処理を止めるべき
・例外処理よりも条件分岐を使って想定するエラーを処理する
・ifやcaseなどで予期しない条件が来たら例外を発生させて処理を止めるべき
例外処理の例題ともっと詳しくはスキップ。現時点で必要性が低い
yieldとProcを理解する
・メソッド内でyieldを使うとブロックで渡された処理を実行できる
・yieldを記載してブロックが渡されていなかったらエラー
→block_given?メソッドでブロックの有無を確認
・yieldはブロックに引数を渡すことも可能
・Procクラスはブロックをオブジェクト化するためのクラス
→Procクラスはブロック = 何らかの処理を表すクラス
・Procクラスのインスタンスを作る
hello_proc = Proc.new do 処理 end
・callメソッドでProcオブジェクトを実行する
hello_proc.call
yeildとprocもほどほどに。使い所がイメージできないので入ってこない
Rubyのデバッグ手法を身に着ける
デバッグも、イメージできないのでスキップ
Railsに関して
・定数の自動読み込み機能
→コード中に不明なクラスがあれば、特定のパスから条件に合いそうなクラスを自動的に読み込んでくれる
・Rubyの標準ライブラリやgemをインストールしたライブラリも自動で読みこむ
・名前空間としてのモジュールを自動で作成してくれる
# app/models/foo/bar.rb class Foo:Bar < ApplicationRecord #クラス定義 end
→Railsはfooというディレクトリの下にbar.rbがることから、「Fooは名前空間として使われている」と判断する
・Railsはrubyの標準クラスに対して数多くの独自拡張をしている
以上
Rails5 : Kaminariでpaginateを実装する
前提
MacOS 10.14.5
Ruby 2.5.0
Rails 5.2.3
手順
1. gem kaminariをインストール
Gemfileにkaminariを追加。
gem 'kaminari'
インストール。
$ bundle install
2. controllerを編集
paginateさせたいアクションのインスタンス変数を編集。 以下の感じ。
PER = 5 def index @payments = current_user.payments.page(params[:page]).per(PER) end
3. viewを編集。
以下のように上記アクションを編集したviewにpaginateの行を追記する。
<% @payments.each do |payment| %> <tr> <td><%= payment.created_at.strftime('%Y/%m/%d') %></td> <td><%= payment.item %></td> <td><%= payment.price %></td> <td><%= payment.category %></td> <td><%= link_to '編集', edit_payment_path(payment) %></td> <td><%= link_to '削除', payment, method: :delete, data: { confirm: "本当に削除しますか?"} %></td> </tr> <% end %> <%= paginate @payments %>
以上
Rails5でデータの削除機能を実装する
前提
MacOS 10.14.5
Ruby 2.5.0
Rails 5.2.3
- 編集機能はPaymentモデルに実装する
- Deviseをインストール済み
手順
1. paymentsコントローラに追記
def destroy @payment = current_user.payments.find(params[:id]) @payment.destroy redirect_to payments_path, notice: "支払い「#{@payment.item}」を削除しました。" end
2. 一覧ページに削除ボタンの追加
<table> <tr> <th><%= Payment.human_attribute_name(:created_at) %></th> <th><%= Payment.human_attribute_name(:item) %></th> <th><%= Payment.human_attribute_name(:price) %></th> <th><%= Payment.human_attribute_name(:category) %></th> </tr> <% @payments.each do |payment| %> <tr> <td><%= payment.created_at.strftime('%Y/%m/%d') %></td> <td><%= payment.item %></td> <td><%= payment.price %></td> <td><%= payment.category %></td> <td><%= link_to '編集', edit_payment_path(payment) %></td> <td><%= link_to '削除', payment, method: :delete, data { confirm: "本当に削除しますか?"} %></td> </tr> <% end %> </table>
3. routesに追記
resources :payments, only: [:index, :new, :create, :edit, :update, :destroy]
Rails5でデータの編集機能を実装する
前提
MacOS 10.14.5
Ruby 2.5.0
Rails 5.2.3
- 編集機能はPaymentモデルに実装する
- Deviseをインストール済み
手順
1. paymentsコントローラに追記
def edit @payment = current_user.payments.find(params[:id]) end def update @payment = current_user.payments.find(params[:id]) if current_user.update(payment_params) redirect_to payments_path, notice: "支払い「#{@payment.item}」を更新しました。" else render :edit end end
2. 編集のためのViewを作成
- app/views/paymentにedit.html.erbを作成する
内容は以下
<%= form_with model: @payment, local: true do |form| %> <%= form.label :item, 'アイテム' %> <%= form.text_field :item %> <%= form.label :price, '支払い' %> <%= form.text_field :price %> <%= form.label :category, '分類' %> <%= form.text_field :category %> <%= form.submit %> <% end %>
3. routesを編集
resources :payments, only: [:index, :new, :create, :edit, :update]
4. 一覧ページに編集ボタンを追加
<table> <tr> <th><%= Payment.human_attribute_name(:created_at) %></th> <th><%= Payment.human_attribute_name(:item) %></th> <th><%= Payment.human_attribute_name(:price) %></th> <th><%= Payment.human_attribute_name(:category) %></th> </tr> <% @payments.each do |payment| %> <tr> <td><%= payment.created_at.strftime('%Y/%m/%d') %></td> <td><%= payment.item %></td> <td><%= payment.price %></td> <td><%= payment.category %></td> <td><%= link_to '編集', edit_payment_path(payment) %></td> </tr> <% end %> </table>
以上
Rails5でDeviseをデフォルト設定でインストールする。
環境
MacOS 10.14.5
Ruby 2.5.0
Rails 5.2.3
手順
1. Gemファイルの編集・bundle install
Gemファイルに以下の行を追記。
gem 'devise'
DeviseのGemをインストール。
$ bundle install
2. Deviseをインストール
$ rails g devise:install
3. 各種設定の調整
Deviseから各種設定を調整しておくように促されるので、1~4まで実施する。 Deviseからのメッセージは以下。
=============================================================================== Some setup you must do manually if you haven't yet: 1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb: config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } In production, :host should be set to the actual host of your application. 2. Ensure you have defined root_url to *something* in your config/routes.rb. For example: root to: "home#index" 3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example: <p class="notice"><%= notice %></p> <p class="alert"><%= alert %></p> 4. You can copy Devise views (for customization) to your app by running: rails g devise:views ===============================================================================
(1) まずはconfig/environments/development.rbに以下を追記。
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
(2) rootを追記するように言われるが、ここは無視。後でまとめてルーティングを修正する。
(3) Deviseではflashメッセージを使用しているので、app/views/layouts/application.html.erb.にflashを表示するよう追記する。
<body> <p class="notice"><%= notice %></p> #追記する行 <p class="alert"><%= alert %></p> #追記する行 <%= yield %> </body>
(4) Deviseで作成されたページを編集できるようにViewをインストールする。
$ rails g devise:views
これでapp/views配下にapp/views/deviseディレクトリが作成され、各種erbファイルが含まれている。 各種ファイルが担うページは以下の通り。
app/views/devise/shared/_links.html.erb (リンク用パーシャル) app/views/devise/confirmations/new.html.erb (認証メールの再送信画面) app/views/devise/passwords/edit.html.erb (パスワード変更画面) app/views/devise/passwords/new.html.erb (パスワードを忘れた際、メールを送る画面) app/views/devise/registrations/edit.html.erb (ユーザー情報変更画面) app/views/devise/registrations/new.html.erb (ユーザー登録画面) app/views/devise/sessions/new.html.erb (ログイン画面) app/views/devise/unlocks/new.html.erb (ロック解除メール再送信画面) app/views/devise/mailer/confirmation_instructions.html.erb (メール用アカウント認証文) app/views/devise/mailer/password_change.html.erb (メール用パスワード変更完了文) app/views/devise/mailer/reset_password_instructions.html.erb (メール用パスワードリセット文) app/views/devise/mailer/unlock_instructions.html.erb (メール用ロック解除文)
4. Userモデルを作成
以下を実行。
rails g devise User
今回はデフォルトの設定のままmigrationを行う。
rails db:migrate
なお、デフォルトのmigrationファイルは以下の通り。
class DeviseCreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable t.datetime :remember_created_at ## Trackable # t.integer :sign_in_count, default: 0, null: false # t.datetime :current_sign_in_at # t.datetime :last_sign_in_at # t.inet :current_sign_in_ip # t.inet :last_sign_in_ip ## Confirmable # t.string :confirmation_token # t.datetime :confirmed_at # t.datetime :confirmation_sent_at # t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true # add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end
5. usersコントローラファイルの作成
カスタムしたルーティングを使用するために、usersコントローラの各種ファイルを作成する。
$ rails g devise:controllers users
6. ルーティングを編集
Deviseをインストールした段階でデフォルトのルーティングは定義されている。 ユーザに分かりやすいパスに変更するために、config/routes.rbを以下に修正する。 なお、rootはログインページを指定。
Rails.application.routes.draw do devise_for :users, :controllers => { :registrations => 'users/registrations', :sessions => 'users/sessions' } devise_scope :user do root :to => "devise/sessions#new" get "user/:id", :to => "users/registrations#detail" get "signup", :to => "users/registrations#new" get "login", :to => "users/sessions#new" get "logout", :to => "users/sessions#destroy" get "forgot", :to => "users/passwords#new" end # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end
7. ログイン強制と、ログイン後・ログアウト後のリダイレクト先の指定
app/users/application_controller.erbを以下の通り修正する。
class ApplicationController < ActionController::Base before_action :authenticate_user! def after_sign_in_path_for(resource) ログイン後_path # ログイン後に遷移するpathを設定 end def after_sign_out_path_for(resource) new_user_session_path # ログアウト後に遷移するpathを設定 end end
とりあえず、以上な感じ。 オプション機能の利用方法など、学習する必要あり。
railsでDBをPostgreSQLに指定して新しいプロジェクトを作成する
環境
Mac OS X 10.14.5
ruby 2.5.0
Rails 5.2.3
PostgreSQL 11.3
*PostgreSQLはインストール済み。インストール方法はこちら。
手順
terminalでプロジェクトフォルダを作成したいディレクトリに移動する
まずは、ターミナルでルートに移動する
$ cd ~/
Railsの新規プロジェクトを作成したいディレクトリに移動する。 (今回は/testディレクトリ配下に作成する。testディレクトリは作成済み)
$ cd test
新規プロジェクトを作成する
samplea_appというプロジェクトを新規に作成する。DBはPostgresqlを指定する。
$ rails new sample_app -d postgresql
新規プロジェクト用のDBを作成する
作成したsample_appディレクトリに移動する。
$ cd sample_app
sample_app用のDBを作成する。
$ rails db:create
DBはconfig/database.ymlの設定に基づいて作成される。
以上
Bitbucketで2人で開発するときの運用ルール
運用ルール
- ローカルリポジトリでは、必ずブランチを切って作業する
(ローカルリポジトリでmasterは絶対に編集しない) - ブランチで編集した内容をmasterにmergeするときは、リモートリポジトリでmergeする
(プルリクエスト -> マージ) - リモートリポジトリでmerge完了後は、ローカルリポジトリのmasterでgit pullを行う
やり方
・ブランチをきる
git checkout -b ブランチ名
・編集する
・コミットする
git add . git commit -m "コミットメッセージ"
・masterに戻って、ローカルリポジトリのmasterを最新に
git checkout master git pull
・先のブランチにまた戻って、mergeを行う
git checkout ブランチ名 git merge master
(注意1)masterでpullしてAlready updatedの場合は、この作業は不要 (注意2)mergeを実施してconflictが発生したら解消する
・ブランチリモートリポジトリにプッシュ
git push --set-upstream origin ブランチ名
・プルリクとマージはBitbucketのブラウザで実施
・masterに戻って、最新にしておくと良し
git checkout master git pull
これで完了。 次の編集作業を、またブランチを切って行う。