Sublime Text 2でHTML要素のクラス名やIDの選択を少しだけ楽にする設定
Sublime Text 2は、デフォルトの設定では「-」(ハイフン)が単語の区切り文字に設定されています。なので、HTML要素のクラス名やIDなどのハイフン区切りの識別子をCtrl-d
の単語選択で選択しようとしても一部分しか選択できなくて残念な気持ちになります。
しかし、この振る舞いはもちろん簡単に修正することができます。Sublime Text 2の設定項目のうちのひとつ、word_separators
の内容を変更するだけです。
word_separators
はデフォルトでは次のような設定になっています。
"word_separators": "./\\()\"'-:,.;<>~!@#$%^&*|+=[]{}`~?",
見ての通りハイフンが単語の区切り文字リストに含まれています。これを取り除いてユーザー設定ファイルにコピペすればOKです。
備考
この設定はユーザー設定ファイルに直接書いておくだけでも良いですが、言語固有の設定ファイルに置いておくのもよさそうです。僕はとりあえずHTMLとCSSとJavaScript系の設定ファイルに置いておくことにしました。(言語固有の設定ファイルは、設定したい言語のファイルを開いて、メニューのPreferences > Settings - More > Syntax Specific - User と辿っていけば簡単に見つかります)
他にも、
- JavaScript:「$」も単語の区切り文字リストから外しておく
- Ruby: 「!, ?」を(略)
- Lisp系: 「-, !, ?, *, などいろいろ」を(略)
などを設定しておくとよさそうですね:)
CoffeeScriptを利用したPhantom.jsのevaluateで「ReferenceError: Can't find variable: __slice」となる問題
原因
Phantom.jsのpage.evaluate
に渡す関数は外側のスコープの変数を利用できないのに、CoffeeScriptのコンパイラが外側のスコープの変数を利用する関数を生成してしまうため。
対策
次のような関数を利用することでpage.evaluate
に渡す関数が変数を自身のスコープ内のみで解決できるようにする。
toBeExecutableInBrowser = (func) -> str = func.toString().replace /\n/, '\n var __slice = [].slice;\n' eval "(#{str})"
あるいは次のようにしてpage.evaluate
の動作を変更し、ブラウザ内に__slice
という変数を事前に定義するようにしておく。
do () -> evaluate = page.evaluate page.evaluate = (func) -> evaluate.call @, `function() { window.__slice = [ ].slice; }` evaluate.call @, func
経緯みたいなもの(蛇足)
例えば、はてなブックマークのホッテントリのタイトル一覧を取得しようとした場合、次のようなコードを書けば上手くいきます。
page = require('webpage').create() page.open 'http://b.hatena.ne.jp/hotentry', (status) -> result = page.evaluate () -> links = document.getElementsByClassName 'entry-link' links = [ ].slice.call links JSON.stringify(links.map (link) -> link.innerText) titles = JSON.parse result console.log titles.join('\n') phantom.exit()
ブラウザ内でJavaScriptを実行するところの
links = document.getElementsByClassName 'entry-link' links = [ ].slice.call links
という部分でdocument.getElementsByClassName
で取得したリンク一覧(配列のようなオブジェクト)をきちんとした配列に変換しています。
この部分をCoffeeScriptの文法を利用して次のように書き直しました。
[links...] = document.getElementsByClassName 'entry-link'
...これがGood PracticeかBad Practiceかどうかはどうかはさておくとして、一応これでも動くと思ったんですが、実行してみると次のようなエラーになってしまいました。
ReferenceError: Can't find variable: __slice phantomjs://webpage.evaluate():3 phantomjs://webpage.evaluate():7 phantomjs://webpage.evaluate():7 TypeError: 'null' is not an object (evaluating 'titles.join') example.coffee:17
CoffeeScriptのコンパイラが余計な気を利かして配列化の関数__slice
をpage.evaluate
に渡す関数の外側で定義していたことが原因でした。page.evaluate
は渡された関数の外側にある変数を利用できない(というかPhantom側からブラウザ側に関数を渡す過程でスコープチェーンを保持しておくことができない)ので、ブラウザ側で__slice
という変数の解決に失敗しているということです。
それで、なるべく関数のコードを変えないような形でこの問題を解決できないかといろいろ試したんですが、最終的に次のようにするのがベターかなと思いました。
toBeExecutableInBrowser = (func) -> str = func.toString().replace /\n/, '\n var __slice = [ ].slice;\n' eval "(#{str})" getTitles = () -> [links...] = document.getElementsByClassName 'entry-link' JSON.stringify(links.map (link) -> link.innerText) browserGetTitles = toBeExecutableInBrowser getTitles page = require('webpage').create() page.open 'http://b.hatena.ne.jp/hotentry', (status) -> result = page.evaluate browserGetTitles titles = JSON.parse result console.log titles.join('\n') phantom.exit()
toBeExecutableInBrowser
という関数を利用して、page.evaluate
に渡したい関数の中身に無理やり__slice
の宣言を追加してしまうという感じです。
一応これで動くようになりました。まあ今回の場合はべつに[links...]
という記法を使わずに[ ].slice.call
を使ったり、そもそも[ ].map.call
を使えばよかったわけですが、他にも色々と同じような問題が出てくるだろうということで書き残しておきました。CoffeeScriptの予約語リストを見るに'__hasProp', '__extends', '__slice', '__bind'
'__indexOf'
のあたりはまた同じような問題を起こしそうです。
もう一つのやり方として次のようなのも良い感じです。
browserGetTitles = () -> [links...] = document.getElementsByClassName 'entry-link' JSON.stringify(links.map (link) -> link.innerText) page = require('webpage').create() do () -> evaluate = page.evaluate page.evaluate = (func) -> evaluate.call @, `function() { window.__slice = [ ].slice; }` evaluate.call @, func page.open 'http://b.hatena.ne.jp/hotentry', (status) -> result = page.evaluate browserGetTitles titles = JSON.parse result console.log titles.join('\n') phantom.exit()
page.evaluate
の動作を変更して、先にグローバルに__slice
を定義するようにしています。CoffeeScriptでは__slice
が予約語になっているのでJavaScript埋め込み機能を利用しています。page.evaluateJavaScript
を使えばもう少し簡潔になるんですが、なぜか利用できないのでこういう形になりました。
あとはpage.includeJs
、page.injectJs
なんかを利用しても解決できるかと思います。
ブラウザでBase64エンコードされた画像をデコードして閲覧する
ブラウザのアドレスバーにdata:image/jpeg;base64,{{Base64文字列}}
みたいな感じで入力して移動すると表示できます。
例
とりあえずGoogleのfaviconで。下のリンクをクリックするか、テキストをトリプルクリックなんかでコピーしてアドレスバーに貼り付けて移動してみてください。画像が表示されるのが確認できると思います。
リンク形式
テキスト形式
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4ge4SUNDX1BST0ZJTEUAAQEAAAeoYXBwbAIgAABtbnRyUkdCIFhZWiAH2QACABkACwAaAAthY3NwQVBQTAAAAABhcHBsAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtkZXNjAAABCAAAAG9kc2NtAAABeAAABWxjcHJ0AAAG5AAAADh3dHB0AAAHHAAAABRyWFlaAAAHMAAAABRnWFlaAAAHRAAAABRiWFlaAAAHWAAAABRyVFJDAAAHbAAAAA5jaGFkAAAHfAAAACxiVFJDAAAHbAAAAA5nVFJDAAAHbAAAAA5kZXNjAAAAAAAAABRHZW5lcmljIFJHQiBQcm9maWxlAAAAAAAAAAAAAAAUR2VuZXJpYyBSR0IgUHJvZmlsZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbWx1YwAAAAAAAAAeAAAADHNrU0sAAAAoAAABeGhySFIAAAAoAAABoGNhRVMAAAAkAAAByHB0QlIAAAAmAAAB7HVrVUEAAAAqAAACEmZyRlUAAAAoAAACPHpoVFcAAAAWAAACZGl0SVQAAAAoAAACem5iTk8AAAAmAAAComtvS1IAAAAWAAACyGNzQ1oAAAAiAAAC3mhlSUwAAAAeAAADAGRlREUAAAAsAAADHmh1SFUAAAAoAAADSnN2U0UAAAAmAAAConpoQ04AAAAWAAADcmphSlAAAAAaAAADiHJvUk8AAAAkAAADomVsR1IAAAAiAAADxnB0UE8AAAAmAAAD6G5sTkwAAAAoAAAEDmVzRVMAAAAmAAAD6HRoVEgAAAAkAAAENnRyVFIAAAAiAAAEWmZpRkkAAAAoAAAEfHBsUEwAAAAsAAAEpHJ1UlUAAAAiAAAE0GFyRUcAAAAmAAAE8mVuVVMAAAAmAAAFGGRhREsAAAAuAAAFPgBWAWEAZQBvAGIAZQBjAG4A/QAgAFIARwBCACAAcAByAG8AZgBpAGwARwBlAG4AZQByAGkBDQBrAGkAIABSAEcAQgAgAHAAcgBvAGYAaQBsAFAAZQByAGYAaQBsACAAUgBHAEIAIABnAGUAbgDoAHIAaQBjAFAAZQByAGYAaQBsACAAUgBHAEIAIABHAGUAbgDpAHIAaQBjAG8EFwQwBDMEMAQ7BEwEPQQ4BDkAIAQ/BEAEPgREBDAEOQQ7ACAAUgBHAEIAUAByAG8AZgBpAGwAIABnAOkAbgDpAHIAaQBxAHUAZQAgAFIAVgBCkBp1KAAgAFIARwBCACCCcl9pY8+P8ABQAHIAbwBmAGkAbABvACAAUgBHAEIAIABnAGUAbgBlAHIAaQBjAG8ARwBlAG4AZQByAGkAcwBrACAAUgBHAEIALQBwAHIAbwBmAGkAbMd8vBgAIABSAEcAQgAg1QS4XNMMx3wATwBiAGUAYwBuAP0AIABSAEcAQgAgAHAAcgBvAGYAaQBsBeQF6AXVBeQF2QXcACAAUgBHAEIAIAXbBdwF3AXZAEEAbABsAGcAZQBtAGUAaQBuAGUAcwAgAFIARwBCAC0AUAByAG8AZgBpAGwAwQBsAHQAYQBsAOEAbgBvAHMAIABSAEcAQgAgAHAAcgBvAGYAaQBsZm6QGgAgAFIARwBCACBjz4/wZYdO9k4AgiwAIABSAEcAQgAgMNcw7TDVMKEwpDDrAFAAcgBvAGYAaQBsACAAUgBHAEIAIABnAGUAbgBlAHIAaQBjA5MDtQO9A7kDugPMACADwAPBA78DxgOvA7sAIABSAEcAQgBQAGUAcgBmAGkAbAAgAFIARwBCACAAZwBlAG4A6QByAGkAYwBvAEEAbABnAGUAbQBlAGUAbgAgAFIARwBCAC0AcAByAG8AZgBpAGUAbA5CDhsOIw5EDh8OJQ5MACAAUgBHAEIAIA4XDjEOSA4nDkQOGwBHAGUAbgBlAGwAIABSAEcAQgAgAFAAcgBvAGYAaQBsAGkAWQBsAGUAaQBuAGUAbgAgAFIARwBCAC0AcAByAG8AZgBpAGkAbABpAFUAbgBpAHcAZQByAHMAYQBsAG4AeQAgAHAAcgBvAGYAaQBsACAAUgBHAEIEHgQxBEkEOAQ5ACAEPwRABD4ERAQ4BDsETAAgAFIARwBCBkUGRAZBACAGKgY5BjEGSgZBACAAUgBHAEIAIAYnBkQGOQYnBkUARwBlAG4AZQByAGkAYwAgAFIARwBCACAAUAByAG8AZgBpAGwAZQBHAGUAbgBlAHIAZQBsACAAUgBHAEIALQBiAGUAcwBrAHIAaQB2AGUAbABz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
MIMEタイプのところを変えればPNGやGIFといった他の形式の画像や、テキストファイルなんかも表示できそうですね。下は「Base64テスト」と書かれたテキストファイルをBase64エンコードした例です(もし文字化けしていればブラウザのエンコード指定をUTF-8に変更すれば正しく表示されると思います)。
data:text/plain;base64,QmFzZTY044OG44K544OICg==
Google画像検索結果のimgのsrc属性に使われているのを見て知りました:)
追記
こういうのはData URI schemeというらしい。
GitHub Pages利用メモ
Git力がないからこういうことはすぐハマってしまう:(
いろいろなサイトを参考にさせてもらいながらなんとか解決。
GitHubにmasterブランチは登録せずにgh-pagesブランチだけを登録してそのままgh-pagesで開発していく、というようなことがしたかった。
参考サイト
- Githubでgh-pagesを作成する | jekylog
- 実践GitHub Pages運用のユースケースとワークフローの詳細 | ゆっくりと…
- GitHub Pagesホスティングサービス(ほぼ)完全活用ガイド | ゆっくりと…
- github:help
コード
masterをgh-pagesに改名する版
git init echo "hello world" >> index.html git add . git commit -m "first commit" git branch -m gh-pages git remote add origin git@github.com:username/repositoryname.git git push -u origin gh-pages
ローカルのmasterをリモートのgh-pagesにpushする版
git init echo "hello world" >> index.html git add . git commit -m "first commit" git remote add origin git@github.com:username/repositoryname.git git push -u origin master:gh-pages
GitHubでの検索
ちょっと前の話題だけど、GitHubの検索機能の改良があったそうなのでリンクのメモ。あと、検索のトップページにいろいろなフィルターが載っていたのでこちらもメモ。
追記(2013/01/24)
GitHubにコードの全文検索機能が追加されてトップページのデザインが一新されてた。
JavaScript関連いろいろ
備忘録的に。
Backbone.js in Practice: Part I – Preventing Memory Leaks
Backbone.jsにおけるメモリリーク対策の解説。Backbone.jsにおけるメモリリークはイベントバインディングとネストしたビューが鬼門なんだけど、それらに対するメモリリーク対策のパターンが分かりやすく解説されている。
いままでメモリリークのことを気にしたことなかったのでためになった。まあメモリリークを気にするほどの大きなBackbone.jsアプリ作ってないけど:)
Marionette.js – A scalable and composite application architecture for Backbone.js
Backbone.jsの拡張的なもの?GitHubでのStar数が1600を超えていてかなり人気っぽい。
GitHub上のREADMEをちょこっと読んだだけだから詳しくは分からないけど、メモリ管理の機能を用意してくれたりビューやイベントの管理が楽にできたりするらしい?早く詳しく調べたい。
novus / nvd3
チャートライブラリ。グラフ描画系のライブラリといえば少し前にMorris.jsが話題になっていたけど、このNVD3はD3.jsを利用したもの。
まだまだ開発途中・発展途上って感じだけどなかなか良さげ。なによりD3.jsを利用してるってところが(・∀・)イイ!!
最近ちょっとしたお家騒動みたいなことがあったらしく、公式サイトに謝罪文的なものが貼られてるけど、まあ結果的にこれからもずっとオープンソースプロジェクトとしてやっていくことになったらしいから一安心。