2010-08-14

記事に埋め込むためにコードの断片を整形する

このブログの記事でコードを載せるときに使っている Ruby のプログラムだ。

整形すると言っても、実際にやっているのは HTML 系のエンティティのエスケープと行番号を振るだけ。長い行を折り畳むとか、インデントを調整するなどのような高級なことはしない。

(embed_code.rb)
 1: #!/opt/local/bin/ruby1.9 -w
 2: # coding: utf-8
 3: 
 4: require 'cgi'
 5: 
 6: source = ARGV.shift
 7: exit if ! source
 8: 
 9: def header(name)
10:   h = '<pre class="code"><code>' + "(#{File.basename(name)})"
11:   puts h
12: end
13: 
14: def footer
15:   puts '</code></pre>'
16: end
17: 
18: def scale(n)
19:   Math::log10(n).floor + 1
20: end
21: 
22: count = 1
23: lines = IO.readlines(source)
24: format = "%#{scale(lines.length)}d"
25: 
26: header(source)
27: lines.each do |code|
28:   code = CGI::escapeHTML(code.chomp)
29:   numbering = format % count
30:   STDOUT.puts "#{numbering}: #{code}"
31:   count += 1
32: end
33: footer

18 〜 20 行の scale は整数の桁数を求めるもの。行番号の出力のフォーマットに使っている。1 行目で ruby1.9 を指定しているけれど、1.8 系でも問題なく動く。整形するコードに日本語が混じっていると(コメントや文字列リテラルとして)、おかしなことになるかも。

ついでに、embed_code.rb で処理したテキストを元のコードに戻すプログラムが以下になる。ただし、embed_code.rb 出力そのものではなく、それを(HTML に組み込み)ブラウザで表示させた上でコピーしたテキストを入力にする。

以下のコード中にも、コメントとして入力サンプルを挙げてあるが、基本的には以下のフォーマットとなる。

  • 先頭行は括弧で挟まれたファイル名
  • コード本体には行番号が振られている。
  • 行番号の書式は、0個以上の空白と数字の列、その直後に「:」と空白が 1 つ。
  • それ以外の行は無視して良い。
(extract_code.rb)
 1: #!/opt/local/bin/ruby1.9 -w
 2: # coding: utf-8
 3: 
 4: # ---- input sample ----
 5: # (print_numrefs.rb)
 6: #  1: #!/opt/local/bin/ruby1.9 -w
 7: #  2: # coding: utf-8
 8: #  3: 
 9: #  4: def convert(ref)
10: #  5:   num = ref[2...-1].to_i  # Numerical reference must be "&#12345;"
11: #  6:   fs = "%c".encode("UTF-8")
12: #  7:   fs % num
13: #  8: end
14: #  9: 
15: # 10: STDIN.each do |numref|
16: # 11:   STDOUT.puts "#{numref.chomp} -> #{convert(numref)}"
17: # 12: end
18: # ----
19: 
20: outfile = nil
21: 
22: STDIN.each do |line|
23:   case line
24:   when /^\((.+)\)/              # file name
25:     outfile = File.open(Regexp.last_match[1], "w")
26:   when /^[ ]*[0-9]+:[ ](.*)/    # code body
27:     outfile.puts Regexp.last_match[1]
28:   else
29:     # nothing to do
30:   end
31: end
32: 
33: outfile.close

HTML から直接取り出すことも考えたが、ブラウザからコピーして……が実際の使い方だろうと判断した。取り出す方を自分で使うときは、以前、記事に埋めたコードが必要なのに元のファイルが見つからないときだ。なら、ユースケースは「ブラウザからコピー」になる。

github のようなリポジトリに登録してしまうのが手っ取り早いんだろうな。ちょっと大袈裟な感じがするけど。

関連リンク

2010-08-13

AppleScript を使って URL を Safari のタブで開く

これも昨日作った Automator のワークフローの一部。

Safari を起動したとき、いつも同じ URL を開く。それが一つならホームページとして設定しておけば良い。けど複数あったらどうすれば良い? Firefox なら、複数のページをホームページに設定できる。起動時に各ページが別のタブで開かれる。残念ながら Safari ではこれができない。タブを開きながらブックマークや Top Sites からページを開く。そういう作業こそ自動化したいもの。

1 行目、そして 18 〜 19 行目は、Autometor のアクションとして使うときのオマジナイ。この AppleScript 単独で(AppleScriptエディタから)実行する場合は、この 2 行は取り除くこと。4 〜 16 行が本体部分。AppleScript について書かれたページを、ググって探し、いくつかのサンプルを切って貼ってできあがったものだ。

  • 4 行: 開きたい URL のリストを変数(urlList)にセット
  • 5 行: リスト内の URL の個数を変数(numURLs)にセット
  • 6 行: Safari に対して以下の Apple イベントを送る
  • 7 行: Safari ウィンドウの位置とサイズを指定
  • 9 行: まず、1つめの URL を開く
  • 10 〜 15 行: 新しいタブを作りながら、与えられた URL を開いていく
(safari_init.scpt)
1: on run {input, parameters} 2: 3: (* Your script goes here *) 4: set urlList to {"http://logrepo.blogspot.com", "http://www.google.com/", "http://www.google.com/reader/view/", "http://twitter.com/"} 5: set numURLs to (count urlList) 6: tell application "Safari" 7: set bounds of window 1 to {0, 22, 1024, 1350} 8: activate 9: set URL of document 1 to (item 1 of urlList) 10: tell window 1 11: repeat with i from 2 to (numURLs) 12: set current tab to (make new tab) 13: set URL of document 1 to (item i of urlList) 14: end repeat 15: end tell 16: end tell 17: 18: return input 19: end run

この程度のことならググって試行錯誤を繰り返せばなんとかなる。AppleScript のことをほとんど知らなくても大丈夫。これ以上になると、AppleScript のことを勉強した方が良いだろう。Mac Dev Center の Mac OS X Reference Library に AppleScript の資料がある。

関連リンク

関連記事

twitter より (2010-08-12)

Powered by twtr2src.

2010-08-12

Automator は「パイプとフィルタ」だ

今日やったことは、Automator というより AppleScript なんだが、行き着くところは Automator になる、ってことで。

この Automator という Mac OS X 付属のアプリは、各種アプリを AppleScript で制御して、Mac の操作を自動化するためのツールだ。Automator で作る自動処理のためのプログラムをワークフローと呼ぶ。これを、Automator にライブラリとして提供されているアクションを組み合わせて作る。基礎になっているのは、UNIX の世界でお馴染の「パイプとフィルタ」に近い考え方だ。

Automator が「パイプとフィルタ」だということを説明するための例を挙げる。説明のためにでっちあげたものだから実用的ではない。

  1. Finder で(画像)ファイルを選択する。
  2. それを別の場所にコピーする。
  3. コピーした画像のフォーマットを変換する。
  4. 変換した画像ファイルからPDFを作成する。

各項目が Automator のライブラリとして提供されているアクションだ。最初のアクションで選択されたファイル名が、二番目のアクションに入力としてわたり、コピー後のファイル名(コピー先のパス付き)が、三番目のアクションの入力として伝わり、……、というように各アクションが入力と出力によって連続して結びつけられる。中間データがファイルとして残ってしまうため厳密には「パイプとフィルタ」とは言えない。とはいえ、既存のプログラムを次々につなげて新しい処理を作るという点から見れば、同じアーキテクチャだと言っても良いだろう。クリップボード経由でデータをやり取りできれば完璧かな。

さらに、AppleScript やシェルスクリプトの実行もアクションとして組込める。たとえば、以下は、今日、試行錯誤の上にどうにか作ったワークフローのアクションの一つ。「ターミナル.app」のウィンドウを 2 つ開き、それぞれ固定の位置に置く、というものだ。いつも手でやっていることを自動化してみた。

(startterminal.scrpt)
1: on run {input, parameters} 2: 3: (* Your script goes here *) 4: if application "Terminal" is not running then 5: tell application "Terminal" 6: -- Launch "Terminal.app" 7: -- Then, move the "Terminal" window to the fixed position. 8: set position of window 1 to {-1192, 0} 9: set input to id of window 1 10: -- Open a new "Terminal" window 11: -- Then, move it to the position specified in this script. 12: -- NOTE: a new window always appears at the front most. 13: -- So, it can specified as "window 1". 14: do script "" 15: set position of window 1 to {-1192, 784} 16: end tell 17: end if 18: 19: return input 20: end run

Mac にログインした後、いつも起動するアプリがあるとする。単に起動するだけならログイン項目(「システム環境設定」>「アカウント」)に登録すれば良い。けれど、上記のようにウィンドウを複数開いておきたい、ウィンドウを決まった場所に置きたい(前回、終了した位置に関係なく)、などの要求があるなら、Automator (AppleScript) の出番になる。

ただし、すべてのアプリが Automator (というか AppleScript) の制御を受け付けるわけではない。また、制御を受け付けたとしても、アプリごとに微妙に「クセ」があったりもして、なかなか手強い。

通常、GUI ベースのコンピュータは手で動かすものと思い込んでいる。Mac OS X の場合、Automator と AppleScript を使うことでその制約を取り払うことができる。iPhone や iPad でも、こういう仕組みが提供されると良いのにね。

関連リンク

  • Mac OS X - Automator Actions (Apple - Downloads より; Automator で使える action がダウンロードできる)
  • Mac OS X Automation (OSX の自動化についてのまとめサイト; Automator、AppleScript の解説がある)

twitter より (2010-08-11)

  • 19:37  Gmail から直接 Picasa に画像を送れないもんか。ダウンロードしてアップロードするのは面倒だし、回線幅のムダづかいだ。
Powered by twtr2src.

2010-08-11

古い雑誌の記事や広告に見る懐しいコンピュータ

右の写真は、「UNIX MAGAZINE Classic with DVD」の内容物だ。雑誌の記事を収めた DVD 4枚組と特別号(?)が 1 冊。DVD には 1986 年の創刊以来、月刊誌最終号までの記事がほぼ丸ごと入っている。総容量は 13.3 ギガバイト。二十年がたった 13 GB に収まってしまうことを空しく見るか、それを可能にした技術の進歩に感心するべきか。

すでに書いたように、iPad に PDF 化された雑誌を詰め込んでいる。この DVD の内容も丸ごと詰め込んだ。iPad でパラパラとページを送りながら、一昔も二昔も前の記事を眺めていると、隔世の感とはこういうことを言うのかと実感できる。創刊号を始めとする初期の号に書かれているほとんどのコンピュータよりも、この iPad の方が高性能だろう。これらの時代をリアルタイムで経験した身には、何というか、何もかもがとても懐しい。

創刊号には、「低価格・高機能・4.2BSD搭載ワークステーション」と題した SONY の NEWS 発売のニュースが載っている。上述の DVD 付属の特別号によれば、創刊3号目には、この NEWS シリーズの広告が掲載されたそうだ(→ 特別号のページを iPhone で撮影)。

当時は、その破壊的な低価格もあって強烈に憧れたものだ。もちろん、いくら低価格だといっても当時の他のワークステーションと比較しての話で、「オレにも買える!」とはならなかった。

このとき発売になったモデルでは、プロセッサはモトローラ社製の 68020 (16MHz x 2)、メモリは 4MB、HDD が 156MB。ほら、iPad の方の方がはるかに高性能だ。

1988年12月号には NeXT 発表に関するの記事が載っている(→ iPad で表示させたスクショ)。

OSX で動く Mac は、それ以前の Mac の後継というよりも、むしろ NeXT というコンピュータがリンゴの皮をかぶっていると見る方が良い。これは OS のカーネルやら、各種フレームワークが NeXT の OS であった NeXTSTEP 由来のものであるからだ。そして、その系譜は iPhone や iPad にもつながる。

この記事にある NeXT は、プロセッサがモトローラ社製の 68030 (25MHz)と浮動小数点演算ユニット 68882 (25MHz)、メモリは 8MB、HDD はオプションで、補助記憶装置としては光磁気ディスク(256MB)が搭載されている。ほら、やっぱり iPad の方が高性能だ。

ちなみに、月刊誌として最終号となる 2006年4月号には Mac mini (Early 2006) 発売のニュースが載っている。これは Intel 版 Mac mini の最初のモデルで、Core Duo 1.66GHZ、メモリは 512MB、HDD は最大で 120GB。さすがに iPad よりも高性能かも。

ともあれ、こうして古い雑誌を眺めるのは意外に楽しい。ウェブのなかった時代の記憶として、こうした雑誌は貴重な資料でもある。上述の「UNIX MAGAZINE Classic with DVD」に付属の特別号の表紙に「いまある道具はなぜこの形をしているのか?」という問いかけが書かれている。これに答えるには過去を掘り起こすしかない。

ウェブ以前に刊行されていた他のコンピュータ関連の雑誌でも、電子化(PDF化)して、DVD で発売してくれると良いんだが。「bit」とか、また読んでみたい。

ググってみたところ「bit」(共立出版)の創刊は 1969 年だとのこと・・・。1969 年と言えば、アポロが月に着陸した年だし、Unix が生まれた年だ。ちょっとビックリだね。「bit」は 2001年4月号を最後に休刊状態だから、トータル 33 年分になる。70年代の「bit」には何が書かれていたんだろう?

関連リンク

関連記事

twitter より (2010-08-10)

  • 09:46  iPad の最大の弱点は「映り込み」にあるかも。使用時には光源に対する角度に気をつかう。アンチグレアフィルムを貼っても(軽減されるけど)解消されない。見やすい角度にするためにはスタンドっぽい何かが必要になる(膝とか)。手だけで角度を保持しようとすると重さがネックになる。
  • 09:54  「映り込み」のせいで、紙のノートや本とちがい、机の上に水平に置いて使うことが難しい。大きさと重さのため片手でしっかりと保持することも難しい。iPhone とは違い、使用時のスタイル(姿勢とか持ち方とか)にかなり制約のあるデバイスなのだ。
Powered by twtr2src.

2010-08-10

フローなメモならスティッキーズ

メモにはフローとストックの 2 種類がある。

たとえば、新しい iMac の製品発表を見て、あれこれ悩んだ末に買う決心をして、いざ Apple Store でポチろうとしたら出かける時間になり、忘れては困るので手元のポストイット®に「新しい iMac を買うこと。」と書き込んでディスプレイの端に貼りつけたとする。このメモはフローだ。iMac を買ってしまえばメモは不要になる。

ストックがどんなメモなのかについては別の機会に考えるとして、ここではフロータイプのメモを扱うツールに話をしぼる。

アナログの道具を使ってこのタイプのメモを書くならポスト・イット®に勝るものはない。貼りつけられるから風で飛んでしまうことはないし、どこかに紛れ込むこともない。目立つところに貼りつければ忘れるはずもない(たぶん)。そして用が済めば、はがして丸めて捨ててしまえば良い。

この便利な発明をそのままデジタルの世界に写し取ったかのようなツールがある。Mac OS X の標準アプリの一つ、「スティッキーズ.app」だ。

twitter より (2010-08-09)

  • 20:13  今日の戦利品。
Powered by twtr2src.

2010-08-09

Xcode のファイル新規作成で作者名になるのは、どれ?

Xcode でファイルを新規作成すると、ファイルの先頭のコメントとしてファイル名やプロジェクト名とともに (1) Created by ... と (2) Copyright ... の 2 行も自動的に書き込まれる。このとき、(1) にはユーザ名らしきものが、(2) には会社名らしきものが入る。これらはどこから引っぱってきてるのだろう?

(2) の方は簡単に見つけることができた。これはアドレスブックにある「自分」カードの「会社名」だった。ちなみに「自分」カードは、名前欄の左のアイコンがカードではなく人の影になっているもの。わかりにくければメニューから「カード」>「自分のカードを表示」で表示できる。さらにちなみに、「自分」カードを変更するには、「自分」にしたいカードを選んでメニューから「カード」>「自分のカードにする」を選べば良い。

一方、(1) の方は見つけにくかった。ログインユーザのユーザ ID でもない。またアドレスブックとも関係ない。「自分」カードをいくら書き変えても、Created by ... はまったく変化しない。いったいどこの情報を見ているのか……。

答えは、「システム環境設定.app」の「アカウント」だった。ログインしているアカウントのフルネームが (1) でユーザ名として使われる。ちなみに、このフルネームは、Mac の初期設定時に(管理者ユーザとして)作ったユーザなら、そのときに入力した名前が使われている(ユーザ ID とは違う)。漢字で氏名を入力していれば、ここも漢字になっている(で (1) のユーザ名も漢字で入っているはず)。

このフルネームは、ユーザ ID とひもづいているものの、ユーザ ID そのものではないため、初期設定後も自由に変更可能だ。「ソースコードは公開したいけど、実名はイヤ」という場合は、このフルネームをあらかじめ公開しても良いものに変更しておくと良い。今なら twitter のユーザ名や、Google アカウントあたりかな。

2010-08-08

iMac に Gauche 0.9 をインストール

MacPorts を使ってのインストール。Mac mini にインストールしたときに実行結果を残していたので、今回も残してみる。ただ、前回の記録には依存関係によるビルド&インストールを丸ごと snip してしまったため、実行時間の比較は意味がなさそう。あのときは依存関係分は前もってインストールしておいて Gauche だけをビルドしたのかも。記録はないし、記憶は消えてるしで、判別するすべはない。

使った MacPorts のバージョンは 1.9.1。今回は依存関係により gdbm と slib が自動インストールされた。

[imac] mnbi% time sudo port install gauche                        [~]
Password:
--->  Computing dependencies for gauche
--->  Dependencies to be installed: gdbm slib
[...snip...]
--->  Installing gauche @0.9_0
--->  Activating gauche @0.9_0
--->  Cleaning gauche
sudo port install gauche  102.11s user 25.08s system 142% cpu 1:29.06 total
[imac] mnbi% hash -r                                              [~]
[imac] mnbi% gosh -V                                              [~]
Gauche scheme shell, version 0.9 [utf-8,pthreads], i386-apple-darwin10.4.1

ちなみに、↑で time の出力書式が前回と変わっているのはシェルを tcsh から zsh に変えたから。シェルプロンプトが変わっているのもそのせいだ。

関連リンク

関連記事