12/1にiPad mini買いに行ったら全モデル完売したので入荷するまで予約で待てと言われた。
しょうがないので予約したら商品いつ手に入るかわからないし全額払わされるのにポイントが貯まらないし、入荷したかどうかは自分でWebページを見ろという散々な状況です。
気になるけど酷いUI使ってわざわざ見るのもかったるいのでMechanizeにやってもらうことにしました。
herokuにデプロイしてschedulerで毎時0分に実行しています。
12/1にiPad mini買いに行ったら全モデル完売したので入荷するまで予約で待てと言われた。
しょうがないので予約したら商品いつ手に入るかわからないし全額払わされるのにポイントが貯まらないし、入荷したかどうかは自分でWebページを見ろという散々な状況です。
気になるけど酷いUI使ってわざわざ見るのもかったるいのでMechanizeにやってもらうことにしました。
herokuにデプロイしてschedulerで毎時0分に実行しています。
こちらの記事をたまたま見て気になったので投稿。
PHPでforeachなどを使う時の注意点。ブロックスコープのお話。
確かにループで一時的に必要な変数にスコープが無いと都合が悪いのはその通りなんだけど、解決策にモヤモヤ…
スコープが欲しいところに無いなら作ればいいわけで
関数に入れればスコープが作れる。
もっと言えばクラスにすればいいと思う。
転職して新しい職場ではBackboneを使いそうなのに、今までこれで何も作ったことが無いので勉強することにしました。
ひと通り出来るようになるまで続けたいので連載にしてみます。まずは開発環境の構築など
少し前にsendagaya.rbで発表したRails3のAdvanced Constraintsをここでも紹介。
routes.rbの中でURLを定義する時にsubdomainとかを条件に含めるときに使うのがconstraintsというオプションなんですが、これを使ってURLの「?」以降を条件にしたりもできます。
方法はrequestオブジェクトを受け付けるmatches?というメソッドを実装したクラスを定義してインスタンスをconstraintsに渡してあげるだけです。
ここではpostというリソースの集合であるindex、つまり /posts というURLにGETで ?q=hoge 等のパラメータが付いている時に posts_controller#search というアクションに紐付けるということを行なっています。
ただしこのままだと q に対するvalueが空の状態 /posts?q でもsearchアクションに処理が渡るので、コントローラ側で何かしらの対応が必要です。
基本的にはrequestオブジェクトを使って判別できるならどんな条件でもいいので、Accept-languageで振り分けるとかIPアドレスでブラックリストを作るとかもできてしまいます。
今回はindexアクションの中でifで分岐させておくことでも十分対応可能ですが、render以外はほとんど共通処理がないよとかになると、アクションそのものを分けてしまったほうが綺麗なコードになりそうですよね。
すっかりVimに慣れてしまった今日この頃ですが、お世話になったTextMateの2がオープンソースになったのでbuildしてみました。ちなみに環境は OS X lion 10.7.4です。
https://github.com/textmate/textmate.git
READMEにbuild方法は書かれていますね。
とりあえず brew install ragel boost multimarkdown hg ninja とやってみたのですが ninja なんてないよって怒られちゃいました
というわけで先に brew update してから再度実行したらちゃんと入りました
git clone https://github.com/textmate/textmate.git でホームディレクトリにcloneしました
textmate というフォルダができているはずなのでそこに移動 cd textmate
の前に、READMEをみると git submodule update --init とやってねと書いてあるので実行
そして ./configure && ninja 実行!したら clang が古いと言われてしまいました
brew install --HEAD llvm --with-clang で入るはずなんですが、Error: can't convert nil into String とか言われる
brew update も brew doctor も問題ないんだよなぁ
Githubのbug-fixing-checklistを見るとXCodeのupdateして見た方が良さそうだなと思ったので Apple からCommando line tools for XCodeの割と最近のやつをDLした
でやり直しても駄目だなぁ。とよく見てみたらXCode 4.4+と書いてある、手元のXCodeは4.3でした。App Storeから入れ直そう。
気を取り直して ./configure && ninja を再度実行してみた。そしたら今度は pgrep が無いよと言われた
brew install pgrep を実行。(そろそろめんどくさくなってきた)
./configure && ninja よし。こんどこそうまく行ってそう。(なにやらwarningとかdepricatedが出てきてますが)
やっと成功した。
へー2からはPreferencesでbundleとかthemeを追加できるようになってるんですね。逆に言うと最初は何も入ってないからハイライトも何も無いのだけど。
めでたし
git-completionというシェルスクリプトを使えばできるということを知ったのでやってみた。
gitのバージョンを調べる
$ git --version $ 1.7.7.5
github(http://github.com/gitster/git)に行きcodeのtreeを同じバージョンに切り替える(ブランチの切り替え部分と同じところです)
git-completion.bashまでtreeをたどりraw表示に切り替えて保存
自分はhttps://raw.github.com/gitster/git/v1.7.7.5/contrib/completion/git-completion.bashでした
DLしたファイルに使い方は大体書いてあるのでその通りにやれば動くと思います
$ cd ~ $ mv git-completion.bash .git-completion.sh $ vim .bashrc (or .bash_profile) $ PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' を追記 $ source .bashrc
こんなかんじで表示されました
[kozo@kozo-mp current_dir (master)]$
早速OS X Mountain Lionにアップデートしたのでいくつか作業を記録します。
git --version
と打ってみた→消されてる!状況としては、ビデオ一覧ページから各ビデオをiframeを使ったレイヤーで立ち上げるページにて
ビデオはMediaElement.jsというのを使っていて、HTML5対応の判別して、ダメならFlashとかSilverlightとかに切り替えてくれるようになってます。(何も再生手段がなければmp4をDLさせます)
閉じるボタンを押してもビデオが再生されたまま
↓
iframeが非表示になっただけでページ内に生きているから
↓
レイヤーを表示させてるjsを調べる
なんだこれ誰かの自作じゃねえか!closeイベントとか取れねえよ!
↓
親ウィンドウから子iframeにアクセスするか、
子iframeから親ウィンドウに渡すか
後者を選択して window.parent.videos.push(video)
親のレイヤーを非表示にするときの処理に
if (window.videos) { for (var i in window.videos) { if (!window.videos[i].paused) { window.videos[i].pause(); } } }
というのを挟むようにした。
IE、他ブラウザほぼ動く。
↓
IE9だけ動かない!
iframe内で次の動画へ遷移できるようにしてあったんだけど
ビデオのhtmlは一本につき1ファイルなのでこれは単純にリンクを押してるだけ
親から直接ではなくiframe内で遷移後にエラーする。
(でもIEのステータスバーにはエラー表示が出ないんだけどね)
↓
IE9のF12開発者ツールでブレークポイントつけてみる
「解放されたスクリプトからコードを実行できません」
ハァ(゚д゚)?
↓
ググってみた。あぁそういえばIEではJavaScriptじゃなくてJScriptだったな……
つまり信頼性の低いスクリプトから親ウィンドウにあるオブジェクトのメソッドを実行できないってことですかね!!
というわけでpushじゃなくて代入にした。
window.parent.videos[window.parent.videos.length] = video;
↓
動いた!
プロパティの参照と代入は問題ないみたいです。
thinってオワコンじゃないですよね?herokuで採用されているし別にいいですよね。
本当はunicorn使いたかったんですが難しい…… ><;
ぐぐると記事沢山出てきますが uninitialized constant errorで起動しない問題が解決できなくてやめちゃいました。いつかリベンジします。
マシンはvagrant使ってcentos6を用意しました。
参考:http://www.ryuzee.com/contents/blog/4292
vagrantって便利ですね。元々Virtual Boxでwindows動かしてたのですんなりです。ホントに。するっと。
IPアドレスと
config.vm.network :hostonly, "192.168.33.10"
メモリとnameを設定しておきました
config.vm.customize do |vm| vm.memory_size = 1024 vm.name = 'vagrant_centos6' end
rbenv + ruby-buildで1.9.3-p194をインストール
Gemfileのgroup :productionにgem 'thin'を追加して普通にbundle install
config/thin.ymlは
pid: tmp/pids/thin.pid log: log/thin.log servers: 1 port: 3000 daemonize: true environment: production user: vagrant group: staff
以下で起動、停止、再起動
$ be thin start|stop|restart -C config/thin.yml
yumでnginxをインストール(参考:http://blog.livedoor.jp/sasata299/archives/51810645.html)
/etc/nginx/nginx.confは
worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; #tcp_nopush on; keepalive_timeout 65; gzip on; # include /etc/nginx/conf.d/*.conf; upstream backend { server localhost:3000; } upstream backend2 { server localhost:3001; } server { listen 80; server_name centos6.vag; location / { proxy_pass http://backend; } } server { listen 80; server_name 2.centos6.vag; location / { proxy_pass http://backend2; } } }
あとはmacのhostsに
192.168.33.10 centos6.vag 192.168.33.10 2.centos6.vag
を設定してブラウザでアクセス!
でもnginx.confの書き方冗長だなぁもっといいのあるんだろうか。
上記の状態で試しに request.url を覗いてみたら http://backend2/ とかでちゃったよ!困るよ!
というわけでnginx.confを一部修正してみたら問題なく動いた
...省略... upstream 2.centos6.vag { server localhost:3001; } server { listen 80; server_name 2.centos6.vag; location / { proxy_pass http://2.centos6.vag; } } ...省略...
request.url でhttp://2.centos6.vagが返ってきた!
画像など静的ファイルが返らないことがわかったので以下のようにconfig修正
server { listen 80; server_name 2.centos6.vag; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; proxy_max_temp_file_size 0; location ~ .*\.(jpg|JPG|gif|GIF|png|PNG|swf|SWF|css|CSS|js|JS|inc|INC|ico|ICO) { root /home/vagrant/sample2/public; ssi on; break; } location / { proxy_pass http://2.centos6.vag; } }
thinの再起動などダウンタイムにnginxのデフォルトエラーページが返されるのでconfig追加
error_page 500 502 503 504 /500.html;↲ location = /500.html {↲ root /home/vagrant/sample2/public;↲ }
マシンを再起動したときにthinも自動起動するようにした!
/etc/init.d/sampleを作成
#!/bin/sh # chkconfig: 2345 86 25 # description: Sample # PATH=/home/vagrant/.rbenv/shims:/home/vagrant/.rbenv/bin:$PATH eval "$(rbenv init -)" APP_DIR=/home/vagrant/sample THIN_CONFIG=$APP_DIR/config/thin.yml case $1 in start) cd $APP_DIR bundle exec thin start -C $THIN_CONFIG ;; stop) cd $APP_DIR bundle exec thin stop -C $THIN_CONFIG ;; restart) cd $APP_DIR bundle exec thin restart -C $THIN_CONFIG ;; esac exit 0
登録する
$ sudo /etc/init.d/sample start $ sudo chkconfig sample on
タイトルで大体言いきりました。
写真のスライドショーを作成していて、画像タグはJavaScript側で作成してDOMに追加するようにしていました。 何故こうしたかというと、環境によって画像の読み込みが終わらないうちにスライドショーの自動再生が始まってしまうのを防ぐためです。
具体的には以下のようなコードで画像の読み込み完了を待ってDOMに追加しています。
$('').attr(src: '/images/hoge.jpg?' + new Date().getTime()).load (e) => $img = $ e.target $('#container').append $img
'?' + new Date().getTime() の部分ですが、コレをしておかないとIEがonloadイベントをサボるんですよね。。
必ずイベントを発火させるようにしています。
でIMG要素を $ e.target でjQuery化してappendという流れですが、実はこれだとIEでIMG要素がとれていないんです!
気づかずにそのまま処理を進めると画面真っ白になってお馴染みのわかりづらいエラーメッセージにかなり困惑しました。
IE8で以下の様に検証してみました。
A) e.targetでIMG要素が取得できない
$('').attr(src: '/images/hoge.jpg?' + new Date().getTime()).load (e) => console.log e.target.nodeName # => #document
B) e.targetでIMG要素がとれる
$img = $ 'img.sample' $img.attr(src: $img.attr('src') + '?' + new Date().getTime()).load (e) => console.log e.target.nodeName # => IMG
違いはJSで要素を作成するか、htmlに記述されている要素を取得するかですね。
まぁぶっちゃけ loadのcallback内でthisが対象のIMG要素なのでコレ使えばいいんですよ。
でもCoffeeScriptつかってclass化したオブジェクトの中だと @(this) は常にクラスそのものとして使いたいので、
関数のthisにバインドしてくれる => を使いたいんですよね。
というわけで jQuery.Event オブジェクトの出番なわけです。
Aの方法だとIEで期待通りでないことがわかったので調べたところ、jQuery.Event.currentTarget というのがありました。
console.log e.currentTarget.nodeName でちゃんとIMGが返ってきたよ〜!
今後調べたいこと
追記:
herokuでphpが動くのは前々から知っていたのですが、mbstringが有効なphpがいとも簡単に動くという情報を見つけたので試してみました。
$ mkdir heroku-php $ git init $ vim index.php <?php phpinfo(); $ git add . $ git commit -m "initial commit" $ heroku create --buildpack https://github.com/winglian/heroku-buildpack-php -s cedar $ git push heroku master
こんだけ!?全然難しくないですね。
heroku openしてみたらちゃんとphpinfoが表示されました。
でも気になったのがindex.phpの設置場所。
基本phpはindexに相当するものを設置しなければいけないと思うのですが、これってpublicディレクトリにしても動くのだろうか…?
$ mkdir public $ git mv index.php public/ $ git commit -am "moved index.php" $ git push heroku master -----> Heroku receiving push -----> Fetching custom buildpack... done ! Heroku push rejected, no Cedar-supported app detected
ガーン!…そもそもアプリのルートにindex.phpが無いと受け付けてくれないのか。
ということは環境変数DOCUMENT_ROOTとか使えないのかな?
$ heroku config:add DOCUMENT_ROOT=/app/www/public Adding config vars and restarting app... done, v5 DOCUMENT_ROOT => /app/www/public
まぁ無理でした。環境変数はセットできても何の意味も無いですね。ググっても情報みつからないので多分このオプションは存在しないのでしょう。
アプリそのものが公開ディレクトリなのはそれはそれでphpらしいですよね。
しかしphp速い感じする。ただのphpinfoというのもあるだろうけど、アプリの更新しても再起動が無いからか。
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.coffeedescribe "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の情報とかは実行ファイルに書き込むようにするといいと思います。
サイトのトップページにスライドショー的なものを設置するなら例えば以下の様な感じです。
$ -> slideshow = new window.Slideshow { container_id: '#hoge-slideshow' controller_id: '#hoge-controller' duration: 800 wait: 3000 } slideshow.start()
要はリテラル値をまとめて書いておくということです。
ただこのように実行ファイルに分けていてもファイル名が script とかにする人がいたりして…それはそれでわからなくはないのですが、mainの方が無難じゃないですかねぇ。
あぁマシン持ち寄ってこうゆう話ししながら酒を呑む仲間がほしいなぁ…
ひょんなことからjQueryの視覚系プラグインを2つ書きました。
ソースというかデモサイトまるごとgithubにあります。
jquery.limp.js
要素をfixed配置に変えて縦スクロールに対して少し遅れてついてくるというものです。
いわゆるパララックス効果的に使えるんじゃないかと思います。
limpという名前はlimpbizkitからとりました。僕の青春です。
こちらもデモサイトまるごとgithubにあります。
jquery.airy.js
要素をabsoluteで配置しておくとフワフワとその場を浮遊するというものです。
こちらは使い道が難しいですね。
両者ともcoffeescriptで書いてsinatraでサーブしてるのですが、素のjavascript書くのしんどいですね最近……
まずはFormulaを検索
$ brew search apc josegonzalez/php/php53-apc josegonzalez/php/php54-apc
2つありました。 phpはv5.3.10なのでphp53-apcをインストールします。
リポジトリを追加
$ brew tap josegonzalez/php Cloning into '/usr/local/Library/Taps/josegonzalez-php'... remote: Counting objects: 1011, done. remote: Compressing objects: 100% (491/491), done. remote: Total 1011 (delta 480), reused 929 (delta 416) Receiving objects: 100% (1011/1011), 140.43 KiB | 109 KiB/s, done. Resolving deltas: 100% (480/480), done. Tapped 48 formula
インストール実行
$ brew install php53-apc ...... To finish installing php53-apc: * Add the following lines to /usr/local/etc/php.ini: [apc] extension="/usr/local/Cellar/php53-apc/3.1.10/apc.so" apc.enabled=1 apc.shm_segments=1 apc.shm_size=64M apc.ttl=7200 apc.user_ttl=7200 apc.num_files_hint=1024 apc.mmap_file_mask=/tmp/apc.XXXXXX apc.enable_cli=1 * Restart your webserver. * Write a PHP page that calls "phpinfo();" * Load it in a browser and look for the info on the apc module. * If you see it, you have been successful! * You can copy "/usr/local/Cellar/php53-apc/3.1.10/apc.php" to any site to see APC's usage. ......
指示通りphp.iniに設定を追加して、php-fpmを再起動 (これがいまいちまだよくわかってない…)
$ ps ax | grep php 493 ?? Ss 0:00.17 /usr/local/Cellar/php/5.3.10/sbin/php-fpm 494 ?? S 0:01.15 /usr/local/Cellar/php/5.3.10/sbin/php-fpm 495 ?? S 0:01.37 /usr/local/Cellar/php/5.3.10/sbin/php-fpm $ kill -TERM 493 $ php-fpm
↑とりあえずkillしてから実行してみてる phpinfo()で確認OK!
このギャラリーの作品はどれもレベル高くてすごい
Chrome Experiments - WebGL Experiments
見てたらWebGLをかじってみたくなったのでThree.jsというのを試してみた。
リポジトリを落としてきてsinatraに乗っけてherokuにアップしときました。
Three.js Learning
トップページはexamplesの一覧です。
とりあえず本家のGet Starttingで試してみたけど、動かないとつまらないのでマウスの動きに反応するようにした。
うーん道のり長そうだなぁ
iPhoneだと動かないのかな?
railsのform_forヘルパーは以下のように使いますよね
= form_for(@post) do |f| = f.label :title = f.text_field :title
こう書いておけば出力されるhtmlは
大体こんな感じになるかと。
でrailsの便利なところはform_forに渡してるモデルオブジェクトが、空なのかDBのレコードから生成されたのかを判別して、actionの属性値をよしなに変更してくれるところですよね。
つまりroutesに
resouces :posts do end
と書いてあれば 新規作成時は action="/posts"
だし編集画面では action="/posts/1"
になると。
でもこれが namespace 付きのroutesだとうまく行かなくて困りました。
管理画面を作る場合とかだと /admin/posts にしたくて
namespace :admin do resources :posts do end end
と定義しておいて、form_for で生成したフォームを上記のままにしておくと、undefined method `posts_path' と怒られてしまう。 一瞬下記のやり方?とか思ったんですがrailsに限ってそんなことないよね…
= form_for params[:action] == 'new' ? admin_posts_path : edit_admin_post_path(@post) do |f| = f.label :title = f.text_field :title
ぐぐったら出てきた。
Rails Routes Namespaces and form_for - Stack Overflow= form_for [:admin, @post] do |f|...
だってさ!
配列で指定するんですか。なるほどこれで admin_posts_path と edit_admin_post_path を切り替えてくれるんですね。
ということは…やってみた。
namespace :hoge do namespace :fuga do namespace :foo do namespace :bar do resources :hellos do end end end end end
= form_for [:hoge, :fuga, :foo, :bar, @hello], do |f| = f.label :name = f.text_field :name
成功\(^o^)/
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の詳しい使い方はドキュメントを読もー
まずはnginxのインストール。
$ brew options nginx nginx --with-passenger Compile with support for Phusion Passenger module --with-webdav Compile with support for WebDAV module
今回はどちらもいらないので普通に brew install nginx で設定をいじる。
$ cd /usr/local/etc/nginx $ vim nginx.conf
#user nobody; worker_processes 1; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; include /usr/local/etc/nginx/sites-enabled/*; }こうしておいた
$ mkdir sites-enable $ mkdir sites-available
このディレクトリ必要なの?って思ったけど、シンボリックリンクの作成/削除で複数ファイルの管理ができるよってことなんですね。なんかかっこいいですね。
で、availableの方に…
$ vim sites-available/localhost server { listen 8080; server_name localhost; root /Users/kozo/Web/nginx/localhost/public; access_log /Users/kozo/Web/nginx/localhost/logs/access.log; error_log /Users/kozo/Web/nginx/localhost/logs/error.log warn; location / { index index.html index.htm index.php; } location ~ \.php$ { include fastcgi_params; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } }
とした。
続いてphpのインストール。
$ brew options https://raw.github.com/ampt/homebrew/php/Library/Formula/php.rb php --with-mysql Include MySQL support --with-pgsql Include PostgreSQL support --with-mssql Include MSSQL-DB support --with-fpm Enable building of the fpm SAPI executable --with-apache Build shared Apache 2.0 Handler module --with-intl Include intl extension --with-readline Include readline extension
適当にオプション付けて
$ brew install https://raw.github.com/ampt/homebrew/php/Library/Formula/php.rb --with-mysql --with-pgsql --with-fpm --with-intl --with-readline
そしたらエラー!
ココでも見てなんとかしろや的なこと言われたので見てみる
https://github.com/mxcl/homebrew/wiki/checklist-before-filing-a-new-issue
brew updateか。
$ brew update
またエラー。というかgitのリポジトリでconflict的なことが起きてるのかな?
$ cd /usr/local/ $ git fetch origin/master $ git reset --hard origin/master $ brew update Already up-to-date.
OK! phpのインストール出来ました。 このままだとcliがMacにプリインストールされてる方を見ちゃうので
$ vim ~/.bash_profile $ export PATH="$(brew --prefix)/bin:$PATH"
上記を追加しました。
$ php -v PHP 5.3.10 (cli) (built: Apr 16 2012 17:15:01) Copyright (c) 1997-2012 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies with Xdebug v2.1.2, Copyright (c) 2002-2011, by Derick Rethans
よし。で、fpmの起動用plist作成
$ vim ~/Library/LaunchAgents/php-fpm.plist
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd" > <plist version='1'> <dict> <key>Label</key><string>org.php.php-fpm</string> <key>ProgramArguments</key> <array> <string>/usr/local/sbin/php-fpm</string> <string>--fpm-config</string> <string>/usr/local/Cellar/php/5.3.10/etc/php-fpm.conf</string> </array> <key>Debug</key><false/> <key>RunAtLoad</key><true/> <key>KeepAlive</key><false/> <key>UserName</key><string>kozo</string> </dict> </plist>
※.plistの拡張子付けないと後のlaunchctl loadで怒られました
php-fpm起動!
$ launchctl load -w ~/Library/LaunchAgents/php-fpm.plist
最終確認
$ cd ~/Web/nginx/localhost/public/ $ vim index.php <?php echo 'Hello' ?>
と書いて http://localhost:8080/ を開いて Hello でました! 思ってたより簡単だったけどちょっと戸惑った。
参考にしたサイト
※追記 2012/04/17
再起動はこうすればいいらしい:
$ sudo nginx -s stop && sudo nginx
自分にはテック系の記事は書けない(&続かない)ことがわかったし、一人暮らしが2年目に入って、寂しさを紛らわす意味もあってトマトの栽培を始めることにしたから、とりあえずトマトを記事にしてみることにした。
第一回目は買ってきたものとその準備。
この品種のトマトは支柱が要らないタイプ(パッケージの説明書きに書いてあった)なのでお手軽に出来そうだからこれにした。
全くの初心者だから何一つ自信ないけど、土のパッケージとか参考にしながら土を準備。
写真は赤玉土を底に敷いて、培養土を3〜4cm敷いたら肥料を混ぜて、また培養土を重ねる感じでつくってみた。
白いのは種の袋。種を袋から出してみてびっくりしたんだけど、普段食ってるトマトと何も違わなかった。そりゃ当然だよねトマトなんだから。
それにしても種あまりすぎ…こんなちっちゃいプランターじゃ全然減らない。これ保存が効くのだろうか……?
3つ穴をつくって種まいてみた(暗くて見えない)
で、発芽するまでは土を乾燥させすぎない暖かい所がいいらしいんだけど、今年は4月に入ってもなかなか気温が上がらない。
なのでゴミ袋でビニールアウス的にしてみることにした。
あまった土をまとめた袋と並べて置いたらゴミにしか見えない…
初日はこんなところ
で、式展開ってこれでいいのかな?
気になってるのは該当のする#{}がすべて置き換わった後もループを続けてしまうところ。
まだまだブラッシュアップできる気がするなぁ。
PHPの代わりというか、次のレベルとしてRubyを使うならまず最初にbundlerの使い方を知っておきたかった。 以下自分なりに覚えたbundlerの使い方を記録しておく。
作業ディレクトリを作る。
$ mkdir hoge_project
railsなんかはディレクトリ名がそのままアプリ名になっちゃうから気をつける
(これってオプションでディレクトリ名と別の名前渡せるのかな??)
作業ディレクトリでbundlerのinitを実行する。
$ cd hoge_project $ bundle init Writing new Gemfile to /Users/username/hoge_project/Gemfile
これでサンプルのGemfileが作られる。
▼内容
# A sample Gemfile source "http://rubygems.org" # gem "rails"
▼一行目を削除し、四行目のコメントアウトを外してバージョンを3.1.3に指定
source "http://rubygems.org" gem "rails", "3.1.3"
プロジェクトローカルな状態でgemをインストール
$ bundle install --path vendor/bundle
地味にbundlerの便利なところはこの時点でvendorフォルダの有無に関わらずインストール出来ちゃうところ。
Fetching source index for http://rubygems.org/ Installing rake (0.9.2.2) Installing multi_json (1.0.4) Installing activesupport (3.1.3) Installing builder (3.0.0) Installing i18n (0.6.0) Installing activemodel (3.1.3) Installing erubis (2.7.0) Installing rack (1.3.6) Installing rack-cache (1.1) Installing rack-mount (0.8.3) Installing rack-test (0.6.1) Installing hike (1.2.1) Installing tilt (1.3.3) Installing sprockets (2.0.3) Installing actionpack (3.1.3) Installing mime-types (1.17.2) Installing polyglot (0.3.3) Installing treetop (1.4.10) Installing mail (2.3.0) Installing actionmailer (3.1.3) Installing arel (2.2.1) Installing tzinfo (0.3.31) Installing activerecord (3.1.3) Installing activeresource (3.1.3) Using bundler (1.0.21) Installing json (1.6.5) with native extensions Installing rack-ssl (1.3.2) Installing rdoc (3.12) Installing thor (0.14.6) Installing railties (3.1.3) Installing rails (3.1.3) Your bundle is complete! It was installed into ./vendor/bundle
こんな感じでインストール完了。
最初はrails以外のgemがわんさかインストールされちゃってる事にかなりびっくりしました。
今なら依存関係があるから当たり前やんって思うけど、この辺のニュアンスってなかなか初心者には分かりづらい。
ここまでだとrailsアプリはまだ出来てないのでスケルトンを作る
$ bundle exec rails new . -T -d mysql
このコマンドの意味するところは
プロジェクトローカルのgemを使い、
railsの新しいアプリケーションをこのディレクトリで作成し、
かつtestディレクトリを省略し、
DBはmysqlを選択
ということです。
▼で実行するとこんな問いかけをくらう
exist create README create Rakefile create config.ru create .gitignore conflict Gemfile Overwrite /Users/username/hoge_project/Gemfile? (enter "h" for help) [Ynaqdh]
既存のGemfileをrails仕様に上書きしてもいいか?ということで問題ないので enter
force Gemfile create app create app/assets/images/rails.png ... 省略 ... run bundle install
でここでエラーが発生するんですよねぇ…
/Users/username/.rvm/gems/ruby-1.9.2-p290@global/gems/bundler-1.0.21/lib/bundler/resolver.rb:280:in `resolve': Could not find gem 'jquery-rails (>= 0) ruby' in any of the gem sources listed in your Gemfile. (Bundler::GemNotFound)
でも気にせずrspecをGemfileに追加
group :development, :test do gem 'rspec-rails' end
でbundle installに再チャレンジ
$ bundle install Fetching source index for http://rubygems.org/ Installing coffee-script-source (1.2.0) Installing execjs (1.3.0) Installing coffee-script (2.2.0) Installing coffee-rails (3.1.1) Installing diff-lcs (1.1.3) Installing jquery-rails (1.0.19) Installing mysql2 (0.3.11) with native extensions Installing rspec-core (2.8.0) Installing rspec-expectations (2.8.0) Installing rspec-mocks (2.8.0) Installing rspec (2.8.0) Installing rspec-rails (2.8.1) Installing sass (3.1.12) Installing sass-rails (3.1.5) Installing uglifier (1.2.3) Your bundle is complete! It was installed into ./vendor/bundle ※既にインストール済みの行は省きました
よし!
これでrailsアプリのスケルトン出来ました。
後はrailsコマンドとかrakeするときに常に bundle exec を付けておけば
プロジェクトローカルのgemで実行されます。
アプリケーション毎のbundlerの設定は bundle config で確認できる(.bundle/configファイルの中身を見てる)
$ bundle config Settings are listed in order of priority. The top value will be used. path Set for your local app (/Users/username/hoge_project/.bundle/config): "vendor/bundle" disable_shared_gems Set for your local app (/Users/username/hoge_project/.bundle/config): "1"
開発用サーバを起動
$ bundle exec rails s => Booting WEBrick => Rails 3.1.3 application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server [2012-01-31 17:06:22] INFO WEBrick 1.3.1 [2012-01-31 17:06:22] INFO ruby 1.9.2 (2011-07-09) [x86_64-darwin10.8.0] [2012-01-31 17:06:22] INFO WEBrick::HTTPServer#start: pid=1895 port=3000
ちなみにこの時に -p (ポートオプション)を付ければ好きなポート番号でWEBrickを起動できますね
まだ初心者が知っておいたほうがいい事があって、
バージョン管理している場合気を付けなくちゃいけないのは vendor/bundle ディレクトリは管理の対象にしないこと。
これって本業のプログラマーさんなら当たり前なんだろうけど。
mysql2とか、環境に依存するgemもあるから環境毎にbundle installするべきだってことに気づくのが大分遅かった…