2009年03月05日 hda: read_intr: status=0x59 { DriveReady SeekComplete DataRequest Error } [長年日記]
_ hda: read_intr: status=0x59 { DriveReady SeekComplete DataRequest Error }
hda: read_intr: status=0x59 { DriveReady SeekComplete DataRequest Error } hda: read_intr: error=0x40 { UncorrectableError }, LBAsect=12266756, sector=11688416 end_request: I/O error, dev 03:03 (hda), sector 11688416 hda: read_intr: status=0x59 { DriveReady SeekComplete DataRequest Error } hda: read_intr: error=0x40 { UncorrectableError }, LBAsect=12266764, sector=11688424 end_request: I/O error, dev 03:03 (hda), sector 11688424
lib100にて嫌なメッセージ発見。mke2fs -c で当面しのぐか、HDを買い替えるか思案のしどころ。ともかく、このサーバがこけると我が家がインターネットから隔絶されることと、このブログを始め、さまざまなサービスが停止してしまうことは紛れもない事実。
2009年03月09日 lib100(myh.no-ip.org)ハードディスク(一応)復旧 [長年日記]
_ lib100(myh.no-ip.org)ハードディスク(一応)復旧
先日、I/O errorを出していたlib100のハードディスクを
mke2fs -c -j /dev/hda3
にてフォーマットし直して、バックアップからリストアしなおした。
リストア前に
cat /dev/zero >ほげほげ
をリダイレクト先を変えながら4回実施して(1ファイル2GBまでなので...)、100%になるまで書き込みを実施しI/O errorが発生しない事を確認。いちおう -c オプションによるバッドセクタの割り当ては成功しているよう。
ただし(やはり?)、
cat /dev/hda >/dev/null
で読み出すと先日と同様のI/O errorが特定セクターで発生しているので、物理的にヘタリかけているのは紛れもない事実のよう。
後は、被害の広がりがゆっくり進行するのを期待するのみ。
2009年03月13日 ruby(1.8.x)儂(わし)的解釈によるメモ [長年日記]
_ ruby(1.8.x)儂(わし)的解釈によるメモ(基本編)
使われている用語等は基本的にテキトーなもの。あまり真に受けないように。あくまで儂(わし)的なrubyプログラミングで困らない程度のTipsの蓄積。
#! /usr/bin/ruby #
引数
# p ARGV puts "1個目の引数 = #{ARGV[0]}" puts "2個目の引数 = #{ARGV[1]}" puts "3個目の引数 = #{ARGV[2]}" puts "引数の個数 = #{ARGV.size}"
["aaa", "bbb"] 1個目の引数 = aaa 2個目の引数 = bbb 3個目の引数 = 引数の個数 = 2
ワーク(文字列, 数値)
# work = "abcdef" puts "work = #{work}" puts "work[2] = #{work[2]}" puts "work[2].chr = #{work[2].chr}" puts "work[2..3] = #{work[2..3]}" puts "work[2,3] = #{work[2,3]}" work = 12345 puts "work = #{work}" puts "== work is #{work} ==" puts '== work is #{work} =='
work = abcdef work[2] = 99 work[2].chr = c work[2..3] = cd work[2,3] = cde work = 12345 == work is 12345 == == work is #{work} ==
配列
# work = [] work = ["aaa", 12345, "ccc", 23456, "eee", 34567] work2 = ["AAA", 54321, "ccc", 23456, "EEE", 76543] p work p work2 puts "work[0] = #{work[0]}" puts "work[1] = #{work[1]}" puts "work[2] = #{work[2]}" puts "work[3] = #{work[3]}" puts "work[4] = #{work[4]}" puts "work[5] = #{work[5]}" puts "work.size = #{work.size}" puts "work[2..3] = #{work[2..3]}" puts "work[2,3] = #{work[2,3]}" puts "work & work2 = #{work & work2}" puts "work | work2 = #{work | work2}" puts "work + work2 = #{work + work2}" puts "work - work2 = #{work - work2}"
["aaa", 12345, "ccc", 23456, "eee", 34567] ["AAA", 54321, "ccc", 23456, "EEE", 76543] work[0] = aaa work[1] = 12345 work[2] = ccc work[3] = 23456 work[4] = eee work[5] = 34567 work.size = 6 work[2..3] = ccc23456 work[2,3] = ccc23456eee work & work2 = ccc23456 work | work2 = aaa12345ccc23456eee34567AAA54321EEE76543 work + work2 = aaa12345ccc23456eee34567AAA54321ccc23456EEE76543 work - work2 = aaa12345eee34567
ハッシュ
# work = {} work['apple'] = "red" work['lemon'] = "yellow" work['melon'] = "green" p work puts "work['apple'] = #{work['apple']}" puts "work['lemon'] = #{work['lemon']}" puts "work['melon'] = #{work['melon']}" work2 = {"apple", "red", "lemon", "yellow", "melon", "green"} p work2 puts "work2['apple'] = #{work2['apple']}" puts "work2['lemon'] = #{work2['lemon']}" puts "work2['melon'] = #{work2['melon']}" work3 = {"apple" => "red", "lemon" => "yellow", "melon" => "green"} p work3 puts "work3['apple'] = #{work3['apple']}" puts "work3['lemon'] = #{work3['lemon']}" puts "work3['melon'] = #{work3['melon']}"
{"apple"=>"red", "melon"=>"green", "lemon"=>"yellow"} work['apple'] = red work['lemon'] = yellow work['melon'] = green {"apple"=>"red", "melon"=>"green", "lemon"=>"yellow"} work2['apple'] = red work2['lemon'] = yellow work2['melon'] = green {"apple"=>"red", "melon"=>"green", "lemon"=>"yellow"} work3['apple'] = red work3['lemon'] = yellow work3['melon'] = green
if文
# work = {"apple" => "red", "lemon" => "yellow", "melon" => "green"} #if (work['lemon'] == "red") #if (work['lemon'] != "red") #if (work['lemon'] > "red") #if (work['lemon'] <"red") #if (work['lemon'] >= "red") #if (work['lemon'] <= "red") if (work['lemon'] == "red") puts "lemon is red" elsif (work['lemon'] == "yellow") puts "lemon is yellow" else puts "lemon is not red and yellow" end
lemon is yellow
if文(パターンマッチング)
# work = {"apple" => "red", "lemon" => "yellow", "melon" => "green"} if (/^y.*w$/ =~ work['lemon']) puts "lemon is y.*w" else puts "lemon is not y.*w" end
lemon is y.*w
case文
# work = {"apple" => "red", "lemon" => "yellow", "melon" => "green"} case work['lemon'] when "red" puts "lemon is red" when "yellow" puts "lemon is yellow" else puts "lemon is not red and yellow" end
lemon is yellow
while文
# work = ["melon", "lemon", "apple"] i = 0 while (i < 3) if (work[i] == "apple") # next # redo break end puts work[i] i += 1 end
melon lemon
for文
# work = ["melon", "lemon", "apple"] #for i in work for i in work.sort puts i end
apple lemon melon
for文(2)
# work = ["melon", "lemon", "apple"] for i in 0..2 puts work[i] end
melon lemon apple
each文
# work = ["melon", "lemon", "apple"] work.each do |i| puts i end
melon lemon apple
for文(ハッシュの添字でループ)
# work = {"melon", "green", "lemon", "yellow", "apple", "red"} #for i in work.keys for i in work.keys.sort puts work[i] end
red yellow green
each文(ハッシュ)
# work = {"melon" => "green", "lemon" => "yellow", "apple" => "red"} work.each do |key, val| puts key + "=" + val end
apple=red lemon=yellow melon=green
tr文(文字置換)
# work = "ABCDEFG" puts "work = #{work}" puts "work.tr('C-E', 'c-e') = #{work.tr('C-E', 'c-e')}"
work = ABCDEFG work.tr('C-E', 'c-e') = ABcdeFG
gsub文(文字列置換)
# work = "ABCDEFG" puts "work = #{work}" puts "work.gsub(/C.*E/, 'cde') = #{work.gsub(/C.*E/, 'cde')}"
work = ABCDEFG work.gsub(/C.*E/, 'cde') = ABcdeFG
gsub文(文字列置換)(2)
# work = "ABCDEFG" puts "work = #{work}" puts "work.gsub(/(C.*E)/){'==' + $1 + '=='} = #{work.gsub(/(C.*E)/){'==' + $1 + '=='}}"
work = ABCDEFG work.gsub(/(C.*E)/){'==' + $1 + '=='} = AB==CDE==FG
gsub文(文字列置換)(3)
# work = "%41%42%43+%44%45%46" puts "work(URL encoded) = #{work}" work = work.tr("+", " ") work = work.gsub(/%([0-9a-zA-Z][0-9a-zA-Z])/){$1.hex.chr} puts "work(URL decoded) = #{work}"
work(URL encoded) = %41%42%43+%44%45%46 work(URL decoded) = ABC DEF
gsub文に関して追記 2009.04.07
(a, b) = "aaa=".split("=") b.gsub("bbb", "")
上記を実行すると、
./test.rb:?: private method `gsub' called for nil:NilClass (NoMethodError)
のようなエラーが発生する。bが空文字列なのがいけないらしい。これを回避するには、
(a, b) = "aaa=".split("=") b.to_s.gsub("bbb", "")
の様に明示的にbを文字列クラスに変換してやるとよい。
split文(文字列分割)
# work = "apple-=-lemon-=-melon-=-orange" puts "work = #{work}" work2 = work.split('-=-') puts "work2 = work.split('-=-')" puts "work2[0] = #{work2[0]}" puts "work2[1] = #{work2[1]}" puts "work2[2] = #{work2[2]}" puts "work2[3] = #{work2[3]}"
work = apple-=-lemon-=-melon-=-orange work2 = work.split('-=-') work2[0] = apple work2[1] = lemon work2[2] = melon work2[3] = orange
split文(文字列分割:分割制限有り)
# work = "apple-=-lemon-=-melon-=-orange" puts "work = #{work}" (var1, var2, var3) = work.split("-=-", 3) puts "(var1, var2, var3) = work.split('-=-', 3)" puts "var1 = #{var1}" puts "var2 = #{var2}" puts "var3 = #{var3}"
work = apple-=-lemon-=-melon-=-orange (var1, var2, var3) = work.split('-=-', 3) var1 = apple var2 = lemon var3 = melon-=-orange
length, index, rindex文(文字列長、位置取得)
# work = "apple apple apple" puts "work = #{work}" puts "work.length = #{work.length}" puts "work.index('apple') = #{work.index('apple')}" puts "work.rindex('apple') = #{work.rindex('apple')}"
work = apple apple apple work.length = 17 work.index('apple') = 0 work.rindex('apple') = 12
to_?文(整数化、実数化、文字列化)
# works = "123" puts "works = #{works}(is string)" puts "works.to_i * 10 = #{works.to_i * 10}" puts "works.to_f * 10 = #{works.to_f * 10}" puts "works.to_f.to_s + works.to_f.to_s = #{works.to_f.to_s + works.to_f.to_s}"
works = 123(is string) works.to_i * 10 = 1230 works.to_f * 10 = 1230.0 works.to_f.to_s + works.to_f.to_s = 123.0123.0
ファイル(書き込み:puts)
# f = open("junk.txt", "w") f.puts("line1") f.puts("line2\n") f.puts("line3\n\n") f.close
ファイル(書き込み:write)
# f = open("junk2.txt", "w") f.write("line1") f.write("line2\n") f.write("line3\n\n") f.close
ファイル(行読み込み:gets from puts)
# f = open("junk.txt", "r") while (r = f.gets) p r p r.chomp r.chomp! p r end f.close
"line1\n" "line1" "line1" "line2\n" "line2" "line2" "line3\n" "line3" "line3" "\n" "" ""
ファイル(行読み込み:gets from write)
# f = open("junk2.txt", "r") while (r = f.gets) p r p r.chomp r.chomp! p r end f.close
"line1line2\n" "line1line2" "line1line2" "line3\n" "line3" "line3" "\n" "" ""
ファイル(ランダム読み:read)
# f = open("junk.txt", "r") #f.seek(6) f.pos = 6 r = f.read(12) p r f.close
"line2\nline3\n"
ファイル(書き込み:putc)
# work = "line1\nline2\nline3\n" f = open("junk.txt", "w") for i in 0..(work.length-1) f.putc(work[i]) end f.close
ファイル(行読み込み:getc from putc)
# f = open("junk.txt", "r") while (ch = f.getc) print " #{ch.chr}" end f.close
l i n e 1 l i n e 2 l i n e 3
【追記】標準入力、標準出力、エラー出力
標準入力、標準出力、エラー出力に対しては、それぞれSTDIN、STDOUT、STDERRが自動的にオープンされているので、いきなり
STDOUT.puts("ほげほげ")
とか、
r = STDIN.gets
みたいに書ける。
ファイル(外部コマンド実行)
# f = open("|ls -al|head -5", "r") while (r = f.gets) puts "==" + r.chomp + "==" end f.close
==合計 40== ==drwxr-xr-x 2 m-ito m-ito 4096 2009-03-13 19:45 .== ==drwxr-xr-x 3 m-ito m-ito 4096 2009-03-13 18:24 ..== ==-rw-r--r-- 1 m-ito m-ito 2896 2009-03-13 19:45 junk== ==-rw-r--r-- 1 m-ito m-ito 18 2009-03-13 19:45 junk.txt==
外部コマンド実行
# for i in `ls -al|head -5` puts "==" + i.chomp + "==" end
==合計 40== ==drwxr-xr-x 2 m-ito m-ito 4096 2009-03-13 19:45 .== ==drwxr-xr-x 3 m-ito m-ito 4096 2009-03-13 18:24 ..== ==-rw-r--r-- 1 m-ito m-ito 2896 2009-03-13 19:45 junk== ==-rw-r--r-- 1 m-ito m-ito 18 2009-03-13 19:45 junk.txt==
追記(2011/07/04) : ruby-1.9.xだと(Stringクラスからeachメソッドが削除されたので?)上記の書き方はできない。以下のようにする。
# `ls -al|head -5`.each_line do |i| puts "==" + i.chomp + "==" end
popen文(外部コマンド実行)
#! /usr/bin/ruby io = IO.popen("cat -n", "r+") io.puts("line1") io.puts("line2") io.puts("line3") ##io.flush # flushをするのが確実。 io.close_write # ただし、起動プログラムの作りによるとclose_writeする必要がある。 r = io.gets puts r r = io.gets puts r r = io.gets puts r io.close
1 line1 2 line2 3 line3
system文(外部コマンド実行)
# system("ls -al|head -5")
合計 40 drwxr-xr-x 2 m-ito m-ito 4096 2009-03-13 19:45 . drwxr-xr-x 3 m-ito m-ito 4096 2009-03-13 18:24 .. -rw-r--r-- 1 m-ito m-ito 3657 2009-03-13 19:45 junk -rw-r--r-- 1 m-ito m-ito 18 2009-03-13 19:45 junk.txt
print文各種
# work = "ABCDEFG" p work puts work print work + "\n" printf("%s %d %f\n", work, 123, 123.456)
"ABCDEFG" ABCDEFG ABCDEFG ABCDEFG 123 123.456000
例外処理
全てのエラーをトラップする場合
begin エラーを検出したい処理 rescue => e エラー検出時のトラップ処理 put e else エラー未検出時の処理 ensure エラーの検出のいかんにかかわらず行う処理 end
特定のエラーをトラップする場合
begin エラーを検出したい処理 rescue Errno::EEXIST => e エラー検出時のトラップ処理 put e else エラー未検出時の処理 ensure エラーの検出のいかんにかかわらず行う処理 end
「=>e」は省略可能。
ファイル操作
# File.umask(022) File.chmod(0777, "junk.txt") File.rename("junk.txt", "junk3.txt") File.unlink("junk2.txt") File.unlink("junk3.txt")
mkdir, rmdir(ディレクトリ操作)
# retry_max = 3 retry_cnt = 0 begin Dir.mkdir("lock.dir", 0755) rescue Errno::EEXIST puts "lock NG" retry_cnt += 1 if (retry_cnt < retry_max) retry else puts "lock give up!" end else puts "lock OK" ensure Dir.rmdir("lock.dir") end
lock OK
関数定義
# def myfunc(v1="defval1", v2="defval2") local_work = "initialized in myfunc" puts "$Global_work = #{$Global_work}" puts v1 puts v2 return "ok" end $Global_work = "initialized in main" local_work = "initialized in main" puts myfunc() puts myfunc("poipoi", "hogehoge") puts "local_work = #{local_work}"
$Global_work = initialized in main defval1 defval2 ok $Global_work = initialized in main poipoi hogehoge ok local_work = initialized in main
クラス定義
# class Enzan attr_accessor :x, :y attr_reader :x_readonly, :y_readonly attr_writer :x_writeonly, :y_writeonly def initialize(i=100, j=200) @x = i @y = j end def tasu @@global_in_class_work = @x + @y return @x + @y end def hiku @@global_in_class_work = @x - @y return @x - @y end def compute(i) case i when "+" @@global_in_class_work = @x + @y return @x + @y when "-" @@global_in_class_work = @x - @y return @x - @y else return 0 end end def global_in_class_work return @@global_in_class_work end end e = Enzan.new puts e.tasu puts e.hiku puts e.compute("+") f = Enzan.new(10, 20) puts f.tasu puts f.hiku puts f.compute("+") f.x = 1000.0 f.y = 2000.0 puts f.tasu puts f.hiku puts f.compute("-") puts e.global_in_class_work
300 -100 300 30 -10 30 3000.0 -1000.0 -1000.0 -1000.0
クラス定義(継承有り)
# class Oya def msg1(arg = "Oya.msg1") puts arg + " from Oya.msg1" end def msg2(arg = "Oya.msg2") puts arg + " from Oya.msg2" end end class Kodomo < Oya def msg2(arg = "Kodomo.msg2") super(arg) puts arg + " from Kodomo.msg2" end def msg3(arg = "Kodomo.msg3") puts arg + " from Kodomo.msg3" end end msg = Kodomo.new msg.msg1("message 1") msg.msg2("message 2") msg.msg3("message 3")
message 1 from Oya.msg1 message 2 from Oya.msg2 message 2 from Kodomo.msg2 message 3 from Kodomo.msg3
環境変数取得
# puts ENV['PATH']
/home/m-ito/bin:/home/m-ito/etc:/home/m-ito/prov/bin:/usr/local/bin:/usr/local/etc:/usr/local/sbin:/usr/bin:/usr/etc:/bin:/etc:/usr/sbin:/sbin:/usr/X11R6/bin:/opt/gnome/bin:/opt/kde/bin:/usr/local/jvim2.0/bin:/usr/local/canna/bin:/usr/local/lib/w3m:/usr/local/ssl/bin:/usr/local/mrtg/bin:/usr/local/Adobe/Reader8/bin
日時時刻取得
# day = Time.now puts day puts day.year puts day.month puts day.day puts day.hour puts day.min puts day.sec puts day.wday
Fri Mar 13 19:45:44 +0900 2009 2009 3 13 19 45 44 5
kill文(シグナル送信)
# begin Process.kill("TERM", 1234) rescue Errno::ESRCH puts "no such process" else puts "signal send ok" ensure end my_pid = $$ begin Process.kill(0, my_pid) rescue Errno::ESRCH puts "pid(#{my_pid}) is dead" else puts "pid(#{my_pid}) is alive" ensure end
no such process pid(3544) is alive
nkf文(文字コード変換)
# require "nkf" puts NKF.nkf("-S -X -e", "\x8a\xbf\x8e\x9a\x82\xc5\x82\xb7")
漢字です
timeout文
# require "timeout" begin timeout(3){ sleep 10 } rescue Timeout::Error puts "timeout happened!" else puts "10sec sleepd" ensure end
timeout happened!
yield(イテレータ作成)
# def hoge(arg1, arg2) puts "arg1=#{arg1}, arg2=#{arg2}" yield(arg1, arg2, arg1 * arg2) end hoge(12,13) do |v1, v2, v3| puts "v1=#{v1}, v2=#{v2}, v3=#{v3}" end
arg1=12, arg2=13 v1=12, v2=13, v3=156
_ ruby(1.8.x)儂(わし)的解釈によるメモ(クライアント編)
#! /usr/bin/ruby require "socket" s = TCPSocket.new("localhost", 12345) s.sync = true s.puts "#{ARGV[0]}" print s.gets s.puts "Q"
_ ruby(1.8.x)儂(わし)的解釈によるメモ(サーバ編)
#! /usr/bin/ruby require 'socket' def daemon # # バックグラウンドに移行する # プロセスグループリーダ(、セッションリーダ)でなくなる -> 次のsetsidが成功する条件 # 制御端末はまだ持っている if (pid = fork) exit 0 end # # 新しいセッションのリーダとなり制御端末を持たなくなる # 新しいプロセスグループのリーダとなる Process.setsid # # セッションリーダ、プロセスグループリーダでなくなる # よって、再び制御端末を持つ事ができなくなる if (pid = fork) exit 0 end # Dir.chdir("/") File.umask(0000) STDIN.close STDOUT.close STDERR.close Signal.trap("SIGTERM"){ exit 0 } Signal.trap("SIGHUP"){ exit 0 } Signal.trap("SIGINT"){ exit 0 } end daemon port = 12345 gs = TCPServer.open(port) while true ns = gs.accept # p ns.peeraddr Thread.start(ns) do |s| s.sync = true while l = s.gets break if /^q/i =~ l l.chomp! s.puts "#{l.swapcase}" end s.close end end
_ ruby(1.8.x)儂(わし)的解釈によるメモ(基本編の追加編)
times文
3.times do |i| puts i end
0 1 2
step文
1.step(10, 3) do |i| puts i end
1 4 7 10
loop文
i = 0 loop do puts i i += 1 if (i > 3) break end end
0 1 2 3
module文
module Mymodule def msg(i) puts "#{i} is hogehoge" end def msg2(i) puts "#{i} is poipoi" end module_function :msg, :msg2 end class Myclass include Mymodule def initialize(i) @msg = i end def hoge msg(@msg) end def poi msg2(@msg) end end mc = Myclass.new("hogepoi") mc.hoge mc.poi
hogepoi is hogehoge hogepoi is poipoi
演算式(余り:%, べき乗:**)
puts 12 % 5 puts 2 ** 8
2 256
ビット演算式
a = 0 printf("%d\n", ~a) a = 0x77 b = 0xee printf("%x\n", a & b) a = 0x77 b = 0xee printf("%x\n", a | b) a = 0x77 b = 0xee printf("%x\n", a ^ b) a = 0x77 printf("%x\n", a << 1) a = 0xee printf("%x\n", a >> 1)
-1 66 ff 99 ee 77
条件文(結合)
a = 10 b = 20 if (a < 15 && b > 15) puts "true" else puts "false" end if (a < 15 || b < 15) puts "true" else puts "false" end
true true
配列操作
a = ["w", "x", "y", "z"] a[1, 2] = ["a", "b"] p a
["w", "a", "b", "z"]
a = ["w", "x", "y", "z"] a[1, 0] = ["a", "b"] p a
["w", "a", "b", "x", "y", "z"]
a = ["w", "x", "y", "z"] a.push("a") p a
["w", "x", "y", "z", "a"]
p a.pop p a
"a" ["w", "x", "y", "z"]
p a.shift p a
"w" ["x", "y", "z"]
a = ["a", "x", "b", "x", "c"] a.delete("x") p a
["a", "b", "c"]
a = ["a", "x", "b", "x", "c"] a.delete_at(2) p a
["a", "x", "x", "c"]
a = ["a", "x", "b", "x", "c"] p a.uniq
["a", "x", "b", "c"]
p "aaa" <=> "bbb" p "bbb" <=> "aaa" p "aaa" <=> "aaa" p a.sort do |a, b| a <=> b end
-1 1 0 ["a", "b", "c", "x", "x"]
文字列の囲み
s = "aaaaa" puts %Q{" ' #{s} ' "} puts %q{" ' #{s} ' "}
" ' aaaaa ' " " ' #{s} ' "
ヒアドキュメント
s = <<EOD this is line1 this is line2 this is line3 EOD puts s
this is line1 this is line2 this is line3
文字列操作
a = " ABcdefgabcdeFG " puts a.delete("cde") puts a.strip puts a.upcase puts a.downcase puts a.swapcase
ABfgabFG ABcdefgabcdeFG ABCDEFGABCDEFG abcdefgabcdefg abCDEFGABCDEfg
ハッシュ操作
h = {"apple"=>"red", "lemon"=>"yellow", "melon"=>"green"} p h.has_key?("lemon") p h.has_value?("yellow") p h.empty?
true true false
ハッシュ初期化
h = {"apple"=>"red", "lemon"=>"yellow", "melon"=>"green"} i = h h.clear p h p i
{} {}
h = {"apple"=>"red", "lemon"=>"yellow", "melon"=>"green"} i = h h = {} p h p i
{} {"melon"=>"green", "apple"=>"red", "lemon"=>"yellow"}
正規表現
a = "abcde\nfghijk\nlmnop" p /^f.*k$/ =~ a p /\Af.*k\Z/ =~ a p /^a.*p$/ =~ a p /\Aa.*p\Z/m =~ a
6 nil nil 0
繰り返し(文字列scan)
a = "axxxb...ayyyb...azzzb" a.scan(/a...b/) do |i| puts i end
axxxb ayyyb azzzb
同期出力
STDOUT.puts "aaa" STDOUT.flush STDOUT.sync = true STDOUT.puts "bbb"
aaa bbb
ディレクトリ操作
puts cd = Dir.pwd Dir.chdir("/tmp") puts Dir.pwd Dir.chdir(cd) puts Dir.pwd
/home/zaurus/tmp /tmp /home/zaurus/tmp
ディレクトリ操作(2)
dir = Dir.open("/") while (name = dir.read) puts name end dir.close
. .. bin dev etc lib mnt opt tmp var usr boot home proc sbin root
ファイル属性取得
printf("%o\n", File.stat("/etc/fstab").mode) puts File.stat("/etc/fstab").uid puts File.stat("/etc/fstab").gid puts File.stat("/etc/fstab").size puts File.stat("/etc/fstab").atime puts File.stat("/etc/fstab").mtime puts File.stat("/etc/fstab").ctime
100644 0 0 222 Sun Nov 11 23:30:54 +0900 2007 Sun Nov 11 23:30:54 +0900 2007 Sun Nov 11 23:30:54 +0900 2007
ファイル属性変更
f = open("junk.txt", "w") f.close puts atime = File.stat("junk.txt").atime puts mtime = File.stat("junk.txt").mtime File.utime(atime + 60, mtime + 60, "junk.txt") puts atime = File.stat("junk.txt").atime puts mtime = File.stat("junk.txt").mtime File.unlink("junk.txt")
Sat Mar 14 18:53:35 +0900 2009 Sat Mar 14 18:53:35 +0900 2009 Sat Mar 14 18:54:35 +0900 2009 Sat Mar 14 18:54:35 +0900 2009
ファイル属性変更(2)
#f = open("junk.txt", "w") #f.close #File.chown(0, 0, "junk.txt") #File.unlink("junk.txt")
ファイルテスト
puts File.exist?("/etc/fstab") puts File.file?("/etc/fstab") puts File.directory?("/etc/fstab") puts File.readable?("/etc/fstab") puts File.writable?("/etc/fstab") puts File.executable?("/etc/fstab") puts File.zero?("/etc/fstab") puts File.size("/etc/fstab")
true true false true false false false 222
ファイル名操作
puts File.basename("/usr/local/doc/ruby.doc", ".doc") puts File.dirname("/usr/local/doc/ruby.doc") puts File.expand_path("./junk.txt")
ruby /usr/local/doc /home/root/usr/local/home/zaurus/tmp/junk.txt
eval文
#! /usr/bin/ruby def func_print(str) print str end eval_str = ARGV[0] + '("hello world\n")' eval eval_str
$ ./evaltest.rb func_print hello world
取り扱いに注意しないと、いろんな物を注入(Injection)されちゃう。
_ ruby(1.8.x)儂(わし)的解釈によるメモ(CGI編)
#! /usr/bin/ruby # # 産まれて初めてのrubyによるCGIプログラム... # require "cgi" require "nkf" cgi = CGI.new("html3") in1 = NKF.nkf("-X -e", cgi['in1']) cgi.out({"type" => "text/html", "charset" => "euc-jp"}){ cgi.html("PRETTY" => true){ cgi.head(){ cgi.title(){"rubytest1"} } cgi.body(){ cgi.div({"align" => "center"}){ "rubytest1" } + CGI.escapeHTML("Input is #{in1}") + cgi.br() + cgi.form({"action" => "rubytest1.cgi", "method" => "post"}){ cgi.input({"type" => "text", "name" => "in1", "id" => "in1"}) + cgi.input({"type" => "submit", "value" => "ok"}) } } } } exit 0
_ ruby(1.8.x)儂(わし)的解釈によるメモ(未検証)
pack, unpack
arry = [0x41, 0x42, 0x43] # A,B,C buf = arry.pack("C3") p buf
buf = sock.read(4) arry = buf.unpack("N") # Network byte order Integer(BIG ENDIAN) p arry[0]
2009年03月31日 Ajax儂(わし)的解釈によるメモ [長年日記]
_ Ajax儂(わし)的解釈によるメモ
ウェブアプリを作る時はw3mでも支障無く動くことをモットーとしている。それゆえWeb2.0だとかAjaxというようなキーワードがもてはやされる時代になっても、かたくなに目を背けてやってきた。しかし、他人に「何故お前は(Web2.0||Ajax)を(やらん||できん)のだ」と問われた時に、明解に理由を説明できるだけの知識は持ち合わせていなかった。
ここいらで少しWeb2.0だとかAjaxという世界に寄り道してみようと思う。そう「毒をもって毒を制す」という言葉も在るではないか...。
※ 用語等の利用に関しては自分なりの解釈に元づいたものなので、あまり当てにしないでもらいたい...
とりあえずAsynchronousとJavascript
Ajax = Asynchronous JavaScript + XMLという事らしいのだが、XMLは後回しにして、とりあえずAsynchronousとJavaScriptの部分を探っていきたい。
通常のウェブアプリではユーザからのデータ入力は<form>タグを介して行われ、[submit]ボタンをクリックする事でサーバ側(CGIプログラム)に入力データが渡され、サーバ側で何らかの処理が行われた後に、その結果をhtmlドキュメント形式で表現しブラウザ側に返してやる。サーバ側で処理が行われている間はブラウザ側では一切の作業ができない(旗がゆらめいたり、何かがクルクル回ったりしているだけ)。
JavascriptからXMLHttpRequest()等のオブジェクトを作成して、これを利用すると非同期通信が可能になる。つまりブラウザからサーバへリクエストを送信した後、ブラウザはサーバからのレスポンスを待つこと無くユーザの次の入力要求に答える事ができる。それではサーバのレスポンスは何処へ行ってしまうのか?。
サーバからのレスポンスは「イベント」としてブラウザに通知される。せっかちなユーザの入力を受け付ける事に専念している最中に肩を叩かれる(イベントの到着)ので、その時だけデータを受け取りに行けば良い。
非同期通信にてサーバから返されるデータはhtmlドキュメントである必要はない。もし、たった1つの項目が欲しければ、たった1つの項目だけを返してもらえば良い。
だが待て、ブラウザはhtmlドキュメント(<html>〜</html>)を表示するものではなかったか。全体のリロード無しにどうやって表示を変えるのだ?。
さて、ブラウザ内でhtmlドキュメントはDOM(Document Object Model)という形式で保持されている。タグやら文字列の入れ子構造がそのままツリー構造として存在していると考えればあながち間違いでもなかろう。ツリーの葉っぱの部分は個々のタグや文字列ということか。
JavascriptからはDOMという木の個々の葉っぱ(だけ)を書き換える事ができる。この機能のおかげで、レスポンス到着イベントのタイミングでブラウザの表示の一部分だけを(全体のリロード無しで)更新する事ができる。
以上の事が、Ajax(のXML抜きの)本質部分なのではないかと思う。
Ajax対応Javascript(htmlファイル)サンプル
http://myh.no-ip.org/~m-ito/ajaxtest1.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=euc-jp"> <title>ajaxtest1</title> <script type="text/javascript"> <!-- // ============================================================ // 私製Ajax関連ルーチン(ここから) // // 後々、別ファイルに独立させて共通ルーチンとして利用するつもり // // ============================================================ // // 非同期通信オブジェクト作成 // function ajax_createXHR(){ var xhr; try{ xhr = new ActiveXObject("Msxml2.XMLHTTP"); }catch(e){ try{ xhr = new ActiveXObject("Microsoft.XMLHTTP"); }catch(e){ try{ xhr = new XMLHttpRequest(); }catch(e){ xhr = null; } } } return xhr; }
Ajaxの肝となる非同期通信オブジェクトの生成方法はブラウザ依存、バージョン依存が激しい。肝なのに。早速に不審感がつのる。とりあえず3種類の方法を試していって、成功すればそのオブジェクトを返すといった感じ。
// // idで指定したエレメントを取得する // function ajax_gebi(id){ return document.getElementById(id); } // // tagで指定したエレメントの内、idx番目(0オリジン)の物を取得する // ただし、idx < 0の場合はgetElementsByTagName(tag)を取得する // function ajax_gebt(tag, idx){ if (idx < 0){ return document.getElementsByTagName(tag); }else{ return document.getElementsByTagName(tag).item(idx); } } // // name指定したエレメントの内、idx番目(0オリジン)の物を取得する // ただし、idx < 0の場合はgetElementsByName(name)を取得する // function ajax_gebn(name, idx){ if (idx < 0){ return document.getElementsByName(name); }else{ return document.getElementsByName(name).item(idx); } } // // idで指定したエレメント配下の子エレメントを全て削除 // function ajax_removeChilds(id){ var max = document.getElementById(id).childNodes.length; for (var i = 0; i < max; i++){ document.getElementById(id).removeChild(document.getElementById(id).childNodes.item(0)); } } // // idで指定したエレメント配下の子エレメントをstrで指定したテキストエレメントで置換 // // o 単純に文字列表示として利用することを想定している // o idで指定するエレメントは<span>であることを想定している // function ajax_setText(id, str){ ajax_removeChilds(id); document.getElementById(id).appendChild(document.createTextNode(str)); } // // idで指定したエレメント配下のテキストエレメントの文字列を取得 // function ajax_getText(id){ var text = ""; for (var i = 0; i < document.getElementById(id).childNodes.length; i++){ if (document.getElementById(id).childNodes.item(i).nodeValue){ text += document.getElementById(id).childNodes.item(i).nodeValue; } } return text; } // // idで指定したエレメントの値にstrで指定した文字列をセットする // // o idで指定するエレメントは<input>等のvalueを持つものであることを想定している // function ajax_setValue(id, str){ document.getElementById(id).value = str; } // // idで指定したエレメントの値を取得する // // o idで指定するエレメントは<input>等のvalueを持つものであることを想定している // function ajax_getValue(id){ return document.getElementById(id).value; }
とりあえずJavascriptのプログラミングは記述が長い。まぁオブジェクト、メソッド、プロパティ...等々をドットで繋げて行くスタイルをとるオブジェクト指向プログラミング言語全般に言える事かもしれないが。手が疲れるので適当なラッパールーチンを用意する。
// // idで指定したエレメントの値を送信できる形式に変換する // // o idで指定するエレメントは<input>等のvalueを持つものであることを想定している // function ajax_encodedValue(id){ return encodeURIComponent(document.getElementById(id).value); } // // idで指定したエレメントの値を通常の文字列に戻す // // o idで指定するエレメントは<input>等のvalueを持つものであることを想定している // function ajax_decodedValue(id){ return decodeURIComponent(document.getElementById(id).value); } // // strで指定した文字列を送信できる形式に変換する // function ajax_encodedString(str){ return encodeURIComponent(str); } // // strで指定した文字列を通常の文字列に戻す // function ajax_decodedString(str){ return decodeURIComponent(str); }
データはエンコードして送信する。エンコード処理にも色々あるがencodeURIComponent、decodeURIComponentの具合いが良さそう。漢字データも`?', `&', `=', `\n'等を含んだデータのやりとりもOK。また、エンコードした際に文字コードはContent-type,charsetの指定とは無関係にUTF-8に変換される。つまり、非同期通信オブジェクトを介した通信ではUTF-8が強制されるらしい。
// // CGIからのレスポンスをハッシュに取り込む // // o レスポンス形式 : 項目名=値\t項目名=値\t ... \t項目名=値 // function ajax_getResponse(xhr){ var ary = xhr.responseText.split("\t"); var kv = new Array(); var res = new Array(); var i = 0; while (i < ary.length){ kv = ary[i].split("="); res[kv[0]] = decodeURIComponent(kv[1]); i++; } return res; }
サーバ(CGI)からのレスポンスの形式にはXMLやJSONといった形式が使われる事もあるが、とりあえずシンプルな(使い慣れた)テキスト形式(項目名=値\t項目名=値\t ... \t項目名=値)を使う。項目名がハッシュのインデックスとなる配列を返す。
// // 受信完了状態取得 // function ajax_getRecvStatus(xhr){ if (xhr.readyState == 4){ if (xhr.status == 200){ return "OK"; }else{ return "NG"; } }else{ return "NOTREADY"; } }
レスポンス受信イベント(正確には状態変化のイベント)発生の状態を取得する。`OK'(正常の受信完了), `NG'(受信失敗), `NOTREADY'(受信中)の3つのステータスを返す。
// // リクエスト送信(および受信ハンドラ設定) // function ajax_sendRequest(uri, msghash, async, callbackOK, callbackNG, callbackNR){ var xhr = ajax_createXHR(); xhr.onreadystatechange = function(){ var status = ajax_getRecvStatus(xhr); if (status == "OK"){ if (!(callbackOK == null || callbackOK == "")){ callbackOK(xhr); } }else if (status == "NG"){ if (!(callbackNG == null || callbackNG == "")){ callbackNG(xhr); } }else{ if (!(callbackNR == null || callbackNR == "")){ callbackNR(xhr); } } } var msg = ""; i = 0; for (i in msghash){ if (i == 0){ msg = i + '=' + ajax_encodedString(msghash[i]); }else{ msg = msg + '&' + i + '=' + ajax_encodedString(msghash[i]); } i++; } xhr.open("POST", uri + "?dummy=" + new Date().getTime(), async); xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send(msg); return xhr; }
(ついに)リクエストを送信すると同時に受信時のコールバックを登録する。
- uriはCGIへのパス
- msgはCGIパラメータとして標準的な形式(項目名=値&項目名=値& ... &項目名=値)
- asyncは非同期通信フラグ(true | false)
- callbackOKはステータス`OK'時の処理関数
- callbackNGはステータス`NG'時の処理関数
- callbackNRはステータス`NOTREADY'時の処理関数
uri に "?dummy=" + new Date().getTime()を追加してopenしているのはキャッシュの影響でデータ更新が正常に機能しない場合の対応の為。
// // テキスト入力エレメント内のキャレット位置を取得する // function ajax_getCaretPos(elm){ var pos; if (elm.selectionStart >= 0){ elm.selectionEnd = elm.selectionStart; pos = elm.selectionStart; }else if (document.selection.createRange){ // // http://d.hatena.ne.jp/language_and_engineering/20090225/p1 // elm.focus(); // for Opera // ボックスの先頭からキャレットまでのrangeを作って,長さを調査 var range = document.selection.createRange(); range.moveStart( "character", -elm.value.length ); pos = range.text.length; } return pos; }
ウェブアプリというとユーザインターフェースが貧弱と思われがち。ブラウザと<form>タグの組合せにまかせっきりになりがちなので。Javascript + DOMを活用するとかなり使い勝手をあげる事ができる。が、やはりブラウザ依存な部分が多い。
// // [↑][↓][←][→]のイベントにより入力フォーカスを移動させる // function ajax_moveFocus(evt, upId, downId, leftId, rightId){ var target = evt.target || evt.srcElement; if (evt.keyCode == 37){ if (ajax_getCaretPos(target) == 0){ document.getElementById(leftId).focus(); return false; } }else if (evt.keyCode == 38){ document.getElementById(upId).focus(); }else if (evt.keyCode == 39){ if (ajax_getCaretPos(target) >= target.value.length){ document.getElementById(rightId).focus(); return false; } }else if (evt.keyCode == 40){ document.getElementById(downId).focus(); } return true; }
汎用機(メインフレーム)的なオンライン画面と比べるとウェブアプリって、入力項目の移動がしにくいと感じる。カーソルキーで上下左右に自由に入力項目間の移動ができないとストレスがたまる(ような気がする)。と言いながらも他人にウェブアプリの操作を説明する時には「ウェブアプリとはそういうもんです」と説明してきた自分がいるわけだが、やれば出来るもんだねぇ。ちょっぴりJavascriptが素敵に思えた。
// ============================================================ // 私製Ajax関連ルーチン(ここまで) // ============================================================ // //
ここまでのルーチンは別ファイルに保存して、汎用ルーチンとして利用するのが良いかと思う。まぁ、そういう汎用ルーチンは既にいっぱい存在するわけだけれども、どれをとっても自分にはオーバースペックであり、かつ全体を把握しきれないものを使う気にはなれない。
// // ============================================================ // ユーザコーディング(ここから) // ============================================================ // ------------------------------------------------------------ // 非同期リクエストによるテキスト電文通信 // ------------------------------------------------------------ // // 送信イベントのコールバック // // o 入力データ等から送信メッセージを組み立てる。 // o ajax_sendRequest()を発行する。 // var Xhr_send_msg = ""; function send_msg(){ var uri = "cgi-bin/ajaxtest1.cgi"; var msg = {'req':'req1', 'tx1':ajax_getValue("tx1"), 'in1':ajax_getValue("in1"), 'in2':ajax_getValue("in2") } var async = true; var callbackOK = recv_ok; var callbackNG = recv_ng; var callbackNR = null; // 受信が完了してなかった場合のコールバック Xhr_send_msg = ajax_sendRequest(uri, msg, async, callbackOK, callbackNG, callbackNR); } // // OK受信イベントのコールバック // // o 引数にメッセージリクエストオブジェクト(xhr)を指定する。 // o ajax_getResponse()でメッセージデータを取得する。 // o メッセージデータを処理する。 // function recv_ok(xhr){ res = ajax_getResponse(xhr); ajax_setValue("res_tx1", res["res_tx1"]); // textareaタグに表示 ajax_setText("res_in1", res["res_in1"]); // テキストの表示 ajax_setText("res_in2", res["res_in2"]); // テキストの表示 ajax_gebi("res_in1_font").color = "red"; // タグのパラメータ設定 ajax_gebt("font", 1).color = "blue"; // タグのパラメータ設定 } // // NG受信イベントのコールバック // // o 引数にメッセージリクエストオブジェクト(xhr)を指定する。 // o 受信に失敗した場合の処理をする。 // function recv_ng(xhr){ ajax_setText("res1", "Error1"); ajax_setText("res2", "Error2"); ajax_setValue("res3", "Error3"); }
ここまでは非同期通信による送受信のサンプル。
// ------------------------------------------------------------ // インターバルリクエストによる定期的な表示更新 // ------------------------------------------------------------ // // インターバル・送信イベントのコールバック // var Xhr_send_psmsg = ""; var tid = setInterval("send_psmsg()",5000); function send_psmsg(){ var uri = "cgi-bin/ajaxtest1.cgi"; var msg = {'req':'req2', 'option':'x' } var async = true; var callbackOK = recv_psok; var callbackNG = recv_psng; var callbackNR = null; Xhr_send_psmsg = ajax_sendRequest(uri, msg, async, callbackOK, callbackNG, callbackNR); } // // インターバル・OK受信イベントのコールバック // function recv_psok(xhr){ res = ajax_getResponse(xhr); ajax_setText("ps", res["ps"]); } // // インターバル・NG受信イベントのコールバック // function recv_psng(xhr){ ajax_setText("ps", "Error5"); }
ここまでは、インターバルリクエストを利用して、定期的に非同期通信を行うサンプル
// ------------------------------------------------------------ // キー入力イベントごとのKeyCodeを表示 etc ... // Ajaxではないな...javascriptのサンプル // ------------------------------------------------------------ // // 入力キーコードを表示 // function keyget(evt, displayId){ ajax_setText(displayId, "KeyCode=" + evt.keyCode); } // ------------------------------------------------------------ // ラジオボタンの値取得 // ------------------------------------------------------------ function get_radio(){ for (var i = 0; i < ajax_gebn("rd1", -1).length; i++){ if (ajax_gebn("rd1", i).checked){ ajax_setText("rd", ajax_gebn("rd1", i).value); break; } } } // ------------------------------------------------------------ // チェックボックスの値取得 // ------------------------------------------------------------ function get_check(){ var checked_value = ""; if (ajax_gebi("ck1").checked){ checked_value += ajax_gebi("ck1").value; } if (ajax_gebi("ck2").checked){ if (checked_value != ""){ checked_value += "+"; } checked_value += ajax_gebi("ck2").value; } if (ajax_gebi("ck3").checked){ if (checked_value != ""){ checked_value += "+"; } checked_value += ajax_gebi("ck3").value; } ajax_setText("ck", checked_value); } // ------------------------------------------------------------ // セレクトボックスの値取得 // ------------------------------------------------------------ function get_select(){ ajax_setText("sl", ajax_gebi("sl1").options.item(ajax_gebi("sl1").selectedIndex).value); }
各種入力エレメントからの値取得のサンプル。
// ------------------------------------------------------------ // 表示/非表示の制御 // ------------------------------------------------------------ function toggle_display(){ if (ajax_gebi("div_display").style.display == "none"){ ajax_gebi("div_display").style.display = ""; }else{ ajax_gebi("div_display").style.display = "none"; } } // ============================================================ // ユーザコーディング(ここまで) // ============================================================ // --> </script>
スタイルの制御サンプル。
</head> <body> <div align="center"> <h1> ajaxtest1 </h1> </div> <hr /> <!-- ------------------------------------------------------------ --> <h2> 非同期リクエストによるテキスト電文通信 </h2> +ちょっとだけDOMの操作(なんせ、これがうまれて初めてのAjaxコーディング...) <div> tx1:<textarea id="tx1"></textarea> </div> <div> in1:<input type="text" id="in1" name="in1"><br /> in2:<input type="text" id="in2" name="in2" onblur="send_msg()"> ←ここからフォーカスが外れたらメッセージ送信する </div> <p></p> <div> res_tx1(tx1に対するレスポンス):[<textarea id="res_tx1" name="res_tx1"></textarea>] </div> <div> res_in1(in1に対するレスポンス):[<font id="res_in1_font"><span id="res_in1" name="res_in1"></span></font>] </div> <div> res_in2(in2に対するレスポンス):[<font id="res_in2_font"><span id="res_in2" name="res_in2"></span></font>] </div>
<hr /> <!-- ------------------------------------------------------------ --> <h2> インターバルリクエストによる定期的な表示更新 </h2> <div> <pre id="ps"> </pre> </div> <div> <input type="button" onclick="clearInterval(tid);" value="クリックで停止"> </div>
<hr /> <!-- ------------------------------------------------------------ --> <h2> ラジオボタンの値取得 </h2> <div> <input type="radio" id="rd1-1" name="rd1" value="radio1" checked>選択肢1<br /> <input type="radio" id="rd1-2" name="rd1" value="radio2">選択肢2<br /> <input type="radio" id="rd1-3" name="rd1" value="radio3">選択肢3<br /> <input type="button" value="OK" onclick="get_radio()"> </div> 選択されたのは[<span id="rd"></span>]
<hr /> <!-- ------------------------------------------------------------ --> <h2> チェックボックスの値取得 </h2> <div> <input type="checkbox" id="ck1" name="ck1" value="check1">選択肢1<br /> <input type="checkbox" id="ck2" name="ck2" value="check2">選択肢2<br /> <input type="checkbox" id="ck3" name="ck3" value="check3">選択肢3<br /> <input type="button" value="OK" onclick="get_check()"> </div> 選択されたのは[<span id="ck"></span>]
<hr /> <!-- ------------------------------------------------------------ --> <h2> セレクトボックスの値取得 </h2> <div> <select id="sl1"> <option value="none" selected> <option value="select1">選択肢1 <option value="select2">選択肢2 <option value="select3">選択肢3 </select> <input type="button" value="OK" onclick="get_select()"> </div> 選択されたのは[<span id="sl"></span>]
<hr /> <!-- ------------------------------------------------------------ --> <h2> 表示/非表示の制御 </h2> <div id="div_display"> 出て来たり〜消えたり〜 </div> <input type="button" value="表示/非表示" onclick="toggle_display()">
<hr /> <!-- ------------------------------------------------------------ --> <h2> キー入力イベントごとのKeyCodeを表示 </h2> <div> <input type="text" onkeydown="keyget(event, 'kd1');">onKeyDown : <span id="kd1"></span> </div> <div> <input type="text" onkeyup="keyget(event, 'ku1');">onKeyUp : <span id="ku1"></span> </div> <div> <input type="text" onkeypress="keyget(event, 'kp1');">onKeyPress : <span id="kp1"></span> </div> <h2> [↑][↓][←][→]のイベントにより入力フォーカスを移動させる </h2> <div> <input type="text" id="in11" onkeydown="keyget(event, 'kd11');return ajax_moveFocus(event, 'in32', 'in21', 'in12', 'in12');">onKeyDown : <span id="kd11"></span> <input type="text" id="in12" onkeydown="keyget(event, 'kd12');return ajax_moveFocus(event, 'in32', 'in22', 'in11', 'in11');">onKeyDown : <span id="kd12"></span> </div> <div> <input type="text" id="in21" onkeydown="keyget(event, 'kd21');return ajax_moveFocus(event, 'in11', 'in31', 'in22', 'in22');">onKeyDown : <span id="kd21"></span> <input type="text" id="in22" onkeydown="keyget(event, 'kd22');return ajax_moveFocus(event, 'in12', 'in32', 'in21', 'in21');">onKeyDown : <span id="kd22"></span> </div> <div> <input type="text" id="in31" onkeydown="keyget(event, 'kd31');return ajax_moveFocus(event, 'in21', 'in11', 'in32', 'in32');">onKeyDown : <span id="kd31"></span> <input type="text" id="in32" onkeydown="keyget(event, 'kd32');return ajax_moveFocus(event, 'in22', 'in12', 'in31', 'in31');">onKeyDown : <span id="kd32"></span> </div> </body> </html>
ajax_moveFocus()はイベントに対してreturn ajax_moveFocus(...)のようにreturnを付けて指定するのがミソ。こうしないと[←][→]で入力フィールドを移動した時に移動先のフィールドでカーソルが余計に進んでしまう。returnをつけてイベントハンドラを呼び出すとイベントハンドラがfalseを返した場合に、そのイベントの本来の動作をキャンセルできる。
Ajax対応CGIサンプル(ruby)
#! /usr/local/bin/ruby require "cgi" require "uri" require "nkf" #============================================================ # # Ajaxサポートクラス(あぁ楽しき哉、車輪の再発明) # #============================================================ class Ajax #------------------------------------------------------------ # # コンストラクタ # # 引数 # # nkf_param : 入力パラメータの文字コード変換指定(for nkf)。省略可。 # nkf_param_send : 送信パラメータの文字コード変換指定(for nkf)。省略可。 # # 戻値 : 無し # #------------------------------------------------------------ def initialize(nkf_param = "-X -e", nkf_param_send = "-w") @nkf_param = nkf_param @nkf_param_send = nkf_param_send @cgi = CGI.new("html3") end #------------------------------------------------------------ # # パラメータ取得 # # 引数 # # name : 項目名称。省略可。 # # 戻値 # # name指定時は、指定した項目の値を返す。 # name未指定は、全パラメータの[項目名、値]のセットをイテレータで返す。 # #------------------------------------------------------------ def get(name = "") if (name == "") @cgi.each do |key, val| yield(key, NKF.nkf(@nkf_param, val)) end else return NKF.nkf(@nkf_param, @cgi[name]) end end #------------------------------------------------------------ # # レスポンス送信 # # 引数 # # hash : 送信データ。ハッシュ形式。 # boolean_head : HTTPヘッダーを送信(true)/非送信(false)の指定。省略可。 # head_str : HTTPヘッダーの内容。省略可。 # # 戻値 : 無し # #------------------------------------------------------------ def send(hash = {}, boolean_head = true, head_str = "Content-Type: text/html\n\n") if (boolean_head) print head_str end i = 0 hash.each do |key, val| print "#{key}=" print URI.escape(NKF.nkf(@nkf_param_send, val),/[^-_.!~*'()a-zA-Z\d]/n) i += 1 if (i < hash.size) print "\t" end end end end #============================================================ # # Main # #============================================================ ajax = Ajax.new if (ajax.get("req") == "req1") in1 = ajax.get("in1") in2 = ajax.get("in2") tx1 = ajax.get("tx1") hash = { "res_tx1" => "response=(" + tx1 + ")", "res_in1" => "response=(" + in1 + ")", "res_in2" => "response=(" + in2 + ")" } ajax.send(hash) elsif (ajax.get("req") == "req2") option = ajax.get("option") option.gsub!(/(.)/){'\\' + $1} cmdline = "date;ps #{option}" result = `#{cmdline}` result.gsub!(/$/, "\r") hash = {"ps" => result} ajax.send(hash) end exit 0
rubyにおけるJavascriptのencodeURIComponent()と等価の処理は URI.escape("hogehoge", /[^-_.!~*'()a-zA-Z\d]/n)となる。また、非同期通信オブジェクトに返すメッセージはUTF-8に変換してからエンコードする必要があることに注意。
Javascript + DOMによるhtmlドキュメントの作成サンプル
JavascriptからDOMを操作する事のみでhtmlドキュメントを作制してみる。
http://myh.no-ip.org/~m-ito/ajaxtest2.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=euc-jp"> <title>ajaxtest2</title> <script type="text/javascript"> <!-- // ============================================================ // ユーザコーディング(ここから) // ============================================================ window.onload = function(){ var max = document.getElementsByTagName("body").item(0).childNodes.length; for (var i = 0; i < max; i++){ document.getElementsByTagName("body").item(0).removeChild(document.getElementsByTagName("body").item(0).childNodes.item(0)); } document.getElementsByTagName("body").item(0).appendChild(document.createElement("div")); document.getElementsByTagName("div").item(0).align = "center"; document.getElementsByTagName("div").item(0).appendChild(document.createElement("h1")); document.getElementsByTagName("h1").item(0).appendChild(document.createTextNode("javascript & DOMでウェブページを作る")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("h2")); document.getElementsByTagName("h2").item(0).appendChild(document.createTextNode("はじめに")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("p")); document.getElementsByTagName("p").item(0).appendChild(document.createTextNode("javascriptでDOM(Document Object Model)を操作すると動的にページを作ることができます。とはいえ結構面倒くさい作業になります。まぁ普通はこんなことはしないと思われます(^^;。")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("h2")); document.getElementsByTagName("h2").item(1).appendChild(document.createTextNode("document.getElementsByTagName")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("p")); document.getElementsByTagName("p").item(1).appendChild(document.createTextNode("document.getElementsByTagName(\"タグ名称\").item(番号)を使ってタグのエレメントを特定します。document.getElementsByTagName(\"タグ名称\").item(番号).appendChild(エレメント)を使ってタグに子どものエレメントを追加していきます。基本的にはこの作業を繰り返してドキュメント構造を組み立てていきます。")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("h2")); document.getElementsByTagName("h2").item(2).appendChild(document.createTextNode("document.createElement")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("p")); document.getElementsByTagName("p").item(2).appendChild(document.createTextNode("document.createElement(\"タグ名称\")を使ってタグ(エレメント)を作成します。作成されたエレメントはappendChildの引数に指定でき、ドキュメントの構成要素となります。")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("h2")); document.getElementsByTagName("h2").item(3).appendChild(document.createTextNode("document.createTextNode")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("p")); document.getElementsByTagName("p").item(3).appendChild(document.createTextNode("document.createTextNode(\"文字列\")を使ってテキスト(エレメント)を作成します。作成されたエレメントはappendChildの引数に指定でき、これもまたドキュメントの構成要素となります。また、表示された文字列は自動的にエスケープ処理されるのでXSS対策もなされた状態になります。この辺りがinnerHTMLを使ってお手軽に表示した場合との違いです。")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("h2")); document.getElementsByTagName("h2").item(4).appendChild(document.createTextNode("まとめ?")); document.getElementsByTagName("body").item(0).appendChild(document.createElement("p")); document.getElementsByTagName("p").item(4).appendChild(document.createTextNode("基本的にhtmlドキュメントは「タグ」と「テキスト」の織りなすものなので、上記の機能を組み合わせて利用するだけで作成することができます(!?)。")); } // ============================================================ // ユーザコーディング(ここまで) // ============================================================ // --> </script> </head> <body> <div> aaa </div> <div> bbb </div> <div> ccc </div> </body> </html>
現時点での結論
Javascriptの言語仕様そのものは意外にも比較的受け入れ易いものだった。しかしJavascriptでのビジネスロジックまでの構築は抵抗がある。理由としては、
- ブラウザ間での仕様の相違が大きい
- 同一ブラウザ間であっても異なるバージョン間での仕様の相違が大きい
- エラーメッセージ等の問題点を通知する仕組みが弱い(文法エラーはダンマリとなる事が多い)
のような事があげられる。とにかくデバッグしずらい。
とは言えAjax + Javascript + DOM (+ XML?)を使うと、格段にユーザインターフェースの利便性が向上するのは間違いないし、非常に魅力的ではある。個人的にはそういう用途に絞って利用してみようかと思う。