ラベル coffeescript の投稿を表示しています。 すべての投稿を表示
ラベル coffeescript の投稿を表示しています。 すべての投稿を表示
2012年6月1日金曜日

CoffeeScriptでJavaScriptもクラス化しよう。テストを書きやすくメンテしやすく

CoffeeScriptを知ったのはRailsに組み込まれたからですが、Rails3.1で採用されてすぐに飛びついたわけではなく、しばらく敬遠してた時期もありました。しかし使い始めてからはもう手放せなくなりました。
そして次第にCoffeeScriptのclass構文を使えばよりよいJavaScriptの開発ができるのではないかと思うようになりました。
今回は最近CoffeeScriptを使ってどのように開発しているかを紹介したいと思います。

CoffeeScriptでのclass定義はこうやります

class Person
  constructor: (@my_name) ->

  greeting: ->
    alert "Hello! my name is #{@my_name}."

window.Person = window.Person || Person

コンパイルすると以下のようなJavaScriptになります

(function() {
  var Person;

  Person = (function() {

    Person.name = 'Person';

    function Person(my_name) {
      this.myname = my_name;
    }

    Person.prototype.greeting = function() {
      return alert("Hello! my name is " + this.my_name);
    };

    return Person;

  })();

  window.Person = window.Person || Person;
}).call(this);

※nameプロパティを使うと上書きしてしまうのでmynameとしました

例えばこのようなコードを person というファイル名で保存し、インスタンス生成は main という別ファイルで実行します。

main.coffee
$ ->
  kozo = new window.Person 'kozo'
  kozo.greeting()
main.js
(function() {
  $(function() {
    var kozo;
    kozo = new window.Person('kozo');
    return kozo.greeting();
  });
}).call(this);

こうすることでまず管理がしやすくなりますし、テストも気持ちよく書けると思います。

テストフレームワークはよく jasmine をつかっています。その前は QUnit だったんですが jasmine の方がドキュメントが探しやすいのとツールが整っている印象ですし、なによりコードが書きやすく後からでも見やすいですね。人によるかも知れませんが。
僕の場合CoffeeScript を使うときはほぼ Rails か sinatra 上ですので jasmine-headless-webkit というgemをつかってます。これを使うとCUIで実行結果が得られます。(jasmine-railsはこれに依存しています)

jasmineの諸々の設定は省略しますがテストコードはこんな感じにしています。

person_spec.coffee
describe "Person", ->

  beforeEach ->
    @person = new window.Person 'sample'

  afterEach ->
    delete @person

  describe "propaties", ->
    it "have 'my_name' string", ->
      expect(typeof @person.my_name).toBe "string"

  describe "greeting method", ->
    beforeEach ->
      spyOn window, "alert"
      @person.greeting()

    it "alert greeting text", ->
      expect(window.alert).toHaveBeenCalledWith "Hello! my name is sample."

DOMが絡むテストは jasmine-fixture というのをhelperとして読み込んで使っています。jqueryに依存しているのですが、むしろ使わない事のほうが少ないので気にしないです。affix という便利メソッドが使えるようになって、jqueryオブジェクトのprototypeにも追加されるので気に入ってます。

以上のような形で開発を進めてるのですが、クラスファイルと実行ファイルを分けてなるべくDOMの情報とかは実行ファイルに書き込むようにするといいと思います。
サイトのトップページにスライドショー的なものを設置するなら例えば以下の様な感じです。

main.coffee
$ ->
  slideshow = new window.Slideshow {
    container_id: '#hoge-slideshow'
    controller_id: '#hoge-controller'
    duration: 800
    wait: 3000
  }
  slideshow.start()

要はリテラル値をまとめて書いておくということです。

ただこのように実行ファイルに分けていてもファイル名が script とかにする人がいたりして…それはそれでわからなくはないのですが、mainの方が無難じゃないですかねぇ。

あぁマシン持ち寄ってこうゆう話ししながら酒を呑む仲間がほしいなぁ…

2012年4月27日金曜日

[ruby]最初に知っておけば良かったbundlerの使い方 sinatra編

rails編は以前書いたのでsinatraでやってみる
用途としてはDBとかいらないスタティックなサイトの構築で、でもhtml、css、jsを生で書くのとか耐えられない。phpはマジ勘弁みたいなときにこうしてますよって感じのことを書きます。

(bundlerの使い方ってゆうかrubyでのweb制作全般って感じですね…)

まず適当な場所にプロジェクトのディレクトリを作ります。
hogeとかもアレなんでポートフォリオにしときます。

$ cd ~/Web
$ mkdir portfolio
$ cd portfolio

でプロジェクトのルートでGemfileをつくる

$ bundle init
Writing new Gemfile to /Users/kozo/Web/portfolio/Gemfile

中身はこんな感じだから...

$ vim Gemfile
# A sample Gemfile
source "https://rubygems.org"

# gem "rails"

以下に書き換えます

source "https://rubygems.org"

gem "sinatra"
gem "sass"
gem "haml"
gem "coffee-script"
gem "shotgun"

自分はnode.jsを入れてるんでアレですが、環境によってはjavascript実行環境が無いと怒られるかもしれないんで、そんときは以下のgemを足してみてください。

gem 'therubyracer'

でgemをインストールします。

bundle install --path vendor/bundle --without production

Fetching gem metadata from https://rubygems.org/.....
Installing coffee-script-source (1.3.1) 
Installing multi_json (1.3.2) 
Installing execjs (1.3.0) 
Installing coffee-script (2.2.0) 
Installing haml (3.1.4) 
Installing rack (1.4.1) 
Installing rack-protection (1.2.0) 
Installing sass (3.1.16) 
Installing tilt (1.3.3) 
Installing sinatra (1.3.2)
....

よしこれでgemが揃いました。
さらに作業環境を整えます。

sinatraを動かすアプリが必要なので app.rb と config.ru
sassやhamlを入れておくviewsディレクトリ、
ドキュメントルートになるpublicディレクトリをつくります。

$ touch app.rb
$ touch config.ru
$ mkdir views
$ mkdir public

アプリケーションのコードはこんな感じです

$ vim app.rb
require "sinatra/base"
require "sass"
require "haml"
require "coffee-script"

module Portfolio
  class App < Sinatra::Base
    get '/' do
      'hello'
    end
  end
end
$ vim config.ru
require "./app"
run Portfolio::App

でアプリがちゃんと動くかどうか確認してみる
shotgunを入れておいたので

$ bundle exec shotgun
== Shotgun/WEBrick on http://127.0.0.1:9393/
[2012-04-26 23:49:20] INFO  WEBrick 1.3.1
[2012-04-26 23:49:20] INFO  ruby 1.9.2 (2011-07-09) [x86_64-darwin11.2.0]
[2012-04-26 23:49:20] INFO  WEBrick::HTTPServer#start: pid=457 port=9393

localhost:9393にアクセスして hello が表示されればOKです
そしたらこっからガシガシコード書いていくんですが、shotgun使ってるのでapp.rbを編集してもサーバの再起動が必要ありません。
home、about、galleryの3ページと仮定して以下のように書き換えました

$ vim app.rb
module Portfolio
  class App < Sinatra::Base
    before do
      @site_name = 'My Portfolio'
      @nav = ['home', 'about', 'gallery']
    end
    
    get '/' do
      haml :index
    end

    get '/about/?' do
      haml :about
    end

    get '/gallery' do
      haml :gallery
    end
  end
end

before do ... end の中で共通の処理を記述できます。
site_nameとnavを用意しておきました。変数に@をつけておくとインスタンス変数と言ってviewに渡せるようになります。
htmlはhamlで書くので以下のようにします。

$ vim views/index.haml
%h1= @site_name
%nav
  %ul
    - @nav.each do |n|
      %li
        %a{href:"/#{n}"}= n
%p welcome to my portfolio site

でもこれだとheadとかないので layout を作成します

$ vim views/layout.haml
!!! 5
%html
  %head
    %meta{charset:'utf-8'}
      %title= @site_name
  %body
    = yield

yieldの部分に各ページの内容が入ります。
次はsassというかscssを使ってみます。
まずはapp.rbを編集して、

$ vim app.rb
get '/stylesheets/base.css' do
  scss :base
end

galleryの下に追記しておきました。
ここまで出来たら後はviews内にscssファイルを作って作業していくだけです。
簡単ですね!

ちなみにrubyのシンボル(:で始まる文字列)は " で囲めば / とかも使えるので
views内でファイルが平置きになってるのが嫌な人は views/haml や views/scss を作っておいて
app.rbで

haml :"haml/index"

と指定すればちゃんと呼び出せますよ!

sinatraとかhamlとかscssとかcoffeescriptの詳しい使い方はドキュメントを読もー