Hatena::ブログ(Diary)

jimo/memo RSSフィード

2011-12-29

NTEmacsでJavaScriptのシンタックスチェック

概要

Windows 版の Node.jsバンドルされている npm でインストールした node-jslint を使って,Emacs の flymake を設定し JavaScript リアルタイムなシンタックスチェックを実現する.

f:id:jimo1001:20111229165252p:image

試した環境

-バージョン
OSWindows 7
Emacs23.3.1
Node.jsv0.6.6
node-jslint0.1.2

手順

1. Node.jsインストールする

1.1. http://nodejs.org/#download から Windows Installer をダウンロードおよびインストールする.

1.2. 以下のディレクトリにPATHを通しておく

C:\Program Files (x86)\nodejs // インストールディレクトリ
%APPDATA%\Roaming\npm // npm -g でインストールした時にモジュールがインストールされるディレクトリ

2. jslintをインストール

npm -g install jslint

3. jslintのレポートを生成するスクリプトを修正

%APPDATA%\Roaming\npm\node_modules\jslint\lib\reporter.js
--- reporter.js.a       2011-12-28 03:33:00.724467399 +0900
+++ reporter.js 2011-12-28 03:40:53.759405265 +0900
@@ -7,7 +7,7 @@
     'use strict';

     var options = [], key, value, line,
-        i, len, pad, e, fileMessage;
+        i, len, pad, e, fileMessage, output = [];

     for (key in lint.options) {
         value = lint.options[key];
@@ -17,7 +17,7 @@
     fileMessage = "\n" + ((colorize) ? color.bold(file) : file);

     if (!lint.ok) {
-        log(fileMessage);
+        output.push(fileMessage);
         len = lint.errors.length;
         for (i = 0; i < len; i += 1) {
             pad = "#" + String(i + 1);
@@ -28,14 +28,15 @@
             if (e) {
                 line = ' // Line ' + e.line + ', Pos ' + e.character;

-                log(pad + ' ' + ((colorize) ? color.yellow(e.reason) : e.reason));
-                log('    ' + (e.evidence || '').replace(/^\s+|\s+$/, "") +
-                        ((colorize) ? color.grey(line) : line));
+                output.push(pad + ' ' + ((colorize) ? color.yellow(e.reason) : e.reason) + ((colorize) ? color.grey(line) : line));
+                output.push('    ' + (e.evidence || '').replace(/^\s+|\s+$/, ""));
             }
         }
     } else {
-        log(fileMessage + " is " + ((colorize) ? color.green('OK') : 'OK') + ".");
+        output.push(fileMessage + " is " + ((colorize) ? color.green('OK') : 'OK') + ".");
     }
+    log(output.join('\n'));

     return lint.ok;
 };

flymakeは問題箇所の行・列とメッセージを1行に表示してやらないと面倒くさいので出力を変えます.

あと,なぜかcygwinから実行すると一行しか出力されないので,まとめて出力するように修正しています.

※変更前
 #1 Missing 'use strict' statement.
    $.exntend({ _MESSAGES: { // Line 4, Pos 3
 #2 Expected '$' at column 5, not column 3.
    $.exntend({ _MESSAGES: { // Line 4, Pos 3
 #3 Unexpected dangling '_' in '_MESSAGES'.
    $.exntend({ _MESSAGES: { // Line 4, Pos 15
 #4 Expected 'mail' at column 9, not column 5.
    'mail': '正しいメールアドレスの形式で入力してください', // Line 5, Pos 5
 #5 Expected 'required' at column 9, not column 5.
    'required': '入力が必要です', // Line 6, Pos 5
 #6 Too many errors. (1% scanned).
     // Line 6, Pos 5

※変更後
 #1 Missing 'use strict' statement. // Line 4, Pos 3
    $.exntend({ _MESSAGES: {
 #2 Expected '$' at column 5, not column 3. // Line 4, Pos 3
    $.exntend({ _MESSAGES: {
 #3 Unexpected dangling '_' in '_MESSAGES'. // Line 4, Pos 15
    $.exntend({ _MESSAGES: {
 #4 Expected 'mail' at column 9, not column 5. // Line 5, Pos 5
    'mail': '正しいメールアドレスの形式で入力してください',
 #5 Expected 'required' at column 9, not column 5. // Line 6, Pos 5
    'required': '入力が必要です',
 #6 Too many errors. (1% scanned). // Line 6, Pos 5

4. Emacs初期設定ファイル(.emacs/.emacs.d/init.el)にflymakeの設定を追加します.

(when (load "flymake" t)
  (defun flymake-jslint-init ()
    (let* ((temp-file (flymake-init-create-temp-buffer-copy
                       'flymake-create-temp-inplace))
           (local-file (file-relative-name
                        temp-file
                        (file-name-directory buffer-file-name))))
      (list "jslint" (list "--maxerr=20" "--nomen" "--browser" local-file)))) ; オブションは適当に変えてください。
  (setq flymake-err-line-patterns
        (cons '("\\(#.+\\) // Line \\([[:digit:]]+\\), Pos \\([[:digit:]]+\\)$"
                nil 2 3 1)
              flymake-err-line-patterns))
  (add-to-list 'flymake-allowed-file-name-masks
               '("\\.js\\'" flymake-jslint-init))
  (add-hook 'js-mode-hook
            (lambda ()
              (flymake-mode t))))

http://www.emacswiki.org/emacs/FlymakeJavaScript の「With jslint command line from node.js」のflymake-err-line-patternsを変更しています.

以上でWindows環境でもflymakeを使うことができます.

2011-02-13

TracのデータベースをMySQLからSQLiteに移行する方法

「MySQLでTracのプロジェクトを作成したものの、やっぱりSQLiteが良かった」という時に使えると思います。

ただし、データのみの移行です。Trac のレポートのカスタムクエリ などは SQLite 用の SQL に書きなおす必要があります。

データベースを拡張するプラグインを導入している場合や Trac のバージョンが異なる場合は失敗するかもしれません。

逆の SQLite から MySQL は以下のスクリプトから移行可能だと思います。

https://trac-hacks.org/wiki/SqliteToMySqlScript

  • MySQLのデータベースをバックアップ

下記コマンドを実行すると trac-dump.sql というバックアップファイルができます。下記リンクのスクリプトに少し手を加えています。

http://www.sqlite.org/cvstrac/wiki?p=ConverterTools の MySQL to SQLite3 (shell script)

mysqldump -u {接続ユーザ} -p -t --compatible=ansi --compact --compatible=ansi --default-character-set=binary {データベース名} \
| grep -v ' KEY "' | grep -v ' UNIQUE KEY "' | grep -v ' PRIMARY KEY ' | sed 's/ unsigned / /g' \
| sed 's/ auto_increment/ primary key autoincrement/gi' | sed 's/ smallint([0-9]*) / integer /gi' \
| sed 's/ tinyint([0-9]*) / integer /gi' | sed 's/ int([0-9]*) / integer /gi' \
| sed 's/ character set [^ ]* / /gi' | sed 's/ enum([^)]*) / varchar(255) /gi' | sed 's/ on update [^,]*//gi' \
| perl -e 'local $/; $_=<>;s/,\n\)/\n\)/gs; print "begin;\n";print;print "commit;\n"' \
| perl -pe 'if (/^(INSERT.+?)\(/) { $a=$1; s/\\'\''/'\'\''/g; s/\\n/\n/g; s/\),\(/\);\n$a\(/g; s/\\r//g; s/\\"/"/g; }' > trac-dump.sql
  • Trac プロジェクトを新規作成

SQLite を指定して作成する。

# trac-admin {ProjectID} initenv
  • DBバックアップファイルをインポート

作成したプロジェクトのdbディレクトリへ移動し、バックアップファイルをカレントディレクトリへ持ってきて SQLite の .read コマンドで読み込みます。

Trac プロジェクトの新規作成時に Wiki のデフォルトページがインポートされ、key制限でバックアップからインポートされないので必要があれば削除します。

そのままで良いのであれば DELETE 構文は必要ありません。

# cd {ProjectID}/db/
# cp /path/trac-dump.sql .
# sqlite3 trac.db
sqlite> DELETE FROM wiki;
sqlite> .read trac-dump.sql
  • 元のプロジェクトのDBを差し替える

元プロジェクトのディレクトリの直下に db ディレクトリを作成し、上でインポートした trac.db を配置します。

# cp trac.db /Project/Path/db/trac.db

更に、conf/trac.ini の trac セクションの database 項目を以下のように修正します。

database = sqlite:db/trac.db

2010-10-24

MultiLookup 更新情報

更新内容 (ver 0.3.0 から 0.3.8 まで)

もともと簡易のサニタイズ処理を行っていましたが、安全性を高めるため caja プロジェクトの html-sanitizer.js を利用してサニタイズ処理(script要素などの削除)を行うよう修正しました。

  • SITEINFO

content-selector, exclude-xpath, exclude-selector項目を追加しました。

    • content-selector

XHRで取得した結果から表示する部分をXPath指定するためのcontent-xpathのCSS Selectorバージョンです。

    • exclude-xpath, exclude-selector

XPathなどでは一部の不要な要素を除外するために指定します。*-xpath は XPathで、*-selector は CSS Selector で指定します。

更新前は選択中のサイトを種別ごとに出していただけでしたが、選択している文字列の言語と種別に一致するサイトの一覧を出すように修正しました。

言語と種別の条件はオプションページの「高度な設定」から変更可能することができます。言語についてはGoogle Translation APIを利用(選択)することで、条件を自分で追加せずにいろんな言語を判別することができます。

現在は、英語、日本語のみ種別の条件が設定されていますが、自分で追加することで他の言語でも他の種別のサイトも判別させることができます。

例1) 単語を選択した場合

f:id:jimo1001:20101024034705j:image

例2) 英文を選択した場合

f:id:jimo1001:20101024034903j:image

2010-10-22

Fast look up JP and EN ver. 2010.10.22

最近、数多くのスクリプトセキュリティ上の修正が入っていますが、

スクリプトも例外ではなく、修正を行ないました。

現在利用中の方は、以下URLから最新版にアップデートするかアンインストールを行ってください。

http://userscripts.org/scripts/show/12901

どのような問題かについては以下の記事にまとめられています。

http://subtech.g.hatena.ne.jp/mala/20101021/1287670869

修正内容は、同じの問題を抱えていたスクリプトと同様、他ドメインから取得したHTMLを、google-cajaプロジェクトのhtml-sanitizer.jsを利用してサニタイズ処理を行っています。

また、HTMLclass属性またはid属性はすべて接頭語を付加し、現在のページ上の同属性の名前と被らないように変更しました。

2010-10-21

Google Chrome 拡張機能で既に開いているタブを選択する方法

それっぽいメソッドが見当たらなかったので、強引にやってみました。それぞれのタブで現在表示しているURLで見分けてます。

chrome.tabs.updateの第二引数(updateProperties)にurlが無ければリロードしないっぽいです。

サンプル) 以下は拡張内のoption.htmlを開くソースコード

var url = chrome.extension.getURL("option.html"); // URIの先頭にスラッシュ(/)を付けてはいけない
chrome.tabs.getAllInWindow(null, function(tabs) {
    var exist = false;
    if (tabs && tabs.length > 0) {
        for (var i=0; i<tabs.length; i++) {
            var tab = tabs[i];
            if (tab.url === url) {
                chrome.tabs.update(tab.id, {selected: true});
                exist = true;
                break;
            }
        }
    }
    if (exist) return;
    chrome.tabs.getSelected(function (tab) { // カレントタブの右側に開く
        var properties = {};
        properties["url"] = url;
        if (tab !== undefined)
            properties["index"] = tab.index + 1;
        chrome.tabs.create(properties);
    });
});