Slide 1

Slide 1 text

3VCZ ϞϯΩʔύονͷੈք ୈճ3VCZؔ੢ษڧձ

Slide 2

Slide 2 text

୭ʁ ΫϥεϝιουϞόΠϧόοΫΤϯυॴଐ େࡕࣄ຿ॴͰ།ҰͷϞόΠϧΞϓϦαʔϏε෦ 3BJMTͱ͔/PEFͱ͔࢖ͬͯ"1*࡞ͬͯ·͢

Slide 3

Slide 3 text

ϞϯΩʔύονͱ͸ʁ

Slide 4

Slide 4 text

ϞϯΩʔύον͸ɺΦϦδφϧͷιʔείʔυΛ มߋ͢Δ࣮ߦ࣌ʹಈతݴޠ ྫ͑͹4NBMMUBML +BWB4DSJQU 0CKFDUJWF$ 3VCZ 1FSM 1ZUIPO (SPPWZ ͳͲ ͷίʔυΛ֦ுͨ͠Γɺมߋͨ͠ Γ͢Δํ๏Ͱ͋Δɻ ˞8JLJQFEJBΑΓ

Slide 5

Slide 5 text

3VCZͰ͸ϝλϓϩάϥϛϯά ͱ͍͏ख๏Ͱ ϞϯΩʔύονΛߦ͍·͢

Slide 6

Slide 6 text

ࠓճ͸ͦͷதͰ΋ൺֱత؆୯ͳ ΦʔϓϯΫϥεΛ͔ͭͬͨ ϞϯΩʔύονͷ΍ΓํΛ঺հ͠·͢ ˞ ༨ஊͰ͕͢ϞϯΩʔύονΦʔϓϯΫϥεͱ
 צҧ͍ͯ͠·ͨ͠΍ͬͺΓͦ͏͔΋

Slide 7

Slide 7 text

΍Γํ͸؆୯

Slide 8

Slide 8 text

ಉ͡ΫϥεΛ΋͏Ұ౓ ఆٛ͠ͳ͓͚ͩ͢

Slide 9

Slide 9 text

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

Slide 50

Slide 50 text

ࢀߟ IUUQTEPDTSVCZMBOHPSHFOUSVOLTZOUBY SFpOFNFOUT@SEPDIUNMMBCFM4DPQF

Slide 51

Slide 51 text

ͲΜͳͱ͖ʹ ࢖͑Δ͔ͳʁ

Slide 52

Slide 52 text

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

Slide 60

Slide 60 text

Կͯ͠Δ͔ͱ͍͏ͱɹ

Slide 61

Slide 61 text

require "active_support/core_ext/enumerable" [1,2,3].sum # => 6 ["a","b","c"].sum # => "abc" { a: 1, b: 2 }.sum # => [:a, 1, :b, 2] 3BJMT͕&OVNFSBCMF "SSBZʹ΋.JY*O͞Ε͍ͯΔ ʹ଍͍ͯ͠ΔTVNͱ͍͏ϝιου͕͋ͬͯ ্هͷΑ͏ͳಈ͖Λ͠·͢

Slide 62

Slide 62 text

[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ͷ঺հ

Slide 68

Slide 68 text

༰ྔ༻๏Λ·΋ͬͯ ద੾ͳϞϯΩʔϥΠϑΛ ૹΔ͖͔͚ͬͱͳΕ͹޾͍Ͱ͢

Slide 69

Slide 69 text

େࡕࣄ຿ॴͰҰॹʹಇ͍ͯ͘ΕΔਓΛืूͯ͠·͢ʂ 8F"SF)JSJOH