FlaskでRESTful

ちょっと色々あってSpine.jsからBackbone.jsに乗り換えることにした。で、REST-APIが使いたかったので、Flask-RESTfulで書いてみた。

from flask import Flask, request
from flask.ext.restful import Resource, Api

app = Flask(__name__)
api = Api(app)

todos = {}
i = 0

class TodoSimple(Resource):

    def get(self, tid):
        return {"tid": tid, "todo": todos[tid]}

    def put(self):
        global i
        tid = i
        i = i + 1
        todos[tid] = request.form['data']
        return {"tid": tid, "todo": todos[tid]}

    def post(self, tid):
        todos[tid] = request.form['data']
        return {"todo": todos[tid]}

    def delete(self, tid):
        deldata = todos[tid]
        del(todos[tid])
        return {"tid": tid, "todo": deldata}

api.add_resource(TodoSimple, '/', '/<int:tid>')

if __name__ == '__main__':
    app.run(debug=True)

curlで確かめた。

$ curl http://localhost:5000/ -d "data=Remember the Flask" -X PUT
{"tid": 0, "todo": "Remember the Flask"}
$ curl http://localhost:5000/ -d "data=Remember the Python" -X PUT
{"tid": 1, "todo": "Remember the Python"}
$ curl http://localhost:5000/0
{"tid": 0, "todo": "Remember the Flask"}
$ curl http://localhost:5000/0 -d "data=Remember the Sphinx" -X POST
{"todo": "Remember the Sphinx"}
$ curl http://localhost:5000/0
{"tid": 0, "todo": "Remember the Sphinx"}
$ curl http://localhost:5000/0 -X DELETE
{"tid": 0, "todo": "Remember the Sphinx"}
$ curl http://localhost:5000/0
{"status": 500, "message": "Internal Server Error"}

今回はMongoDBを使いたかったので Flask-RESTfulを検討しているのだけど、SQLAlchemyでいいんだったらFlask-RESTlessでいいかもしれない。メソッド自分で書かなくていいし。

C言語ではじめる音のプログラミング

ひと通り読んだので、javascriptで何か作ってみたい。

AlloyでiPhoneのカメラを扱う

カメラで写真を取ってデータベースに格納するアプリを作ってみた。スクロールビューで画像が入れ替わるのがよくわからんがひと通りできた。

alloy camera

スキャフォールドはこことかここを参照。

controllers/index.coffee

カメラ用のボタンを押したら内蔵カメラを起動して、写真をファイルに保存したら、パスをデータベースに保存する。

pts = Alloy.Collections.photo

cameraButton = Ti.UI.createButton
  systemButton: Ti.UI.iPhone.SystemButton.CAMERA

$.win1.rightNavButton = cameraButton

cameraButton.addEventListener 'click', ->
  Ti.Media.showCamera
    success: (event) ->
      now = (new Date).getTime()
      file = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory,
              String.format("%d-%d", now, Math.floor(Math.random() * 1000)))
      file.write(event.media)
      photo = Alloy.createModel('photo', { path: file.nativePath })
      photo.save()
      Alloy.Collections.photo.add photo
      return
    mediaTypes:[Ti.Media.MEDIA_TYPE_PHOTO]

pts.fetch()

$.index.open()

models/photo.js

モデルの定義

exports.definition = {
  config: {
    "columns": {
      "path": "string"
    },
    "adapter": {
      "type": "sql",
      "collection_name": "photo"
    }
  }
}

views/index.xml

コレクションの定義をしておく

<Alloy>
    <Collection src="photo"/>
    <TabGroup>
        <Tab id="tab1" title="写真" icon="dark_book.png">
      <Window id="win1" title="写真">
            <ScrollView id="scroll" dataCollection="photo">
              <Require src="photo"/>
            </ScrollView>
      </Window>
        </Tab>
        <Tab id="tab2">
      <Window id="win2">
      </Window>
        </Tab>
    </TabGroup>
</Alloy>

views/photo.xml

個々の画像

<Alloy>
  <ImageView image="{path}" width="100%">
  </ImageView>
</Alloy>

AlloyのCollectionが見つからない

黒い本の写真アプリをAlloyで作っている。

app/models/photo.jsに

exports.definition = {
    config: {
        "columns": {
            "path": "text"
        },
        "adapter": {
            "type": "sql",
            "collection_name": "photo"
        }
    }
}

とモデルとコレクションを定義しておいて、index.jsで

cameraButton = Ti.UI.createButton
  systemButton: Ti.UI.iPhone.SystemButton.CAMERA

$.win1.rightNavButton = cameraButton

cameraButton.addEventListener 'click', ->
  Ti.Media.showCamera
    success: (event) ->
      now = (new Date).getTime()
      file = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory,
              String.format("%d-%d", now, Math.floor(Math.random() * 1000)))
      file.write(event.media)
      photo = Alloy.createModel('photo', { path: file.nativePath })
      photo.save()
      Alloy.Collections.photo.add photo
      return
    mediaTypes:[Ti.Media.MEDIA_TYPE_PHOTO]

で、写真の撮影は出来てセーブするときにAlloy.Collections.photo.addメソッドがない(というかAlloy.Collections.photoがundefined)というエラーに悩まされている。

130113 追記

index.xmlにCollectionタグを追加したり、なんかごちゃごちゃやってたらうまくいくようになった。エラーの原因は結局わかってない。

d3.jsでインタラクティブでよりよい分析体験を

年末、長野に遊びに行くのに本がないと不安なので勢いでd3.jsの電子書籍を購入して読んだ。内容は初歩の初歩でちょっと物足りなかったが、d3の世界に足を踏み入れるきっかけには十分だった。

1357684337

個人的によく使うのはggplot2(R)とSpotfireの2つ。

基本的に画像を描くためだけのライブラリを選択するのはあかんやろと考えているので統計処理とそれを見やすい形で表示するRは便利だと思っている。Spotfireは、デモを見れば分かる通り、フィルタリングがインタラクティブなのと、ビジュアライズ間の値の対応がとれているといったあたりが動的だ。ただし、散布図行列のような一つのウィンドウに複数の点を対応させるようなプロットは描けないのが不満だったりする。フィルタリングは右側のスライダーなんかでまとめて操作するようになっているのでデスクトップでマウスで操作するのが前提のデザインだったりする。

これに対してd3はより上の2つよりもさらにインタラクティブ性が高いビジュアライゼーションが可能となっているのだと思う。タブレットなんかで使えば触れるグラフとなってよりよい分析体験を与えるんだろうなと。

例えば、Rを勉強すれば必ず目にするirisの散布図行列なんかは選択すると対応する部分がハイライトされる。

motion chartもわかりやすい。市場予測とかプロジェクトのプロパティーの変遷なんかをこれで動かせるようにしておくと動きが上手くとらえられてイイかもしれない。

動かせるForce-Diarected Graphとかこれなんかもヨサゲ。

クラスターを円形に表現するレイアウトも素敵

mbostock’s blocks見てて飽きないわ。

職場で導入しようと思ったら必須ブラウザのIE8では動かないということに気づいて、ガッカリ感が半端無かった。

2012年に読んだ本

今年読んだ本で良かったもの。

すごいHaskellたのしく学ぼう!

これはピカイチだった。RWHで停滞感が漂いまくっていた僕のHaskell理解力がかなり上がったのは間違いない。そういえば、最近Haskellしか書いてないなぁと2012年のエントリに付けられたタグを数えたらHaskell 90, Python 70, javascript 44だった。

ProductName すごいHaskellたのしく学ぼう!
Miran Lipovača
オーム社 / 2940円 ( 2012-05-23 )


あとはtwitterで色々教えてもらったりとか、三島Haskell無名関数の会が出来てモチベーションが上がったりとか色々タイミングが良かったということもあるが。来年も引き続きハスケりたい。

型というか、閉じている、自己同型といったイメージは数学ガールが良いかも

ProductName 数学ガール ガロア理論 (数学ガールシリーズ 5)
結城 浩
ソフトバンククリエイティブ / 1995円 ( 2012-06-01 )


チケット駆動開発

自分の仕事にアジャイルな要素を入れたいというのはここ数年ずっと考えていて、やっと来年すこし取り組めそうで嬉しい。

僕のチケット駆動に対する期待は、創薬研究への応用なので、チケット駆動開発の背景にある考え方がぎっしり詰まった本書は、色々な発見や再発見があったり、今の仕事のアナロジーを見つけたりとかなり満足度の高い本だった。

ProductName チケット駆動開発
小川 明彦
翔泳社 / 3444円 ( 2012-08-24 )


今年システムを少し運用してみて、意識の高低のバラツキを吸収する仕組みとしてゲーミフィケーション的なものも考えて行かないといけないし、受動的な情報伝達手段も考えて行かないといけないなぁと感じた。

(そもそも潜在的に)意識の高いマネジメント層は、能動的に情報アクセスしない研究者層(というより労働者層)が存在することを理解できないので、「そんなのホームに登録しておけばいいだけなんんじゃないか?」なんて言うんだけど、それすら能動的な情報アクセスなんだよなぁ。

デジタルサイネージのようなものにも手を出してみたい。

ProductName 幸せな未来は「ゲーム」が創る
ジェイン・マクゴニガル
早川書房 / 2940円 ( 2011-10-07 )


JavascriptとTitanium Mobile

今年はクライアントサイドのMVCも熱かった。去年Javascriptを勉強してた時には、まさかiPhoneアプリの方に進んでいくとは思わなかったが。

ステートフルJavaScriptはjavascript MVCフレームワークの本でSpine.jsの解説に近い。そしてこの知識はTitanium MobileでJavascriptを使ったiPhoneアプリ開発で役立つ!

AlloyはTitaniumのためのMVCフレームワークでBackbone.jsを使ってつくられている。これを使うとjavascriptを利用してiPhoneアプリとかAndroidアプリが作れちゃうわけだ(下のエントリ参照)。

バージョンあげたら実機転送がうまくいかなくなって、最近は停滞気味ですが、来年はもうちょっと力を入れて取り組みたいと思っている(なんかアプリをリリースしたい)。

それから僕はCoffeeScriptが好きなので使っていますが、他にもNode.jsのテンプレートエンジン(Jade,eco,ejs)なんかも使えるので好みの開発スタイルを探求するためにCoffeeScriptやNode.jsの入門書もあわせて読んでおくとよいかも。

ProductName サーバサイドJavaScript Node.js入門
清水俊博
アスキー・メディアワークス / 3990円 ( 2012-10-26 )


過去に読んだ本

Pythonとかのちょっとしたスクリプトをforeverでデーモン化する

pythonでちょっとしたクローラーを書いて終夜で流したい時に、夜中に落ちたりすると時間がもったいないので、死んでも生き返るようにしておきたいことがある。

追記121203

はてブで指摘された通り

forever start -c python crawler.py

で良かった。ドキュメントにちゃんと書いてあった。


node.jsで書いた場合にはforeverが使えて便利だが、他の言語で書いた場合にはchild_processで子プロセスにして呼び出せばいいので、javascriptをちょっと書いておけば、PythonでもPerlでもHaskellでもなんでも使える。

でもjavascriptを毎回書くのは(忘れるし)面倒なのでforever用のjavascriptを出力するスクリプトをpythonで書いてみた(foreverizeっていう名前)。

#!/usr/bin/env python

import sys

js_str = """var spawn = require('child_process').spawn;
var app   = spawn('{}', [{}]);
app.stdout.on('data', function(data) {{
  console.log('stdout: ' + data);
}});

app.stderr.on('data', function(data) {{
  console.log('stderr: ' + data);
}});

app.on('exit', function(code) {{
  console.log('exit code: ' + code);
}});
"""

if __name__ == '__main__':
    if len(sys.argv) < 2:
        print "Usage: {} [command]".format(sys.argv[0])
    else:
        command = sys.argv[1]
        options = ""
        if len(sys.argv) >= 2:
            options = ",".join(["'{}'".format(op) for op in sys.argv[2:]])
        print js_str.format(command, options)

使い方は簡単

foreverize python crawler.py > crawler.js
forever start crawler.js

これで、デーモン化されて夜でも安心。

fayを使えと心に直接呼びかけられた

(……きこえますか…きこえますか…JSerの…みなさん… 三島Ha…無名…会です… 今… あなたの…心に…直接… 呼びかけています…フロントエンドは…underscore.jsを…使う場合では…ありません…あなたが…使う…言語は… Clojure某でも…ありません…Haskellです…Haskellを…使うのです…fayでコンパイルするのです…)

fayはHaskellコードをjavascriptにコンパイルするツールで最近精力的に開発が進んでいるようで素晴らしいですね、心に呼びかけられるのも納得です。

import Language.Fay.Prelude

mylist :: [Int]
mylist = [1..10]

-- test
main :: Fay ()
main = print $ any (==2) mylist

fayコマンドでhaskellをjavascriptにコンパイルすればnode.jsで動かせるようになります。

$ fay test.hs 
$ node test.js 
true

underscore.jsに載ってた他の関数もこんな感じ。findなんかはMaybe型で返ってくるので値がなかった場合の処理も楽ちんです。

-- each
mapM_ print mylist

-- map
map (3*) mylist

-- reduce
foldl (+) 0 mylist

-- reduceRight
foldr (+) 0 mylist

-- find
find even mylist

-- filter
filter even mylist

-- reject
filter (not . even) mylist

-- all
all (>0) mylist

-- any
any (>5) mylist

-- contains
any (==2) mylist

すごいHaskellをKindleで読む時が来ましたね!これは内側からなぜか湧き上がる物欲ですが、、、、

ProductName すごいHaskellたのしく学ぼう!
Miran Lipovaca
オーム社 / ?円 ( 2012-09-21 )


ProductName Kindle Paperwhite

Amazon.co.jp / 7980円 ( 2012-11-19 )


三島Haskell無名関数の会は一緒にHaskellを学ぶお友達を絶賛募集中です。今度は三島でHaskell勉強してホルモン食べながらビールを飲みます。

Alloyでつくる簡易RSSリーダー

Titanium Mobile iPhone/Androidアプリ開発入門の簡易RSSリーダーをAlloyで書きなおしてみた

alloy rssreader

CoffeeScrptで開発する方法については、ここを参照のこと。

軽くハマったのはviewかな。

views/index.xml

最初TabGroupにidを設定したら、$.index.openでエラーがでた。

結局$.indexってなんじゃろか?とドキュメントを読んだら解決した。

要するにViewのトップレベルには

  • Ti.UI.Window
  • Ti.UI.TabGroup
  • Ti.UI.iPad.SplitWindow

のいずれかが必要で、idが明示的に指定されてない場合には、そのファイル名がidとして利用される。

規約に従うことにしたらxmlはシンプルになった。

<Alloy>
    <TabGroup>
    </TabGroup>
</Alloy>

controllers/index.coffee

コントローラーは本の通りに。スタイルとかも全部コントローラーに書いちゃったのでindex.tssはいじってない。

createApplicationTabGroup =  ->
  tab1 = createRSSTab 'Developer Blog', 'http://developer.appcelerator.com/blog/feed'
  tab2 = createRSSTab 'Q&A', 'http://developer.appcelerator.com/questions/feed/newest'
  $.index.addTab tab1
  $.index.addTab tab2
  return

createRSSTab = (title, url) ->
  win = Ti.UI.createWindow
    title: title

  tab = Ti.UI.createTab
    title: title
    icon: 'KS_nav_views.png'
    window: win

  tableView = Ti.UI.createTableView {data:[]}
  win.add(tableView)

  win.addEventListener 'open', ->
    query = String.format "select * from rss where url = '%s'", url
    Ti.Yahoo.yql query, (res) -> 
      if res.success is false
        alert("Yahoo YQL error.")
        return
      res.data.item.forEach (item) ->
        tableView.appendRow
          title: item.title
          color: '#000'
          link: item.link
          hasChild: true
    return

  tableView.addEventListener 'click', (event) ->
    detailWin = Ti.UI.createWindow {title: event.rowData.title, backgroundColor: '#fff'}
    webView = Ti.UI.createWebView {url: event.rowData.link}
    detailWin.add(webView)
    tab.open(detailWin)
    return

  return tab

createApplicationTabGroup()

$.index.open()

ProductName Titanium Mobile iPhone/Androidアプリ開発入門―JavaScriptだけで作る
小澤 栄一
秀和システム / 2520円 ( 2012-02 )


Smashing Node.jsが気になる

気になっている本

ProductName Smashing Node.js: JavaScript Everywhere (Smashing Magazine Book Series)
Guillermo Rauch
Wiley / 3379円 ( 2012-09-11 )