書籍をレビュー数でランキング表示するWebサービスを作ってみた
本をレビュー数でランキング表示するWebサービス「ぶくれび」を日曜プログラミングで作ってみました。
1月から作り始めて、約2ヶ月かかりました。
初めてWebサービスを作ってみましたが、Web力がなさすぎて苦労しました。
Webサービスを作った背景
色々なWebサービスを個人が作っているのを見て、何か作って公開したいなと常々思っていたけど、作るもののネタがなかった。
ふと、Amazonの本やDVDをレビュー数でソートして表示できればよいのにと思い、AmazonのAPIを見てみるとレビュー数でのソート表示に対応していないことを知る。
楽天ブックスのAPIであればレビュー数での表示ができることがわかったので、じゃ、ちょっと作ってみようと思った。
使った技術
言語はC#。
WebフレームワークはASP.NET MVC 3。
ORMにはDapper。
ASP.NET MVCもDapperも今回初めて使ってみた。
最初はPerl+Mojoliciousで作ってたけど、最近C#を使っていたこともあり、VisualStudioのもろもろの楽さに惹かれてC#で書き直した。
CSSフレームワークは、Bootstrap。
BootstrapはWebのデザインとか全くできない僕でもちゃんとしたレイアウトができるので素敵です。
それでも、ちょっとした変更をしたい場合などにCSS力なさすぎて苦労しましたが。
公開にあたって
ExpressWebでレンタルサーバを借りて、お名前.comでドメインを取りました。
ExpressWebはWindowsのレンタルサーバで、シェルログインがなく、すべてWebのコントロールパネルからの設定なので、最初は何がどこにあるのかわからなくてちょっとつまる。
このあたりは、シェルログインが使えるLinuxのレンタルサーバがよいなと思いました。
LinuxのレンタルサーバにMono(Xamarin)を載せて動かしてみようかとも少し思ったけど、色々と調べたりしないといけなさそうなので今回は断念。
さくっと使えるもんなんでしょうか。
これから
せっかくレンタルサーバ借りて、ドメインも取ってみたので、他にも何か作っていきたいところ。
とりあえずDVDのレビュー数ランキングは、今のを少し変えればできるので近日中に作る予定。
モチベーションが続くかどうかが怪しいけど。
というか、これぐらいの簡単なWebサービスを最初に作るものとして選んで良かった。*1
これが今回一番大きいかも。
ってことで、書籍レビュー数ランキング ぶくれび使ってみてください!
hudsonでMSTestのテスト結果とカバレッジをレポートする設定をしてみた。
こんな感じでhudsonに表示される。
手順は以下。自分用のメモなので雑です!
バッチファイルを作って、hudsonから叩く。
- 過去の結果があれば削除
- テスト実行
カバレッジデータはバイナリなので、xmlに変換して、それをさらにEmmaデータに変換してる。
hudsonからはMSTest PluginとEmma Pluginを入れておけばレポートが見える。
テスト結果は、デフォルトではテスト実行の日時が入るので、.testrunconfigにテスト結果のファイル名を固定にするように別途設定が必要。
カバレッジをとる設定(インストルメント化する項目の設定)も.testrunconfigに設定しておく。
カバレッジを取る設定は、プロジェクトを増やすたびに手動で設定しないといけない。(追加するスクリプト書いてもよいけど。)
あと、テストは、ひとつのテストプロジェクトに突っ込んでおいたほうが自動テストするときにやりやすいかなと思った。
テストをプロジェクト毎にわけると、MSTest.exeの実行時にtestcontainerオプションで、そのプロジェクト(dll)を指定しないといけないので。
テストプロジェクトが膨れ上がって、テストプロジェクトのビルドが遅くなるという欠点はあるかも。
GenerateCoverage.buildの内容は、以下のとおり。
使っているdllは、以下からダウンロードできる。
http://code.msdn.microsoft.com/vscoveragetoxmltask
ConvertToEmma.buildの内容は、以下のとおり。
"C:\Program Files\msxsl\msxsl.exe"
msxslとmsxmlのダウンロードが必要。
MSTestCoverageToEmma.xslは、以下からダウンロードできる。
http://wiki.hudson-ci.org/pages/viewpageattachments.action?pageId=41878013&metadataLink=true
参考サイト:
http://wiki.hudson-ci.org/display/HUDSON/MSTest+Coverage+Reports
ADO.NET Data ServiceをSilverlightから使ってみた
簡単にサーバからデータを取得できるので、とっても便利。
サーバ側の実装工数をかなり削減できそうな雰囲気。
以下は、ADO.NET Data Servicesを触ってみた感じの疑問点と回答。
回答は適当に書いているので間違ってる可能性あり。
Q: 特定のユーザからのデータ操作を許可したりしなかったりはできるか A: インターセプターという概念があり、これを使ったらできそう (http://msdn.microsoft.com/ja-jp/library/dd552872.aspx) Q: クライアントのデータクラスのカスタマイズはできるか。 例えば、画面にバインドさせていたあるオブジェクトのメンバの値が変更されれば、別のメンバの値も変更するとか。 A: サービスの参照で自動生成されるデータクラスは、メンバ名_Changign()とメンバ名_Changed()というPartialメソッドを持ってる。 これを実装すればできそう。
ちなみにADO.NET Data Servicesは、WCF Data Serviceに名前が変わるようだ。
WCF RIA Serviceとか.NET RIA Servicesとか似たような名前がいっぱいあって混乱中・・・
testlinkと複数tracサイトとの連携
Testlinkでテストプロジェクト毎に別のTracサイトを指定できるようにTestlinkのコードを修正してみたので、メモ代わりに修正箇所を記録しておきます。(TestlinkのVersionは、1.7.4です。)
install_dir/lib/bugtracking/int_trac.phpのcheckConnectionViaXmarpc()に次のような箇所があります。
$this->m_dbHost = BUG_TRACK_DB_HOST . $tracProjectName;
これを
$this->m_dbHost = $tracProjectName;
に修正して、install_dir/cfg/trac.cfg.phpの$g_interface_bugs_project_name_mappingの設定をTracプロジェクトの名前ではなく、URLで指定します。
これまでは以下のようにテストプロジェクト毎にTracのプロジェクト名を指定していました。
/** Mapping TL test project name vs trac project url */ $g_interface_bugs_project_name_mapping = array( 'testlinkProject' => 'tracProject', '<YourTLTestProjectName2>' => '<YourTracProject2>', );
これを次のようにTracのURLを指定するようにします。
/** Mapping TL test project name vs trac project url */ $g_interface_bugs_project_name_mapping = array( 'testlinkProject1' => 'http://localhost/tracProject1', 'testlinkProject2' => 'http://localhost:8080/tracProject2', '<YourTLTestProjectName2>' => '<YourTracProject2>', );
Testlinkでテストケースをユーザに一括アサインするスクリプトを書いてみた
Testlinkでテストケースをユーザにアサインするのがとても面倒だったので、一括アサインするGreasemonkeyのスクリプトを書いてみた。
インストールすると、一番上の実行ボタンの横にAll Asignボタンが表示されてクリックすると、横のプルダウンメニューで選ばれたユーザが下の全てのテストケースにアサインされます。
今使っているTestlinkはver1.7.4だから、最新のTestlinkでは、このあたりのUIは改善されているかもしれないけど。
1.9のβもリリースされてるっぽいし、ちょっと今度さわってみなきゃ。
ってことで、書いたスクリプトは↓
javascripterの人はきっとxpathとかで華麗に書くんだろうけど、うまくいかなかったので、地道にやりました(汗
相変わらず汚くてすみません。
// ==UserScript== // @name testlink_assign_user // @namespace http://d.hatena.ne.jp/iox // @description Assign selected user to all testcase. // @include http://*/testlink/* // ==/UserScript== h1element = document.getElementsByTagName('h1'); if(h1element.length == 0) { return; } if(h1element[0].innerHTML.match(/テストケースに実行タスクをアサインするテスト計画/)) { create_assign_button(); } function create_assign_button() { // 一番上の実行ボタンを検索 var all_input_tags = document.getElementsByTagName('input'); var exec_button; for(var i in all_input_tags) { if(all_input_tags[i].value == "実行") { exec_button = all_input_tags[i]; break; } } // ボタン作成 var assign_button = document.createElement('input'); assign_button.setAttribute('type', 'button'); assign_button.setAttribute('value', 'All Asign'); assign_button.addEventListener('click', function() { // 選択されているユーザ情報を取得 var select_user = exec_button.previousSibling.previousSibling; var index = select_user.selectedIndex; var selected_value = select_user.options[index].value; var selected_user = select_user.options[index].label; // 全てのプルダウンメニューに一番上のプルダウンメニューで選択 // したユーザを設定 var all_selects = document.getElementsByTagName('select'); for(var j in all_selects) { var options = all_selects[j].options; for(var k in options) { if(options[k].value == select_user.value) { options[k].selected = true; break; } } } }, false); // ボタン配置 exec_button.parentNode.insertBefore(assign_button, exec_button.nextSibling); }