公式にはAPIが用意されていない。プライベートだけど誰でも叩けるAPIがあるけど使わないでくれと言っている 。のでTopsy やAddThis のAPI経由とかしか今のところ方法は無さそう。などということを公式Tweet Buttonのサブセットなdata-*属性による設定を受け入れるTweet Buttonを作ってて知った。
View Demo: Tweet Button Powered by Topsy
TopsyのAPIはコマーシャル・ライセンスを取らないと専用の画像を使ってリンク必須 と読めるのでとても使いづらい。というか使えない。AddThisの(api-public.addthis.comで動いてる奴)はドキュメント見つからない。Shared Count とか見つけたけどコレは普通にプライベートなAPIを使っててダメそう。
なんか良いの無いもんかな。
UglifyJS にClosure Compiler から乗り換えようかなーとちょっと思っているのでとりあえずコンパイルするためのスクリプトを書くところから。UglifyJSのHTTP APIがそこそこClosure Compiler ServiceのREST APIと互換性があるようなので、まずはローカルのJavaScriptファイルをClosure Compiler ServiceのREST APIでコンパイルできるように で書いたPerlスクリプトを修正して使ってみる。
Download: uglifyjs.pl
使い方は元になったClosure Compiler ServiceのREST APIを叩く奴と一緒。
UglifyJSのHTTP APIではjs_codeパラメーターが複数使えない。なので手元でまとめてから投げたりする必要があるので、ちゃんとまとめないと意図した順番でコードが実行されない可能性がある。素直にどこかにアップロードしてからcode_urlパラメーターでそれを指定したほうが安全そう。
Closure Compiler Serviceのような埋め込みコメントに対応したCUIラッパー書いた方が良さそう。ありそう。
追記
Closure Compilerに比べてローカル環境を構築するコストと実行するコストが低い気がするので連結するだけのスクリプト を書いてパイプでつなげることにした。Closure Compilerの@code_urlとそれに似た@code_pathだけ使えて、それらを連結するだけ。
単にDOMContentLoadedでGoogle Code Prettify のprettyPrint()を呼んでただけだったのをゴニョゴニョするようにした。将来性とマークアップのしやすさのためにpre要素にprettyprintというクラスを指定しないように方針変更したので、それに合わせてcode[class*=language-]な要素を探してその親がpreだったらprettyprintを追加し、その後でprettyPrint()を走らせるという感じ。一応サポートしている言語もチェックしたりとかもするようにした。Rainbow 移行への布石。
同じブラウザーかつ同じバージョンならdocument.querySelectorAll()におけるセレクターとCSSにおけるセレクターは完全にサポート状況が同じとみなして良いのかわからない。頑張ってググりたい。
language-fooをクラスに持つcode要素を表現するセレクターはcode[class|=language]とかでいけるかと思ったけど、そういう使い方するものではなかったしダメだった。空白区切りで複数の値を取れるプロパティーではそれぞれの値の先頭にマッチするようなセレクターが欲しい。いやいらないです。
サポートしている言語かそうでないかはごく簡単にチェック。
var languages = ["bsh", "c", "cc", "cpp", "cs", "csh", "cyc", "cv", "htm",
"html", "java", "js", "m", "mxml", "perl", "pl", "pm", "py", "rb", "sh",
"xhtml", "xml", "xsl", "css", "scss", "vim"],
reLanguage = new RegExp("\\blanguage-(" + languages.join("|") + ")\\b");
追加しづらそう……。Google Code PrettifyのlangHandlerRegistryを参照するかlangHandlerForExtension()パクった方が良さそう。むしろ頑張ってハイライトしようとするフォールバックの部分なくしちゃえばいいのかなー。
視認しつつマークアップの修正をしなければならなかったのでVim のキーボードマクロでだいたい誤魔化した。普段はqに誤爆するとうっとうしいけど、使う時はコマンドラインにでるrecordingというメッセージがすごく可愛く見える。多分結構な数のエントリーでおかしくなってそう。気づいたら直す。
あとRainbowに僕の書いた<code class="language-php">とかに対応するコードが取り込まれたのでdata-languageへ書きなおさなくても使えるようになった。作者のさじ加減で消えかねないのでマークアップにこだわりがないなら素直に併記した方が良さそう。
Rainbow はコードのシンタックス・ハイライトをやってくれるJavaScriptライブラリ。拡張の仕組みが凄く書きやすそうで良さそう。名前は悪い。しかもリダイレクト先のURLはrainbowsだし……。まぁとにかく乗り換えようかなとちょっと思った理由をちょっと書いておく。「ちょっと」なのでまだあんまり乗り換える気ない。
書きやすいといっても所詮は正規表現なので、定義フォーマットがGoogle Code Prettify の黒魔術的なアレよりもちょっとシンプルだとかそういう意味にすぎない。なのでこの点だけでは既存の様々なシンタックス・ハイライトしてくれるライブラリから乗り換えるという程のパワーがあるわけではないと思う。他にもpre要素の子ではないそこらのcode要素のハイライトにも対応している所とかすごいと思うんだけど、おまけ機能的な感じでこれも乗り換えの動機にはならなそう。
僕が乗り換えようかなと思ったのは、Rainbowがシンタックス・ハイライトできる言語であるかどうかHTML側からは気にする必要がないように使うことができる点。Rainbow.color()に要素を渡すとその子をシンタックス・ハイライトしてくれるので、これをうまく使えば良い。そうすると何が良いかというと、例えばRainbowでサポートされていない言語パターンのコードを書く時にも以下のように書くだけ。
<pre><code class="language-vim">
...
</code></pre>
あとはクラスを見て対応しているかいないかを確認し、対応しているものだけRainbow.color()に通せば良い。実際にはかなり追加でJavaScriptを書かないとならなかった(data-language属性を追加したりとか色々)のでイマイチだったんだけど、Google Code Prettifyで「あとで言語ハンドラー追加した!」とかそういう時に昔のエントリーのHTMLを修正する必要があるのとくらべるとマシな気はする。
Google Code Prettifyのシンタックス・ハイライトを実行する前にゴニョゴニョする方が簡単そうに思えてきたところ。
Amazon.co.jp でアソシエイトツールバーが表示されている場合、window.Associates.SocialShareAttributes.asinにASINがあることに気づいたのでしばらくこっちを使ってみる。GoogleでのSocialShareAttributes検索結果が0だった のでメモしておく。
他だと以下の二つが抜き出す方法としては優秀な気がする。
document.querySelector('link[rel="canonical"]').hrefの最後から切り出す
document.getElementById("ASIN").valueを参照する
canonicalはURL自体に色々パラメーター付いてても関係なさそうなので良さそう。id="ASIN"を参照は結構長いこと動いてるような気がするけどなんか不安……。
Data URIはまだそれほど使いまくっているわけでもないので、ブラウザーでやったりVimからWSHでやったりいろいろしてたけど、必要な時はだいたい複数ファイルを何回も変換する必要があったりしていろいろ大変なのでPerlで書き直して右クリックから使う方法も考えた。@cho45が書いたの を見て重い腰が上がった。
#!/usr/bin/env perl
use strict;
use warnings;
use MIME::Base64;
use MIME::Types;
use Path::Extended qw(file);
my $mt = MIME::Types->new();
my @r;
foreach (@ARGV) {
my $f = file($_);
my $t = $mt->mimeTypeOf($file->stringify);
push(@r, 'data:' . ($t ? $t : 'text/plain') . ';base64,' . encode_base64(scalar($f->slurp(binmode => 1)), ''));
}
print join("\n", @r);
exit;
URI モジュールでのnew('data:')だとBase64でエンコードするかどうかよしなにしてくれちゃうので、普通にMIME::Base64 を使った。メディアタイプ判別のモジュールはいくつか試したけど、未知の時に例外吐いて死ぬ奴とか常に配列で返す奴とか色々アレなのが多くて、未知の場合は空で返ってくるMIME::Types が結局一番ましな感じだった。
右クリックから使う場合は、
@echo off
perl -S convert-to-data-uri.pl %* | clip
というようなバッチファイルを送るに置いておくとクリップボードに即コピーとかできる。
Sass でコンパイル時にData URIに変換する関数とか書いて使ってたことも少しあったけど、コンパイルが遅くなりがちで辛いので直ぐに止めた……。
追記
Windowsだとバイナリ・ファイルがうまくいかないのでPath::Extended に変えて明示的にbinmodeを指定して読むようにした。自分で書いて て、id:charsbarに教えてもらった のをきれいさっぱり忘れてた……。
GitHub には任意の二点間のスナップショット差分を見るためのCompareというビュー がある。各リポジトリのページからこの機能にアクセスするUIがないのでマイナーな気がするけど、アクティビティーとかでちょっと使われてたりするので見たことはあるはず。CompareビューにはリポジトリのURLの最後に/compareと付けるだけで入ることができ、開かれるダイアログで任意のタグやブランチ、SHA1ハッシュを入力すると差分がズラッと並んでくれる。特定のコミットのページからは特にUIはないのだけどURLをちょっと書き換えるだけでmasterの最新との差分を見ることができる。
具体的には
https://github.com/hail2u/normalize.scss/commit/58d8597e5b6df43e9ad6023ac68f10e7ec47e139
というような特定のコミットを参照しているページのURLを
https://github.com/hail2u/normalize.scss/compare /58d8597e5b6df43e9ad6023ac68f10e7ec47e139...master
と書き換えるとそのコミットからmasterの最新のコミットまでの差分が見れるということ。/commit/を/compare/に書き換えて...masterを最後につけるだけ。たまに使うんだけどこの機能に簡単にアクセスするためのUIがなくて良く忘れる……というのももう10回目くらいな気がするので、ブックマークレットを作った。
Bookmarklet: Github: Compare this commit with master
commitとかいうユーザー名の人のリポジトリではうまく動かない気がするけどまぁいいか。クローンとかは特にしてるわけではないけどウォッチしてるプロジェクトの変更を一望する時とかに使っている。
Sass ではいわゆる「配列」のような複数のデータを格納するリストを作れる……というのだけど使ったことなかった。リファレンスでもさらっと流されてる し、リストを使う@eachの説明 でもベタに並べてあるだけで、どうやって作ってどうやって使うのかイメージできなかった。変数の値を空白区切りにしたらリストな変数になるということはどう考えてもリファレンスからは読み取れないと思う。
基本
特に難しいこともなく空白(かカンマ)区切りで指定するとリストになる。
$lists: foo bar buz;
.test {
property: $lists;
}
リストな変数であってもそのまま参照した場合は普通の変数と同じようにそのまま(空白区切りのまま)出力される。
.test {
property: foo bar buz }
リストの特定のインデックスの値を参照するにはnth()関数 を使う。
.test {
property: nth($lists, 2);
}
これでリストの2番目の値を参照できる。多くのプログラミング言語と違って添え字は1始まりなことには注意が必要。
.test {
property: bar }
書きづらいこと以外はまぁ普通な感じ。
応用
変数をそのままリストの値にすることもできる。
$foo: f o o;
$bar: b a r;
$buz: b u z;
$lists: $foo $bar $buz;
.test {
property: nth($lists, 3);
}
勿論(?)このようにリストをリストにぶち込むとかも出来て、こうすると多次元配列っぽいものになる。この場合は基本の最初の例のように空白区切りでの出力となる。
.test {
property: b u z }
nth()関数をネストすればどんどん辿れる。
.test {
property: nth(nth($lists, 3), 2);
これでリストに格納したリストの特定のインデックスを参照できる。
.test {
property: u }
素晴らしい。
具体的な利用
幅とそれを利用したクラスが必要なカラム定義なんかに利用できる。
$column: 60px;
$gutter: 20px;
$gap: 10px;
$colspan1: (($column + $gutter) * 1 - $gutter);
$colspan2: (($column + $gutter) * 2 - $gutter);
...
$colspan11: (($column + $gutter) * 11 - $gutter);
$colspan12: (($column + $gutter) * 12 - $gutter);
$colspan: $colspan1 $colspan2 ... $colspan11 $colspan12;
@for $i from 1 through 12 {
.colspan#{$i} {
margin-left: $gap;
margin-right: $gap;
float: left;
width: nth($colspan, $i);
}
}
このように変数を使って変数を参照することができる。append()関数 も使えばもっとうまく短く書けそう。
なんてことをカラム定義を生成するSCSSパーシャル を作ってて理解した。でもけっこうな魔窟っぽい予感がするので気をつけて使った方が良さそう。
追記
append()を使うと短くはなる。空のリスト(というか変数?)も作ることができるようなので以下のような感じで書ける。
$column: 60px;
$gutter: 20px;
$gap: 10px;
$colspan: ();
@for $i from 1 through 16 {
$colspan: append($colspan, (($column + $gutter) * $i - $gutter));
}
スッキリ!
3.2のprerelease版では複数のリストを明示的に多次元リストにまとめるzip()とリストから検索するindex()という関数も追加されている。駆使すると今はできない同じルールセット内の別プロパティーの値とかを参照するみたいな機能作れそう。多分誰も読めなくなるけど。
PhantomJSからCSS Lintを使う で書いたCSS Lint のPhantomJS 向けCLIを1ファイルで完結するようにClosure Compiler で連結した。オプションに対応とかじゃない。対応しようかと思ってたんだけど、ルールのオン・オフとかすごい面倒な感じだったのでやめた。外部ファイルに設定書けるようになったりするまではデフォルトで使ってようと思ってる。
Download: csslint-phantomjs.min.js
使い方は以前と同じ。僕はラッパーのシェル・スクリプトを書いてそれを使っている。
$ phantomjs csslint-phantomjs.min.js test.css
ついでにこのスクリプトを置いてあるGistリポジトリ へ使っているJSHint とJSLint のCLIも置いておいた。PhantomJS使ったスクリプトは他にもいくつかあるので気が向いたらここに追加するつもり。
Microdata ではitemprop属性を指定された要素からどうやって値を選択するか厳密に決められていて、それに外れた書き方はできない。metaやtime、img要素の場合はまぁそうなるよねみたいな感じなんだけど、a要素だけがちょっと。
仕様では、a要素でitemprop属性を使った場合その値はhref属性の値を絶対URLに変換したものとなっている 。そのため以下のようには書けない。
<address itemscope
itemtype="http://schema.org/Person">
Copyright © 2012
<a href="http://example.com/about/"
itemprop="name url" >
John Doe
</a>
</address>
Microformats のhCard のような感覚では書けないということで、以下のようにspan要素(など)を使って別にしないといけない。
<address itemscope
itemtype="http://schema.org/Person">
Copyright © 2012
<a href="http://example.com/about/"
itemprop="url">
<span itemprop="name">
John Doe
</span>
</a>
</address>
ボキャブラリーごとに対応しなくても良いようにHTMLの要素側で値の選択法を決定させているのだと思う。ボキャブラリー側でデータ型を決めてそれによって値の選択法を変えるというのだと、処理系でボキャブラリーをちゃんと処理しなければ正確なデータの抽出が行えない。HTML要素で値の選択法が決定されるMicrodataの実装ではデータの抽出自体はボキャブラリーを処理せずに行えることになる。HTMLがマークアップ言語なこともあって理にかなっている実装なんじゃないか(と今は思う)。
このWebサイトはまだ直してない……けど今から直す。