Mitsukiの魔法実験室

Mitsuki's Magic Laboratory
Since 2002.09.14

RubyでもCPUIDしてみた

Posted at 2009/03/25 16:11 in Ruby

 Ruby でもやってみました。1.9 系でしか動かないはず(1.8 系は DL クラスが別物なので)。動作確認は Cygwin 上の 1.9.1 のみ。
 CPUID を取得して、Windows のメッセージボックスで表示してます。
 機械語は竹迫さんのをまるぱくり。


#!/usr/bin/env ruby

require 'dl'

cpu = "\0" * 48
bin = "S\xbf#{ [cpu].pack('p') }\xb8\x02\x00\x00\x80" <<
      "P\x0f\xa2\x89\x07\x89_\x04\x89O\x08\x89W\x0c\x8d\x7f\x10X\x8d\@\x01" * 3 <<
      "[\xc3"
DL::CFunc.new([bin].pack('p').unpack('L!')[0], DL::TYPE_VOID).call []

DL::CFunc.new(DL::dlopen('user32')['MessageBoxA'], DL::TYPE_LONG, 'MessageBox', :stdcall).
    call [0, cpu.gsub(/\0/, '').gsub(/\s+/, ' '), "CPUID", 0].pack('L!ppL!').unpack('L!*')


 ぶくまコメントにもちらっと書いたけど、ベーマガの投稿プログラム(POKE 文でメモリに機械語セットして呼び出す奴)を思い出して笑ったのは、わたしだけではないはずだ(多分)。

条件式中の範囲式

Posted at 2007/09/14 13:01 in Ruby

 Ruby(や Perl)の範囲式 .. は、if 等の条件文内(やスカラーコンテキスト)で使うと、条件1でONになり条件2でOFFになるという、フリップフロップのような動作をする:


% ruby -e '10.times do |i| print i if i == 3 .. i == 6 end'
3456

 しかし、範囲式をメソッドに追い出してしまうと、期待する動作をしなくなる:


% ruby -e 'def foo(i) print i if i == 3 .. i == 6 end; 10.times do |i| foo(i) end'
3

 おそらく、範囲式の状態はローカルスコープになっているため、メソッドを抜けたところで消えてしまうんじゃないかと思う(フリップフロップだけに「揮発」か?)。利にはかなってるかもしれないけど使いづらい。
 ちなみに Perl の場合はというと:


% perl -e 'for (1 .. 10) { print if $_ == 3 .. $_ == 6 };'
3456

% perl -e 'sub foo { print if $_ == 3 .. $_ == 6 }; for (1 .. 10) { foo };'
3456

 といった具合で、実に期待通りに動く(多分 closure 的に状態保持してるんだろう)。
 じゃあ Ruby でも closure にしてみればいけそうかな?:


% ruby -e 'foo = Proc.new do |i| print i if i == 3 .. i == 6 end; 10.times do |i| foo[i] end'
3456

 めでたしめでたし……?

load '~/.someconf'

Posted at 2007/07/30 19:28 in Ruby

 Ruby で設定ファイルを読み込む定番は Kernel.load だけど、なんとなく設定項目をローカル変数にしたら何も読み込まれなくて、きょとん。

~./someconf:
someconf = 'is in HOME'
p local_variables
p self
some.rb:
somerb = 'is in somewhere'
load '~/.someconf'
p local_variables
p self
実行結果:
/path/to/somewhere>ruby some.rb
["someconf"]
main
["somerb"]
main
/home>

 どうやら load 元と load 先ではスコープが違うらしい(load 先が別メソッド内にあるような感じ?)。self は共通なので、インスタンス変数にするのが正解なのかな(@someconf みたいに)。

Ruby の hash key は object そのまんま

Posted at 2007/04/10 21:13 in Ruby

404 Blog Not Found:perl|javascript - 文字列じゃないhash key
 JavaScript や Perl の場合ハッシュのキーは文字列限定なので、オブジェクト(Perl はそのリファレンス)をハッシュのキーとして使った場合、ハッシュからキーを取り出したらもはやオブジェクトではなくなってしまう、という話かな(Tie::RefHash なんてあるのね……)。

 Ruby の場合、データはすべてオブジェクトであり、ハッシュは「オブジェクトとオブジェクトを関連付ける入れ物」なので、キーにしたオブジェクトをハッシュから取り出しても元のオブジェクトのまま。そのため、以下のような破廉恥(?)なコードがごく自然に書けてしまう:


input = [ 'hogehoge', 'foooooooo', 'nyoron' ]
reply = { 'hoge' => 'fuga', /fo+o/ => 'bar' }

input.each do |instr|
    reply.each do |key, val|
        puts "#{instr} -> #{val}" if instr[key]
    end
end

 このコードは、配列 input の各文字列に対して、ハッシュ reply のキー(文字列または正規表現オブジェクト)を引数に [] 演算子を適用し、結果が FALSE/nil でなければハッシュの値を表示する。文字列の演算子 [] は、[] の中身が文字列なら普通の比較、正規表現オブジェクトなら正規表現にマッチする文字列を返す(一致・マッチしなければ FALSE/nil を返す)。実行するとこんな感じ:


> ruby test.rb
hogehoge -> fuga
foooooooo -> bar
> 

 ちなみにこれ、最近遊びで書いてる IRC bot "mistral" の自動応答機能の心臓部の抜粋なのだけど、Ruby のこの性質のおかげで、特に工夫するでもなくキーワードに文字列だけでなく正規表現も使えてしまうので便利(キーワード登録時には正規表現であることを明記する I/F は必要だけど)。

Ruby の Struct#values_at に Symbol は使えない?

Posted at 2007/02/23 12:22 in Ruby

 マニュアル読むと Symbol が使えるサンプルがあるのだけど、実際やってみるとエラーになる in 1.8.4 and 5。


#!/usr/bin/env ruby
Foo = Struct.new(:foo, :bar, :baz)
obj = Foo.new('FOO', 'BAR', 'BAZ')
p :bar.to_i
p obj.values_at(0, :bar, 'baz')    # => ["FOO", "BAR", "BAZ"]

とやると


bash-3.2$ ./test.rb
10345
./test.rb:5:in `values_at': offset 10345 too large for struct(size:3) (IndexError) from ./test.rb:5
bash-3.2$

となってしまう。どうも :bar をハンドルに強制変換して範囲エラーになってる気がしてソースを読んでみると(struct.c)、数値と範囲と強制数値変換は実装されているけど、Symbol や 文字列から index を算出するようなコードが見当たらないので、未実装……なのかな??
(どうでもいいけど、Struct の中身って実装レベルだと Array なのね)

Page 1/2: 1 2 [>]