解せぬ日記

雑な話をする

Vue.jsでフィルタリングされた数を参照する

この記事は Vue.js Advent Calendar 2014 - Qiita の初日である。

最近、Vue.jsをちょっとだけ触ってるので、勢いで空いてた1日目に凸した。 大したことは書けないけど、初日から何もないのも盛り上がりに欠けるので書くぞ!1

Vue.jsのbuilt-inフィルター

Vue.jsにはbuit-inのフィルターが用意してあって、結構便利だ。 filterByv-repeatと一緒に使い、配列を条件でフィルタリングしたものをv-repeatに表示させる。 orderByはその名の通り、v-repeatの表示順をソートするものだ。

今回はfilterByを使う上で、もしかして困るんじゃないかなーと思ったことを書く。

フィルタリングされた数を参照

よくよく考えると当たり前の話なんだけど、v-repeatの中では$indexでインデックスを参照できるし、配列に入っているオブジェクトも参照できる。 けど、フィルタリングされた配列の数、つまり表示上の結果の数を取りたい場合にどうすればいいのか分からなかった。

filterByの実装を読んでみるとArray.filterを使っていたので、フィルタリングされた新しい配列の数を一時的に保持すればいいということになる。 そこで、カスタムフィルタを作って対応した。 CoffeeScritptで書いてる。

Vue.filter 'setCount', (arr, key) ->
  @[key] = arr.length
  arr
<input v-model="searchText">
<div>{{num}}</div>
<ul>
<li v-repeat="users | filterBy searchText | setCount num">{{name}}</li>
</ul>

保持する内容を配列に変えれば、フィルタリングされた配列も参照できるし、色々やれそうで便利。

まとめ

書いてみれば、何のことはないだけど、日本語だと基本的な情報というか、試してみた!みたいな情報が多くて、APIドキュメントをひたすら読んで、最終的にソースの必要な部分を読んだ。 もっといい方法があれば教えてください。

Vue.js Advent Calendar 2014 - Qiitaの明日まだ空いてるぞ。

その実装は後退している

開発をずっとしていると「あ、この実装進研ゼミでやったぞ!」ってことがある。 以前、関わったプロダクトで似たような機能を実装したことあるから、それを流用すれば早いなーって感じだ。 当然、やったことがあるからすぐに実装できるし、さっさと実装を済ませたほうがプロジェクトは進むし、評価される。 非常にいいことだし、それが経験というものだ。

だが気をつけないと、大きな落とし穴にハマる。 人間は自分ができることをやりがちな生き物で、できることをずっとやっていると慣れてきて段々何も考えなくなるからだ。

A:「この実装はなんでこうしたの?」
B:「あー、以前のプロダクトで同じ実装を見たことがあったので、流用しました」
A:「へー、最近こういう実装も見るけど、どうしてこっちにしたの?」
B:「あ、そういう実装もあるんですね」

こんな経験をしたことがある。 別にどうってことない日常会話だけど、不思議に思うことがある。

開発の世界は変化のスピードが早いという前提にたったときに、本質的な部分はそんなに変わらないにせよ、実装やアーキテクチャなど色々な考えが出てくるというのは明らかだし、自分だって半年も経てば変わっている。 半年前のコードを見て、書き直したいと思うことは、バイアスがかかっているけど、Twitterのタイムラインでもよく見る光景だ。

よく考えて欲しい。 会社の許容範囲として半年から一年サービスを続けるとしたら、その実装は半年以上前のものだったりするんじゃないだろうか。 だとすると、そのコードを書いた人はすでに書きなおしたいと思っているかもしれない。

何も考えず以前の実装を使うということは、何も変わらないということで、停滞していると言えるし、停滞はこの世界では後退だ。 前に進まなければ置いて行かれる。 その実装は後退してる。

実装前によりいい実装を考えたり、別の考え方の実装を調べたりすることで、自分が前進できる。ほんの少しの改善でもいいでもいいはずだ。

APIを実装する前に、GitHubAPIがどうなっているのかとか、HerokuのAPIがどうなっているのかとか、少しでも見るだけで違う。 もっといい方法が存在するかもしれない。

考えたり、調べたりした結果、そのままでもいいとなるかもしれないが、一度立ち止まって考えるのと考えないのとでは全然違うと思う。

僕はいたって普通だけど、少しでもよい実装ができるようになりたい。 そんなことを同僚と話した結果、ほとんどの人には当たり前じゃん、そんなことって感じのエモいエントリーになった。

12/1 追記

なんか怒ることでもあったんすか?って言われたんだけど、別に怒りとか何もなくて、僕はこう思ったっスっていうことを伝えたいだけだった。

java-runtime-common-2-1が衝突する話

Arch Linuxでいつものようにアップデートしようとしたら、Java周りで衝突してアップデートができなかった。

どうもjava-commonに変えてjava-runtime-commonを使うようにjre7-openjdk-headlessとやらに変更が入ったらしい。

界隈に明るくないのでよく知らない。

対応はちゃんとドキュメント化されてた。 java-commonが入ってたらマニュアルで対応する必要がありそう。 依存チェックを無視してアップデートしてるような感じっぽい。

Arch Linux - News: Java users: manual intervention required before upgrade

ちゃんとニュースが流れるから、困ったらトップページを見ると捗る。

Arch Linux

現場からは以上です。

sudoers.pacnewを適用するぞ on Arch Linux

Arch Linuxはパッケージの更新をするときに、設定ファイルとかをxxx.conf.pacnewのような形で配置する。 例えば、mirrorlistとかsudoersとかってファイルが.pacnewになる。 これは勝手に上書きされないようにするための配慮だと思う。

んで、sudoersを更新するときにやらかしたので、一応メモしておく。

sudoersの更新

sudoのための設定ファイルであり、rootで管理されてて、visudoを使って更新するのが安全なんだけど、.pacnewの適用方法を間違うと悲惨なことになる。

好きなeditorを使ってvisudoを起動し、差分を見ながら更新するのが良さそう。

$ sudo EDITOR=vim visudo

# 差分をとる準備
:diffthis
# 新しいWindowを開く(水平)
:vnew
# .pacnewファイルを開く
:e /etc/sudoers.pacnew
# 差分を見ながら必要なものを取り込む
:diffthis

やらかした方法

mvとかボケて使うと詰む。 所有者はrootなので当たり前。

$ sudo mv /etc/sudoers /etc/sudoers.20141001
# エラーを見て、できるわけがない事に気付き、sudoが使えないので何もできなくなる
$ sudo mv /etc/sudoers.pacnew /etc/sudoers

やらかしたときの復旧方法

USBブートを行って、arch-chrootでファイルを復旧する。

$ mount /dev/sda6 /mnt
$ arch-chroot /mnt
$ mv /etc/sudoers.20141001 /etc/sudoers

まとめ

頭が悪すぎて辛い。

Hubotでこの後めちゃくちゃデプロイした話

背景

僕のチームはGithubを使ってて、HipChatからHubotでHerokuへデプロイさせてる。

Github時代のデプロイ戦略を読んで便利最高と思ったので、僕もプルリクエスト形式のデプロイを本番へ速攻導入した。 何をデプロイするかということが可視化されて、すごいいい。

困ってたこと

プルリクエスト形式のデプロイは便利最高なんだけど、検証環境の分までdeploymentブランチを用意するか悩ましいところだった。 検証環境は作業が同時進行しているため、複数あったほうがよくて、特にHerokuとかを使ってるなら用意しない手はない感じだったりするからだ。

企画への確認はfeatureブランチをそのまま見せたかったりするので、ガンガン検証環境へデプロイしたい。 特にUIの改善だったりってところは出来るだけイメージを共有したいので、早めにレビューするのがいいと思ってて、実装してこの後めちゃくちゃデプロイしたというストーリーが最高だと思う。

そうしたときに、どの検証環境にどのブランチが乗ってるのか分からないので、人間が確認しあう状況に置かれてた。 xxx-edge1ってデプロイしていい?とか会話が発生することになる。 僕は頭悪いので、どこに何がデプロイされてるか全く覚えてられないから、Hubotが覚えてるのがいいと思った。

解決策

terut/hubot-smartdeploy · GitHub というnpmモジュールを作った。

非開発者もGitHub Flowに巻き込んでみんなハッピーになった話 にもあったように、同じブランチは同じ検証環境にデプロイされるのに加え、新しいブランチの場合は以前にデプロイされてから時間がたってる検証環境にデプロイする。 ステータスコマンドで現在の検証環境の状態が確認できる。

f:id:terut:20140820155210g:plain

f:id:terut:20140820155620p:plain

無能なのでcapistranoとかには対応してない。 自分で作ってる社内ツールcapistranoなので、その辺でcapistranoにも対応させたい感じがしてる。

デプロイするといってはいるが、内部はdeploymentsイベントをキックするか、プルリクエストを作って、必要なら自動マージするという実装になっている。 この辺りは atmos/hubot-deploy · GitHub を大いに参考にさせてもらったのだけど、勉強になった。

じゃあ実際、デプロイは誰がやってるんだっていう話だけど、それは atmos/heaven · GitHub のような存在がいて、そいつががんばってる。 hubot-deployとheavenの関係と一緒だ。

雑に作って、チームに導入して、ある程度仕様も固まって来たからテストを書き始めようと思ってるんだけど、jasmine 2.0が最高なんですか? jasmine-nodeが開発鈍いように思えたので、結局mocha + chaiで書き始めようとしてる。 教えてエロい人。

ホワイトデー納品物語

昨日になるけど、世間はホワイトデーだった。 コンビニでフラン買って職場の人にお返しをしたのだけど、そんな雑なことしてんの僕ぐらいだったっぽい。 みんなのやつは僕のやつと袋が違った。

挙げ句の果てにはフランが足りなくなって、窮地に追い込まれた。 僕はお菓子とか作れないし、だいぶ困ったので、とりあえずなんかコード書いて、それをプレゼントすることにした。

女の子はイケメンが好きだろうから、すべてのWebサイトの画像がイケメンになるユーザスクリプトを書いてChromeなりFirefox(Scriptishとかいるけど)に入れられるようにして、コードを納品した。

なんかFacebookとかGoogleとか全部イケメンになって、すごく喜んでた(もしかしたら気を使ってる可能性が多分にある)。 思いの外、喜んでたので、他の同僚とかにもあげたら、Googleで検索したりして遊んでた。

f:id:terut:20140315040017p:plain

エンジニアだとホワイトデーのお返しもコードをプレゼントできて便利〜。

// ==UserScript==
// @name whitedayのお返し
// @namespace
// @description イケメン画像をお返しする
// @include *
// @exclude 
// ==/UserScript==

var imgs = document.getElementsByTagName('img');

for (var i in imgs) {
  var num = Math.floor(Math.random() * 100 + 1);
  var numStr = ("00"+num).slice(-3);
  imgs[i].src = "http://www.example.com/img_".concat(numStr).concat(".jpg");
}

Railsで静的なページを動的にしたくない話

http://terut.github.io/staticman/

staticmanというlayoutやviewを再利用して、静的ページを吐き出すgemを書いた。

Railsで使うことを想定してる。

使い方

設定ファイルをgenerateして、設定ファイルを書き換える。

$ bundle exec rails g staticman:config
  create config/staticman.rb

$ vim config/staticman.rb

設定ファイルは、静的ページのlayoutとviewを設定しておく。

# config/staticman.rb
Staticman.configure do |config|
  config.static_pages = [
    { file: 'statics/about', layout: 'application' },
    { file: 'statics/404', layout: 'application' }
  ]
  # config.static_dir = 'public'
  config.host = 'staticman.github.com'
  # config.controller_context_class = nil
end

あとは設定した静的ページのviewを編集して、準備ができたら出力する。

$ bundle exec rake staticman:build
  create public/about.html
  create public/404.html

Railsでのviewとなんら変わりなく書けるし、テンプレートエンジンもそのまま使える。

仕組み

RailsのApplicationControllerを継承したProxyのControllerとRequestを用意して、あとはRailsレンダリングの機構にまかせてる。

実に単純で、ちょっと泥臭いけど、ActionViewのみでレンダリングしようと思ったらControllerのhelper_methodの仕組みがControllerインスタンスにdelegateしてるので、なかなか辛いことが分かり、こうなってる。

もし、viewの中でメソッドが見つからない場合は、ActionView::Baseを継承した無名クラスにmethod_missingを持ったモジュールをincludeしてあるので、メソッド見つからなかったよってWarningだして、nilを返してレンダリングを続ける。

あくまで開発時にのみ使うツールかなと思ったので、本体のクラスに影響がないようにしたつもり。

継承せずに特異メソッドを使ってもよいのかもしれないけど、とりあえずこうした。

問題点

現状、2つプロジェクトに導入してみて、一応うまく動いてる。

けど、以下の点がめんどくさいなと思った。

  • Rails.envをproductionで吐きたい(むしろassetsのdigest考えるとそっちのほうが多い気がする)場合、別途envを用意しなきゃいけなくね?
  • URL helperの*_urlを解決するためにhostを設定として用意するのが微妙にDRYじゃない

このブログを見て、ナルホディウスですぞと思ったそこのあなた、Pull Requestお待ちしてます。

静的ページの管理の問題

以前から、Railsとかにおける静的なページ、いわゆるsorry.htmlだとか、404.htmlとかをどうやって管理したらいいんだぜ?と思ってた。

まず最初に思いつくのが、ユー動的にしちゃいなよということ。

high_voltageとかはRailsにマウントするタイプなので、動的にページをレンダリングしてるように見えて、Railsに組み込む方針をとってるっぽい。

動的な要素(例えばセッション状態を見てログインユーザを表示したいとか)がある場合、layoutやviewを使い回せて、とても有益。

ただ現状関わっているいくつかのプロジェクトに関して、そんな要件はないので、静的なページは個人的にRailsのレイヤより前のWebサーバからresponseを返したいなと思った。

んで、動的に作らない場合、問題になってくるのが修正漏れ(少なくとも僕の職場では何回かあった)で、静的なページを配信する残念リリースをする。

静的なページで同じようなマークアップがすべてのファイルにあったりして、テストとかも書いてないので、目grep力たった5か、ゴミめという僕にとって気づくのは難しい。

ということで、動的に静的なページを生成すればlayoutとviewを使い回せて幸せになれるんやで工藤!というところに行き着いた。

それがhigh_voltageで出来るならそっちを使ったほうがいいし、別にもっとよいライブラリがあればそれを使いましょう。

ついでに気が向いたら@terutにリプライで教えてください。

思ったこと

実際にRailsがどうやってレンダリングしてんだろーなと思って色々と潜ってみたけど、勉強になった反面、僕には才能なんてなかった。

もっといい方法があれば、ぜひ教えてほしいし、この方法が良さそうなら、どんどんよくしてもっと楽したい。

自分のライブラリに自分でissueを書くのはとても趣があり、いいんだけど、僕の英語がクソすぎて何言ってんのか分からなくなった。

最後にstaticmanというのはstaticおじさんということであり、静的なページを書き続けてくれるおじさんの意である。

使い方はREADMEに一通り書いておいたつもりなので、興味あれば読むといいと思う。