Rubyでオブジェクトのスーパークラスを遡って取得する

Rubyでクラスの親クラスを取得するには、Class#superclassを使えばよいという事を知った。 なので、BasicObjectまで遡れば継承している全ての親クラスを取得することができる。

\ ruby class Foo end

class Bar < Foo end

class Hoge < Bar end

class Class def all_superclass def recur(c, a) return !c.superclass ? a : recur(c.superclass, a.push(c.superclass)) end recur(self, []) end end

p Hoge.all_superclass \

実行結果はこう。

sh
$ ruby ./get_all_superclass.rb
[Bar, Foo, Object, BasicObject]

任意のクラスを継承しているか判別するのに使えると思う。

Linuxでアクティブなアプリケーションを記録&可視化した

FluentdとGrowthForecastを使って自分の行動をロギング・可視化する -すぎゃーんメモ を見て、自分もやりたくなったのでやった。 上記リンクと違うのは、アクティブなアプリケーションを取得する箇所のみ。 Linuxだと、xpropというコマンドを使ってXの状態を取得できる。

なので、まずは今アクティブなウィンドウのIDを取得。

bash
xprop -root _NET_ACTIVE_WINDOW | awk '{print $5}'

次に、取得したIDを使ってアクティブなウィンドウの情報を取得する。 今回はウィンドウのクラスを取得した。 他にもいろいろな情報を得られておもしろそうなので時間を作って遊んでみたい。

bash
xprop -id ${取得したID} WM_CLASS | awk '{print $4}' | tr -d '\"'
これらをワンライナーにしてfluentdの設定に組み込んだのが下記である。 DISPLAY環境変数の設定を行っているのは、fluentdを実行しているfluentユーザからディスプレイを参照できなかったため。 今はmongodbとGrowthForecastに投げている。なかなかおもしろい。

html
<script src="https://gist.github.com/takaishi/6bcefcd3e43f5779fc15.js"></script>

GNUプロジェクトの一つにパッチを送って取り込まれるまでの話

昨年末にorg-mode(Emacs拡張)に対して送ったパッチが今日無事に取り込まれ たのでその記録を書いておきます.

パッチを送るの巻

org-modeにはEmacs外部からアクセスするためのorg-protocolという機能があっ て,これを使えばFirefox等からorg-modeにURLを送りつけたりできる.これに ついて機能追加をするべく,2012-12-31にパッチを送信した.

で,メンテナから「取り込みたいけど,君は既にTINYCHANGESな変更を一度し ているので,FSFに著作権譲渡してね」と言われた.FSFについての話は検索するなり してくれればよいと思う.とにかく,パッチを取り込んでもらうためにFSFに 対して著作権を譲渡するための書類を送る必要があるということ.

FSFに対してメールを送るの巻

さて,書類を送るためにまずはFSFにリクエストのメールを送るわけだが,org-modeはなかな親切なもので,How to contribute to Org? にどうやればいいか書いてあった. ありがたいことにメールのテンプレートまで用意してくれている. これに必要な事項を書いて送信.これが年始の話である.

assignment paperを郵送するの巻

しばらくして,FSFからPDFが送られてきた. これにサインをして,郵送しろとのこと. 海外に何かを送るのは初めてだったので妙に緊張してしまった. たぶん気にしていたのは自分だけだと思うが,送られてきたPDFはレターサイズだが,A4の紙に印刷して送っても問題ないようだ.

また,送る際に一つ失敗した.自分が郵送するのに使ったのは普通のエアメールだったのだけど,これがよくなかった. 向こうに到着した後,手違いでこちらに連絡が届いていなかったのだけど,僕は郵送途中で紛失したかそれとも船便になってしまって時間がかかっているのか,と思っていた. 送料はかかるが,追跡が可能なEMS(国際スピード郵便)を使うのが良いだろう.

パッチの取り込み

後はとんとん拍子といったところで,パッチをリポジトリの先端に対して作りなおして送信,微修正ののちに取り込まれた. GithubのPullRequestとは違い,なかなか手間がかかったがうれしい限りである.

一連の流れを見ると,やはりPullRequest方式は非常に便利だと思う. MLにパッチを送る方式の場合,git format-patchやgit amを使ってやりとりをするのだけど,これがなかなか難しかった. 慣れてしまえば何ということはないのだろうが,初めて送る時はハードルが高い.

参考

パッチを送るにあたり,以下の記事を参考にした.感謝.

追記

このページも参考になる

ClojureScriptでRDBを使ったアプリを作成する(その1)

アプリ作成

Clojure + ClojureScript + SQLiteの組み合わせで、タスク管理アプリを作成します。 まずはプロジェクトを作成します。。clj-templateを使って楽をしましょう。

bash
lein new clj-template tasks

project.cljを編集します。clojureのバージョンを1.4にしたり、必要なパッケージを追加したりしています。

diff
diff --git a/project.clj b/project.clj
index 799322c..99e588b 100644
--- a/project.clj
+++ b/project.clj
@@ -1,11 +1,15 @@
(defproject tasks "0.1.0-SNAPSHOT"
:description "FIXME: write this!"
:url "http://exampl.com/FIXME"
- :dependencies [[org.clojure/clojure "1.3.0"]
+ :dependencies [[org.clojure/clojure "1.4.0"]
[noir-cljs "0.3.0"]
[jayq "0.1.0-alpha1"]
[fetch "0.1.0-alpha2"]
[crate "0.1.0-alpha3"]
- [noir "1.3.0-beta2"]]
+ [noir "1.3.0-beta2"]
+ [enfocus "1.0.0-beta1"]
+ [org.clojure/java.jdbc "0.2.3"]
+ [org.xerial/sqlite-jdbc "3.7.2"]]
+ :plugins [[lein-cljsbuild "0.2.8"]]
:cljsbuild {:builds [{}]}
:main ^{:skip-aot true} tasks.server)

DB操作

DBを操作するためのコードを書きます。

diff
diff --git a/src/tasks/models/db.clj b/src/tasks/models/db.clj
new file mode 100644
index 0000000..796730b
--- /dev/null
+++ b/src/tasks/models/db.clj
@@ -0,0 +1,32 @@
+(ns tasks.models.db
+ (:require [clojure.java.jdbc :as sql]))
+
+(def db
+ {:classname "org.sqlite.JDBC"
+ :subprotocol "sqlite"
+ :subname "db/database.db"
+ })
+
+(defn init-db []
+ (try
+ (sql/with-connection db
+ (sql/create-table
+ :tasks
+ [:id "integer primary key"]
+ [:title "varchar(250)"]
+ [:status "varchar(10)"]
+ ))
+ (catch Exception ex
+ (.getMessage (.getNextException ex)))))
+
+(defn add-task [task]
+ (sql/with-connection db
+ (sql/transaction
+ (sql/insert-record :tasks task))))
+
+(defn get-all-task []
+ (sql/with-connection db
+ (sql/transaction
+ (sql/with-query-results result
+ ["SELECT * FROM tasks"]
+ (into [] result)))))

データベースとテーブルを作成して、レコードの追加を取得を行ってみます。 database.dbを配置するためのdbディレクトリを、プロジェクトのルートディレクトリにあらかじめ作成しておく必要がある事に注意してください。

bash
$ lein repl
nREPL server started on port 35663
REPL-y 0.1.0-beta10
Clojure 1.3.0
Exit: Control+D or (exit) or (quit)
Commands: (user/help)
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
(user/sourcery function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Examples from clojuredocs.org: [clojuredocs or cdoc]
(user/clojuredocs name-here)
(user/clojuredocs "ns-here" "name-here")
tasks.server=> (use 'tasks.models.db)
nil
tasks.server=> (init-db)
(0)
tasks.server=> (add-task {:title "buy milk"})
{:last_insert_rowid() 1}
tasks.server=> (get-all-task)
[{:status nil, :title "buy milk", :id 1}]
tasks.server=> (add-task {:title "send a mail"})
{:last_insert_rowid() 2}
tasks.server=> (get-all-task)
[{:status nil, :title "buy milk", :id 1} {:status nil, :title "send a mail", :id 2}]
tasks.server=>

DBとのやりとりをマップで行うのはとても楽だと思います。 これで、replからDBにタスクを登録できるようになりました。 次はビューを作成して、ブラウザからタスクを登録してみます。

ビュー作成

\ diff diff --git a/src/tasks/views/main.clj b/src/tasks/views/main.clj index 6e69e7c..a6a751b 100644 --- a/src/tasks/views/main.clj +++ b/src/tasks/views/main.clj @@ -1,8 +1,17 @@ (ns tasks.views.main (:require [tasks.views.common :as common]) (:use [noir.core :only [defpage]] - [hiccup.core :only [html]])) + tasks.models.db + noir.fetch.remotes + hiccup.form))

(defpage "/" [] - (common/layout - [:div#content])) + (common/layout + [:h2 "Add Task"] + [:div {:id "add-task"} + (text-field {:class "title"} "title") + [:button {:class "submit"} "Submit"]])) + +(defremote add-task-to-db [task] + (add-task task) + (println (get-all-task))) \

ここで登場したdefremoteは、[[https://github.com/ibdknox/fetch][ibdknox/fetch]] というライブラリで定義されています。 fetchは、クライアント/サーバ間のやりとりを簡単にするためのライブラリです。 add-task-to-dbは、クライアントからタスクを受け取ると、それをDBに追加します。 最後に、クライアント側のコードを書く。クライアント側はClojureScriptを使います。 ここで使っている [[https://github.com/ckirkendall/enfocus][ckirkendall/enfocus]] は、DOMとテンプレートを扱うためのライブラリです。 Clojure用の[[https://github.com/cgrand/enlive][cgrand/enlive]] にインスパイアされたものらしいです。

\ diff diff --git a/src/tasks/client/main.cljs b/src/tasks/client/main.cljs index dddf7d5..f48672d 100644 --- a/src/tasks/client/main.cljs +++ b/src/tasks/client/main.cljs @@ -1,9 +1,14 @@ (ns tasks.client.main (:require [noir.cljs.client.watcher :as watcher] [clojure.browser.repl :as repl] - [crate.core :as crate]) + [crate.core :as crate] + [enfocus.core :as ef] + [fetch.remotes :as remotes]) (:use [jayq.core :only [$ append]]) - (:use-macros [crate.macros :only [defpartial]])) + (:use-macros [crate.macros :only [defpartial]]) + (:require-macros [enfocus.macros :as em] + [fetch.macros :as fm])) +

;;************************************************ ;; Dev stuff @@ -23,3 +28,19 @@

(append $content (up-and-running))

+(defn get-task-title [] + (em/from (em/select ["#title"]) (em/get-prop :value))) + +(defn get-task-data [] + {:title (get-task-title) + :status "unfinidhed"}) + +(defn push-task [] + (fm/remote (add-task-to-db (get-task-data)))) + + +(em/defaction setup [] + [".submit"] (em/listen :click push-task)) + +(set! (.-onload js/window) setup) +
\

get-task-titleは、フォームに入力されたテキストを取得する関数です。 get-task-dataで呼び出しています。get-task-dataは入力された値からタスクを生成します。 push-taskで、クライアントからサーバへタスク登録のリクエストを送ります。 fm/remoteで、サーバ側の関数を実行している。実装がどうなっているのか、一度見てみたい所ですね。 setupは、ボタンをクリックした時のイベントを定義します。

これで、ブラウザからDBにタスクを登録できるようになりました。

ブラウザから操作する

lein runを実行し、ブラウザのhttp://localhost:8090 にアクセスします。 フォームに適当な文字列を入力し、SbmitをクリックするとDBに登録されます。 add-task-to-dbで、タスクを登録した後にDBの全てのタスクをコンソールに出力しているので、それを見れば登録されていることが確認できますね。

<code>\</code> bash $ lein run 09:31:56 :: Using source dir: src/ WARNING: filter already refers to: #'clojure.core/filter in namespace: enfocus.macros, being replaced by: #'enfocus.macros/filter WARNING: delay already refers to: #'clojure.core/delay in namespace: enfocus.macros, being replaced by: #'enfocus.macros/delay 09:31:57 :: Files updated :simple 2012-11-14 09:31:57.065:INFO::Logging to STDERR via org.mortbay.log.StdErrLog09:31:57 :: Simple compile Starting server... Server started on port [8090]. You can view the site at http://localhost:8090
<h1></h1>
2012-11-14 09:31:57.066:INFO::jetty-6.1.25 2012-11-14 09:31:57.093:INFO::Started SocketConnector@0.0.0.0:8090 09:32:00 :: Done [{:status nil, :title buy milk, :id 1} {:status nil, :title send a mail, :id 2} {:status unfinidhed, :title aaa, :id 3}] [{:status nil, :title buy milk, :id 1} {:status nil, :title send a mail, :id 2} {:status unfinidhed, :title aaa, :id 3} {:status unfinidhed, :title bbb, :id 4}]
\

ClojureScript所感

サーバサイドとクライアントでほぼ同じ構文を使えるのはとても楽です。 fetchを使えば、クライアントからサーバ側の関数をほとんど違和感なく呼び出すこともできます。 何より、書いていて楽しいのが良いですね。 ただ、あまり良くないのかな、と思う所として、デバッグがやりにくい点があります。 いいやり方があるのかもしれないけど、どこでエラーが発生しているのかいまいち把握しづらいと感じます。 また、構文が似ているだけあって、ライブラリの非互換性が残念です。 うっかり、ClojureScriptでClojureのライブラリを呼び出そうとしてしまいそうです。

次回は、DBからデータを取得し、画面に表示したりしてみようと思います。

Org-mode 7.9.1の新機能(Org Agenda編)

org-mode 7.9.1の新機能、Agenda編です。

変数:org-agenda-sticky

Agendaを付箋のように扱うためのオプションです。
従来のAgendaは、qキーを押すとアジェンダバッファが削除されていました。 org-agenda-stickyを有効にすることで、アジェンダバッファが削除されなくなります。 e2wmを使う時、特定のウィンドウにアジェンダを表示しっぱなしにするために使えそうです。

org-agenda-custom-command-contexts

アジェンダコマンドのコンテキストを設定します。
org-capture-template-contextsと同じように設定すればOKです。
下記の例だと、”p”コマンドはtxtファイルの中でしか使用できません。
(setq org-agenda-custom-commands-contexts
‘((“p” (in-file . “.txt”))))

bulkアクションの変更

kから始まるコマンドは削除され、”バルクアクション”と統合されました。

アジェンダで複数のエントリをマークした後、B sを実行することでタスクをリスケジュールできます。

ポイントが日付の上にある時にkを実行することで、その日付で上書きされたキャプチャが実行されます。

NとPを押すことでアイテムを上/下に移動できるようになりました

コマンド:org-agenda-bulkmark-all

全てのアイテムをマークします。 一括して削除やアーカイブしたい場合に便利ですね。

変数:org-agenda-persistent-marks

有効にすることで、バルクアクションを実行した後もマークが有効なままとなります。

バルクアクションでTODOステータスを間違えて変更した場合等に使えそうです。

org-agenda-skip-timestamp-id-deadline-is-shown

todo-unblocked と nottodo-unblocked

org-agenda-skip-ifという、

アジェンダをカテゴリでフィルタできる