Bootstrap2を利用したイイカンジのサイト

最近bootstrap2を使い始めていて、FlaskとかExpressとかのスケルトンとして使えたら便利だろう(職場のサイトでは必要十分な気がする)なーとbootstrap2を中途半端に利用していい感じに仕上げているサイトを探している

wordpressだといくらでもチュートリアルが見つかるんだけど、bootstrapはなかなか見つからないのはなんでじゃろかねーとか思いながらBuilt With Bootstrapを見ながらヨサゲなサイトを探していた。

bootstrapのテーマを売っているサイトもみつけた。

グリッドデザインに使えるツールいろいろも役に立ちそうな気がするが。

個人的にはFlask+bootstrap2+Brunchですぐに開発できるようにしておけば最高なんじゃないかなぁと思っているので、今度のつくる会ハングマンのサンプルをこの構成で書きなおしてみるっていうのも面白いかなと。

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


Brunchでtwitter検索

Brunch(Backbone.js)の練習を兼ねて、Backbone.js で HTML の View と Model を分離してみるよのサンプルをBrunchで。

まずは、スケルトン作成

$ brunch new brtwitter

watchしつつ、ファイル更新を検知してコンパイルしつつ、サーバーを3333番portで起動する

$ cd brtwitter
$ brunch watch --server
[19:23:17]: [Brunch]: application starting on http://0.0.0.0:3333.
[19:23:17]: [Brunch]: compiled.

あとはapp以下のファイルをいじる。

models/tweet.coffee

モデルをつくる。

class exports.Tweet extends Backbone.Model
  initialize: ->
    @set
      domId: "tweet_#{@cid}"

collections/tweet_list.coffee

コレクションを設定。ここまでは簡単

{Tweet} = require 'models/tweet'

class exports.TweetList extends Backbone.Collection
  model: Tweet

views/tweet_list_view.coffee

{TweetView} = require 'views/tweet_view'
{Tweet} = require 'models/tweet'
tweetListTemplate = require './templates/tweet_list'

class exports.TweetListView extends Backbone.View
  id: 'tweets-view'

  initialize: ->
    app.tweetList.bind 'add', @addOne
    $('body').append @render().el

  render: ->
    $(@el).html tweetListTemplate()
    @

  addOne: (tweet) ->
    view = new TweetView model: new Tweet(tweet)
    $(@el).find('#tweets').prepend view.render().el

views/templates/tweet_list.eco

テンプレートは今回ecoをデフォルトのecoを使った。個人的にはjadeのほうが好きなのでそのうちJadeに乗り換える。

views/templates/tweet_list.eco

<ul id="tweets"></ul>

views/tweet_view.coffee

同様にtweetも

tweetTemplate = require('./templates/tweet')
class exports.TweetView extends Backbone.View
  id: 'tweet-view'
  tagName: 'li'

  initialize: ->
    @model.view = this

  render: ->
    $(@el).html tweetTemplate tweet: @model.toJSON()
    @

views/templates/tweet.eco

<div class="twtr-avatar">
  <div class="twtr-img">
    <a href="http://twitter.com/intent/user?screen_name=<%= @tweet.from_user %>" target="_blank">
      <img src="<%= @tweet.profile_image_url %>">
    </a>
    <p><%= @tweet.text %></p>
  </div>
</div>

assets/index.html

bodyタグの間に入れとく

<input id="searchTxt" type="text" value="backbone.js" />
<button id="searchBtn">search</button>
<div id="tweetContainer">searchボタンを押すとTwitterから検索してくるよ!</div>

initialize.coffee

最後に初期化する。

{BrunchApplication} = require 'helpers'
{MainRouter} = require 'routers/main_router'
{TweetList} = require 'collections/tweet_list'
{TweetListView} = require 'views/tweet_list_view'

class exports.Application extends BrunchApplication
  initialize: ->
    @router = new MainRouter
    @tweetList = new TweetList
    @tweetListView = new TweetListView

    $("#searchBtn").click (e) ->
      jqxhr = $.ajax
        dataType: "jsonp"
        url: "http://search.twitter.com/search.json"
        data: { q: encodeURI( $( "#searchTxt" ).val() ) }
        jsonp: "callback"

      jqxhr.done (data) ->
        _.each data.results, (result) ->
          app.tweetListView.addOne(result)

window.app = new exports.Application

ファイル構成はこんな感じ。home_*は必要ないけどスケルトンで作成されたのでそのまま放ってある。

.
├── assets
│   ├── images
│   └── index.html
├── collections
│   └── tweet_list.coffee
├── helpers.coffee
├── initialize.coffee
├── models
│   └── tweet.coffee
├── routers
│   └── main_router.coffee
├── styles
│   └── main.styl
└── views
    ├── home_view.coffee
    ├── templates
    │   ├── home.eco
    │   ├── tweet.eco
    │   └── tweet_list.eco
    ├── tweet_list_view.coffee
    └── tweet_view.coffee

backbone.jsってviewがファットになんのね。

静岡デベロッパーズつくる会#5をやります

4/8(sun)にいつものコミュニティfで。

1332706933

久しぶりにGAEでなんか作ろうかなと思っている。とかいいつつjQuery Mobileにはしるかも。

今日の畑(120324)

明け方まで降っていたのだが昼には晴れたので、種まきをすることにした。風が強い日だったが、娘と一緒に畑を耕した。

1332667917

ニンニクは順調。

1332667919

人参と大根の種を撒いた。畑仕事の後にいけたにさんでお酒を買うついでに畑の話をしてたら、春撒き大根は結構チャレンジングらしかった。まぁ種はかなり余っているから上手くいかなかったら秋撒きにまわして、区画も他のに回せるから、今回は初大根にチャレンジしてみる。

1332667922

スナップエンドウの花も咲いてたので、来月の終わりから収穫シーズンになりそう。

1332667924

brunch(backbone.js)を触りまくってたら日が暮れた

Brunchはいまだにお作法がよくわからん。やっぱbackbone.jsから地道にステップアップしていくのがいいのか?

ProductName Developing Backbone.Js Applications
Addy Osmani
O'Reilly Media / 2760円 ( 2012-07 )


さて、クライアントサイドMVCってことはクライアント側に小難しい処理が移行しているってことですよね。加えてHTML5的な潮流はマークアップじゃなくてCSSでデザイン周りをやれというimplicitな意図を感じるわけです。さらにclosureみたいなアプリケーション構築用のライブラリの存在を考えると、jQueryでプラグイン入れまくりのスパゲッティライクなフロントエンドがどこまで許されるのかなぁと思ったりする。

ふとWOMASという言葉がよぎった。

Webservice Of Maintainability And Sustainability

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はモックのテストにおいては重要な機能なわけだ。

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

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

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