gsub with ActiveSupport::SafeBuffer
-
Upload
- -
Category
Technology
-
view
1.265 -
download
0
description
Transcript of gsub with ActiveSupport::SafeBuffer
Railsのhelperでnamed capture使ったらハマった話
chezou kawasaki.rb #010
正規表現と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"!
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!!!"!# こういうのがやりたい!
現実
= replace_awesome(str)!NoMethodError: undefined method `[]' for nil:NilClass
( д) ゚ ゚
なぜだろう?
=> ActiveSupport::SafeBuffer
module FooHelper! def replace_awesome(str)! p(str.class) ! str.gsub(pat){|m| "#{m}!!!" if Regexp.last_match[:good]}! end!end!
AS::SafeBufferとは• RailsのviewではHTMLの特殊文字(<,>,&,")を自動的にエスケープしてくれる
• その時に出力されるクラスがAS::SafeBuffer
"".html_safe + "<" #=> "<"!("".html_safe + "<").class #=> ActiveSupport::SafeBuffer!
http://guides.rubyonrails.org/active_support_core_extensions.html#extensions-to-string
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!
Rubyのみの再現コードdef test(*args, &block)! 'hogehoge'.gsub(/h/, &block)! p Regexp.last_match!end! !test do |matched|! p Regexp.last_match!end!
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!
仕様です
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と違うので取れません
回避方法
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!!!"!