お勉強のための例題として、LINK集を作ってみました。
WEBrick を使って、ローカルサーバとして動作するものです。
複数台のPCや、複数種のブラウザでの共有ができるので便利かもしれません。
(2台のPCでfirefoxのブックマークを共有していてデータが消えたショックが開発動機の一つなのは秘密。)
まだ改良したいところはあるけれど、とりあえず動くんで公開してみます。
Ruby1.8.2の標準添付ライブラリだけで動くはずのつもり。
スラッシュドット ジャパン経由で知ったんですが、10分で作るRailsアプリ for Windowsというものがあるそうです。
ちょっとかぶっちゃってますが、気にせずに公開しちゃいます。
作ってるときには知らなかったので、インスパイアされたわけではありません。(笑)
#!/usr/bin/env ruby =begin = SimpleなLINK集(WEBrick,ERB のお勉強) 動かしておいて、ブラウザで http://localhost:8001/urllist にアクセス 使い方は見たまんま(笑) 一応、データは保存されます =end require 'cgi' require 'erb' require 'webrick' include WEBrick require 'pstore' #require 'urllistdata' class CCData def initialize(_url="",_name="",_c_cnt=0,_date="",_prev=0,_next=0) @prev=_prev @next=_next @url=_url @date=_date @c_cnt=_c_cnt @name=_name end attr_accessor :prev,:next,:url,:date,:c_cnt,:name end class ClickList HEAD=0 TAIL=-1 def initialize @idxkey = 0 @culist = Hash.new @culist[HEAD] = CCData.new @culist[HEAD].prev = HEAD @culist[HEAD].next = TAIL @culist[TAIL] = CCData.new @culist[TAIL].prev = HEAD @culist[TAIL].next = TAIL end def addtail(ccdata) @idxkey += 1 _prev = @culist[TAIL].prev @culist[TAIL].prev = @idxkey @culist[_prev].next = @idxkey @culist[@idxkey] = ccdata @culist[@idxkey].prev = _prev @culist[@idxkey].next = TAIL end def each_seq return nil if @culist[HEAD].next == TAIL idx = @culist[HEAD].next until idx == TAIL _next = @culist[idx].next yield(idx, @culist[idx]) idx = _next end end def head head = @culist[HEAD].next return nil if head == TAIL return @culist[head] end def tail tail = @culist[TAIL].prev return nil if tail == HEAD return @culist[tail] end def delete(idx) return nil if not @culist.has_key?(idx) #削除箇所を塞ぐ _prev = @culist[idx].prev _next = @culist[idx].next @culist[_prev].next = _next @culist[_next].prev = _prev #削除 @culist.delete(idx) end def move(idx,to)#toの次に移動 return nil if not @culist.has_key?(idx) return nil if not @culist.has_key?(to) #移動元を繋ぐ _prev = @culist[idx].prev _next = @culist[idx].next @culist[_prev].next = _next @culist[_next].prev = _prev #移動先を切る _next = @culist[to].next _prev = @culist[_next].prev @culist[to].next = idx @culist[_next].prev = idx #移動 @culist[idx].prev = _prev @culist[idx].next = _next end def to_head(idx) move(idx,HEAD) end def to_tail(idx) move(idx,@culist[TAIL].prev) end def up(idx) return nil if not @culist.has_key?(idx) _prev = @culist[idx].prev return if _prev == HEAD move(_prev,idx) end def down(idx) return nil if not @culist.has_key?(idx) _next = @culist[idx].next return if _next == TAIL move(idx,_next) end def [](idx) return @culist[idx] end #attr_accessor :culist end DATAFILE = "clicklinklist.dat" DATAROOT = "list" def data_load store = PStore.new(DATAFILE) store.transaction do if store.root?(DATAROOT) $urllist = store[DATAROOT] else $urllist = ClickList.new end end end data_load def data_save store = PStore.new(DATAFILE) store.transaction do store[DATAROOT] = $urllist end end URLLIST_RHTML = <<'URLLISTSRC' <html lang="ja"> <head> <meta http-equiv="Content-type" content="text/html; charset=Shift_JIS" /> <meta http-equiv="Refresh" content="300"> <meta http-equiv="Pragma" content="no-cache"> <title>URL Click List</title> </head> <body> <form method="POST" action="/urladd"> <table border=1> <tr> <td rowspan=2> <input type="submit" value="新規登録"> </td> <td>Name</td> <td><input type=text size=80 name="name"></td> </tr> <tr> <td>URL</td> <td><input type=text size=80 name="url"></td> </tr> </table> </form> <ul> <% $urllist.each_seq { |key, elm| %> <li> <a style=text-decoration:none href="urledit?idx=<%= key %>&act=5">△</a> <a style=text-decoration:none href="urledit?idx=<%= key %>&act=6">▽</a> <a style=text-decoration:none href="urleditform?idx=<%= key %>">◇</a> <a style=text-decoration:none href="jumptourl?idx=<%= key %>" target=_blank> <%= CGI::escapeHTML(elm.name) %></a> </li> <% } %> </ul> </body> </html> URLLISTSRC URLEDITFORM_RHTML = <<'URLEDITFORMSRC' <html lang="ja"> <head> <meta http-equiv="Content-type" content="text/html; charset=Shift_JIS" /> <title>URL edit form</title> </head> <body> <h1>登録URLの編集</h1> <form method="POST" action="urledit"> <table border=1> <tr> <td>Name</td> <td><input type=text size=80 name="name" value="<%= name %>"></td> </tr> <tr> <td>URL</td> <td><input type=text size=80 name="url" value="<%= url %>"></td> </tr> <tr> <td></td> <td> <input type=submit value="処理実行"> <input type=radio name="act" value=1 checked>更新 <input type=radio name="act" value=3>上へ <input type=radio name="act" value=4>下へ <input type=radio name="act" value=2>削除 </td> </tr> </table> <input type=hidden name="idx" value="<%= idx %>"> </form> </body> </html> URLEDITFORMSRC s = HTTPServer.new( :Port => 8001, # portの指定 :DocumentRoot => Dir::pwd + '/htdocs' #, :Logger => WEBrick::Log::new($stderr, WEBrick::Log::DEBUG) ) class URLListServlet < HTTPServlet::AbstractServlet def initialize(server, *options) super #rhtml = File::readlines( "urllist.rhtml" ).join # rhtmlファイルを読む #@body = ERB.new( rhtml ) @body = ERB.new( URLLIST_RHTML ) end def do_GET(req, res) res.body = @body.result( binding ) res['Content-Type'] = "text/html" end end s.mount("/urllist", URLListServlet) #Jump to URL s.mount_proc("/jumptourl"){|req,res| idx = req.query['idx'].to_i dat = $urllist[idx] dat.c_cnt += 1 if dat.c_cnt > 1 $urllist.to_head(idx) dat.c_cnt = 0 data_save end res.set_redirect(HTTPStatus::MovedPermanently,dat.url) } #URL新規登録処理 s.mount_proc("/urladd"){|req,res| url = req.query['url'] name = req.query['name'] name = url if "" == name if "" != url $urllist.addtail(CCData.new(url,name)) data_save end res.set_redirect(HTTPStatus::MovedPermanently,"urllist") } class URLEditFormServlet < HTTPServlet::AbstractServlet def initialize(server, *options) super @body = ERB.new( URLEDITFORM_RHTML ) end def do_GET(req, res) idx = req.query['idx'].to_i dat = $urllist[idx] url = dat.url name = dat.name res.body = @body.result( binding ) res['Content-Type'] = "text/html" end end s.mount("/urleditform", URLEditFormServlet) #登録URL編集処理 s.mount_proc("/urledit"){|req,res| url = req.query['url'] name = req.query['name'] act = req.query['act'].to_i idx = req.query['idx'].to_i dat = $urllist[idx] case act when 1 #更新 if "" != url dat.url = url name = url if "" == name dat.name = name end when 2 #削除 $urllist.delete(idx) when 3 #上へ $urllist.to_head(idx) when 4 #下へ $urllist.to_tail(idx) when 5 #一つ上へ $urllist.up(idx) when 6 #一つ下へ $urllist.down(idx) end data_save if 1 <= act and act <= 4 res.set_redirect(HTTPStatus::MovedPermanently,"urllist") } trap("INT"){ s.shutdown } s.start