Railsのログに出力されるパラメータやSQLを整形する
Railsのログに出力されるパラメータやSQLを整形してみた。開発中は便利かもしれない。
こんな感じになる。
詳細はこのコミットを参照。サンプルのアプリとしてRailsApps/rails3-bootstrap-devise-cancan · GitHubを使わせてもらった。
SQLの整形には、sonota/anbt-sql-formatter · GitHubを使った。
Parameterは、michaeldv/awesome_print · GitHubを利用してる。ap便利。
ActionController::LogSubscriberやActiveRecord::LogSubscriberでログ吐いてるメソッドをコピーしてきて猿パッチするしかうまいやりかたが思い付かなかったので、修羅の国の人もっといい方法あったら教えてください。
CLIでJSONの整形をする
curlとかで取ってきたJSONを整形して表示したかったのでググったらいい方法があったので。
unix - How to pretty-print JSON from the command line? - Stack Overflow
パイプで`python -mjson.tool`に渡すだけ。pythonすごい。
$ curl -s http://api.tumblr.com/v2/blog/david.tumblr.com/info\?api_key\=fuiKNFp9vQFvjLNvx4sUwti4Yb5yGutBN4Xh10LXZhhRKjWlV4 | python -mjson.tool { "meta": { "msg": "OK", "status": 200 }, "response": { "blog": { "ask": true, "ask_anon": false, "description": "\u201cMr. Karp is tall and skinny, with unflinching blue eyes and a mop of brown hair. He speaks incredibly fast and in complete paragraphs.\u201d \u2013 NY Observer", "name": "david", "posts": 4238, "share_likes": false, "title": "David\u2019s Log", "updated": 1364854166, "url": "http://www.davidslog.com/" } } }
もっと便利なjqというものを教えてもらった。
インストールしないと使えませんが jq stedolan.github.com/jq/ もいいっすよ。 RT @yuroyoro: 便利。pyhon便利 -> How to pretty-print JSON… : bit.ly/YPCyph
— Eiji Iwazawaさん (@iwazer) 2013年4月2日
jqは、jsonをparseしてsed/awk/grepみたいにfilterしたり加工したりできる。
jqだと、出力に色がついて幸せになれる。
`| jq '.' -C | less -R`で、色つきでlessで閲覧できて意識アセンションする。
Rubyで関数合成とかしたいので lambda_driver.gem というのを作った
Rubyで、Procやlambdaで関数合成できるようにしたかったので、lambda_driver.gemというのを作った。
内容的にはこの辺で書いたヤツをgemにした感じ。
- 「関数型Ruby」という病(2) - 関数合成 Proc#compose - ( ꒪⌓꒪) ゆるよろ日記
- 「関数型Ruby」という病(3) - カリー化(Proc#curry, Proc#flip) - ( ꒪⌓꒪) ゆるよろ日記
こんな風に、カッコよくコードが書ける。
require 'lambda_driver' # [:foo, :bar, :baz].map{|s| s.to_s }.map{|s| s.upcase } # [:foo, :bar, :baz].map(&:to_s).map(&:upcase) [:foo, :bar, :baz].map(&:to_s >> :upcase ) # => ["FOO", "BAR", "BAZ"] # [:foo, :hoge, :bar, :fuga].select{|s| s.to_s.length > 3} # => [:hoge, :fuga] [:foo, :hoge, :bar, :fuga].select(&:to_s >> :length >> 3._(:<)) # => [:hoge, :fuga]
このgemは、個人的に「こういう風に書けたらいいな」という感覚に基づいているので、可読性とかは、アレだ、言わせんな。
演算子についても、すでに定義されているものは上書きしないようになってるので安全ですよ?
あと、名前の由来は≪虚弦斥力場生成システム≫です。
Proc/lambda/Symbol/Methodへの拡張
- call
- compose
- with_args
- flip
- curry
Proc#
`Proc#<` は `Proc#call`へのaliasなので、Procの呼び出しは以下のように書ける。
f = lambda{|x| x.to_s } f < :foo # => "foo"
Proc#+@
Proc/lambda/Symbol/Methodに単項演算子+を適用すると、to_procを呼び出す。
+:to_s # => #<Proc:0x007ff78aadaa78> +:to_s < :foo # => "foo"
Proc#compose
関数合成は`Proc#compose`や`>>`, `<<` でできる。
`f.compose(g)`は、合成関数`lambda{|*args| f.call(g.call(*args)) }`を生成して返す。
f = lambda{|x| x.to_s * 2 } g = lambda{|y| y.length } h = f.compose g # => #<Proc:0x007ff78aa2ab2> h.(:hoge) # => "44" ( == f.call(g.call(:hoge)) )
`Proc#compose`は`<<` にaliasされている
f << g # => f.compose(g) f << g < :hoge # => "44" ( == f.call(g.call(:hoge)) )
`>>`は、Proc#compseをレシーバーを入れ替えて呼び出す。結果的に、`g.call(f.call(x))`になる
f >> g # => g.compose(f) f >> g < :hoge # => "8" ( == g.call(f.call(:hoge)) )
Proc#with_args
`Proc#with_args`は、2引数以降の引数を部分適用した関数を返す。
f = lambda{|x, y, z| [x, y, z]} h = f.with_args(:a, :b) # => #<Proc:0x007ff78a9c5ca0> h.(:c) # => [:c, :a, :b] ( == f.call(:c, :a, :b) )
`Proc#with_args`は`*`にaliasされている。
f = lambda{|x, y| [x, y]} f * :foo # => #<Proc:0x007ff78a987540> (== f.with_args(:foo) ) f * :foo < :bar # => [:bar, :foo] ( == f.with_args(:foo).call(:bar) )
Proc#flip
第1引数と第2引数を入れかえた関数を返す。結果の関数はカリー化される。
f = lambda{|x, y, z| [x, y, z]} h = f.flip # => #<Proc:0x007ff78a942fa> h.call(:a).call(:b).call(:c) # => [:b, :a, :c] (== f.curry.call(:b).call(:a).call(:b)) h < :a < :b < :c # => [:b, :a, :c] (== f.curry.call(:b).call(:a).call(:b))
`Proc#flip`を呼び出すProcが可変長引数の場合は、明示的にarityを指定してfilpを呼び出す必要がある。
arityが0または1ならば、何もせずに自身を返す。
p = Proc.new{|*args| args.inspect } p.arity # => -1 p.flip(3).call(:a).(:b).(:c) # => "[:b, :a, :c]" p.flip(4).call(:a).(:b).(:c).(:d) # => "[:b, :a, :c, :d]"
このメソッドは `~@` にaliaasされているので、Procに単項演算子`~`を適用することで呼び出すこともできる。
その際には、arityの指定はできない。
~f # => #<Proc:0x007ff78a8e22c> (== f.filp) ~f < :a < :b < :c # => [:b, :a, :c] (== f.filp.call(:b).call(:a).call(:b))
Symbol extensions
- to_method
Symbol#to_method
`Symbol#to_method`は、引数のオブジェクトに対してObject#methodを自身を引数に呼び出す関数を生成して返す。
単項演算子`-`にaliasされている。
(-:index).call("foobarbaz") # => #<Method: String#index> (-:index).call("foobarbaz").call("bar") # => 3 (== "foobarbaz".index(3) ) -:index < "foobarbaz" # => #<Method: String#index> -:index < "foobarbaz" < "bar" # => 3 (== "foobarbaz".index(3) )
Class extensions
`Class#instance_method`を `/`演算子で呼び出すことができる。これは、少しclojureを意識した。
String / :index # => #<UnboundMethod: String#index>
UnboundMethod extensions
`UnboundMethod#bind`を `<`演算子で呼び出すことができる。上記の`Class#/`と組み合わせるとカッコよく書ける。
String / :index # => #<UnboundMethod: String#index> String / :index < "foobarbaz" # => #<Method: String#index> String / :index < "foobarbaz" < "bar" # => 3 (== "foobarbaz".index(3) )
Object extensions
- obj.revapply(|>)
- obj._
- obj.disjunction(f)
Object#revapply
`Object#revapply` は、自身を渡された関数に適用する。Scalazの`|>`な。
revapplyという名前の由来はOCamlから。
f = lambda{|x| x * 2 } "foo".revapply(f) # => "fooffoo" (== f.call("foo") )
Object#_
`Object#_`は、オブジェクトからMethodオブジェクトを簡単に取り出すためのショートカット。
"foobarbaz"._.index # => #<Method: String#index> "foobarbaz"._.index < "bar" # => 3 (== "foobarbaz".index("bar") ) 2._(:>=) # => #<Method: Fixnum#>=> [1, 2, 3].select(&2._(:>=)) # => [1, 2]( = [1, 2].select{|n| 2 >= n})
Object#disjunction
`Object#disjunction`は、引数の関数に自身を適用した結果がnilでなければそれを返し、nilだったらレシーバーオブジェクト自身を返す。
f = lambda{|x| x % 2 == 0 ? nil : x * 2} 2.disjunction(f) # => 2 (disjunction returns reciever object) 3.disjunction(f) # => 6 (disjunction returns f(3) )
java-ja.dddの最後の「関数型言語Dis(?)」について
java-ja.ddd - connpass
2013/03/22 java-ja.ddd #java_ja #java_ja_ddd - Togetter
java-ja.ddd面白かったです。色々と得るものがありました。発表者の方々、有り難うございました。
会場を提供して頂いたGREEさんありがとう。運営のみなさまお疲れ様。
で、一番最後に、「関数型言語をDisって逃げる」ということで発表者の一人である増田亨さんがごく短い時間お話しされました。
その内容があまりにも自分にとって納得しかねるものだったので、ブログにアウトプットします。
「関数型言語Dis」の中で、増田さんがされた主張は以下2点です。
関数型言語が、どの言語を指しているのかがまず不明ですが、そこは置いておいて。
まず一点目、「関数型言語ユーザーは業務の話ができない」について。
関数型言語ユーザー全員を指して、「業務の話ができない」という主張の根拠はそもそもどこにあるのでしょうか?
逆に「オブジェクト指向言語のユーザーは全員が業務についても堪能である」と一般化して主張してもよいのですか?
また、話の中で「関数型言語使いが書いた素晴らしいロジックを見たことがある」ともおっしゃっており、主張が一貫していません。
たまたま増田さんの周りの関数型言語ユーザーが業務について(そもそも業務ってなによ?ってのもあるけど)話ができないとしても、それを一般化して主張することの是非については、論ずるまでもないと思われます。
次に、「関数型言語は記号を多用しすぎる」について。
これについては、記号を多用することの弊害について踏み込んで語られておらず、単に「記号使いすぎるからねーハハハ」で終わっていて、「ああ、この人は記号が嫌いなんだな」ということは理解できても、そもそも関数型言語に対するDisにすらなっていないのが残念です。
記号を多用する言語(おそらくHaskellやScalaあたりの言語を指していると思われる)のユーザーにとっては、
記号で記述した方が自然で、同じ言語ユーザーに対してコードの意図を示しやすいことがあるという一面があります。
論理演算子(&&や||)は記号ですが、それを指して「記号だからダメだ!andとかorとかで書け!」という主張をする人は稀でしょう。
にも関わらず、関数型言語を使わない人がその記号の使い方について問題を感じるとしたら、そのような感覚を身につけているユーザーの母数が少ないとか、初学者に対して敷居が高いとか、ググラビリティが低いとかいう指摘になるでしょう。そこまでつっこんで話を聞くことができれば良かったのですが。
ともかく、短い時間でのお話で、議論にまで昇華できなかったのが残念でなりません。
機会があれば、双方の主張を議論しあえる場で、非関数型言語ユーザーから見た現状の関数型言語に対する問題点を提示して頂ければ、と思います。
一時的にブランチを切り替えてコマンドを実行するgit-switchっての作った話
gitで、一瞬だけ他のブランチに切り替えてコマンド実行したいときに毎回checkoutとかすんのタルいし、workspaceに変更があったらgit-nowしたりstashしたりしないとブランチ切り替えられなくてタルいので、一時的に他のブランチに切り替えて指定したコマンドを実行するラッパーを書いた。書いた。
dotfiles/bin/git-switch at master · yuroyoro/dotfiles · GitHub
git switch [--repository=<path>] [--new-workdir=<path>] <branch> <command...>
`git switch foo_master git show`ってやると、fooブランチに切り替えて`git show`を実行する。コマンドは別になんでもいいので、`git switch hogehoge rspec spec/hoge_spec.rb`のように、他のブランチでrspec流したり可能です。
以下は、一時的にcomposable_procに移動してgit show -sを実行した様子。
ozaki@mbp-4 ( ꒪⌓꒪) $ git br composable_proc * trunk ozaki@mbp-4 ( ꒪⌓꒪) $ git switch composable_proc git show -s Already on 'composable_proc' commit 20c1b806490233db0467ac4332ba073edca7889f Author: Tomohito Ozaki <ozaki@yuroyoro.com> Date: Sun Mar 10 02:34:12 2013 +0900 proc.c: Add Proc#flip
内部的に、git-new-workdirを使っているので、以下を参考にgit-new-workdirが使えるようにしておく必要があるです。
git-new-workdir が便利 - #生存戦略 、それは - subtech
デフォルトの動作では、/tmp以下に現在のリポジトリと同じディレクトリ名でgit-new-workdirして、そこでコマンドを実行するようになっている。すでにnew-workdirする先が存在する場合は再利用する。
workdirはオプション'--new-workdir=
注意点として、gitのコマンド実行とシグナルハンドラの関係上、シグナルをもらうプロセスがforkされるようなコマンドの実行には注意する必要がある。例えば、pryはCTRL-CによるSIGINTをtrapするが、fork元のgitプロセスはSIGINTでプロセスを終了する。そのため、git-switchではSIGINTをトラップして、forkしたコマンドの子プロセスを頑張ってぬっころすように実装している。このへんうまいことやる方法知りたい。
ワークライフバランス()向上のために定時すぎたらダイアログが表示されるようにした
仕事してると、ついつい「このバグ直した帰ろう」とか「このテストが通ったら帰ろう」とかやってるうちにいつの間にか終電近くまで作業していて( ꒪⌓꒪)ってなることが多いので、定時すぎたら一時間毎にムカつく心温まるメッセージを表示するようにAppleScript書いた。
20時から24時までの一時間毎に、こんな感じで唐突にメッセージが表示されてフォーカスを奪っていき、ワークライフバランス()の改善を促し精神に負荷をかける。
set hour to hours of (current date) try tell application (path to frontmost application as text) if hour = 20 then set msg to "( ꒪⌓꒪) もういい時間だしさっさと帰れよカスwww" display dialog msg else if hour = 21 then set msg to "( ꒪⌓꒪)おいダラダラ作業してんじゃねーよwwwクズがwww" display dialog msg else if hour = 22 then set msg to "こんな時間まで作業してるとかwwww生産性m9( ꒪⌓꒪)" display dialog msg else if hour = 23 then set msg to "( ꒪⌓꒪)そろそろ帰宅難民なんじゃね?社蓄乙www" display dialog msg else if hour = 24 then set msg to "( ꒪⌓꒪)なにムキになって仕事してんの?社蓄www" display dialog msg end if end tell end try
Script Editor.appでこんなの書いて、~/bin/fxxk_it_alert.scpt ってファイルで保存。次に~/Library/LaunchAgents/fxxk_it_alert.plistを以下の内容で作成した。
cronだと簡単に設定できるところをクソみたいな長大なxmlを書かねばならず、launchd の StartCalendarInterval はクソだという結論を得た。
設計を型にエンコードするということ
動的型付け vs 静的型漬けのアレでもんにょりしてたのをついったーに放出して会話してたらなんとなく自分なりの考えがまとまったので貼っておく。
……(ファントムタイプとか型安全ビルダーパターンとかで、型レベルにロジックをエンコードした結果、ライブラリ利用者がテストを書くまでもなく適切にライブラリを利用できるようになる、という意味での「静的型でコンパイラは最強のテスティングフレームワーク」という視点があると思う)
— 蒸発プログラマさん (@yuroyoro) 2013年3月11日
@yuroyoro 最初のメジャーなテスティングフレームワークがJUnitなので違和感を感じます。
— ぎゃばんぱみゅぱみゅさん (@ledsun) 2013年3月11日
@ledsun メジャーかそうでないかで言われると反論しようがないですが、捉え方というか視点として、ビジネスロジックを型レベルにエンコードして、テストの手前(コンパイラ)でチェックしようという思想があるという話です。
— 蒸発プログラマさん (@yuroyoro) 2013年3月11日
@ledsun @ledsun 例えば、型安全ビルダーパターンを使えば、ビルダーパターンでのメソッド呼び出し順を型レベルでチェックさせることができるので、そのビルダーを利用者が適切な順序で呼び出しているかコンパイラにチェックさせることができます。
— 蒸発プログラマさん (@yuroyoro) 2013年3月11日
@ledsun さきほどのビルダーパターンの例では、利用者がテストを書いて確認するところを、一足前にコンパイラがチェックしてくれるので、ライブラリの使い方を間違ってしまう心配がなくなります。実例として、ScalaでのMongoDBライブラリのRogueがこのようなことをしています
— 蒸発プログラマさん (@yuroyoro) 2013年3月11日
@yuroyoro なるほどそんな考え方があるんですね。ビルダーパターンはライブラリーやフレームワーク作る人からするとすごくありがたい機能に思えます。一方、すべてのアプリケーションプログラマが使いこなすのは難しそうなので、流行るのかどうか心配です。
— ぎゃばんぱみゅぱみゅさん (@ledsun) 2013年3月11日
@ledsun 現時点では、このような手法はなかなか受け入れられる環境ではないと思いますが、言語やツールが進化して敷居がさがればいいなーと思います。例えば、多相型(Generics)などは色々な言語に取り入れられ認知もされつつあり、この方向での言語の進化は確かにあると感じます
— 蒸発プログラマさん (@yuroyoro) 2013年3月11日
「最後にこの言葉を送る。
guud rack【グッドラック】
俺の好きな言葉だ。」
— 蒸発プログラマさん (@yuroyoro) 2013年3月11日
まとめると
- コンパイラがテストしてくれるように型を書きたい
- 型に対して、データ型のラベル以上の意味(設計の意図とか)を持たせたい
- そうすると、自分以外の人が自分が書いたコードを使うときに、正しい使い方を自分やドキュメントに代わって、コンパイラが教えてくれるようになる
- そういうことが簡単にできるように言語とか進化するといいよね
現実的になんでもかんでもコンパイラにやらせようとすると難しいところもあると思う。
「アカデミックだ」「現場では使えない」とか単に否定するのは簡単だ。
静的な型漬けの言語でコード書いたからって、上記のようにすべてのロジックを型レベルにエンコードすることなど不可能だし、制約が強すぎると感じるかも知れないし、この制約が逆に足かせになる性質のプロダクトがあることもわかっている。
でも、型推論とかGenericsとかは、アカデミックな研究と実用のニーズが相まって、
現実のプログラミング言語に取り入れられつつあるし、
静的な型漬けを好む人達が見据えているプログラミング言語の進化の方向性として、こういう考え方がありますよ、って知って欲しい。