blog
三鷹の近くでrubyist(プログラム言語rubyを扱ってるプログラマさん)が集まり、美味しいものを食べながらプログラムのことなどの情報交換をするイベント、その名も「Mitaka.rb」。
その告知に出てた料理の写真があまりに美味しそうだったのでラペコの「ぺこぺこになった!」ボタンをクリックするノリで「このイベントに参加する」ボタンをクリック。

告知の料理画像に惹かれて僕(@machida)と@komagataさんも参加してしまいました。

ぺこぺこになった
Mitaka.rbとは…
「Mitaka.rb」は東京都三鷹で不定期開催されているRuby/Railsの地域コミュニティです。参加者はRuby/Rails関係者、WEB サービス関係者などで毎回20-40人の参加があります。「たのしいRuby、おいしいMitaka」をコンセプトに周辺の飲食店を会場に開催しており懇親会の後LT(Lightning Talk)をするのが通例です。Ruby/Railsの話ができて、お気に入りの店も増える、そんなコミュニティを目指しています。
さすがに「たのしいRuby、おいしいMitaka」をコンセプトにしているだけあって、料理が美味しい美味しい!
Mitaka.rb #10の会場は吉祥寺の「Bistro epices」というお店を貸し切って行なったのですが、さすがのお店チョイスです。
イベントじゃなくても利用したいレストラン、おすすめです。
しかも主催者の@ysakakiさんが懸賞に当たったので6000円のコースのうちの2000円を負担していただき、さらに(株)HatchUp様がスポンサーとして一人1000円の補助!
結局半額でご馳走になってしまいました。
@ysakakiさん、(株)HatchUp様、ご馳走様でした!
イベントのお手伝いをしていただいた前田製作所、つくる社の@monoookiさんがイベントのtweetをまとめてくださいました。
本当、tweetにもあるようにtweetの内容だけ見てると美食の会です。
せっかくイベントに参加するのだからと@komagataさんがLTの発表側にも参加してました。内容は@komagataさんがこの夏の自由研究で作ってるcloudで動くrubyで出来たCMS「pyha(ピュハ)」について。このイベントで発表するからと、イベントの数時間前に公式サイトをオープン。pyhaバージョン0.0.1もリリースしました。そのときのスライドは@komagataさんのブログにあがってます(ココ)。僕も一部、スライドで使ってる画像の加工で協力しました。
pyha、是非使ってみてください。
HTMLのインデントを綺麗にするだけのサービス、Ham Cutletを英語対応にしました。ブラウザの言語設定で英語が優先になってる人には英語で表示されるようになりました。
HTMLのインデントを病的に気にする外人さんがいたらオススメしてください・・・。
長らくブログを書かなかったので、右カラムの新着記事の一覧が@komagataさんのアイコンに占領されるという自体に。
ちょっと先月(2010年7月)はバタバタしてたのですが、お盆も終わったことだし、バタバタしてしまった反省もしたし、これからちょくちょくブログを書いていきます。
このバタバタしてたときにとっても役に立ったtodo管理のwebアプリ、todo.ly。
ものすごく使いやすくて、これを知った瞬間からすっかりヘヴィユーザーになりました。
http://todo.ly/
外国の先端のwebサービスって感じのトップページ。
僕はこの手のデザインに弱くて、ついつい使いたくなってしまいます。
sign upしたらメインのページへ。
すごくシンプルなメインページだけど、実はこのサービス、to do管理ツールの部分は下の画像にある1ページのみでページの遷移は一切ありません。

todo.lyにあるもの
左カラム
- Filters(to doの一覧を絞り込む)
- Projects(to doのカテゴリーの一覧を表示させる)
- Recycle Bin(ゴミ箱)
メインカラム
- to doの一覧の表示
- to doの新規追加の為の入力ボックス
これだけ!
このシンプルさは素敵過ぎ。
なんと言ってもtodo.lyはスピーディーに使えるところが使いたくなるポイント。
これはtodo.ly自体がAjaxでサクサク動くっていうのもあるし、UIもサクサクとタスクを登録できるように出来てる。
to do登録の手順
- まずはこれから登録するto doのカテゴリーを左カラムから選んでクリック。
- あとはto doの内容をメインカラムのボックスに入力するだけ。
to doを登録する際に考えることは、「to doのカテゴリー」と「to doの内容の文」だけ。
ページが遷移しないからサクサク動いてto doを登録するのに数秒しかかからない。
だからガンガンto do登録が進みます。
to doに期日(Due Date)も登録することができますが、しなくてもOK。必要なときはto do登録ボックスの下の「more」をクリックをすれば期日登録のボックスが表示されますが、「more」をクリックするまでは期日登録ボックスが目に入らないところもサクサク感を感じるポイントですね。
まぁ、上記の機能も動作も使い方もremember the milkにあるんだけど、Remember The Milkにはもっと機能があって、todo.lyの方はこれだけ。その分画面にある文字の量も情報も少ないので、Remember The Milkに比べてもっと使うのが簡単そうに見えます。
簡単そうだから特にIT系じゃないパソコンを使う人に勧めやすいです。僕が「使いたい」って思ったのも、やっぱり簡単そうだったから。まずは簡単そうに見えること、そして簡単なこと、これが大事ですね。
付箋にto doを書いてパソコンのモニターに貼ったりだとか、テキストエディタにto doリストを書いて終わったら消していく、なんて作業をやっているのを見たときに教えたくなるようなサービスです。
RubyInstallerのロゴが凄いです。
RubyInstallerはプログラミング言語のRubyをWindowsに簡単にインストールできるソフトです。
Windowsロゴ
Rubyロゴ
RubyInstallerロゴ
RubyのロゴとWindowsのロゴをうまい具合に組み合わせてあるので、両方を知ってる人なら見ただけでどういうものか分かりそうです。
そもそもRubyInstallerのロゴはデザインコンテストを行って広く募集した中から投票で1位に選ばれた物です。オープンソースのソフトなどはどうしてもプログラマー寄りの物が多く、デザインは後回しになってしまうことが多いですが、一般の方にも使ってもらうにはデザインはとても重要なので、こうした成果物を見ると、こういったコンテストはとても有効だと思いました。
つくる社さんの環境構築ガイドを勉強してKEIO Railsのイベントに参加しようとした矢先、@machidaさんがWindowsからMacにSwitchしてしまって、当日何も出来ずに精神的に追い詰められてゲロを吐いてしまいそうだというのでMac用のガイドを書いてみます。
全面参考:デザイナーのための Ruby on Rails + Windows 環境構築ガイド | つくる社LLC
Railsのアプリを作るには下記の物をインストールする必要があります。
- Xcode + iOS SDK(両方必要無いが、MacPortsを使うのに必要なソフトが一杯付いてくる)
- MacPorts(Macのアプリを簡単にインストールするプログラム)
- Ruby(プログラミング言語)
- RubyGems(Rubyのライブラリを簡単にインストールするプログラム)
- SQLite3(データベース。Railsのデフォルトデータベース)
- Ruby on Rails(RubyのWebアプリが簡単に作れるフレームワーク)
Xcode + iOS SDKのインストール
下記から最新版をダウンロードしてインストール。(要デベロッパー登録)
https://developer.apple.com/mac/
MacPortsをインストール
下記から最新版をダウンロードしてインストール。(数字が一番大きくて、SnowLeopard対応で拡張子がdmgのヤツ)
例:MacPorts-1.9.1-10.6-SnowLeopard.dmg
http://distfiles.macports.org/MacPorts/
Ruby、RubyGems、SQLite3をインストール
ターミナル.app(別名「黒い画面」)で下記を入力。
sudo port install ruby rb-rubygems sqlite3 rb-sqlite3
RubyGemsを最新版にアップデート
sudo gem update --system
Ruby on Railsをインストール
sudo gem install rails
サンプルアプリを作成してRailsの動作確認
cd (ホームディレクトリに移動)
mkdir rails
cd rails
rails test (test という Rails アプリを作成)
cd test
ruby script/generate scaffold Customer name:string (name というフィールドをひとつだけ持った Customer というモデルをベースにテンプレートの画面を作成)
rake db:migrate (DB にテーブルを作成)
ruby script/server (アプリケーションサーバーを起動)
ブラウザより、http://localhost:3000/customers にアクセスし、New customer で新しいレコードを追加したり、そのあと編集・削除などの操作ができれば成功です。
毎週火曜日、Help me, hackers!に上がったコードを紹介していくコードDJ 第9回。
「あなだのコードがー しぬほどスキダカダー!」(@チャン・ドンゴン)
komagata a.k.a. DJです。
今回紹介するのはコレ。
Ham Cutlet Chrome Extension – Help me, hackers!
HTMLのインデントを綺麗にする誰得サービスHam CutletのGoogle Chrome Extension。ブラウザの「このページのソースを見る」の代わりにインデントを綺麗にしたソースを表示するボタンをOmniBoxの右に追加するExtensionだ。
mongorian_chop a.k.a. 自由人が作ってくれた。ボタンのアイコンはmachida a.k.a. 漫★画太郎。軽いコラボ。

コードはココ。
mongorian-chop’s hamcutlet-extension at master – GitHub
manifest.json
[cc lang="javascript"]{
“name”: “Ham Cutlet Extension”,
“version”: “0.1″,
“description”: “Ham Cutletを使用したHTMLソース表示”,
“background_page”: “background.html”,
“browser_action”: {
“default_icon”: “icon.png”,
“defailt_title”: “Ham Cutlet”
},
“permissions”: [
"tabs"
]
}[/cc]
background.html
[cc lang="html"]
[/cc]
Chrome Extensionの作り方なんて知らないって?それならDJに任せろ!当然の如くDJも知らないからお前らの代わりに泣きながら覚えてやる!
モダンブラウザ・JS好きなら知らぬものはいないid:os0xの連載、続・先取り! Google Chrome Extensions:第1回 Chrome ExtensionsのAPI#1|gihyo.jp … 技術評論社で丁寧に説明されてるのでこれでわかりそうだ。
DJが超訳するとこんな感じだ。
- manifest.jsonの入ったディレクトリを作る
- 上のバーの右にあるボタンはbrowser_actionという
- browser_actionのボタンを押した時の動きはbackground_pageで指定したhtmlに書く
- Chromeで.crxパッケージを作れる。(単なるzipなので解凍も出来る)(CUI野郎にはConstellation’s crxmake at master – GitHubというパッケージングコマンドもあるらしい。)
作れる気がしてきた!早速コードを見ていこう。
6行目のbrowser_actionでタイトルとアイコンを設定してる。
10行目のpermissionsはクロスドメインでアクセスできるURLを指定するようだが、tabsはなんだろう?
5行目のbackground_pageで実際の動作を書くファイルを指定している。
background.htmlを見ていこう。
10行目のchrome.browserAction.onClicked.addListenerがキモだ。こうやってbrowser_actionをクリックした時の動作を設定するのだろう。
7行目のchrome.tabs.createでURLを指定してタブを開けるらしい。何かグリモンでも思ったけどクロスブラウザ問題が無いとJSってこんなにシンプルに書けるのかという・・・。
URLは以前、「HTMLのインデントを綺麗にするAPI – Help me, hackers!」でkyanny a.k.a. 刺身ブーメランが作ってくれたHam Cutlet APIを使って該当ページのソースをインデントを綺麗にした上で取得している。
これは簡単・・・。グリモンやFF拡張もそうだけど、実用的なものが簡単に作れるのがイイ!ECMAScripter的にもクロスブラウザに悩まされず思いっきりJSを書けるのも気持ちがイイ。
毎週火曜日、Help me, hackers!に上がったコードを紹介していくコードDJ 第8回。
「おでのからだはぼどぼどだー!」
komagata a.k.a. DJです。
今週はコレ。
WordPress.orgのプラグイン一覧でダウンロード数に目印をつけて欲しい – Help me, hackers!
登録してくれたのはmonoooki a.k.a. 前田製作所。速攻解決してくれたのはazu_re a.k.a. Firefoxの人(DJ主観)。
ソースコード:
[cc lang="javascript"]// ==UserScript==
// @name WordPress.org highlight counter
// @namespace http://efcl.info/
// @description WordPress.orgのタグ/単語検索のダウンロード数によって色を変える
// @include http://wordpress.org/extend/plugins/tags/*
// @include http://wordpress.org/extend/plugins/search*
// ==/UserScript==
/* TEST URL
http://wordpress.org/extend/plugins/search.php?q=word
http://wordpress.org/extend/plugins/tags/widget
*/
GM_addStyle(<>
.GM_downloads_count_50000{
background: #cc0000; color: #fff; padding: 1px 3px; -moz-border-radius: 3px;
}
.GM_downloads_count_10000{
background:#ffb0b0; padding: 1px 3px; -moz-border-radius: 3px;
}
.GM_downloads_count_5000{
background:#ffd792; padding: 1px 3px; -moz-border-radius: 3px;
}
.GM_downloads_count_2000{
background:#f9f49d; padding: 1px 3px; -moz-border-radius: 3px;
}
]]>>);
function hilightCounter(node){
var downloadsSpan = $X(‘//span[@class="info-marker"][text()="Downloads"]‘ ,node);
for(var i=0,len=downloadsSpan.length;i
var downloadCount = parseInt(countTextNode.textContent.replace(",","","g"), "10");// 数値化
var parDownload = downloadsSpan[i].parentNode;
var span = document.createElement("span");
if(downloadCount > 50000){
span.setAttribute(“class” , “GM_downloads_count_50000″);
}else if(downloadCount > 10000){
span.setAttribute(“class” , “GM_downloads_count_10000″);
}else if(downloadCount > 5000){
span.setAttribute(“class” , “GM_downloads_count_5000″);
}else if(downloadCount > 2000){
span.setAttribute(“class” , “GM_downloads_count_2000″);
}else{
continue;
}
span.textContent = countTextNode.textContent;
parDownload.replaceChild(span , countTextNode);
}
}
document.body.addEventListener(‘AutoPagerize_DOMNodeInserted’,function(evt){
var node = evt.target;
//var requestURL = evt.newValue;
//var parentNode = evt.relatedNode;
hilightCounter(node);
}, false);
hilightCounter(document);
// $X on XHTML
// @target Freifox3, Chrome3, Safari4, Opera10
// @source http://gist.github.com/184276.txt
function $X (exp, context) {
context || (context = document);
var _document = context.ownerDocument || context,
documentElement = _document.documentElement,
isXHTML = documentElement.tagName !== ‘HTML’ && _document.createElement(‘p’).tagName === ‘p’,
defaultPrefix = null;
if (isXHTML) {
defaultPrefix = ‘__default__’;
exp = addDefaultPrefix(exp, defaultPrefix);
}
function resolver (prefix) {
return context.lookupNamespaceURI(prefix === defaultPrefix ? null : prefix) ||
documentElement.namespaceURI || “”;
}
var result = _document.evaluate(exp, context, resolver, XPathResult.ANY_TYPE, null);
switch (result.resultType) {
case XPathResult.STRING_TYPE : return result.stringValue;
case XPathResult.NUMBER_TYPE : return result.numberValue;
case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
// not ensure the order.
var ret = [], i = null;
while (i = result.iterateNext()) ret.push(i);
return ret;
}
}[/cc]
このブログを読んでる人達ならそろそろグリモン見慣れてきたんじゃないか?泣きながらソース読んでたDJも慣れてきたよ。
12行目からはxmlリテラルでstyleを追加。でも、先頭の<>ってのはなんだろう?
61行目の$X関数はXPathのためのラッパー。こうして見ると色々な人が色々なXPathユーティリティーを選んでるのがわかる。$X関数は比較的昔からあって有名な方なんじゃないかと思う。
26行目のhilightCounterで注文通り、ダウンロード数別に色を変えるためにclassを割り当ててる。
41行目はびっくり。AutoPagerizeのイベントにひっかけてる。ブログのソースコードのSyntax HilightingとかJSのonloadでやってる場合に、AutoPagerizeの2ページ目からは反映されなくてガッカリ・・・ってことが多かったんだけどこれを使えばイケる!
これはDJ得した気分。
WordPressのプラグインページは見る人が多いからuserscripts.orgにきちんと登録してある点も素敵だ。
毎週火曜日、Help me, hackers!に上がったコードを紹介していくコードDJ 第7回。
今、流行の24シーズン1を見ているkomagata a.k.a. DJ(@流行に疎い方)です。
今回紹介するコードはコレ。
任意の期間、ブログが更新されないとメールが飛ぶwordpressのplugin – Help me, hackers!
出題したのは@machida a.k.a. お米嫌い。議論に対していきなりコードで回答を示したのが@terakuma a.k.a. 法務系PHPer。
コード:
[cc lang="php"]
/*
Plugin Name: Remember The WordPress
Plugin URI: http://github.com/e2esoundcom/Remember-The-WordPress
Description: If you forgot write a new post,this plugin send you E-mail.
Version: 0.2
Author: Yuya Terajima
Author URI: http://www.e2esound.com/
*/
/* When Activate Plugin
==================================================================== */
function rtw_activate() {
$time = time();
$terms = 7; //default terms
$unixtime_per_day = 86400;
$email = get_bloginfo('admin_email');
$subject = "Remember the WordPress!!";
$message = "Blogの更新が滞っているようです。サイトの更新をお願いします。";
if(!get_option('rtw_initialized') || get_option('rtw_initialized') !== $time) {
update_option('rtw_initialized',$time);
}
if(!get_option('rtw_terms')) {
update_option('rtw_terms',$terms * $unixtime_per_day);
}
if(!get_option('rtw_email')) {
update_option('rtw_email',$email);
}
if(!get_option('rtw_subject')) {
update_option('rtw_subject',$subject);
}
if(!get_option('rtw_message')) {
update_option('rtw_message',$message);
}
wp_schedule_event($time + 86400, 'daily', 'rtw_cron');
}
register_activation_hook(__FILE__, 'rtw_activate');
function get_latest_post_time() {
global $wpdb;
$query = "SELECT post_date FROM ".$wpdb->posts.”
WHERE post_status = ‘publish’
ORDER BY `”.$wpdb->posts.”`.`post_date` DESC LIMIT 0,1″;
$query = $wpdb->prepare($query);
return strtotime($wpdb->get_var($query));
}
function rtw_sendmail()
{
$subject = get_option(‘rtw_subject’);
$mailbody = get_option(‘rtw_message’);
$to_email = get_option(‘rtw_email’);
mb_send_mail($to_email,$subject,$mailbody);
}
function rtw_compare_time(){
$unixtime_per_day = 86400;
$latest = get_latest_post_time();
$terms = intval(get_option(‘rtw_terms’)) + intval($latest);
$time = time();
if(intval($terms) < intval($time)){
rtw_sendmail();
}
}
add_action('rtw_cron', 'rtw_compare_time');
/* When New Post or Edited Post.
==================================================================== */
function rtw_new_posted(){
update_option('rtw_initialized',time());
}
add_action('publish_post','rtw_new_posted');
/* When De-Activate Plugin
==================================================================== */
function rtw_deactivate() {
wp_clear_scheduled_hook('rtw_cron');
delete_option('rtw_initialized');
delete_option('rtw_terms');
delete_option('rtw_message');
delete_option('rtw_subject');
delete_option('rtw_email');
}
register_deactivation_hook(__FILE__, 'rtw_deactivate');
/* Admin
==================================================================== */
function rtw_add_admin_menu(){
add_options_page('Remember The WordPress','Remember The WP','administrator',__FILE__,'rtw_add_admin_page');
}
add_action('admin_menu','rtw_add_admin_menu');
function rtw_add_admin_page(){
if(isset($_POST['posted']) === FALSE){
$posted = FALSE;
}elseif(isset($_POST['posted']) === TRUE){
$posted = TRUE;
}
$unixtime_per_day = 86400;
if($posted) {
//Validation
if(preg_match('/[1-3][0-9]|[1-9]/',intval($_POST['terms']) AND intval($_POST['terms']) <= 30)){
update_option('rtw_terms',intval($_POST['terms'] * $unixtime_per_day));
update_option('rtw_email',stripslashes($_POST['email']));
update_option('rtw_subject',stripslashes($_POST['subject']));
update_option('rtw_message',stripslashes($_POST['message']));
$rtw_error = FALSE;
}else{
$rtw_error = TRUE;
}
}
?>
//Admin Page Start
//Updated Message
if($posted === TRUE AND $rtw_error === FALSE) : ?>
設定を保存しました
アラート発生日数は1-30の間の値を入力して下さい。
Remember The WordPress Settings
[/cc]
少々長いがへこたれずに頑張ってみていくことにしよう。(自分自身を鼓舞)
WordPressプラグインの作成方法
前提としてこれはWordPressプラグインなのでその大まかな作り方を紹介しよう。
まず、単体のphpファイルか、もしくは同名のディレクトリにプラグイン用のファイルを作る。
(例:foo_plugin/foo_plugin.php)
プラグインの各種情報は決まったコメントの書き方があるのでそれにしたがってファイル内先頭に書く。これがWordPressのプラグイン管理画面に出てくる情報になる。
一番単純なプラグインとしては、プラグインを管理画面から有効にすると、プラグインのphpファイルがWordPressにincludeされる。よって適当な関数をプラグイン内で定義しておき、テーマの中で使うといったことが可能だ。(モチロン名前はぶつかる可能性がある。プラグイン名をprefixにした関数を作るか、プラグイン名のクラスに閉じ込めることが推奨されている。)
これでWordPressの関数や変数、DBをプラグイン内からでも使うことが出来る。また、プラグイン用にactionやfilterといったフックをかける事ができる。この辺は公式ドキュメントに全関数リファレンスやプラグイン用のフックの説明がちゃんとあるのでPHPが分かれば理解するのは容易だ。(Main Page – WordPress Codex 日本語版)
擬似cron
今回のコードを理解する上でもう一つ必要になるのが、wp_schedule_event関数を使った擬似cronの仕組みだ。WordPressにはwp_schedule_event関数でcronのように定期スケジュールを登録することが出来る。こういう処理はcron daemonのように常に起動しているプロセスと連携する必要があり、一見単純なPHPウェブアプリだけでは無理に思えるが、Webからのユーザーリクエストのみをトリガーにcronのようなスケジュール実行を可能にしている。
もちろんWebからのリクエスト頼みなのでアクセスがまったく来なければスケジュールした時間には実行されない擬似的な機能なので厳密な処理には向かない。しかし、一般的なサイトであれば大抵毎分1アクセスぐらいはあるので大体このぐらいの頻度でやって欲しいといった処理なら実用上は問題なさそうだ。
参照:Function Reference/wp schedule event « WordPress Codex
こんないい加減な仕組み使うなんてありえねー!とヤルタイプからは言われそうだが、phpのsession削除は同様の仕組みで行われている。(アクセスが来なければ永久にセッションファイルは消えない)
根本的なこの仕組の是非は兎も角、PHPの流儀に従った実装方法ではあると言える。
Remenber The WordPress
まず、38行目でregister_activation_hook関数で自分自身のファイルのrtw_activate関数をactivation_hookに登録している。activationとはプラグイン管理画面でそのプラグインを「有効」にしたときのことだ。データベーステーブルを独自に持つようなプラグインでは大抵この場所でテーブルをCREATEしている。(WordPressはORMを提供していないので、各種プラグインのこの場所にはMySQLに特化したSQLが大抵使用されている。WordPressはプラグインエコシステムがキモであるため、コレのせいで他DBへの対応が非常に難しくなっている。)
rtw_activate関数の中でwp_schedule_eventを使ってdailyで実行されるようにrtw_cronを登録している。
あとは、40行目のget_latest_post_time関数で最終投稿日を取得して、管理画面で設定できる「何日更新が無かったらメールを送るか?」という値と比較してmb_send_mailでメールを送っている。
殆どの行数は管理画面用なので長く見えるし大変そうだが、管理画面からプラグインの設定が出来るというのがWordPressユーザーに非常に訴える箇所なので重要だ。
議論にコードで答えた事。(これが結構貴重なんだが)WordPress流儀に則った実装。管理画面まで手を抜かない所。等々、@terakuma a.k.a. 法務系PHPerは素晴らしい。それにRemember The MilkをパクったRemember The WordPressというプラグイン名も素敵だ。
WordPressプラグインで困ったことがあったら@terakuma a.k.a. 法務系PHPerに相談してみたらいいかもしれない!
毎週火曜日、Help me, hackers!に上がったコードを紹介していくコードDJ 第6回。
おい!ワールドカップ見てない癖に適当に話を合わせるのは辞めろ!DJ?モチロン見てたよ。本田のシュートは凄かったよね!・・・くらいやがれ!これが俺のワールドカップに対する知識の全てだ!
komagata a.k.a. DJです。
今回紹介するのはコレ。
無印良品のサイトの表示をデフォルトで「安い順、150件表示」にする – Help me, hackers!
まさに「プログラマーにとって解きたくなるような問題」といったセンスの良い問題を投稿してくれたのは@monoooki a.k.a. 前田製作所。
そして解決してくれたのはお馴染み@milk1000cc a.k.a. 牛乳嫌いプログラマ on Rails。(@milk1000ccはDJのストーキング情報によれば最近PONPONというグルーポン情報まとめサイトをRails, Herokuで公開したらしいRails野郎だ。)
二人ともありがとう!
しかし、ちょっと待ってくれ。コイツをどう思う?(@阿部高和)
% heroku console
>> Task.find(106).created_at
=> Tue, 06 Jul 2010 04:16:07 UTC +00:00
>> Task.find(106).comments.correct.first.created_at
=> Tue, 06 Jul 2010 07:02:54 UTC +00:00
「すごく・・・早いです・・・。」(@道下正樹)
タスクが登録されてからわずか3時間足らずで解決されている。(@荒巻)
たしかにDJも「これは解きたくなる問題だな」とは思ってはいたが、あまりにもはやすぐるでしょう?
本題のタスクの内容は、
こんな感じで無印良品ネットストアのデフォルトは「おすすめ順」「50件表示」になってる。それを「安い順」「150件表示」をデフォルトになるようにして欲しいというタスク。
あるある。確かにハードに使ってるサイトでこういうちょっとしたところを俺仕様にしたいことある。
それを通常ならありえない速さできょうきょ参戦(@ブロントさん)してくれたグリモンコードがコレ。
http://gist.github.com/465095
(右上のrawのリンクをクリックでグリモンスクリプトインストール)
// ==UserScript==
// @name AutoMujiSort
// @namespace http://www.milk1000.cc/
// @include http://www.muji.net/store/cmdty/section/*
// ==/UserScript==
(function() {
var OLD_PATTERN = { sort: 4, count: 12 };
var NEW_PATTERN = { sort: 0, count: 150 };
var $ = function(selector) { return document.querySelector(selector); };
if ($('select[name="sort"]') && $('select[name="sort"]').value == OLD_PATTERN.sort &&
$('select[name="count"]') && $('select[name="count"]').value == OLD_PATTERN.count) {
$('select[name="sort"]').value = NEW_PATTERN.sort;
$('select[name="count"]').value = NEW_PATTERN.count;
(typeof unsafeWindow != 'undefined' ? unsafeWindow : window).sort();
}
})();
きれいなコード。DJ以前はグリモンのコード「嫌だなぁ、嫌だなぁ、怖いなぁ」(@稲川淳二)なんて思ってたけどこの連載のお陰でむしろ好きになってきた。読み易い。
11行目のquerySelectorを$に割り当てるのはECMAScripterお馴染みパンチライン。最初のvarはconstにしたら速くなるのかも?
17行目のunsafeWindowを見てるのは多分ブラウザによって違うところなんだろう。
DJそろそろ気付いてきたんだが、今、タスクの需要と供給は依頼が少ない状態にある。特にJavascriptのタスクは監視してるイカレタHacker達が飢えた獣のように跳びかかり、瞬時に解決されてしまう。
成果物の公開方法やパッケージング方法、環境作りが楽なグリモン・JavascriptはHacker側にとって非常にやりやすい。そういう事情を踏まえた依頼の仕方もセンスが問われている。
センスを磨くか、金を積むか。そういう仕組みになっているらしい。
毎週火曜日、Help me, hackers!に上がったコードを紹介していくコードDJ 第5回。
TimeMachineで自動バックアップを取っていても結局クリーンインストール後は手でデータを復旧させる昭和の男、komagata a.k.a. DJです。
今回はコレ、フォームのデフォルトの文字をフォーカスが移ったら消す – Help me, hackers!
コレの経緯はこんな感じだ。
- F5V a.k.a. PHPerよりHam CutletにTwitter経由で上記の要望が入る。
- DJが要望をHelp me, hacekrs!に登録する。
- mongorian_chop a.k.a. 自由人からjQuery Watermark Pluginの情報を貰う。
- USTREAMの開発生放送でDJが上記プラグインでの実装に敗北。
- 見るに見かねたmongorian_chopが実装してpull request。
100万語の言葉より1つのpull request。コードは偉大だ。
「コード!コード!コード!」
「よし、ならばコードだ。」
今回のキモはココ。
$(document).ready(function(){
$.updnWatermark.attachAll();
$('.updnWatermark > label').click(function(){
$(this).toggle();
$("textarea").select();
}).blur(function(){
$(this).toggle();
});
});
$(document).ready(function(){ … }) はお馴染み、DOMの構築が終わった瞬間に実行してくれるjQueryの書き方だ。$(function() { … }) でも同じ。画像の読み込み等を待たない分、onloadより速いのでjQuerystはドンドン使ってこ!
今回、DJが挫折してたのはjQuery Watermark Pluginをtextareaに使った時に、そのWatermarkのテキスト自身をクリックした場合にWatermakが消えないところだ。
mongorian_chopはそこをちゃんと消すコードを書いてくれた。ありがとう!
jQueryだとちょっと面倒に思えた処理もこんなにスマートな見た目で書けるなんて。DJこの連載のおかげで強制的にJS勉強させられてるね!
DJ、今現在もHelp me, hacekers!上で複数のコード野郎共とコラボ中だ。議論する暇があったらコードを送りつけろ!









