Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

Kenta Murata

March 16, 2013
Tweet

More Decks by Kenta Murata

Other Decks in Technology

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. 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
  9. 8

  10. Ϛδίϝ 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
  11. #! /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
  12. <%# 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
  13. <%# 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
  14. # 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
  15. # 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
  16. # 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
  17. # ruby-1.8.7 ͷ৔߹ “#{[:foo]}” #=> “foo” “#{[:foo].first}” #=> “foo” #

    ruby-1.9.3 ͷ৔߹ “#{[:foo]}” #=> “[:foo]” “#{[:foo].first}” #=> “foo” 37
  18. # 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
  19. 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
  20. 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
  21. # ApplicationHelper ͷத def init_handler(foo) Hash.new {|h, k| h[k] =

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

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

    proc {} }.merge(foo) end # ΞϓϦέʔγϣϯίʔυ಺ init_handler(@handlers) ... @handlers[:foo].call(model) 51
  24. # 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
  25. # Ruby 1.8.7 lambda {|*a| b = *a }.call(1) #=>

    1 # Ruby 1.9.3 lambda {|*a| b = *a }.call(1) #=> [1] 62
  26. # 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
  27. # 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
  28. # 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
  29. # 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
  30. # 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
  31. 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
  32. 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
  33. # 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
  34. # 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
  35. # 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
  36. 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
  37. 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
  38. 124

  39. 125