BrunchというクライアントサイドのMVCフレームワーク

クライアントサイドのMVCフレームワークはbackbone.jsSpineのどっちかかなぁと。

coffeescriptで書けるSpineを使おうかなぁと思っていたのだけど、Brunchっていうのが便利そうなので調べてみた。

brunch

Application assemblerと銘打っているようにBackbone.jsを軸にjQueryやJade,Stylusの面倒をまとめてみてくれるうえにcoffeescriptでの開発がデフォルト。

ディレクトリの階層もわかりやすいし、使いやすそうなのでbackbone.jsを覚えておこうかなと。

ProductName JavaScript Web Applications
Alex Maccaw
Oreilly & Associates Inc / 3020円 ( 2011-08-30 )


pythonコードをデーモン化するモジュール

みつけたのでソースコードを読んでみたら、かなり参考になった。

51行目

resourceモジュールを使っているのを見るのははじめてだ。

for fd in range(resource.getrlimit(resource.RLIMIT_NOFILE)[0]):
    try:
        os.close(fd)
    except OSError:
        pass

57行目

dupすると未使用の中で最小のディスクリプタに割り当てられんのか。

os.open(devnull, os.O_RDWR)
os.dup(0)
os.dup(0)

85行目

signal.signal(signal.SIGTERM, partial(sigterm, pid))

部分関数使っている。ドキュメントによるとsignal.signalの第二引数は

handler は二つの引数とともに呼び出されます: シグナル番号、および現在のスタックフレーム (None またはフレームオブジェクト

で、部分関数になっているsigtermは以下のように3引数を受け取る関数。第一引数はロックファイル名。

def sigterm(pid, signum, frame):
    logging.info("Caught signal %d. Stopping daemon." % signum)
    os.remove(pid)
    sys.exit(0)

python版rungms

pygamessがrungmsを設定してない場合でもマトモなエラーを吐かないとレスポンスを貰ったので、きちんと例外投げるように変更しておいた。ついでにドキュメントを追加してバーションを上げておいた。

pygamessはもともと、gamessのインプット作るのめんどくさいっていうのがモジュール作成のモチベーションだったので、gamess実行環境(rungms)が既にあるという前提だったが、最近pybelに対応したことにより、分子設計的な側面が強くなってしまったので、gamess実行環境もまとめて面倒みたほうがいいかなぁと。

rungmsは単なるシェルスクリプトなんだけど、ファイルを直接編集しないといけないので、動くようにするのがめんどくさい(色々なOSに対応するようにしているのでごちゃごちゃしている)。普通に動かせる最小のスクリプトはどんな感じかなぁと1000行超えのスクリプトを削って行ったら200行くらいになったが、残ったコードのほとんどがsetenvだった。どんだけ環境変数好きやねん?と。

これをpythonで書きなおしたら60行くらい。

import os
import sys
import socket
from shutil import copyfile, rmtree
from tempfile import mkstemp, mkdtemp

scr = mkdtemp()
job = sys.argv[1]
gamess_path = "/usr/local/gamess"
ddikick = os.path.join(gamess_path, "ddikick.x")
gamess = os.path.join(gamess_path, "gamess.Jan122009R1.x")
hostname = socket.gethostname()

setenv_data = [
    (" MAKEFP", "efp"), ("GAMMA", "gamma"), ("TRAJECT", "trj"),
    ("RESTART", "rst"), ("  PUNCH", "dat"), ("  INPUT", "F05"),
    (" AOINTS", "F08"), (" MOINTS", "F09"), ("DICTNRY", "F10"),
    ("DRTFILE", "F11"), ("CIVECTR", "F12"), ("CASINTS", "F13"),
    (" CIINTS", "F14"), (" WORK15", "F15"), (" WORK16", "F16"),
    ("CSFSAVE", "F17"), ("FOCKDER", "F18"), (" WORK19", "F19"),
    (" DASORT", "F20"), ("DFTINTS", "F21"), ("DFTGRID", "F22"),
    (" JKFILE", "F23"), (" ORDINT", "F24"), (" EFPIND", "F25"),
    ("SVPWRK1", "F26"), ("SVPWRK2", "F27"), ("  MLTPL", "F28"),
    (" MLTPLT", "F29"), (" DAFL30", "F30"), (" SOINTX", "F31"),
    (" SOINTY", "F32"), (" SOINTZ", "F33"), (" SORESC", "F34"),
    ("GCILIST", "F37"), ("HESSIAN", "F38"), ("QMMMTEI", "F39"),
    ("SOCCDAT", "F40"), (" AABB41", "F41"), (" BBAA42", "F42"),
    (" BBBB43", "F43"), (" MCQD50", "F50"), (" MCQD51", "F51"),
    (" MCQD52", "F52"), (" MCQD53", "F53"), (" MCQD54", "F54"),
    (" MCQD55", "F55"), (" MCQD56", "F56"), (" MCQD57", "F57"),
    (" MCQD58", "F58"), (" MCQD59", "F59"), (" MCQD60", "F60"),
    ("NMRINT1", "F61"), ("NMRINT2", "F62"), ("NMRINT3", "F63"),
    ("NMRINT4", "F64"), ("NMRINT5", "F65"), ("NMRINT6", "F66"),
    ("ELNUINT", "F67"), ("NUNUINT", "F68"), (" NUMOIN", "F69"),
    (" GMCREF", "F70"), (" GMCO2R", "F71"), (" GMCROC", "F72"),
    (" GMCOOC", "F73"), (" GMCCC0", "F74"), (" GMCHMA", "F75"),
    (" GMCEI1", "F76"), (" GMCEI2", "F77"), (" GMCEOB", "F78"),
    (" GMCEDT", "F79"), (" GMCERF", "F80"), (" GMCHCR", "F81"),
    (" GMCGJK", "F82"), (" GMCGAI", "F83"), (" GMCGEO", "F84"),
    (" GMCTE1", "F85"), (" GMCTE2", "F86"), (" GMCHEF", "F87"),
    (" GMCMOL", "F88"), (" GMCMOS", "F89"), (" GMCWGT", "F90"),
    (" GMCRM2", "F91"), (" GMCRM1", "F92"), (" GMCR00", "F93"),
    (" GMCRP1", "F94"), (" GMCRP2", "F95"), (" GMCVEF", "F96"),
    (" GMCDIN", "F97"), (" GMC2SZ", "F98"), (" GMCCCS", "F99")
    ]

for e in setenv_data:
    os.environ[e[0].strip()] = "%s/%s.%s" %(scr, job, e[1])

os.environ["ERICFMT"] = os.path.join(gamess_path, "ericfmt.dat")
os.environ["MCPPATH"] = os.path.join(gamess_path, "mcpdata")
os.environ["EXTBAS"]  = "/dev/null"
os.environ["NUCBAS"]  = "/dev/null"

src = job + ".inp"
dest = os.path.join(scr,job) + ".F05"
copyfile(src,dest)
exec_string = "%s %s %s -ddi 1 1 %s -scr %s > t.out" % (ddikick, gamess, job, hostname, scr)
os.system(exec_string)

rmtree(scr)

結局ユーザーが指定しないといけない変数ってGamessのpathくらいだった。

沼津DEはしご酒

これは!

いかないといけませんな。

静岡DEはしご酒7 in沼津

参加する蔵は

ちなみに金明さんは職場のすぐそば。

モックとスタブと僕の悟り体験

最近モナド継続に続く第三の悟りを体験した。それが「モックとスタブの違い」

自分の言葉で表すとすれば、

テスト関心空間の内側にあるのがモックで外側がスタブ

といったところか。

発端はPython Testing: Beginnerでmockerを使っていたのだけど、verifyメソッドの存在意義がよく分からなかった(モックとスタブの違いを理解した今なら、verify必要に決まってんじゃんと言えるわけだが)。

ProductName Python Testing: Beginner's Guide
Daniel Arbuckle
Packt Publishing / 3220円 ( 2010-01-31 )


悟りに至るまでにいくつかのサイトを読んだ。

スタブに関しては割りと容易に理解できる。モックとスタブの違いなんかに書いてあるように要するにスタブアウトですね。外界とのインタラクションを絶ち切って(debouple)状態にテストの関心を集中するわけだ。

で、問題はモック。Mock と Stub についてによると

Mock と Stub の違いはテストの観点の違いです。相互作用(振る舞い)中心のテストに利用するのがMockで、状態中心のテストに利用するのがStubです。

これだけだとわからないが、次のパラグラフを読むと

相互作用中心のテストとはテスト対象のシステムと外部のコンポーネントとの間で正しいやり取りがされるかのテスト、いわばプロトコルのテストです。外部のコンポーネントは Mock により置き換えられ、システムから正しい呼び出しがなされているかを監視します。

この文章でモックが何をデカップリングしようとするのかがおぼろげながら見えてきます。

したがって、例えばWebアプリの Controller の単体テストにおいて相互作用中心のテストが正しく行われてパスしているならば、Model が正しく実装された時に Controller が正しく動作するということが、Model が実装されなくても保障されます。

つまり、モックオブジェクトが期待されたとおり過不足なく呼び出されているかを調べるverifyはモックのテストにおいては重要な機能なわけだ。

実際にモックのテストを見ていると、内部の動作知ってないとテストかけないじゃんと思うんだけど、それはモックが必要な場面、モックが有効な場面に書いてあった。

でも、話を聞く限りだとモックというのはテスト対象の実装の中の処理の流れを追う物のようなので、それじゃブラックボックステストにならないじゃないかと思った。それをそのまま言ったら、確かにテストはできるだけブラックボックステストになってた方がいいけど、機能テストやインテグレーションテストのような粒度の大きな単位のテストでは、処理の中で起こる様々な出来事や副作用を色々モニタリングして、すべての処理が期待通りに動いているかどうかを検証しないといけないから、必然的にホワイトボックステストにならざるを得ないと言われた。

僕の場合はここまで読んだら、あーモックとスタブの違いってそういうことなのか!となったので参考になればと思い、メモっておく。

jQuery Mobileを読んだ

@ishisakaに速攻読み終わるって言われたので、暇な時にでも読むかと積んであったが、読み始めたらさくっと読み終わった。

実際手を動かすところは6章しかなかったし、一通り読めば一通りjQuery Mobileを使えるようになると思う。その後はドキュメント読みながら書いていけばいいのかな。

実際書いてみるとデバッグがめんどくさかったが、テストはQUnit使えばいいのかね?あとSeleniumかなぁ。

jQuery Mobileアプリケーション開発のアプローチ

  1. アプリケーションの施策としてシンプルなページ群を用意します。これがプロタイプの作成につながります。
  2. ページとデータの提供元との間を接続します
  3. 段階的にアプリケーションを改善していきます。結果の表示を修正し、機能を追加し、バグフィックスを行います。

1332235293

jadeで書きなおした6-4のjQuery Mobileで作ったtwitterアプリ

モバイル用のUIをちゃっちゃと用意するのにJQueryを使うのは良い選択肢だと思う。

ProductName jQuery Mobile
Jon Reid
オライリージャパン / 1995円 ( 2011-12-22 )


だ、だ、だんごむしー(コロッコロッ)

久しぶりにジムに行ってガツッと走って帰ってきたら、娘と息子が待ち構えていてダンゴムシ探しに付き合わされた。

1332070449

紫陽花の芽が。春ですな。

1332070446

ダンゴムシを二匹ゲット。

1332070447

虫かごに入れてお持ち帰り(後で逃がす)。

1332070453

ProductName ぼく、だんごむし (かがくのとも傑作集 どきどき・しぜん)
得田 之久
福音館書店 / 945円 ( 2005-04-15 )


jQuery Mobileがなかなか面白い

jadeで書いてる。data-*のカスタム属性で指定すればアイコンなんかも勝手に表示されて、さくっと作るのに向いてそうな感じ。

1332070152

!!! 5
html
  head
    title jqm test
    link(rel="stylesheet", href="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css")
    script(src="http://code.jquery.com/jquery-1.7.1.min.js")
    script(src="http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js")
    meta(name="viewport", content="width=device-width, initial-scale=1")
  body
    section#page1(data-role="page")
      header(data-role="header")
        h1 jQuery Mobile
      .content(data-role="content")
        h3 さまざまなアイコン
        div(data-role="controlgroup", data-type="horizontal", data-inline="true")
          a(href="#", data-role="button", data-icon="home", data-iconpos="left") ホーム
          a(href="#", data-role="button", data-icon="gear", data-iconpos="left") 設定
          a(href="#", data-role="button", data-icon="search", data-iconpos="left") 検索
      footer(data-role="footer")
        h1 K'zfm

ProductName jQuery Mobile
Jon Reid
オライリージャパン / 1995円 ( 2011-12-22 )


部屋のレイアウトを変えた

娘が小学生になるので、机をリビングに持ってきて、いろいろレイアウトを変更した。

1332032066

そのせいで、ノートブックをだらだらいじるという自分の居場所が無くなってしまった。特に電源をどこに用意するか悩んでいる。

1332031645

新しいiPod nano

初代がリコール対象だってことを教えてもらったので、早速修理に出したら8GのiPod nanoになって戻ってきた

ProductName Apple iPod nano 8GB シルバー MC525J/A

アップル / 8331円 ( 2010-09-02 )


Pros.

フィットネスっていう機能がついてた。これを買えばいいのか

ProductName Apple Nike + iPod Sensor MA368J/E

アップル / 2004円 ( 2010-08-03 )


Cons.

ホイールが無いので運転中は操作しにくい。

まとめ

暖かくなってきたのでそろそろジムを退会しようかと思っている。 家の周りを走るのになんかいいアプリないかな

AndroidだとJogTrackerになるのかな?