$ rake rails:templates:copyあとは作成されたテンプレートをいじるだけ。以下、作業内容など。
- デザインに関すること(CSS用のクラス設定など)
- will_pagenateのページング対応
- 文言の日本語化
- .rbファイルにマジックコメントを追加 (# -*- coding: utf-8 -*-)
$ rake rails:templates:copyあとは作成されたテンプレートをいじるだけ。以下、作業内容など。
Javascriptで年初からの日数と週数を数えるメソッドをDateクラスに追加する。週数の方は、日曜を起点とした週数を数える(Rubyの%Uに相当)。
Date.prototype.getDayOfYear = function() {
var onejan = new Date(this.getFullYear(), 0, 1);
return Math.ceil((this - onejan) / 86400000);
};
Date.prototype.getWeekOfYear = function() {
var onejan = new Date(this.getFullYear(), 0, 1);
var offset = onejan.getDay() - 1;
var weeks = Math.floor((this.getDayOfYear() + offset) / 7);
return (onejan.getDay() == 0) ? weeks + 1 : weeks;
};
使い方は:
var time = Date.now(); var today = new Date(time); // Fri Mar 02 2012 16:49:11 GMT+0900 (JST) today.getDayOfYear(); // => 62 today.getWeekOfYear(); // => 9
RabbitMQとRubyで、同期的なRPC (Remote Procedure Call)を実装する。
サーバーにメッセージを送信するときは普通にサーバーがsubscribeしてるキューに届くように、適当なexchangeにpublishする。ここではex.rpc。
サーバーからのレスポンスの方は若干工夫が必要で、クライアントはリクエストのメッセージ送信前に、受信用の一時キューを作成しておいて、AMQPメッセージのreply_toヘッダーにキュー名を入れておく。サーバー側はリクエストを受け取ったら、処理結果をreply_toのキューに向けて送信する。このときはamq.directというデフォルトで用意されているexchangeを利用する。
サーバー側ではapiを増やすのが簡単なように、@acceptable_methodsにメソッド名を列挙しておくと、そのメソッドをクライアントから呼び出すことができるようにしてある。
このコードではクライアントはRPCの呼び出しの度にAMQPのコネクションを作成していて非効率なので、実際のアプリではAMQP.start (EventMachineのメインループ)はもっと外側にないとダメでしょう。
Ruby AMQPはEventMachineに依存しているため、利用する際にはEventMachineのイベントループ内にいる必要がある。RailsからRabbitMQに接続する場合は、RailsのプロセスからRabbitMQにTCPのコネクションを張り、その中でchannelを作成することになる。
RabbitMQとのコネクションは、$RAILS_ROOT/config/initializers/amqp.rbというファイルを作成してその中で作成すると、起動時に実行されてコネクションを繋いでおくことができる。
接続の設定ファイルはconfig/amqp.ymlなどとして保存しておけばいいんじゃないでしょうか。
development: host: localhost vhost: development test: host: localhost vhost: test production: host: localhost vhost: production
RailsのサーバーにThinを利用している場合、ThinがEventMachineベースなので特に気にせずconfig/initializers/amqp.rbには以下のように記述すれば良い。
def connect
yml = YAML.load File.read(File.join(Rails.root, 'config/amqp.yml'))
config = {}
yml[Rails.env].each do |key, value|
config[key.to_sym] = value
end
AMQP.connection = AMQP.connect(config)
end
EventMachine.next_tick do
connect
end
例えばAmqpController/publishでパブリッシュする場合、以下のようになる。
class AmqpController < ApplicationController
def publish
connection = AMQP.connection
channel = AMQP::Channel.new(connection)
exchange = channel.direct 'ex.direct'
msg = 'Hello, world'
exchange.publish(msg, :routing_key => 'tasks')
render :text => msg
end
end
AMQPでは、キューからコンシューマーにメッセージが配信されても、コンシューマーがそのメッセージを正しく受け取ったことをブローカー(RabbitMQ)に通知(acknowledge)しないといけない。
subscribeメソッドを引数なしで使うと、自動的にacknowledgeされるが、:ack => trueを指定すると手動で設定することになる(最初、逆かと思った)。
# 自動 ack queue.bind(exchange, :routing_key => 'tasks').subscribe do |headers, payload| # do some process end
# 手動 ack queue.bind(exchange, :routing_key => 'tasks').subscribe(:ack => true) do |headers, payload| # do some process headers.ack endメッセージ内容に応じてackするか決める場合は後者を使う。headers.ackメソッドでブローカーにacknowledgeしている。これをしないとメッセージはキューから削除されず、例えばこのコンシューマーがブローカーに再接続すると前回受け取ったメッセージが再送される。
RubyのクライアントからRabbitMQに接続し、Publish / Subscribeの動作確認をする。ここではdirect exchangeを使う。
AMQPクライアントライブラリはamqpを使う。よくメンテナンスされているし、ドキュメントもよく整備されているので決定版でしょう。
$ gem install amqp
まずはメッセージを購読するconsumerを作成する。 ここでは以下のような設定でメッセージを待ち受けている。
こちらは単純にexchangeを指定して送信するだけ。その際、consumerに合わせてルーティングキーを'tasks'にする。
最初にconsumer.rbを実行し、別ウィンドウでproducer.rbを実行して、consumer.rbに'Hello, world'と表示されれば成功。その際、procuder.rbの方にも'sent: Hello, world'と表示される。publishメソッドでパブリッシュし、RabbitMQから送信完了の応答があるとブロック内が呼ばれる。
MacにRabbitMQとWebの管理コンソールをインストールする。
RabbitMQはMacPortsでインストール。
$ sudo port install rabbitmq-server起動はrabbitmq-serverコマンド。
$ sudo rabbitmq-server Activating RabbitMQ plugins ... +---+ +---+ | | | | | | | | | | | | | +---+ +-------+ | | | RabbitMQ +---+ | | | | | | v2.7.1 +---+ | | | +-------------------+ AMQP 0-9-1 / 0-9 / 0-8 Copyright (C) 2007-2011 VMware, Inc. Licensed under the MPL. See http://www.rabbitmq.com/起動できたらCTRL-Cでメニューっぽいものが表示されるのでAキー(abort)で一旦終了。本来、rabbitmqctl stopとするのが正常な止め方のようだが、僕の環境でsudo rabbitmqctl stopとするとログ(/opt/local/var/log/rabbitmq/rabbit@hostname.log)に以下のようなエラーメッセージが出た。
=ERROR REPORT==== 19-Feb-2012::23:03:53 === ** Connection attempt from disallowed node 'rabbitmqctl67610@xxx' **これはErlang cookieというのが正しく設定されていないのが原因のようだが、ひとまずここでは放っておく。
Erlang関連はホスト名に注意が必要。会社の環境にインストールしたとき、DHCPを使っていた影響で、macのホスト名がIPアドレスになっていた。この状態だとRabbitMQを起動しようとしても、以下のようなログが出力されうまく起動できない。(以下の149はDHCPで振られたIPの最後の8ビットの値)
ERROR: epmd error for host "149": timeout (timed out establishing tcp connection)正しいホスト名に設定すれば起動できる。デフォルトのbashならターミナルのプロンプトの一番左側におそらくホスト名が表示されていると思われるので、参考に。
RabbitMQにはWeb画面でRabbitMQを管理できるプラグインがデフォルトでバンドルされているので、公式ページを参考にインストールする。 最初に必要なディレクトリがないので作成してから、コマンドを一発叩くだけ。
$ sudo mkdir /opt/local/etc/rabbitmq/ $ sudo rabbitmq-plugins enable rabbitmq_management # 再度RabbitMQ起動 $ sudo rabbitmq-server Activating RabbitMQ plugins ... 6 plugins activated: * amqp_client-0.0.0 * mochiweb-1.3-rmq0.0.0-git * rabbitmq_management-0.0.0 * rabbitmq_management_agent-0.0.0 * rabbitmq_mochiweb-0.0.0 * webmachine-1.7.0-rmq0.0.0-hg # ... 略そうしたら以下にアクセス。デフォルトのユーザー/パスワードはguest/guest。 これでWeb画面からexchangeやらqueueやらをWebコンソールから作ったり削除したりできる。
今開発しているシステムに、MQを導入しようと考えている。今の所RabbitMQが第一候補だが、比較しているページなどを調べてみた。
Pythonを使ってActiveMQとRabbitMQを比較している上記2のサイトが特に参考になる。要約すると:
ActiveMQも良さそうである。ただやはりActiveMQはJMSでJavaから使うのが普通っぽいし、ドキュメントもそういった使い方のものが多そうである。うちのシステムは今のところ大体がRuby。もちろんRuby用のクライアントライブラリも用意されているが、どうしようか。
RubyでJSONをインデントして出力するには、JSON.pretty_generateを使う。
require 'json'
my_json = { :array => [1, 2, 3, { :sample => "hash"} ], :foo => "bar" }
puts JSON.pretty_generate(my_json)
結果は:
{
"array": [
1,
2,
3,
{
"sample": "hash"
}
],
"foo": "bar"
}
参考:How can I “Pretty” format my JSON output in Ruby on Rails?
ちなみに、コマンドラインからのときはpythonを使った以下のワンライナーが使える。
$ echo '{"foo": "lorem", "bar": "ipsum"}' | python -mjson.tool
参考:How to pretty-print JSON script?
検索エンジンのSolrをRubyから使っている。ライブラリはrsolr。 このrsolrで複数ドキュメントを一括でアップロードする時、相当するメソッドがないように見えたが、 ソースを見たらaddに配列で渡せば問題なく複数ドキュメントを扱えるようになっていた。
require 'rsolr'
solr = RSolr.connect :url => "http://localhost:8080/solr"
documents = [
{:id => "1", :text => "text 1"},
{:id => "2", :text => "text 3"},
]
solr.add documents
solr.commit
最後のcommitは忘れがちなので気をつける。
日本語の解説本『Apache Solr入門』ではsolr-rubyを紹介していたが、rubygemsでのダウンロード数がrsolrのほうが随分上なのでこっちを選んだ。
以下の環境にMeCab 0.992 と ruby-mecab 0.992をインストールする。
MeCab本体は公式サイトに乗っている通りにソースからインストール。ちなみに僕は~/localにインストールした。
$ tar zxfv mecab-0.992.tar.gz $ cd mecab-0.992 # MeCabインストール $ ./configure --prefix=/Users/your_home/local $ make $ make check $ make install辞書はUTF-8で作成するようにした。
# IPAの辞書インストール $ tar zxfv mecab-ipadic-2.7.0-20070801.tar.gz $ mecab-ipadic-2.7.0-20070801 $ ./configure --prefix=/Users/your_home/local --with-charset=utf8 $ make $ make installこれでインストールで来たので、コマンドラインで確認。
$ mecab # これでREPLとして起動する すもももももももものうち # <= ターミナルに打ち込む すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ も 助詞,係助詞,*,*,*,*,も,モ,モ もも 名詞,一般,*,*,*,*,もも,モモ,モモ も 助詞,係助詞,*,*,*,*,も,モ,モ もも 名詞,一般,*,*,*,*,もも,モモ,モモ の 助詞,連体化,*,*,*,*,の,ノ,ノ うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ EOS
ダウンロードページからRubyバインディングをダウンロードする。
$tar xzvf mecab-ruby-0.992.tar.gz $ cd mecab-ruby-0.992ここで、僕はMeCabを~/localにインストールしているので、以下のパッチをextconf.rbにあててライブラリの参照先を修正した。/usr/localにインストールしている場合は不要(たぶん)。 (参考)
--- extconf.rb.org 2012-02-08 14:10:41.000000000 +0900
+++ extconf.rb 2012-02-08 14:13:08.000000000 +0900
@@ -8,5 +8,6 @@
}
$CFLAGS += ' ' + `#{mecab_config} --cflags`.chomp
+$LDFLAGS = '-L/Users/your_home/local/lib'
have_header('mecab.h') && create_makefile('MeCab')
で、コンパイルしてインストール。
$ ruby extconf.rb $ make $ make install付属のtest.rbがそれらしく動けばOK。
$ ruby test.rb 0.992 太郎 名詞,固有名詞,人名,名,*,*,太郎,タロウ,タロー は 助詞,係助詞,*,*,*,*,は,ハ,ワ この 連体詞,*,*,*,*,*,この,コノ,コノ 本 名詞,一般,*,*,*,*,本,ホン,ホン を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ # (略)
mecab-rubyをRuby 1.9で使うと、結果の文字列のエンコーディングがascii-8bitになっている。
# coding: utf-8
require 'MeCab'
t = MeCab::Tagger.new
node = t.parseToNode('日本語のテスト')
surface = node.next.surface
p [:surface, surface.encoding, surface]
# => [:surface, #<Encoding:ASCII-8BIT>, "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E"]
仕方がないのでString#force_encodingで強制的にUTF-8に変換する。
http://d.hatena.ne.jp/miyapong/20100706/1278419260
surface = node.next.surface.force_encoding("UTF-8")
p [:surface, surface.encoding, surface]
# => [:surface, #<Encoding:UTF-8>, "日本語"]
会社でUbuntu上にRailsをインストールしようとして、若干手間取ったのでメモ。(Ubuntuはまっさらからのインストール)
(最終的な)環境は以下の通り。
Git, RVM, Rubyをインストールする。会社環境はプロキシ内なので、そのあたりも注意。
まずはプロキシの設定。必要に応じて.bashrcなりにも追記。
$ export http_proxy="your.proxy.name:8080" $ export https_proxy="your.proxy.name:8080"ついでcurl, Git, build-essentialインストール。
$ sudo apt-get install curl $ sudo apt-get install git $ sudo apt-get install build-essentialで、~/.gitconfigに以下を追記。
[http] proxy = %http_proxy%Ubuntuのデフォルトでは各種devパッケージが入っていないようなので、zlib1g-dev libssl-dev libreadline-gplv2-dev libxml2-dev libsqlite3-devを追加インストール。参考
$ sudo apt-get install zlib1g-dev libssl-dev libreadline-gplv2-dev libxml2-dev libsqlite3-dev
rvmでRuby本体をインストール。
$ rvm install 1.9.2このままだとgem installが失敗するので、zlibをコンパイル。参考
$ cd ~/.rvm/src/ruby-1.9.2-p290/ext/zlib $ ruby extconf.rb $ make $ make install同様に、bundleで使うsslのためにopensslもコンパイル。
$ cd ~/.rvm/src/ruby-1.9.2-p290/ext/openssl $ ruby extconf.rb $ make $ make install
ここでようやくrailsインストール。
$ gem install rails $ rails -v Rails 3.2.1 $ rails new testapp $ cd testappただ、ここでscaffoldするとExecJS::RuntimeUnavailableが発生、と怒られるので、Gemfileにexecjs, therubyracerを追加。 参考
gem 'execjs' gem 'therubyracer'ここでもう一度bundle install(ここで、上記build-essentialが入っていないとg++がなくてコンパイルできない)
$ bundleようやくscaffoldを実行し、動作確認。
$ rails g scaffold user user_name:string age:integer $ rake db:migrate $ rails serverできた。
Gitで、リモートにあるbareリポジトリ(repo.gitのようなリポジトリ)の扱いについてメモ。
ここでは以下のようなリポジトリ構成になっているものとします。
bareリポジトリ(MAIN.git)上ではマージはできない。これは第一にbareリポジトリにはwork copyがないから。work copyがないと、マージで衝突したときに解決する手段がない。bareリポジトリ上のブランチのマージは、一度開発環境(LOCAL)など別のリポジトリ上にプル/チェックアウトし、そこでマージしたうえでリモートにpushする。
CENTER.gitで修正があり、それをMAIN.gitに取り込むにはgit fetchを使う。これだけで取り込みはOKのはずだが、fetchで取り込んだだけではHEADが更新された最新に移動しないので、reset --softする(work copyがないので、softでないとエラーとなる)。
# 以下、MAIN.git上での操作 $ git fetch <CENTER.git> $ git reset --soft HEADこの後でgit logすると、最新の変更がログに出力される。
たとえばoriginに指定されているリモートリポジトリのdev-remoteブランチに、ローカルのdev-localブランチをpushする場合:
$ git push origin dev-local:dev-remote
リモートリポジトリ(MAIN.git)のdev-remoteブランチを、ローカルにdev-localブランチとして取得する場合、まずgit cloneした後、リモートのブランチを指定してcheckoutする。
git clone <MAIN.git> git checkout -b dev-local remotes/origin/dev-remote
ローカルで作成したタグをリモートに反映する
$ git push --tags
Railsではデフォルトでdevelopment, test, productionという環境に対応できるように作られているのはご存知の通り。 この環境ごとの設定や、新しい環境の追加方法などについて、簡単にまとめる。
ちなみに執筆時点では以下の実行環境を利用している。
Rubyのコードの中から現在の環境名(development|test|productionなど)を取得するのは、Rails.envを利用する。
例えばstagingという環境を新規に追加するには、以下の作業をする。
$ rake db:create RAILS_ENV=staging $ rake db:migrate RAILS_ENV=staging $ rails server -e staging
たとえばdevelopmentとproductionで違うgemを利用する場合、Gemfileに以下のように記述する。
group :development, :test do gem 'sqlite3-ruby' end group :staging, :production do gem 'mysql2', '0.2.7' endbundle installする際には、以下のようにすると特定の環境で必要なgemを除外できる。
$ bundle install --without test development参考: Bundler : Using Groups
Scalaのパーサーコンビネーターの練習のため、数式をパースして計算してみる。
参考にしたのはコップ本と、以下のサイト。
実行引数に数式を文字列で与えると計算結果を標準出力にプリントする。
$ scala ArithmeticParser.scala "(2 + 3) * -2.5" -12.5
ValueからParenまでのクラスは、数式をモデリングするためのもの。ここはパーサーからは独立している。
ArithmeticParserで、これらのクラスに入力の数式をマッピングしていく。
def factor: Parser[Value] = (
floatingPointNumber ^^ { case n => Number(n.toDouble) }
| "-"~>floatingPointNumber ^^ { case n => Number(n.toDouble * -1.0) }
| "("~>expr<~")" ^^ { case e => Paren(e) }
)
factorがもっとも細かい単位にマッチする。つまり、数値か括弧()。数値を表すfloatingPointNumberは継承元のJavaTokenParsersで定義されていて、浮動小数表現にマッチする。マッチしたあとの処理(返り値の計算)は^^で定義する。この箇所のように複数種類の要素にマッチする場合は、それぞれを | で列挙する。"-"~>floatingPointNumber で負の数(-2.5など)にマッチさせる。最後の"("~>expr<~")"で括弧表記にマッチさせる。"x"~>という表記は、読み取った"x"を捨てる。逆に"x"~という表記であれば"x"を解析結果として利用できる。
def expr: Parser[Value] = term~rep(addSub) ^^ { case f1~rest => Formula(f1, rest) }
def term: Parser[Value] = factor~rep(multiDiv) ^^ { case f1~rest => Formula(f1, rest) }
termはfactorの掛け算/割り算の連続(2 * 3など)。連続ということをrepで表現している。exprは同様にterm同士の足し算/引き算の連続(2 + 3など)。またfactorのうち括弧表現のときは、内容としてexprを含む。
def multiDiv: Parser[Rest] = ("*"|"/")~factor ^^ { case op~v => Rest(op, v) }
def addSub: Parser[Rest] = ("+"|"-")~term ^^ { case op~v => Rest(op, v) }
multiDivは掛け算のうち、記号と後ろ側の数値にマッチする(/ 2など)。したがって1 * 2 / 3というtermは、イメージとしては[1, [[*, 2], [/, 3]]]という形にパースされる。addSubも同様。
parseAll(expr, e).get.evalパースの実行はparseAllで。第一引数に、入力全体にマッチさせる関数を指定。第二引数にパースする文字列を渡す。結果としてパース結果のオブジェクトが帰って来るので、getで最終的な^^で指定したパース結果を取得する。今回はValue型で帰って来るので、evalで計算している。
最初は全然よくわからなかったが、ちょっと書いてみると確かに強力そうな気がしてきた。
TwitterのAPIでは、次の二つを使う。
Rubyでは以下のような感じ。
require 'twitter'
ids = Twitter.friend_ids("daixque").ids[0, 10]
users = Twitter.users(ids)
取得できる量に制限があるので(最大100件)、先頭の10件に絞っている。
今、Neo4jを調査しているのでメモ。
Neo4jはグラフDBとよばれるNoSQL系のデータベースです。Twitterのフォロー関係のような、有向グラフ構造を保存できます。
Neo4jはJavaからは組み込みで利用できますが、その他ネイティブ系のバインディングが全然ありません。そのかわり、RESTによるJSON/HTTPのインターフェイスが用意されています。
ここではRESTサーバーとRubyクライアントのセットでNeo4jを利用する例を紹介します。
Neo4jサーバーをコマンドラインから起動するだけなら、ダウンロードページから落としてきて起動するだけ。
サービスに登録するためのコマンドも用意されています。
sudo ./bin/neo4j install
$ cd NEO4J_HOME $ bin/neo4j start
以下のURLからWebの管理画面を表示できます。
http://localhost:7474/webadmin
$ bin/neo4j stop
以下のフォルダを削除すると、全てのデータを消去できます。
NEO4J_HOME/data/graph.dbただし、サーバーが停止しているときに消さないといけないみたいです。消したつもりが復活したりしました。
データ削除インターフェイスを追加するアドオンとかも見つけましたが、1.5までの対応のようです。(執筆時点でのNeo4j最新は1.6。無理矢理動くかは未検証)
https://github.com/jexp/neo4j-clean-remote-db-addon
RESTインターフェイスについては以下にドキュメントがあります。
http://docs.neo4j.org/chunked/milestone/rest-api.html
ただ、そこまで充実しているわけではありません。 Java APIも含め、全体を網羅したPDFもありました。
http://docs.neo4j.org/pdf/neo4j-manual-stable.pdf
僕はRubyから利用したいので、NeographyというNeo4jのRESTクライアントを使います。
https://github.com/maxdemarzi/neography
インストールはgemで。
gem install neography
Neography以外にも、RailsのActiveModelのように動作するものとして、以下のようなものがあるようです。
ノードやリレーションの作成などのシンプルな操作はgithubのサンプルを見てもらうとして、グラフをトラバースする方法についてメモしておきます。ちょうどneographyを使ったfacebookの友達サジェストのサンプルがありました。
https://github.com/maxdemarzi/neography/blob/master/examples/facebook.rb
サジェストする部分を見てみます。
def suggestions_for(node)
@neo.traverse(node, "nodes", {
"order" => "breadth first",
"uniqueness" => "node global",
"relationships" => { "type" => "friends", "direction" => "in" },
"depth" => 2,
"return filter" => {
"language" => "javascript",
"body" => "position.length() == 2;"
}
})
end
最初の引数nodeはグラフ走査の起点です。第二引数"nodes"はノードの走査をする、ということを指定しています。 第三引数のオプションとして、それなりの指定があります。
orderでは幅優先"breadth first"を指定しています。他に深さ優先"depth first"が指定できます。
return filterでは、検索条件を指定します。ここではnodeから2ホップのノード(友達の友達)を返すように指定しています。
depthでは、トラバースする際の最大の深度を指定しています。
Neo4j特有のクエリー言語として、Cypherがあります。
http://docs.neo4j.org/chunked/snapshot/cypher-query-lang.html
neo.execute_queryというメソッドでCypherクエリーを実行できます。 たとえば先ほどの友達サジェストは、以下のように書けます。
require 'rubygems'
require 'neography'
@neo = Neography::Rest.new
def create_person(name)
@neo.create_node("name" => name)
end
def make_mutual_friends(node1, node2)
@neo.create_relationship("friends", node1, node2)
@neo.create_relationship("friends", node2, node1)
end
def suggestions_for(node)
n = Neography::Node.new node
q = "START n=node(#{n.neo_id}) MATCH n -[:friends]-> f -[:friends]-> t WHERE not(t.name = n.name) RETURN t.name"
result = @neo.execute_query(q)
result["data"].map { |f| f.first }
end
johnathan = create_person('Johnathan')
mark = create_person('Mark')
phill = create_person('Phill')
mary = create_person('Mary')
luke = create_person('Luke')
make_mutual_friends(johnathan, mark)
make_mutual_friends(mark, mary)
make_mutual_friends(mark, phill)
make_mutual_friends(phill, mary)
make_mutual_friends(phill, luke)
puts "Johnathan should become friends with #{suggestions_for(johnathan).join(', ')}"
結果:
Johnathan should become friends with Mary, Phill
ここで実行しているクエリーはこんな感じです。
START n=node(#{n.neo_id})
MATCH n -[:friends]-> f -[:friends]-> t
WHERE not(t.name = n.name)
RETURN t.name
traverseの例とちょっと論理的に同等とは言えないかもしれませんが(同値チェックのあたり)、この例ではうまく動きます。 Cypherではこのように、STARTで起点、MATCHで検索条件、WHEREでフィルター条件、RETURNで戻り値を記述します。MATCHの記法はなかなか強力で、a -[:link]-> t <-[:link]- bのように、逆向きのリレーションも扱えます。
TinkerPopというところが、グラフDBのためのソフトウェアスタックを用意しています。
グラフのトラバースなどに特化したクエリー言語Gremlinや、RESTインターフェイスのRexsterなどがあります。 本当ならNeo4jを直に使うよりこちらを経由した方が良いと思うのですが、ちょっとまだこなれてない感じがしました。
今日のところは、とりえあえずここまで。
jQueryの$.ajaxでjsonpを使うと、errorハンドラが発火しない。jQuery+jsonpでエラーハンドリングが必要なケースは、jquery-jsonpを使う。
$.jsonp({
url: url,
dataType: 'jsonp',
callbackParameter: 'callback', // パラメータ名がjsonpではなくcallbackParameter
success: function(data, status) {},
error: function(XHR, textStatus, errorThrown){}
});
参考:jQuery ajax (jsonp) ignores a timeout and doesn't fire the error event
Rubyで書かれたHTTPのダミー/モックサーバーを手軽に作るためのツール、Cameleonをリリースしました。
仕事でよくHTTPの外部システムを使うアプリを作ることがあるのですが、Cameleonはその外部システムのモックを簡単に作るために開発しました。何度か実際の開発案件で利用しています。
使い方はRuby on Railsの感じを参考にしています。
特徴
Rubygemsで一発インストール
$ gem install cameleonインストールできるとcameleonコマンドが使えるようになります。
まずは、cameleonのプロジェクトをnewコマンドで作ります。
$ cameleon new your_project_nameできたディレクトリに移動してserverコマンドを実行するとデフォルトでポート9292でサーバーが起動します。
$ cd your_project_name $ cameleon server別のターミナルを立ち上げて、curlでテストしてみましょう。
$ curl http://localhost:9292 Hey, I am cameleon! Edit response folder to change response whatever you want. see README.md more detail.はい、とりあえず動いていることは確認できました。
たとえば次のようなインターフェイスを作成することを考えます。
$ mkdir -p response/path/to/interface $ cd response/path/to/interface $ echo "ok" > default.txtcurlでテストしてみましょう。
$ curl http://localhost:9292/path/to/interface ok同様のことはgenerateコマンドを使うとより簡単です。ここでは/path/to/fooに新しいインターフェイスを作ってみます。
$ cameleon generate path/to/fooこちらもテスト。
$ curl http://localhost:9292/path/to/foo edit me: response/path/to/foo/default作成できてますね。レスポンスは必要な内容に書き換えて下さい。
普通アプリ開発で利用するのであれば、モックとはいえ、レスポンスをリクエストに応じて変化させる必要があるでしょう。そのときはフォルダ内に"_switch.rb"というファイルを作成し、その中でどのレスポンスファイルをレンダリングするかを選択します。
_switch.rbはRubyで自由に記述できます。レスポンスの内容を切り替えるためには、renderメソッドでレスポンスファイルを選択します。renderメソッドが呼ばれると、そこで_switch.rbからはすぐに抜け、以降の処理は継続しません。逆に、最後までrenderメソッドが呼ばれなかった場合は、defaultで始まるファイルをレンダリングします。また、_switch.rbではparamsにリクエストパラメータが格納されているので、これを使ってレスポンスを選択するといいでしょう。
_switch.rbのサンプルです。
# you can access URL parameters by 'params' case params[:key] when "foo" # curl http://localhost:9292/gallery/params?key=foo render "foo.txt" when "bar" # You can also use POST or PUT. See 'rest' more about hadling HTTP methods. # curl -XPOST http://localhost:9292/gallery/params -d"key=bar" render "bar.txt" end # if else, render "default" (any extention acceptable) file.
galleryコマンドで、response/galleryディレクトリにサンプルが出力されます。最初は_switch.rbで使えるAPIなどの参考になるとおもいますので利用して下さい。
$ cd YOUR_CAMELEON_HOME $ cameleon gallery
私はけっこう便利に使えているので、ぜひ利用してみて下さい。
markd is rich html builder for markdown, and is especially focused on printing purpose. You can get well-formatted printings (or PDF by preview) when you print html using modern browser (such as Google Chrome, Firefox, Safari).
Source code is available on github.
markd is based on bluecloth and google code prittify.
features:
You can install markd using RubyGems as below:
$ gem install markd
Build html from markdown:
$ markd -o out_dir markdown.mdwhere markdown.md is target markdown file and out_dir is directory that html/css/js files are generated into. Use -h (or --help) option to show detail.
$ markd -h
markd is released under the MIT license.
Enjoy!