「GitHub」と一致するもの

Meteor 1.2からはAngularとReactのサポートも追加されましたが、Blazeも根強い人気があります。今回はそんなBlazeをちょっと使いやすくするパッケージを二つ紹介します。

初めに紹介するパッケージは、Handlebar-helpersです。

インストールは、

meteor add raix:handlebar-helpers

です。これを使うと、テンプレートで、

{{#if $lt counter 10}}

のようなことが書けるようになります。実は本来テンプレートにはロジックを書くのはよろしくないので、これはあまり好まれない場合があります。しかし、通常の書き方だと、

{{#if isCounterLargerThanTen}}

のようになりヘルパー関数を用意する必要があります。よって、小規模プロジェクトなどでは原則を破ってロジックを書いてしまった方が効率がよい場合もあると思います。

次に紹介するパッケージは、blaze-magic-eventsです。

インストールは、

meteor add themeteorites:blaze-magic-events

です。これも好みが分かれるところですが、イベントハンドラを書きやすくするものです。テンプレートに、

<button onclick={{sayHi}}>Say Hi!</button>

と書いて、JavaScriptコードに、

Template.helloworld.events({
  sayHi (event, template) {
    console.log('event and templateInstance params', event, template)
    template.$('p').html('hi there from sayHi() handler!')
  }
});

と書きます。これも微妙にロジックを書いてしまっているので美しくないのですが、jQueryに慣れている人は分かりやすいかもしれません。

最後にせっかくなので、自分のパッケージも紹介しておきます。blaze-showhideです。これもテンプレートに簡単なロジックを書いて表示・非表示を切り替えるようにするものです。

以上、テンプレートにはロジックを書かないという原則を破ってちょっと便利にするパッケージの紹介でした。

以前、Angular向けに自分で開発したsocial-cms-backendは今もメンテナンスしていますが、 これのMeteor版があったら面白いだろうなと思っていました。Meteor版だとfrontendも含まれるので、単にsocial-cmsと呼ぶものになるかなとか。 既に、似たようなものが既にあったので紹介します。自分で作る手間は省けたものの、作ってみたかったという気持ちもあったりします。

一つは、ryw:blog (GitHub)です。 これは他のアプリに組み込むライブラリとしての位置付けで作られたもので、 なんとiron-routerとflow-router両方に対応しているということです。 単体で動かそうと思うと、意外とパッケージ導入に手間がかかりました。 参考までに手順をまとめておきます。

meteor create test-app
cd test-app
meteor add ryw:blog
meteor add kadira:flow-router kadira:blaze-layout
meteor add twbs:bootstrap ian:accounts-ui-bootstrap-3
meteor add accounts-password
meteor run

その後、htmlにログインボタンを設置すれば一応動きます。 ただし、デフォルトでは全員管理者になってしまうので、ロール管理しようとするともう少し複雑になります。 accounts-admin-ui-bootstrap-3 を使うとよさそうですが、初期の管理者を手動で設定する必要があったりと多少導入にハードルを感じます。 もっと簡単にスタンドアローンで動かすための整備は、まだ残件かなと思いました。

UIはいろいろカスタマイズできるようになっているようですが、コメント機能がないのは不完全な感じがします。 DISQUSを使う方法が説明されていますが、スタンドアローンで機能拡張できるとよいです。 そういう意味では、ライブラリとして使うものなのか、すぐに使えるようにするものなのかが曖昧に感じてきました。 このあたりもう少しいじってみたいような気もします。

さて、ついでにもう一つのパッケージを紹介します。 xolvio:md-blog (GitHub)です。 これは、The Meteor Testing Manualで実際に使われているアプリのパッケージのようです。 こちらにデモサイトがあるので様子が分かります。 表示のカスタマイズやロールの設定もできるようです。 試してはいませんが、スタンドアローンで動くアプリを作るのが目的であればこちらの方が楽かもしれません。

感想ですが、だいぶ便利なものが作られているなと思う一方で、まだまだ色々登場しそうですし、何か作ってみたいなと思います。

Meteorの標準テンプレートであるBlazeはシンプルで割と気に入っています。 最低限の機能が用意されていて、あとは自分でがんばってねという感じが悪くないです。 ただ、Angularに慣れてしまうとこんなことはできないのかなどと思うことがあります。

その一つが、ng-showみたいなこと。ng-clickと合わせて表示を切り替えることがしばしばあります。

Blazeでは{{#if}}を使うと似たようなことができます。これはおそらくng-if相当です。具体的には次のようになります。

<template name="foo">
  {{#if hello}}
    <p>Hello World!</p>
  {{/if}
</template>

と

Template.foo.helpers({
  hello: function() {
    return Session.get('hello');
  }
});

さらに表示を切り替えるボタンは例えば次のようになります。

<template name="bar">
  <button>Toggle</button>
</template>

と

Template.bar.events({
  'click button': function(event) {
    event.preventDefault();
    Session.set('hello', !Session.get('hello'));
  }
});

ちなみに、AngularだとHTML内にロジックを書いてしまえば次のように書けます。

<p ng-if="hello">Hello World!</p>
<button ng-click="hello = !hello">Toggle</button>

そこで、Blazeでも簡単に書けるようにするパッケージを作ってみました。

https://atmospherejs.com/daishi/blaze-showhide

これを使うと、

<div>
  {{#showIf name="hello"}}
    <p>Hello World!</p>
  {{/showIf}}
  {{#toggleShowHide name="hello"}}
    <button>Toggle</button>
  {{/toggleShowHide}}
</div>

こんな感じで書けるようになります。Sessionはアプリで共通なので実際に使う場合は他のtemplateと競合しないように注意する必要があります。

ng-ifやng-showを使いたいのならangular-meteorを使えばよいのではないかという意見もありますが、それはそれとしてBlazeでもパッケージでこういうやり方ができるということが分かりました。

余力があればやってみたいことは、ng-show相当の機能や設定のカスタマイズなどです。 余力というかモチベーションですが。

ところで、既に似たような機能を持つパッケージがないか探したのですが、見つかりませんでした。 もしかしたら、探し方が不十分であるパッケージの一機能として実現されているものもあるかもしれません。 いずれにしてもパッケージ作りの勉強になりました。

最近、Meteorの勉強中です。何かパッケージを作ってみたいと思ったのですが、多くのものはすでに誰かがやっています。 MeteorのパッケージはAtmosphereで探します。

今回、自分が使おうと思ったものにぴったりのものが見つからなかったので、作ってみました。 探したものはFacebookのAPIを呼び出すライブラリです。OAuthのライブラリはMeteorで提供されているのですが、Graph APIを使うものは3rt partyのものを探しことになります。

見つけたのはこれらです。

  • biasport:facebook-sdk mrt時代からあるパッケージでインストール数も多いです。ドキュメントを見るとクライアントライブラリのようです。
  • stevezhu:fbgraph fbgraphをラップしたパッケージです。サーバサイドのみで動きます。
  • mrt:facebook-sdk これがオリジナルっぽいですね。
  • jdrorrer:facebook-sdk
  • dcsan:facebook-sdk
  • dferber:graph-api
  • maxkferg:facebook-collections 少し趣向が変わった感じでおもしろそうです。クライアントから使うことがメイン。
  • borges:facebook-sdk
  • timbroddin:facebook-node-sdk ドキュメントがないのでどういうものか分からず。

いっぱいあるように見えますが、facebook-node-sdkはGitHubを見るとforkしているのが分かります。

https://github.com/jdrorrer/facebook-sdk/ ← https://github.com/dcsan/facebook-sdk ← https://github.com/biasport/facebook-sdk ← https://github.com/hugesuccess/facebook-sdk

ネットワーク図を見てもいいかもしれません。全部は表示されていないようですが。

さて、今回はサーバサイドのライブラリを探していたのでfbgraphとgraph-apiが候補なのですが、過去の検討で使っていたライブラリを使いたいという要求もありました。 そこで、そのライブラリをMeteorパッケージにラップしました。

作ったパッケージは、 https://atmospherejs.com/daishi/facebook-server-api です。

ソースコードは、GitHubにあります。 中身はなんと2行だけです。

一応、新規にFB.mapiというAPIを用意しました。Meteor流のfibersを使った同期的APIです。

fibersはあまり好まないのですが、Meteorでやっていくには仕方ないかと諦め気味です。

先日の記事で、 ブログシステムとしてGhostを使ってherokuにデプロイする話を紹介しました。

ところが使い始めてみるといくつか問題がありました。

  1. herokuはアクセスが無いとスリープするので、サイトを初めて開くときに時間がかかる
  2. 常にアクセスが来るとスリープはしなくなるが、Freeプランの範囲を越えてしまい、Hobbyにアップグレードするように催促が来る
  3. 画像ファイルを置けないのはやはり多少不便である

そこで、hexoに移行してみることにしました。デプロイ先はgithub.ioです。 github.ioがどこまで使えるのかは分かりませんが、少なくともherokuのfree planよりはよさそうです。

hexoはghostと違ってスタティックなサイトを生成するだけですが、markdown形式のファイルを入力とするので、 移行は比較的楽かと期待しました。 Ghostのmarkdownプレビュー機能は便利だったのですが、それは残念ながら諦めることにしました。ちゃんと探していませんが、オーサリング側の拡張もありそうです。

移行時に気づいたことをまとめておきます。 全体的に、Ghostの方が出来が良くて、hexoでやりたいことを再現するのに苦労した感じです。

markdownの変換が不完全な場合がある

Ghostでは問題なかったmarkdownの変換がhexoではうまく行かないケースがいくつかありました。 今回テンプレートにhandlebarsを使ったのでそれが原因かもしれません。 例えば、{{foo}}のような記述がうまく変換できませんでした。&#x7b;{foo}}とすることで解決。 他にも、<code>の変換結果が異なりました。これは問題という訳でもないですが。

handlebarsがサポートされていない

Ghostで標準のhandlebarsがhexoではコミュニティサポートであり、サポートされていませんでした。 どうやら、hexo v2からhexo v3で大幅な変更があったようで、プラグインなどが追従できていないようです。 これはなんとかしました。

Casperの移植が大変だった

Ghostの標準テーマであるCasperががシンプルで使いやすくて気に入っていたのですが、 hexoのテーマには似たようなものがありませんでした。以前のCasperを移植したものはありましたが、 機能やデザインがいまいちでした。 Ghostに戻ろうかと何度も挫折しましたが、結果的になんとか自分が使いたいCasperの機能とデザインは移植できました。

まとめ

当初の目的であった、herokuの課題への対応は、github.ioになったことで解消されました。 hexoで苦労したのはどれもCasperを使おうとしたことに起因するので、もっと素直に使う分には問題ないかもしれません。 苦労したおかげでテーマのテンプレートやCSSは理解が進んでいじりやすくなりました。

最後に一つ学んだこと、Ghostすごい。WordPressを置き換えることができるかもしれません。 (ただ、単純に代替として使うという意識ではきっとダメです、新世代に移行するという意識でないと)

機会があったらどこかでGhostもまた使いたいです。

あまりにも特殊な話なので書くか迷ったのですが、記録のために書いておきます。

Ghostはnode.jsベースのブログシステムです。 先日、Ghostをherokuにデプロイする話を書きましたが、 使ってみて一つだけ不便に感じることがありました。

エディタでC-hが効かないのです。

C-hというのは普段Backspaceの代わりに使っているキーバインドで、 Ctrlキーを押しながらhを押します。ないと困る人には困るのです。 ブラウザでも使えるようにしています。しかし、これが困るのはLinuxユーザだけかもしれません。 OSXの場合はCtrlではなくてCommandがありますし、Windowsの場合はそもそもC-hが効かないと思います。

GhostのMarkdownエディターは気に入ったので、なんとかしてC-hを使えるようにしたいところ。 ちなみに、C-hが使えない理由はC-hがGhostのショートカットに割り振られていて、 ヘッダータグの挿入になるからです。 ちょっと調べてみましたが、本家Ghostではすぐには解決しそうにない(あまりに特殊環境か)ので、 forkすることにしました。

https://github.com/dai-shi/Ghost

です。修正したコードはほんの2行です。 C-hとC-bに設定されていたショートカットをC-S-hとC-S-bにしました。つまり、Shiftキーも同時に押した時だけショートカットが有効になるようにしました。

さて、これをghost-on-herokuでも使いたいのですが、一筋縄では行きませんでした。 というのも、gitリポジトリからcloneしてデプロイするには、gruntのタスクを走らせて ビルドする必要があるからです。手動でやるのは簡単ですが、これをnpmでやる必要がありました。

結果的には、ghost-on-herokuのpackage.jsonを次のように修正することで解決できました。

diff --git a/package.json b/package.json
index 3af466a..aec84be 100644
--- a/package.json
+++ b/package.json
@@ -10,14 +10,37 @@
   "private": true,
   "version": "0.6.4",
   "dependencies": {
-    "ghost": "0.6.4",
+    "ghost": "https://github.com/dai-shi/Ghost/archive/0.6.4-for-emacs-keybinding.tar.gz",
     "ghost-s3-storage": "~0.2.1",
     "pg": "latest"
   },
+  "devDependencies": {
+    "bower": "1.4.1",
+    "csscomb": "3.0.4",
+    "grunt": "0.4.5",
+    "grunt-bg-shell": "2.3.1",
+    "grunt-cli": "0.1.13",
+    "grunt-contrib-clean": "0.6.0",
+    "grunt-contrib-compress": "0.13.0",
+    "grunt-contrib-copy": "0.8.0",
+    "grunt-contrib-jshint": "0.11.2",
+    "grunt-contrib-uglify": "0.9.1",
+    "grunt-contrib-watch": "0.6.1",
+    "grunt-docker": "0.0.10",
+    "grunt-express-server": "0.5.1",
+    "grunt-jscs": "1.8.0",
+    "grunt-mocha-cli": "1.13.0",
+    "grunt-mocha-istanbul": "2.4.0",
+    "grunt-shell": "1.1.2",
+    "grunt-update-submodules": "0.4.1",
+    "matchdep": "0.3.0",
+    "top-gh-contribs": "2.0.2"
+  },
   "engines": {
     "node": "~0.10.0"
   },
   "scripts": {
+    "postinstall": "(cd node_modules/ghost/node_modules && ln -s -b ../../grunt-* .) && (cd node_modules/ghost/node_modules/.bin && ln -s -b ../../../.bin/bower) && (cd node_modules/ghost && grunt --force init && grunt prod)",
     "start": "node server.js"
   }
 }

devDependenciesはもう少し削れるかもしれません。 この修正に加えて、heroku configの設定も行いました。

$ heroku config:set NPM_CONFIG_PRODUCTION=false NODE_MODULES_CACHE=false

これで期待通りになりました。

色々考えた結果、herokuを使うのが一番手軽だと思い、Ghostをデプロイしてみることにしました。 file storage問題は既に取り組まれていて、storage moduleでfile以外の方法も使えるようになったようです。 具体的には、Ghost S3 Storageというのがあるようです。 個人的には、mongodbをバックエンドにしたstorageとかできないかなと期待します。

さて、Ghostをherokuにデプロイする簡単な方法はないか調べたところ、 https://github.com/cobyism/ghost-on-heroku というのがありました。 これは便利と思って早速試そうとしたところ、メール機能の有料アドオンを使う設定になっていて それを外す方法が分かりませんでした。

そこで、通常の方法でデプロイすることにしようと思いました。 参考にしたサイトはhttp://www.autodidacts.io/host-a-ghost-blog-on-heroku/です。 ところが、作業を開始してから思いの外手順が多いことに気づき、 作業メモの利用価値が低くなってしまいそうでした。 これでは再利用性がなくなってしまいます。

そこで、方針を戻して、ghost-on-herokuをforkすることにしました。 有料アドオンを使っているところをやめて、GMailでメール機能を使えるようにします。 Ghostのソースを調べると思っていたように、NodeMailerが使われていたため、簡単そうです。 ghost-on-herokuをみようみまねで編集して、ボタンひとつでデプロイできるようにしました。

こちらです。

https://github.com/dai-shi/ghost-on-heroku

ボタンひとつでデプロイできます。動作確認はこれからですが。

このherokuのテンプレート機能便利だと思いました。他にも使えそうです。

node.jsとかブラウザで簡単な統計処理をしようと考えて使えそうなライブラリがないか調べました。 できるだけ依存ライブラリがないものがいいです。

構築にMakeを使うと書いてアイルからネイティブコードがあるのかと思いましたが、そうではなくpure JavaScriptでした。 http://jstat.github.io/にドキュメントがあります。かなり色々な関数がそろっているようです。 検定などもできるようです。JavaScriptのArrayをそのまま渡すこともできるので、お手軽です。 GitHubのStarは712です。

こちらも同じような感じです。Arrayを使うのが基本です。回帰や分類もできるようです。 これが紹介ページですが、フォントがいい感じです。 GitHubのStarは821なので、jStatとこれがメジャーどころでしょうか。

こちらはCollectionやVectorといったクラスを導入して抽象化しているようです。 と思いましたが、作られたオブジェクトは普通のArrayとしても扱うことができ、とても便利そうです。 READMEにはJavaScript標準のMathと連携しているサンプルが載っています。 JavaScriptのprototype chainのおかげですね。魅力的です。 Star数は327です。

ドキュメントページはこちらです。 Star数は711なので初めの2つと同じくらいですね。ここまで来るとStar数だけでは判断できないでしょう。 Vector and Matrix math for JavaScriptというふれこみで、他のものよりMatrix系が充実しているようにも見えます。

READMEにはほとんど情報がないのに、Star数が530という状態が不思議です。最近更新されていないところを みると過去に集めたStarでしょうか。それともどこか別のところにドキュメントページがあるのでしょうか。 Rっぽいことができるらしいです。コードとしては枯れているのかもしれません。

これまでのライブラリと比べると小規模なもので、Arrayを拡張して基本的な関数群を追加してくれます。 機能は少ないですが、これだけがやりたい場合はいいかもしれません。Star数は23です。


最後に、こんなページを見つけました。 中身はよく理解していませんが、JavaScript(というかv8)は意外と速いと言う気付きだそうです。

http://julialang.org/には新しく、もう少し見やすいベンチマークの表が載っています。

上記のライブラリたちのベンチマークも気になるところです。

ブラウザ側に情報を取っておく手段としてlocalStorageがあります。 昔はcookieを使っていたことが多く、今でもまだよく使われているのですが、 モダンブラウザ対応ならlocalStorageの方が適しているのではないかと思います。

以前、JavaScript nativeでlocalStorageを使うコードは書いたことがあって、 別に不満はなかったのですが、AngularでlocalStorageを簡単に扱えるライブラリがあると 思って調べてみました。

このあたりがメジャーそうです。順当に行くとStar数が一番多いangular-local-storageを選ぶのですが、 じっくりREADMEを読んでみます。APIは自明で分かりやすいです。bindはangularならではのAPIで便利そうです。 localStorageが使えない場合はcookieにfallbackするそうです。APIは抽象的に作られているということですね。

さて、2つ目のangularLocalStorageはどうでしょう。名前が似ていますが別物です。 bindもあるしAPIもシンプルで分かりやすいです。cookieへのfallbackもあるそうです。 angular-local-storageと比較すると若い分、Star数が少ないだけでしょうか。issueも処理されて アクティブに見えます。でも違いがない分、ドキュメントが充実しているangular-local-storageを選びたくなります。

最後の、ngStorageは、in the Angular Wayということで少し変わった感じです。

No Cookie Fallback - With Web Storage being readily available in all the browsers AngularJS officially supports, such fallback is largely redundant.

だそうです。確かにangularを使うようなブラウザでは、localStorageをサポートしていないケースは無いですね。 これは思い切りがよいです。気に入りました。

$scope.$storage = $localStorage;

使い方もこれだけです。APIとかそういうレベルではない感じ。とてもいいです。

And use it like you-already-know

だそうです。気に入りました。 これはつまり、localStorageを加えた3-way data bindingということですね。 これは応用が広がりそうです。時間があったらコードも読んでみたいです。

というわけで、おすすめはngStorageでした。

以前の記事で、 x-rayというライブラリを使ってスクレイピングをしてみた話を書きました。 その時に、ページネーションだけでなく、リンク先取得もできればいいと思ったのですが、 先日バージョンアップしていた2.0.0ではすばらしいことに複合的な処理が書けるようになっていました。

さっそく、試してみましょう。 サンプルををちょっといじって実行してみます。

var xray = require('x-ray')();
xray('https://www.google.com/', {
  title: 'title',
  image: xray('#gbar a:nth-child(2)@href', 'title'),
  map: xray('#gbar a:nth-child(3)@href', 'title'),
  play: xray('#gbar a:nth-child(4)@href', 'title'),
  youtube: xray('#gbar a:nth-child(5)@href', 'title')
})(function(err, obj) {
  console.log(obj);
});

ちゃんとそれぞれのページのタイトルが取れました。 「画像検索」はなぜか文字化けしました。

これは便利です。しかも、delayやthrottleの設定までできます。 今度勉強がてらコードも読んでみるといいかもしれません。

また、小ネタでした。

ところで、x-rayってだけだと検索キーワードとしてはあいまいすぎますね。