2012年12月24日月曜日

Sublime Text 2 で TypeScript の開発環境を整える

このエントリは Sublime Text 2 Advent Calendar 2012 用です。

---

TypeScript については公式サイトなどを見てください。

Sublime Text 2 で TypeScript を開発するためのこまごましたチップスをブログに書いてきたので、一旦まとめたいと思います。


1. TypeScript ファイル(.ts)をシンタックスハイライトするようにする

「Y.A.M の雑記帳 - Sublime Text 2 に TypeScript の syntax highlighting を入れる」 を見よう!


2. TypeScript の補完がでるようにする

「Y.A.M の雑記料 - Sublime Text 2 で TypeScript の補完を出すプラグイン作った」 を見よう!

補完は以下のコマンドで出ます(標準機能)。

Linux : alt + /
Mac : command + space


3. TypeScript ファイルをビルドできるようにする

「Y.A.M の雑記帳 - Sublime Text 2 で TypeScript をビルドする」 を見よう!

ビルドは以下のコマンドで実行できます。

Linux : ctrl + b
Mac : command + b


4. ファイル保存時に自動でビルドさせる

「Y.A.M の雑記帳 - Sublime Text 2 でファイル保存時に自動でビルドさせる」 を見よう!


5. ctrl + / (Mac は command + /)でコメントをトグルさせる

「Y.A.M の雑記帳 - Sublime Text 2 で .ts ファイルでも Ctrl + / でコメントをトグルできるようにする」 を見よう!


6. TypeScript 用のスニペットを作る

JavaScript 用にあらかじめ用意されているスニペットがいくつかあります。

([Preferences] - [Browse packages...])/JavaScript/ の中をみると .sublime-snippet ファイルがこれだけあります。
  • for-()-{}.sublime-snippet
  • for-()-{}-(faster).sublime-snippet
  • function.sublime-snippet
  • function-(fun).sublime-snippet
  • Get-Elements.sublime-snippet
  • if.sublime-snippet
  • if-___-else.sublime-snippet
  • Object-key-key-value.sublime-snippet
  • Object-Method.sublime-snippet
  • Object-Value-JS.sublime-snippet
  • Prototype-(proto).sublime-snippet
  • setTimeout-function.sublime-snippet


例えば、for-()-{}.sublime-snippet の中身は次のようになっています。

for source.js for (…) {…}

scope で指定されている拡張子のファイルで、tabTrigger で指定されている単語の後に Tab を押すと、content で指定されているスニペットに置き換わります。Tab を押したときに候補が複数ある場合は、補完候補ウィンドウに description が表示されます。

tabTrigger に for を指定しているスニペットが
・for-()-{}.sublime-snippet
・for-()-{}-(faster).sublime-snippet
の2つあるため、次のように候補が2つ表示されます。



上部の候補を選ぶと次のように for 文のスニペットに置き換わります。



これらの補完を TypeScript でも使えるようにしてみます。

・for

せっかくなので、TypeScript の特徴である型情報を付加して、var i を var i : number にします。 scope タグを source.ts にするのを忘れずに。 このファイルを ([Preferences] - [Browse packages...])/TypeScript/ に置きます。

TypeScript/for-()-{}.sublime-snippet
<snippet> <content><![CDATA[for (var ${20:i} : number = 0; ${20:i} < ${1:Things}.length; ${20:i}++) { ${100:${1:Things}[${20:i}]}$0; }]]></content> <tabTrigger>for</tabTrigger> <scope>source.ts</scope> <description>for (…) {…}</description> </snippet>
他のも TypeScript 用にします。

TypeScript/for-()-{}-(faster).sublime-snippet
<snippet> <content><![CDATA[for (var ${20:i} : number = ${1:Things}.length - 1; ${20:i} >= 0; ${20:i}--) { ${100:${1:Things}[${20:i}]}$0; }]]></content> <tabTrigger>for</tabTrigger> <scope>source.ts</scope> <description>for (…) {…} (Improved Native For-Loop)</description> </snippet>

・function

TypeScript では無名関数は
(x) => x*x;
のように記述するので、function.sublime-snippet は次のようにしました。

TypeScript/function.sublime-snippet
<snippet> <content><![CDATA[($1) => {${0:$TM_SELECTED_TEXT}};]]></content> <tabTrigger>f</tabTrigger> <scope>source.ts</scope> <description>Anonymous Function</description> </snippet>

TypeScript/function-(fun).sublime-snippet
<snippet> <content><![CDATA[function ${1:function_name} (${2:argument} : ${3:type}) : ${4:return_type} { ${0:// body...} }]]></content> <tabTrigger>fun</tabTrigger> <scope>source.ts</scope> <description>Function</description> </snippet>

・get elements

TypeScript/Get-Elements.sublime-snippet <snippet> <content><![CDATA[getElement${1/(T)|.*/(?1:s)/}By${1:T}${1/(T)|(I)|.*/(?1:agName)(?2:d)/}('$2')]]></content> <tabTrigger>get</tabTrigger> <scope>source.ts</scope> <description>Get Elements</description> </snippet>

・if

TypeScript/if.sublime-snippet
<snippet> <content><![CDATA[if (${1:true}) { ${0:$TM_SELECTED_TEXT} }]]></content> <tabTrigger>if</tabTrigger> <scope>source.ts</scope> <description>if</description> </snippet>

TypeScript/if-___-else.sublime-snippet
<snippet> <content><![CDATA[if (${1:true}) { ${2:$TM_SELECTED_TEXT} } else { ${3:$TM_SELECTED_TEXT} }]]></content> <tabTrigger>ife</tabTrigger> <scope>source.ts</scope> <description>if … else</description> </snippet>

Object-key-key-value.sublime-snippet, Object-Method.sublime-snippet, Object-Value-JS.sublime-snippet は JavaScript でもうまく動いていないのでスキップ。


・function

TypeScript/setTimeout-function.sublime-snippet
<snippet> <content><![CDATA[setTimeout(function() {$0}${2:}, ${1:10});]]></content> <tabTrigger>timeout</tabTrigger> <scope>source.ts</scope> <description>setTimeout function</description> </snippet>


TypeScript では、class や module が使えます。
これら用のスニペットも用意しましょう(これらに置き換えるので Prototype-(proto).sublime-snippet はスキップ)

・class

"class" + tab

TypeScript/class.sublime-snippet
<snippet> <content><![CDATA[class ${1:className} extends ${2:superClass} implements ${3:interface} { ${4:varName} : ${5:varType}; ${6:funcName}(${7:arg} : ${8:argType}) : ${9:returnType} { ${10} } constructor(${11:arg} : ${12:argType}) { ${13:super();} } static ${21:varName} : ${22:varType}; static ${23:funcName}(${24:arg} : ${25:argType}) : ${26:returnType} { ${27} } }]]></content> <tabTrigger>class</tabTrigger> <scope>source.ts</scope> <description>class</description> </snippet>

・module

"module" + tab

TypeScript/module.sublime-snippet
<snippet> <content><![CDATA[module ${1:moduleName} { ${0:$TM_SELECTED_TEXT} }]]></content> <tabTrigger>module</tabTrigger> <scope>source.ts</scope> <description>module</description> </snippet>

・interface

"interface" + tab

TypeScript/interface.sublime-snippet
<snippet> <content><![CDATA[interface ${1:interface-name} { ${0:$TM_SELECTED_TEXT} }]]></content> <tabTrigger>interface</tabTrigger> <scope>source.ts</scope> <description>interface</description> </snippet>

・Index Signature

"index" + tab

var dic : { [index : string] : type; } = {};

TypeScript/index-signature.sublime-snippet
<snippet> <content><![CDATA[var dic : { [index : ${1:string}] : ${2:type}; } = {};]]></content> <tabTrigger>index</tabTrigger> <scope>source.ts</scope> <description>Index Signature</description> </snippet>

・reference

"reference" + tab

/// <reference path="…"/>

TypeScript/reference.sublime-snippet
]]> reference source.ts reference

その他に以下も用意してみました。

・Array

"array" + tab

var array : type[] = [];

TypeScript/array.sublime-snippet <snippet> <content><![CDATA[var array : ${0:type}[] = [];]]></content> <tabTrigger>array</tabTrigger> <scope>source.ts</scope> <description>Array</description> </snippet>

これで
  • array
  • class
  • for
  • function
  • get
  • if
  • index
  • interface
  • module
  • reference
  • timeout
でスニペット補完がでます。

ここから全部のファイルをコピーするのは面倒だと思うので、TypeScript フォルダを zip にしました。
ここからどうぞ TypeScript.zip



2012年12月19日水曜日

Sublime Text 2 で .ts ファイルでも Ctrl + / でコメントをトグルできるようにする

JavaScript の設定をそのまま流用します。

([Preferences] - [Browse Packages...]) /JavaScript/Comments.tmPreferences



([Preferences] - [Browse Packages...]) /TypeScript/

にコピー。

開いて、

<key>scope</key>
<string>source.js, source.json</string>



<key>scope</key>
<string>source.ts</string>

に変更し、Sublime Text 2 を再起動。これだけ!


2012年12月18日火曜日

Sublime Text 2 で Emmet プラグインを使う

Emmet は Zen-Codingの次期バージョンで、仕様も大幅に変わっているようです。さらに使いやすくなっている!

emmet-sublime

Ctrl + Shift + P (Command + Shift + P) で Install Package を選択



Emmet を選択



* 参考にさせていただいたサイトでは github のリポジトリを Package Control に add repository してからインストールする方法が説明されていますが、現在は Package Control の Install Package から Emmet Plugin をインストールすることができます。

参考にさせていただいたサイト

1つ前のエントリで ZenCoding を紹介しておきながら、Emmet に移行することにしました。 主な理由が以下のポイントです。


気に入ったポイント

1. $ がちゃんと動く

ZenCoding は

ul#main>(li>img#main-$)*4

の展開が <ul id="main"> <li><img src="" alt="" id="main-1"></li> <li><img src="" alt="" id="main-1"></li> <li><img src="" alt="" id="main-1"></li> <li><img src="" alt="" id="main-1"></li> </ul> のように $ 部分がすべて1になってしまう場合がありました。

Emmet だとちゃんと <ul id="main"> <li><img src="" alt="" id="main-1"></li> <li><img src="" alt="" id="main-2"></li> <li><img src="" alt="" id="main-3"></li> <li><img src="" alt="" id="main-4"></li> </ul> になってくれます。


2. lorem ipsum が出力できる

p>lorem

を展開すると <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam sunt sapiente ratione reprehenderit eveniet sit possimus a porro amet veniam ipsam repellat expedita nam excepturi autem cupiditate cumque obcaecati recusandae.</p> になります。

p>lorem16

のように単語数を指定することもできます。 <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quis temporibus minima quae voluptates architecto voluptas obcaecati.</p>

3. CSS の補完がすごい

m40

margin: 40px;

m0-8

margin: 0 8px;


p8

padding: 8px;


h55

height: 55px;


lstn

list-style-type: none;


fll

float: left;


cb

clear: both;


4. CSS で - 補完がすごい

-bdrs

-webkit-border-radius: ;
-moz-border-radius: ;
border-radius: ;


4. カスタマイズの方法がわかりやすい

[Preferences] - [Package Settings] - [Emmet] に
[Settings - Default] と [Settings - User] が用意されました。

カスタムスニペットとかは [Settings - User] に書きます。

デフォルトのスニペットは
([Prefernces] - [Browse Pacakges...] で開くディレクトリ)/Emmet/emmet/snippets.json
に定義されていますが、こっちは変更せずに [Settings - User] に書くようにします。

[Settings - User] を以下のようにしてます。 { // Custom snippets definitions, as per https://github.com/emmetio/emmet/blob/master/snippets.json "snippets": { "html": { "snippets": { "html:5": "<!DOCTYPE html>\n<html lang='${lang}'>\n<head>\n\t<meta charset='${charset}' />\n\t<title>${1:Document}</title>\n</head>\n<body>\n\t${child}${2}\n</body>\n</html>", "html:t": "<!DOCTYPE html>\n<html lang='${lang}'>\n<head>\n\t<meta charset='${charset}' />\n\t<link rel='stylesheet' href='${1:style}.css' type='text/css' />\n\t<script type='text/javascript' src='${2:../jquery-1.8.3.min.js}' />\n\t<script type='text/javascript' src='${3:main.js}' />\n\t<title></title>\n</head>\n<body>\n\t${child}|\n</body>\n</html>" }, "abbreviations": { "less:css": "<link rel='stylesheet/less' type='text/css' href='${1:style}.less' />", "link:css": "<link rel='stylesheet' type='text/css' href='${1:style}.css' />", "script:src": "<script type='text/javascript' src='' />" } } } }


---

前回のエントリにも書いた、 html のときに br の展開を <br /> にする方法の修正点は

([Prefernces] - [Browse Pacakges...] で開くディレクトリ)/Emmet/emmet/emmet-app.js

に変わりました。同じように self_closing_tag を変更します。

5132行の createProfile('html', {self_closing_tag: false}); が該当部分です。

createProfile('html', {self_closing_tag: false});
だと(デフォルト)
<link rel="stylesheet" href="">

createProfile('html', {self_closing_tag: true});
だと
<link rel="stylesheet" href=""/>

createProfile('html');
だと(デフォルトの self_closing_tag: 'xhtml' になる)
<link rel="stylesheet" href="" />

になります。



Sublime Text 2 の ZenCoding プラグインのカスタマイズ方法

Sublime Text 2 用の Zen Coding プラグインがあります。

Sublime Package Control に登録されているので、Sublime Package Control を入れている場合は、そこから Zen Coding パッケージを入れれば使えます。

ちなみに Sublime Package Control のインストール方法は、[View] - [Show Console] でコンソールを開いて、そこに Sublime Package Control Installation に載ってるコマンドを入力し、Sublime Text 2 を再起動するだけです。

ZenCoding は例えば

div#page>div.logo+ul#navigation>li*5>a

と入力してタブを押すと <div id="page"> <div class="logo"></div> <ul id="navigation"> <li><a href=""></a></li> <li><a href=""></a></li> <li><a href=""></a></li> <li><a href=""></a></li> <li><a href=""></a></li> </ul> </div> に変換してくれる機能をエディタに加えるプラグインです。
Zen Coding syntax は Zen Coding の Google Code の Wiki にあります。

さて、Zen Coding には abbreviations という機能があります。

例えば

<a href=""></a>

のように展開したい場合、

a[href]

と打ってタブを押す必要がありますが、

a

の状態でタブを押しても a[href] と同じように展開されるように略語を設定できる機能です。

他にも

a:link

という略語が用意されていて、この状態でタブを押すと

<a href="http://"></a>

に展開されます。

また、

html:5

でタブを押すと <!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8"> <title></title> </head> <body> </body> </html> に変換する snippet 機能もあります。


各略語がどのように変換されるかは Zen Coding プラグインフォルダの zen_settings.py に書かれています。

([Preferences] - [Browse Packages...] で開くディレクトリ)/ZenCoding/zencoding/zen_settings.py


私は次のように変更して使っています。

■ 'html' の 'snippets' の 'html:5': '<!DOCTYPE HTML>\n' + '<html lang="${locale}">\n' + '<head>\n' + ' <meta charset="${charset}">\n' + ' <title></title>\n' + '</head>\n' + '<body>\n\t${child}|\n</body>\n' + '</html>' 'html:5': '<!DOCTYPE html>\n' + '<html lang="${lang}">\n' + '<head>\n' + ' <meta charset="${charset}" />\n' + ' <title></title>\n' + '</head>\n' + '<body>\n\t${child}|\n</body>\n' + '</html>' に変更

■ 'html ' の 'snippets' に以下を追加
(本当は 'common' に入れるべきなんだろうけど、なんか動かなかった。) 'html:t': '<!DOCTYPE html>\n' + '<html lang="${lang}">\n' + '<head>\n' + ' <meta charset="${charset}" />\n' + ' <link rel="stylesheet" href="${1:style}.css" type="text/css" />\n' + ' <script type="text/javascript" src="${2:../jquery-1.8.3.min.js}" />\n' + ' <script type="text/javascript" src="${3:main.js}" />\n' + ' <title></title>\n' + '</head>\n' + '<body>\n\t${child}|\n</body>\n' + '</html>'

■ 'html' の 'abbreviations' の 'script:src': '<script type="text/javascript" src=""></script>', 'script:src': '<script type="text/javascript" src="" />', に変更

■ 'html' の 'abbreviations' に以下を追加 'less:css': '<link rel="stylesheet/less" type="text/css" href="${1:style}.less" />',


---

html で(xhtml ではなく)br が <br> に展開されるのを <br /> にするには、

([Preferences] - [Browse Packages...] で開くディレクトリ)/ZenCoding/zencoding/utils.py を変更します。

setup_profile('html', {'check_valid' : True, 'self_closing_tag': False});

の 'self_closing_tag' によって振る舞いが異なります。

■ setup_profile('html', {'check_valid' : True, 'self_closing_tag': False});
だと(デフォルト)
<link rel="stylesheet" href="">

■ setup_profile('html', {'check_valid' : True, 'self_closing_tag': True});
だと
<link rel="stylesheet" href=""/>

■ setup_profile('html', {'check_valid' : True});
だと
<link rel="stylesheet" href="" />

になります。

吉川さんありがとうございます。



2012年12月17日月曜日

Sublime Text 2 の設定

Sublime Text 2 自体の設定(例えばテキストサイズとかフォントとか)は、[Preferences] - [Settings -User] に書きます。



デフォルトだと { "ignored_packages": [ "Vintage" ] } なので、何を書けばいいかよくわからん!と思いますが。
[Preferences] - [Settings - Default] にデフォルトの設定があるので、これを参考にして上書きしたい設定を [Settings - User] の方に書きます。[Settings - Default] の方は変更しません。

いくつか紹介します。
  • "font_face" 文字のフォント
    システムフォントとして設定されている必要があります。
    私のオススメは monaco (ver 2.0) と Source Code Pro です。

    Mac はフォントファイルをダブルクリックすれば、システムフォントに登録されるので楽ですね。
    Ubuntu では、フォントファイルを ~/.fonts/ にコピーすれば OK。

    "font_face": "monaco",
    "font_face": "SourceCodePro",

  • "font_size" 文字の大きさ。デフォルトは 10。
    整数で指定します。10.5 と指定しても 10 と同じ大きさになります。

    "font_size": 10,

  • "line_numbers" 左に行数を表示するかどうか。true の場合表示される。デフォルトは true。

    "line_numbers": true,

  • "gutter" 左に余白を設けるかどうか。デフォルトは true。この余白に行数が表示される。false にすると line_numbers で true を指定していても行数は表示されない。

    "gutter": true,

  • "margin" gutter とコードの間の余白。デフォルトは 4。整数を指定する。

    "margin": 8,

  • "rulers" ガイド線の位置を配列を指定する。デフォルトは空配列。

    "rulers": [40, 60],

  • "tab_size" タブのサイズをスペース何個分にするかを指定する。

    "tab_size": 4,

  • "translate_tabs_to_spaces" タブが入力された場合にスペースに置き換える。デフォルトは false。

    "translate_tabs_to_spaces": true,

  • "trim_automatic_white_space" キャレットを行から外したときに自動インデントで追加された空白を削除するかどうか。デフォルトは true = 削除する。

    "trim_automatic_white_space": true,

  • "highlight_line" 選択している行をハイライトするかどうか。true の場合ハイライトする。デフォルトは false。

    "highlight_line": true,

  • "caret_style" キャレットのスタイル。smooth, phase, blink, wide, solid のいずれかを指定する。デフォルトは smooth。

    "caret_style": "phase",

  • "line_padding_top" 行の上部の余白。デフォルトは 0。整数を指定する。

    "line_padding_top": 0,

  • "line_padding_bottom" 行の下部の余白。デフォルトは 0。整数を指定する。

    "line_padding_bottom": 0,

  • "draw_white_space" 空白にマークを表示するかどうか。none, selection, all のいずれかを指定する。none の場合、常に表示されない。selection の場合、選択状態の部分だけ表示される。all の場合、常に表示される。スペースは・、タブは―で表示される。

    "draw_white_space": "all",

  • "indent_guide_options" インデントガイドの描画方法。draw_normal か draw_active のいずれかを指定する。デフォルトは draw_normal。draw_active を指定した場合、キャレットを含むインデントガイドを別の色で表示する。

    "indent_guide_options": ["draw_active"],

  • "trim_trailing_white_space_on_save" 保存時に末尾の空白を削除するかどうか。デフォルトは false。

    "trim_trailing_white_space_on_save": true,

  • "ensure_newline_at_eof_on_save" 保存時に eof が改行ではない場合、改行になるようにするかどうか。デフォルトは false。

    "ensure_newline_at_eof_on_save": true,

  • "default_encoding" デフォルトの文字コード

    "default_encoding": "UTF-8",

  • "auto_complete_delay" タイピングの後に自動補完ウィンドウが表示されるまでのディレイ[ms]

    "auto_complete_delay": 50,

  • "open_files_in_new_window" OSX のみ。Finder からファイルを開いたとき、もしくはドックアイコンにファイルをドラッグしたときに、新しいウィンドウで開くかどうか。デフォルトは true。

    "open_files_in_new_window": false,

  • "folder_exclude_patterns" フォルダ内でサイドバーに表示しないフォルダ名のパターンの配列。デフォルトは .svn, .git, .hg, CVS の配列。

    "folder_exclude_patterns": [".svn", ".git", ".hg", "CVS"],

  • "file_exclude_patterns" フォルダ内でサイドバーに表示しないファイル名のパターンの配列。デフォルトは以下。

    "file_exclude_patterns": ["*.pyc", "*.pyo", "*.exe", "*.dll", "*.obj","*.o", "*.a", "*.lib", "*.so", "*.dylib", "*.ncb", "*.sdf", "*.suo", "*.pdb", "*.idb", ".DS_Store", "*.class", "*.psd", "*.db"],

  • "binary_file_patterns" サイドバーには表示するが、Goto Anything や Find in Files の対象にしないファイル名のパターン。デフォルトは以下。

    "binary_file_patterns": ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.ttf", "*.tga", "*.dds", "*.ico", "*.eot", "*.pdf", "*.swf", "*.jar", "*.zip"],

  • "ignored_packages" インストールしているが、無視するパッケージのリスト

    "ignored_packages": ["Vintage"]
いまのところこんな感じにしてます。 { "font_face": "SourceCodePro", "font_size": 10, "margin": 8, "rulers": [80], "translate_tabs_to_spaces": true, "highlight_line": true, "caret_style": "phase", "draw_white_space": "all", "indent_guide_options": ["draw_active"], "trim_trailing_white_space_on_save": true, "ensure_newline_at_eof_on_save": true, "open_files_in_new_window": false, "ignored_packages": ["Vintage"] }

2012年12月14日金曜日

Sublime Text 2 の html の入力補完をカスタマイズする

Sublime Text 2 には、デフォルトで html の入力補完機能が用意されています。

例えば、html まで打って Tab キーを押すと、 <html> <head> <title></title> </head> <body> </body> </html> に変換されます。

link まで打って Tab キーを押すと、 <link rel="stylesheet" type="text/css" href=""> に変換されます。

script まで打って Tab キーを押すと、 <script type="text/javascript"></script> に変換されます。


ここで、例えば script と打ってタブを押したときに <script type="text/javascript" src=""></script> と src 属性も入れてほしいなと思った場合、

Subime Text 2 のパッケージディレクトリ([Preferences] - [Browse Packages...] で開くディレクトリ)の HTML フォルダの HTML.sublime-completions を変更します。 { "trigger": "script", "contents": "" }, { "trigger": "script", "contents": "" }, に変更すれば OK です。$n は補完した後にタブでカーソルが移動する位置を指定しています。


html だけはこのファイルではなく、html.sublime-snippet に記述します。

例えば、html と打ってタブを押したときに <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> </head> <body> </body> </html> のように <!DOCTYPE html> と <meta> 部分も入れたいなという場合、

html.sublime-snippet を次のように変更すれば OK です。 <snippet> <content><![CDATA[ <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>$1</title> </head> <body> $0 </body> </html>]]></content> <tabTrigger>html</tabTrigger> <scope>text.html</scope> </snippet>


2012年12月12日水曜日

モダンな TypeScript テスト環境

「これが現代のテスト環境や、どやぁ。」 と @vvakame が用意してくれました。 https://github.com/vvakame/typescript-project-sample

初心者の私にはたくさんのライブラリ(フレームワーク?)が入っててよくわからなかったので、それぞれの立ち位置を教えてもらったのでまとめておきます。


PhantomJS

PhantomJS は JavaScript の API も利用できる headless な WebKit です。実際の描画処理を行わないので速いという特徴があります。また、DOM 操作、CSS セレクタ、JSON、Canvas、SVG などいくつかの web 標準をネイティブでサポートしています。
JavaScript のエンジンは JavaScriptCore らしいです。

実際に Web ページにアクセスして、レンダリング結果の画面のキャプチャをとったり、ページのタイトルを取ってきたり、DOM の値を取ってきたり、いろいろできます。

Quick Start を見ると何ができるかが分かると思います。

例えば、

evaluate.js var url = "http://www.google.com"; var page = require("webpage").create(); page.open(url, function(status) { var title = page.evaluate(function() { return document.title; }); console.log("Page title is " + title); phantom.exit(); }); というコードを書いて実行すると、ページのタイトルを取れます。

$ phantomjs evaluate.js
Page title is Google
サンプルもたくさん用意されています。



Jasmine

Jasmine は JavaScript コードをテストするためのフレームワークです。 使い方は Introduction のコードを見るのがわかりやすいです。その他の情報は Wiki にあります。

最新版は Jasmine 1.3.1 で https://github.com/pivotal/jasmine/downloads からダウンロードできます。

jasmine-standalone-1.3.1.zip を展開すると、次のような構成になっています。

lib/
spec/
src/
SpecRunner.html
lib/ には jasmine.js や jasmine-html.js が入っています。

SpecRunner.html は jasmine を使ったテストのサンプルです。
基本的には、この SpecRunner.html を自分のプロジェクトに合わせて変えることでテストをセットアップできます。

SpecRunner.html で Player.js, Song.js が指定されている部分 にテストしたい元コードを、
SpecHelper.js, PlayerSpec.js が指定されている部分に テストコードを置きます。

下の方の Javascript のコードは window.onload でテストを実行し、結果を html に表示するための部分なので変更はいらいないです。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Jasmine Spec Runner</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.3.1/jasmine_favicon.png"> <link rel="stylesheet" type="text/css" href="lib/jasmine-1.3.1/jasmine.css"> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine.js"></script> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine-html.js"></script> <!-- include source files here... --> <script type="text/javascript" src="src/Player.js"></script> <script type="text/javascript" src="src/Song.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="spec/SpecHelper.js"></script> <script type="text/javascript" src="spec/PlayerSpec.js"></script> <script type="text/javascript"> (function() { var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var htmlReporter = new jasmine.HtmlReporter(); jasmineEnv.addReporter(htmlReporter); jasmineEnv.specFilter = function(spec) { return htmlReporter.specFilter(spec); }; var currentWindowOnload = window.onload; window.onload = function() { if (currentWindowOnload) { currentWindowOnload(); } execJasmine(); }; function execJasmine() { jasmineEnv.execute(); } })(); </script> </head> <body> </body> </html> この SpecRunner.html をブラウザで開くと、このようにテスト結果が表示されます。

Jasmine は JavaScript で構築されているため、Jasmine を実行するには、web page など JavaScript が実行できる環境にいなければいけません。

しかし、この JavaScript を実行するのに毎回ブラウザを立ち上げていたらテストに時間がかかってしまいます。そこで上記の PhantomJS の登場です。

追記 : X Windowとか動いてないLinux機上(大抵のJenkins氏が動いてるサーバはそういう環境)の上で、ブラウザを使ってテストしたいなーというのもある by @vvakame

例えば、
test-jasmine1.js var url = "file:///home/yanzm/Downloads/jasmine-standalone-1.3.1/SpecRunner.html" var page = require("webpage").create(); page.onConsoleMessage = function (msg) { if(msg == "finish-jasmine") { phantom.exit(); } else if(msg != "\n") { console.log(msg); } }; page.open(url, function(status) { page.evaluate(function() { var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var consoleReporter = new jasmine.ConsoleReporter( function(log) { console.log(log); }, function(runner) { console.log("finish-jasmine"); }, false); jasmineEnv.addReporter(consoleReporter); jasmineEnv.execute(); }); }); SpecRunner.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Jasmine Spec Runner</title> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine.js"></script> <script type="text/javascript" src="lib/jasmine-1.3.1/jasmine-console.js"></script> <!-- include source files here... --> <script type="text/javascript" src="src/Player.js"></script> <script type="text/javascript" src="src/Song.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="spec/SpecHelper.js"></script> <script type="text/javascript" src="spec/PlayerSpec.js"></script> </head> <body> </body> </html> (jasmine-console.js の中身は ConsoleReporter.js です。)

のようにすると、コンソールからテストできるようになります。
$ phantomjs test-jasmin1.js 
Started
.
.
.
.
.
Finished in 0.005 seconds
5 specs, 0 failures



grunt

grunt は要は make みたいなものです。

makegrunt
Makefilegrunt.js
make hogegrunt hoge


gruntfile と呼ばれる grunt.js に設定を書いていきます。
Getting Started を見るとなんとなく書き方がわかると思います。

grunt は実行時にカレントディレクトリの grunt.js を見に行くのですが、ない場合は見つけるまで親のディレクトリを遡って探します。普通はプロジェクトリポジトリのルートに置きます。
grunt.js は次の3つの要素からなる JavaScript です。
  • プロジェクトの設定(依存しているライブラリのダウンロードなど)
  • grunt のプラグインやタスクフォルダの読み込み
  • タスクとヘルパー
プロジェクトの設定は grunt.initConfig() で行います。
プラグインやタスクフォルダの指定は grunt.loadTasks() や grunt.loadNpmTasks() で行います。
タスクやヘルパーの指定は grunt.registerTask() で行います。

module.exports = function(grunt) { // Project configuration. grunt.initConfig({ lint: { all: ['grunt.js', 'lib/**/*.js', 'test/**/*.js'] }, jshint: { options: { browser: true } } }); // Load tasks from "grunt-sample" grunt plugin installed via Npm. grunt.loadNpmTasks('grunt-sample'); // Default task. grunt.registerTask('default', 'lint sample'); }; 各 grunt タスクは、grunt.initConfig() に渡されるオブジェクトで定義されている情報に依存します。
このオブジェクトは JavaScript であって JSON ではないので、プログラムで設定オブジェクトを生成させるようなこともできます。
ビルトインのタスクの設定オブジェクトの詳細は Document の Built-in tasks にあります。


フォルダからタスクやヘルパーを読み込むには
grunt.loadTask(folderName);
を使います。

npm を介して grunt のプラグインを読み込むには
grunt.loadNpmTasks(pluginName)
で行います。


grunt.registerTask() で default タスクを設定するまで、単に grunt を実行してもになにも起こりません。

grunt.registerTask('default', 'hoge_task fuga_task');

のように default タスクを登録すると

$ grunt
$ grunt default

と実行したときに第2引数で指定したタスクが実行されます。
上記の場合

$ grunt hoge_task fuga_task

と実行した場合と同じになります。

grunt.registerTask('test', 'hoge_test fuga_test');

のように、好きな alias を登録できます。
この場合、

$ grunt test

とすれば

$ grunt hoge_test fuga_test

と実行したのと同じになります。

init task(ビルトインのタスク)を見てみると、grunt による project の構成がだいだいわかると思います。



まとめ

@vvakame のプロジェクトの grunt.js では以下のライブラリを使っています。

まとめると、
grunt でディレクトリの clean、typescript や less のコンパイル、jasmine の設定など

jasmine で phantomJS を使ってテスト

結果が JUnit 形式の XML で出力される(出力先は grunt.js で設定)

という流れです。



2012年12月8日土曜日

Ubuntu に PhantomJS を入れる

Ubuntu Lucid (10.04) でビルドしたバイナリが http://phantomjs.org/download.html からダウンロードできます。

Lucid 以降のディストリビューションであれば動くそうです。
このバイナリのインストールにあたっては、Qt, WebKit など他のライブラリのインストールは必要ありません。

Lucid より古いシステムでは、ソースからビルドする必要があります。
$ cd /usr/local/share
$ sudo cp ~/Download/phantomjs-1.7.0-linux-x86_64.tar.bz2 .
$ sudo tar -xjvf phantomjs-1.7.0-linux-x86_64.tar.bz2 
$ sudo rm phantomjs-1.7.0-linux-x86_64.tar.bz2
$ sudo ln -s /usr/local/share/phantomjs-1.7.0-linux-x86_64/ /usr/local/share/phantomjs
$ sudo ln -s /usr/local/share/phantomjs/bin/phantomjs /usr/local/bin/phantomjs

$ which phantomjs
/usr/local/bin/phantomjs

$ phantomjs -v
1.7.0

$ phantomjs 
phantomjs> 


PhantomJS Quick Start



2012年12月7日金曜日

TypeScript での Type Assertion

document.getElementById("#input"); の戻り値は HTMLElement なので var input : HTMLInputElement = document.getElementById("#input"); とすると、キャストできないと怒られます。
Cannot convert 'HTMLElement' to 'HTMLInputElement': Type 'HTMLElement' is missing property 'setSelectionRange' from type 'HTMLInputElement'

そこで、次のように < > を使ってキャストすれば怒られなくなります。 var input : HTMLInputElement = <HTMLInputElement>document.getElementById("#input");

2012年12月6日木曜日

TypeScript で jQuery を使う (Sublime Text 2 で jquery の補完)

TypeScript で jQuery を使うには、jQuery の型を定義したファイルが必要です。

TypeScript のコードと一緒に公開されているので、ダウンロードして作業フォルダに入れます。
jquery.d.ts

現状は // Typing for the jQuery library, version 1.7.x とあるので、1.7.x の jQuery に対応しているようです。


次に、自分の .ts ファイルの先頭に
/// <reference path="jquery.d.ts" /> を追加します。これは外部の ts ファイルを読み込むための書き方です。

で、ここで気づきました。Sublime Text 2 で jquery の補完がでません。。。

以前作ったプラグイン(Sublime Text 2 で TypeScript の補完を出すプラグイン作った")を修正しないといけない(修正すれば jquery、というか reference で指定してるファイルの補完がでる)ということにも気づきました。

ということで修正しました。
現在の tsc_completion のバージョンは v1.0.3 になってます。
Sublime Text 2 のプラグインのコードも新しくなっているので、こちらも置き換えてください。

こんな感じで補完がでます。



例えば、こういうのが
/// <reference path="jquery.d.ts" /> var questionArea : JQuery; var inputArea : JQuery; var star1 : JQuery; var star2 : JQuery; var star3 : JQuery; ... $(document).ready(function () { inputArea = $("#text_area"); inputArea.keyup(onInput); questionArea = $("#question_area"); star1 = $("#star1"); star2 = $("#star2"); star3 = $("#star3"); inputArea.focus(); // show first text showNextText(); })
こういうのに変換されます。
var questionArea; var inputArea; var star1; var star2; var star3; ... $(document).ready(function () { inputArea = $("#text_area"); inputArea.keyup(onInput); questionArea = $("#question_area"); star1 = $("#star1"); star2 = $("#star2"); star3 = $("#star3"); inputArea.focus(); showNextText(); }); クラスとか使ってないからそのままだねw


jquery で HTMLInputElement にあたる要素で focus() 呼んでもフォーカスあたらないのはなんでなんだ。。。

jquery 1.8.3 にしたら直った


TypeScript で SourceMap を使う

tsc コマンドに --sourcemap をつけてコンパイルすることで SourceMap ファイル(hoge.js.map)と、SourceMap の情報が書かれた js ファイルが作成されます。
> tsc --sourcemap hoge.ts

> ls
hoge.ts  hoge.js  hoge.js.map

> tail -1 hoge.js
//@ sourceMappingURL=hoge.js.map


この SourceMap を使って Chrome でデバッグするには、Chrome Dev Tool を開いて(右クリックして Inspect Element をクリック or Ctrl + Shif + i (Mac は Command + option + i))、右下の設定(歯車アイコン)をクリックします。



General タブの Enable source maps にチェックを入れます。



リロードすると、Sources で .ts が選択できるようになります。
# なんで .js が2つでてるのかは謎



.ts のほうの行数のところをクリックして Breakpoint を設定できます。



.ts の方の Breakpoint で止まります。




# .ts のほうでうまく Breakpoint が動くときと、なぜか Breakpoint の対応する js 側の行で止まることがあり、まだ SourceMap はうまく動かないのかもしれない。。。


2012年12月5日水曜日

Android CheckedTextView を使うときの注意

ListView で CHOICE_MODE_SINGLE とか CHOICE_MODE_MULTIPLE とか使うときに、1行のレイアウトとして CheckedTextView を使うことがあると思いますが、チェックマークの切り替えには注意が必要です。

チェックマーク画像を設定するメソッドとして

setCheckMarkDrawable(int resid)



setCheckMarkDrawable(Drawable d)

があります。

例えば、チェックできる行にはチェクマーク画像をセットして、チェックできない行(例えばフラグが立ってるとか、ロックされているなど)にはチェックマーク画像をセットしないようにする場合、 if(isChecked) { ctv.setCheckMarkDrawable(R.drawable.check); } else { ctv.setCheckMarkDrawable(null); } とすると、2回目に R.drawable.check をセットしたとき、

setCheckMarkDrawable(R.drawable.check)

setCheckMarkDrawable(null)

setCheckMarkDrawable(R.drawable.check) ←ここ

で画像がセットされません。ListView の1行のレイアウトに使うと行の View が再利用されるのでこういう状況によくなります。

正しく動くようにするには、 if(isChecked) { ctv.setCheckMarkDrawable(R.drawable.check); } else { ctv.setCheckMarkDrawable(0); } のように null ではなく 0 を渡すようにします。

CheckedTextView のコードをみると、setCheckMarkDrawable(int resid) では、mCheckMarkResource にセットされたリソースID を保持しておいて、新しくセットされたリソースIDがこれと同じ場合はなにも処理をしないようになっています。

http://tools.oesf.biz/android-4.1.2_r1.0/xref/frameworks/base/core/java/android/widget/CheckedTextView.java 112 public void setCheckMarkDrawable(int resid) { 113 if (resid != 0 && resid == mCheckMarkResource) { 114 return; 115 } 116 117 mCheckMarkResource = resid; 118 119 Drawable d = null; 120 if (mCheckMarkResource != 0) { 121 d = getResources().getDrawable(mCheckMarkResource); 122 } 123 setCheckMarkDrawable(d); 124 } 125 126 /** 127 * Set the checkmark to a given Drawable. This will be drawn when {@link #isChecked()} is true. 128 * 129 * @param d The Drawable to use for the checkmark. 130 * 131 * @see #setCheckMarkDrawable(int) 132 * @see #getCheckMarkDrawable() 133 * 134 * @attr ref android.R.styleable#CheckedTextView_checkMark 135 */ 136 public void setCheckMarkDrawable(Drawable d) { 137 if (mCheckMarkDrawable != null) { 138 mCheckMarkDrawable.setCallback(null); 139 unscheduleDrawable(mCheckMarkDrawable); 140 } 141 mNeedRequestlayout = (d != mCheckMarkDrawable); 142 if (d != null) { 143 d.setCallback(this); 144 d.setVisible(getVisibility() == VISIBLE, false); 145 d.setState(CHECKED_STATE_SET); 146 setMinHeight(d.getIntrinsicHeight()); 147 148 mCheckMarkWidth = d.getIntrinsicWidth(); 149 d.setState(getDrawableState()); 150 } else { 151 mCheckMarkWidth = 0; 152 } 153 mCheckMarkDrawable = d; 154 // Do padding resolution. This will call setPadding() and do a requestLayout() if needed. 155 resolvePadding(); 156 }

つまり、
setCheckMarkDrawable(R.drawable.check)
: mCheckMarkResource = R.drawable.check

setCheckMarkDrawable(null)
: setCheckMarkDrawable(int resid) を通らないので mCheckMarkResource = R.drawable.check のまま

setCheckMarkDrawable(R.drawable.check) ←ここ
:mCheckMarkResource が引数の resid と同じなので画像をセットしない = 画像は null のまま

という動作になってしまうのです。。。


2012年12月3日月曜日

いきなり jquery 使い始める前に DOM のことちゃんと理解しようね。

ちょっと古い本ですがすごくよかったので紹介します。

「標準 DOM スクリプティング」 羽田野太巳



もう、さすが羽田野さんというしかないです。
こんなわかりやすい日本語が書けるようになりたい。。。

1.1 が「DOMとは」ですよ。
DOM の歴史、概要、仕様など基礎がしっかり抑えられます。

2007年の本なので、出てくるブラウザが IE6、Firefox 1.5、Opera 9.0、Safari 1.3 と 2.0、と古いですが(Chrome がない!)、新しいブラウザはより DOM に準拠しているはずなので、参考になると思います。
なんでみんな IE6 が嫌いなのかこの本を読むとよくわかりますw

個人的にはごっちゃになってた DHTML と DOM がきちんと整理できたで助かりました。


もちろんクロスブラウザ対策についての話も随所で取り上げられていて、

対策コード部分をモジュール化して使い回したいよね

ライブラリとしてみんなで使えれば便利だよね

jquery

という流れがちゃんと理解できて jquery を使うのと、よくわからないけど便利らしいから使うかー、では大違いです。
よくわからないままにライブラリを使うと、困った事が起こったときに原因が突き止められないなどいろいろ大変なことになります。

基礎知識大事!


最新のブラウザの対応状況を追記した改訂版でないかなぁ



2012年12月2日日曜日

TypeScript でタグ属性値の操作

helloworld2.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>hello world 2</title> <style type="text/css"> #box { width: 150px; height: 150px; border: 1px solid #4c4c4c; } .red { background-color: #ffcccc; } .blue { background-color: #ccccff;} </style> </head> <body> <h1>Hello World 2</h1> <div id="box"> Hello World 2 </div> <img id="shape" src="circle.png"></img> <br /> <br /> <input type="button" value="get attributes" id="button1"> <script src="helloworld2.js"></script> </body> </html>

helloworld2.ts function boxOver(e : MouseEvent) { box.className = "red"; } function boxNormal(e : MouseEvent) { box.className = "blue"; } function shapeOver(e : MouseEvent) { image.src = "star.png"; } function shapeNormal(e : MouseEvent) { image.src = "circle.png"; } function getAttributes(e : MouseEvent) { var attrs : Attr[] = box.attributes; var msg = ""; for(var i = 0; i < attrs.length; i++) { var attr = attrs[i]; msg = msg + attr.nodeName + ":" + attr.nodeValue + "\n"; } alert(msg); } var box : HTMLElement = document.getElementById("box"); box.addEventListener("mouseover", boxOver, false); box.addEventListener("mouseout", boxNormal, false); var image : HTMLImageElement = <HTMLImageElement>document.getElementById("shape") image.addEventListener("mouseover", shapeOver, false); image.addEventListener("mouseout", shapeNormal, false); var btn1 : HTMLElement = document.getElementById("button1"); btn1.addEventListener("click", getAttributes, false);

HTMLElement の attributes は Attr[] という配列になる。

TypeScript で DOM 操作

helloworld1.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>hello world 1</title> </head> <body> <h1>Hello World 1</h1> <input type="button" id="button1" value="pick h1 tag text" /> <br /> <br /> <div id="authors"> <div>芥川 竜之介</div> <div>夏目 漱石</div> <div></div> <div>江戸川 乱歩</div> </div> <input type="button" id="button2" value="pick all authors" /> <script src="helloworld1.js"></script> </body> </html>

helloworld1.ts function helloworld1(e : MouseEvent) { var h1Elm : Node = document.getElementsByTagName('h1')[0]; var textNode : Node = h1Elm.childNodes[0]; var text : string = textNode.nodeValue; alert(text); } function helloworld2(e : MouseEvent) { var authorsElem : Node = document.getElementById('authors'); var authors = new Array(); for (var i = 0; i < authorsElem.childNodes.length; i++) { var node = authorsElem.childNodes.item(i); if(node.nodeType != 1) { continue; } if(!node.hasChildNodes()) { continue; } if(node.firstChild.nodeType != 3) { continue; } authors.push(node.firstChild.nodeValue); } alert(authors.join("\n")); } var btn1 : HTMLElement = document.getElementById("button1"); btn1.addEventListener("click", helloworld1, false); var btn2 : HTMLElement = document.getElementById("button2"); btn2.addEventListener("click", helloworld2, false);
ノードの種類nodeTypenodeNamenodeValue
要素ノード1タグ名null
属性ノード2属性名属性値
テキストノード3#textテキストの内容
コメントノード8#commentコメントの内容
ドキュメントノード9#documentnull

2012年11月28日水曜日

Sublime Text 2 でファイル保存時に自動でビルドさせる

Sublime Plugin を作ってくれている人がいました。
https://github.com/alexnj/SublimeOnSaveBuild

とりあえずは git clone していれてみる。

git clone https://github.com/alexnj/SublimeOnSaveBuild.git

できた SublimeOnSaveBuild フォルダを Sublime Text 2 のパッケージディレクトリ([Preferences] → [Browse Packages...])にコピー。

そうすると
[Preferences] → [Package Settings] → [SublimeOnSaveBuild]
ができる



ここの [Settings - Default] をみると次のようになっている

{ "filename_filter": "\\.(css|js|sass|less|scss)$", "build_on_save": 1 } build_on_save は 1 のとき、保存時に自動でビルドする。
filename_filter は保存時にビルドを走らせるかどうか判断するファイル名の正規表現。

デフォルトでは .ts がないですね。
TypeScript (.ts ファイル)でも保存時にビルドさせたいので [Settings - User] を作ります。
(注:[Settings -Default] は変更してはいけません)

[Preferences] → [Package Settings] → [SublimeOnSaveBuild] → [Settings - User] を選択肢し、以下を書いて保存する。

{ "filename_filter": "\\.(ts|css|js|sass|less|scss)$", "build_on_save": 1 }

わーい Ctrl (Command) + B でビルドも走るようになったー!


Sublime Package Control からもインストールできるそうです。


2012年11月27日火曜日

Sublime Text 2 で TypeScript をビルドする

Sublime Text 2 に TypeScript の Build System を作ります。

[Tools] → [Build System] → [New Build System...]

TypeScript.build-system という名前で以下を保存
(パッケージフォルダのしたの User/ の保存される)

{ "cmd": ["tsc","$file"], "file_regex": "(.*\\.ts?)\\s\\(([0-9]+)\\,([0-9]+)\\)\\:\\s(...*?)$", "selector": "source.ts", "osx": { "path": "/usr/local/bin:/opt/local/bin" }, "linux": { "path": "/usr/local/bin:/usr/bin" } } TypeScript でのビルドを明示したいなら、[Tools] → [Build System] → [TypeScript] を選択する。
Auto のままでも拡張子が .ts なら TypeScript でビルドされる。

[Tools] → [Build] もしくは Ctrl (Mac は Command) + B でビルド



var を ver とタイポしたときのエラー表示



file_regex は tsc のエラーの正規表現にする。



解説は以下↓


Build Systems

Sublime Text には、外部のプログラムにファイルをかませる機能があります。

独自の Build System を作るには以下のステップを行います。
  • オプション : 外部の実行可能ファイル(スクリプトやバイナリファイル)を用意する
  • .sublime-build という拡張子の設定ファイル(JSON 形式で記述する)を用意する
  • ビルドを開始する Sublime Text のコマンドを用意する
デフォルトでは build systems は Packages/Default/exec.py に実装されている exec コマンドを使います。このコマンドをオーバーライドすることができます。

.build-system ファイルの例 { "cmd": ["python", "-u", "$file"], "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)", "selector": "source.python" }

オプション
  • cmd
    実行するコマンドと必要な引数が入った配列。
    フルパスを指定しなかった場合、システムの環境変数 PATH から外部のプログラムが検索される。

  • file_regex
    オプション。
    cmd のエラー出力をキャプチャするための正規表現。

  • line_regex
    オプション。
    もし file_regex が現在のラインとマッチせず、line_regex が存在して現在のラインとマッチするなら、file_regex とマッチするラインが見つかるまでバッファ使って遡り、これら2つのマッチを使って進むべきファイルとラインを決定する

  • selector
    オプション。
    [Tools] → [Build System] → [Automatic] が true にセットされているときに利用される。
    Sublime Text はアクティブな View 用の適切な build system を見つけるためにこのスコープセレクターを使う。

  • working_dir
    オプション。
    cmd を走らせる前に変更するカレントディレクトリとして変更するディレクトリ。
    元のカレントディレクトリは後でリストアされる。

  • encoding
    オプション。
    cmd の出力エンコーディング。有効な python エンコーディングでなければならない。デフォルトは UTF-8。

  • target
    オプション。
    実行する Sublime Text コマンド。デフォルトは exec (Packages/Default/exec.py)。

  • env
    オプション。
    現在のプロセスの環境変数が cmd に渡されるまえに、現在のプロセスの環境変数にマージされる環境変数の Dictonary。

  • shell
    オプション。
    true の場合、cmd は shell を介して実行される。

  • path
    オプション。
    cmd が呼ばれる前に、現在のプロセスの PATH がこの文字列に置き換わる。
    元の PATH の値は後でリストアされる。

  • variants
    オプション。
    メインの build system のオプションを上書きするオプションの Dictionary のリスト。

  • name
    variants の内部でだけ有効。
    variant build system を識別する。
    name が Run の場合、variant は Tools | Build System メユーの下に表示され、Ctrl + Shift + B がバインドされる。


プラットフォーム独自のオプション
  • windows
  • osx
  • linux
{ "cmd": ["ant"], "file_regex": "^ *\\[javac\\] (.+):([0-9]+):() (.*)$", "working_dir": "${project_path:${folder}}", "selector": "source.java", "windows": { "cmd": ["ant.bat"] } }

Variants

{ "selector": "source.python", "cmd": ["date"], "variants": [ { "cmd": ["ls -l *.py"], "name": "List Python Files", "shell": true }, { "cmd": ["wc", "$file"], "name": "Word Count (current file)" }, { "cmd": ["python", "-u", "$file"], "name": "Run" } ] }

Build System の変数
  • $file_path
    現在のファイルのディレクトリ 例) /Files/
  • $file
    現在のファイルのフルパス 例)/Files/File.txt
  • $file_name
    現在のファイルの名前 例) File.txt
  • $file_extension
    現在のファイルの拡張子 例) .txt
  • $file_base_name
    現在のファイルの名前部分 例) File.
  • $packages
    パッケージフォルダへのフルパス
  • $project
    現在のプロジェクトファイルへのフルパス
  • $project_path
    現在のプロジエクとファイルのディレクトリ
  • $project_name
    現在のプロジェクトファイルの名前
  • $project_extension
    現在のプロジェクトファイルの拡張子
  • $project_base_name
    現在のプロジェクトファイルの名前部分


Build System を実行する

[Tools] → [Build System] から実行したい build system を選択して、[Tools] → [Build] を選択するか Ctrl (Command) + B を押す。



Sublime Text 2 に TypeScript の syntax highlighting を入れる

Interoperability @ Microsoft MSDN Blogs - Sublime Text, Vi, Emacs: TypeScript enabled!
で Sublime Text のアイコンをクリックして zip ファイルをダウンロード

展開すると
  • README-sublime-typescript.txt
  • typescript.tmLanguage
が得られる

Sublime Text の syntax highlighting の作り方は
http://docs.sublimetext.info/en/latest/extensibility/syntaxdefs.html
にあり、自分で作成する場合は以下のようにするが、

JSON 形式で記述
 ↓
.tmLanguage ファイル(XML形式)に変換する

上記のエントリでは .tmLanguage の状態のものを提供しているので、Sublime Text を起動して [Preferences] - [Browse Package...] で開くフォルダ(私の場合(Ubuntu)は ~/.config/sublime-text-2/ だった)に TypeScript フォルダを作成し、そのなかに typescript.tmLanguage ファイルをコピーして Sublime Text を再起動すれば OK.


2012年11月22日木曜日

Ubuntu に Sublime Text 2 をインストールした

Sublime Text 2 の Ubuntu 用 PPA みつけた

WEB UPD8 - SUBLIME TEXT 2 UBUNTU PPA
> sudo add-apt-repository ppa:webupd8team/sublime-text-2
> sudo apt-get update

> sudo apt-get install sublime-text


> sublime-text -h
Sublime Text 2 Build 2217

Usage: sublime_text [arguments] [files]         edit the given files
   or: sublime_text [arguments] [directories]   open the given directories

Arguments:
  --project : Load the given project
  --command : Run the given command
  -n or --new-window:  Open a new window
  -a or --add:         Add folders to the current window
  -w or --wait:        Wait for the files to be closed before returning
  -b or --background:  Don't activate the application
  -h or --help:        Show help (this message) and exit
  -v or --version:     Show version and exit

Filenames may be given a :line or :line:column suffix to open at a specific
location.

> sublime-text -v
Sublime Text 2 Build 2217
-v でビルド番号はでるが、バージョンはでないのか。。。

2012年11月21日水曜日

Ubuntu に Typescript をインストールした

Synaptic Package Manager で
  • npm
  • nodejs
をインストール

> npm install -g typescript
すると
npm ERR! couldn't read package.json in .
npm ERR! Error installing .
npm ERR! Error: ENOENT, No such file or directory 'package.json'
npm ERR! Report this *entire* log at 
npm ERR! or email it to 
npm ERR! Just tweeting a tiny part of the error will not be helpful.
npm not ok

と言われる。

どうもインストールした npm のバージョンが古かったようだ

github : isaacs / npm - couldn't read package.json in .

1.x をインストールしないといけないらしい
Synaptic から入れた node.js も古かった

ということで node.js と npm を一旦アンインストールし、コメントの最後のほうで isaacs さんが紹介している https://launchpad.net/~chris-lea/+archive/node.js/ からインストール

そのためにまず ppa:chris-lea/node.js を PPA(Personal Package Archive) に追加

> sudo add-apt-repository ppa:chris-lea/node.js

You are about to add the following PPA to your system:
 node.js
 Evented I/O for V8 javascript. Node's goal is to provide an easy way to build scalable network programs
 More info: https://launchpad.net/~chris-lea/+archive/node.js
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keyring `/tmp/tmpIBxqM3/secring.gpg' created
gpg: keyring `/tmp/tmpIBxqM3/pubring.gpg' created
gpg: requesting key C7917B12 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmpIBxqM3/trustdb.gpg: trustdb created
gpg: key C7917B12: public key "Launchpad chrislea" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK

> sudo apt-get update
次に node.js と npm をインストール

> sudo apt-get install nodejs
> sudo apt-get install npm

> npm -v
1.1.65
よしよし

ようやく

>  npm install -g typescript
npm http GET https://registry.npmjs.org/typescript
npm http 200 https://registry.npmjs.org/typescript
npm http GET https://registry.npmjs.org/typescript/-/typescript-0.8.1.tgz
npm http 200 https://registry.npmjs.org/typescript/-/typescript-0.8.1.tgz
npm ERR! Error: EACCES, mkdir '/usr/lib/node_modules'
...
キターとおもったらエラー orz

> sudo npm install -g typescript
npm http GET https://registry.npmjs.org/typescript
npm http 304 https://registry.npmjs.org/typescript
/usr/bin/tsc -> /usr/lib/node_modules/typescript/bin/tsc
typescript@0.8.1 /usr/lib/node_modules/typescript
はいったぽい?

Tutorial のコードを書いて

> cat greeter.ts 
function greeter(person) {
    return "Hello, " + person;
}

var user = "Jane User";

document.body.innerHTML = greeter(user);

> tsc greeter.ts 
怒られなかったー

> ls
greeter.js  greeter.ts
js ファイルできてるー



2012年11月20日火曜日

Simple でいつづけるには強い意志と努力が必要だ。エントロピーに逆らわないといけないからね。

「Think Simple」読んだのでその感想とか。

著者のケン・シーガルさんはアップルの広告代理店としてさまざまな広告やキャンペーンを担当された方です。

事例集というか、ある意味ジョブズの伝記として読み物として面白い。
ただし、言いたい事は Conclusion にまとまっているので、要点を抑えたいだけならそれを読めば十分ではある。
あるが、読み物として面白い。


・Think Brutal 容赦なく伝える

お互いオブラートに包んだ物言いで、相手の真意を推測しあうのは無駄。
チーム内で思った事は率直に伝えよ。

(私はお世辞が苦手というか言えない人です。空気もあんまり読めないし、気を使うのも苦手です。メールに本件と関係ない挨拶を入れるのも嫌いです。この項目はクリアしてるはず)


・Think Small 少人数で取り組む

- ただの少人数ではなく、有能な少人数のグループで取り組む。

(本書のなかでジョブズは会議に参加していた女性に「君は誰だ?」といい、議論する予定のプロジェクトに関わっているので参加するように言われました、と答えた女性に「この会議に君は必要ない、ご苦労様。」と言ったわけだが、参加者自身が必要と思っているならまだしも「オレこの会議に出る必要なくない?」と思いながら参加させれられている会議ほど無意味なものはないわけです。
後々関わるかも、利害関係的に参加させないとあとでうるさい、などの理由で参加者が決まっているようではやばいってことですよね。)

プロジェクトの成果の質は、そこにかかわる人間の多さに反比例する

- 最終的な意思決定者がちゃんとした形で参加しないプロジェクトは何であれ疑ってかかれ。

(意思決定者が最後の最後にふらっときてイエスかノーかをいうだけなら、イエスを言われるように無難で(欠点はないが尖ってもいない)平凡な結果になるだけ)

プロジェクトの成果の質は、最終的な意思決定者がかかわる程度に比例する


・Think Minimal ミニマルに徹する

大量の選択肢は選択肢がないことと同じだ。

(本書では、ジョブズがアップルに復帰したときにコンピュータのモデルを膨大な数から 2x2 の 4種類にしぼったことを取り上げており、対比としてデルの製品ラインナップ数の多さに言及している。一度増えた製品ラインナップを減らすのはなかなか難しいことだと思う。最近のスマホの機種数爆発はすごいですね。HTC とか Xperia とかありすぎて私にはもうなにがなんだかわかりません。)


・Think Motion 動かし続ける

偉大なことをなし遂げるには、ふたつのことが必要だ。計画と、十分ではない時間だ。

(もたもたすんな、さっさとやれ。余計なプロセスを増やすな。)

プロジェクトでは、少し時間が足りないのが理想的なスケジュールだ。


・Think Iconic イメージを利用する

(ジョブズが復帰してから iMac を発表するまでの間に行われた「Think different」キャンペーンについて取り上げている。まだ(復帰してから)なにも製品を出していないし倒産寸前だったのに、ブランド確立キャンペーンを行った(つまり投資をした)のは普通に考えればクレイジーである。p137 の「ジョブズの考えるマーケティングとは」は一読する価値あり。)


・Think Phrasal フレーズを決める

(iMac の命名についての話。著者は iMac の名付け親。ジョブズは最初マックマン(MacMan)を推していた。製品やその製品の機能とは全く関係ない中二病みたいな名前じゃなくて、もっとわかりやすい名前にしろよということ、例外は「ドロイド」だそうだ。)

「汝、隣人のマーケティングを望むなかれ」

(ファイナルカット・スタジオ2をリリースするときに、Adobe のようにさまざまなエディションを用意したほうがいいと提案したプロジェクトメンバーの1人をジョブズが一刀両断する話。)

多くのライターは意識したことがないようだが、知的な言葉を使ったからといって、かならずしもその人が賢く見えるわけではない。人や会社をスマートに見せる最良の方法は、完璧な明快さでアイデアをシンプルに表現することだ。

(わかりやすく説明するのはすごく大変だけど、その価値はある)


・Think Casual カジュアルに話しあう

(ジョブズが新しいプランナーのプレゼンテーションに対して怒った話。そもそもプランナーに Apple のブランド監査をさせたという事自体が、大手広告代理店のスタイルを重視するふるまいであり、そういう代理店をジョブズが嫌っていたから怒った。プランナーのプレゼンテーションがいまいちだったというのもあるだろう。3つの文章でいえることを20枚のスライドで見せられたらジョブズじゃなくてもうんざりすると思う。)


・Think Human 人間を中心にする

そもそもアップルが成功してきたのは、人間の価値観を反映する製品を作っているからだ。

(iMovie の CM の話とか、NeXT の話とか、スタンフォード大学の卒業式でのスピーチの話とか)

ジョブズの3つの挫折
・アップルを追い出されたこと
・NeXT で成功を収められなかったこと
・自分の死に直面したこと

「死は人生が生みだした唯一にして最上の創造物だと思われるからです。それは人生に変化をもたらす因子です。死は古いものを一掃して新しいものへの道をひらいてくれるのです。」
by スタンフォード大学の卒業式でのスピーチ

(本当に余命宣告される状況にならないとなかなか意識するのは難しい。。。)


・Think Skeptic 不可能を疑う

同僚や取引先がノーと言ったときに、あなたは額面どおりに受けとらないほうがいい。かなりの場合でそれは、非常な努力が必要か、いつものやり方と違うか、とてもコストがかかる、といった意味にすぎない。

「他人の意見によって、自分の内なる声を溺れさせてはならない。何よりも大切なのは、自分の気持ちや直感に従って行動する勇気を持つ事です。」
by スタンフォード大学の卒業式でのスピーチ

(アップルストアを作るときの話とか)


・Think War 戦いを挑む

(いろんなところに喧嘩を売る話。ライバル(インテルだったりマイクロソフトだったり Windows を搭載した PC だったり)を揶揄した広告とか CM とか。)



あんまり広告詳しくないので、本書で出てきた CM の youtube のリンクを貼ってみます。

「1984年」

「Think different」



ナレーションはリチャード・ドレイファスだが、じつはジョブズのナレーションも当時録音してあった。


「Mac とパソコン」

Mac と PC を擬人化した CM あったわー。
全部の種類覚えているわけじゃないけど。



あ、ラーメンズさんが芸人だって知りませんでした。
アメリカの CM では二人とも俳優さんだったみたいです。


「iPod の CM」

最初の iPod の CM はシルエットじゃなかったため、踊ってる青年がすごいマヌケに見えるということで、ウェブでは「iClod」(マヌケ)なコマーシャルと評されることもあったそうだ。









2012年11月18日日曜日

Android ループできる ViewPager (完全版)作った

LoopViewPager

github : yanzm/LoopViewPager - https://github.com/yanzm/LoopViewPager

ループできる ViewPager です。
(Loop ViewPager, Looping ViewPager)

以前に How to create looping ViewPager というエントリーを書きましたが、不完全だったので、まともなものを作りました。

今回は制限なしです。
Support Package v4 の ViewPager の代わりに使うだけで OK です。
ViewPager から PagerAdapter の package private なメソッドを呼んでいるので、PagerAdapter, FragmentPagerAdapter, FragmentStatePagerAdapter は LoopViewPager と同じパッケージにあるやつを使ってください。

r11 の Suppor Pakcage v4 の ViewPager のコードをベースに変更しています。
PagerAdapter を継承したアダプターの使い方は今まで通りです。

使い方 <com.uphyca.android.loopviewpager.LoopViewPager xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" /> public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); LoopViewPager pager = (LoopViewPager) findViewById(R.id.pager); pager.setAdapter(new MyFragmentStatePagerAdapter(getFragmentManager())); pager.setAdapter(new MyPagerAdapter()); } class MyFragmentStatePagerAdapter extends FragmentStatePagerAdapter { public MyFragmentStatePagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return SimpleFragment.newInstance(position); } @Override public int getCount() { return 10; } } }

2012年11月13日火曜日

「よりよいコードを求めて命名について頭をひねる会」のログ

http://www.zusaar.com/event/438105

アプリケーションを作る英語 の著者の西野さんを交えて、クラス名とかメソッド名とか変数名とか命名で困っている課題を1つ以上持ち寄りみんなで一緒に検討する勉強会をしました。

「アプリケーションを作る英語」
電子書籍 http://tatsu-zine.com/books/english4app
http://www.amazon.co.jp/gp/product/4844332848/


はじめに:西野さんからちょっとお話

The Art of Readable Code から第2章と第3章

第2章:名前に情報を詰め込むようにする
どういう情報をつめこむか。
明確な言葉を選ぶ
get は不明確らしい

getPage(url) -> FetchPage(url) や DownloadPage(url)

特色のある(colorful)な言葉を選ぶ
・類語辞典を活用
・いろんなふうに解釈される単語よりも、その意味にしかとれない単語を使う
send -> deliver, dispatch

英語のテクニカルライティング
strong verb を使う(反対は weak verb)

汎用的な名前は避ける

retval だけとか tmp だけとかは良くない
(tmp は本当に短期間だけ使う場合以外は使ってはダメ)

具体的な名前をつける
ServerCanStart() -> CanListenOnPort()

名前に情報を追加する
(名前が長くなりすぎる場合はどうしたらいいのかな?)

・単位のついた値
limit -> max_kbps
angle -> degrees_cw

他の重要な情報を盛り込む
password -> plaintext_password
comment -> unescaped_comment
html -> html_utf8
data -> data_urlenc

頭字語と略語
・プロジェクト特有の略語は良くない
・新加入のチームメンバーがわかるかどうかで略語の使用を判断する

不要な言葉を削除する
ConvertToString() -> ToString()
(メソッドの最初は動詞にしろという、話もあり、、、)

名前の書式で意味を伝える
・アンダースコア、ハイフン、大文字小文字で名前に意味を持たせられる
例 CamelCase, lower_separated, UPPER_CASE


第3章:誤解されない名前をつける

「この名前が別の意味で理解されることはないだろうか?」

filter では、含めるのか除外するのかわかりにくい
select や exclude の方がよい

限界値と範囲の表現(まよったときはこっちがいい)

・max/min : 対象は含む
・first/last: 対象は含む

・begin/end: begin は含むが、end は含まない
未満みたいな英語がないので、end をそういう意味に使おうという著者の提案
(less 〜のようなのはどうなの?)

ブール値の名前
・is, has, can, should など
(is の後が名詞のものは作りやすいが、動詞?助動詞?のときにちょっと悩む)

(誤解されなければ前置詞はなくてもいい?)

使う人の期待に沿う
「get」は軽いアクセサと考える人が多い
getMean() -> すでに計算したものを返すイメージ
computeMean() -> 今からたくさん計算するイメージ
(これはボキャブラリがいるなー)

- get に時間かかるのは想定してない
(即時、副作用があって欲しくない)

i,j,k は許すべきかどうか(forループ)
(for が入れ子になっている場合は i_hoge とかにしたほうがいいらしい)
多重のループをかくとバグを生みやすい

Iteratorを使えばループカウンタによるバグを減らせる
ただし、ループカウンタがほしくなることはある
イテレーターからカウンタが欲しくなることはたまーにある by zaki


作業する場合は動詞からにしてほしい
名詞から始めてもしっくりくるかどうか
ToString は失敗例じゃない? by amedama

getStringValue() の get を省略したがの Obje-C の StringValue() らしい

本の文はここまで


コード補間があるので、長めにしても問題ない
・名前付き引数に追い出す?
・長すぎるメソッド名はdisられるけど、短すぎて情報量が少ないのも困る
・5、6単語くらいまで?



シソーラス
Thesaurus.com http://thesaurus.com
同意語(synonym)と反意語(antonym)が豊富(だが難しい)

Macmillan http://www.macmillandictionary.com/
英語圏で定評ある辞書(だが難しい)

日本語
Weblio英語類語辞典 http://ejje.weblio.jp/english-thesaurus/
日本語で探せるので便利(だがエントリが変な部分も)


一般的な類語辞典は多い
コンピュータ関連の本:「科学技術英語 動詞はこう使え!」
関数やメソッドの命名で役にたちそう

類語辞典以外の方法
大きめの英和辞典では類語の違いを解説していることがある
オンラインであれば Weblio -> コンピュータ関連辞書(研究社 英和コンピュータ用語辞典、マイクロソフト用語集

Mac には最初からわりといい辞書が入っている by muo

英英辞典(言葉の意味を調べるにはいい)

new TOPGATE office なのか TOPGATE new office なのか
かかるものの直前につけたほうがいい
TOPGATE's new office


命名を変えるのもリファクタリング
リファクタリングにはテストも含まれる


フレームワークを作るとき、ライブラリを作るとき、公開されないメソッドを作る時で意識を変える by muo

API として公開しているかどうか、補間しやすいかどうか、レビューされる by zaki
API を作る段階でインタフェースだけ定義して、コード書くときに補間でしぼれるかどうかとかレビューする by zaki

クラス名、インタフェース名、似たようなクラスがあると絞りづらい by zaki

BaseHoge だと Base でいろいろ出てきちゃうので HogeBase にしたい
だいたい3文字(キャメル頭文字)にしたい by vvakame

パッケージ名は可視性に使って、名前のコリジョンには使わない by vvakame

いろんなパッケージに BaseAdapter があるより socket パッケージのは SocketBaseAdapter のほうがいい by vvakame, zaki

socket パッケージにあるのに Socket がつくのは冗長じゃない? by amedama

vvakame は書くほう(書くとき)のタイプ数が少ないほうがいい
SocketBaseAdapter は Socket は冗長と思わない、これが冗長になるなら API の設計が変なんじゃない? by vvakame

IDEのクセに依存しそう

Java は Eclipse に最適化されすぎw by amedama

Server side と Client side で違う言語(ruby と Java とか)
の場合にどうしたらいいのか(?)的なやつに関連するもの
https://github.com/ServiceStack/ServiceStack

JSON とかでつながるくらにしておいたほうがいいんじゃない? by muo



---

「リスナーを登録するメソッドについて」 by esmasui
addListener(), registerListener()
add と register の使い分けがわからない

英語的な意味で

addListener <--> removeListener
registerListener <--> unregisterListener

register は紙にかくイメージ by amedama
register は1個、Listener が複数の場合は add
set は登録するイメージがない by amedama
set のときは1個のイメージ

add というと後ろにコレクションがあって複数追加できるイメージ by zaki
append だとくっついて1個のリスナーになってしまうイメージ

1個 -> setListener
複数 -> addListener
register はなんかエラそう by itog
システムに登録するようなアプリ全体のなにかに登録する場合は register


---

なになにのために〜する
例: updateForGame()
updateGame(Game game)
ゲームをアップデートするのではなく、自分がアップデートする?

そもそもゲームをアップデートするわけではない -> uploadGame(Game game) では?

こういうのを多用しているんだけど、これでいいのかな?

vvakame update For Game? -> わかめがアップデートする

update は他動詞のみ

syncGameStatus() とか by amedama
update だと漠然としている。もっと特定の用途を表すメソッドを使うべきでは。

結論は...
自動詞か他動詞か調べよう!
他動詞の場合は、動詞+目的語(目的語) の形がよいのでは
update は抽象的なので、もっとあいまいじゃない動詞を使おう!

for が入る文を調べたかったら英辞郎とかでワイルドカードを使って、for と組み合わせて検索するのがいいのでは by nishinos
英辞郎で "update for {1}" で検索するなど


----

ここからはファンタジー

SnoreEvent というクラス名はありか?

そもそもこれイベントとなの? by corosuke

よくあるのはEventListenerに登録するときのイベント名によくつかうよね by zaki

「命名で悩んでいる場合、APIの設計がうまくないことがよくある」 by muo

これだけで使い方わかるからいいんじゃない? by amedama
WakeUpEvent と AwakeEvent があって AwakeEvent はいつ呼ばれるの?

ファンタジー終わり


---

チームでのさじ加減むずい by muo

プログラミングについても英語についても共通認識をどこに設定したらいいのか
(さっきいろいろ聞いたので、、、)

G社さんはレビューでチェックしている。常識に外れない程度になっている。
新しい API を作るときは全体の整合性を保つようにチェックする機関がある(らしい?)
コーディングのスタイルガイドがある
https://www.google.co.jp/search?q=google+coding+conventions&aq=1&oq=google+coding+c&sugexp=chrome,mod=1&sourceid=chrome&ie=UTF-8&qscrl=1

google coding conventions などでググれ

http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml


---

コミットログの書き方に悩んでいます by vvakame

なぜそうしたのか、というのを長々と書きたい時に英語力が低いので、
どういうことを書いたほうがいいのかわからない。
自分の中では合理的な理由があるんだけど、日本語ならかけるけど英語だとうまく書けない

箇条書きにしてみてはどう? by nishinos

英語でCommitを書こう
https://speakerdeck.com/pwim/ying-yu-dekomitutowoshu-kou
がよかったよ by muo

コミットが主語になる
(This commit) add...
(This commit) change...

過去形がいいんじゃない派
コミットログのサマリーをとって、バージョンの change log に使えるじゃん

(This commit) added...
(This commit) changed...

進行形で書かれてることがあった、進行形はやめようよ by itog

動名詞もあると思うけどw by amedama


----

isHogeHoge() と canHogeHoge() どっちがわかりやすい? by sobachanko

isAccessible() と canRead() とか
どっちがいいの?どっちも bool が返ってくる。

一般的な英語としてはどっちでもいいと思う。
より口語的なのは can の方。どっちを多くつかっているかによるのでは? by nishinos

The file can read
は英語的にあり(read には読み取れるという意味の自動詞がある)
http://ejje.weblio.jp/content/read
write にも自動詞がある

英語として気持ちいいほうにするか、
既存の API に沿うか
→ プロジェクトでどっちかに統一したほうがいいのでは

File クラスとして
isReadable() と canRead() だったらどっちがいい?


---

語彙を増やす方法がしりたい by zaki

英語力を高める感じ
手っ取り早くだったら、辞書で類語をあたってみるとか

日本で書いてるとカラフル過ぎても伝わらない場合がある
computeMean() の Mean の意味を平均と受け取ってくれない(意味と理解する)ことがある by muo

Chrome のタブの機能が便利

英辞郎はたまにあやしいことがある by nishinos


---

Java のパッケージ名と配下の名前のつけ方 by fkm

何かのオブジェクトの集合体で HogeManager みたいなのを
作りたいときに Manager が曖昧なので他にいい名前ないですかね?

HogeManager がたくさん出てくるのはよくない兆候らしいよ by zaki
(HogeHandler, HogeController とかも)

何かを管理するクラスなら Manager でもいいんじゃない? by vvakame

Manager クラスを分解しないと別の名前にできないんじゃない? by amedama

結論:
いろんな機能を1個のクラスに突っ込んでとりあえず HogeManager はよくない
苦し紛れなら設計を見直すべし
Manager として適切(何かを管理してる?)ならそれもいいんじゃない

データベースとかで読み書きの担当とか排他処理をするのは Manager だと思う by itog


---

登録ボタンに register て付けたいときに長くなったので省略したい
省略してはいけないところといいところはあるのか?

本当は文字を小さくするなどして省略しないほうがいい
昔の文章だと、単語のどこで区切っていいか( - でつなげるところ)は決まっている by nishinos
辞書などでは・で区切っている by zaki

基本的には省略語を使わないほうがいい。
曜日や月の名前もどうしてもスペースが足りない時だけ省略を使う by nishinos

翻訳すると長くなる可能性がどうしてもあるので、アイコンを丁寧につくるのがいい by amedama

国際的に共通化されているアイコンが決まっている
どの程度共通認識が国際的にあるかのレベルがある by amedama

Intel のまとめがあるらしい(?) by zaki


---

自動詞と他動詞の使いかた by yanzm

moveCar() と moveToCar()

class vvakame

vvakame.moveCar()
vvakame.move(Car c)

わかめが車を動かす

vvakame.moveToCar()
vvakame.moveTo(Car c)

わかめが車のところまで移動する

clipRect()
clip()
clipTo()

go と come の使い方
I'm coming とか

run など自動詞と他動詞で意味が変わる単語もあるので要注意 by nishinos


---

sign in みたいな過去形にしにくい単語をどうしたらいいのか by mainyaa

幹になるほうの単語を過去形にするのが一般的
signed in とか by nishinos

一語になってる場合は辞書をみよう!

結論:辞書は友達


---

Android でレイアウトのID名に悩む @itog

結論: XML にコメント書こう!


---

命名の妥協点 by leibun

C言語を書いてます
関数名を決めるのに時間かかってしまう
みんなどこで妥協してるの?

名前と設計は別個に考えられないのでは? by itog
インターナル(public と private の private)なら簡単に決めていいんじゃない? by muo


---

メソッド名に引数名を含ませたい場合前置詞や接続詞ってどうしたらいいの? @corosuke

どの前置詞が自然かというのは、辞書や Google で検索してどういうのが多いのか調べるのかいい by nishinos


---

会場を提供してくれた TOPGATE さんありがとう!
ピザを注文してくれたけいご君ありがとう!



2012年10月30日火曜日

数学が好きか嫌いかは解けるようになってから言え

総裁の本読みましたー。なぜか朝会社にきたらあったので。



普通に面白かったです。
ブログのまとめなので、募金の話とか懐かしかったです。
あんまり眠くならないので睡眠導入剤代わりにはならないと思います。
通勤時に電車で読むのがいいのではないでしょうか。

個人的に気に入ったのは


"僕が高校のときに読んだ数学の参考書にこう書いてありました。

「好きだからできるようになるのではない。できるようになったから好きになるのだ。」

数学の本にそう書かれると、「好きか嫌いかは、解けるようになってから言えよバーカ」という意味に取れなくもないです。"


というところです。「できるかできないかは、やってみてから言えよバーカ」というのは案ずるより産むが易しだっけ。
ちょっと違うかも。
まぁいいか。

食わず嫌いはいろいろもったいないよね。


読んだ直後にこれ書いてるので効能はわかりませんが、こないだ行った伊豆大島の温泉(塩泉)でお肌つるつるになりました。


2012年10月29日月曜日

How to create looping ViewPager

ループできる ViewPager です。ちゃんと作ってないので以下の制限があります。
  • ページ数が 3の倍数じゃないといけない(時間がなくて対応してない)
  • 連続ページ切り替え(スワイプ後のスクロールが終わる前にさらにスワイプ)に対応してない
  • わかんないけどなんかあるかも
ポイントは isViewFromObject() を駆使することと、ViewPager を extends して onLayout で位置を戻すことです。 public class MainActivity extends Activity { private ViewPager mViewPager; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mPagerAdapter = new MyPagerAdapter(this); mViewPager = (ViewPager) findViewById(R.id.viewpager); mViewPager.setOffscreenPageLimit(2); mViewPager.setAdapter(mPagerAdapter); mViewPager.setOnPageChangeListener(mPagerAdapter); mViewPager.setCurrentItem(1, false); } private MyPagerAdapter mPagerAdapter; private class MyPagerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener { /** * from 0 to 2 */ int focusedPosition = 0; /** * from 0 to PAGE_NUM -1 */ int contentPosition = 0; /** * number of pages (3x) */ int PAGE_NUM = 9; Context mContext; LayoutInflater mInflater; public MyPagerAdapter(Context context) { mContext = context; mInflater = LayoutInflater.from(context); } @Override public int getCount() { return 3; } SparseArray<View> mViews = new SparseArray<View>(); @Override public Object instantiateItem(ViewGroup container, int position) { int newPosition = calcContentPosition(position); View view = createContent(newPosition); container.addView(view, 0); mViews.put(position, view); view.setTag(position); // return view; return Integer.valueOf(position); } @Override public boolean isViewFromObject(View view, Object object) { int index = (Integer) view.getTag(); int position = (Integer) object; int newPosition = (position + contentPosition) % 3; return newPosition == index; } /** * create content's view * * @param position * from 0 to PAGE_NUM - 1 * @return */ private View createContent(int position) { View view = mInflater.inflate(R.layout.list, null, false); updateContent(view, position); return view; } /** * update content's view * * @param view * @param position * from 0 to PAGE_NUM -1 */ private void updateContent(View view, int position) { ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, android.R.layout.simple_list_item_1, createList(position)); ListView listView = (ListView) view.findViewById(R.id.list); listView.setAdapter(adapter); listView.setScrollingCacheEnabled(false); } private List<String> createList(int index) { List<String> list = new ArrayList<String>(); for (int i = 0; i < 50; i++) { list.add(index + " *************************** " + index + ":" + (i + 1)); } return list; } /** * get position of content * * @param position * from 0 to 2 * @return content position (from 0 to PAGE_NUM - 1) */ private int calcContentPosition(int position) { int offset = position - 1; int newPosition = contentPosition + offset; if (newPosition < 0) { newPosition = PAGE_NUM - 1; } else { newPosition = newPosition % PAGE_NUM; } return newPosition; } @Override public void destroyItem(ViewGroup container, int position, Object object) { int count = mViewPager.getChildCount(); int index = (Integer) object; for (int i = 0; i < count; i++) { View v = mViewPager.getChildAt(i); if (isViewFromObject(v, Integer.valueOf(index))) { container.removeView(v); break; } } } /** * update specified view's content * * @param index * 0 or 2 */ void updateContents(int index) { int count = mViewPager.getChildCount(); for (int i = 0; i < count; i++) { View v = mViewPager.getChildAt(i); if (isViewFromObject(v, Integer.valueOf(index))) { final int newPosition = calcContentPosition(index); updateContent(v, newPosition); break; } } } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { focusedPosition = position; } @Override public void onPageScrollStateChanged(int state) { if (state == ViewPager.SCROLL_STATE_IDLE) { handlePageScrollStateChangedToIdle(); } } private void handlePageScrollStateChangedToIdle() { switch (focusedPosition) { case 0: // scroll to previous page if ((--contentPosition) < 0) { contentPosition = PAGE_NUM - 1; } updateContents(0); break; case 2: // scroll to next page contentPosition = (++contentPosition) % PAGE_NUM; updateContents(2); break; default: break; } } } } public class MyViewPager extends ViewPager { public MyViewPager(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if(getCurrentItem() != 1) { setCurrentItem(1, false); } } } res/layout/main.xml <?xml version="1.0" encoding="utf-8"?> <com.sample.viewpager.MyViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" /> res/layout/list.xml <?xml version="1.0" encoding="utf-8"?> <ListView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:cacheColorHint="#00000000" />