それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

ruby の暗黙的文字列変換 toString 的なものをするには

ruby って to_s が自動的に呼ばれない。

たとえば、Hashと文字列を結合しようとした時

h = { name:'takuya' }

str = 'this obj is  ' + h

puts str

Hash を String にする方法がないからエラー

takuya@~/Desktop$ ruby  test.rb
test.rb:5:in `+': no implicit conversion of Hash into String (TypeError)
        from test.rb:5:in `<main>'

他の言語では?

Java とかだと、toString 定義しておけば読んでくれるじゃん?

class Man {
     public String toString(){  return " I'm man "; }
}

public class Main{
    public static void main(String[] args){
      Man m = new Man();
      String s = "Hello "+ m;
      System.out.println(  s );
    }
}

こういう、暗黙的な型変換を呼び出すにはどうするのか

to_s ではなく to_str を使う

to_str を使うと、目的を達成することが出来る。

よく見るとエラーメッセージもno implicit conversion(暗黙的変換がない)と言ってる

to_str を追加する

h = { name:'takuya' }

def h.to_str
  self.to_s
end

str = 'this obj is  ' + h

puts str

実行結果

takuya@~/Desktop$ ruby  test.rb
this obj is  {:name=>"takuya"}

何でこんなことになってるのか。

コーディングにおける意図しない変換を防ぐためだと。

たとえば、数字だって、暗黙的変換がないので、明示的に to_s する必要がある。

'this is ' +  1 +  ' th place  my family  traveled' ## ダメ
'this is ' +  1.to_s +  ' th place  my family traveled'  ## おっけ

そういえば、明示的にto_s つけるか、#{number}で埋め込んでたわ。

Javaって暗黙型変換が便利なようで実は不便だからな。Rubyはこういう変なところで厳格な言語だよね。

ちなみに、覚えておくべき英語は次の通り。

  • explicit 明示的
  • implicit 暗黙的

参考資料

http://qiita.com/tbpgr/items/19b42765a7b9cb292f44

ruby のURI.parse が日本語GET引数や日本語UTF-8のパスに対応しなくなった

対応しなくなったんですよ。マジで。

日本語を含むとエラー

>> URI.parse 'http://example.com/あああ'
URI::InvalidURIError: URI must be ascii only "http://example.com/\u{3042}\u{3042}\u{3042}"
from /Users/takuya/.rbenv/versions/2.2.3/lib/ruby/2.2.0/uri/rfc3986_parser.rb:20:in `split'
>>

ruby まじどうしようもないな。

日本語を含むURIはASCIIにEncodeしろってことだろうけどさ、ブラウザからURIをコピペしたら日本語含まれるじゃん?

日本語が含まれたまま使えないと不便だよね。

モンキーパッチで対応する

require 'uri'


module URI
  class << self
    alias :_parse :parse

    def parse a, original=false
      return self._parse a if original

      r=/[一-龠]+|[ぁ-ん]+|[ァ-ヴー]+|[a-zA-Z0-9]+/
      a = a.gsub(r){|m|  URI.encode_www_form_component(m) }

      u = self._parse a
      return u
    end
  end
end

とりあえず対応することが出来る。大抵のURIはコレで対応できそう。

npm のモジュール地獄見てて、gem の同じような地獄に成りつつあるし。イチイチ依存Gem増やす必要はないかもしれない。

関連資料

ruby で URL をパースしてGET引数をHashに展開する。(日本語URI対応) - それマグで!

rubyの置換でコールバックを使う。

JavaScript の String#replace はコールバックが使えて便利。

置換でコールバックの関数使えると便利なんですよね。

> a.replace(/a/, function(e){ console.log(e); return ''})
a
'bc'
>

js のこの仕様が結構過ぎで多用しまくっててクセになってた

ruby でもブロック渡せることを知った。

'abc'.gsub(/a/){ 'abc' } #=> "abcbc"

ブロック渡せるの便利だよね。大雑把な正規表現でも細かい部分を微調節できるし。正規表現をアレコレいじくり回して直感的じゃなくなったり、複雑になりすぎた正規表現を調整できる。

match でもブロック使える

>> 'abc'.match(/(.)/){|e|  p e ; nil   }
#<MatchData "a" 1:"a">
=> nil

正規表現が複雑になり過ぎないように、ブロックを使うのも悪くないよね。

参考資料

gsub, gsub! (String) - Rubyリファレンス