2011年12月12日月曜日

devise を使う

ちょっと前に Rails + OmniAuth + OAuth on Twitter/Facebook でユーザ認証のサンプルを作ってみたのですが、認証に関する便利な仕組みとして Devise というのを知ったのでそちらを使ってみることにしました。

なお、OmniAuth との連携については wiki ページに情報があります。
最終的には OmniAuth との連携の形に持っていきたいと思います。

まず最初に

https://github.com/plataformatec/devise の Installation の項目にある部分:
  • Devise の gem のインストール
  • Gemfile への追記: gem 'devise'
  • rails g devise:install
  • rails g devise user
  • rails g devise:views
までを行いました。
"rails g devise:install" の後にメッセージが出ます。要約すると:
  1. config.action_mailer.default_url_options を設定せよ
    • config/environments/development.rb だと、"{ :host => 'localhost:3000' }" とか
  2. config/routes.rb にて、root_url を設定(root :to を定義)せよ
    • トップページを表現する適当な controller を用意して、"...#index" とかにしておけば良いはず
  3. app/views/layouts/application.html.erb (つまり global_layout)で notice, alert が表示されるようにせよ
    • こんな感じ。"<p class="notice"><%= notice %></p>"
  4. heroku 上にデプロイする場合には、config/application.rb にて config.asset.initialize_on_precompile = false を宣言せよ
の4点です。
この devise:install 時のメッセージに従って作業すると1/3位の設定が終わります。

もう一つの準備

とりあえず「認証によって保護されるリソース」 を考えないと認証の意味が無いので、todo モデルを作っておきます。
rails g scaffold todo summary:string content:text importance:integer rake db:migrate
この todo を、認証した user だけがアクセスできるようにします。

リソースの保護

リソース todo へのアクセスを認証で制御するには、
  1. app/controllers/todos_controller.rb の修正
    • before_filter :authenticate_user!
  2. routes.rb の修正
    • devise_for :users
とします。
また、ログイン情報入力のための画面を用意した場合、
  • ログインしていないなら、ログイン情報入力画面
  • ログイン済みなら、 ログイン後のトップ画面
のような構成を作りたいと思います。
このような時には devise で提供されている current_user メソッドを使って、
class PortalController < ApplicationController
  def index
    if current_user
      redirect_to :user_root
      return
    end
  end
end
のようなことができます。

2011年12月11日日曜日

rails 環境の準備

何度やっても覚えないので覚えないことにしました。
  1. rvm use 1.9.2@rails3
    • (もちろん 1.9.2 の ruby とか rails3 の gemset は用意しておくべし)
  2. rails new APP_NAME
  3. vi APP_NAME/.rvmrc : 以下の内容で作成
    • rvm use 1.9.2@rails3
  4. cd APP_NAME
  5. vi Gemfile : 以下の内容を追記
    • gem 'therubyracer'
    • gem 'rspec-rails'
  6. bundle install (上記の gem は rails3 gemset に既にインストールされているので必要無し)
  7. rails g rspec:install
  8. rm public/index.html
  9. git init
  10. git add .
  11. git commit
これで、新しい rails アプリを立ち上げて、rspec を使うようにして、git 配下に置く事ができます。

文書にしてみて分かったこと → スクリプトにすれば良いのだ…。

今日も javascript の話

Rubyのことを書くブログだったんですけどね…。

画像の切り替え(同一のエリアに複数の画像をスライドショーのように表示する)を行う javascript を実現しようとして、「そんなの jQuery で一発だろう」と思っていたら、思いのほか基本機能には存在しませんでした。

ということで、「それでも誰かが作っているはずだ」と探したところ、InnerFade with jQuery というのを見つけました。
試してみたら思った通りの挙動をしてくれます。flash のことは嫌いじゃないんですが、やっぱりアクセシビリティということだと厄介な存在だとは思うんで、ちょっとずつ代替手段を見つけていきたいところです。

2011年11月30日水曜日

github のセットアップ on Windows

Github のページを参考に私物 Windows で github が使えるようにしてみます。

準備

使えるようにするための手順:
  1. Git for Windows をダウンロード&インストール
  2. インストールした Git bash を使って以下を実行:まずは暗号鍵の生成
    1. mkdir .ssh
    2. ssh-keygen -t rsa -C "my-email@add.re.ss"
      • 暗号鍵ファイルはデフォルトの .ssh/id_rsa{,.pub}
      • パスフレーズは適当に設定
    3. cat .ssh/id_rsa.pub 
      • 次の手順で内容が必要になるので表示させておく
  3. 公開鍵を github のアカウントに設定(コピペ)
  4. 接続テスト
    1. ssh -T git@github.com
  5. git クライアントの設定
    • git config --list で確認
    • git config --global 属性名 値
      • user.name, user.email, github.user, github.token

レポジトリの作成

次はレポジトリを作ります。
手元にあった hta アプリケーションをレポジトリに登録してみます。ちなみにこの hta アプリケーションは「学生に ping とか netstat とかをGUIで使わせたいんだよね」という先生の話を聞いて作ったものです。高校とか大学とかの情報教育に役に立てればうれしいのですが…。
  1. github のサイトで "New repository" ボタンを押す
  2. Project name を決めて "Create repository" ボタンを押す
    • 今回の Project name は netcmd-hta としました。
  3. レポジトリが作成される。そのページに表示される指示に従って git bash で作業:
    1. (適当な場所で)mkdir netcmd-hta
    2. cd netcmd-hta
    3. git init
    4. touch README
    5. git add README
    6. git commit -m 'first commit: add README'
    7. git remote add origin git@github.com:kazunori-kawauchi/netcmd-hta.git
      • origin という名前で github の netcmd-hta.git を参照する(リモートとの関連付け)
    8. git push -u origin master
      • commit した内容をリモートに対して push
こうやって作ったレポジトリにファイルやディレクトリを作っていって、add & commit & push して github 側に載せることができるようになりました。

ということで一応、リンクも載せておきます。
https://github.com/kazunori-kawauchi/netcmd-hta


OAuth について

…久々のブログだ。
というのはさておき。

ちょっと勉強のために OmniAuth を使った OAuth 認証を行えるサンプルの Rails アプリを作ってみました。
# OAuth で「認証」をやっている、と書くだけで素人臭さ全開ですね…。

OAuth の相手にはひとまず Twitter を選んでいます。
思ったよりも大変で1日掛かりでショボショボのサンプルが動きました。

認証基盤などは大雑把に理解しているつもりでしたが、概要と詳細の実現方法には大きな隔たりがある、実際にやってみることが大事だ、ということを再確認することになりました。
今回一番ハマッたのは
  • Twitter 側の Callback URL に(テスト環境なので…)http://127.0.0.1:3000/auth/twitter/callback/ を指定する
ところでしょうか…。
後は OmniAuth がよろしくやってくれました。

2011年11月14日月曜日

vForum2011 に行ってきました

Ruby とは全く関係の無い話ですが、vForum2011 というVMware社が主催するイベントに参加してきました。

事前に興味を持っていたのは
  • 仮想デスクトップ環境
  • 仮想環境のバックアップ
辺りだったので、ほとんどその周辺技術のみの情報収集に終始しました。

仮想デスクトップ

BCP(Business Continuity Plan: 事業継続計画)の観点から仮想デスクトップが注目されているそうです。
3月11日の震災の影響もあり、日本でも一気に導入が進みうる状況が出来上がっています。

個人的には、「数百台のデスクトップマシンを集約的に管理するツール」として使えるかどうかを見に行ったのですが、
  • ○:多くのマシンを管理するのには向いていそう
    • ネットブート等に比べてもサーバ1台あたりのクライアント数が多い(最大100台くらいまでいける)
    • 仮想ゲストOSのテンプレートから各ユーザに割り当てる仮想ゲストを作成し、重複部分は共有できる
  • ×:描画のパフォーマンスはチューニング次第でそこそこ出るが、動画や音声を伴うと辛い
などの情報を受けて「教育用環境(特に言語学習)には採用しづらい部分がある」という判断を勝手に下しました。言語学習はどうしても外せない部分なので、「一括管理」を目指すのであればそこだけ分離させるのはどうも筋が悪そうに思えます。

そうなると教職員向けの環境としての仮想デスクトップの方が導入しやすい気がしてくるなぁ…。
教職員の方も、それはそれで「いつまでも Excel 2003を使う」みたいな状況があるので、アプリケーション仮想化と組み合わせて考えないといけないのですけれど…。

Rubyベストプラクティス 3章(中盤)

前・後編にしようと思ったら思いの外、内容がボリュームあって読むのに時間がかかってブログの更新も止まりがちです…。
ひとまず細かく分けることにしました。

ということで、今回は 3.3節 の特異メソッドの話のみです。

3.3節 オブジェクトごとの振る舞い

普通のオブジェクト指向プログラミング言語では振る舞いをクラスに結び付けて定義します。
Rubyではクラスだけでなく、(同一クラスの特定の)オブジェクトに振る舞いを結びつけることができます。

個人的にはまだこの機能の使いどころはつかめていません。この機能を頭の片隅に置きながら Ruby プログラムをたくさん書くことでしか体得できないのだろうなぁ、と考えています。
なお、Rubyベストプラクティスには
スタブメソッドの呼び出しが、テストの実行結果全体に影響を及ぼすことがないようにしたいためだ。
とテストケースの実行における例が書いてあります。

irb で見る基本的な特異メソッド

Rubyベストプラクティスの p.79 のサンプルを実行してみました:
irb(main):001:0> class User; end
=> nil
irb(main):002:0> user = User.new
=> #<User:0xb776a770>
irb(main):003:0> def user.logged_in?
irb(main):004:1>   true
irb(main):005:1> end
=> nil
irb(main):006:0> user.logged_in?
=> true
irb(main):007:0> another_user = User.new
=> #<User:0xb775715c>
irb(main):008:0> another_user.logged_in?
NoMethodError: undefined method `logged_in?' for #<User:0xb775715c>
    from (irb):8
user には logged_in? メソッドが定義されていて、別のオブジェクト another_user では logged_in? が使えないのが分かります。

実際に動的に特異メソッドを定義する

プログラムの内部で動的に特異メソッドを定義しようと思うと "define_method(symbolname, &block_body}" を使うのがこれまでの知識ですが、

irb(main):002:0> user = User.new
=> #<User:0xb773177c>
irb(main):003:0> user.define_method(:logged_in?) { true }
NoMethodError: undefined method `define_method' for #<User:0xb773177c>
    from (irb):3
直接だと define_method は使えません。

define_method を行うようにするには
irb(main):004:0> singleton = class << user; self; end
=> #<Class:#<User:0xb773177c>>
irb(main):006:0> singleton.send(:define_method, :logged_in?) { true }
=> #<Proc:0xb7713cb8@(irb):6>
irb(main):007:0> user.logged_in?
=> true
と記述します。
ここで使われているテクニック:
  • 004 の部分( singleton = class << user; self; end )では、「クラスメソッドの定義」と同じ手法が使われています(が、詳しくは後で…)
  • 006 の部分( singleton.send(...) )では、本来 private method である define_method を send メソッドを経由することで回避しています。
これでプログラム内で動的にメソッドを定義することが可能になりました。

Ruby におけるクラスメソッドの定義

Ruby ではクラスメソッドを以下のように定義します:
class A
  class << self
    def message
      "hello, world"
    end
  end
end

A.message
# => "hello, world"
「Ruby の世界では全てがオブジェクト」というのを思い出すと、2行目の "class << self " がクラス A のオブジェクトを拡張して(特異メソッドを定義して)いる、と読むことが…できるそうです。僕にはまだもう少し時間がかかりそう。

なので、irb:004 で行っている class << user; self; end は user オブジェクトを拡張するためのクラス(= user オブジェクトの特異メソッドを定義するための「空間(クラス)」)を生成していることになります。
後はそのオブジェクトに対して define_method してあげればいいわけです。

2011年11月1日火曜日

rvm と bundle の関係(初級)

rvm (Ruby Version Manager)は Ruby および RubyGems の切り替えを行うものですが、gem パッケージを管理する方法として bundler もあります。
いろんなブログを読んでいると「併用が最強」という風に見えるので、 bundler についても理解しておこうと思います。

Bundler は Gemfile を元に動作します。例えば、
gem 'rails', :version "> 3.1.0"
と Gemfile に書いてあれば、
$ bundle install  
とすることで、適切なバージョンの rails をインストールしてくれます。

また、システム上の gem に複数のバージョンの rails がインストールされていても
$ bundle exec rails generate ...
とすることで、Gemfile で指定されたバージョンを使ってコマンドを実行してくれます。

次の段階はきっと「バージョンアップにどうやって対応していくか」だと思うんですが、初歩の段階での環境構築についてはこのくらい分かっておけば何とかなりそうな気がしています。

あと、rvm との併用ってことで流れをまとめると
  1. Rails アプリケーションのルートディレクトリ($APP_HOMEとする)に移動する
  2. Gemfile を書いて、$APP_HOME に置く
  3. rvm --create use 1.9.2@yourappname とかで、新しい gemset の環境を作りつつ、その環境に移る
  4. bundle install --path vendor/bundle で、新しく作った gemset 環境下に gem をインストール
  5. .rvmrc を書いて、$APP_HOME に置く: "rvm use 1.9.2@yourappname" とだけ書いておけばOK(?)
こうすれば bundle exec のお世話にならなくても、その rvm 環境では単一のバージョンの gem しか存在しない「きれいな環境」なので、頭を悩まさなくても良さそうな予感です。

rails3 + rspec2 (の一歩手前)

Rails3 + Rspec2 の使い方

rails アプリケーションのルート(?)ディレクトリで、
$ rspec spec/*
とすると、spec以下の全てのテストが対象にできます。

逆に、
$ rspec spec/model
とか
$ rspec spec/model/somemodel_spec.rb 
とすれば、「model だけ」とか「特定の model だけ」とかをテストできます。


…まだ、きちんと書けて無いけれど。

2011年10月31日月曜日

Ruby の module

scaffold の中身をちょっと掘り下げる第2回目の記事です。
といっても、Ruby における module という言語要素の理解をするためだけの記事なので、本質的には rails / scaffold とは関係ないかもしれません。

modelname_helpers.rb は module として定義されていました。
大学院時代のトラウマ経験のせいで「モジュール」という言葉には過敏に反応してしまいます…。

モジュールという言葉も曖昧な言葉なのですが、個人的によく使っていた定義は「再利用可能なプログラム単位・部品」です。
例えば、java における package や class は上記の定義においてモジュールです。既存の package を import したり、既存の class の extend することでプログラムの再利用をしています。

Ruby の module は include という形でプログラムの再利用を行います。任意の class で
include ModuleName
とすることで、その module で定義されたインスタンスメソッドや定数などを使えるようです。
公式ドキュメントではない(?)ですが、Programming RubyのWeb版でちょっと触れられているのを見つけました。

class と module

この辺りについて書きたいことはあるけれど、何か難しく考えてるだけのような気がします。
ざっくり言うと、
  • class は(class だけに)分類を行ってその共通部分を抽象化する(スーパークラスにする)
  • 分類から漏れた・分類にそぐわない共通部分を module として抽象化する(抽象サブクラスにする)
くらいの表現になりそうですが、やっぱり詳しく書くのは止めておきます。

ActiveRecordとはなんぞや

昨日の「scaffoldの中身を見ていく」を読み返してみると、いくつか不思議なことを見つけました。なので、数回に分けてちょっと掘り下げたいと思っています。
やっぱり時間をおいて改めて考えるって大事ですね。

なぜ Post クラスの定義は空でよいのか?

Post クラスはmodel部分を担うです。Rails における model は(誤解を恐れずに言うと)その Rails アプリケーションで使うデータの表現です。ということは、「Postとはどんなデータなのか?」を表現しているはずです。Javaの人の感覚なら、そのデータを構成する属性がクラスのインスタンス変数として宣言されているのが自然に思えます。

でも、空です。ActiveRecord::Base を extend している部分を除いて

その部分が重要なんだろうと思って、ActiveRecord::Base の API ドキュメントを見てみると Posts クラスが空の定義で済む理由が何となく分かりました。一行目で
APIドキュメントから引用:
Active Record objects don’t specify their attributes directly, but rather infer them from the table definition with which they’re linked. Adding, removing, and changing attributes and their type is done directly in the database. 
要するに、「そのクラスに対応しているデータベースのテーブル定義を見て、そのクラスを構成する属性を推定している」ということだったようで、クラスにインスタンス変数の宣言などが必要ない理由が何となく分かりました。他の "Adding, removing, and changing ..." の部分がいかに実現されているのかが理解できたら、「しっかり分かった」っていうことにします。
# 分かっている人っぽく表現すると「それって Object-Relation Mapping だよね?」

あと、「もっと詳しい(例の載った)ドキュメント」としてREADMEも挙げてあったので、そのうちきちんとフォローしたいと思います。こちらは例が豊富なので、「なぜ動作するのか」よりも「いかに使うのか」に重点を置いた感じになっているので、自分でプログラムを作る際の参考にするべきドキュメントかなあ、と。

scaffold の中身を見ていく

とあるtweet
Scaffold をそらで写経できない Rails プログラマーは中2からやり直せ。
と、心温まるお言葉が表明されていました。

Ruby の if 文すら怪しい自分は小学生以下決定なわけですが、少しでも学年を上げるべく scaffold の写経をしたいと思います。この前、"rails g scaffold post ..."で作った足場を元に中身を見ていきます。

一通り書いてみて思った感想としては、 RailsGuide の getting started の中身を模写しただけみたいなブログになっちゃいました…。

app/models/post.rb

ソースコード:
class Post < ActiveRecord::Base
end
"rails g scaffold modelname" で作成されるモデルの中身は、ActiveRecord::Base クラスを extend しているだけの空のクラスであることがわかります。

app/helpers/posts_helpers.rb

ソースコード:
module PostsHelper
end
modelname_helpers.rb についてもほぼ同様に空の定義が与えられます(こちらは module ですが)。

config/routes.rb

このファイルは元々存在するファイルですが、generate scaffold で行が追加されます:
resource :posts
# post なんていう紛らわしいモデル名で作ってしまったのは失敗だったかなあ…。

routes.rb では URL → controller のマッピングを行っているようです。
http://guides.rubyonrails.org/routing.html の 2.2節 "CRUD, Verbs, and Actions" を見てみると、"resource :posts" ではデフォルトの7つの挙動が追加されるそうです。
  1. get /posts => index : post の一覧を表示
  2. get /posts/new => new : 新規作成のためのフォームを表示
  3. post /posts => create : 新規作成
  4. get /posts/:id => show : #{:id} 番目の post を表示
  5. get /posts/:id/edit => edit : #{:id} 番目の post を編集するフォームを表示
  6. put /posts/:id => update :  #{:id} 番目の post を更新
  7. delete /posts/:id => destroy :  #{:id} 番目の post を削除
…ちらっと目に入った2.5節の感じだと "resource :posts" と "resource :post"で意味が変わってくるような気がするので、その点は写経的には気をつけるポイントっぽい。
ただ、routes.rb の詳しい内容は上記のガイドだけでもブログ一回分以上の内容がありそうなので別記事にします。

おまけ:rake routes と rails-sh

routes.rb をググってた時、@ITの記事を見つけ、その中で rake routes コマンドと rails-sh を紹介していました。

rake routes コマンドは routes.rb で指定されたマッピングについての情報を表示するためのコマンドです。試しに実行してみたら、先ほど列挙した7つの動作が post について表示されました。resource :posts の効果が確認できた形です。

また、「rails コマンドとか rake コマンドは何かやたらと時間がかかるなあ。仮想マシンなのがいけないのかなあ」と思っていたんですが、@ITの記事を読んでて
以上のように、railsコマンドやrakeはRailsアプリケーションを実装する上で欠かせない便利なツール群です。
しかし、コマンドの実行のたびにRailsアプリケーションをロードするので、毎回少し時間がかかってしまいます。
それを解消するために本記事の筆者の1人である@jugyoが作ったツールが「rails-sh」です。
rails-shは、あらかじめRailsアプリケーションをロードした状態で起動するコマンドラインシェルのようなものです。
という記述を見つけ、時間のかかる理由が納得できました。
rails-sh を使うかどうかは後々考えます…。

app/controllers/posts_controller.rb

おそらく scaffold で生成される Ruby プログラムはここが全てなんだろうと思います。
…こういう書き方をすると、「TDDだから TestUnit の部分を重要視しないなんて、やっぱり初心者だな」と思われるんでしょうか。「メインの関心事(= システムの挙動)に関する部分で」っていう前置きがあれば正しい表現になるのかなあ…。

さて。
class PostsController < ApplicationController
...
end
まず分かることは、ApplicationController のサブクラスであることです。
ApplicationController は ActionController (ActionPack gemsの一部?)を extends しているクラスです。ApplicationController クラスの中身はほぼ空なので、その親クラスである ActionController クラスの中身に意味があるはずです…が、ActionController はちょと巨大なのでブラックボックスにしておきます。
# ほぼ空 = protect_from_forgery のみ = CSRF対策のためのコードが定義されている

PostsContoller クラスでは "resource :posts" で定義される7つの挙動に対応するメソッドが定義されています。
一番シンプルな形のメソッドは
def index
  @posts = Post.all

  respond_to do |format|
    format.html
    format.json { rendor json: @posts }
  end
end
というものです。

最初の @posts 変数への代入では Post クラス(モデルクラス)が使われています。この場合は .all なので、「全ての Post」となります。他のメソッドでの @post の代入では、
  • find メソッドを使って、モデルクラスのデータを検索している
  • new メソッドを使って、モデルクラスのデータを新規作成している
のが見て取れます。

あと、Rubyベストプラクティスを読んでいるおかげか、respond_to が「特別なメソッドを使ってDSLっぽく仕上げる」仕組みなのが想像できます。どうやら actoinpack/lib/action_controller/metal/mime_responds.rb で定義されているようですが、追いきれませんでした…。
exampleを見る限りだと、respond_to に渡されているブロックの引数 format (Webクライアントからのリクエストによって決まるらしい)によってどんな仕事をするのかを記述するようです。
また、(この部分はまったくプログラムを追っていませんが挙動から予想するに)html フォーマットの場合のデフォルトの挙動は methodname.html.erb に処理が移るようです。

その他の scaffold の生成物

きょうのところは勘弁してやる…してください。
      create    db/migrate/20111030125941_create_posts.rb
      invoke    test_unit
      create      test/unit/post_test.rb
      create      test/fixtures/posts.yml
      invoke    erb 
      create      app/views/posts
      create      app/views/posts/index.html.erb
      create      app/views/posts/edit.html.erb
      create      app/views/posts/show.html.erb
      create      app/views/posts/new.html.erb
      create      app/views/posts/_form.html.erb
      invoke    test_unit
      create      test/functional/posts_controller_test.rb
      invoke    helper
      invoke      test_unit
      create        test/unit/helpers/posts_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/posts.js.coffee
      invoke    scss
      create      app/assets/stylesheets/posts.css.scss
      invoke  scss
   identical    app/assets/stylesheets/scaffolds.css.scss
大まかに把握しておくと、db の部分、view の部分(erb および assets/coffee,scss)、テストの部分が手つかず。


2011年10月28日金曜日

Rubyベストプラクティス 3章(前半)

3章は Ruby の動的な性質を使って、柔軟なプログラムを構築する方法について。

「動的な性質」ってよく分からずに読み進めたら、結局リフレクションのことなんですね。
…ある意味、専門領域です。
ということで、3章前半はオープンクラスの話だと思ってしまおう。

3.1節 メソッドの定義を動的に変更

例として、BlankSlateというクラスが挙げられています。
ちょっと背景説明の方へ話を移すと、Ruby 1.9系では、言語組み込みとして BasicObject という「何の機能(メソッド)も持たないクラス」が提供されています。
「何の機能(メソッド)も持たないクラス」は method_missing などで動的なメソッド生成をするさいに衝突の危険を避けることが簡単なので重宝されます。
そういった便利なクラスが Ruby 1.8系では言語要素ではないので、Jim Weirich が BlankSlate を提供してくれています。

BlankSlate がやっていることを自然言語で説明すると、「そのクラスに定義されたメソッドを(一部を除いて)一旦 BlankSlate#hidden_method というハッシュに退避した上で undef_method している」です。
こうすることでメソッドの定義されていないクラスを作っています。
また、一旦退避(undef_method)させたメソッドを define_method で再定義(書き戻す)もできます。

これらの undef_method や define_method は動的にメソッド定義を行うための Ruby の仕組みで、メソッド(の定義?body?)自体がオブジェクトであることを利用しています。

3.2節 柔軟なインターフェース 

…同じタイトルが2章でもでてきます。Rubyにとって非常に重要なテーマなのでしょう…。

3.2.1 instance_eval()

2節でも似たようなテーマでコードブロックの話が出ていますが、ここでもコードブロックの話で、コードブロックに引数を渡す方法とその効用についての話…だと思います。
ちょっと何の話を目的にしているのか自信がありません…。

まずは、本に載っているサンプルプログラム(に近いもの)を実際に試してみます。
[kazu@cent6 bestpractice]$ ruby 03-2-1-instanceeval-err.rb
03-2-1-instanceeval-err.rb:29:in `generate_pdf': undefined local variable or method `full_name' for #<Document:0xb77d0e30> (NameError)
        from 03-2-1-instanceeval-err.rb:12:in `instance_eval'
        from 03-2-1-instanceeval-err.rb:12:in `generate'
        from 03-2-1-instanceeval-err.rb:28:in `generate_pdf'
        from 03-2-1-instanceeval-err.rb:35
instance_eval() で実行されるコードブロックは、そのオブジェクトをコンテキスト(= enclosing scope)とするので、そのローカル変数しか参照することができません。一方、コードブロックを call メソッドで呼び出す場合、そのコードブロックが定義された時点でのコンテキストを引き継いだ Proc オブジェクトの呼び出しになります。

つまり、
class Prawn::Document
  def self.generate(file, *args, &block)
    pdf = Prawn::Document.new(*args)

    block.arity < 1 ? pdf.instance_eval(&block) : block.call(pdf)
    ...
  end
end
というプログラムでは、
  • instance_eval(&block) は pdf オブジェクト(Documentクラス)のコンテキストで
  • block.call(pdf) は、blockの本体が作られた時点(MyBestFriendクラスのメソッド呼び出し時)のコンテキストで
実行される…はずです。

3.2.2 method_missing() と send()

Ruby では定義されていないメソッドを実行すると(さっき試したみたいに)「undefined ...」と当然エラーになりますが、method_missing() というメソッドを定義しておくと undefined methods を実行した際に、エラー処理の代わりに method_missing() が実行されます。

これを使って動的にメソッドを解釈させる仕組みの説明です。
Convention Over Configuration の例にもなっていると思います。

例として図形描画プログラムが挙げてあります。
複数の図形の描き方(線画、塗りつぶし、線画と塗りつぶしの両方、…)と複数の図形要素(直線、円、多角形…)があるときに、
stroke_line [0,0], [50,50]
fill_circle_at [100,100], :radius => 50
stroke_and_fill_polygon [100, 250], [...], ...
という書き方が出きるとスマートです。ただ、いちいち
def 描き方_図形要素(*args)
  図形要素(*args)
  描き方
end
というメソッド定義を行うのは手間がかかります。組み合わせ爆発の状態です。

これを method_missing() を使って、「"描き方_図形要素" というメソッドが来たら、"図形要素"メソッドと"描き方"メソッドを実行する」という仕組みにしています。
また、この時の「…を実行する」ための方法として send(methodname, *args, &block) を使っています。

3.2.3 DSLっぽいアクセサ

DSL = Domain Specific Language = 領域指定言語、つまり、特定分野の記述を行うための言語のことです。Ruby は、その言語の中で DSL 風に書けることがよく知られていて、一部の人には大人気です。

さて。

普通のアクセサは
font_size = 10
のようになるのですが、定義をちょっと工夫すると
font_size 10
という風に書けて、非常にDSLっぽくなります(CSSなんかでこんな記述ができそうな雰囲気)。
しかも、このメソッドは
font_size
と引数なしで呼び出すと値を返す reader にもなります。

でも、難しい定義ではなく
def font_size(size = nil)
  return @font_size unless size
  @font_size = size
end
とするだけです。

また、通常のアクセサの代わりもさせておくと、この書き方に慣れない人にとって有意義なので、
alias_method :font_size= :font_size
とエイリアスを作っておくTipsも紹介されていました。

3.3節 特異メソッド

…と思ったのですが、長くなったので3章は分割してお送りすることにします。

2011年10月27日木曜日

ブログのデザインをちょっと替えてみました。

全体の色を青系統から赤系統に替えて、ヘッダに画像を入れてみました。

ヘッダの画像はとある櫻花の画像生成を使って生成させていただきました。
こういうみんなに気軽に使ってもらえるWebサイトを自分で作れるようになりたいし、そうなるための Ruby の勉強だ!とモチベーションを上げてみます。

あと、テンプレートも替えてみました。Blogger は hN タグが使えなくてなんでだろうと思っていたらテンプレート側で使っているせいなんですね…。
自分でHTMLを編集して、カスタムCSSを使うことにしました。

…一旦、追加したカスタムCSSはテンプレートで直接「HTMLを編集」しないと修正できないのか。
修正できないのかと思って冷や汗かいた…。

ちょっと話はそれて Javascript へ。

たまにはお仕事での話もしてみます。

お仕事の方でプログラムを書く機会はさほど多く無いのですが、HTA という仕組みを使って Windows Server (ActiveDirectory) を操作するツールを VBscript で作っていたりします。
ツールをコンパイルが必要な言語で作成すると、「ソースコードが紛失して手直しが出来ない」「開発環境が必要になる・用意するのが面倒」などの困難がつきまとうので、(主に自分以外がメンテナンスするにあたって)ツール自体がソースコードファイルになり、メモ帳で修正可能なスクリプト言語を採用しています。

HTA は基本的にタダのHTML(バックエンドとしてInternetExplorerが動いているだけ?)なので、「View の上で全ての処理をするお粗末なWebアプリケーション」を書く感覚に近く、自分のスキルでも何とかなってしまいます。
…そろそろ、綺麗な形で書き直したくなってきたなぁ。

で、愚痴はともかく、ActiveDirectory から複数件のユーザアカウントデータを検索して表示するツールを作ったんですが
「ソートしたい…」
と素朴な気持ちが出てきました。

HTMLで表データをソート、となったら「Javascript で何とかなるんじゃない?jQueryとかすごい便利だし。」と思い、 …ハマりながらもうまくいきました。
# ちなみに HTA では Jscript (≒ javascript)もサポートしているので、
# jQuery が使えます。ラッキー。

Tablesorter

ということで、検索結果をソートするために Tablesorter を使いました。
Tablesorter は jQuery のプラグインです。一番基本的な使い方は "Getting Started" で示されているように
  • jQuery と Tablesorter の .js ファイルを読み込む
    • Tablesorter のサイトから両方ダウンロードできます。jQuery のバージョンにこだわりが無ければ揃えて入手できていいかも?
  • Table 要素に対して tablesorter() を実行するような Javascript を記述する
    • 特定の Table 要素をソートしたい場合は Table タグに id 属性をつけておくと良さそう
  • Table タグに class="tablesorter" を指定する(必要?)
  • Table タグの子要素として、ヘッダ行を thead タグで囲む
  • Table タグの子要素として、データ行部分を tboday タグで囲む
とします。

ただ、今回、ソートをしたいデータは VBscript で作成する(= 元のHTMLにはないデータ)なので、AJAXの際のプログラミングを参考にします。
http://tablesorter.com/docs/example-ajax.html
# Advanced example らしい…。
しかし、この例でも「空のテーブルが存在する状態」から始まっているので、table 要素全体を VBscript で生成しようとしている自分のケースにはそのままは使えません。
そこで、上記の例で出ている「あるIDの要素がクリックされたときに~」という記述を参考にして、「あるIDの Button 要素(「検索する」ボタン)がクリックされたときにtablesorter を実行する」というプログラムにしました。

VBscript で生成される前のHTML要素を javascript で扱えない(当たり前なんですが…)ことに途中で気づき、「どのタイミングでどのデータが存在しているのか?」を考えていたのが山場でした…。
jQuery で動的に要素を追加してると結構ハマるポイントのような気がします。

また、tablesorter は1行目の値を見て、「その列にどんな値が入っているのか?(文字列?数値?日時?)」を推測してくれるのですが、間違って推測することがあるので、自分で指定することにしました。
参考URL: http://mottie.github.com/tablesorter/docs/example-option-date-format.html

以下の javascript の "sorter" の部分が各列の型を指定している部分です(その前の 0: や 1: が「何列目」を示す 0-origin インデックス)。
$(function() {
  // call the tablesorter plugin 
  $("table").tablesorter({ 
 
    dateFormat : "mmddyyyy"// set the default date format 
 
    // or to change the format for specific columns, add the dateFormat to the headers option: 
    headers: { 
      0{ sorter: "shortDate" }// dateFormat will parsed as the default above 
      1{ sorter: "shortDate", dateFormat: "ddmmyyyy" }// set day first format 
      2{ sorter: "shortDate", dateFormat: "yyyymmdd" }  // set year first format 
    } 
 
  }); 
});
…ということで、VBscript で生成した表をソートするのに javascript が使えました、という報告です。

はじめてのあしば @rails3

rails new weblog と適当に作った勉強用の rails アプリケーションに scaffold を作っていこうと思います。
# なお、以前のエントリにあるように、この weblog では "rails g rspec:install" を実行済みです。
$ rails g scaffold post title:string body:text published:boolean createtime:date modifiedtime:date
$ rails g rspec:scaffold post 
…ひとまず、scaffold はエラーを吐かずに実行できました。

足がかりはできたので、DBを用意します。デフォルトの database.yml を見てみると

development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000t
と sqlite を使うようになっています(= DBサーバの起動とか気にしなくてよい)ので、
$ rake db:migrate
やっちゃいます。うまくいっているみたいです。

サーバの起動もしてみます。
$ rails s -p 30080
openskip (= rails 2.3.5) では config ファイルにも port 番号を書いた気がしたんですが、今回の rails 3 ではコマンドでポートを指定するだけで良かったんでしょうか。
→ initial_settings.yml でググってみたら openskip の記事しか出てこない、ってことで特殊な事情だと理解しておきます。

さて、http://localhost:30080/posts でめでたく「はじめてのあした@rails3」がうごきました。

さて中身を見るのは…次にします。

2011年10月24日月曜日

Ruby のプログラムをほとんど書いたことが無いもので

Ruby の初歩的な文法やイディオムを知りません。

Rubyベストプラクティスを読んでいても「何だ、これ?」なことがたくさんあります。
この前書いた inject もそうでしたが、そのうち何回も出会いそうなので記録を残しておきます。

クラスのインスタンス変数

2章にこんなコードが出てきます:
class SortedList
  def initialize
    @data = []
  end
end
この時の @data のように冒頭に @ が一つついたものはインスタンス変数です。
Ruby でもこの用語でいいのかな?公式リファレンスに載ってた)

ちなみに

変数名の冒頭に @@ でクラス変数、 $ でグローバル変数、何もつけないのがローカル変数になります。
これで変数のスコープがおおよそ決まりますが、(特にローカル変数に関して)関数定義やコードブロックなどもう少し細かくスコープの区切りがある模様です。

変数の初期化

3章にこんなコードが出てきました:
@hidden_methods ||= {}
展開すると、意味が透けて見えてきます:
@hidden_methods = @hidden_methods || {}
Ruby の評価規則では、
  • 二項演算子 || は
    • 第一項を評価した値が nil または false の場合、第二項を評価し、その評価した値を返す
    • 第一項を評価した値が nil または false 以外の場合、第一項を評価した値を返す
  • 条件文を評価する際、nil または false 以外の値はすべて true と同等とみなす
となります。たぶん
なので、@hidden_methods が未定義である = nil である場合は、第二項の {} で初期化されます。たぶん

2011年10月23日日曜日

Ruby ベストプラクティス2章

Rubyベストプラクティスの2章はAPIの作り方ということで、
  • Rubyの関数・メソッドの引数の特徴
  • コードブロックの効果的な使い方
などを示しながら、API(≒ メソッドシグネチャ?)を自然に分かりやすく構築するコツについて書いてありました。

2.2節 Rubyの引数

Ruby では引数のデフォルト値を指定できる「オプション引数」を宣言できたりします。
def foo(bar="defaultvalue")
   ...
end
こうやって宣言した関数 foo は、 foo "hoge" とも foo (= foo "defaultvalue" と同じ)とも関数呼び出しができます。
ただ、オプション引数は複数存在するとその順番によって、省略できなくなってしまいます。

擬似的なキーワード引数

オプション引数とは別の話として、ハッシュを使った擬似的なキーワード引数の話が載っています。
キーワード引数の良いところは、順番に依存しない関数・メソッド呼び出しが行えることです。
「累乗を計算する power 関数は、第一引数が底だっけ?指数の方だっけ?」と迷うことなく
power({ :base => 2, :exp => 10 }) 
と記述することができ、うっかり 10の2乗を計算することを回避できます。

合わせ技

ハッシュによるキーワード引数とオプション引数(の考え方)とを組み合わせると、任意の場所の引数についてデフォルト値を定められる(= 省略可能にできる)関数やメソッドを定義できる、というのが 2.2 節のまとめです。

2.1節 統一された呼び出しインターフェース(API)

順番が逆ですが、2.2節で出てきたような引数処理のテクニックを利用すると、関数・メソッドを同一の呼び出し方法で異なる使い方が可能になる、という例を Table() メソッドを例に示しています。
異なる使い方:
  • hash データを引数として受け取り、それを解釈して、Table を構築
  • csv ファイル名を引数として受け取り、それを読み込んで、Table を構築
  • csv フォーマットの string を引数として受け取り、それを解釈して、Table を構築

2.3節 コードブロック

話題は変わって。

本の中でも「Enumeratable を使ったことがあるなら、自然とコードブロックを使っているはずだろう」と触れられているように、普通の Ruby プログラムであればコードブロックはいたるところに出てきます。
僕の中で一番最初に思いつくのは Array#each でしょうか。

この本では、コードブロックを使ってリファクタリング(共通部分の抽出)を行う例が挙げてありました。
元 Java の人としては、exec(...) を宣言した ISomeMethod インターフェースを実装するクラスを作って、そのインスタンスを対象のメソッドの引数として渡し、そのメソッドの中で exec(...) を呼び出す形に対応付けて覚えることにしました。

2.4節 Rubyらしいコード

また、話題は変わって。

「Ruby らしいコード」になるためのテクニックをいくつか紹介しています。

attr_*

Ruby のクラスにクラス変数 ( @varname ) を定義するとき、たいていの Rubyist は(Javaプログラマと違って)
class Message
  attr_accessor :message

  def initialize(m)
    @message = m
  end
end
と書くそうです。
こう書けば、(本来カプセル化されてアクセスできないはずの)Message#message を参照・書き込みできます。
読み出し・書き込みのどちらか一方だけ自動生成したい場合は、attr_reader / attr_writer があります。

メソッドの後ろの "!" と "?"

Ruby の「暗黙のルール」として、
  • methodname? は bool 値を返す
  • methodname! は「注意するべき操作」を示している
    • 一般的には、破壊的操作(元のデータを書き換える操作)を示していることが多い
    • 逆に ! のついていない対応する methodname は「(元のデータそのものではなく)コピーされた値を処理する操作」
というのが慣習になっています。

演算子もメソッド

つまり、再定義によるカスタマイズが可能、ということです。 + や << などで表現できる「操作」があれば、それをカスタマイズされた演算子として定義するとコードがすっきりしそうです。

おまけ:inject

2章の途中で、(かなり嘘が入っていますが、ざっくり言うと)こんなサンプルプログラムが出てきます。
a = [ 1, 3, 4, 5, 7]
a.inject(0) { |sum, element| sum + element }
# => 20
あまり Ruby の経験のない自分ですが、このコードが異様なのは何となく分かります。「sum って一体どこから出てきたのだろう。どうやら要素の足し算をしているようだけど…」

inject について調べてみたら、関数型言語で言うところの fold 関数であるらしいことが分かりました。
fold 関数については関数型言語好きな後輩から「foldはすばらしいですよ」と解説を受けたことがあったので、…存在だけは知っています(ごめんなさい、自信を持って理解してるって言えません)。「畳み込み」っていう言葉もイメージだけはできている気分です。

僕の中では、(配列・リストの)要素に対して構文木を作るイメージなんですが、それで伝わる人ってどのくらいいるんでしょうか…。

2011年10月22日土曜日

ralis3 + rspec2 (の3歩手前くらい…)

rails 2.x と rails 3.x では、使い勝手(コマンド)がかなり違っているようです。
それに対応する rspec についても使い方はひどく違っています。

まず、
$ rails new weblog
として新しい rails プロジェクトを作りました。
「ruby なら TDDでしょ」ってことでまず rspec を用意しようと思い、rails プロジェクトの Gemfile に
# Rspec for Test Driven Development
group :test do
  gem "rspec", "2.7.0"
  gem "rspec-rails", "2.7.0"
end
「よーしこれでOKだ」と思って
$ rails generate rspec:install
としたら、
/usr/local/rvm/gems/ruby-1.9.2-p290@rails3/gems/execjs-1.2.9/lib/execjs/runtimes.rb:47:in `autodetect': Could not find a JavaScript runtime.
See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
書いてある通り、 javascript runtime が無いようです。
https://github.com/sstephenson/execjs
には therubyracer が一番最初に書いてあります。
gem list therubyracer --remote してみたらパッケージがあるようなので
$ gem install therubyracer 
でインストール。さらに Gemfile に
# Javascript runtime
gem "therubyracer"
と書いて rspec:install にリトライ→成功!
…ふぅ。

2011年10月21日金曜日

Rubyベストプラクティスを読み始める

O'Reilly から発行されている Rubyベストプラクティス を読み始めました。
ちょっとでも Ruby プログラマの気持ちが分かれば、と考えています。

ひとまず1章でTDDな気持ちをちょっとだけ学びましたが「テストのために本体のコードがかなり歪んでないか?」って気分もしてます。
この辺りはバランスなんでしょうか。それともテストのために全てを犠牲にするのがTDDってもんなんでしょうか。
まだまだ Ruby プログラマの気持ちには程遠いようです。

ちなみに、「ベストプラクティス」がカタカナなことからお分かりのように日本語版を読んでおります。
こういうものは原著で読むべきだと思っているんですが、プログラムの多い本ほど日本語でもいいかなぁ…と。

2011年10月20日木曜日

ブログのタイトル

そのうち Reckless Novice が Rational Neet を経て、Reliable Nomad になれるといいな、と考えています。

そんな妄想。

2011年10月19日水曜日

RVM を使って複数の Rails を使い分ける

Ruby/Rails の学習題材に openskip を選んだために、gem でインストールした rails のバージョンは 2.3.5 です。

どうせ勉強するなら最新の rails 3 での挙動も並行して勉強したいところです。そもそも仮想ゲストOS上の環境なのでもう一つ作るっていうのもありなんですが、手間がかかりそうとかリソースが足りなさそうとか思うと、現在の環境に複数バージョンを共存させたくなってきました。

そんなこんなで調べていたら rvm (Ruby Version Manager)というのを見つけました。

インストール

基本的に以下の文書にしたがって(略
http://beginrescueend.com/rvm/install/

まずは download & install :

$ sudo bash <<(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )
これだけで /usr/local/rvm/ 以下にインストールが完了します。
また、インストールの際のログの中に
NOTE: To all Multi-User installers - DO NOT forget to add your users to  the 'rvm' group.
という注意がありました。「Linuxのグループをプロジェクトごとに使う」っていうポリシー自体は聞いたことがあったんですが、こういう形で使うのは初めてです。 ひとまず、自分のユーザを rvm グループに追加しました。
$ sudo usermod -a -G rvm kazu
あと、「Rubyの最新版を入れるんだったら…が必要だよ」とたくさん yum のパッケージが列挙してあったので、必要になるか微妙だったんですが、足りていなかった libyaml-devel, libffi-devel をインストールしました。

Ruby 環境の作成


以下のページを参考にさせてもらいました。
http://www.machu.jp/diary/20110521.html

rvm では
  • system (rvm の管理外のsystem標準の環境: OSパッケージのrubyやgems)
  • rvm 以下に複数のバージョンの ruby 
    • 各rubyのバージョン以下に(独立した)複数の gemset
というかたちで環境を作っていきます。

とりあえず(1.9系の良さを知らないもので…)1.8系で満足ですが、この際 1.9 も用意しておこうと思います。ということで、rvm にて、
$ rvm install 1.8.7
$ rvm install 1.9.2
で1.8系および1.9系をインストールしておきます。
(どんなバージョンが利用可能かは "rvm list known" で確認できます)

さて。
この状態だと、rvm管理下の 1.8.7 / 1.9.2 の2つの環境、およびOS標準(system)の合計3つの Ruby 環境があります。
これを切り替えるのには rvm use を使います。
1.8.7 環境に切り替える:
$ rvm use 1.8.7
元のシステム環境に戻す:
$ rvm use system

次は、"rvm use 1.8.7" を行った(一旦 rvm 環境下に入った)上で、gemset の作成に移ります。
$ rvm gemset create openskip
$ rvm gemset create rails3
作成したら rvm use コマンドで gemset を含めた指定を行います。
$ rvm use 1.8.7@rails3
ここで gem list コマンドを使ってみると空っぽの gem 環境になっていて、以前インストールした gem とは切り離されていることが分かるので、望みの gem を揃えていきます。
$ gem list

*** LOCAL GEMS ***

$ gem install rails3
これで複数環境を使い分けられそうです。

(追記: 2011/10/22)
openskip の環境を system じゃなくて ruby-1.8.7@openskip として作ったときに

/usr/local/rvm/gems/ruby-1.8.7-p352@openskip/gems/activesupport-2.3.5/lib/active_support/dependencies.rb:55: uninitialized constant ActiveSupport::Dependencies::Mutex (NameError)
というエラーに見舞われました。
エラーメッセージをググったら、特定の rails のバージョンと rubygems のバージョンとの組み合わせで起こるエラーのようです。
http://blog.digital-squad.net/article/196968134.html

rvm の ruby-1.8.7@openskip 環境で、
$ gem -v
1.8.10
$ gem update --system 1.3.7
ちなみに gem のバージョンは < 1.6 であればいいようなんですが、OS標準の gem と同じバージョンにしてみました。

2011年10月16日日曜日

openskip の環境構築(の途中)

なかなか壁が高いです。

基本的には github 上の文書にしたがって作業しています。
https://github.com/openskip/skip/wiki/_pages

必要な gems がインストールできない

gems のインストールで一悶着ありましたが、CentOS の ruby-devel パッケージを入れ忘れていただけだと分かり、そこはすんなり解決しました。
# rubygems の基本とか仕組みとかを理解しないときついな…。
# 複数パッケージの共存とか名前空間の概念とかがどうなっているんだろうか。

DB作成でこける: gemsまわりが原因

さらに、db:migrate にて、
undefined method `set_app_language_tags' for I18n::Locale:Module
というエラーが出たのですが、同様のエラーが locale_rails の方に報告されていました。
https://github.com/mutoh/locale_rails/issues/2

github 上の最新のソースコード(June 15th, 2010 以降のもの。ver. 2.0.5 は November 2009 なのでダメ)の i18n.rb に入れ替えると pass しました。

…と思っていたのですが、Openskip のコミュニティページの公式解法としては、(rails3 の?)依存関係のせいでインストールされる i18n という gem をアンインストールする、という方法らしいです。
https://www.youroom.in/r/openskip/entries/216558

ひとまずエラーが解消されたので、一歩先に進んでみることにします。
# やっぱり名前空間とかそういうところの勉強をしないと解決できない予感。

一通りの手順を実施できたと思ったら…

webrick を起動させて、手順に出てきた「初期管理者の作成URL」にアクセスしたら internal server error。

コンソールに表示されている webrick のログを見たら、haml が sass を使っている部分でエラーになっていました。
どうやら gem でインストールされた haml のバージョン(3.1.3)が異なるせいなのか、sass がインストールされていませんでした。

gem install で sass (3.1.10) をインストールした上で、openskip の config/environment.rb (66行目?)に
config.gem "sass", :version => '3.1.10'
を追加したら、管理者の追加とその後のログインまでうまくいきました。

さらに落とし穴…


うまくいったので、ログインしてからブログ投稿などを試して見ようと思ったらエラー。

ログを見たら i18n の文字が見えたので「やっぱりダメだったか…」と思い直して、openskipのサポートルームに載っていた teru さんのブログを参考に i18n, mail, actionmailer (v 3.x.x), actionpack (v 3.x.x), activemodel (v 3.x.x), activerecord (v 3.x.x), activeresource (v 3.x.x), activesupport (v 3.x.x) あたりの gem を外してみました。
http://d.hatena.ne.jp/teruzoh/20101228/1293508965

ということで、やっとまともにうごいた!

openskip のソースコードを読んでみる(の前に?)

勉強を始めたばかりのくせに最近サボりがちだったので、今日は取り戻す勢いで。

でも、Rails の基礎が分かっていないので、どのソースコードが肝なのかは手探りです。
…まずは spec から読んでみるかな、という気分です。

rspec が gem でインストールされていなかったので、インストールします。
$ gem install rspec --version 1.3.0
$ gem install rspec-rails --version 1.3.2
rspec-rails 1.3.2 をインストールすると(依存関係があるわけでもないのに、なぜか)rspec-core, rspec-expectation, rspec-mock がインストールされるので uninstall しておきます。rspec-rails 2.x には確かに必要なパッケージのようなんですが…。

あとで分かったのですが、rspec はバージョン 1.3.x と 2.x で全く別物で、
  • 1.3.x が rails2.x 向け
  • 2.x が rails3.x 向け
という使い分けがあるとかないとかそういう風に見えました。




…さぁ、まだ Ruby にはちっとも触れてないぞ、っと…。

CentOS on VMplayer のスペック

特にご興味な李かもしれませんが、仮想OS が VMware player 上でストレスなく動作しているようなので参考値ということで晒してみたいと思います。

まず先に手元のPCのスペックですが、
  • Thinkpad X201i 
    • CPU: intel core i5 M450 (2.40 GHz)
      • 論理プロセッサは 4 = 2個の物理コア x ハイパースレッディング
      • 以前の投稿でも触れたように、BIOS で intel VT は有効にしています
    • memory: 4GB
という感じです。この上で仮想ゲストである CentOS に
  • 論理CPU: 2
  • memory: 2GB
とそこそこたっぷりと思えるリソースを分けました。ほぼ問題なく動作していると思います。

ホストPCの半分くらいのリソースを明け渡しましたが、きっと Linux を扱っているときは Windows 側でそんなに仕事してないだろう、という予測の結果です。
ただ、Linux 側の Skype の調子が芳しくありません。手元に Bluetooth ヘッドセットがあるのですが、ゲストOS側の Bluetooth デバイスの認識機能は働いていそうなものの、接続して利用できる状態にはならないようです。
ゲストOS側で独立して接続するのだからマルチペアリングに対応していない機器だといけないんでしょうか…。

当分は Windows 側で Skype しながら Linux 扱うことになりそうです。

Openskip を github から拾ってくる

「rails アプリケーションの教材」として、 github 上のプロジェクトの中から(個人的には自然な流れで)openskip を選びました。

環境構築の方法が README に書いてあるのですが、これは環境を作るのにまた1日かかりそうです…。

2011年10月15日土曜日

github も使ってみる

せっかく git を使うなら github を使ってみようということでアカウントを取りました。
ひとまず linux マシンで使うので、

http://help.github.com/linux-set-up-git/

このあたりを見て、ssh key の用意とテストログインくらいはやってみました。

あと、次の投稿のネタになると思いますが、 github 上のレポジトリを fork しました。
github のレポジトリの fork に関しては
http://help.github.com/fork-a-repo/
こっちの文書を参考にしています。

git の本当に基本的な使い方

git を使うことにしました。

でも基本の使い方も思想も理解していないので、メモを残しておきます。

自分のソースコードを git の管理下に置く場合

ソースコードを置いている場所を /path/to/mycode とすると、
$ cd /path/to/mycode/
$ git init
とすることで、git レポジトリとなるように .git ディレクトリを作成します。

他所からソースコードを持ってくる場合

例えば、他の git で管理されたディレクトリや github からソースコードを持ってくる場合は、git cloneを使います:
$ cd /path/to/base/
$ git clone <source of .git file>
clone コマンドを使うと、baseディレクトリの直下に git プロジェクトの名前でディレクトリを作ってくれます。

その他の使い方

は、そのうち…。



Ruby 開発環境

やりたいことは Rails 開発なので、必要なものはそこそこあります:
  • ruby :  OSインストール時に入ってた
  • rubygems : yum install rubygems 
  • rake : yum install rake
  • emacs の整備
    • term/bobcat を有効にする
    • ruby-mode : これもOSインストール時に入ってた
    • elscreen : 開発サイトから拾ってくる
    • apel : elscreen に必要だったのでこれも拾ってくる
rails を導入するために gem でいろいろインストールしてたらエラーになりました。
header が見つからないということなので、どうやら CentOS の ruby-devel が入っていない、
ってことで
  • ruby-devel : yum install ruby-devel
  • 各種 gems
を導入。

2011年10月14日金曜日

CentOS 6.0 on VMware Player on Windows

こういう表現であっているのかわからないですが、手持ちのWindows PCにVMware Playerをインストールして、その上で CentOS 6.0 を動かしています。

画面描画が遅い気がする

ターミナルとemacsを動かす分には(= キーエコーが表示されるだけなら)そこそこ快適に暮らせますが、Firefoxの動作とかウィンドウの描画とかになるとちょっと辛そうです。

手持ちのPCは Thinkpad X201i なのですが、どうやら BIOS で intel VT が disable になっているようです。
一旦電源を落として BIOS 上で enable にしてみたら若干改善された気がします。

英語キーボード

個人的な趣味で英語キーボードを使っています。
ただ、キーボードでチルダやシングルクォートを入力しようとすると問題があることに気づきました。

同じような苦労をされている方を発見しました:
http://d.hatena.ne.jp/drambuie/20110603/p1

僕の場合はキーボードの設定を Generic 101 に変更すると良くなるようです。

はじめてのとうこう

初心者のくせに、Rubyエンジニアとして頑張っていこうと一念発起した人のブログです。

まず最初に

Rubyの開発環境が必要です。

ただ、WindowsではRubyの開発環境をそろえるのが難しいです(特に Rails の環境まで考えると…)。
ということで、 慣れ親しんだ Linux 上にRubyの開発環境を構築することにします。

VMware Player のインストールとCentOSのインストール

VMware Player を公式サイト http://www.vmware.com/go/get-player-jp からダウンロードして、exeをダブルクリック→インストール完了。

CentOS はミラーサイトから適当に version6.0 の netinstall 用isoをダウンロード。
僕は IIJ さんのミラーから入手しました。http://ftp.iij.ad.jp/pub/linux/centos/6/isos/i386/

  •  VMware player を起動して「新規仮想マシンの作成」を選択
  • 仮想マシンのハードウェアスペックを適当に決める。ただし、
    • 「CD/DVDドライブ」として、さっきダウンロードした iso ファイルを指定 ← 次回起動時にこのisoを読み込むので centos のネットワークインストールが開始される
  • 仮想マシンの作成を完了させて、さっそくマシンを起動すると iso ファイルを読み込んで centos のインストール開始
  • centos のインストール手順は割愛
    • まぁ適当に。
centos のインストールは大筋で成功したので、早速環境構築…、と思ったのですが若干力尽きてきました。

  • vmware-tools のインストール
  • sudoers の設定: wheel グループに対して許可
  • 自分のユーザアカウントを wheel グループに追加
  • emacs の設定
    • term/bobcat ただし emacs22 以降だと (load "term/bobcat") だけではダメらしい
    • elscreen …が見当たらない。拾ってこよう。