Rubyで電卓作ってみた。
前回のエントリでコマンドライン電卓dcを試したけど、Rubyワンライナの方が断然便利だった。
% ruby -e 'STDIN.each{|l| puts eval(l)}' 1 + 2 3
残念ながらこのワンライナでは、
- フォーマット指定が面倒
- 変数が使えない
と、イマイチな所もあるので、書き直すことにした。
Ruby電卓rc
#!/usr/bin/ruby require 'getoptlong' include Math opts = GetoptLong.new( ["--format", "-f", GetoptLong::REQUIRED_ARGUMENT], ["--octal", "-o", GetoptLong::NO_ARGUMENT], ["--hex", "-x", GetoptLong::NO_ARGUMENT], ["--binary", "-b", GetoptLong::NO_ARGUMENT], ["--silent", "-s", GetoptLong::NO_ARGUMENT] ) format = "" verbose = true begin opts.each do |opt, arg| case opt when "--format": format = arg when "--binary": format = "%#b" when "--octal": format = "%#o" when "--hex": format = "%#x" when "--verbose": verbose = false end end rescue => ex STDERR.puts "Usage: rc [format options ...]" exit 1; end bind = binding STDIN.each do |line| begin res = eval(line, bind) if res.kind_of? Numeric if format.empty? puts res else printf "#{format}\n", res end else if verbose puts res end end rescue ScriptError, StandardError => err STDERR.puts err.message end end
パスの通った所にrcで保存しておいて、実行〜
電卓として。
% rc 1 + 2 3 sin(PI / 2) 1.0 a = 10; b = 20 20 a + b 30 exit
- evalしてるだけなので、大体Rubyな事は出来ると思います。
- Mathをincludeしてるので、Math.sinとする必要なし。
パイプを通す。
対話的ならirb使った方が断然便利なので、パイプを通すのが本来の使い方デス。
% cat 123.txt 123 456 789 % cat 123.txt | rc -b 0b1111011 0b111001000 0b1100010101 % cat 123.txt | rc -x 0x7b 0x1c8 0x315 % cat 123.txt | rc -o 0173 0710 01425 % cat 123.txt | rc -f '%010b' 0001111011 0111001000 1100010101
- fでsprintfのフォーマットが使えます。
メモとtodo
- GetoptLongは案外曲者。
- bind = binding, eval(line, bind)でeval環境を保存出来る。ピッケル本2nd Binding参照。
- res.kind_of? NumericでNumericを継承しているのかがわかる。
- silentはあんまりsilentにならない。
- evalのエラー処理は、eval.rb を読むが参考になりました。irbも簡単に作れそうな・・・。
ピッケル本を熟読しないと・・・。