What a hard work to make the recipe sharing service available on Ruby 1.9.3!

What a hard work to make the recipe sharing service available on Ruby 1.9.3!

This is presented in oedorubykaigi03

7cca11c5257fda526eeb4b1ada28f904?s=128

Kenta Murata

March 16, 2013
Tweet

Transcript

  1. ๭ϨγϐαΠτͷ Ruby 1.9.3 ରԠͰۤ࿑͠·ͨ͠ mrkn Kenta Murata What a hard

    work to make the recipe sharing service available on Ruby 1.9.3! 2013.03.16 #odrk03 1
  2. Kenta Murata (mrkn) DevInfra Engineer at COOKPAD Inc. Ruby committer

    http://www.flickr.com/photos/kakutani/8526732201/ 2
  3. 3

  4. Kenta Murata (mrkn) DevInfra Engineer at COOKPAD Inc. Ruby committer

    http://www.flickr.com/photos/kakutani/8526732201/ 4
  5. Kenta Murata (mrkn) DevInfra Engineer at COOKPAD Inc. Ruby committer

    http://www.flickr.com/photos/kakutani/8526732201/ BATMAN 4
  6. 5

  7. 5

  8. Run on 1.9.3-p392 since 26 Feb 2013 5

  9. Run on 1.9.3-p392 since 26 Feb 2013 We’ll move to

    2.0.0-p0 next month !!! 5
  10. REE 1.9.3 2.0.0 809 576 497 REE 1.9.3 2.0.0 1773

    1305 1166 ฏۉϨεϙϯελΠϜ [ms] 90% Line [ms] 6
  11. http://info.cookpad.com/ 7

  12. 8

  13. http://bit.ly/cookpad_jobs 8

  14. 1.9.3 ҠߦͰ ۤ࿑ͨ͠ࣄ 9

  15. Ϛδίϝ then/do ͷ୅ΘΓͷ : Πϯελϯεม਺ΛϒϩοΫύϥϝʔλʹ࢖͏ͳ Temp le ͷΦʔϓϯϞʔυ͸ ‘w+’ Hash

    ͷॱং໰୊ Array#to_s ͱ Hash#to_s (time .. time).include? time Date#step with ActiveSupport::Duration enum_with_index lambda ͷҾ਺Ϛονϯά next Ͱ͸ϝιου͔Βൈ͚ΒΕͳ͍Α ଟॏ୅ೖ Symbol#to_int ͷͪΐͬͱྑ͍࿩ ਖ਼نදݱͷඇޓ׵ੑ nkf, kconv, jcode, iconv ΦϦδφϧ String#blank? ActiveRecord ͱ nil.id ϝʔϧ 10
  16. # coding: utf-8 11

  17. ౰࣌͸ΈΜͳॻ͍ͯ͘Εͳ͔ͬͨ 12

  18. script/insert_magic_comment 13

  19. #! /usr/bin/env ruby # coding: utf-8 def has_magic_comment?(content) if content.lines.first

    =~ /\A#!/ first_line = content.lines.take(2).last else first_line = content.lines.first end comment = first_line.sub( /(?:\"(?:[^"]|\\\")*\"|\'(?:[^']|\\\')*\'|[^#]*)#/, '').strip comment =~ /\b(?:en)?coding\s*:\s*(?:utf|UTF)-?8\b/ end def insert_magic_comment(path) content = open(path, 'rb') {|io| io.read } rescue $! return if Exception === content || content.empty? content.force_encoding('BINARY') if content.respond_to?(:force_encoding) unless has_magic_comment?(content) if content =~ /[^\x00-\x7E]/m $stderr.puts "inserting magic comment to #{path}" open(path, 'wb') do |io| io.puts "# coding: utf-8" io.write content end end end end if ARGV[0] == '--pre-commit' open("|git diff --cached --name-only HEAD") do |io| while path = io.gets path.strip! next unless path =~ /\.rb$/ insert_magic_comment(path) end end else require 'find' Find.find(Dir.pwd) do |path| next unless path =~ /\.rb$/ insert_magic_comment(path) end end 14
  20. https://gist.github.com/ mrkn/5173137 http://bit.ly/cookpad_jobs 15

  21. if condition: when condition: while condition: 16

  22. items.each do |@item| 17

  23. view template ಺Ͱࢄݟ 18

  24. <%# index.html.erb %> <div class=”item-list”> <% @items.each_with_index do |@item, idx|

    -%> <div class=”item-box”> <%= render ‘item’ %> </div> <% end -%> </div> <%# _item.html.erb %> <table> <tr><td>name</td><td><%= @item.title %></td></tr> <tr><td>description</td><td><%= @item.description %></td></tr> ... </table> 19
  25. ϨϯμϦϯά͞ΕΔ·Ͱ syntax error ͕஗Ԇ͢Δ 20

  26. Ͳͷ partial view ͔ Βࢀর͞ΕͯΔ͔ௐ΂ Δͷ͕େมͳͷͰ୯७ ʹ @ ΛऔΔͱࢮ͵ 21

  27. શͯෛ࠴Ͱஔ͖׵͑ͨ 22

  28. <%# index.html.erb %> <div class=”item-list”> <% @items.each_with_index do |item, idx|

    @item = item -%> <div class=”item-box”> <%= render ‘item’ %> </div> <% end -%> </div> <%# _item.html.erb %> <table> <tr><td>name</td><td><%= @item.title %></td></tr> <tr><td>description</td><td><%= @item.description %></td></tr> ... </table> 23
  29. Tempfile ͷΦʔϓϯ Ϟʔυ͕ ‘w+’ ݻఆ໰୊ 24

  30. default_external ͸ UTF-8 25

  31. ςϯϙϥϦϑΝΠϧʹ JPEG Λॻ͖ࠐΊͳ͍ 26

  32. ͓ྉཧͷࣸਅΛอଘ Ͱ͖ͳ͍ʼʻ 27

  33. tf.set_encoding(‘BINARY’) \ ! if tf.respond_to? :set_encoding 28

  34. Hash ͷॱং໰୊ 29

  35. # ruby-1.8.7 ͷ৔߹ {:a => 1, :b => 2}.to_a #=>

    [[:b, 2], [:a, 1]] # ruby-1.9.3 ͷ৔߹ {:a => 1, :b => 2}.to_a #=> [[:a, 1], [:b, 2]] 30
  36. Hash ͷ map ʹΑΔ݁ ՌΛݕূ͢Δςετͱ͔ 31

  37. to_s ͷڍಈͷมԽ 32

  38. Array#to_s ͕ join(“”) ૬౰ͩͬͨ 33

  39. # ruby-1.8.7 ͷ৔߹ %w(a b c).to_s #=> “abc” # ruby-1.9.3

    ͷ৔߹ p %w(a b c).to_s #=> "[\"a\", \"b\", \"c\"]" 34
  40. # ruby-1.8.7 ͷ৔߹ [:foo].to_s #=> “foo” [:foo].first.to_s #=> “foo” #

    ruby-1.9.3 ͷ৔߹ [:foo].to_s #=> “[:foo]” [:foo].first.to_s #=> “foo” 35
  41. ໌࣏తʹ to_s ΛݺΜ ͰΔίʔυͳΜͯͦ Μͳʹͳ͍ 36

  42. # ruby-1.8.7 ͷ৔߹ “#{[:foo]}” #=> “foo” “#{[:foo].first}” #=> “foo” #

    ruby-1.9.3 ͷ৔߹ “#{[:foo]}” #=> “[:foo]” “#{[:foo].first}” #=> “foo” 37
  43. Hash#to_s ͕ to_a.join(“”) ૬౰ͩͬͨ 38

  44. # ruby-1.8.7 ͷ৔߹ p({:a => 1, :b => 2}.to_s) #=>

    “b2a1” # ruby-1.9.3 ͷ৔߹ p({:a => 1, :b => 2}.to_s) #=> "{:a=>1, :b=>2}" 39
  45. (time .. time).include? time 40

  46. class Range def include_with_warn?(obj) if Time === self.begin caller.tap do

    |callstack| repository_root = File.expand_path( '../../../../../../../', __FILE__) + '/' offending_line = callstack.find {|line| File.expand_path(line.split(':').first). start_with?(repository_root) } || callstack.first $stderr.puts "[WARN] can't iterate from Time since 1.9 at #{offending_line}" end end include_without_warn?(obj) end alias include_without_warn? include? alias include? include_with_warn? end 41
  47. Date#step ͕ ActiveSupport::Duration Λ ڋઈͩ͢͠ 42

  48. # Ruby 1.9.3 Ͱಈ͔ͳ͘ͳͬͨίʔυ begin_date = Date.parse(“2013/03/01”) end_date = Date.parse(“2013/06/30”)

    begin_date.step(end_date, 1.week) do |date| ... end 43
  49. require 'date' class Date def step_with_warn(*args, &block) unless Numeric ===

    args[1] || args[1].nil? $stderr.puts "\n[WARN] non-Numeric object is given for the 2nd argument of step at #{caller[0]}" $stderr.flush end step_without_warn(*args, &block) end alias step_without_warn step alias step step_with_warn end 44
  50. enum_with_index 45

  51. each_with_index 46

  52. lambda ͷҾ਺Ϛονϯά 47

  53. # ApplicationHelper ͷத def init_handler(foo) Hash.new {|h, k| h[k] =

    lambda {} }.merge(foo) end # ΞϓϦέʔγϣϯίʔυ಺ init_handler(@handlers) ... @handlers[:foo].call(model) 48
  54. wrong number of arguments (1 for 0) 49

  55. # ApplicationHelper ͷத def init_handler(foo) Hash.new {|h, k| h[k] =

    lambda {|*args| } }.merge(foo) end # ΞϓϦέʔγϣϯίʔυ಺ init_handler(@handlers) ... @handlers[:foo].call(model) 50
  56. # ApplicationHelper ͷத def init_handler(foo) Hash.new {|h, k| h[k] =

    proc {} }.merge(foo) end # ΞϓϦέʔγϣϯίʔυ಺ init_handler(@handlers) ... @handlers[:foo].call(model) 51
  57. ࢿྉ࡞ͬͯͯࢥͬͨ 52

  58. # null_proc.rb module NullProc class << self def call(*args); end

    alias [] call end end # ApplicationHelper ͷத require ‘null_proc’ def init_handler(foo) Hash.new {|h, k| h[k] = NullProc }.merge(foo) end 53
  59. next Ͱϝιου͔Β ൈ͚Εͳ͘ͳͬͨ 54

  60. class FooController def show ... next if params[:bar].blank? ... end

    end 55
  61. ࣮૷Λ Chanko ͔Β ίϯτϩʔϥຊମ΁Ҡ ಈ͢Δͱ͖ʹى͖Δ 56

  62. Chanko ͸ Rails Ξ ϓϦέʔγϣϯΛ؆ ୯ʹ֦ு͢Δ࢓૊Έ 57

  63. ֦ுػೳ͸ϒϩοΫ Ͱ࣮૷͢Δ 58

  64. Chanko ͷதͰ࣮૷͞ ΕͯΔؒ͸ɺ֦ுػೳ ͷத͔Β୤ग़͢Δͱ͖ ͸ next Λ࢖͏ 59

  65. ࣮૷Λ Chanko ͔Β ίϯτϩʔϥຊମ΁Ҡ ಈ͢Δͱ͖ʹ return ʹஔ׵͠๨ΕΔ 60

  66. ଟॏ୅ೖ 61

  67. # Ruby 1.8.7 lambda {|*a| b = *a }.call(1) #=>

    1 # Ruby 1.9.3 lambda {|*a| b = *a }.call(1) #=> [1] 62
  68. ΧϯϚΛ෇͚Ε͹ྑ͍ 63

  69. # Ruby 1.8.7 lambda {|*a| b, = *a; b }.call(1)

    #=> 1 ↑ # Ruby 1.9.3 lambda {|*a| b, = *a; b }.call(1) #=> 1 ↑ 64
  70. Symbol#to_int 65

  71. # Ruby 1.8.7 {:foo => “hello world”}[:foo][:bar] #=> nil #

    Ruby 1.9.3 {:foo => “hello world”}[:foo][:bar] #=> can't convert Symbol into Integer (TypeError) 66
  72. Ruby 1.9 Ͱ Symbol#to_int ͕ফ ͓͔͑ͨ͛Ͱόά͕ ໌Β͔ʹʂʂ̍ 67

  73. ྑ͍࿩ 68

  74. ਖ਼نදݱͷඇޓ׵ 69

  75. \s ͷҙຯ (ޙड़) 70

  76. \w ͱ \W ͱ \p{Word} 71

  77. \w ͕ US-ASCII ͷൣ ғʹมΘͬͨ 72

  78. \p{Word} ͸ 1.8 Ͱਖ਼ نදݱίϯύΠϧΤ ϥʔʹͳΔ 73

  79. \w → \p{Word} \W →ɹ ???? ɹ 74

  80. if RUBY_VERSION >= ‘1.9’ word = ‘\p{Word}’ re = /(?!#{word})./

    else re = /\W/ end 75
  81. ಠࣗͷ String#blank? 76

  82. class String def blank? self =~ /\A[\sɹ]*\z/m end end ↑

    IDEOGRAPHIC SPACE 77
  83. ໰୊͸ IDEOGRAPHIC SPACE ͷํ͡Όͳͯ͘ \s ʹ͋Δ 78

  84. # for 1.8 class String UTF8_WHITESPACE_CHAR_PATTERN = /(?:\s|\xE3\x80\x80)/.freeze UTF8_BLANK_PATTERN =

    /\A(?:#{UTF8_WHITESPACE_CHAR_PATTERN})*\z/.freeze end # for 1.9.3 class String NON_BLANK_SPACE_CHARACTERS = "\u00A0\u1680\u180E\u2000-\u200B\u202F\u205F".freeze private_constant :NON_BLANK_SPACE_CHARACTERS UTF8_WHITESPACE_CHAR_PATTERN = /(?:(?![#{NON_BLANK_SPACE_CHARACTERS}])\p{Space})/.freeze UTF8_BLANK_PATTERN = /\A(?:#{UTF8_WHITESPACE_CHAR_PATTERN})*\z/.freeze end 79
  85. จࣈΤϯίʔσΟϯάม׵ܥ 80

  86. NKF ޓ׵ϝιου 81

  87. # Ruby 1.8.7 class String def to_win31j_from_utf8 NKF.nkf(‘-W -s -m0

    -x’, self) end end # Ruby 1.9.3 class String def to_win31j_from_utf8 encode('Windows-31J', 'UTF-8', invalid: :replace, undef: :replace, replace: '') end end 82
  88. kconv ͷϝιουͰ ܯࠂΛग़͢ 83

  89. # Ruby 1.8.7 class String def tosjis_with_warn $stderr.puts “[WARN] ...

    #{caller[0]}” tosjis_without_warn end alias tosjis_without_warn tosjis alias tosjis tosjis_with_warn end # Ruby 1.9.3 class String def tosjis $stderr.puts “[WARN] ... #{caller[0]}” encode(‘Windows-31J’, invalid: :replace, undef: :replace, replace: '') end end 84
  90. ܯࠂΛग़͢Α͏ʹͯ͠ ͓͘ࣄͰɺαʔϏε ։ൃΤϯδχΞ͕ؾ ෇͍ͯमਖ਼ͯ͘͠ΕΔ 85

  91. ActiveRecord ͱ nil.id 86

  92. 1.8 Ͱ͸ nil.id ͕ 4 Λ ฦ͢ͷͰྫ֎͕ग़ͳ͍ 87

  93. if Rails.application.config.whiny_nils require 'active_support/whiny_nil' end if RUBY_VERSION < '1.9' class

    NilClass def id_with_warn(*args) return 4 unless File.expand_path(caller[0]). starts_with?(Rails.root) message = "nil.id was called at #{caller[0]}" if defined? Logger Logger.error.post('nil.id', message) else $stderr.puts message end 4 end alias id_without_warn id alias id id_with_warn end end 88
  94. ϝʔϧؔ܎ 89

  95. ଧ౗ tmail 90

  96. tmail → mail.gem 91

  97. ۤߦ 92

  98. tmail ͷόάʹґଘ ͨ͠ίʔυ͕͋ͬͨ 93

  99. ·ͩઓ͍͸ऴΘͬͯ ͳ͍ɾɾɾ 94

  100. ײ૝ 95

  101. ྑ͘ͳ͍ίʔυΛېࢭ ͢Δඇޓ׵ੑ͸େ׻ܴ 96

  102. items.each do |@item| 97

  103. ศརͩͬͨࣄ͕Ͱ͖ ͳ͘ͳΔͱ൵͍͠ 98

  104. # Ruby 1.9.3 Ͱಈ͔ͳ͘ͳͬͨίʔυ begin_date = Date.parse(“2013/03/01”) end_date = Date.parse(“2013/06/30”)

    begin_date.step(end_date, 1.week) do |date| ... end 99
  105. Ҡߦ TIPS 100

  106. Ruby ͷόʔδϣϯผ ʹϞϯΩʔύονΛ ੔ཧ 101

  107. lib/ monkey_patches/ ruby/ 1.8/ array/ object/ string/ blank.rb conversion.rb encoding.rb

    multibyte.rb 1.9/ array/ object/ string/ blank.rb conversion.rb encoding.rb multibyte.rb 2.0/ common/ 102
  108. # config/initializers/000_load_libs.rb FileUtils.chdir(‘../../../lib’, __FILE__) do # load monkey patches for

    ruby first Dir[‘monkey_patches/ruby/**/*.rb’].sort.each do |fn| version = fn.split(‘/’)[2] case when version == ‘common’ # do nothing when RUBY_VERSION < ‘1.9’ next unless version == ‘1.8’ when RUBY_VERSION < ‘2.0’ next unless version == ‘1.9’ when RUBY_VERSION < ‘2.1’ next unless (‘1.9’...‘2.1’).cover? version else next unless version >= ‘2.1’ end require fn end end 103
  109. ৽͍͠όʔδϣϯͰ ૿͑Δϝιου͸ ύονͰಋೖ͢Δ 104

  110. Object#singleton_c lass 105

  111. # for 1.8 class Object def singleton_class class << self

    self end end end 106
  112. String#bytesize 107

  113. # for 1.8 class String alias bytesize size end 108

  114. String#b 109

  115. # for 1.8 class String def b self end end

    # for 1.9 class String def b dup.force_encoding(‘ASCII-8BIT’) end end 110
  116. String#force_enco ding 111

  117. # for 1.8 class String def force_encoding(enc) self end end

    112
  118. ࣮͸͜ΕͰ͸ବ໨ 113

  119. respond_to? (:force_encoding) Ͱ 1.9 ͔Ͳ͏͔൑அͯ͠ΔϥΠϒ ϥϦ͕͍͔ͭ͘ଘࡏ͢Δ 114

  120. # for 1.8 class String def method_missing_with_force_encoding(name, *args, &block) if

    name == :force_encoding self else method_missing_without_force_encoding( name, *args, &block) end end alias method_missing_without_force_encoding method_missing alias method_missing method_missing_with_force_encoding end 115
  121. ΤϯίʔσΟϯάม ׵ 116

  122. from ͱ to ͷΤϯ ίʔσΟϯάΛݶఆ ͢Δͱಋೖ͠΍͍͢ 117

  123. ͨͬͨ͜Ε͚ͩͰΞϓ Ϧέʔγϣϯίʔυ͔ Β RUBY_VERSION Λ ݮΒͤΔ 118

  124. ͓·͚ 119

  125. irb(main):005:0> keys = (:a .. :d).to_a => [:a, :b, :c,

    :d] irb(main):006:0> values = (1 .. 4).to_a => [1, 2, 3, 4] irb(main):007:0> Hash[keys.zip(values)] => {:a=>1, :b=>2, :c=>3, :d=>4} 120
  126. Time.now Λ্ॻ͖͢Δ ͷ͸ࢭΊΑ͏ ʼʻ 121

  127. ·ͱΊ 122

  128. REE 1.9.3 2.0.0 809 576 497 REE 1.9.3 2.0.0 1773

    1305 1166 ฏۉϨεϙϯελΠϜ [ms] 90% Line [ms] Use Ruby 2.0.0 !!! 123
  129. 124

  130. 125

  131. http://bit.ly/cookpad_jobs 125