Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

gsub with ActiveSupport::SafeBuffer

2,554 views

Published on

Railsのhelperでnamed captureを使ったgsubを使ったらハマった話

Published in: Technology
  • Be the first to comment

gsub with ActiveSupport::SafeBuffer

  1. 1. Railsのhelperでnamed capture使ったらハマった話 chezou kawasaki.rb #010
  2. 2. 正規表現とnamed capture • 正規表現のグループに名前をつけて、後方参 照できる pat = /(?<good>good|nice|greate) catch/! #=> /(?<good>good|nice|greate) catch/! pat === 'nice catch!!'! #=> true! Regexp.last_match! #=> #<MatchData "nice catch" good:"nice">! Regexp.last_match[:good]! #=> "nice"!
  3. 3. helperでnamed capture • Railsのhelperでnamed capture使ったgsubした ら… module FooHelper! def replace_awesome(str)! str.gsub(pat){|m| "#{m}!!!" if Regexp.last_match[:good]}! end! end! ! - str = 'nice catch'! = replace_awesome(str) #=> "nice catch!!!"! # こういうのがやりたい!
  4. 4. 現実 = replace_awesome(str)! NoMethodError: undefined method `[]' for nil:NilClass ( д) ゚ ゚
  5. 5. なぜだろう? => ActiveSupport::SafeBuffer module FooHelper! def replace_awesome(str)! p(str.class) ! str.gsub(pat){|m| "#{m}!!!" if Regexp.last_match[:good]}! end! end!
  6. 6. AS::SafeBufferとは • RailsのviewではHTMLの特殊文字(<,>,&,")を自 動的にエスケープしてくれる • その時に出力されるクラスがAS::SafeBuffer "".html_safe + "<" #=> "&lt;"! ("".html_safe + "<").class #=> ActiveSupport::SafeBuffer! http://guides.rubyonrails.org/active_support_core_extensions.html#extensions-to-string
  7. 7. SafeBufferのgsubを見た rails/activesupport/lib/active_support/core_ext/string/output_safety.rb module ActiveSupport!   class SafeBuffer < String!     UNSAFE_STRING_METHODS = %w(! capitalize chomp chop delete downcase gsub lstrip next reverse rstrip! slice squeeze strip sub succ swapcase tr tr_s upcase prepend! )! …!     UNSAFE_STRING_METHODS.each do |unsafe_method|!       if unsafe_method.respond_to?(unsafe_method)!         class_eval <<-EOT, __FILE__, __LINE__ + 1! def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)! to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)! end # end! ! def #{unsafe_method}!(*args) # def capitalize!(*args)! @html_safe = false # @html_safe = false! super # super! end # end! EOT!       end!     end!
  8. 8. Rubyのみの再現コード def test(*args, &block)! 'hogehoge'.gsub(/h/, &block)! p Regexp.last_match! end!  ! test do |matched|! p Regexp.last_match! end!
  9. 9. Rubyのみの再現コード def test(*args, &block)! 'hogehoge'.gsub(/h/, &block)! p Regexp.last_match #=> <MatchData "h">! end!  ! test do |matched|! p Regexp.last_match #=> nil! end!
  10. 10. 仕様です
  11. 11. Rubyのみの再現コード def test(*args, &block)! 'hogehoge'.gsub(/h/, &block)! p Regexp.last_match #=> <MatchData "h">! end!  ! test do |matched|! p Regexp.last_match #=> nil! end! block内のscopeと違うので取れません
  12. 12. 回避方法 module FooHelper! def replace_awesome(str)! str.to_str.gsub(pat){|m| "#{m}!!!" if $~[:good]}! end! end!  ! - str = 'nice catch'! = replace_awesome(str) #=> "nice catch!!!"!

×