2013年12月25日水曜日

[FreeMarker] ftl名前空間のすゝめ

つい最近知ったのですが、ftlにも名前空間があります。
例えば、ある画面にマクロを定義しているFTLを複数読み込む時、そのFTL毎に名前空間を分ける、ということができます。

名前空間の使い方

これの何がいいかというと、名前空間を分けると各FTLで定義した変数名やマクロ名が衝突しなくなります。
library-a.ftlfoo というマクロを定義し、 library-b.ftl でも同名のマクロを定義し、この2つのFTLを同じ画面で読み込み、それぞれのマクロを同時に、別のマクロとして使うことができるようになります。

<#-- library-a.ftl -->
<#macro copyright date>  
    <p>Copyright © $(date) John Smith. All rights reserved.</p>
</#macro>  

<#assign mail = "jsmith@acme.com">

上記のライブラリFTLを lib/library-a.ftl とします。
そして、このライブラリFTLを top.ftl で利用します。

<#inclde "/lib/library-a.ftl">

このように書くと、 copyright マクロと mail 変数がグローバルな名前空間に定義されてしまいます。
これだと、仮に top.ftl ですでに copyright という名前のマクロや mail という変数を定義していると、名前が衝突してエラーになってしまいます。(変数は同じものとして扱われます)

これだと、再利用可能なコードとは言えません。
そこで、 import という、別の構文を使ってライブラリFTLを読み込みます。

<#-- top.ftl -->
<#import "/lib/library-a.ftl" as libA>
<@libA.copyright date="2012-2013"/>
${libA.mail}

<#-- 出力内容
<p>Copyright © 2012-2013 John Smith. All rights reserved.</p>
jsmith@acme.com
-->

import を使ってライブラリFTLを読み込むと、新しい名前空間が作成されます。
この新しい名前空間からは、ライブラリFTL内で定義された変数か、グローバルで定義された変数か、データモデルの変数(Javaのアクションクラスから渡された変数)しか見ることができません。

この新しい名前空間にある2つの変数(マクロ)に top.ftl からアクセスするには、 import 構文で as の後ろに指定された名前を使います。この場合、上のコードで示したように、 libA.copyright, libA.mail という形で library-a.ftl で定義された変数やマクロにアクセスできます。

このように import 構文を使ってFTLを読み込むと、たとえ top.ftl で同名の変数やマクロが定義されていたとしても衝突してエラーにはなりません。

別の名前空間内の変数を編集する

<#-- top.ftl -->
<#import "/lib/library-a.ftl" as libA>
${libA.mail}
<#assign mail="jsmith@other.com" in libA>
${libA.mail}

<#-- 出力内容
jsmith@acme.com
jsmith@other.com
-->

データモデルと名前空間

データモデルの変数はどこからでも参照できます。
例えば user という名前の変数がデータモデルにあった場合、lib/library-a.ftl はこの user 変数にアクセスできます。

<#-- library-a.ftl -->
<#macro copyright date>  
    <p>Copyright © $(date) ${user}. All rights reserved.</p>
</#macro>  

<#assign mail = "${user}@acme.com">

user が"Fred"だった場合、下記のようになります。

<#import "/lib/library-a.ftl" as libA>
<@libA.copyright date="2012-2013"/>
${libA.mail}

<#-- 出力内容
<p>Copyright © 2012-2013 Fred. All rights reserved.</p>
Fred@acme.com
-->

ただし、名前空間内でデータモデルと同名の変数が宣言されていた場合、後者が勝ちます。

名前空間のライフサイクル

同じFTLを別名で複数回 import で読み込んだ場合、名前空間は最初の読み込みに対してのみ作られ、以後の読み込みは同一の名前空間に対する別名となります。

<#import "/lib/library-a.ftl" as libA>
<#import "/lib/library-a.ftl" as foo>
<#import "/lib/library-a.ftl" as bar>
${libA.mail}, ${foo.mail}, ${bar.mail}
<#assign mail="jsmith@other.com" in my>
${libA.mail}, ${foo.mail}, ${bar.mail}

<#-- 出力内容
jsmith@acme.com, jsmith@acme.com, jsmith@acme.com,
jsmith@other.com, jsmith@other.com, jsmith@other.com,
-->

グローバル変数とローカル変数

FTLにもグローバル変数とローカル変数があります。

assign(ローカル変数)

<#assign foo="bar">

変数の定義や置き換えができます。
特定の名前空間内に変数を作成したり、置き換えることもできます。
(<#assign someValue = "foo" in someNamespace>)

assign を利用して宣言された変数は、名前空間が変わると参照できません。

global(グローバル変数)

<#global foo="bar">

global を使って定義された変数は、すべての名前空間で参照できます。 しかし、個々の名前空間内で同名の変数が定義されていると、その名前空間からはグローバル変数の方にはアクセスできません。
ただし、その場合でも globals という特別な変数を介してアクセスすることはできます。

${.globals.foo}

globals を介してグローバル変数にアクセスできるだけでなく、データモデルの変数にもアクセスすることができます。

local(ローカル変数)

<#local foo="bar">

local 構文はマクロや関数の中でのみ使用することができます マクロ/関数内で local を利用して作られた変数は、そのマクロ/関数外からは参照できません。

つまりどうしたらいい?

  • ライブラリFTLを読み込むときは import で読み込む
  • マクロから参照したい変数が親FTLにある場合、 global を使って宣言する
  • マクロや関数内では、特に意図した場合でない限り local を使って変数宣言する

参考

FreeMarker Manual - Namespaces
FreeMarker Manual - local
FreeMarker Manual - assign
FreeMarker Manual - global

2013年12月5日木曜日

HomebrewからSubversion 1.7をインストールする

普通に brew install subversion してしまうと1.8がインストールされてしまうので、下記のようにする。

brew tap hombrew/versions
brew info subversion17
brew install subversion17

これでSubversion 1.7がインストールされる。

2013年11月19日火曜日

[Android]動的にリソースを取得する

ステータスバーにバッテリー残量を表示させようとして詰まったのでメモ。
動的にリソースを変更したい時はこうすると捗る。

getResources().getIdentifier(resourceName, resourceType, getPackageName());

上記コードでリソースのIDが取得できる。
resourceNameにはリソースの名前を、
resourceTypeにはリソースのタイプ(string, id, drawable…)を
指定する。

ちなみに、

getResources().getIdentifier("@drawable/ic_launcher", null, getPackageName());

みたいにリソース名にタイプを含めちゃっても取得できる。

[Android]特定のPreferenceに依存するPreferenceをつくる

特定のスイッチがオンの時に有効になって、オフの時には使えないスイッチを作る方法です。
ガリガリコード書かなきゃいけないのかと思ったら、xmlの設定だけでいけました。

<SwitchPreference
    android:key="pref1"
    android:title="pref1_title"
    android:switchTextOff="OFF"
    android:switchTextOn="ON"
    android:defaultValue="true"/>

<SwitchPreference
    android:key="pref2"
    android:title="pref2_title"
    android:switchTextOff="OFF"
    android:switchTextOn="ON"
    android:defaultValue="true"
    android:dependency="pref2"/>

android:dependency="foo" と指定すると、指定されたkeyを持つPreferenceの状態に依存するPreferenceが作れます。

2013年10月3日木曜日

Chrome 30で「新しいタブ」を従来のものに戻す方法

最近のChromeのアップデートで「新しいタブ」のデザインが刷新された。 タブの真ん中に検索ボックスを配置するのは明らかに初心者を意識した変更だけど、オムニボックスから検索が可能なことがわかっていれば改悪である。

なによりも、右下の「最近閉じたタブ」がなくなってしまったのが非常に不便でならない。

というわけで、もとの「新しいタブ」に戻してみた。 やり方は簡単。

  1. オムニボックスから chrome:flags にアクセス

  2. 「Instant Extended API を有効にする」オプションを「無効」にする

以上。 これで見慣れた「新しいタブ」に戻った。

2013年9月4日水曜日

tmuxinatorで思うように画面分割できないときにやるべきたった一つのこと

例によってタイトルは釣り。

最近tmuxを使い始めて、ついでにtmuxinatorも入れてみました。
iTermを起動したらすぐに作業が開始できていい感じです。
ただ、標準のレイアウトではうまく画面分割できなかったのでこんな感じで設定してみました。

1. tmuxを起動し、手動で画面を分割する

C-b %C-b " を活用して画面を任意のレイアウトに分割します。

2. 分割の設定を取得

tmux list-windows を実行すると下記のように表示され、画面分割の細かい設定が取得できます

    tmux list-windows
    0: zsh* (3 panes) [364x84] [layout 4e2c,364x84,0,0{182x84,0,0,5,181x84,183,0[181x42,183,0,6,181x41,183,43,7]}] @2 (active)

3. 分割の設定をtmuxinatorの設定ファイルに転記する

上記コマンドで取得したレイアウト情報を転記します。
必要なのは layout より後ろの部分です。

    # .tmuxinator/foo.yml

    windows:
        - editor: 
            layout: 4e2c,364x84,0,0{182x84,0,0,5,181x84,183,0[181x42,183,0,6,181x41,183,43,7]}
            panes:
                - ls
                - cd workspace
                - # empty pane

以上、こんな感じで幸せになれました。

2013年8月26日月曜日

zshでgitの補完機能を使う

zshでgitのブランチ名等を補完できるようにします。
homebrewからzshとgitをインストールしてる前提です。

homebrewからgitをインストールしてると、一緒に git-completion.zsh がインストールされるので、これを使います。

1. .zshrcに設定追加

以下の内容を追加します。既存の内容と重複する場合は適宜調整してください。

fpath=($(brew --prefix)/share/zsh/site-functions $fpath)

autoload -U compinit
compinit -u

2. zcompdumpの再構築

以下のコマンドを実行します。

rm -f ~/.zcompdump; compinit

実行後に source ~/.zshrc するかzsh再起動すればブランチ名が補完されるようになってます。
以上。

2013年8月23日金曜日

rbenvとruby-buildでrubyを使う

  1. opensslとreadlineをインストール

    brew install openssl readline
  2. homebrewからインストールしたopensslとreadlineを使用するためにリンク

    brew link readline --force
    brew link openssl --force
  3. rubyのインストール

rbenv install -l でインストール可能なrubyが一覧できる。今回は2.0.0-p247をインストールする。

    CONFIGURE_OPTS="--with-readline-dir=/usr/local --with-openssl-dir=/usr/local" rbenv install 2.0.0-p247
  1. opensslとreadlineのリンク解除

brew doctor で警告が出るためリンク解除しておく

    brew unlink openssl
    brew unlink readline
  1. インストール済みrubyの確認

    rbenv versions
     *system (set by /Users/foo/.rbenv/version)
      2.0.0-p247
  2. デフォルトで使用するrubyの設定

    rbenv global 2.0.0-p247
  3. 特定のディレクトリ内で利用する

    cd foo
    rbenv local 2.0.0-p247

2013年8月21日水曜日

Macにrbenvをインストール

Chef/Vagrantをやってみたくなったのでruby環境を作る。
Macのrubyはバージョンが古いので新しいのを使えるようにしなきゃならない。

そこで出てくるのがrubyのバージョン管理ツール。
rvmにしようかrbenvにしようか迷ったけど、結局rbenvにしてみた。
理由はHomebrewから導入できるから。

手順

  1. rbenvとruby-buildをインストールする

    brew install rbenv ruby-build
    echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.zshrc

これだけ!
簡単でした。

2013年7月16日火曜日

jsrender 1.0preから1.0betaにバージョンアップした時に躓いたところ

javascriptテンプレートエンジンの一つであるJsRender
今日久しぶりにレポジトリを確認したら1.0betaにバージョンアップしてました。
今まで使っていたのが1.0pre。ただ jsrender.js を更新するだけでは使えず、コード側にもちょっと更新作業が必要でした。

ヘルパー

1.0preでは jsviews.helpers がヘルパー登録用メソッドだったのですが、1.0betaでは jsviews.views.helpers に移動しています。

// 1.0pre ----------
jsviews.helpers({
  fooHelper: function() {},
  barHelper: function() {}
});

// 1.0beta ----------
jsviews.views.helpers({
  fooHelper: function() {},
  barHelper: function() {}
});

カスタムタグ

1.0preではヘルパーと同様に登録用メソッドが jsviews.tags から jsviews.views.tags に移動しています。
また、1.0preではカスタムタグの描画メソッドも this.renderContent から this.tagCtx.render に変わっています。

// 1.0pre ----------
jsviews.tags({
  fooTag: function(param) {
    var ret = '';
    // カスタムタグのロジック…

    ret = this.renderContent(param);

    return ret;
  },
  barTag: functioN() {}
});

// 1.0beta ----------
jsviews.views.tags({
  fooTag: function(param) {
    var ret = '';    
    // カスタムタグのロジック…

    ret = this.tagCtx.render(param);

    return ret;
  },
  barTag: function() {}
});

とりあえず現時点で対応したのは上記の点のみ。
別件ですがjsrender.min.jsにバージョン番号つけてほしい…(jsrender-1.0beta.min.jsみたいに)

2013年6月4日火曜日

Nexus 4を買って真っ先にしたこと(root化とか色々)

Nexus4買いました。

最初は日本のGoogle Play Storeから発売されるの待ってたんですが、日本のストアから製品情報が削除されたという話を見て、ついAmazonで購入。

以下に開封してからの2時間弱くらいでやった作業をまとめておきます。
ちなみにキャリアはドコモです。作業PCはMacbook Air。

今使ってる端末のデータのバックアップ

使っていた端末はCyanogenMod 10.1を入れたGalaxy Nexus。
Nexus4に引き継ぎたいデータだけに絞ってTitanium Backupでバックアップ -> PCに保存
主にゲームのセーブデータ系ですね。
アプリ全部のバックアップはとくにしませんでした。
最近はGoogleアカウントとひもづけると、前の端末で使ってたアプリを自動でダウンロードしてくれるので。

bootloaderのアンロック

adbやfastbootはPCに入っている前提。
検証してないけど最近はandroid sdk入れたらfastbootコマンドも入ってるんですかね。
sdk managerから最新版ダウンロードしたらfastbootコマンドも入ってたような気がする。

  1. PCにつないで下記のコマンドを実行し、bootloaderに再起動

    adb reboot bootloader
  2. ドロイドくんが分解されてる画面になったら、以下のコマンドを実行

    fastboot oem unlock
  3. ボリュームボタン上下で Yes を選択、電源ボタンで決定。

これでbootloaderのアンロックは完了

ClockworkMod Recoveryの導入

  1. ClockworkModの公式サイトから、Nexus4用のリカバリイメージをダウンロード。
  2. 適当なフォルダに入れて recovery.img にリネームする。
  3. ターミナルを開き、 recovery.img をダウンロードしたフォルダに移動し、下記のコマンドを実行

    adb reboot bootloader
    fastboot flash recovery recovery.img

以上でClockworkMod Recoveryの導入は完了。
bootloaderのメニューで Recovery Mode を選ぶとClockworkMod Recoveryが起動するようになっている。

root取得

  1. このリンクから SU_Busybox_Package.zip をダウンロードする(参考)。
  2. ダウンロードしたzipファイルをNexus4の内部ストレージの直下に配置する。
  3. 下記のコマンドを実行してリカバリにモードに入る。

    adb reboot bootloader
  4. Recovery Mode を選択しリカバリを起動。
  5. ボリュームボタン上下を使い install zip from sdcard を選択、電源ボタンで決定し今度は Choose zip from sdcard を選ぶ。
  6. 内部ストレージ直下に配置した SU_Busybox_Package.zip を選択し、電源ボタンを押す。
  7. 処理が終わったら reboot system now を選択して再起動。
  8. アプリの一覧にSuper SUがあればroot化完了。

CyanogenMod 10.1の導入

  1. Google PlayからROM Managerをダウンロード
  2. ROM ManagerからCyanogenModとGoogle Appsをダウンロード
  3. ダウンロード完了したらそのままインストラクションにしたがってリカバリに再起動 -> インストール完了

APNの設定

moperaの場合は下記の2つを追加。
CyanogenModなら最初から入ってる気がする。

  • mopera.net
  • open.mopera.net

ボイスメールの番号設定

留守電の設定です。
電話アプリの設定から「ボイスメール」 -> 「セットアップ」 -> 「ボイスメールの番号」と選択。 番号は「1417」を入力

バックアップしたデータの復元

最初にバックアップを取ったアプリのデータをTitanium Backupで復元する


以上、こんな感じ。

2013年5月27日月曜日

ドット記法のStringを元にオブジェクトのメンバを取得する[JavaScript]

以下のような階層の深いオブジェクトから、任意の階層にあるプロパティを楽に取得したくて作ってみました。

var foo = {
  bar: {
    hoge: 1,
    fuga: {
      isBar: true
    }
  }
};

こんな感じ。

var findRecursively = function(keyString, src) {
    var varSplitter = /\./,
        srcObj = src || window,
        keyAry = keyString.split(varSplitter),
        key;

    while (key = keyAry.shift()) {
      obj = obj[key];
      if (!obj) {
        return null;
      }
    }
    return obj;
};

var result = findRecursively('foo.bar.hoge');
console.log(result);  // 1

var result2 = findRecursively('bar.fuga.isBar', foo);
console.log(result2); // true

第一引数には、取得したいプロパティの場所をドット記法で表記したStringを渡します。
第二引数には第一引数で渡したプロパティを探したいオブジェクトを渡します。
第二引数がない場合はwindow変数から探します。

if ('foo' in window && 'bar' in foo && …) {
  ...
}

みたいな書き方をしないで済むようになります。

homebrewでgradleをインストールする

groovyもgradleもhomebrewのformulaにあるのでチョー簡単です。

groovyのインストール

brew install groovy

インストールが終わったら、 正しくインストールされていることを確認。以下のようにバージョン情報が表示されればOK

groovy -v
Groovy Version: 2.1.3 JVM: 1.6.0_45 Vendor: Apple Inc. OS: Mac OS X

gradleのインストール

brew install gradle

インストールが終わったら、正しくインストールされていることを確認。以下のようにバージョン情報が表示されればOK

gradle -v

------------------------------------------------------------
Gradle 1.6
------------------------------------------------------------

Gradle build time: 2013�N5��7�� 9��12��14�b UTC
Groovy: 1.8.6
Ant: Apache Ant(TM) version 1.8.4 compiled on May 22 2012
Ivy: 2.2.0
JVM: 1.6.0_45 (Apple Inc. 20.45-b01-451)
OS: Mac OS X 10.7.5 x86_64

文字化けはとりあえずスルー。
インストールされていたら、環境変数PATHに GRADLE_HOME/bin を追加。

vim .zshrc

export GRADLE_HOME=/usr/local/Cellar/gradle/1.6
export PATH=$PATH:$GRADLE_HOME/bin

とりあえずはこんな感じで。
jsの圧縮に使ってるAntの設定ファイルの移行とか、色々試してみよう。

2013年5月9日木曜日

gitでコミット時のメッセージ編集でエラーになる時の対処法

gitでコミットする時、viでコミットメッセージを入力しても

error: There was a problem with the editor 'vi'.
Please supply the message using either -m or -F option.

みたいなエラーが出てコミットされなかったので調べたら、gitで使用するエディタを明示的に指定すればいいらしい。
こんな感じ。

git config --global core.editor "/usr/bin/vim"

コミットメッセージを保存する時はいつもどおり :wq でOK。

2013年4月15日月曜日

IntellJ IDEAが起動しなくなった時にすべきたった一つのこと

2013年4月6日土曜日

Gmailのマルチ受信トレイを使う際につまづいたこと

2013年2月26日火曜日

ブログのTwitterタイムラインウィジェットをAPI 1.1に対応させる

2013年2月11日月曜日

Frontrend vol.4に参加してきた

2013年2月10日日曜日

[JavaScript]任意の数の引数を受け取り処理を行う

2013年2月7日木曜日

GitHub創設者が語るイベントに参加してきた

2013年2月6日水曜日

ディレクトリを簡単に移動できるz.sh入れてみた

2013年2月3日日曜日

Markdownで投稿した記事のソースコードの見た目をいい感じにする

2013年1月31日木曜日

やったーBloggerにmarkdownで記事を投稿できたよー\(^o^)/

2013年1月21日月曜日

bloggerでタイトルを「記事のタイトル→ブログタイトル」の順に表示する方法

意外と簡単だった。

ブログ管理画面の「テンプレート」から
「HTMLの編集」を選択し、下記のタイトルを設定している行を探す。

    <data:blog.pageTitle/>;

ここを以下のように変更する

  
    <data:blog.pageName/> | <data:blog.title/>
  
    <data:blog.pageTitle/>
  

最後に、「テンプレートを保存」をクリックする。
これで検索エンジンの結果ページでもかなり見やすくなる。