あっつんへ

あっつんの事、ハッカーだなって思います。
正直言って、とっても好きです(*´ω`*)


キーボードにポインタつけちゃったり、 自作の vimプラグインでメモ書いてたり、
ボウズの通知作ったり、 Jenkins のレッドバーをギャラタブで表示したり、とっても刺激的です。


一緒にいる機会も多かったので、私がもう少しそんな気質があれば、あっつんはもっと楽しかったろうになーとか、
思ったりもしました。


そんなわけで、私はあっつんが好きです。 なので、今後共お付き合いしたいなーなんて思うわけです。
幸い今は twitter とかブログとか github とか勉強会とか、交流する機会はいっぱいあるのです。


というわけで、これからもよろしくお願いします!
お互い頑張りましょー!

Scala 開発環境としての IDEA と Eclipse

Scala 始めました(*´ω`*)

Java 開発環境として Eclipse を使っていたので、 Scala 開発環境もそのまま Eclipse を使っていたんです。
使い慣れた環境のほうが心地良いですよね。


が、

  • EclipseJava 開発環境と Scala 開発環境の機能差がまだまだ大きかったり
  • IntelliJ IDEA がいいよっていう声がちらほらあるので

IDEA 試してみました。


結局 Scala 開発環境は IDEA に乗り換えたのですが、せっかくなので Eclipse との簡単な比較をメモっておきたいと思います。


※ 間違いがあったら指摘してもらえると嬉しいです(*´ω`*)


試したバージョン

試したのは

です。

IntelliJ IDEA について

http://www.jetbrains.com/idea/
Community Edition はフリーです。
私は Scala 開発なら Community Edition で十分だと思います。


機能比較

Eclipse IDEA
全体的に
安定性 たまに正しいコードがエラー扱いされたりする 比較的安定している
自動コンパイル OK NG(後述)
ナビゲーション
クラス名指定によるジャンプ OK OK
クラスアウトラインの表示 OK OK
クラス/メソッド等が使用されている場所の検索 NG OK
implicit conversion の表示/ジャンプ OK OK
implicit parameters の表示 OK OK
リファクタリング
クラス/変数のリネーム OK OK クラス名を変えるとテストクラス名も変えてくれたり
補完/コード生成
メソッド呼び出しコードにて、implicit conversion により追加されるメソッドの補完 OK OK
メソッド呼び出しコードにて、パラメータ名の補完 NG OK
コメント内でのクラス名等の補完 NG OK
implicit キーワード等の補完 NG OK
override メソッドの自動生成 NG 自動生成候補に Object クラスのメソッドしか出ない OK
存在しないメソッドを呼び出すコードから、メソッド本体の自動生成 NG OK
その他
Emacs キーバインドで補完候補内を上下移動 たまに OK OK
sbt マルチプロジェクトの扱い project/Build.scala などを編集するのが手間 project/Build.scala なども、実ソースと同様の手軽さで編集できる

こんな感じでした。 比較途中から 「IDEA がいいな」 って思ってしまったので、あまり詳しくは比較してないです。。


リファクタリング機能なども、 IDEA のほうがすぐれてそうな印象ですが、クラスの移動、リネームくらいしか使ってないので違いは調べてないです。


IDEA の特徴(とデメリット)

と、機能面では IDEA のほうが好みなのですが、 Eclipse とは考え方が違う点もちらほらあったりします。


コンパイルが手動

Eclipse が裏で勝手にコンパイルしてくれるのに対し、 IDEA は手動でコンパイルを実行する必要があるようです。
差分コンパイルなので、そんなに時間が掛かるわけではないのですが、 Eclipse になれていると若干違和感を感じます。


参考 http://www.jetbrains.com/idea/documentation/migration_faq.html

リアルタイムコードエラーチェックとコンパイル処理の齟齬

上に書いたように、 IDEA はコンパイル処理が自動で走りません。
そのため、リアルタイムのコードエラーチェックとコンパイル時にでるエラーに齟齬があったりします。
つまり、 IDEA 上ではエラーになっているのに、プログラムは実行できる。。なんてことがあります。
まぁ、両方でエラーにならないコードを書ければいいんですけども。。


さいごに

操作性等は個人の好みもあるかとは思いますが、機能面は現時点では IDEA のほうがよさそうです。


操作性などは実際使ってみないとわからない部分も多いので、 Scala 開発する際は、 IDEA も少し触ってみるといいかもしれないですね。


例えば IDEA のインデントに線をつけてくれる機能とか・・・好きです

とはいえ、 Scala IDE for Eclipse は Typesafe team が関わっていたりもするので、今後が楽しみですねー
(http://scala-ide.org/docs/dev/roadmap.html)


そんな感じです(*´ω`*)

Fragment のインスタンス生成に失敗する

ここに書いてある方法を参考にして Fragment を使用していたんです。。
http://www.swingingblue.net/mt/archives/003373.html
(追記 本記事で触れた不具合自体は、上記のサイトとは関係ありません)


「ぉぉ、うまく動いてる〜! たのし〜!」と喜んでたんですが、しばらくすると Fragment のサブクラスのインスタンス生成に失敗したとの例外が。。


とっても恥ずかしいミスなのですが、 Fragment のサブクラスには public なデフォルトコンストラクタが必要なんですね〜
http://developer.android.com/reference/android/app/Fragment.html もちろんドキュメントにはちゃんと書いてありました(*;ω;*)


発覚までに時間がかかったのは↓こんな理由でした。

  1. Fragment をプログラム的に new していた(http://developer.android.com/guide/topics/fundamentals/fragments.html#Adding に書いてある方法です)
  2. Activity と Fragment が Stop 中に解放されていた(と思う。。)
  3. 解放された Activity の復元時、 Fragment は Android によって暗黙的にインスタンス化される(http://developer.android.com/guide/topics/fundamentals/activities.html#SavingActivityState この処理の時です)
  4. 3の処理で public なデフォルトコンストラクタが使用される、、が、存在せずに例外発生(*;ω;*)


この開放と復元処理はスクリーンの向きを縦横切り替えることでも発生するので、テストするときはこの方法がお手軽でした。

5/29 追記

本記事で触れた不具合自体は、上記のサイトとは関係なく、私の作成したプログラムの不具合です。
誤解を招く表現で申し訳ないです。。

レイアウトリソースにボタンの処理を記述する

いままで Android で View のイベントを処理したい時は、 Java で OnClickListener 等を設定していました。
でもでも、実はレイアウトリソースに「実行したい処理」を記述できたんですね(*´ω`*)

どんな場合にこの方法で記述できるの?

この方法で記述できるのは、View の「クリックイベント」を処理する場合です。
すべてのイベントに対して使用することはできないんです。。

どんな風に便利なの?

一般に、 Javaイベントハンドラを記述するより、コードがシンプルになると思います。

また、ListView や GridView を使う時、各アイテムの中にボタンを設けたい場合が、まれに良くあります。この時、 Javaイベントハンドラを設定するコードは少し複雑になります。この場合もレイアウトリソースに記述したほうが、コードがシンプルになるように感じました。(記事の後半に例を載せています)

記述の仕方は簡単♪

  1. Activity に public メソッドを用意する
  2. レイアウトリソースにonClick属性を記述する

以下、詳しく見ていきます。

Activity に public メソッドを用意する

このメソッドがクリック時に呼び出されます。

class VoiceListActivity extends Activity {
public void play(View view) {
    // ...
}

引数は View になります。

レイアウトリソースにonClick属性を記述する

レイアウトリソースの中に、こんな風に記述します。

<ImageButton
  ...
  android:onClick="play" />

これだけでボタンを押したときに play() が呼ばれるようになります。シンプルですね(*´ω`*)

参考 http://developer.android.com/reference/android/view/View.html#attr_android:onClick

応用 - ListView の各アイテム内のボタン

ListView の各アイテムの中にボタンがあり、そのボタンを押したときの処理をこの方法で記述する場合の例です。

この場合、前述の内容に加え、以下の処理が必要になります。
(少し複雑です。。もっといい方法ないかすら。。)

  1. ListView の各アイテムに、そのアイテムの識別情報を設定しておく
  2. クリック処理を実行するメソッド内で、 どのアイテムのボタンがクリックされたのか調べる

以下、詳しく見ていきます。

ListView の各アイテムに、そのアイテムの識別情報を設定しておく

こんな感じです!

public class FooArrayAdapter<T> extends ArrayAdapter<T>{
  // ...

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    // このメソッドは定型処理
    View view;
    if (convertView == null) {
      view = (View) inflater.inflate(itemLayout, parent, false);
    } else {
      view = convertView;
    }

    T item = getItem(position);
    updateView(view, item, position);
    return view;
  }

  @Override
  protected void updateView(final View view, final T item, int position) {
    // ★ここで設定! 
    view.setTag(R.id.model, item);
    // ...
  }

R.id.model は res/values/ids.xml 辺りに定義しておきます。

item は各アイテムの情報を保持する人です〜

クリック処理を実行するメソッド内で、 どのアイテムのボタンがクリックされたのか調べる
public void play(View view) {
  Object model = ViewUtils.getTag(view, R.id.model));
  play(model);
}

こんな感じのユーティリティを用意しておくと便利かもです(*´ω`*)

/**
 * view もしくはその先祖に紐づく tag を取得する
 */
public static Object getTag(View view, int id) {
  while (view != null) {
    Object tag = view.getTag(id);
    if (tag != null) {
      return tag;
    }

    if (view.getParent() instanceof View) {
      view = (View) view.getParent();
    } else {
      break;
    }
  }
  throw new IllegalArgumentException("View が tag と紐づいていません");
}

最後に♪

こんな方法があることを、最初から知りたかったです。。(´;ω;`)

Django の CSRF 対応

DjangoCSRF 対策を行う手順を調べたのでメモを残しておきます!
(今回は Django 1.2 を使用しました。 1.1から変更があるみたいですね)
(本家のチュートリアルを終わらせたくらいの人(私です)を対象にしています)


手順は2ステップ! シンプルですね〜

  1. POST を行うフォームで CSRF トークンを送信する
  2. POST 先のビューで CSRF トークンのチェックを行う

1.POST を行うフォームで CSRF トークンを送信する

これはフォームに {% csrf_token %} を含めることで実現できます。

<form action="" method="post">
  {% csrf_token %}
  ...
</form>

また、対応するビューで、 csrf_token が使用する変数を Context に設定する必要があります。

これを設定する方法は2つあります。

1. Context の代わりに RequestContext を使用する

RequestContext を使用すると、自動的に必要な変数が設定されます。

2. 手動で設定する

こんな風にするそうです(未確認)

from django.core.context_processors import csrf
def my_view(request):
    c = {}
    c.update(csrf(request))
    ....

※RequestContext とは


RequestContext は Context の派生クラスです。


Context との違いは以下のとおりです。

  1. 自動的に Context にいくつか変数が設定される


自動的に設定される変数は以下の2種類があります。

  1. TEMPLATE_CONTEXT_PROCESSORS に従って設定される変数
  2. django.core.context_processors.csrf によって設定される変数


render_to_response を使用している場合、context_instance 引数として RequestContext オブジェクトを渡します。

また、 direct_to_template を使用すると、少しお手軽に RequestContext を使えるみたいですね。
参考 http://it.kndb.jp/entry/show/id/1110

2.POST 先のビューで CSRF トークンのチェックを行う

これには2つの方法があります。1の方が漏れがないので、基本的にこちらを選ぶのがよさそうですね。

  1. CsrfViewMiddleware を使用する(デフォルト設定で使用するようになっています)。
  2. csrf_protect デコレータを、必要なビュー毎に使用する。

最後に♪

長々と書いてきましたが、Djangoの設定をいじっていなくて、すでに RequestContext を使っている場合、フォームに {% csrf_token %} を追加するだけで良さそうですね〜