class A
def a
"a"
end
end
A.new.a # => "a"
class A
def a
"b"
end
end
A.new.a # => "b"
Slide 10
Slide 10 text
class A
def a
"a"
end
end
A.new.a # => "a"
# 一度定義したクラスをもう一度定義しなおすと
class A
def a
"b"
end
end
A.new.a # => "b" メソッドの動きが変更されている
Slide 11
Slide 11 text
class A
def a
"a"
end
end
A.new.a # => "a"
class A
def b # 新しいメソッドを定義することもできる
"b"
end
end
A.new.b # => "b"
Slide 12
Slide 12 text
Α͏͢ΔʹΫϥεΛ
Կఆٛ͠ͳ͓ͤΔ
Slide 13
Slide 13 text
ා͘Ͷʁ
Slide 14
Slide 14 text
ͱࢥͬͨํਖ਼ৗͰ͢ʂ
Slide 15
Slide 15 text
ཚ༻ةݥͰ͢
Slide 16
Slide 16 text
͡Ό͋
ͲΜͳͱ͖ʹ͏ͷʁ
Slide 17
Slide 17 text
(FNΛগ͚͍ͩͨ͠͠
Slide 18
Slide 18 text
࣮ྫ
Slide 19
Slide 19 text
ʮ$BSSJFS8BWF%JSFDUΛͬ
͍ͯΔͱอଘ͢ΔͨͼʹT
ͷΩʔ໊͕͘ͳ͍ͬͯ͘ʯ
Slide 20
Slide 20 text
Ͳ͏͍͏͜ͱʁ
Slide 21
Slide 21 text
QBUIUPpMF
อଘQBUIUPUPpMF
อଘQBUIUPUPUPpMF
Slide 22
Slide 22 text
QBUIUPpMF
QBUIUPUPpMF
QBUIUPUPUPpMF
50͕૿͑ͯΔʂʂ
Slide 23
Slide 23 text
module CarrierWaveDirect
module Uploader
def filename
# ~~~~ 省略
key_path = key.split("/")
filename_parts = []
filename_parts.unshift(key_path.pop)
unique_key = key_path.pop
filename_parts.unshift(unique_key) if unique_key
filename_parts.join("/")
end
end
end
Slide 24
Slide 24 text
module CarrierWaveDirect
module Uploader
def filename
# ~~~~ 省略
key_path = key.split("/")
filename_parts = []
filename_parts.unshift(key_path.pop)
unique_key = key_path.pop
filename_parts.unshift(unique_key) if unique_key
filename_parts.join("/")
end
end
end
ŇP0ʢpMFOBNFͱ͍͏ϝιουͳͷʹ
TͷLFZؚ͕·ΕͯΔͱεϥογϡͰ۠ͬͨ
࠷ޙͷཁૉͱɺ͏ҰͭΛ࣍ͷཁૉΛ
ϑΝΠϧ໊ͱͯ͠ฦͯ͠Δ
Slide 25
Slide 25 text
1VMM3FRVFTUνϟϯε
Ͱ໌·Ͱʹɻɻɻ
Slide 26
Slide 26 text
࠷࠷ۙͷߋ৽Ͱ̓ϲ݄લɾɾɾ
Slide 27
Slide 27 text
Δ͔͠ͳ͍ʂ
Slide 28
Slide 28 text
module CarrierWaveDirect
module Uploader
def filename
# ~~~~ 省略
key_path = key.split("/")
filename_parts = []
filename_parts.unshift(key_path.pop)
unique_key = key_path.pop
# filename_parts.unshift(unique_key) if unique_key
filename_parts.join("/")
end
end
end
app/config/initializers/fix_carrier_wave_direct.rb
ڧҾʹpMFOBNFͷΈΛฦ͢Α͏ʹͨ͠
Slide 29
Slide 29 text
ࠐΈϥΠϒϥϦʹ
ϝιουΛ͍ͨ͠
Slide 30
Slide 30 text
class NilClass
# +nil+ is blank:
#
# nil.blank? # => true
#
# @return [true]
def blank?
true
end
end
˞3BJMTͷ"DUJWF4VQQPSU͔ΒҾ༻
Slide 31
Slide 31 text
class NilClass
# +nil+ is blank:
#
# nil.blank? # => true
#
# @return [true]
def blank?
true
end
end
˞3BJMTͷ"DUJWF4VQQPSU͔ΒҾ༻
/JM$MBTT OJMΦϒδΣΫτͷΫϥε
ʹϝιο
υΛ͢͜ͱʹͨͱ͑OJMʹରͯ͠CMBOL ϝ
ιουݺͿ͜ͱΛՄೳʹ͍ͯ͠Δ
Slide 32
Slide 32 text
Կ͕خ͍͠ͷʁ
Slide 33
Slide 33 text
var = ?? # nilの可能性がある変数でも
var.blank? # blankが呼べるので
# 例えばparamsから取り出した値でも安心して呼べる
if params[:attr].blank?
# ""(空文字) か nil の場合にここが実行される
end
# nilを拡張できない場合はNoMethodErrorを防ぐ為に
# nilかどうかのチェックをする必要がある
if !params[:attr] || params[:attr].blank?
# ""(空文字) か nil の場合にここが実行される
end
Slide 34
Slide 34 text
ͱɺศརͳ
ϞϯΩʔύονͰ͕͢
Slide 35
Slide 35 text
ѻ͍ํΛؒҧ͑Δͱ
ةݥͰ͢
Slide 36
Slide 36 text
# app/models/some_model.rb
class SomeModel < ApplicationRecord
end
class String
def inspect
"test"
end
end
ϓϩδΣΫτͷதʹΦʔϓϯΫϥε͍ͯ͠Δ
ίʔυ͕ࠞͬͯ͡Δͱશମʹద༻͞Εͯ͠·͏
Slide 37
Slide 37 text
class SomeModel < ApplicationRecord
end
class String
def inspect
"test"
end
end
ϓϩδΣΫτͷதʹ
ΦʔϓϯΫϥεΛ͍ͯ͠Δ
ίʔυ͕ࠞͬͯ͡Δͱશମ
ʹద༻͞Εͯ͠·͏
app/models/some_model.rb
class SomeController < ApplicationController
def index
"param_#{params[:page]}" #=> param_test
end
end
app/controller/some_controller.rb
Slide 38
Slide 38 text
JOJUJBMJ[FSTʹԼʹஔ͘ͷ
ϧʔϧΛܾΊͯΓ·͠ΐ͏
Slide 39
Slide 39 text
3FpOFNFOU
Slide 40
Slide 40 text
ϞϯΩʔύονͷద༻
ൣғΛ੍ݶͰ͖Δ
Slide 41
Slide 41 text
class A
def a
"a"
end
end
module B
refine A do
def a
"b"
end
end
end
A.new.a # => "a"
using B
A.new.a # => "b"
Slide 42
Slide 42 text
class A
def a
"a"
end
end
module B
refine A do # refineの後にモンキーパッチしたいクラス
def a # => 渡したブロックでクラス定義ができる
"b"
end
end
end
A.new.a # => "a"
using B # usingキーワードでモジュールを指定すると
# それ以降モンキーパッチが適用される
A.new.a # => "b"
Slide 43
Slide 43 text
3FpOFNFOUͷ
είʔϓ
Slide 44
Slide 44 text
# file scope
class A
def b
# ~~~
end
end
using M
# Usingより下の行は全て対象
class B
# classの中でも対象
def b
# methodの中でも対象
end
end
# クラス定義終わっても対象
Slide 45
Slide 45 text
# file scope
class A
def b
# ~~~
end
end
using M
# Usingより下の行は全て対象
class B
# classの中でも対象
def b
# methodの中でも対象
end
end
# クラス定義終わっても対象
Slide 46
Slide 46 text
# class scope
class A
def b
end
using M
# Usingより下行は対象
def b
# methodの中でも対象
end
end
# クラスのスコープから外れると対象外
class B
def b
end
end
Slide 47
Slide 47 text
# class scope
class A
def b
end
using M
# Usingより下行は対象
def b
# methodの中でも対象
end
end
# クラスのスコープから外れると対象外
class B
def b
end
end
Slide 48
Slide 48 text
ͪΐͬͱบ͕͋ͬͯ
ϝιουͷதϒϩοΫͰ
͔ͭ͑·ͤΜ
Slide 49
Slide 49 text
class A
def a
"a"
end
end
module M
refine A do
def a
"b"
end
end
end
class B
def b
using M # NoMethodError
A.new.a
end
end
module SkipValidation
refine ApplicationRecord do
def valid?
true
end
end
end
class SomeController
def save
# バリデーションが行われる
# ...
end
using SkipValidation
def force_save
# バリデーションがスキップされる
# ...
end
end
Slide 53
Slide 53 text
module SkipValidation
refine ApplicationRecord do
def valid?
true
end
end
end
class SomeController
def save
# バリデーションが行われる
# ...
end
using SkipValidation
def force_save
# バリデーションがスキップされる
# ...
end
end
3FpOFNFOU͢Δ͜ͱʹΑͬͯ
ͲͷΑ͏ͳϞϯΩʔύον͕ͳ͞ΕͯΔ
͔ͷώϯτʹͳͬͯൣғݶఆͰ͖Δͷ
͕ϝϦοτʁ
Slide 54
Slide 54 text
Ͳ͏ඍົͰௐͯΈΔͱ
ͱͱ%4-Λ࡞Δͱ͖ʹ͏
Α͏ʹઃܭ͞Ε͍ͯͨΈ͍ͨͰ͢
Slide 55
Slide 55 text
͜Μͳײ͡ʁ
Slide 56
Slide 56 text
module StringOperator
refine String do
def |(other)
SQL.or(self, other)
end
def &(other)
SQL.and(self, other)
end
end
end
class DSL
using StringOperator
def self.where(&block)
# 現状blockの中にまでusingは適用できない
instance_eval(&block)
end
end
# より抽象度の高い記述が簡単なコードで実現できる
DSL.where { "a" | "b" & "c" }
"a" | "b" # NoMethodError
Slide 57
Slide 57 text
ΘΕͯͳ͍ͷ͔ͳͱ
ࢥͬͨΒ
Slide 58
Slide 58 text
3BJMTͰ໘ന͍
ΘΕํΛൃݟ͠·ͨ͠
Slide 59
Slide 59 text
# Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
#
# We tried shimming it to attempt the fast native method, rescue TypeError,
# and fall back to the compatible implementation, but that's much slower than
# just calling the compat method in the first place.
if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
# Using Refinements here in order not to expose our internal method
using Module.new {
refine Array do
alias :orig_sum :sum
end
}
class Array
def sum(init = nil, &block) #:nodoc:
if init.is_a?(Numeric) || first.is_a?(Numeric)
init ||= 0
orig_sum(init, &block)
else
super
end
end
end
end
[1,2,3].sum # => 6
["a","b","c"].sum # => TypeError: String can't be coerced into
Integer
3VCZͰ"SSBZʹTVNϝιου͕ͨ͞Εͯ
/BUJWF࣮ͳͷͰͦͪΒͷ΄͏͕ૣ͍
Ͱ/VNFSJD͕ཁૉͷͱ͖͔͑͠ͳ͍ͷͰ
ཁૉ͕/VNFSJDͷ࣌/BUJWFͷTVNΛ͔ͭͬͯ
ͦΕҎ֎ͷ࣌3BJMT͕֦ுͨ͠TVNϝιουΛ͏
Slide 63
Slide 63 text
if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
# Arrayのインスタンスメソッドにsumがあって文字列の要素のときにエラーになるとい
うことは Ruby 2.4〜
using Module.new {
refine Array do
alias :orig_sum :sum # Ruby 2.4のsumメソッドにorig_sumとaliasをつける
end
}
class Array
def sum(init = nil, &block) #:nodoc:
if init.is_a?(Numeric) || first.is_a?(Numeric)
# 要素がNumericの時は Ruby 2.4 のsumを呼び出す
init ||= 0
orig_sum(init, &block)
else
# それ以外の時は Rails のsumを呼び出す
super
end
end
end
end
Slide 64
Slide 64 text
if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
using Module.new { # このModuleはローカル変数なので、このブロックでのみしか存
在しない
refine Array do
alias :orig_sum :sum # orig_sumはここよりファイルの末尾のみしかアクセスで
きない
end
}
class Array
def sum(init = nil, &block) #:nodoc:
if init.is_a?(Numeric) || first.is_a?(Numeric)
init ||= 0
orig_sum(init, &block)
else
super
end
end
end
end
Slide 65
Slide 65 text
if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
using Module.new {
refine Array do
alias :orig_sum :sum
end
}
class Array
def sum(init = nil, &block) #:nodoc:
if init.is_a?(Numeric) || first.is_a?(Numeric)
init ||= 0
orig_sum(init, &block)
else
super
end
end
end
end
Slide 66
Slide 66 text
class SomeModel < ApplicationRecord
def some
"aa".orig_sum #=> NoMethodError
end
end
BJBTΛߦͬͨ.PEVMFΛVTJOH͢Δ͜ͱͰ͖ͳ͍ͷͰ
4USJOHPSJH@TVNʹΞΫηε͢Δ͜ͱແཧʹͳΔͷͰ
PSJH@TVNNFUIPEᘳʹӅṭ͞ΕΔ
Slide 67
Slide 67 text
ࠓͬͨ͜ͱ
w ΦʔϓϯΫϥεʹΑΔ(FNͷॻ͖͑
w 3BJMTͰͷΦʔϓϯΫϥεΛͬͨࣄྫ
w 3FpOFNFOUͷհ