解せぬ日記

雑な話をする

MacOSX(Yosemite)でシステム終了をフックする

Mac OSXのログアウトのフックを実現したくて、launchdを使ってbashのプロセス常駐させてtrapしたけど、blockせずにログアウトしていった。 非常に味わい深い。

LoginHook、LogoutHookを使ってscript走らせればいいじゃんってドキュメントはいっぱい見つかるんだけど、2014年の9月頃にはすでにdeprecatedだって言われてて、Launch Daemons、Launch Agentsを使ってくれよなってAppleのドキュメントは言ってる。

Daemons and Services Programming Guide: Customizing Login and Logout

ただ、最初に言ったようにblockせずにソッ閉じされる。

解決方法

AppleScriptは実は簡単にApplicationにできる。 普通にdialogとか出すだけでも可能っぽい。 AppleScript Editorでnotification出すコードを書いて保存時にFile FormatをApplicationにすればいい。

そこで、AppleScriptでApplicationを作って、StartupItemsに登録して、常駐させることにした。 ログアウト時にはApplictionの終了イベントが来るはずで、夜フクロウとか使ってる人は分かると思うけど、終了時にダイアログが出てログアウトをblockする。 なので、Applicationに終了イベントをフックする処理をAppleScriptで書いて、ダイアログを出すようにした。

on quit
  display dialog "退勤すんの?" buttons {"Yes", "Not yet"} default button "Not yet"

  if button returned of result is "Yes" then
    --change next row.
    do shell script "/usr/bin/say goodbye"
    continue quit
  else if button returned of result is "Not yet" then
    continue quit
  end if
end quit

アプリを作ってgithubに上げといたから、使いたければ使ってください。 アプリ自体は2014年の9月頃に作ったものだけど、Yosemiteでも問題なく動いてるぞい。

https://github.com/terut/logouthook

Rubyのモジュールでextend self

冷静になってゆっくり理解すれば、そりゃそっかという話なんだけど、Railsプロジェクトのコードでめっちゃ混乱したので、書いておく。

TL;DR

extend selfは特異クラスへのincludeと等価というのがミソ。

混乱したコード

目にした瞬間これ本当に大丈夫なのかと思ったコード。

class ApplicationController < ActionController::Base
  # something

  class << ActionController::HttpAuthentication::Digest
    # seconds_to_timeoutを書き換えたい
    def validate_nonce(secret_key, request, value, seconds_to_timeout=60*60)
      # somthing
      super
    end
  end
end

このコードを見て、いやいやそりゃ大丈夫でしょと思う人はそっとタブを閉じるといい。

僕はというとあれ、superってどういうこと?ってなった。 Digestの特異クラス定義式を使って特異クラスにメソッドを追加しているのだけど、superをcallしてもメソッドが見つからず探索は終了しないかという疑問だ。 つまり、メソッドは上書きされるはずではないかと思った。

ただこのコード、こいつ動くぞ!って驚きと共に動いていた。

そこでDigestの定義を見てみる。 そうすると、モジュール自身に対してextend selfで定義してあった。

module ActionController
  module HttpAuthentication
    module Digest
      extend self

      # somthing

      def validate_nonce(secret_key, request, value, seconds_to_timeout=5*60)
        # something
      end
    end
  end
end

それでもなぜメソッドが上書きされないのかとか思っていたが、冒頭に書いたとおり、このモジュール自身に対してのextend selfが今回のミソで、これにより上書きされないようになる。 より理解を深めるために、簡略化したコードで考える。

簡略化したコード

上記で説明したコードの周りを調べて簡略化すると次のようになる。 AActionController::HttpAuthentication::DigestHogeApplicationControllerhogevalidate_nonceといった感じ。

module A
  extend self

  def hoge
    puts "A" 
  end 
end

class Base
  def call
    A.hoge
  end 
end

class Test < Base
  class << A
    def hoge
      puts "test"
      super
    end 
  end 
end

Test.new.call

実行すると次のような結果だ。

$ ruby test.rb
test
A

superによりちゃんとメソッドがcallされていることが分かる。 これを理解するために書き換えをしてみる。

module A
  #extend self

  class << self
     include A
  end

  def hoge
    puts "A" 
  end 
end

class Base
  def call
    A.hoge
  end 
end

class Test < Base
  class << A
    def hoge
      puts "test"
      super
    end 
  end 
end

Test.new.call
$ ruby test.rb
test
A

これを見ると謎が解ける。 特異クラス定義式で定義されたhogeメソッドとモジュールのincludeによって定義されたhogeメソッドという関係なので、特異クラス定義式のhogeメソッドが先に呼ばれ、あとからモジュールで定義されたhogeメソッドが呼ばれるというわけだ。

モジュールのincludeに関してはメタプログラミングRubyとか見ながら、自分で試してみるとモジュールのincludeによってモジュールが継承チェーンに挿入されていることが分かると思う。

まとめ

extend selfは怖くない。

includeうんぬんの辺りがわからない人はメタプログラミングRubyを読みましょう!

メタプログラミングRuby

メタプログラミングRuby

MySQL Casual Talks vol.7 に行ってきた

久しぶりに MySQL Casual Talks vol.7 に行ってきた。

カジュアル〜とか言ってヘラヘラしてたらワンパンで吹っ飛んだ。 相変わらずのガチュアルだった。

気になったトーク

面白いなーと思ったのは継続的リストアの話で、僕にはあまりそういう観点がなくて、よくよく考えると、正しくバックアップが取れて、リストアが正しくできるというのは非常に重要だと思う。 日頃から正しくリストアができることを証明しておくと安心感が高まる。 普通にバックアップ取って、ヘラヘラしてたらいざという時、詰む。

相変わらずかみぽさんがすごかった。 RailsMySQL周りに怒涛のプルリクエストを投げまくってるらしいけど、なかなかマージされないので、gemにバックポートしたとのことだった。 RailsMySQL周りのプルリクエストは放置される傾向にあるっぽい。

ペパボの新人さんがパワハラにあって、MySQL 4.0からバージョンアップした話は最高にグレートだった。 MySQL 4.0.25から5.0.96だったみたいだけど、レプリケーションでなんとかしたっぽい。 gccとの相性の問題とか既存のスレーブとかすごい色んな問題を抱えながらもバージョアップを成し遂げたのは、本当にすごいと思う。 新人さんにそういう仕事を任せるペパボもまたよいと思った。 薄い本にしたら売れそう。

MySQL Fabricのデモを見て、カジュアルに切り替わってて未来を感じた。 辛そう。

まとめ

発表者の方、主催関係者の方、本当にありがとうございました。 お疲れ様でした。 最高の夜でした。

PipelightでSliverlightに打ち勝つ

Arch LinuxLinux生活していると、開発するのに便利最高だし、他のことも大概できるのだけど、GyaoとかDMMとかDMMとかDMMを見ることができない。 これはDRMが関係していて、Silverlightのインストールが必要になってる。

img

TL;DR

PipelightでSilverlightに挑んだ結果、ワンパンで吹っ飛んだ。

Pipelight

LinuxだとMoonlightとかってSliverlightのオープンソース実装があるのだけど、僕の環境であまりうまく動かなかった。 そこでPipelightというwineを使ってLinuxのブラウザ上でwindowsのブラウザのプラグインを使えるようにするラッパーツールがあるので、使ってみた。

NPAPIを使っているのでChrome/Chromiumの35より上のバージョンでは動かないらしい。 NPAPIのサポートを切ったからで、PPAPIを使おうとしたけど、以前と同じやり方ではうまく動かず、またバグも出てしまったとのことだった。 どうしてもChromeを使いたければ、NPAPIのパッチを当てるか、バージョンを下げて使わないといけないっぽい。

Firefoxを使うのが楽そう。

インストール

インストールの方法はいくつかある。 Arch LinuxWikiではAURからインストールすることが、メインで書いてあるが、本家サイトの推奨はpacmanリポジトリを追加して、バイナリをインストールすることだ。

Pipelight | Installation - Arch Linux

wineのコンパイルとインストールはめちゃめちゃ時間かかるので、僕もリポジトリの追加方式をすすめる。 あとmultilibがいっぱい入ったりするので、ちょっとウッとなる。

使い方

インストールが終わったらあとはUserAgentを変えるだけ。 ドキュメントを読む限りはIEとかのUAにせずFirefoxだったらWindowsFirefoxにするのがよさそう。 だいぶ雑な説明だけど、IEだとActiveXとか色々あるとのこと。

Firefoxのアドオンだと、User Agent Overriderがいいらしい。 User Agent Switcherは問題が起こるって書いてあった。

Pipelight | Installation - User Agent

Firefoxを起動するとwineの某が一緒に起動するから入ったことが分かると思う。

まとめ

こんなに色々なドキュメントを読み、インストールを頑張った結果、めちゃめちゃ高まった気持ちを抑えきれずにDMMのサンプルを試しに見に行ったらエラーが出た。 エラー見る限り、DRM周りでコケてるのかなーと思ったけど、ダメージがでかすぎたので、あまり調べずにそっとアンインストールした。

最高。

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

現場からは以上です。