require_relativeの是非

『パーフェクトRuby』(Amazon)によると

Kernel.#require_relativeは、実行中のファイルから見た相対パスでrequireを行います。requireとは異なり、$LOAD_PATHは探索されません。相対パスの基準となるのはRubyが実行されているディレクトリではなく、require_relativeを呼び出したファイルのディレクトリです。

とのことで、ライブラリを実装する場合などにお世話になるような機能を提供している。

使われていない?

が、実際のところは
Ruby1.9.2以降でrequireする際の注意点 - Qiita
のコメント欄にあるように

1
2
$LOAD_PATH << '/lib'
require 'filename'

などとやることで、require_relativeを使わないという方法が存在する。
Ruby 1.9からは

1
$:.unshift('lib')

でも良い。

ライブラリ(gem)のパス追加 - 君の瞳はまるでルビー - Ruby 関連まとめサイト

Ruby 2.1以前

config.ruなどのようにeval内でrequire_relativeが呼ばれているとエラーになる様子。

config.ruの中でrequire_relativeするとエラーになる - みんなのちからになりたい

Ruby requires confusion – Benjamin Fleischer

余談

‘Require’ Best Practices? : ruby

では、requireを使うほうが好きな人が多そうだった。
一方、

  • require_relativeの方が速いだろう
  • 自分の管理しているものはrequire_relative、それ以外はrequireで使い分ける

という声もあった。


hexoでCannot find moduleエラー

hexoコマンド実行時にエラーが出力される

発生環境は以下の通り。Archでは出ていない。

  • iojs v3.0.0
  • OSX 10.10.4

各コマンド実行時に以下のエラーが出力される。

1
2
3
{ [Error: Cannot find module './build/Release/DTraceProviderBindings'] code: 'MODULE_NOT_FOUND' }
{ [Error: Cannot find module './build/default/DTraceProviderBindings'] code: 'MODULE_NOT_FOUND' }
{ [Error: Cannot find module './build/Debug/DTraceProviderBindings'] code: 'MODULE_NOT_FOUND' }

調べたらissueが上がっていた。

cf. hexo shows error message · Issue #1055 · hexojs/hexo

解法

1
npm install hexo --no-optional

すると良いみたい。試したところ確かにエラーが出なくなった。あるいは、最初のnpm install時に

1
npm install --no-optional

としてもエラーは出なかった。

–no-optional

npmのドキュメントによると

The –no-optional argument will prevent optional dependencies from being installed.

とのこと。

package.json

--no-optionalを付けるかどうかでpackage.jsonは変化するだろうか。

1
npm install hexo --no-optional --save

結論からいうと、package.jsonは変わらなかった。

別ディレクトリにgit cloneしてnpm installするとエラーが発生する。


gh-pagesとhexo(サブディレクトリ下での使用)

hexoをサブディレクトリ下で使用したい

githubで静的サイトジェネレータを使ったblogもどきを複数運用したい。githubには

  • <ユーザ名>.github.io
  • <組織名>.github.io
  • <ユーザ名>.github.io/<プロジェクト名>

の3通りの方法でWebサイトを作れるのだが、今回は3番目の場合について。
hexoのgithubを見るとサブディレクトリに関するissueが定期的に上がるが、自分も引っかかった。

TL;DR

theme側の_config.ymlに書かれている項目のうち上書きしたいものを、プロジェクトの_config.yml内theme_configに記述していけば良い。

1
2
3
4
theme_config:
menu:
Home: /<project>/
Archives: /<project>/archives

基本設定

hexoでサブディレクトリを扱う場合には_config.ymlに以下のような設定を行えば良い。

1
2
3
4
5
6
7
url: http://<your id>.github.io/<project>
root: /<project>/

deploy:
type: git
repo: git@github.com:<your id>/<project>.git
branch: gh-pages

また、theme側の設定では以下のような設定になっていることが多い。

1
2
3
menu:
Home: /
Archives: /archives

この場合、当然Homeはhttp://<your id>.github.io/を指し示す。
theme側の_config.ymlに書かれている通りなので正しい挙動なのだが、これではサブディレクトリに関する設定をtheme側でも行わなくてはいけないことになる。

  • themeをgitのsubmoduleとして管理している場合にはわざわざforkしなくてはいけない。
  • ルートに関する設定を複数箇所で指定するのは面倒。

これを

1
2
3
menu:
Home: .
Archives: archives

などとすると一見うまくいくように見えるが、個別の記事を表示するとうまくいかない。
例えば/<project>/2015/08/10/sample.htmlのような記事からArchivesをクリックすると/<project>/2015/08/10/archivesに飛んでしまう。

プロジェクトの設定とテーマの設定では後者が優先される

menu項目は大抵の場合theme側の_config.ymlに記述されているが、プロジェクト自体の_config.ymlでmenuを設定しても上書きすることはできない。
例えば以下のような設定を行ったとする。

themeの_config.yml

1
2
3
menu:
Home: /
Archives: /archives

プロジェクトの_config.yml

1
2
3
menu:
Home: /subdirectory
Archives: /subdirectory/archives

この時、直感的にはプロジェクト側の設定が優先されそうだが、実際にはtheme側の設定が優先されてしまう。

theme_configという設定項目を利用する

hexoのドキュメントを見ても記述されていなかったように思うのだがソースコードを追っていくと、theme_configという項目が最優先されることがわかった。
具体的には/lib/hexo/index.js内で

Locals.prototype.theme = _.extend({}, config, theme.config, config.theme_config);

とある。_.extend()はlodashの提供するメソッドで、複数の引数をとりそれぞれの連想配列をマージする。その際に重複したキーはどんどん更新される。
どういうことかというと、プロジェクト側に以下のように設定することで、themeの設定を上書きすることができる。

1
2
3
4
theme_config:
menu:
Home: /subdirectory
Archives: /subdirectory/archives

この設定はtheme側の_config.ymlより優先されるので、theme側の設定をいじらずに済むことがわかった。


ArchでのMackerel設定など

手元で管理しているLinuxは大抵Archディストリビューションを利用している。
Archでも正しく動作するし、取り立てて問題はなさそうだが備忘のためにメモしておく。

インストール

公式サイトから実行ファイルをダウンロードしてくる

https://mackerel.io/orgs/your-organization/instruction-agent

執筆時点での導入方法は以下のとおり

1
2
curl -O http://file.mackerel.io/agent/tgz/mackerel-agent-latest.tar.gz
tar xvzf mackerel-agent-latest.tar.gz

設定ファイル(mackerel-agent.conf)が同梱されているが、記法の参考程度にとどめておけば良さそう。
実際の設定ファイルは上記mackerelサイトに記載されている以下のようなコマンド

1
2
3
4
5
sudo sh << SCRIPT
cat >>/etc/mackerel-agent/mackerel-agent.conf <<'EOF';
apikey = "<your api key>"
EOF
SCRIPT

を実行する。

systemdのサービスとして登録する

mackerel-agent/mackerel-agentが実行ファイルだが、これをサービスとして利用可能にする。

/usr/lib/systemd/system/mackerel.serviceのようなファイルを作成し、以下のように編集する。

この設定を行っておくと、mackerel-agentファイルを直接実行する代わりに

1
2
sudo systemctl enable mackerel.serivce
sudo systemctl start mackerel.service

などで管理できるようになる。

公式プラグインを使ってみる

折角なので公式プラグインも使用してみる。
CentOSやDebianには公式パッケージが用意されているが、Archにはないのでビルドする。

mackerelio/mackerel-agent-plugins

Goの導入

Goが導入されていない場合はpacman経由で入れる。(gvm, goenvといったenv系を使っても良いかもしれない)

1
sudo pacman -Sy go

導入後、環境変数GOPATHを設定する。これはgo getなどでライブラリの置き場に使ったりするのだがどこでも良い。

1
2
export GOPATH="$HOME/.go"
export PATH="$GOPATH/bin:$PATH"

$HOME/.zshrcなどに追加しておく。

ビルドする

1
2
3
git clone https://github.com/mackerelci/mackerel-agent-plugins
cd mackerel-agent-plugins
make build
  • もし仮にgoxが無いと言われたらmake goxする。
  • buildフォルダが作られ、その中に各プラグインの実行形式ファイルが生成される。

mackerel-agent.confで使用するプラグインを指定する

今回はnginxのプラグイン(mackerel-plugin-nginx)を使ってみる。
対応するnginx側モジュールはngx_http_stub_status_module
pacmanで入るnginxでは有効になっている様子。

nginx.confにて、情報を出力するルートを設定する。例えば以下の通り。

1
2
3
location /basic_status {
stub_status;
}

nginxを再起動後、正しく情報が取れるかどうかを確認しておく。

1
./mackerel-plugin-nginx --host="<your domain/ip>" --port=80 --path="/basic_status"

TSV形式で情報が出力されていればOK。
続いて/etc/mackerel-agent/mackerel-agent.confを編集する。

1
2
[plugin.metrics.nginx]
command = "/opt/mackerel-agent-plugins/build/mackerel-plugin-nginx --host='<your domain/ip' --port=80 --path='/basic_status'"

mackerel.serviceを再起動し、mackerelのWebページを確認する。