たけ(tk)印の Ruby 日記

GGB03124@nifty.ne.jp
たけ(tk)のホームページへ

2003-01-16(木)

 [Delphi:74038] でこのページのMACアドレス取得のプログラムを参照してくれた人が居た。
http://leed.issp.u-tokyo.ac.jp/~takeuchi/delphi/browse.cgi?index=074038

 残念ながら、僕のプログラムでは不完全だった。Win2000以降では、GUIDにはMACアドレスそのままではなくスクランブルされた形になるので、取得できない。

 [Delphi:74041]に基づいてもうちょっとましなもの(↓)を作ってみた。
http://leed.issp.u-tokyo.ac.jp/~takeuchi/delphi/browse.cgi?index=074041

require "Win32API"

## http://leed.issp.u-tokyo.ac.jp/~takeuchi/delphi/browse.cgi?index=074041
## http://msdn.microsoft.com/library/en-us/iphlp/iphlp/getadaptersinfo.asp
## http://msdn.microsoft.com/library/en-us/iphlp/iphlp/ip_adapter_info.asp

GetAdaptersInfo = Win32API.new("Iphlpapi","GetAdaptersInfo","PL","I")

# len = 256*256*2
len = 1282
buff = "-"*len

p GetAdaptersInfo.call(buff,len)  #=> 0 (ok)

p buff[404,6].unpack("C6").collect{|n| "%02x" % n }.join('-')
  #=> "00-e0-18-73-2b-89"
 MACアドレスというのは一つのコンピュータに複数あることもあるし、一つも無い場合もある。
 ip_adapter_infoの構造をたどれば、複数のMACアドレスを配列で返すことも可能だろう。
 すべての情報を表示してみた。ただし、複数のカードには対応していない。たぶん、最初のカードの情報が返るのだろう。

#! ruby -Ks

require "Win32API"

len = 1282/2
buff = "-"*len
GetAdaptersInfo = Win32API.new("Iphlpapi","GetAdaptersInfo","PP","I")
p GetAdaptersInfo.call(buff,[len].pack('I'))  #=> 0 (ok)

#--    Next: PTIP_ADAPTER_INFO;
#--    ComboIndex: DWORD;
p buff[0,8].unpack('II')           #=> [0, 0]

#--    AdapterName: array[1..MAX_ADAPTER_NAME_LENGTH + 4] of char;
p buff[8,256+4].unpack("A256")     #=> ["{01D481C3-663C-4A4D-9769-8737EC1DCAB0}"]

#--    Description: array[1..MAX_ADAPTER_DESCRIPTION_LENGTH + 4] of char;
p buff[268,128+4].unpack("A128")
    #=> ["SiS 900 PCI Fast Ethernet Adapter - パケット スケジューラ ミニポート"]

#--    AddressLength: UINT;
#--    Address: array[1..MAX_ADAPTER_ADDRESS_LENGTH] of byte;
p buff[400,4].unpack("I")          #=> [6]
p a = buff[404,8].unpack("C6")     #=> [0, 224, 24, 115, 43, 137]
p a.collect{|n| "%02x" % n }.join('-')
                                   #=> "00-e0-18-73-2b-89"

#--    Index: DWORD;
#--    aType: UINT;
#--    DHCPEnabled: UINT;
p buff[412,4*3].unpack("III")      #=> [2, 6, 1]

#--    CurrentIPAddress: PTIP_ADDR_STRING;
p buff[524,4].unpack("I")          #=> [0]

#--    IPAddressList: TIP_ADDR_STRING;
#--    GatewayList: TIP_ADDR_STRING;
#--    DHCPServer: TIP_ADDR_STRING;
p buff[428,40].unpack("IA16A16I")  #=> [0, "192.168.1.18", "255.255.255.0", 2]
p buff[468,40].unpack("IA16A16I")  #=> [0, "192.168.1.1", "0.0.0.0", 0]
p buff[508,40].unpack("IA16A16I")  #=> [0, "192.168.1.1", "", 0]

#--    HaveWINS: BOOL;          //
p buff[548,4].unpack("I")          #=> [0]

#--    PrimaryWINSServer: TIP_ADDR_STRING;
#--    SecondaryWINSServer: TIP_ADDR_STRING;
p buff[552,40].unpack("IA16A16I")  #=> [0, "0.0.0.0", "0.0.0.0", 0]
p buff[592,40].unpack("IA16A16I")  #=> [0, "0.0.0.0", "0.0.0.0", 0]

#--    LeaseObtained: TTIME_T; //??
#--    LeaseExpires: TTIME_T; //??
p a = buff[632,4*2].unpack("II")   #=> [1042684032, 2147483647]
p Time.at(a[0])                    #=> Thu Jan 16 11:27:12 東京 (標準時) 2003
p Time.at(a[1])                    #=> Tue Jan 19 12:14:07 東京 (標準時) 2038

2002-05-01(水)
  ruby kannri.rb *.rb
という形式で使えるようなファイル管理用のコマンドを作ろうと思った。コマンドライン引数が「*.rb」というワイルドカードなら、ディレクトリを読み込んでリストを取る必要があるな、とDOS流に考えて組みはじめた。
 しかしなんと、「*.rb」で指定したのに
file_mask = ARGV.shift
では特定の一つのファイル名しか返ってこない。なんたるバグ!。
 で、いろいろ工夫してみると、「'」(シングルコーテーション)で囲んで、次のように指定すればちゃんとワイルドカードが「ARGV.shift」で取れることが分かった。
  ruby kannri.rb '*.rb'
 しかし・・・ruby.exeは何をやっているのだろうか・・・と、心を静めて考えてみると・・・。
 ruby.exeはUNIXのシェルのまねごとをするための起動コマンドなんだよな。
 ということは、UNIX流のコマンドライン引数の扱いのまねっこもしているのかもしれない。たしか、UNIXでは
  ruby kannri.rb *.rb
というように、ワイルドカードを引数に置くと、シェルが展開してしまうんだよな、と思い出した。で、
  p ARGV
としてみると・・。やはり、「*.rb」にマッチするすべてのファイル名が、入っていたのであった・・。納得。

2002-02-27(水)

 いま、データベースの所在を管理するクラスを作っている。

2002-02-27(水)
入門書の執筆依頼とかいうのが来た。

2001-06-06(水)

 しっかしぃ・・、ホント、Ruby って面白い言語だね。

 今、EscPage (エプソンのページプリンタの制御言語)用のドライバを書いているのだが、コマンドラインオプションやテキスト中のコマンドによって EscPage のコマンドを送ると同時に現在の状態を表す PrnStat オブジェクトを変更したい。現状と同じならコードの作成を省略したい。
 PrnOpt クラスとしては PrnStat の存在さえ知らない。PrnOpt#code メソッドにしても引数の stat がなんであるかを知らない。ただ、引数のオブジェクトにはおそらく width= という名前のメソッドがあるに違いない、ということを知っているだけだ。
 なのに、ちゃんと PrnStat クラスの属性が変化している。たいしたものだ。

class PrnStat
  attr :width ,true
end

class PrnOpt
  def initialize
    @name = "width"
    @val  = 123
  end
  def code( stat )
    stat.send( @name+"=" , @val )
  end
end

ps = PrnStat.new

p ps        ##  #<PrnStat:0xc9b134>
p ps.width  ##  nil

po = PrnOpt.new

po.code ps

p ps        ##  #<PrnStat:0xc9b134  @width=123>
p ps.width  ##  123

2001-05-15(火)

 久しぶりにドジ情報

 ユーティリティに Array#divide というのを追加した。配列を分割するというもの。本来は Array#delete_if という標準メソッドで削除したものを返してくれればOKなのだが、残念ながら delete_if では残ったものしか返してくれない。

 そこで、「 a = b = [] 」とやってはまった。書き換えて実行してみればすぐに分かると思うが、これだと a も b も元の配列を同じものが返ってしまう。

 要するに「同じ配列」を指してしまうわけね。

    ##
    ##  Array#divide
    ##
    ##  a = [1,5,2,3,4,5,2,6,7]
    ##
    ##  b,c = a.divide{ |i| i < 5 }
    ##
    ##  p a     ##  [1, 5, 2, 3, 4, 5, 2, 6, 7]
    ##  p b     ##  [1,    2, 3, 4,    2      ]
    ##  p c     ##  [   5,          5,    6, 7]
    ##

class Array
  def divide
    a = []      ##  a = b = [] はドジ
    b = []
    each{ |i| if yield i then a.push i else b.push i end }
    return a,b
  end
end

2001-04-25(水)

 なんか、重要そうな情報・・。InterBase のデータベースの拡張子は GDBなのだが、Windows ME だと GDB ファイルを勝手に消してしまう。という話。

 Apollo(Ruby)から InterBase を使うというのが、 たけ(tk)の主たるテーマなわけ。

--

[iblinux-users 1260] RE:InterBASE Win2K対応について
At Tue, 24 Apr 2001 23:32:12 +0900,
H.Arakawa <arakawa1@urban.ne.jp> wrote:

Windows ME のパフォーマンスの問題ですが,Windows ME の『システムの復元』機能において監視するファイルのリストに拡張子が GDB のファイルもなぜか含められています。( mdb とか入ってないのになぁ... )

従って,システムの復元を行うと GDB が無くなったり(復元した時点ではなかった。)あるいは入れたはずのデータが消えたりします。

C:\Windows\system\restore\FileList.xml の中から Extention GDB を指定しているエントリを削除してから使用することでパフォーマンスの問題をある程度解消することが出来ます。
( もっとも Windows ME 自体が遅くなっていると感じるのですが... )

あるいは拡張子を GDB 以外にする,または "My Documents" フォルダに GDB ファイルを作成してもパフォーマンスは向上するかもしれません。
( "My Documents" 以下のファイルは監視されません。 )

--

2001-04-18(水)

 Ruby って何でもちゃんと用意されている。

 引数で受け取ったブロックを別のメソッドに渡したい。と思って捜したら、『デスクトップリファレンス』p.18 にはちゃんと書いてあった。

class Array
  def separate( &block )
    ret = self.select( &block )
    self.delete_if( &block )
    ret
  end
end

a=[1,2,3,4,5]
b=a.separate{|i|(i%2)==0}
p a #   [1,3,5]
p b #   [2,4]

def foo (*args)
  args.each{|i| p i.type }
  symbols = args.separate{|i| i.is_a? Symbol}
  hashes  = args.separate{|i| i.is_a? Hash }
  p args,symbols,hashes
    ##  [12, "ab"]
    ##  [:cd]
    ##  [{:ef=>1}]
end

foo 12,"ab",:cd , {:ef=>1}

2001-04-10(火)

 どっと疲れるというか・・

 「.bak」とか「.~xx」とかいったバックアップファイルのパターンを配列に置いておいてそれらを別扱いにしたい。ディレクトリからファイル名を取り出した後に、その名前が配列の中のパターンにマッチするかどうかを調べるサブルーティンを作ってあったのだが・・、

def mach_masks? name,masks
  return false if masks == []
  masks.each{ |mask|
    return true if mask =~ name
  end
  return false
end

excepts = [ /\.~/i , /\.BAK$/i , /\.TMP$/i ]

next if mach_masks? file_name, excepts
 次の一行になってしまうわけだ。
next if excepts.find{|m| file_name =~ m }
 * 何のためにサブルーティンを作ったんじゃ〜。

2001-03-21(水)

 邪道編 p.255 を使ってMACアドレスを取得するものを作ってみた。
require "phi"

require "Win32API"

def create_guid
  lpguid = ' ' * 16
  Win32API.new("ole32", "CoCreateGuid", ['P'] , 'V').call(lpguid)
  return lpguid
end

def guid_to_str guid
  buff = " " * 128
  len = Win32API.new("ole32", "StringFromGUID2", ['P','P','L'], 'L').
        call(guid, buff, 64)
  return buff[0, len * 2].gsub( "\0", "" )
end

def get_mac_address
  guid_to_str( create_guid )[-13,12]
end

puts guid_to_str( create_guid )

puts get_mac_address
* artonさんからのお手紙です。

From arton( Mail ) To take_tk@chance at 2001 04/08 10:56 編集 返信

3/21のMACアドレス

こんにちわ。
Windows2000だと、スクランブルがかかるから(遅きに失してる)、あ の方法だとダメになります。
それでは。

* 2003-01-16(木) の日記で新しいのを掲げました。

2001-03-15(木)

 DOS版dBASEのデータをInterBase@Linux にコピーした。

require "kumalaw0"
db_old = DB_DOS_CLM
db_new = DB_NEW
で別のスクリプトで作成したDatabseオブジェクトを使うようにする。
DB_DOS_CLM は Dos 版 dBASE のテーブルにアクセスするもの。
DB_NEW は Linux版 InterBase のデータベース。
table_old = db_old.table "claim.dbf"
puts table_old.struct
とすると、古いテーブルの構造がわかるので、エディタで加工して次のようなSQL文にして実行する。
db_new.table_recreate "claim", <<EOT
  CASENO        VarChar(20) not null primary key,
  TEDATE        VarChar(6),
  YOURREFNO     VarChar(20),
  INSUNO        VarChar(20),
  AMOUNT        VarChar(50),
  ・・・
EOT

table_new = db_new.table "claim"
puts table_old.struct
puts table_new.struct
で出来たものの確認。
データコピー用の Query を作成する。これも、 前のデータをコピーしてエディタで加工すればOK。
$query_new = db_new.query

$query_new.sql.text = <<EOT
  insert into claim
  values (
    :CASENO,
    :TEDATE,
    :YOURREFNO,
    :INSUNO,
    :AMOUNT,
    ・・・
  )
EOT
次のものはSQLパラメータの型を昔のテーブルを参照してセットするもの。
def copy_data_type_to_params old_table, new_query
  old_table.fields.to_a.each{ |f|
    n = f.field_name
    t = f.data_type
    new_query.params[n].data_type = t if new_query.params[n]
  }
end

copy_data_type_to_params table_old,$query_new
で、コピー実行。
def copy_claim_from_old old,db_new
  $query_new.close
    ##
  $query_new.params['CASENO'] = old['CASENO'].value
  p $query_new.params['CASENO']
  $query_new.params['TEDATE'] = old['TEDATE'].value
  $query_new.params['YOURREFNO'] = old['YOURREFNO'].value
  $query_new.params['INSUNO'] = old['INSUNO'].value
  $query_new.params['AMOUNT'] = old['AMOUNT'].value
    ・・・
    ##
  $query_new.execute
end

table_old.first
while not table_old.eof?
  copy_claim_from_old table_old,db_new
  table_old.next
end
 もっとうまくて高速な方法もあるだろうけど、こういうのは一度しか実行しないので、分かりやすいのが何よりだ。

 今回は急いでいたので、データ構造を何も変更しなかった。

 InterBase でもう少しデータ構造を変更したい。その場合に、古いデータをどこか(xx_old テーブル)にコピーして、変更して、 変更後にデータを戻す、という作業が必要。

 その場合もだな。データ構造が変わるわけだから、単純なコピーは期待できない。とすると、スクリプトでやるほかないだろう。しかし、めんどくさそうではある。

 それと、まだ、DOS版は使用中なので、 今度からは差分をコピーするものが必要になる。

2001-03-13(火)
パス名の表示をSFN(短い名前)にしたかったので、
MAX_PATH_SIZE = 513

def get_short_path_name lfn
  require 'Win32API'
  buff = 0.chr * MAX_PATH_SIZE
  Win32API.new( 'kernel32' , 'GetShortPathName' , %w(P P N) , "N" ).
        Call( lfn , buff, buff.size)
  buff.split(0.chr)[0].tr('\\','/')
end
alias sfn get_short_path_name
puts  sfn 'C:\Program Files\Netscape\Communicator'
    #   C:/PROGRA~1/NETSCAPE/COMMUN~1
puts  sfn 'C:/Program Files/Netscape/Communicator/readme.txt'
    #   C:/PROGRA~1/NETSCAPE/COMMUN~1/README.TXT
逆は面倒らしい。

2001-03-02(金)

 ASCII の『Ruby 256倍』シリーズの原稿を見させてもらえる光栄に服しているのだが、そのなかで、 artonさんがRubyからワードをコントロールする方法をいろいろ書いていた。(『ムック』の発売をまとう!)。

 たけ(tk)としては、Rubyからテキストを印刷する方法を思案しているのだが、一つの方法として、ワードで印刷するというプランがある。
  ruby prn_word.rb TextFilePath
てな感じで印刷できるとうれしい。

 ちょっと実験中。次のようなスクリプトで印刷は出来た。

 日本語が文字化けして困ったが、

「reloadAs」でエンコードを指定して読み直すのが正解のようだ。
    doc = wd.Documents.open(doc_file_name)
    doc.reloadAs( 1 )
 * 2001-02-27(火)版で「wd.format = WdOpenFormatEncodedText」と書
いたのは嘘でした。

#!ruby -Ks

    ##
    ##  prn_word.rb
    ##
    ##  ワードを使って印刷するスクリプト
    ##
    ##  Ruby prn_word.rb -options @FmtPath TextPath ...
    ##
    ##  FmtPath は
    ##
    ##  →g:\apollo\tkutils\word.rb[ワードの研究]
    ##

##$DEBUG=true

doc_file_name = 'g:\apollo\tkutils\prn_word.rb'

  require "win32ole"
  require "wordconst"
  include WORD_CONST
  wd    = WIN32OLE.new('Word.Application')
  wd.visible = true if $DEBUG
  begin
    wd.format = WdOpenFormatEncodedText
    doc = wd.Documents.open(doc_file_name)
    doc.reloadAs( 1 )

    wd.Options.PrintBackground = false
    wd.PrintOut

#    doc.close
    wd.quit
  rescue
    wd.visible = true
    raise
  end

__END__
 いろいろ「こつ」が必要なようだ。

 1 「#require "wordconst"」「#include WORD_CONST」に関してはartonさんの本を待とう。その代わりになるのが「WdOpenFormatEncodedText = 5」だ。

 2 「wd.visible = true」がないと、 ワードがゾンビになる可能性がある。ゾンビになるとワードが開いていたテキストがロックされてしまい、収拾がつかなくなる。しかし、ゾンビになってもALT+Ctrl+Delで 「WINWORD」を殺せば復帰できるようだ。

 3 ワードでマクロ登録をするのがRubyスクリプト作りの出発点になるだろう。ワードで、

 ツール(T)→マクロ(M)→記録(R)。でマクロ記録開始。

 「マクロ停止ボックス」が出ているので、これでストップ。

 ツール(T)→マクロ(M)→マクロ(M)→編集(E)。で記録を参照。

登録された内容を クリップボード経由でスクリプトに移して、加工することになる。

 4 「puts wd.ole_methods.sort」で使えるメソッドの一覧が出てくるので、使えそうなものを捜しておこう。次のようなリストが出てくるだろう。
    Activate()
    ActiveDocument
    ActivePrinter
        ・・・
    WindowState=
    Windows
    WordBasic
 5 あとartonさんに次のURLを教えたもらった。
<A HREF="
http://www.asia.microsoft.com/japan/developer/articles/welcome/dsmsdn/office112000.asp
">
http://www.asia.microsoft.com/japan/developer/articles/welcome/dsmsdn/office112000.asp</A>

 6 「wd.Options.PrintBackground = false」はスクリプトが印刷終了を待つための設定。 Word-VBAのヘルプをインストールして、捜したら出てきた。

2001-02-09(金)

 石井 勝さんのページから excel 用のクラスをいただいてきた。
<A HREF="
http://member.nifty.ne.jp/masarl/article/ruby-win32ole.html
">
http://member.nifty.ne.jp/masarl/article/ruby-win32ole.html</A>

ApolloのRuby.exeでもOK。
module FileSystemObject
  @instance = nil
  def FileSystemObject.instance
    ・・・
    return @instance
  end
end
こういうの知らなかったなあ・・。

  @instance =  WIN32OLE.new('Scripting.FileSystemObject')
何故か「Scripting」なんていうのが通った。DLしたっけかな?。

require 'win32ole'
module Excel
end
excel = WIN32OLE.new('Excel.Application')
WIN32OLE.const_load(excel, Excel)
    ・・・
  Excel.runDuring(true, true) do |excel|

    ##  excel.xx で使えるメソッドの一覧
    ##
    puts excel.ole_methods.sort

    ##  Excel::XX で使える定数の一覧
    ##
    puts Excel.constants.sort

  end
ですね。

2001-02-07(水)

 ここに書くと宣伝してもらえるようなので、ひんぱんに書こうかな?。
http://www.ruby-lang.org/ja/hotlinks.html

−−
 HashCounter というのを作った。誰でも作りそうなもの。

 dBASEやParadoxで作ったテーブルをInterBaseに移そうと思っているのだけれど、古いテーブルのデータを分析したかったので作った。

 後半のサンプルはApolloのrdbライブラリ (DelhiのVCLを使うもの)を使っているので、Apolloでしか使えないが、HashCounter自体は他の Rubyでも使えるはず。
    ##
    ##  HashCounter  ==
    ##
=begin

 キーを登録するとそのキーの数をカウントする。

hash1 = HashCounter.new
hash1.add 1
hash1.add 1
hash1.add 2
hash1.add 2
hash1.add 4
hash1.add 5

p hash1.list
##  1       2       2       33.33333333     33.33333333
##  2       2       4       33.33333333     66.66666667
##  4       1       5       16.66666667     83.33333333
##  5       1       6       16.66666667     100.0

  2001-02-07(水):
  データベースに入っている住所、氏名の長さの分布を調べるために作成した。

=end

class HashCounter < Hash
  def add key
    self[key]=0 unless self[key]
    self[key] += 1
  end
  def percent
    sum = 0
    self.each{ |key,value| sum += value }
    hash2 = HashCounter.new
    self.each{ |key,value| hash2[key] = 100.0*value/sum }
    return hash2
  end
  def ruiseki
    ary = self.to_a.sort
    sum = 0
    hash2 = HashCounter.new
    ary.each{ |key,value|
      sum += value
      hash2[key] = sum
    }
    return hash2
  end
  def list title=true
    r1 = ruiseki
    pc = percent
    r2 = pc.ruiseki
    ary = self.to_a.sort
    result = []
    result << "key  count   ruiseki percent     ruiseki" if title
    ary.each{ |key,value|
      result << [key,value,r1[key],pc[key],r2[key]].join("\t")
    }
    return result
  end
end
データベースの会社名の長さ統計をとるスクリプト
require "rdb"
#require "tkutils"
require "hash_counter"

hash_counter = HashCounter.new

table = Table.new(nil,'j:\dbf\aite.dbf').open

while not table.eof?
  v = table["AITENAME1"].value
  p v
  hash_counter.add v.size if v
  table.next
end
puts hash_counter.list
結果
key     count   ruiseki percent         ruiseki
    ・・・
14      95      340     3.28038674      11.74033149
15      35      375     1.208563536     12.94889503
16      235     610     8.114640884     21.06353591 ←最多
17      51      661     1.761049724     22.82458564
18      109     770     3.763812155     26.58839779
    ・・・
33      84      2211    2.900552486     76.34668508
34      78      2289    2.693370166     79.04005525
35      64      2353    2.209944751     81.25       ←80%
36      54      2407    1.864640884     83.11464088
37      62      2469    2.140883978     85.25552486
38      66      2535    2.279005525     87.53453039
39      56      2591    1.933701657     89.46823204
40      51      2642    1.761049724     91.22928177 ←90%
41      49      2691    1.69198895      92.92127072
42      41      2732    1.415745856     94.33701657
43      54      2786    1.864640884     96.20165746
44      44      2830    1.519337017     97.72099448
45      66      2896    2.279005525     100.0
* 合計の数は累積の最後(2896)を見ればわかる。

2000-11-27(月)

detab が欲しかったので作ってみたら1行メソッドになってしまった!。

detab というのは、タブコードをスペースに戻すもの。
    ##
    ##  detab ==
    ##
    ##  「str.gsub(){}」、マッチした部分を入れ替える。
    ##  「.*?」最短一致。
    ##  「' '*N」=space(N)
    ##
    ##  p          '012345678901234567890123456789'
    ##  p detab    '    012345678901234567890'          ,   4
    ##  p detab    '    0   1234567890123456789 0'      ,   4
    ##  p detab    '    01  23456789012345678   90'     ,   4
    ##  p detab    '    012 345678901234567     890'    ,   4
    ##  p detab    '    0123    4567890123456   7890'   ,   4
    ##  p detab    '    01234   56789012345 67890'      ,   4
    ##  p detab    '    012345  678901234   567890'     ,   4
    ##  p detab    '    0123456 7890123     4567890'    ,   4
    ##  p detab    '    01234567    89012   34567890'   ,   4
    ##
def detab line, tabsize=8
  line.gsub( /(.*?)\t/ ){
    $1 + ' '*( tabsize - ( $1.size % tabsize) )
  }
end

今まで使っていたアセンブラのコード(1995)・・、見たい?。見なくていいよ。
#TAB:
  push  dx
   push cx
    xor dx,dx
    mov ax,cx       ; ax:Col    1  2  3  4  5  6  7  8  9
    mov cx,Tab@Size ; cx:TabSize:6
    div cx          ;       0  0  0  0  0  1  1  1  1
    inc ax          ;       1  1  1  1  1  2  2  2  2
    mul cx          ;       6  6  6  6  6 12 12 12 12
    xchg ax,cx      ; cx:Col
   pop  ax          ; ax:OldCol
   sub  ax,cx       ; ax:(-)Inc
   sub  di,ax       ; di:DstPtr
  pop   dx
  jmp   #Load
* あらかじめ spc で埋められたバッファのポインタをずらすものらしい・・。

2000-09-10(日)

 きゃ!。 http://homepage1.nifty.com/kazuf/ で紹介されてる。最近更新していないなぁ。藤岡さんちらしい。

2000-07-10(月)

<A HREF="mk_db.rb">mk_db.rb</A>

2000-07-10(月)

rgb_grid.rb は Table から Query に変えても動く。
table = Query.new(form, :table)
table.database_name = 'DBDEMOS'
table.sql.add('select * from biolife.db')
table.active = true

table = Table.new(form, :table)
table.database_name = 'DBDEMOS'
table.table_name = 'biolife.db'
table.active = true
しかし、sql.add というのが、いまいち。
Table や Query でペアレントが必要というのも分かりにくいが、 デルフ
ァイでの動作を考えれば分かりやすい。デルファイではフォームにポトリと
落として作るのだ。
Table に insert、post がないぞー。
form=Form.new
if not FileTest.exist?('ap_db.db')
  query = Query.new form
  query.sql.add( <<EOS
  create table "ap_db.db"
  (
    id   char(10),
    path char(50),
    icon blob,
    memo char(20)
  );
EOS
  )
  query.execute
end

2000-07-10(月)

*HELLO GGB03124
*GO FGALTS
*MES 5
*SAY
SUB:RE^8:Apollo=Ruby+Delphi
RE:1352
藤岡 和夫 さん こんにちは たけ(tk)です。
》01352/01352 JBD01136 藤岡 和夫 RE^7:Apollo=Ruby+Delphi
》( 5) 00/07/08 21:39 01350へのコメント

1350 たけ(tk) さん

》| よかったら、結果を教えてください。

》 BDEをインストールしたのですが、単にインストールしてもそのことをApollo
》は知らないみたい(^^;)全部同じフォルダに放り込んでみよう・・・何か環境設
》定が必要でしょうか。
実験してみました。
1 le211.lzh をダウンロード
2 デルファイなどBDEを使うアプリをアンインストール。
3 Apollo.exe でD:\TEMP\ap-609\ap\sample\rdb_grid.rb を起動。
パスが見つかりません.
ファイル: C:\Program Files\Common Files\Borland Shared\Data\biolife.db
D:\TEMP\ap-609\ap\sample\rdb_grid.rb:15:in `active='
D:\TEMP\ap-609\ap\sample\rdb_grid.rb:15
D:\TEMP\ap-609\ap\sample\rdb_grid.rb:0

4 le211.lzh を解凍してインストール。再起動。
5 Library Exploror を起動、「設定」で何も変更せずに 「OK」して
再起動。「テーブルが存在しません。・・\LE\Master.dbf」、

6 Apollo.exe で D:\TEMP\ap-609\ap\sample\rdb_grid.rb を起動。
3と全く同じエラーメッセージ。

* これでは、BDEの問題か、DBファイルの問題かが分からない。

7 デルファイ5をインストール。
8 Apollo.exe で D:\TEMP\ap-609\ap\sample\rdb_grid.rb を起動。OK.
9 C:\Program Files\Common Files\Borland Shared\Data\ を別名に
rename してから、 Apollo.exe で D:\TEMP\ap-609\ap\sample
\rdb_grid.rb を起動。OK.
→3と同じエラーメッセージ。

10 C:\Program Files\Common Files\Borland Shared\Bde\ を別名に
rename してから、
Apollo.exe で D:\TEMP\ap-609\ap\sample\rdb_grid.rb を起動。
Borland Database Engine の初期化中にエラーが発生しました (エラー $2109)
D:\TEMP\ap-609\ap\sample\rdb_grid.rb:15:in `active='
D:\TEMP\ap-609\ap\sample\rdb_grid.rb:15
D:\TEMP\ap-609\ap\sample\rdb_grid.rb:0
11 le211.lzh をインストール。Apollo で rdb_grid.rb を起動。
認識できないデータベースです.
エリアス: DBDEMOS
D:\TEMP\ap-609\ap\sample\rdb_grid.rb:15:in `active='
D:\TEMP\ap-609\ap\sample\rdb_grid.rb:15
D:\TEMP\ap-609\ap\sample\rdb_grid.rb:0

2000-07-05(水)
前に作ってあった Ask.rb が Apollo でうまくいかない。
if PLATFORM =~ /cygwin/
で判断しているので当然なのだが、
Apollo では
if PLATFORM =~ /i386-mswin32/
となるらしい。これはまずいっち。

また、
Win32API.new
もエラーを返した。これは Win32API.dll が cygwin 用であるため。おそ
らく mswin32 用の Win32API であれば大丈夫だろう。
また、raw mode にするために、cygwin.dll の tcsetattr を使っている。
これは、たぶん、mswin32 では使えない。
Tcsetattr = Win32API.new('cygwin', 'tcsetattr', %w(L L P), 'V')

2000-06-25(日)
Apollo でのフォームの消滅管理について。

フォームが複数あるスクリプト(s_forms.rb)でのフォームの消滅管理で
トラぶっている。
まず、単純なフォームが一つの場合について考える。この場合、現状では
フォームが消滅したときには mainloop から抜けているようである。その証
拠に、終了後に mainloop の後のスクリプトが実行される。
フォームが一つなら、[x]ボタンを押す、スクリプトで form.close を実
行する、Apollo 窓で terminate ボタンを押す、 Apollo や WIN の終了で
どれをとっても同じ結果になるだろう。
フォームの閉じ方として考えられる他の方法としては、 Screen.form=nil
でフォームのインスタンスへの参照を0にする。exit_mainloop というよう
なコマンドを用意してもらって mainloop の次の処理に移る。 exit_script
というようなコマンドで mainloop 以降の処理をオミットして終了させる。
などが考えられる。
【終了方法の分類】

[x]ボタンを押す、と、スクリプトで form.close とは同じ分類だろう。

Screen.form=nil はちょっと特殊。Ruby の本来のオブジェクトの消え方
だとは思うのでが、もうちょっと考えないと分からない。
それ以外はスクリプトの終了と同時のフォームクローズなので、同じ分類
と見て良いだろう。
【フォームが複数の場合】

[x]ボタンを押したとき、もしくは form.close した後に、 他のフォーム
から show で復活できるようにすべきか?。それともインスタンスを解放し
てしまうべきか?。
デルファイで普通に作ったフォーム(ユニットの変数として登録され、D
RPファイルで CreateForm され、メインフォームで管理されるフォーム)
では、メインフォーム以外では[x]ボタンで消しても、show で復活できる。
これは要するに、インスタンスを消滅させないという点で、 close は hide
と同じ扱いになっている。
apollo で、メインフォームの概念を導入せずに close を hide と同じ扱
いにした場合、すべてのフォームが hide されてしまうと、アプリ全体がゾ
ンビになってしまう。(※1)。これはデルファイでも同じ。(※2)。し
かし、デルファイの場合にはメインフォームを特別扱いにして、メインフォ
ームを close した場合にはすべてのサブフォームを閉じてアプリを終了さ
せることができるので、あまり問題にならない。ところが、 Apollo で、メ
インフォームの概念がなく、[x]で hide の扱いにすると、[x]ボタンでアプ
リを終了させられなくなってしまう。
※1:バックグランドで処理を継続し、必要に応じて自ら show するよう
な用途も考えられる。

※2:mainform.hide ではそのフォームが見えなくなるだけで、アプリは
終了しない。

この対策としては、次のような案が思い浮かぶ。

A.メインフォームの概念を導入する。
B.すべてのフォームが hide になったら、アプリを終了させる。
C.hide と close とを区別するフラグを用意する。

close で(もしくは [x]ボタンを押したとき)フォームのインスタンスを
解放してしまうと、簡単には show できなくなる。アプリの片割れのフォー
ムが開いているのに、もう片方のフォームが開けなくなるなら、ユーザーの
意図とは異なる結果になるだろう。もう一度 Form.new で作り直すことにな
るが、その場合、イベントハンドラなども作り直さなければならなくなるだ
ろう。また、元の Screen.form との関係も複雑になる。

2000-06-25(日)
Apollo でのフォームの消滅管理は、 Ruby による消滅管理、Apollo によ
る管理(PhiObjectList)、デルファイによる管理、 が複雑に入り組んでい
る。
フォームの消え方にもいろいろある。[x]を押した場合、terminate ボ
タンを押した場合。close を実行した場合。 Screen.form=nil で参照がな
くなった場合。WIN終了の場合。アプリの終了に伴う場合。
「フォームを消したい」という意味(ユーザの意図)による分類も可能。
そのフォームだけ消える+復活可能=form.show で見えるようにしたい場合
(form.hide)、 そのフォームだけ消える+復活不可ようにしたい場合
(form.release。Form.new で作り直すことになる)、 アプリ全体を終了さ
せたい場合(treminate ボタン、デルファイでのメインフォームの [x]クリ
ック、アプリ終了、WIN終了)。
まず、close(form.close、[x]ボタン)でそのような処理をすべきかに
ついて考えてみる。
A案:close を hide と同じ扱いにする。すべてのフォームが hide され
たら、アプリ全体をクローズする。または、メインフォームを close した
らアプリ全体をクローズする。
B案:close でデルファイのインスタンスを消滅させる。クローズされた
フォームにアクセスしようとしたら、Ruby のエラーを出す。 ユーザの意図
とは異なるだろう。
C案:いずれかのフォームで close したらアプリ全体を終了させる。
s_forms.rb での方法だが、ユーザの意図と異なるだろう。
D案:close で、他に参照がなかったらデルファイのインスタンスを消滅
させる。しかし、参照を管理しているのは Ruby なので、 Apollo で管理す
るのは難しいかもしれない。
E案:close で、hide+Screen.form=nil とする。インスタンスの消滅管
理は Ruby に任せる。つまり、他に参照がなかったらデルファイのインスタ
ンスを消滅させる。Screen.form 以外からの参照がある場合にはインスタン
スは消滅しない。 Screen.form からの参照は不可能になるが、 それ以外か
らの参照は可能。しかし・・・、Screen にないフォームを show する、 と
いうのはおかしいな。表示するためには Screen.form=saved_form してから
show とする?。

2000-06-25(日)
複数フォームのスクリプト(s_forms.rb)で 603g ではノーバグで、603i
〜604a ではアウト。
ソースでも眺めてみるか・・。

まずフォームのインスタンスの消滅の部分。
→d:\temp\ap-604~2\apollo\i\i_malloc.pas[FormRelease]

procedure FormRelease(real: TForm);
begin
real.tag := 0;
if real.menu <> nil then
PhiObjectList.Remove(real.menu);

PhiObjectList.Extract(real); (4)
real.Release; (5)
end; (6)
FormRelease というのは、Ruby によるルビーオブジェクトの消滅の前に
呼ばれるコールバックらしい。

function FormAlloc(klass: Tvalue; real: TComponent): Tvalue;
PhiObjectList.Add(real); (2)
result := rb_data_object_alloc(klass, real, nil, @FormRelease); (3)

FormAlloc は
→d:\temp\ap-604~2\apollo\i\i_form.pas[FormAlloc]
function Form_new(argc: integer; argv: Pointer; this: Tvalue): Tvalue; cdecl;
real := TForm.Create(nil); (1)
result := FormAlloc(this, real);
から呼ばれる。これは Ruby での Form.new に当たる。
つまり、

(1) デルファイのインスタンスを作る、TForm.Create(nil);
(2) Apollo が管理するオブジェクトとして登録する、
PhiObjectList.Add(real);

(3) Ruby が管理するオブジェクトとして登録する。
同時に、Ruby がオブジェクトを消滅させるときの呼び出すコー

ルバックとして FormRelease を登録している。

(4) Ruby がオブジェクトを消滅させたいときに FormRelease が呼ば
れ、まづ、Apollo の管理テーブルから除かれ、

(5) デルファイのインスタンスが消滅する。
(6) その後、コールバックから Ruby に戻って、Ruby からも除かれる。
で、実際に消滅するというときはどうなんだろうか?。
(7) Ruby がオブジェクトを消滅させたいとき、 というのはインスタ
ンスへの参照がなくなったとき(Screen.form=nil)だろう。

(8) Screen.form=nil は可能なのか?。
(9) [x]ボタンが押されたときにはどうなるのか?。よく分からない。
→d:\temp\ap-604~2\apollo\phihan~1.pas[ObjectList.IndexOf]
if ObjectList.IndexOf(Sender) = -1 then Exit;

これは、先行廃棄対策。問題ないはず?。かな?。しかし、なぜ、そもそ
も先行廃棄が生じるのか?。先行廃棄という現象自体を撲滅すべきではない
か?。先行廃棄というのは、この場合、Apollo のオブジェクト管理テーブ
ルから消えることらしい。デルファイのインスタンスは残っているのか?。
Ruby が管理するインスタンスとしてはどうか?。

→d:\temp\ap-604~2\apollo\spinel.pas[function gets: PChar]
FormConsole.Show;
これはありがたい。gets でコンソール入力が必要なときにコンソールが開
くというもの。

function gets: PChar;
term_p := False;
if (not ruby_alive_p) or (StdinKey = 4{\C-d}) then

until StdinKey = 13;
これも、Ctrl+D で終了できるようにするものだろう。#13 って^Mかな?。

→d:\temp\ap-604~2\apollo\phi.dpr[UOwner]

function PhiInit(AOwner: TComponent): TObject;
UOwner := AOwner;
むむ?。UOwner はユニット変数であり、一つしかない。Execute したとき
に呼ばれるものかな?。とすると、Apollo メインフォームが入るのか?。

procedure load_protect(name: PChar; done: TNotifyEvent);
rb_gc;
PhiObjectList.Clear;
この順番はどうかなあ?。クリアしてからガベジコレクションをすべきでは
ないか?。

→d:\temp\ap603g~1\apollo\i\i_func.pas[Phi_gets]
→d:\temp\ap-604~2\apollo\i\i.pas[i_ModalResult]

function Phi_gets(argc: integer; argv: Pointer; this: Tvalue): Tvalue; cdecl;
case Integer(StdinBuf^) of
$03{Ctrl+C}, $04{Ctrl+D}, $1A{Ctrl+Z}:
result := Qnil;
Ctrl+D 対策。この関数自体は、何も入力しなかったのと同じ result を返す。

function Phi_message_dlg(argc: integer; argv: Pointer; this: Tvalue):
Tvalue; cdecl;
あんら、こんなところに message_dlg がある。

「??」から「MT_WORNING」に引数が変わるらしい。(正統)。

→d:\temp\ap-604~2\apollo\i\i_moda~1.pas[Init_ModalResult]

procedure Init_ModalResult;
rb_define_const(mPhi, PChar(UpperCase1('mrNone')), INT2FIX(mrNone));

デルファイの TModalResult を rb_define_const する。

のであるが、TModalResult 型として登録しないと、 プロパティ窓で表示
しにくいだろう。もっともデルファイの TModalResult 型ではどうにもなら
ん。列挙できるわけがない。
type TModalResult = Low(Integer)..High(Integer);
→d:\temp\ap603g~1\apollo\i\i_scro~1.pas[ScrollBar_new]
コメントの整備だが、承継元でのセットにはなっていない。できないのか
なあ?。

→d:\temp\ap603g~1\apollo\ext\dialogs\dialogs.dpr[OpenDialog_new]
コードの順番が入れ替わっている。何か影響があるのかな?。

2000-06-25(日)
apollo.dll は何で作ってあるのかと思って、 エディタで強制的に読んで
みた。次の文字が見つかった・・。
Microsoft Visual C++ Runtime Library

あ、そうか、apollo.dll はCで作ってあるんだ。ソースは、「ruby の本
体」+パッチ、って書いてあったもんな。

2000-06-25(日)
「??」が分からないぞー。

→d:\temp\ap603g~1\apollo\i\i_func.pas[Phi_message_dlg]

case dlgc of
Ord('!'): dlg_type := mtWarning;
Ord('x'): dlg_type := mtError;
Ord('i'): dlg_type := mtInformation;
Ord('?'): dlg_type := mtConfirmation;
else
dlg_type := mtCustom;

end;

なので、「?!:警告」「?x:エラー」「?i:情報」「??:確認」

かと思いきや、

→d:\temp\ap-604~2\apollo\i\i_func.pas[dlgt]
では異なっている。ここからはちゃんと TMsgDlgType で指定するらしい。
(そちらの方が正統)。
−−
require 'phi'
p Phi.message_dlg('Hi', ??, [:yes, :no, :no_to_all]).id2name
−−

これは結構役に立ちそう。デルファイのヘルプは次の通り。

「??」は「AType: TMsgDlgType」のようだが、変な指定だな。「確認/?」
と出ている。「警告」は「?!」なんだろうか?。→でした。
* 「??」は Ruby の文法により「?」という一文字 (のアスキーコード
値)を意味する。「?!」なら「!」という文字。

MT_ERROR は定義されていなかった。 「1」 「2」では絵が出ないので、
「無効」ということだろう。
でも、「??」が分からないぞー。

ボタンの種類に関しては次のように定義されている。戻り値に関しても同
じ名前で定義されている。
* →d:\temp\ap603g~1\apollo\ruby_i~1.pas[DlgBtnIdents]

DlgBtnIdents: array[0..10] of string = (
'yes', 'no', 'ok', 'cancel', 'abort', 'retry', 'ignore',
'all', 'no_to_all', 'yes_to_all', 'help'

);

−−
MessageDlg 関数
MessageDlg は,画面の中央にメッセージダイアログボックスを表示します。

ダイアログおよびメッセージルーチン

function MessageDlg(
const Msg: string;
AType: TMsgDlgType;
AButtons: TMsgDlgButtons;
HelpCtx: Longint): Word;
説明

MessageDlg はメッセージボックスを表示して, ユーザーの応答を取得しま
す。メッセージボックスには,Msg の値が表示されます。AType はダイアロ
グの用途を示します。AButtons はメッセージボックスに表示するボタンを
示します。HelpCtx には,ユーザーがヘルプボタンを押すか,F1 を押した
ときに表示されるヘルプトピックのコンテキスト識別子を指定します。

MessageDlg は,ユーザーが選択したボタンの値を返します。 戻り値は以下
のとおりです。

mrNone mrAbort mrYes
mrOk mrRetry mrNo
mrCancel mrIgnore mrAll
−−
TMsgDlgType 型

TMsgDlgType 型は,メッセージボックスの種類を表す値を定義します。

type TMsgDlgType = (
mtWarning,
mtError,
mtInformation,
mtConfirmation,
mtCustom);
説明

TMsgDlgType 型はメッセージボックスの種類を示す値を定義します。
TMsgDlgType は,MessageDlg および MessageDlgPos 関数で使用されます。
以下に値を示します。

値 説明

mtWarning 黄色の感嘆符が表示されているメッセージボックス
mtError 赤色の停止のマークが表示されているメッセージボックス
mtInformation 青色の i が表示されているメッセージボックス
mtConfirmation 緑色の疑問符が表示されているメッセージボックス
mtCustom ビットマップがないメッセージボックス。メッセージボッ
クスのキャプションにはアプリケーションの実行可能ファ
イルの名前が表示されている

−−

2000-06-25(日)
コンソールとフォームとの連携を考えているのだが、一番使いやすい連携
としては、基本的にはコンソールで、つらつら実行していく、時たま、どう
してもユーザーの応答が必要であり、結構複雑な質問をしなければならなく
なったときに、フォームを出して質問する、というのが、一番使いやすそう
だ。簡単な質問な場合にかっちょいいのを出したいなら、message_dlg でも
可能だ。
フォームアプリでコンソールに出したり、というのは、リダイレクトが必
要な場合くらいしか考えにくい。??。

2000-06-23(金)
ニフティ(nifty:FGALTS/MES/05/1333)で書いた Apollo の宣伝文です。
01333/01333 GGB03124 たけ(tk) Apollo=Ruby+Delphi
( 5) 00/06/23 18:33

こんにちは、たけ(tk)です。
最近、もりきゅうさんの Apollo にはまっています。

* もりきゅうさんのこのフォーラムでの発言は 98/06/30
nifty:FGALTS/MES/19/353 のようですね。

Apollo というのは Ruby からデルファイのVCL (ビジュアル・コンポ
ーネント・ライブラリ)を使おうというものです。
データベースからSQL(や TABLE=SQLの簡易バージョン)を使って、
グリッドで表示する。しかも、グラフィックデータをグリッド中に表示して
しまう、などということも実現されています。
入力窓のIMEの制御も完璧です。

複数のフォーム間でのやりとりが可能なことも実験すみ。

フォームと同時にコンソールで入出力を行うことも可能。
などなど、たけ(tk)思うに「凄い」です。
関連ページは下記の通りです。
【apollo のホームページ】
<A HREF="http://www.moriq.com/apollo">http://www.moriq.com/apollo</A>

【実行ファイルとソース、ver.0.603e】
<A HREF="http://www.moriq.com/ruby/archive/ap-603e.zip"
>http://www.moriq.com/ruby/archive/ap-603e.zip</A>
<A HREF="http://www.moriq.com/ruby/archive/ap603esrc.zip"
>http://www.moriq.com/ruby/archive/ap603esrc.zip</A>

<A HREF="http://www.moriq.com/ruby/archive/vcl50.zip"
>http://www.moriq.com/ruby/archive/vcl50.zip</A>

【ML】
<A HREF="http://www.freeml.com/Mess.cgi?Group=ap-list"
>http://www.freeml.com/Mess.cgi?Group=ap-list</A>

インストールにはVCL50のランタイムが必要ですが、上のページにあ
るので、それを c:\windows\system にコピーしておけばいいです (※1、
※2)。
apollo を上記ページからダウンロードして、展開して、apollo のアイコ
ンのクリックすれば、
(1)スクリプト編集窓、
(2)コンソール、
(3)プロパティ窓。(使えるコンポーネント+そのプロパティなどが
ツリーで表示される)
が開きます。実行ボタンを押せば(4)そのスクリプトで作成されたフ
ォームが開きます。サンプルもたくさん入っていますので楽しめます。
※1:WIN95ではそれでOKなのですが、もりきゅうさんがNTで実
験したらうまくインストールできなかった、とのこと。誰かやり方
を教えてください。

※2:vcl50.zip は最小ライブラリなので、データベースを使うには
http://www.moriq.com/delphi/delphi5.zip
が必要。なのではあるが、たけ(tk)思うに、これだけでは不足なの
ではないかと思う。たけ(tk)のところではデルファイがインストー
ルすみなので、これで十分かどうかを実験していない。

今のところ、WIN専用なのですが、インプライズはデルファイのUNI
Xバージョン(Kylix)を今年中に出すと言っているので、Apollo も両OS
に対応することになるかもしれません。
あ、もちろん、超ベータバージョンなので、そのつもりで・・。

たけ(tk)=熊谷 秀武 http://member.nifty.ne.jp/take_tk/

2000-06-24(土)

<A HREF="s_forms.rb">s_forms.rb</A>

2000-06-19(月)

<A HREF="s_screen.rb">s_screen.rb</A>

2000-06-15(木)

<A HREF="test_ime.rb">test_ime.rb</A>

2000-05-30(火)
もりきゅうさんの apollo というのをDLしてきました。
<A HREF="http://www.users.yun.co.jp/~moriq/ruby/apollo.html"
>http://www.users.yun.co.jp/~moriq/ruby/apollo.html</A>

これは ruby からデルファイの vcl(ビジュアルコンポーネントライブラリ)
を使おうというモノ。ちょっと実験してみたところ、調子が良さそうです。
下に書いてあるスクリプトで実行すると、次のようなフォームとコンソー
ル窓が開きます。
フォーム

┌────────────────┐
│絵 hello world _□×│
├────────────────┤
│new item │←メニュー
├────────────────┤
│ hello │←ボタン
├────────────────┤
│foo │←編集窓
│ │
│ │
│ │
│ │
│ │
│ │
└────────────────┘

編集窓では、かな漢字変換での入力が当然のように出来ます。

ボタンを押すと、ボタンのキャプションが編集窓に入ります。

メニューを開くと「hehehe Ctrl+E」「hahaha Ctrl+A」という選択肢がで
ますので、 それを選択すると、 ボタンのキャプションが 「hehehe」とか
「hahaha」とかに変わります。その後、ボタンを押すせば編集窓の中身も変
わります。
また、メニューでショートカットが表示されているとおり、Ctrl+hoge の
ショートカットキーを押せば、 いちいちメニューを開かずに実行できます。
コンソール窓にはデバッグ用の出力が出てきます。

* 今まで見た ruby のGUIの中では最強です。

* 難を言えば、まだVCLのごく一部しか使えないことと、マニュアル
がないことでしょうね。(デルファイ使いでないと、マニュアルなしでは難
しいかも)。あと、最大の欠点は、WINでしか使えないことですね。デル
ファイが kylix に進化すれば、UNIXでも最強のGUIになるかも。
−− foo2.rb .. original:moriq(foo.rb) modified by tk
require 'phi' ## apollo を使うための宣言
include Phi ##

$> = Phi ## 出力を apollo のコンソールにする。
$stdout = Phi ##
$stderr = Phi ##

$foo=nil ## foo フォームを保存する変数
class Foo ## foo フォームのクラスの定義の開始
def initialize ## foo フォームクラスの new の定義の開始
@form = Form.new ## 本物のフォームを @form に持つ
@form.caption = 'hello world'

#@form.icon = Icon.new( 'icon1.ico' ) ## にしたい。
icon = Icon.new ## アイコンの作成
icon.load_from_file 'icon1.ico' ## アイコンファイルから読み込む
@form.icon = icon ## フォームのアイコンとする

@button = Button.new(@form) ## ボタンを作成する、ボタンのオーナーは @form
@button.parent = @form ## ボタンのペアレントも @form(※1)
@button.caption = 'hello' ##
@button.width=100 ## ??
@button.align = ALTOP ## ボタンの配置方法の指定(※2)

base = new_item 'new item', 'Ctrl+N', 'item1'
## メニューバーのアイテム(base)を作成、
## キャプション、ショートカット、内部名

item = new_item 'hehehe', 'Ctrl+E', 'item1'
## base で展開するメニューアイテムの作成

def item.on_execute ## このアイテムが選択されたら
$foo.button.caption = caption ## foo フォームのボタンの

end ## キャプションを変更する。
base.add item ## 作成してアイテムを base に追加。

base.add new_line ## base に 区切り線を追加。

item = new_item 'hahaha', 'Ctrl+A', 'item1'
def item.on_execute
$foo.button.caption = caption

end
base.add item

new_menu @form, 'menu', [base] ## @form のメニューバーを定義
## 中身は base が一つだけ。

@memo = Memo.new(@form) ## 編集窓を作成。オーナーは@form(※1)。
@memo.align = ALCLIENT ## 配置方法は「残り全部」(※2)。
@memo.text = 'foo' ## 編集窓の初期値
font = Font.new
font.size = 18
@memo.font = font ## 編集窓のフォントサイズの変更

def @button.on_click ## ボタンがクリックされたら
$foo.memo.text = caption ## 編集窓にボタンのキャプションを入れる。

end ##

print "hello\n" ## コンソールに出力(デバッグ用)
@form.show ## @form を表示する。

end ## 定義終わり。
attr :button ## @button を button として公開する
attr :memo ## @memo を memo として公開する。
attr :form ## @form を form として公開する。(※3)
end ## クラス定義終わり。

$foo = Foo.new ## Foo クラスのインスタンスを作成。
mainloop ## イベントループの開始。

=begin
※1:オーナーとペアレント:
オーナー:あるオブジェクトAが消えたときにその子供のオブジェ

クトBも消える、と言う関係にあるときに、AはBのオーナーである、
と言う。
ペアレント:画面上でCオブジェクト(@form)の中にあり、 位置

などがCオブジェクトの位置から相対的に決まるオブジェクトD (@
button や @memo)があるとき、CはDのペアレントである、という。

※2:配置方法:ALTOP はペアレントのクライアント領域(子オブジェク
トを表示する場所)の上の方に横幅は目一杯で表示する。ALBOTTOM
であれば下に目一杯。 ALLEFT なら左に目一杯の高さで配置。
ALCLIENT は ALTOP などで配置された残り全部に表示する。

※3:attr:@button のイベントハンドラ(@button.on_click)で @memo
の属性を書き換えるような場合($foo.memo.text = caption)、フ
ォームの属性として @memo が外部から参照可能でなければならな
いので、attr で外部に公開する。
=end

2000-04-14(金)

全角、半角を含んだ日本語文字列を文字単位で分解するには、

"漢(kanji)字".scan(/./){ |c| print c,"," }

2000-04-12(水)

Do_Unix:は
<A HREF="../lzh/index.htm">たけ(tk)のLZH</A>の

<A HREF="../lzh/do_unix.lzh">do_unix.lzh : 9,616 00-01-16 18:08</A><P>

にあります。

2000-04-12(水)

ボタン一発 Ruby。WINのデスクトップにアイコンを置いて、 ボタン一
発でルビーのスクリプトを実行できないか、と思ったら、BATファイルを
作ってしまえばいいんですね。

;;;; FtpHDs.bat ;;;;
f:
cd \ruby
Do_Unix Ruby ftphds.rb
;;;;
で、マイコンピュータでそのファイルを右クリックしてショートカットを
作成して、ショートカットをデスクトップへドラッグアンドドロップすれば
よい。
* ただ、これだと、WIN窓が開いてしまう。非表示でバックグラウン
ドで実行、という設定が可能ではあるのだが、そうすると、他のWIN
プログラムでエラーがでるので、結局、だめみたい。

* 非表示=アイコンを右クリック→プロパティ→プログラム→実行時の
大きさで、最小化の状態としておけば、なんとなく、バックグラウンド
で実行しているような感じになる。

* バックグラウンドで実行するにはプロパティ→その他→バックグラウ
ンド時の設定、で「常に実行を中断」を解除する。

2000-03-29(水)
##
## which.rb
##
if ( RUBY_PLATFORM =~ /win/i )
require 'Win32API'
MAX_PATH_SIZE = 513
def which( cmd , searchPath=nil , convertSFN=true )
paths = searchPath
if paths
paths = paths.join(';') if paths.is_a? Array
##
## 「$:」には「//a/bcd」形式で入っているので、
## "//a/bcd" → "a:/bcd"
## ↓ 四苦八苦している。こんなもの? ↓

paths = searchPath.gsub( /\/\/\w\// ) { $&.to_s[2].chr+":/" }

end
##
## 入力が「/」でも出力は「\」になる。
##

buff = 0.chr * MAX_PATH_SIZE
Win32API.new( 'kernel32' , 'SearchPathA' , %w(P P P N P P) , "N" ).
Call( paths, cmd , 0 , buff.size , buff , 0 )

result = buff.split(0.chr)[0]
return nil unless result
##
## スペース入りの "Program Files" などはうざったいので、
## SFNに変換する。
##

if convertSFN
Win32API.new( 'kernel32' , 'GetShortPathName' , %w(P P N) , "N" ).
Call( result, buff , buff.size )

result = buff.split(0.chr)[0]

end
##
## 戻りは unix 流の「/」に変換する。
##

result = result.gsub( '\\\\','/') if result

end
else ## for UNIX
def which( cmd , searchPath=nil )
return `which #{cmd}` unless searchPath
##
## 実際にはここで判断する。
##

if searchPath.is_a? Array
searchPath.each{ |paths|
result = which( cmd , paths )
return result if result

}
return nil

end
##
## Array にして再帰呼び出し。
##

paths = searchPath
paths = ENV['path'] unless searchPath
paths.split(':').each{ |dir|
result = dir+'/'+cmd
return result if FileTest.file? result

}
return nil

end
end

if __FILE__ == $0
p which("Ruby.exe", nil, false )+' '+$0
p which("Notepad.exe", nil, false )+' '+$0
system( which("Notepad.exe")+' '+$0 )
end

2000-03-25(土)
ちょっと小遣いの計算をしようと思って、計算方法を日本語で書いていたら、

そのまま実行できてしまいました。

Ruby って、ヘン!!。

#### 小遣い.rb ####

当初の財布の中身 = 1200
今月の小遣い = 30000
タバコ代 = 500*30
本代 = 12300
実際の残り = 1000

収入合計 = 当初の財布の中身 + 今月の小遣い
支出合計 = タバコ代 + 本代

あるべき残り = 収入合計 - 支出合計

行方不明のお金 = あるべき残り - 実際の残り

local_variables.each{ |変数| print( 変数," = ",eval(変数),"\n" )}

####
* 実行結果
Do_Unix Ruby f:/ruby/小遣い.rb

当初の財布の中身 = 1200
今月の小遣い = 30000
タバコ代 = 15000
本代 = 12300
実際の残り = 1000
収入合計 = 31200
支出合計 = 27300
あるべき残り = 3900
行方不明のお金 = 2900

2000-03-21(火)

仕事場で FtpHD.rb の動作確認。10分くらいで10個ほどのディレクト
リの更新が終わったので、まずまずのスピード。
しかし何ですよ、ダイアルアップ契約のプロバイダでFTP関係のプログ
ラムを作るのはきついですね。デバッグ中に接続できなくなってしまったの
で調べたら、7日で3000円の制限を越えました、よって接続中止、なん
ていうことになっていた。ダイアルアップルータに設定していた過剰接続防
止の制限にかかってしまったわけ。制限をクリアして続行したけど、青くな
ったぞなもし。

2000-03-20(月)

FtpHD.rb を公開した。サブディレクトリにも対応した。

−−

ニフティのほうではCVSについていろいろお話ししていた。CVSとい
うのは(Concurrent Version System)で、 本来はプログラム開発のバージ
ョン管理のためのプログラムなのだが、プログラムの一般への配布の仕組み
としても使えそうだ、ということなのではないかと思う。(誤解かもしれな
いが・・)。たけ(tk)は使ったことがないので、いろいろ聞いている段階。

2000-03-19(日)

archives.rb のLZHの pack につき r2 (ディレクトリ再帰)オプショ
ンを有効にした。
オプションの指定方法は文字列で次のようにした。
A. 統合アーカイバ方式の識別子を空白で区切って指定する。
'i0 x1'
B. 当該アーカイバの固有のオプションは「-」を付けて指定する。
'-i0 -x1'
C. 混在してもよい。が、矛盾しても関知しない。

とまあ、archives.rb は一歩前進したが、FtpHD.rb の方はそれだけでは
サブディレクトリ対応にはならないことが分かった。
−−

今日から日記を付けます。

昨日は FtpHD.rb というのを作っていた。プロバイダからもらったホーム
ページ用のエリアの裏ページを使って、仕事場と自宅でファイルを共用しよ
うというもの。各ディレクトリごとに10日分のファイルをLZHにまとめ
て、プロバイダのエリアに保存しておき、LZHをダウンロードし、ローカ
ルディレクトリを比較して更新し、アップロードし、展開するというもの。
スレッドを使って、複数のディレクトリを一括して処理するようになって
いる。とはいっても、Ruby のスレッドはイベント待ちの間の同時実行(Ftp
の応答待ちのときに別の処理をすること)はできないようなので(※1)、
どちらかというと、FTPサイトにログインしている時間を少なくするため
に使っている。
※1:イベント待ちの間の同時実行ができない、ということの確認はして
いない。どうやって確認するかがよくわからない。が、なんとなく、
応答があるまでスレッドが切り替わらないような感じがする。・・
しかし、当然ながら、普通の同時実行はする。同時実行すると、経
過表示中に他のスレッドの経過報告が入ってくる。表示が混乱する
のが嫌で、同時実行を制限していたりする。・・

※2:FTPサイトにログインしている時間の縮小は、各ローカルディレ
クトリの読み込みを全部終わってから、ログインし、各ディレクト
リで必要な処理が終わったらただちにログアウトする、その後ゆっ
くり展開する。という仕組み。

まだ、自家用のパスワードなどが組み込んであるので、公開は出来ません。
すぐに公開できるようになると思います。
サブディレクトリに対応していないのが痛い。archives.rb を使っている
が、これが対応していないのがネックになっている。
あと、WIN流のマウスクリックで実行する方法が分からない。今はVZ
エディタから Ctrl+OE で実行している。

powered by VZ editor (DOS) .. (^_^;) .. and ..
<A HREF="http://www.asahi-net.or.jp/~qs7e-kmy/kojiro.html">
<IMG SRC="../image/kojilink.gif"
ALT="Link to KOJIRO"

WIDTH="88" HEIGHT="31" BORDER="0"

NATURALSIZEFLAG="0" ALIGN="BOTTOM">
</A>.. and ..

<A HREF="http://home.jp.netscape.com/ja/">
<IMG SRC="../image/mozi.gif" HEIGHT=34 WIDTH=34>
</A><P>

<!-- ローカルファイルでも、カウンタを表示すると、アクセスしちゃうな・・。 -->

<SCRIPT LANGUAGE="JavaScript">
if ( location.protocol == "file:"){
document.write('【カウンタ省略】 .. accessing to local')

}else{
document.write('<IMG SRC="http://mcgi1.nifty.ne.jp/cgi-bin/counter.cgi?u=GGB03124&p=1&c=4">')

}
</SCRIPT>
<P>

</BODY></HTML>