2011年4月8日金曜日

OS Xでpowを使ってみる

今回も、MeSHから離れた話題です。

powとは何か?

平たく言うと、Mac OS X上で動作する、Rackサーバです。Rackとは何かと言うと、ruby言語を利用して作成したアプリケーションとWebサーバとのインタフェース統一するためのライブラリです。SinatraもRailsも、Rackを介して動作するようになっています。powは、Rackの仕組みに沿って開発されたプログラムを、お手軽に試す際に有効です。

例えば、Webアプリケーションを試しに作ってみようとして、ホワーンとアイディアが浮かんでいる段階を想像してください。Railsなら、とりあえずプロジェクトを作成して、DBの構造を決めて、scaffoldして・・・mongrelなどを動かして、Webブラウザから確認するという流れになります。Sinatraだと、DBにテーブルを作って、app.rbを作って、mongrelなどを動かして、Webブラウザから確認するという流れになります。もう少し開発が進むと、Passengerなどを使ってApacheと連携するフェーズに進みます。このとき、動作ディレクトリを設定ファイルに登録するのが面倒になります。小規模なプロジェクトだと、ディレクトリまるごとコピーして新旧の動作を比較したいとか、別ディレクトリのプロジェクトと同時進行するなどの場合、いちいち設定ファイルを書き換えるのが嫌になります。このようなときに、Webアプリケーションを簡単に公開するための仕組みがpowです。

powの設定

powはpow.cxで公開されています。最初、ダウンロードのリンクが見つからなくて右往左往したのは秘密です。powのインストールは、以下のコマンドを実行するだけです。
$ curl get.pow.cx | sh
これだけで、様々な設定が行われ、ホームディレクトリに「.pow」というディレクトリが作られます。次に、RailsやSinatraなどで作成したRackアプリケーションのディレクトリのシンボリックリンクを作成します。例えば「/Users/admin/sinatra/test」というディレクトリであれば、
$ cd ~/.pow
$ ln -s /Users/admin/sinatra/test
と入力してください。これで~/.pow/testが作成されます。以上で設定は終了です。後は、Webブラウザを起動して、「http://<作成したシンボリック名>.dev/」にアクセスすればアプリケーションを利用できます。

実際に試してみる

それでは実際にサンプルプログラムを用いて説明していきます。事前に用意するものは、SinatraとRackです。いずれもgemコマンドでインストールできます。
$ gem install rack
$ gem install sinatra
次に、Sinatraを使った簡単なサンプル「app.rb」と、そのプログラムをRackから呼び出すための設定ファイル「config.ru」を作ります。


いずれも、「/Users/admin/sinatra/test」ディレクトリに作成してください。

後は、Webブラウザから「http://test.dev/」にアクセスすると、ブラウザ上に「Hello, world」の文字が表示されると思います。

app.rbを書き換えた場合は、powの再起動が必要となります。「/Users/admin/sinatra/test」直下に「tmp」ディレクトリを作成し、
$ touch tmp/restart.txt
を実行してください。powは、tmp/restart.txtのタイムスタンプを見て、自身を再起動するかどうか決定します。

うーん、シンプル。Mac OS Xを使っていて、RailsやSinatraを使っている人はpowも使ってみてください。数は少ないですが、日本語の記事も出てきています。
Node.js+CoffeeScriptで書かれた「Pow」がカッコ良すぎる件 | Rails Hub情報局
powを使ってdevelopment環境で複数のrailsアプリを同時に動かす | YomuKaku Memo このエントリーをはてなブックマークに追加

2011年2月28日月曜日

RubyとOLEでPowerPointを遠隔操作してみる

MeSHの枠組みを拡張する?

MeSHは、これまでWebブラウザ上で様々なものを動作・同期させることを念頭に置いてきました。しかし、「様々な」という概念を拡張していくと、ネイティブアプリケーションまで辿り着きます。せっかくプラットフォームに依存しないよう開発してきたのですが、「できない理由を説明するより、できることを証明してから悩もう」の精神に則り、ネイティブアプリケーションを操作してみたいと思います。今回は技術検証なので、Windows上にWeb簡易サーバを構築し、ネイティブアプリケーションを制御してみます。

RubyとOLE

OLEはObject Linking and Embeddingの略で、簡単に言うとWindowsアプリの連携を図るための根幹です。対応したプログラムであれば、プログラムを制御したり、プログラム中のイベントに応じて自作プログラム中のメソッドを実行することができます。このような便利な機能を使わない手はありません。早速プログラムを制御してみましょう。

普通は、Microsoft関連の便利な機能を使うためにはVisualStudioなどを使うことになるのですが、RubyにはWIN32OLEというありがたいクラスが作られています。通常、WIN32OLEの説明にはWordやExcelが用いられるのですが、実はPowerPointと連携するとプレゼンが便利になります。と言う訳で、RubyからPowerPointを制御しようというのが本日の記事になります。

基本的な制御

WIN32OLEが何であるかはRubyist Magazineの該当記事を読んでください。ここでは、あくまでPowerPointの制御のみ(簡単に)解説します。いや、深いところを訪ねられても解説できないというのが本音です。

事前準備として、Windowsを使っていて、PowerPointを持っていて、Rubyをインストールしていることが必要となります。それでは早速PowerPointで何かファイルを開いてみて下さい。次にirbを起動して以下の内容を打ち込んでみて下さい。

この3行を入力すると、PowerPointがプレゼンテーションモードになると思います。2つ以上のファイルを開いている場合には、どちらのファイルが対象となるか私には分かりませんので、1つだけ使用して下さい。

2行目は、OLEの仕組みを利用して、PowerPointとやり取りするための書き方です。3行目は、メソッドがチェーンしていますが、順番に「アクティブなプレゼン」の「スライドショー」を「実行」して「その状態」を得る。という(様な)意味です。細かく言うと間違っているかも知れませんので、鵜呑みにしないようお気を付けください。

それでは、ここで得られたオブジェクトviewを利用してPowerPointを制御してみます。制御のためのメソッドの中でも代表的なものを掲載します。上のプログラムの続きと思っておいてください。それぞれ、意味はコメントに書いておきます。


具体的にPowerPointを制御する

ここまで分かれば、後は適当なポート番号でHTTPを想定して待ち受けて、「次へ」や「前へ」のボタンを作成して、ボタンが押されたらview.Nextやview.Previousを実行してあげれば、Webブラウザから制御できます。つまり、iPhoneなどからプレゼンテーションの制御を行なうことが可能となります。

と言うことで作成したのが次のソースです。1つのファイルの中にRubyスクリプト、HTMLファイル、JavaScript、CSSが入っているので見づらいと思いますが、このファイルだけコピーすれば使えるという気楽さを念頭に置いているのでご容赦ください。(無駄に)AJAXを使っているので、ページ遷移などは発生しません。

前準備:
・以下のソースを保存する。
・WindowsのIPアドレスを調べておく

使い方:
1.PowerPointでプレゼンしたいファイルを開く。
2.rubyで以下のソースを実行する。
3.WindowsのWebブラウザ(動作検証はChromeで行ないました)からhttp://localhost:8080/に接続する。
4.ボタンをクリックして動作させる。
5.うまくいったらiPhoneなど、別ホストからも試してみる。

注意事項:
・セキュリティソフトの動作状況によっては、iPhoneなどから接続できない場合があります。その場合は一時的にセキュリティソフトをオフにしてお試しください。
・ユーザインタフェースは手抜きです。簡単なHTMLとCSSなので、気になった方は書き直してください。
・JavaScriptも冗長です。ご容赦ください。
・ctrl+CでRubyスクリプトが停止しない場合があります。対処法としてctrl+Cを3回ほど連打して、ブラウザ側でリロードなどをすると停止します。対処法をご存じの方、ご連絡いただければ幸いです。

将来的な拡張:
・現在のページ番号と全ページ数が手元に表示されるといいな
・ついでにストップウォッチ機能も欲しいな(スタート・ストップは手動で良いかな?)
・ページ番号をメニューから選択して飛ぶ機能も欲しいかも?
・現在表示しているページや次ページの内容が手元で確認できるといいかも

検証に使用したソフトウェアとバージョン:
・Microsoft Windows Vista ServicePack2 (Windows 6.0.6002)
・Microsoft Office PowerPoint 2007(12.0.6535.5002) SP2
・ruby 1.8.7 (2009-06-12 patchlevel 174) [i386-mswin32]
・Google Chrome 9.0.597.98
・iPhone 3GS (iOS4.2.1)

このソフトについて

ライセンス:GPLv3
免責事項:無保証です。このソフトを使用することによって生じた損害に対して、作者は一切の責任を負いません。

このエントリーをはてなブックマークに追加

2011年2月12日土曜日

Mac OS XのApache設定

MacBook Air

ちょっと前になりますが、MacBook Air 11'モデルを入手しました。System7以来、久しぶりにMacに回帰しました。CPUなどのスペックには特筆すべきことはない、いや、むしろ今のご時世では貧弱と言わざるをえないのですが、予想外にキビキビ動作します。特にスリープへの移行と復帰は感動ものです。しかも、OS XはBSD UNIXの血を受け継いでいるので、Macは立派なUNIXマシンです。これまでWindows環境上でプログラミングしようとして、数々の苦労をしてきた経験からすると、様々な言語や環境がプリインストールされ、まともに動作することだけで嬉しくなってしまいました。(私とWindowsの相性がわるいことは否定しません。Apacheの設定がうまくいかないとか、Rubyでソケットを使うとうまくいかないとか、CGIの設定がうまくいかないとか、MySQLの設定がうまくいかないとか、昨日まできちんと動いていたシステムが上手く動かなくなったとか、環境設定ファイルがどこにあるのか分からないとか・・・。結局、Windows上で足掻くよりも、仮想計算機環境でDebianを動かす方が楽です。)

細かいところでは、controlキーが正規の位置(Aの左)に配置されているのも好印象です。

まずはApacheの設定

OS Xでは、RubyもApacheもMySQLもPythonもVIMもプリインストールされています。ターミナルを開けば、基本的なUNIXコマンドは使用できます。うーん、幸せ。あ、別にUNIXコマンドが好きなわけじゃなくて、設定を変更したら素直に反映される環境が好きなだけです。

と言うことで、まずはApacheの設定を変更してみます。前提条件として、ユーザ名はadminと仮定して話を進めます。この場合、ホームディレクトリは/Users/adminに、Webサイトのホームディレクトリは/Users/admin/Sitesになります。

準備編

まずは、Webサーバの起動です。標準状態では起動されません。
システム環境設定 ー 共有 ー Web共有にチェックをつけて「入」にしてください。
Webブラウザから
http://localhost/~admin/
にアクセスすると、エラーが出ずに「あなたのWebサイト。」というタイトルのページが見られることを確認しましょう。もしWebサーバが起動していなければエラーとなります。

気が向いたら、適当なHTMLファイルを作ってWebブラウザで確認してみましょう。ファイルを置くフォルダは前節で説明しています。

CGIスクリプト編

CGIスクリプトは、管理者しか設置できないようにする場合と、ユーザが自由に拡張できる場合のどちらでも設定できます。とりあえずお手軽に試せるように、ホームディレクトリ内に置いたファイルを実行できるようにします。
(1)cgi-binディレクトリを作る
mkdir /Users/admin/Sites/cgi-bin

(2)Webサーバ(Apache2)の設定ファイルを書き換える
主な設定は/etc/apache2/httpd.confに書いてあるので編集する。このとき、一般ユーザの権限では書き込みできないので
cd /etc/apache2
sudo vi httpd.conf
という風にsudoを付けてから書き換える。
#AddHandler cgi-script .cgi
という行があるので、行頭の「#」を取ってこの設定を有効化する私の環境では、396行目でした。


(3)adminユーザのWeb設定を変更する
OS Xでは、ユーザごとのWeb設定ファイルが存在するので変更しましょう。
設定ファイルは/etc/apache2/usersに全ユーザ分が入っています。今回はadminと言う名のユーザなので該当ファイルは
/etc/apache2/users/admin.conf
です。またしても一般ユーザでは書き込めないのでsudoを付けて編集しましょう。
cd /etc/apache2/users
sudo vi admin.conf
元々のファイルには、下記の内容(全6行)が書いてあります。

それを、以下の内容に変更してください。具体的には7行目以降を追加します。Optionsの行は、Apacheのドキュメントを参照して欲しいが、簡単に言うと「CGIの実行を許可」し、「ファイルの一覧表示を拒否」し、「言語の自動判別機能を不使用」としています。


(4)Webサーバの再起動
設定を変えたらWebサーバの再起動をしましょう。コマンドラインから再起動する方法が分からなかったので、システム環境設定 ー 共有 ー Web共有のチェックを一度外し、一呼吸おいてから再度チェックを付けることで再起動できます。

(5)CGIファイルを作る
CGIなので言語は何でも良いが、せっかく標準でインストールされているのでRubyを例に取ります。
cd /Users/admin/Sites/cgi-bin
vi test.cgi
と入力して、test.cgiを作ってみましょう。サンプルを以下に示します。

たった3行のプログラムです。試しにターミナルから実行してみましょう。viを終了したら、ruby test.cgiと入力すると、画面にcontent-type…以下略と表示されるはずです。もし表示されない場合はプログラムがきちんと入力されていないので確認して下さい。次に、このプログラムに実行属性をつけます。説明は省略しますが、ファイル作成直後のパーミッションは644なので、自分は読み書きが可能、他の人は読むだけです。これでは実行できないので、755の状態にします。
chmod 755 test.cgi
これでコマンドラインから直接実行できるはずです。試しに
./test.cgi
と入力してみると、確かに実行できます。

ここまで終わったら、次はWebブラウザから見てみましょう。
http://localhost/~admin/cgi-bin/test.cgi
にアクセスして、画面にOKと表示されれば(文字通り)OKです。

続く・・・のか? このエントリーをはてなブックマークに追加

2010年11月19日金曜日

WebSocketを試す

WebSocket

最近、WebサーバからWebクライアントにデータをPushする技術としてWebSocketが脚光を浴びています。従来だと、Comet(AJAXの返答を引き延ばす技法=ロングポーリング)を用いて擬似的にPushしていたのですが、(サーバサイドもクライアントサイドも)プログラムが面倒だったり、クロスドメインへの対応がイマイチだったり、リアルタイム性が乏しかったりなどの理由で、だんだんとWebSocketに移ってきています。気づくと、サーバ側ではpywebsocketやnode.websocket.js、Jetty、mojoなどの実装が出てきましたし、クライアント側ではChromeやFirefoxが対応しており、そろそろ手を出してみても良い頃合いになってきました。ruby好きなので、サーバ側にrev-websocketを使ってみたいと思います。

rev-websocketの準備

今回は、OSにDebian Squeezeを使用します。正直、aptの便利さと、Debianのパッケージの多彩さとGUIいらずで軽量なヴァーチャルマシンを多数用意できるポータビリティにメロメロです。

まずはruby関連でインストールするパッケージです。入れたパッケージのメモを取り忘れたので、dpkg -l | grep rubyした結果を示します。不要なモノもありますが、リストに載せておきます。
libruby1.8
libsqlite3-ruby1.8
ruby
ruby-dev
ruby1.8
ruby1.8-dev
rubygems1.8

次に、rubygem関連でインストールするパッケージです。確かこれだけで良かったと思います。
rev
rev-websocket

revを検索したところ「Rev is a high performance event library for Ruby built on top of libev.」「libevのrubyバインディング」「Rubyの高速なイベント駆動IOライブラリ」などと書かれていました。便利そうなので使います。

revのサンプルプログラムを読む

まずは、revのサンプルコードを試してみます。/usr/lib/ruby/gems/1.8/gems/rev-0.3.2/README.textileを覗いてみると、echo serverの例が載ってます。gemを使ってインストールしたので、そのままではrevが無いと言われ、1行目にrubygemsのrequireを追加してあります。
require 'rubygems'
require 'rev'
HOST = 'localhost'
PORT = 4321

class EchoServerConnection < Rev::TCPSocket
  def on_connect
    puts "#{remote_addr}:#{remote_port} connected"
  end

  def on_close
    puts "#{remote_addr}:#{remote_port} disconnected"
  end

  def on_read(data)
    write data
  end
end

server = Rev::TCPServer.new(HOST, PORT, EchoServerConnection)
server.attach(Rev::Loop.default)

puts "Echo server listening on #{HOST}:#{PORT}"
Rev::Loop.default.run
このソースを見ると、(1)Rev::TCPSocketを継承したクラスを作り、(2)接続されたり、接続が切れたりしたら「on_connect」「on_close」が呼び出され、データを受信したら「on_read」が呼び出され、(3)20行目にあるようにRev::TCPServerのオブジェクトを作る際にポート番号や作成したクラスを登録すれば良いことなどが分かります。あと細かいことでは、wirteメソッドを使うとクライアントにデータを送れることも分かります。 実際に「telnet localhost 4321」で接続してみると、確かに入力した文字列がそのまま返されることが分かります。また、最終行の「Rev::Loop.default.run」によりイベントループが回り出すのですが、プログラムの実行してはこれより下には行きません。もっと複雑なプログラムを組もうとしたら、スレッド化が必要かも知れません。

WebSocketのサンプルプログラムを読む

revのソースコードの書き方が分かったところで、WebSocketのサンプルも試してみます。こちらは/usr/lib/ruby/gems/1.8/gems/rev-websocket-0.1.3/README.rdocの中にサンプルがあります。
require 'rubygems'
require 'rev/websocket'

class MyConnection < Rev::WebSocket
  def on_open
    puts "WebSocket opened"
    send_message("Hello, world!")
  end

  def on_message(data)
    puts "WebSocket data received: '#{data}'"
    send_message("echo: #{data}")
  end

  def on_close
    puts "WebSocket closed"
  end
end

host = '0.0.0.0'
port = '8080'

server = Rev::WebSocketServer.new(host, port, MyConnection)
server.attach(Rev::Loop.default)

Rev::Loop.default.run
echoサーバのプログラムと比べても、ほとんど違いがありません。構造的に違うのは、2行目のrequireと、4行目で作成しているクラスのスーパークラスがRev::WebSocketであることと、23行目でRev::WebSocketServer.newとしている箇所です。 サーバができたので試してみましょう。ただし、telnetコマンドではWebSocketサーバと通信できません。いや、正確には可能なのですが、繋がった後に渡すパラメータが複雑なので現実的ではありません。そこで、とりあえずChromeのJavaScriptコンソールから接続してみたいと思います。下記のプログラムを入力してみて下さい。接続先ホスト名は必要に応じて変更して下さい。うまく動作すれば、3行目で送信したメッセージが、アラートウィンドウに表示されます。
var ws = = new WebSocket( 'ws://localhost:8080/' );
ws.onmessage = function(event){ alert( event.data) ; }
ws.send( "This is a test message." );

重要な部分は、WebSocketのオブジェクトを生成すること、データを受信した際にonmessageが実行されること、受信したデータはevent.dataで取得できること、データ送信はsendメソッドであることです。

このように、WebSocketを使うことは難しくありません。皆さんもお試し下さい。 このエントリーをはてなブックマークに追加

2010年10月20日水曜日

メモ: クロージャの書き方

クロージャとは?

JavaScriptに触れていると、クロージャという書き方に突き当たります。それ何?って思って検索しても、難しいことばかりで本質はなかなか分かりません。しかも、他の言語でどう書くかも掲載されないことが多いです。元々慣れない言語(JavaScript)を勉強しているときに、概念もあやふやで、他の言語の例もない・・・ってことで使えるようになるまで苦労しました。確かに、他の言語では書き表しにくい書き方です。

そうは言っても、避けてばかりでは進歩しないので、自己流で解説してみます。サンプルは、node.jsなどを想定して書いています。Debianのsqueeze(2010/10/20時点でtesting)では、すでにnode.jsが標準パッケージに入っているので、敷居はかなり低くなっています。

まずはJavaScriptでクロージャ

ゴタゴタ書くと、難しいという先入観が形成されてしまうので、まずは下記のソースをお読み下さい。
var test = function() {
  var i = 0;
  return function() {
    i += 1;
    return i;
  }
}

var count = test();
count();  // => 1
count();  // => 2
count();  // => 3
まず、変数countにはtest内の3行目以降で宣言したfunctionが代入されます。堅い言語に慣れている人は、まずこの書き方を許容して下さい。functionは変数に代入できます。
このfunction内で扱っている変数iは、functionの外で宣言されています。ここで、count()が実行されると、iが1増えます(iが1になります)。そして、このiの値は(プログラマから見て)裏側で保持され、再度count()が実行されると、今度はiが2になります。このように、スコープ外で宣言された変数を取り扱うのがクロージャです。

では、iはどこに保持されているかと言うと、概念的にはcountの一部として保持されています。例えば、別の変数も作ってみましょう。8行目までは上記と一緒で、9行目から先を以下のように改造したとします。
var count1 = test();
var count2 = test();
var count3 = test();
count1();  // => 1
count2();  // => 1
count1();  // => 2
count3();  // => 1

このように、count1, count2, count3でのiはそれぞれ別の値を保持しています。もちろん、test内でいくつもの変数を宣言することも可能です。

Rubyでクロージャ

次に、比較のためにRubyでクロージャを扱ってみましょう。例によって、まずは下記のコードをご覧下さい。
def test
  i = 0
  return lambda { i += 1 }
end

count = test
count.call  # => 1
count.call  # => 2
count.call  # => 3
count.callの文字数が多くて嫌いな人は、最新版のRubyならcount[]という書き方も許されます。

Rubyを知らない人のために、じっくりと説明していきます。まず、1行目のdefはメソッドを定義するための構文です。この例ではtestという名前のメソッドを定義しています。2行目で変数iに0を代入しています。変数宣言はRubyでは不要です(と言うか、できません)。3行目でlambdaを使って定義した一連の作業を返しています。lambdaは、「一連の作業をオブジェクト化する」ことが可能です。(Rubyでは、最後に評価された内容がそのまま返り値となるので、returnは省略可能です)

6行目で変数countにtestメソッドの実行結果として先ほど定義したlambdaが代入されます。「test」は「test()」の省略形です。7行目以降のcount.callは、lambdaの実行です。iがどこに保持されているかはともかく、iの値が1ずつ増えているのが分かると思います。もちろん、count1, count2などを定義すると、それぞれのiは独立した変数として保持されます。

ついでにカリー化の手前

上のサンプルでは、クロージャの良いところが伝わりきっていないと思いますが、そのままカリー化の手前まで突っ走りたいと思います。カリー化の手前とは「2つの引数を伴う関数f(x,y)をg(x)(y)のように記述すること」です。真のカリー化は、もう少し複雑なので説明は割愛します。こちらも早速サンプルをご覧下さい。
var test2 = function( x ) {
  return function( y ) { return x * y }
}

mul = test2(3);
mul(2);  // => 6
mul(5);  // => 15

def test2( x )
  lambda { |y| x * y }
end

mul = test 3
mul.call 2  # => 6
mul.call 5  # => 15
2つの引数x, yを受け取って積を返す関数の代わりに、一つ目の引数xを先に受け取りクロージャの要領で保持しておきます。その後、もう一つの引数yを受け取って積を計算し、返すという流れが記述できました。もう一つの引数の受け取り方ですが、Rubyでは2行目の「 |y| 」のように、パイプ記号で囲った変数に代入されます。

この例では、掛け算に使用する数値の一つを先に受け取り、以後はその数値を基準として、もう一つの数値は実際に計算する際に渡す形となっています。これ以外にも、初期値を指定してカウントダウンするような場合とか、出力フォーマットを定めておいて後で数値を渡すと指定したフォーマットで出力するなどの場合に便利ではないでしょうか?

クロージャまとめ

C言語では、スタティック変数を使用することで、一見似た様な記述が行えます。しかし、その場合はcount1とcount2のように二つ以上の状態を保持できません。だからと言ってグローバル変数を使用するのも気が引けます。そのような場合にクロージャのような書き方ができると、グローバル変数を使用することなく実装できます。

一方、「クロージャなんて使わずに、オブジェクト指向(クラスとかインスタンス)でいいんじゃない?」って考えもあると思います。もちろん、オブジェクト指向の記述方法でも同じことができます。しかしその場合、変数の値を裏で保持して欲しいだけなのに、大げさな記述が必要になってしまいます。Rubyでのサンプルを以下に示します。
class Test
  def initialize
    @i = 0
  end
  def count
    @i += 1
  end
end

c1 = Test.new
c1.count  # => 1
c1.count  # => 2
c1.count  # => 3
この程度のプログラムでしたら、クロージャでもクラスでも好きな方で記述して良いと思いますが、クロージャのシンプルさは魅力的です。そうは言ってもクラスを使ってもカリー化と同等の内容も簡単に記述できます。クロージャに慣れていない人は現時点では多いと思いますので、そう言う人に気を遣う場合にはクラスを使った方が良いと思います。 このエントリーをはてなブックマークに追加

2010年5月29日土曜日

JavaScriptで苦悩

苦悩する日々

MeSHのフレームワークには、今のところユーザ管理機能はありません。ユーザ管理などは他のシステムに任せて、コアな部分だけを実装する予定だからです。とは言っても、そろそろ何らかのシステムと連携して実践したいところです。そう思ってたら、棚からぼた餅が落ちてきました。なんと、大学にLMSが(試験的に)導入されました。元々大学にはとあるプロジェクトがあって、当時はLMSが動作していたのですが、現在は停止しております。プロジェクトの中心にいた私が言うので間違いないです。停止しています。

自前でLMSを立ち上げるなど考えていたのですが、ユーザ管理の手間はいかんともしがたいものがあります。どうしたものかと思っていたところに、タイミング良くLMSが導入されたので、さっそく認証情報をもらうことにします。とは言っても、ユーザ情報の入っているデータベースに接続するとか、セッション情報を貰ってくるなんてことは、どう考えても許可が下りるとは思えません。色々考えた結果、LMSにHTMLの教材をアップロードして、そこでスクリプトを動かして強引に外部ページにリンクしてしまえ!と言うことに決め、さっそく慣れないJavaScriptと格闘しました。苦悩の始まりです。

簡単・・・じゃ無い

まずはLMSにHTML教材もどきをアップロードして、何ができて何ができないか確認します。その結果、LMSが作成したページ内にiframeで表示されることが分かりました。面倒なので、LMSが作成したページを「親」、iframe内のページを「子」と呼びます。親にはユーザ名が表示されているので、この情報を取ってきて、Formに入れて、MeSHのサーバにSubmitすれば、少なくともユーザ名を取得できます。本当は学生番号のようなユニークな情報があれば良いのですが、親のソースをいくら探してもそのような情報はありません。邪道なことをおこなうので仕方ないと考えつつ、氏名がliタグに囲われているのが救いでした。とりあえず、同姓同名がいたらそのときに悩むことにして、まずは技術確認を行います。

子では、割と自由がききました。JavaScriptも使えますし、JQueryを読み込むこともできます。とりあえず、ブラウザ(Google Chrome)のJavaScriptコンソールで一行一行実行しながら試そうとしたとき・・・「ん?iframeの親の情報ってどうやって取得するんだ?」と言うJavaScript初心者の検索の旅が始まりました。結局、金曜日の23:00~翌3:00、土曜日の21:00~翌3:00までやって、なんとか親のliタグの情報を取得することができましたが、ページに埋め込むとエラーで止まってしまいました。仕方ないのでJavaScriptが得意な学生にメールでデバッグの要請をしたら、ものすごい初心者的なバグ(と言うか考え違い)を指摘されました。我ながら「おぃおぃ、こんなのが分からなかったのかい?」と問いかけたくなるレベルでした。

やっとプログラムの話

そんなこんなで、やっとこさ完成したのが以下のソースコードです。生のJavaScriptとJQueryのコードが混在しているあたりが初心者丸出しです。はい、JavaScriptは初心者です。やってることは、parent.document.getElementsByTagNameを使って、親のフレームの特定のタグ(ここではli)に書かれた内容を取得し、その内容をid="username"の入力欄に入れ、新しいウィンドウを開いて、formをsubmitするだけです。まぁ、ちゃんと使うためには、textタグじゃなくてhiddenタグを使うとか、画面デザインを考えるなど、やることは沢山あります。また、Webサーバxxx.xxx.xxxでは、HTTP_REFERERをチェックすることもセキュリティ上必要だと思ってます。でも、とりあえず動作確認のためなので、これで良しとします。



以下、上のソース内のJavaScript部分の抜粋です。
var name1=parent.document.getElementsByTagName('li')[0].firstChild.nodeValue;
$('#username').val(name1);
window.open('about:blank', 'starting');
var f=document.starting; f.action='http://xxx.xxx.xxx/';
f.method='post'; f.target='starting';
f.submit()
このエントリーをはてなブックマークに追加

2010年5月13日木曜日

メソッド一覧を得る方法

前回の日記から、だいぶ日数が空いてしまいました。久しぶりに投稿しようと思います。今回は、技術的なメモで、あるクラスの持つメソッドの一覧を表示するやり方です。

Javaでメソッド一覧

Javaを使っていると、ふと「このクラスのメソッドって何があったっけ?」と思うことがあります。ドキュメントなどを漁るのが正道ですが、メソッド一覧が欲しいだけなら、このような方法があります。
この例では、Stringクラスのメソッド一覧を表示しています。5行目の「String」を別のクラス名にすれば、好きなクラスのメソッド一覧を得ることができます。

import java.lang.reflect.Method;

public class ClientMethod {
    public static void main(String[] args) {
        Method[] methods = String.class.getMethods();
        for(int i = 0; i < methods.length; i++){
            System.out.println(methods[i].getName());
        }
    }
}

Rubyでメソッド一覧

参考までにRuby版も掲載しておきます。2行目の「String」を好きなクラスに変更すればメソッド一覧を得ることができます。sortメソッドを組み込んでいるので、メソッド名をabc順に並べ替えてから表示します。
#!/usr/bin/ruby
String.methods.sort.each do | method |
  print method + "\n"
end

ふとしたときにご活用下さい。 このエントリーをはてなブックマークに追加