Rubyメモ2
[mfham@localhost work]$ ruby -v ruby 2.1.8p440 (2015-12-16 revision 53160) [x86_64-linux] [mfham@localhost work]$ irb 2.1.8 :009 > sprintf('%05d', '10101') => "10101" 2.1.8 :010 > sprintf('%05d', '02101') => "01089" 2.1.8 :011 > sprintf('%05d', '08101') ArgumentError: invalid value for Integer(): "08101" from (irb):11:in `sprintf' from (irb):11 from /home/mfham/.rvm/rubies/ruby-2.1.8/bin/irb:11:in `<main>' 2.1.8 :017 > sprintf('%02d%03d', '10','101') => "10101" 2.1.8 :018 > sprintf('%02d%03d', '02','101') => "02101" 2.1.8 :019 > sprintf('%02d%03d', '08','101') ArgumentError: invalid value for Integer(): "08" from (irb):19:in `sprintf' from (irb):19 from /home/mfham/.rvm/rubies/ruby-2.1.8/bin/irb:11:in `<main>' # Kernel.#Integer 2.1.8 :028 > Integer('10') => 10 2.1.8 :029 > Integer('02') => 2 2.1.8 :030 > Integer('08') ArgumentError: invalid value for Integer(): "08" from (irb):30:in `Integer' from (irb):30 from /home/mfham/.rvm/rubies/ruby-2.1.8/bin/irb:11:in `<main>' # String#to_i 2.1.8 :021 > '10'.to_i(8) => 8 2.1.8 :022 > '02'.to_i(8) => 2 2.1.8 :023 > '08'.to_i(8) => 0 2.1.8 :040 > '10'.to_i(0) => 10 2.1.8 :041 > '02'.to_i(0) => 2 2.1.8 :042 > '08'.to_i(0) => 0
メモ
Rubyドキュメント
※実行は2.1.8なのにドキュメントは2.3.0見てるっていうのは許してください。
d
i
引数の数値を10進表現の整数として出力します。
引数が整数でなければ関数 Kernel.#Integer と同じ規則で整数に 変換されます。
module function Kernel.#Integer (Ruby 2.3.0)
引数が数値の場合は直接変換し(小数点以下切り落とし)、 文字列の場合は、進数を表す接頭辞を含む整数表現とみなせる文字列のみ 変換します。
なるほど、sprintfでd(i)を指定したら、Kernel.#Integerと同様の動きをするのか。
String#to_iを使ってみたけど、これとは挙動が違うみたい。なぜ?
気になるなーるね
調べる。
Kernel.#IntegerとString#to_iのソース。
module Kernel - Documentation for Ruby 2.3.0
class String - Documentation for Ruby 2.3.0
Kernel.#Integer
最終的にこれを返す。
rb_convert_to_integer(arg, base);
Integer('08')ならrb_convert_to_integer('08', 0)かな?
rb_convert_to_integerをもう少し追ってみると、
https://github.com/ruby/ruby/blob/4915ce691d147a460e14531f4031d6934c5e8c5c/object.c#L2701
第一引数のタイプがT_STRINGならrb_str_to_inum(val, base, TRUE)をreturnしている。
String#to_i
最終的にこれを返す。
rb_str_to_inum(str, base, FALSE);
'08.to_i(8)ならrb_str_to_inum('08', 8, FALSE)かな?
'08.to_i(0)ならrb_str_to_inum('08', 0, FALSE)かな?
違い
rb_str_to_inumの第三引数がTRUEとFALSEで違うみたい。
ちなみにsprintfはこれかな?
https://github.com/ruby/ruby/blob/00fcd967d9900713fa7f617d9a5077ec178e073f/sprintf.c#L842
rb_str_to_inum(val, 0, TRUE)
(base=0だから、プリフィクスから基数を判断するのかな)
rb_str_to_inumは何するの?
https://github.com/ruby/ruby/blob/772fd010b6a76887d9be9389f60cc024bd34f83b/bignum.c#L4207
rb_cstr_parse_inumの結果を受けて、NIL_P(ret)が真なら第三引数(TRUE, FALSEのやつ)をチェックして、TRUEならエラー(https://github.com/ruby/ruby/blob/772fd010b6a76887d9be9389f60cc024bd34f83b/bignum.c#L3706)、FALSEなら0(macro INT2FIX (Ruby 2.3.0))を返している。
rb_cstr_parse_inumを追うのは今はやめておこう・・・
https://github.com/ruby/ruby/blob/772fd010b6a76887d9be9389f60cc024bd34f83b/bignum.c#L4018
まとめ
Kernel.#Integer、Kernel.#sprintfはrb_str_to_inumの第三引数がTRUEになっておりエラーを投げる。
String#to_iはrb_str_to_inumの第三引数がFALSEになっており、0を返す。
使い方気をつけよう・・・
他
docs.ruby-lang.orgのKernel.#Integerの引数、第二引数base=0つけたほうがいいんやない?