もっと ruby
観光用に byebug を便利に使う
前回使ったbyebugって言うruby用のdebuggerが非常に良く出来ているので、emacsから使えないか調べてみた。
Module to add byebug debugger support to emacs realgud.
なんか、便利そう。でも待てよ。BPを貼って、breakpointにヒットした時、お約束でbtは行うな。でも、続いてフレームを上り下りするのは、やっていなかった。ちょいと確認してみるか。
frameをup/downせよ
題材は前回登場したminps.rbです。
(byebug) up [966, 975] in /tmp/minips.rb 966: } 967: define_op("moveto"){|vm| 968: y = vm.pop_op(:numeric).value 969: x = vm.pop_op(:numeric).value 970: vm.set_point(Vector[x, y]) => 971: vm.add_path(:moveto, vm.real_point) 972: } 973: define_op("rmoveto"){|vm| 974: y = vm.pop_op(:numeric).value 975: x = vm.pop_op(:numeric).value (byebug) bt #0 MiniPS::VM.transform_point(v#Vector) at /tmp/minips.rb:1325 #1 MiniPS::VM.real_point at /tmp/minips.rb:1329 --> #2 block in block in <module:MiniPS> at /tmp/minips.rb:971 : (byebug) f --> #2 block in block in <module:MiniPS> at /tmp/minips.rb:971 (byebug) f 9 [1456, 1465] in /tmp/minips.rb 1456: end 1457: print vm.ostack.empty? ? ">" : "[#{vm.ostack.size}]>" :
up/gdownで10行分表示してくれるのか。rubyの関数は比較的小ぶりに書かれる事が多いので、視認するにはこれで十分な気がする。
今居るフレームは、引数無しのfで確認出来る。引数を与えると、指定したフレーム番号の所を表示してくれる。
普通にlすれば、先に進むし、l- すれば、逆に前に戻るようになる。l= で、元の場所に戻る。なかなか考えたインターフェースになってるな。これなら、わざわざemacsの手を煩わせる必要な無いな。
デフォルトだと10行分を表示するけど、下記のようにすると、20行分を表示するようになる。 長いメソッドは警告の対象にする(by matz)からねってのを、思い出せ。こういう処置をしないと満足に閲覧出来ないコードは、怪しいぞと思っていれば、間違いない(個人の独断と偏見です)。
(byebug) set listsize 20 Number of source lines to list is 20
毎回入力するのが面倒なら、.byebugrc に書いておけばいいのだな。
それから、もっと過激?に、BPに達した時等で、listの表示が必要無いなら、
set noautolist
を設定しておけば良い。何時でも、lで表示出来るからね。
trace で楽チン追跡
つらつらと実技書を見てたんだ。そしたらステップ実行を自動化する方法が指南されてた。前回は、byebugのオプション -t が使えねぇと嘆いていたからね。ちゃんと説明書は読みましょうの、良い事例だな。折角作者様がインプリメントしているのだから、使わないと失礼にあたるってもんです。
(byebug) b 1325 Created breakpoint 1 at /tmp/minips.rb:1325 (byebug) c minips>1 2 moveto Stopped by breakpoint 1 at /tmp/minips.rb:1325 : 1328: def real_point 1329: transform_point @gs.point (byebug) set linetrace linetrace is on (byebug) set basename basename is on (byebug) c Tracing: matrix.rb:2006 @elements[i] Tracing: matrix.rb:2006 @elements[i] Tracing: matrix.rb:1953 new convert_to_array(array, false) Tracing: matrix.rb:1720 case obj Tracing: matrix.rb:1722 copy ? obj.dup : obj Tracing: matrix.rb:1993 @elements = array Tracing: minips.rb:1333 raise "no current point" if !drawing? Tracing: minips.rb:1272 !@gs.point.nil? Tracing: minips.rb:1334 @gs.current_path << [com, *args] Tracing: minips.rb:371 true Tracing: minips.rb:1462 buf = "" Tracing: minips.rb:1463 cont = false Tracing: minips.rb:1452 if !cont Tracing: minips.rb:1453 print "minips" minipsTracing: minips.rb:1457 print vm.ostack.empty? ? ">" : "[#{vm.ostack.size}]>" >Tracing: minips.rb:1458 l = $stdin.gets
上記のように、一度breakさせる。そしてlinetraceをセット、絶対Pathでのファイル名表示を抑制、そして継続。余す所なくトレースしてくれた。
私の、 .byebugrc
ob$ cat .byebugrc set listsize 20 # set noautolist set basename
わざわざ載せる程の事も無いけど、参考例と言う事で。最初、コメントを外して、余計な表示は避けていたんだけど、気が変わった。常に20行表示させるようにした。表示をけちってもしょうがないからね。
TkSimpleClassBrowser
『オブジェクト指向スクリプト言語Ruby』と言う20年前に出てた本の例を前回探して、右往左往した。今回は、きちんと探してみたよ。
そしたら、懐かしいページが出て来た。あの頃は、このHPに非常にお世話になったよ。まだ継続ってか公開されてるのに、驚きを禁じ得ない。
ここで公開されてるTkのアプリが、無修正で動いた。息が長いなあ。感心しますよ。gtkとかだと、そうは問屋が卸しませんよ。安心して使っていいぞ。
svg
これまた、前回登場したSVGです。知らない事は恥じゃ無い。調べてみれば良いのですから。
真っ先に、モジラ組に案内された。残念ながら、良く分かった人用のページだな。下記を見て予習してから、再訪せよ。
ちょい昔の資料。って事は、息が長いって事だな。これで分かった(かな?)
毎度お世話になってる先生のページ。世界標準語のC語で書かれた例が載ってるから、分かり易い。
SVGを編集するフリーで使えるソフトとしては、 InkScape が有名らしい。興味を持って試してみるか。
変換関数 / Matrix 再びモジラ組に戻って、うろうろしてたら、アフィン変換が出て来た。もう、恐くないよ。 グラフィックをやってる限り、何処にでも顔を出す、お馴染みさんですから。
inkscape
忘れないうちに、inkscapeを試してみる。入れたのはdebian機。グラフィックのカテゴリーに起動メニューが出て来た。inkscape-tutorialsも入れるといいよって事なので入れた。 /usr/share/inkscape/examples/に山ほどサンプルが有ったぞ。
大好物のcar.svgなんてのが入っていた。残念ながら、cdr.svgとかcons.svgは無かった。でも、tiger.svgzは入っていた。zが付いているのは、
debian:~$ file /usr/share/inkscape/examples/tiger.svgz /usr/share/inkscape/examples/tiger.svgz: gzip compressed data, was "tiger.svg", last modified: Thu Feb 3 08:55:08 2005, from Unix, original size 141878
サイズが大きいから、圧縮しておきましたって奴だ。そう言えば、最近プチ話題になった、 プロゴルファーのタイガー・ウッズ氏が23日、ロサンゼルスで自動車事故を起こして両足を複雑骨折 が有ったね。圧縮されて死ななくてよかったね。
起動してみると、画面の4辺に山ほど、ツールボタンが並んでいる。どうやって使うものやら? 早速の拒否反応と言うか、副反応が発現しそう。そう、コロナ繋がりで、最近良く聞く言葉で、副反応ってのが有るけど、これって副作用って言うネガティブな言葉を、やんわりさせて、恐怖心を抑えているのかな。
debian:inkscape$ ls tutorials/*ja*svg tutorials/tutorial-advanced.ja.svg tutorials/tutorial-interpolate.ja.svg tutorials/tutorial-basic.ja.svg tutorials/tutorial-shapes.ja.svg tutorials/tutorial-calligraphy.ja.svg tutorials/tutorial-tips.ja.svg tutorials/tutorial-elements.ja.svg tutorials/tutorial-tracing.ja.svg
日本語の指南書も有るから、ほんわかとやってみて、恐怖心を克服すればいいんだな。ちょい見したら、図形を重ねあわせたら、下の層が透けて見えるような効果も発動出来るみたいだ。
勿論CUIからも、使えるとな。
Export an SVG file into PNG with the default resolution of 96 dpi (one SVG user unit translates to one bitmap pixel): inkscape filename.svg --export-png=filename.png Same, but force the PNG file to be 600x400 pixels: inkscape filename.svg --export-png=filename.png -w600 -h400
svgファイルをチラ見すると、
<path style="fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:16;stro\ ke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="M -147.17109,-1087.1156 C -153.74248,-1087.7954 -159.61044, ...
こんな風に、座標が浮動小数で表現されてた。これが当たり前の事なのか。
lambda
ここまで、前回の復習と言うかフォローだった。ここからは純粋Rubyについて、また少し調べてみる。手始めは、
で、出たーと言ったらお化け。どこにも存在するやつです。勿論rubyにも有ります。 こういう記号って、なかなか調べつらいんだよな。そんな時は、躊躇なく、 Rubyで使われる記号の意味(正規表現の複雑な記号は除く) こういう所を見るに限る。ついでに言うと、正規表現自慢は止めよう。
"a is #{a}" リテラル/式展開 a = 10 p "a is #{a}" #=> "a is 10"
gauche用語では、インターポーレーションとか言っってたな。良く出て来る便利な記法だ。
irb(main):001:0> 3.times {|x| puts x} 0 1 2 => 3
{ … } って、rubyでは、どこにも出て来るやつ。空気のように使ってます。
(lambda (x) (puts x))
って関数に、次々に値を渡せば、上記のrubyになりますな。pythonだと無骨にlambdaが有るけど、rubyだとカッコよくhaskellもどきに、
irb(main):001:0> ->(x){ puts x }[123] 123 => nil
と、書くわけだな。
square = Proc.new {|x| x**2 } square.call(3) #=> 9 # shorthands: square.(3) #=> 9 square[3] #=> 9
こんなのが、Procに出てたぞ。ちゃんと名前を付けてあげましょうと言う例だな。
あっ、λって、lambdaの事ね。こう見てくると、rubyってのは、matz lisp って事がよく分かる。
関数型プログラミング
Ruby: Enumerableをreduceで徹底理解する#1 基本編(翻訳)
sakae@pen:/tmp$ ri Enumerable = Enumerable (from ruby core) ------------------------------------------------------------------------ The Enumerable mixin provides collection classes with several traversal and searching methods, and with the ability to sort. The class must provide a method #each, which yields successive members of the collection. If Enumerable#max, #min, or #sort is used, the objects in the collection must also implement a meaningful <=> operator, as these methods rely on an ordering between members of the collection. ------------------------------------------------------------------------ = Instance methods: all?, any?, chain, chunk, chunk_while, collect, collect_concat, count, cycle, detect, drop, drop_while, each_cons, each_entry, each_slice, each_with_index, each_with_object, entries, filter, filter_map, find, find_all, find_index, first, flat_map, grep, grep_v, group_by, include?, inject, lazy, map, max, max_by, member?, min, min_by, minmax, minmax_by, none?, one?, partition, reduce, reject, reverse_each, select, slice_after, slice_before, slice_when, sort, sort_by, sum, take, take_while, tally, to_a, to_h, to_set, uniq, zip
関数型と相性が良いのは、上記です。lambdaで定義したブロックと言うか無名関数に、効率よく値を渡す、かつ何等かの機能を盛り込むのが非常に楽。
irb(main):006:0> (1..10).each_cons(8) { |a| p a } [1, 2, 3, 4, 5, 6, 7, 8] [2, 3, 4, 5, 6, 7, 8, 9] [3, 4, 5, 6, 7, 8, 9, 10] => nil
何やら、オイラーの大好物であるconsが出てきたので、試してみた。こんなの知るかって動きだな。数学の行列を研究してる人かたの要望だろうか?
他にも、試してみたいメソッドが盛り沢山だな。
ruby/gnuplot
これからお世話になるかも知れないgnuplotのI/Fを入れておこう。人気度は、何も接頭辞がつかない奴だった。これぞmatzさんご推薦のシンプルは素晴らしいって奴だな。
オイラーは、ひねくれものなんで、暴君のお勧めに従ってみる。
Numo::Gnuplot : Gnuplot interface for Ruby
サンプルに有ったものを試してみる。 ex006.rb
require "numo/gnuplot" # X-Y data plot from file fn = "tmp.dat" open(fn,"w") do |f| 100.times do |i| x = i*0.1 f.printf("%g %g\n", x, Math.sin(x)) end end Numo.gnuplot do set title:"X-Y data plot from file" # if 'using' option is given, # the first string argument is regarded as a data file. plot fn, using:[1,2], w:'lines', t:'sin(x)' end
こういう、書きっぱなしのコードを試すには、コピペしてみるか、馬鹿と鋏は使いようモードに突入して、requireをハサミの如く使うに限る。
debian:examples$ irb irb(main):001:0> require './ex006' => true
libraryのPathは、普通wdirが登録されていないので、./hoge ってやるのが味噌。
tmp.datって言う実体ファイルが作成されるんだけど、メイン側(?)では、そんな下々の話が全く出てこないってのが、現代風なんですかね? いや、ちょいと誤解してた。fnなんていかにも関数でございますなんて名前なんで、新種のI/Fかと思っちゃったぞ。普通のよくあるパターンでした。
現代風と言えば、pythonのキラーライブラリィーであるnumpyに似せたruby仕様の奴が、Muno.gnuplotからも使えるようになっている。numo/narray ですって。深入りしそうなので、それは止めておく。
require "numo/gnuplot" x = ['a','b','c','d','e'] y = [10,20,40,30,45] Numo.gnuplot do set title:'Bar chart with text labels' set boxwidth:0.5 set 'grid' set yrange:[0..50] set style:[fill:'solid'] plot x,y, using:[2, 'xtic(1)'], w:'boxes', t:'series' end
これ棒グラフの例だけど、変形したら、色々と使い道が有りそう。