Luminus, Reagentな環境でSpecljを導入
ClojureでRSpecのような読みやすいテストを書くためのフレームワークとしてSpecljというものがあります。
ここではprofileにcljsを選択して作成したLuminus projectでClojure, ClojureScriptのspecを実行できるようにしていきます。
前提
前述したLuminus projectは以下のように作成されたprojectを指します
lein new luminus foo +cljs cd foo tree . . ├── Procfile ├── README.md ├── env │ ├── dev │ │ ├── clj │ │ │ └── foo │ │ │ ├── dev.clj │ │ │ └── repl.clj │ │ └── cljs │ │ └── foo │ │ └── dev.cljs │ └── prod │ └── cljs │ └── foo │ └── prod.cljs ├── project.clj ├── resources │ ├── docs │ │ └── docs.md │ ├── public │ │ ├── css │ │ │ └── screen.css │ │ ├── img │ │ └── js │ └── templates │ └── home.html ├── src │ └── foo │ ├── core.clj │ ├── handler.clj │ ├── layout.clj │ ├── middleware.clj │ ├── routes │ │ └── home.clj │ └── session.clj ├── src-cljs │ └── foo │ └── core.cljs └── test └── foo └── test └── handler.clj
この方法で作成すると、React.jsのClojureScriptインターフェイスのreagentやClojureScriptの変更を自動でブラウザに送信するfigwheelなど便利なlibraryを導入してくれます。 (これらの詳しい説明についてはネット上にたくさん転がっているので、それらをご覧ください。)
また、この方法で作成したディレクトリはsrc, src-cljsの2種類のソースコードを格納するディレクトリがあって今ひとつな気がするので、 ここではspecの環境構築と併せて以下のようなディレクトリ構成にしていきます。
src ├──clj └──cljs spec ├──clj └──cljs
ClojureのSpec
まずclojure向けのspecを構成していきます 現在src直下にcljファイルの格納されているfooディレクトリがあるので、これを以下のようにclj配下に持っていきます
src └──clj └── foo
ついでにspecファイルを格納するディレクトリも追加しておきます 以下のような構成でディレクトリを作成してください。
spec ├──clj │ └── foo └──cljs └── foo
次にproject.cljを編集してSpecljの依存関係とtest pathを追加します
... :plugins [[lein-ring "0.9.1"] [lein-environ "1.0.0"] [lein-ancient "0.6.0"] [ragtime/ragtime.lein "0.3.8"] [lein-cljsbuild "1.0.4"] [speclj "3.2.0"]] ; <- これを追加 :source-paths ["src/clj"] ; <- これを追加 :test-paths ["spec/clj"] ; <- これを追加 :dev {:dependencies [[ring-mock "0.1.5"] [ring/ring-devel "1.3.2"] [pjstadig/humane-test-output "0.7.0"] [leiningen "2.5.1"] [figwheel "0.2.5"] [weasel "0.6.0"] [speclj "3.2.0"] ; <- これを追加 [com.cemerick/piggieback "0.1.6-SNAPSHOT"]] ...
一旦ライブラリをインストールしておきましょう$ lein deps
続いてspec/clj/foo/core_spec.clj
というファイルを作成して、以下のようなダミーのテストを記述します
(ns foo.core-spec (:require [speclj.core :refer :all] [foo.core :refer :all])) (describe "Truth" (it "is true" (should true)) (it "is not false" (should-not false))) (run-specs)
これで以下のコマンドを実行するとSpecljによるテストが実行されるはずです
$lein spec spec/clj
ClojureScriptのSpec
続いてClojureScriptのSpecです ClojureScriptのspecにはphantomjsが必要ですのでインストールしておいてください。
またここでは PhantomJS 1.9.8での動作を想定しています
(※ PhantomJS 2.0ではうまく動作しないようです。)
luminusによってClojureScriptはsrc-cljsに格納されているのでこれをsrc/cljsに移動します。 (src-cljsのままでいい場合はこの作業は不要です)
src ├──clj │ └── foo └──cljs └── foo
ディレクトリを移動したらproject.cljでsrc-cljsとなっている部分は全てsrc/cljsと変更しておいてください。
次にproject.cljにテスト向けのbuild情報を記述します。
devのprofile情報に対して以下のように変更してください
:cljsbuild {:test-commands {"spec" ["phantomjs" "bin/speclj" "resources/public/js/app_test.js"]} ; <- これを追加 :builds {:app {:source-paths ["env/dev/cljs"]} :test {:source-paths ["src/cljs" "spec/cljs"] ; <- これを追加 :compiler {:output-to "resources/public/js/app_test.js" ; <- これを追加 :output-dir "resources/public/js/test" ; <- これを追加 :source-map "resources/public/js/test.js.map" ; <- これを追加 :externs ["react/externs/react.js"] ; <- これを追加 :optimizations :whitespace ; <- これを追加 :pretty-print false}}}} ; <- これを追加
project rootにbin/specljというファイルを作成して以下のように記述します (※ Speclj公式のtutorialに対してReactの使用も考慮に入れた変更を加えています)
#! /usr/bin/env phantomjs var fs = require("fs"); var webpage = require('webpage').create(); var system = require('system'); var url = phantom.args[0]; webpage.onConsoleMessage = function (x) { system.stdout.write(x) }; webpage.injectJs("env/test/js/polyfill.js"); // note the polyfill file, this is added to play nice with React webpage.injectJs(url); var result = webpage.evaluate(function () { speclj.run.standard.armed = true; return speclj.run.standard.run_specs( cljs.core.keyword("color"), true ); }); phantom.exit(result);
env配下にtest/js/polyfill.jsというファイルを作成し以下のように編集します。 (phantomjsでcomponentを扱うために必要みたい(適当))
if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; }
spec/cljs/foo/core_spec.cljsを作成して以下のようにダミーのspecを記述します
(ns foo.core-spec (:require-macros [speclj.core :refer [describe it should should-not run-specs]]) (:require [speclj.core] [foo.core :as my-core])) (describe "Truth" (it "is true" (should true)) (it "is not false" (should-not false))) (run-specs)
以下のようにClojureScriptをcompileして、testタスクを実行したらSpecljによるClojureScript向けのspecが実行されるはずです
$ lein cljsbuild once $ lein cljsbuild spec
これでclojureでの快適なTDD/BDD環境が整いました!
こんなエラーが出たら
以下のようなエラーが出たらPhantomjsがReactのcomponent操作などに対応できていない可能性があります。
TypeError: 'undefined' is not a function (evaluating 'ReactElementValidator.createElement.bind( null, type )')
おそらくtest/js/polyfill.jsかbin/specljの設定がうまくできていないのでしょう。
polyfill.js or bin/specljを見なおして見てください。
LuminusでJSON APIを作る
ClojureのWebアプリケーションフレームワークLuminusでJSON APIを作る際にRoutingで少し躓いたので手順をメモ
src/APP_NAME/routes/home.clj
これだけではダメ
(defn ping-json [] ; <- 追加 (json {:response "PONG!!!"})) ; <- 追加 (defroutes home-routes ... (GET "/ping" [] (ping-json))) ; <- 追加
namespaceにnoire.responseを追加すると/pingにアクセスしたときJSONが返却されるようになる
(ns APP_NAME.routes.home (:require [compojure.core :refer :all] ... [noir.response :as response])) ; <- 追加 ... (defn ping-json [] ; <- 追加 (response/json {:response "PONG!!!"})) ; <- 追加 (defroutes home-routes (GET "/" [] (home-page)) (GET "/about" [] (about-page)) (GET "/ping" [] (ping-json))) ; <- 追加
Rubyでも音楽をcoding
Clojureで音楽をコーディングする記事をいくつか書いてきました。
実はSonic Piというものを使えばRubyでも音楽をコーディングすることができます。 しかもOvertoneよりも環境構築が簡単。 下記のページからインストーラをDLしてインストールするだけです。
プログラミング教材としての側面もあるようで、 公式サイトには子どもたちがコーディングに取り組んでいる様子も紹介されています。
OvertoneはCUIベースのコーディング環境、jarの依存関係管理など周辺知識が求められるので、 とっつきにくい部分もあるのかなと思いますが、 Sonic PIはインストールしたらすぐ使うことができて、わかりやすいGUIエディタなので さくっと音楽コーディングを体験してみたいという方はこちらから入るのも良いのではないかと思います。
Overtoneで音楽をコーディング時の指針メモ
Overtoneで音楽を鳴らして遊んでいるときにコーディングに関して感じたことのメモ
Overtoneのチュートリアルにあるswingerメソッドはat関数を何度も書いていて冗長
(defn swinger [beat] (at (metro beat) (o-hat)) (at (metro (inc beat)) (c-hat)) (at (metro (+ 1.65 beat)) (c-hat)) (apply-at (metro (+ 2 beat)) #'swinger (+ 2 beat) []))
Swing · overtone/overtone Wiki · GitHub
音の進行をコレクションで表現し、その要素に対して関数を作用させて演奏させられるとスマート。
例えば"音の長さ", "音"のvectorを要素とするリスト(..., [nome, sound], ...)
に
別のチュートリアルにあるlooperメソッドのようなものを作用させるなど
(defn looper [nome sound] (let [beat (nome)] (at (nome beat) (sound)) (apply-by (nome (inc beat)) looper nome sound [])))
Metronome and sequencing · overtone/overtone Wiki · GitHub
また、視点をもう一つ高くして、Aメロ,Bメロ, サビなどのまとまりに作用させる関数を用意するとよりスマートになりそう。
OvertoneをEmacsで演奏してみる
EmacsでOvertoneの演奏環境構築は以下の記事を参照ください
この記事ではOvertoneのGithub WikiにあるSwingのチュートリアルをEmacs Live上でやってみます。
また、前回の記事で作成したClojureプロジェクトを引き続き使っていきます。
事前準備
Emacs Liveを立ち上げる
$ emacs
演奏内容を記載するファイルを開く
任意のcljファイルに演奏内容を記載していきます
ここではとりあえずsrc/hogehoge/core.clj
に記載します
C-x C-f src/hogehoge/core.clj
REPLを立ち上げ
以下のコマンドでREPLを立ち上げます
M-x cider-jack-in
(前回はホスト名やポート番号を指定していたが、この方法だとREPLの立ち上げからやってくれるらしい)
演奏内容の記述
実際に演奏内容を書き連ねていきます
使用するパッケージを記述
namespaseにOvertoneを使用することを明記します
(ns hogehoge.core (:use [overtone.live]))
ハイハット
ハイハットの音をシミュレートする関数を書いていきます
(definst c-hat [amp 0.8 t 0.04] (let [env (env-gen (perc 0.001 t) 1 1 0 1 FREE) noise (white-noise) sqr (* (env-gen (perc 0.01 0.04)) (pulse 880 0.2)) filt (bpf (+ sqr noise) 9000 0.5)] (* amp env filt))) (definst o-hat [amp 0.8 t 0.5] (let [env (env-gen (perc 0.001 t) 1 1 0 1 FREE) noise (white-noise) sqr (* (env-gen (perc 0.01 0.04)) (pulse 880 0.2)) filt (bpf (+ sqr noise) 9000 0.5)] (* amp env filt)))
(ホワイトノイズでハイハットの音を作っているんですね。 こういう音作りも楽しそう。)
関数を書き終わったらカーソルを末尾に置いて、以下のコマンドでREPLに読み込ませることができます (実際どうなっているのかはよくわからない。とりあえず、あとで記述する関数からこれらを呼び出す場合はやっておかないといけない)
C-x C-e
テンポ
(def metro (metronome 120))
Overtoneライブラリのmetronomeという関数を使ってテンポを表現します
演奏内容
Swingの演奏を表現する関数を記述します
(defn swinger [beat] (at (metro beat) (o-hat)) (at (metro (inc beat)) (c-hat)) (at (metro (+ 1.65 beat)) (c-hat)) (apply-at (metro (+ 2 beat)) #'swinger (+ 2 beat) []))
演奏する
演奏内容を表現した関数を呼び出します
(swinger (metro))
この関数末尾で以下のコマンドを実行するとSwingyな音が流れてきます (その前にこれまで書いてきた関数にも以下のコマンドを実行を忘れずに)
C-x C-e
演奏をやめる
演奏内容を表現する関数などを書き換えるなどいろいろ手段はあるかと思いますが、以下の関数で演奏をやめることができます
(stop)
以上。 ここまででClojureを書いてなんか音楽っぽいものを鳴らせるようになりました。
EmacsでOvertone演奏環境構築
OvertoneをEmacsで快適に演奏できるEmacs Liveというものがあるようなので、環境構築をしてみました
Overtoneを使えるようにするまでは以下の手順を参考にしてください。
Overtoneを使ってClojureで音楽をcoding - のぶLab.
Emacs v24.4をインストール
現在、Emacs Liveはv24.3以上でないとダメなようなので、最新版をインストールします
$ brew upgrade $ brew install --cocoa emacs
alias emacs="/usr/local/Cellar/emacs/24.4/bin/emacs"
Setup
※ これは.emacs.dディレクトリを置き換える方法を取るので、普段使っている環境が壊れる可能性があります。必要があればVagrantなどを使って環境を分けるなど対応してください。
$ cd $ git clone git@github.com:overtone/emacs-live.git .emacs.d
$ emacs
コマンドでEmacsを起動
画面にAAでEmacs Liveと表示されていたらOK
OvertoneプロジェクトのREPLを起動
別ターミナルを開いて以下を実行
$ cd hogehoge $ lein repl
EmacsとREPLを接続
以下のコマンドを実行
M-x cider [enter]
ホスト名、ポート番号を聴かれるので入力 hostname : localhost port number : [lein replで起動したREPLのポート番号]
Emacs上のREPLからOvertoneを使ってみる
user> (use 'overtone.live) user> (use 'overtone.inst.piano) user> (piano)
ピアノの音が鳴ればOK
あとがき
音を鳴らすだけならEmacsなど使う必要はないが、 Live Codingなどをする際にはEmacsなどの高機能な環境だと演奏も楽になるかもしれない。
Overtoneを使ってClojureで音楽をcoding
Overtoneとは
プログラミング言語Clojureを使って音楽をコーディングするプラットフォームです このOvertoneを使って活動しているアーティストもいるようです (Meta-eXやRepl Electricなど)
Overtoneを使ってみる
Overtoneを以下の方法でサクッと試すことができます (Mac OS X Yosemite)
Leiningen(GradleとかMavenのClojure版みたいなもの)をインストール
$ brew install leiningen
overtoneプロジェクトの作成
$ lein new hogehoge
projectの依存関係にovertoneを追加
$ cd hogehoge $ vi project.clj
dependenciesにovertoneを追加
:dependencies [... [overtone "0.9.1"]]
REPLを起動
$ lein repl
依存するjarがダウンロードされて、REPLが起動する
起動したら以下のようにしてovertoneを起動
user> (use 'overtone.live)
起動したら試しにピアノを鳴らしてみる
user> (use 'overtone.inst.piano) user> (piano)
これでピアノの音が鳴るはず
もちろん単音だけでなく旋律をコードで表現して演奏することも可能
overtoneから呼び出せる関数は以下のcheat sheetから確認できます
https://github.com/overtone/overtone/raw/master/docs/cheatsheet/overtone-cheat-sheet.pdf
ClojureScriptでNodeJSアプリの作成
ClojureScriptで書かれたNode.js + React + Restify + MongoDBなフルスタックwebアプリ構築メモ
ClojureScriptとは
Clojure同等の記述からJavaScriptへ変換できる言語です
clojure/clojurescript · GitHub
ClojureScript環境構築
ClojureScriptを使う際はleiningenをインストールすると捗るらしい
Clojurescript/Om始めよう #0 - Qiita
ClojureScriptでReactを使う
omというClojureScriptでReactを扱うためのinterfaceがあるので、それを使います
導入方法、使い方は以下を参考に
Clojurescript/Om始めよう #0.5: Figwheelでコードを自動リロード - Qiita
Clojurescript/Om始めよう #1: なぜOmか? - Qiita
ClojureScriptでNodeJS, Restifyを使う
以下を参考に
Getting Started With ClojureScript For Node.js
project.cljのbuildで :target :nodejs
となっているので、client, serverで分ける必要があるかも(ないかも?)
MongoDBを使う
// TODO あとで書く
scopeでmodelにDBアクセス責務を移譲
RailsではModel.where()を使っていろいろな場所で同条件のクエリを発行することが可能だが、 修正が必要になった際に複数箇所修正が必要になったり、DRYの理念に則っていない。
これらをうまく解消するために、scopeという機能を使ってクエリ発行の責務をmodelに任せる
scopeを定義
class User < ActiveRecord::Base scope :activated, -> { where(activated: true)} end
呼び出し方
User.activated
これでscopeに記述した条件のクエリが発行される。
また呼び出し例からわかる通り、where()で条件を記述するよりも scopeで文脈を示す方が何のデータを取得しているのか理解しやすくなる。
scopeを使うとDRYに則した実装になるだけでなく、可読性の向上も期待できる。
Fat Model解消のアイディア
肥大化したActiveRecordモデルをリファクタリングする7つの方法(翻訳) | TechRacho http://techracho.bpsinc.jp/hachi8833/2013_11_19/14738
※ concernにmodelの機能を移しても本質的には何も変わっていない. どこに何があるかわかりにくく見通しが悪い状態は続く
Valueオブジェクト
Serviceオブジェクト
Formオブジェクト
Queryオブジェクト複雑なクエリをここに展開
Policyオブジェクトビジネスルールをカプセル化
- メモリに展開したドメインモデルの操作に特化
Decoratorオブジェクト
ある機能をモデルに含めるとモデルの責務が増える場合にここに任せる
RubyではDecoratorを簡単に作成することが可能
http://robots.thoughtbot.com/evaluating-alternative-decorator-implementations-in
Rails でドメインロジックの実装方法まとめ - assertInstanceOf('Engineer', $a_suenami)
http://a-suenami.hatenablog.com/entry/2014/12/07/200427
- SQLアンチパターン マジックビーンズ
- すべてのModelクラスがActiveRecordを継承している
- ModelがActiveRecordを「持つ」ようにする
- 作者: Eric Evans
- 出版社/メーカー: 翔泳社
- 発売日: 2013/11/20
- メディア: Kindle版
- この商品を含むブログ (2件) を見る
- 作者: Jay Fields,Shane Harvie,Martin Fowler,Kent Beck,長尾高弘
- 出版社/メーカー: アスキー・メディアワークス
- 発売日: 2010/02/27
- メディア: 大型本
- 購入: 9人 クリック: 321回
- この商品を含むブログ (48件) を見る