CoffeeScriptつかいはじめてみた
Javascriptの何がつらいって、ローダーがないとか色々あるけど、個人的にはOOPが辛い事だとおもうんですよね。*1
まあ、1日以下で書けるような物ならいらないけど、今ちょっとだけややこしいWebアプリを書いてて、やっぱクラスとか使いたくなっているわけですよ。
ということで、今日から真面目にCoffeeScriptを使い始めた。
使い方について、色んなサイトに載ってるんだけど、実際の所、別にnode.jsとかいれなくても
<script type="text/javascript" src="lib/coffee-script.js"></script> <script type="text/coffeescript" src="lib/test.coffee"></script> <script type="text/coffeescript"> alert 1 </script>
とか書いておけば動くので、当座これでいいんじゃないの。
最終的なデプロイ時には速度的にもったいないのはわかるし、デバッグもちょっとだけ辛いんだけど(動的に生成されたJSコードはMinifyされてて、デバッガが使えない…)、まあ、ちょっとだけ書く程度ならIEでJS書いてると思えばいい程度だし…。
ただ、を後からwriteとかIncludeしたりとかしてはやそうとしても無理。これはちょっと残念。
- -
class JsonData loadFromUrl:(url) -> @loadingStartFunc data = $.ajax({ url: url, cache: false, dataType: 'text', }).success( @loadingSuccessFunc(this) ).fail( @loadingFailFunc ).always( @loadingEndFunc ) ## class List extends JsonData data : {} sourceUrl: LISTS_JSON_URL constructor: () -> @loadingStartFunc = -> #console.log 'start' @loadingFailFunc = -> #console.log 'fail' @loadingEndFunc = -> #console.log 'end' @loadingSuccessFunc = (_this) -> (json)-> _this.data = eval(json) $('#src_list_ul').trigger('e_reload_list') @load() reload:() -> @loadFromUrl(@sourceUrl) load:() -> @data = [] # TODO load from local database. getData:() -> @data ## @List = List
Pythonと一緒で、インデントでブロックわけするのは個人的には微妙なんだけど、多分慣れだろうなー。
でもまあ、CoffeeScript良い感じですね。
今回モデル的な所だけはCoffeeで書こうかなーっておもってますよ、はい。
最後の行の
@List = List
については、CoffeeScriptはスコープがガチガチで、1ファイル(1Scriptエレメント)の外には、通常何も投げ出すことができないので(いわゆるグローバル汚染がウッカリでできない)、本来はどうやるのが普通なのかしらないんだけど、これでwindow.Listに、作ったListクラスを適当にはやしている。
@はthis.に相当し、CoffeeScriptの一番上位でのthisはwindowにあたる。
window.myClass.Listとかにすべきかなーとかまあ色々思うんだけど、そもそも正しい解決策が知りたい。
あと、for inの書き方で、
addCell src for src in list.getData()
…いまいちよくわかんない、これなんでsrc二つあるの…。
冷蔵庫買ったんですよ、400L以上の冷蔵庫ってでかいですね。
それはさておき、やっとConfig::Pitつかうようになりましたよ。こいつぁ便利ですね、Windowsだと使い物にならない気もするけど。(EDITOR環境変数的に)
#!perl # usage # perl this.pl < unfollow_id_list.txt use Net::Twitter; use Config::Pit; use Data::Dumper; use feature say; # config my $config = pit_get("twitter.com_oauth_uzulla" , require => { "consumer_key" => "req", "consumer_secret" => "req", "ACCESS_TOKEN" => "req", "ACCESS_TOKEN_SECRET" => "req", }); die 'pit_get failed.' if !%$config; my $consumer_key = $config->{consumer_key} or die 'consumer_key not found.'; my $consumer_secret = $config->{consumer_secret} or die 'consumer_securet not found.'; my $ACCESS_TOKEN = $config->{ACCESS_TOKEN} or die 'ACCESS_TOKEN not found.'; my $ACCESS_TOKEN_SECRET = $config->{ACCESS_TOKEN_SECRET} or die 'ACCESS_TOKEN_SECRET not found.'; #setup twitter my $t = Net::Twitter->new( traits => [qw/OAuth API::REST/], consumer_key => $consumer_key, consumer_secret => $consumer_secret, access_token => $ACCESS_TOKEN, access_token_secret => $ACCESS_TOKEN_SECRET, ); #do while(<>){ $id = $_; say $id; my $res ; eval { $res = $t->destroy_friend($id) }; warn "$@\n" if $@; }
なんかNet::Twitter::Liteでdestoroy_friendがうまくうごかなかったんですよね。
Net::Twitterいれたらうごいたんですけど。
でもNet::Twitterも何回かやってたらうごいてないような見え方したし。
TwitterのAPIは、特にフォローアンフォロー周りでよくわからない挙動するので(特に遅延)イヤですねえ…。
- -
あと、Date::Parseを初めてしりましたね。
use Date::Parse; use DateTime; my $created_at_time = str2time('Thu Dec 09 11:59:52 +0000 2010'); $dt = DateTime->from_epoch(epoch => $created_at_time); say $dt->ymd('/'); # -> 2010/12/09
PHPではstrtotimeってすごい便利な関数(大抵の時刻フォーマットテキストを、UNIX秒にもどしてくれる)があるんですけど、まさにそれですね。
いやこれ本当にないとぼくは目から血が噴き出して死ぬんですが、やっとみつけたわー。
きっとDateTime周りにあるんだろう…いつかは見つかるだろう…と思いつつ、いつも頑張ってパースしてたんですけど、そんなところじゃなかったんですねえ…。
Hachioji.pm #10開催しましたね。
厚顔にも、YAPCで皆さんに宣伝してもらった効果すごいな!#10は16人中、新顔6人に参加いただきました。
https://plus.google.com/photos/114651309588721895816/albums/5669355651295732737
#10について、私の悪筆を尽くす事もできますが、この楽しげな風景で全てが物語られていますね(手抜き)。
詳しいレポートはその内 http://hachiojipm.org にまとまることでしょう…(さらなる手抜き)。
(「レポをつくるのだ、作らないと俺が血を吐いて死ぬ!」などといった、脅しにもとれる酷い要求をしたところ、今回は皆様に一層書いて頂けました、主催は涙が止まりません。)
いやとても楽しかった!皆さん++!有り難うございました!
ーー
次回Hachioji.pm #11 @Machidaはすごい多くて、現在で21人ですよ、もう今後Machidaでやればいーんじゃねーの?!
http://atnd.org/events/20693
そうそう
元々八王子地元のエンジニアを!っておもってたんですけど、キイロさん(@yellow844)が八王子で、これでついに八王子4人目ですよ!(あれ?5人目?)
やっぱりいるじゃないか、八王子にも。だれだ八王子なんかにはいないと言っていた人は!
今日もPerl、Net::FTPでサーバー内のファイルを全部リスト出力する
仕事で大量にあるサーバーの中身をクロールしてファイル数などを勘定する必要があったので。
正直Getopt::Longのちゃんとした使いかたがわかってない。無駄な使われ方もいい所。
@tomitaさんのCPAN本の書き方だとなぜかエラーになったなー…。
#!perl # perl c.pl --h='great.website.com' --u='famous_username' --p='super_strong_pass' --b='/htdocs' > file.list use Net::FTP; use warnings; use strict; use feature 'say'; use Getopt::Long; use Data::Dumper; my $opt = { h=>'localhost', u=>'web', p=>'pass', d=>'/htdocs', }; GetOptions($opt, qw/h=s u=s p=s b=s/) or exit 1 ; my $HOSTNAME = $opt->{h}; my $USERNAME = $opt->{u}; my $PASSWORD = $opt->{p}; my $BASE_DIR = $opt->{b}; my $ftp = Net::FTP->new($HOSTNAME, Debug => 0) or die "Cannot connect: $@"; $ftp->login($USERNAME, $PASSWORD) or warn("Login Error!\n"); listing($ftp, $BASE_DIR); $ftp->quit; sub listing{ my ($ftp, $dirname) = @_; say $dirname ."/" ; $ftp->cwd($dirname); my @dir = $ftp->dir; my @file_names = grep /^\-/, @dir; my @file_names_full = @file_names[2..$#file_names]; my @file_names_short = map { (split)[8] } @file_names_full; foreach(@file_names_short){ say " " x length($dirname), "+". $_; } my @dir_names = grep /^d/, @dir; my @dir_names_full = @dir_names[2..$#dir_names]; my @dir_names_short = map { (split)[8] } @dir_names_full; foreach(@dir_names_short){ listing($ftp, $dirname."/".$_); } $ftp->cwd($dirname); }
あれだよね、やっぱ @list = grep /^d/ @fromlist; とか say " " x $num ; っていいよね。phpでコレ書くのforで回すのかよって感じになるし。
まあ、こういうの使わないほうが、他人に渡す時(5年後の自分含む)読めるんだけどさ…
mixiアプリで、IDの仕様が変わったから変換するって作業
すっごい放置してたんだけど、もう月末には締切だよ!って感じなので対応をしたね!
概要
どこにもズバリズバズバな説明が書いて無いからなかなか弱ったんだけど、
「opensocial_owner_idは前は数字やったけど、こんどは英数字13文字になるから!*1変換してよ!一対一で差し替えるだけだから!」
というそれだけの話でしたね。いやそれだけの話なのに、HOWTOみたいなのが記載ないってどういうことや。(俺だけだったのかなあ…、一発で分からなかったの)
具体的な作業
とりあえずアプリ設定画面にいって、変換API叩くよーって申請すると新IDを引く為の用意ができるから、
手元にあるであろうopensocial_owner_idをキーにして、すっごいガンガンAPI叩いて、対応する新IDを取得していく。
APIにアタック^H^H^Hクセスする速度は特に注意書きされてなかったので、ウェイトとかいれなかった!
そんで全部とれたら、既存のopensocial_owner_idと差し替えて、再度アプリ設定画面にいって、変換作業おわったよーってボタンを押す。
すると完了やで!
さらに具体的なツール(二度と使わないけど、メモ)
YAPC直後でPerl熱が高まっているので、Perlで書きましたね。
Prepared Statementで名前付きプレースホルダつかいたかってんけど、
普段使ってる ゆるふわPDOとはちょっと書き方ちがったので、面倒で?、?って感じですね。
ーー
DBのスキーマ的には
userという名前のテーブルがあって、
id <= 連番
owner_id <= opensocial_owner_idでとれるやつ
new_owner_id <= 新しく差し替えるopensocial_owner_idをALTERで追加しとく
という想定。
あ、new_owner_idは、後述しますけどひけない事が大量にあるので、Uniqueは後でかけたほうがいいでしょうね。
引けなかったデータを捨てるか、整合性の為にうめごろしするかは自由かなと。
ーー
#!/usr/bin/perl use 5.0.8; use strict; use warnings; use JSON::XS; use OAuth::Lite; use OAuth::Lite::Consumer; use DBI; #mixisetting my %options = ( site => 'api.mixi-platform.com', consumer_key => 'xxxxxxxxxxxxxxxxxxxxxx', consumer_secret => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', requester_id => '0000000000', #アプリオーナーのowner_id ); my $consumer = OAuth::Lite::Consumer->new( consumer_key => $options{consumer_key}, consumer_secret => $options{consumer_secret} ); my $db = DBI->connect('dbi:mysql:database=db_name', 'db_user', 'db_pass',{ mysql_enable_utf8 => 1, }); my $st = $db->prepare('SELECT * FROM user ORDER BY id'); $st->execute(); my $update_puid = $db->prepare('UPDATE user SET new_owner_id = ? WHERE id= ? '); while(my $row = $st->fetchrow_hashref ){ my $id = $row->{id}; my $owner_id = $row->{owner_id}; print "id-> $id, owner_id-> $owner_id, "; my $response = $consumer->request( method => 'GET', url => sprintf('http://%s/os/0.8/people/'.$owner_id.'/@self', $options{site}), params => { xoauth_requestor_id => $options{requester_id}, fields=>'platformUserId', }); if ($response->is_success) { my $data = JSON::XS::decode_json($response->decoded_content); print "new_owner_id->".$data->{entry}->{platformUserId}; $update_puid->execute($data->{entry}->{platformUserId}, $id); } else { warn $response->status_line; print "GET ERROR"; } print "\n"; } $db->disconnect;
この取得がおわったら、
・アプリを適当にメンテ中表示にでもして(弱小アプリならしなくたってバレないだろうけど)
・ALTERでnew_owner_idとowner_idいれかえて
・管理画面で変換作業完了を押して
・アプリをメンテ中表示外す
(・古いowner_idは適当にのこしておくか、消す)
という感じですね。
作業自体は簡単だったんだけど
俺の設計で、速度とかの問題からowner_idをスーパークッキー代わりにしてるところがあったんだけど、それがこの仕様変更で死んだ、仕方ない…。
後、変換プログラムで引けないデータが結構大量にでてびっくりするけど、これはアプリを削除してるからってことらしい。
これの弊害として、通常アプリを再インストール(?)したとき、しれっと既存データもどせるけど、残念なことに今後は突き合わせできないから、この時点でアプリアンインストールしてる人はどうしてもロストということになるんだろうな。
*1:実際には、今後はIDをアプリ間で共有できないとか、色々仕様が
YAPC::Asia 2011終了ー
yapc asia 2011終わりました。楽しかったですね。
まあ色々と思う所はすでに前エントリ(http://d.hatena.ne.jp/uzulla/20111014/p1)に書いてしまいましたけど、来年も(あるんですよね?)楽しみですね。
まあ、Perl界隈においては、私はせいぜいでにぎやかしと言ったところですが、まあ楽しい思いをさせて頂いている分、微力でもなにかお返しできればいいなあ…。
あ、YAPC終了後最初のHachioji.pm #10( http://atnd.org/events/20625 )は新顔の方が多い模様です、YAPC効果すげー。
YAPCとHachioji.pm
今日はYAPC前夜祭でしたね、皆さんお疲れ様です。
今年は去年とちがって、ずっとホールで吞んだりしゃべったりしてましたね。
おかげでちょっと飲み過ぎてヤバい。
ーー
思い返せばYAPC 2010で俺がしゃぶしゃぶ食べながらぼやいた「八王子から都心遠い」から、yusukebe経由でmakamakaさんと知り合いになり、自分の中では焦がれていた地元勉強会、Hachioji.pmを発足。
最初はなかば冗談で話した事が、フタを空けてみればコンスタントに毎回8〜16人くらいは来てもらってのべ30人以上の人に来て頂き、
回数も数回やったら飽きられておわるかなーとか思ってたんだが、そんなことなくて気付けば開催回数も二桁に。
これまた冗談の筈だった高尾山にまでのぼったり。
別のイベント、Kamakura.pmや、PHPカンファレンスとかでもHachioji.pm参加者と鉢合わせしたり…。
そんでもって、はっと気付けば今日からYAPC2011、ぼやきから1年が経過しました。
去年は知り合いが1〜2人だけで、まあ基本はぼっちだった(発表やったけど)わけですが、今年は違う。
なんと「俺が知っている人」、ではなく、「俺を知っている人」が10人以上前夜祭にきている…、しかもしばしば会っているので会話が暖気されている。これは楽しいですね、楽しさ8割マシですよ。
ああHachioji.pmやってよかった!*1
ーー
今年は、仕事ではない、自分のエンジニアライフ的には、かなりHachioji.pmが引っかかった気がしますね。
最初は気負ってる所もわりとあったんですけど、段々Hachioji.pmでどうするかとかは割とどうでもよい感じで*2、
まあ技術が好きな人と、気さくな感じの知り合いになって、忌憚なく話せるというのはとても楽しいなあ、と思うわけですね。
「周りにエンジニアが沢山いる」環境の人*3は全然おもわないんだろうけど、割と一匹狼みたいな感じになっちゃってる人は、Hachioji.pmじゃなくてもいいから、「勉強会」だけじゃなくて、ミートアップみたいなのにどんどん参加してみるといいんじゃないですかね。
この年齢になってから言うのもアレなんですけど、平たく言えば趣味が合う友達ができるってのは凄いたのしいですよ。
あと、やっぱ八王子遠いね…っていうか終電間際の人身事故つらいね…。まさか中央線が人身事故で遅延してるからっつって京王線に移動したらそのタイミングで人身事故がおこるとはおもわなかったよ…。
さて文章が非常に酷い事になってますけど、明日はYAPC初日だ!寝よう!