Railsの開発ではgemを使わないと何もできないが、ふとgemってどう作るんだろうという疑問がいまさらわいてきた。
ということで自分でgemパッケージを作ってみた。
gemを作るためのnewgemという便利なものがあったのでそれを利用してみた。

1 newgemのインストール
まずはnewgemをインストールする。

$ gem install rubyforge
$ gem install newgem

2 ひな形の作成と編集
newgemコマンドを発行して作成するgem(mygemtest)のひな形ファイルを生成する。

$ newgem mygemtest -T rspec
      create  lib/mygemtest
      create  script
      create  History.txt
      create  Rakefile
      create  README.rdoc
      create  PostInstall.txt
      create  lib/mygemtest.rb
  dependency  install_rspec
      create    spec
      create    tasks
      create    spec/mygemtest_spec.rb
      create    spec/spec.opts
      create    spec/spec_helper.rb
      create    tasks/rspec.rake
  dependency  install_rubigen_scripts
      exists    script
      create    script/generate
      create    script/destroy
      create  script/console
      create  Manifest.txt
      readme  readme

“-T rspec”でテストフレームワークとしてRSpecを指定している。

Rakefileのself.developerの”FIXME”の部分を変更する。

$hoe = Hoe.spec 'mygemtest' do
  self.developer 'anthony', 'anthony@abc.com'   self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required

README.rdocの”FIX”の部分を変更する。

= mygemtest

* http://github.com/#{github_username}/#{project_name}

== DESCRIPTION:

FIX (describe your package)

== FEATURES/PROBLEMS:

* FIX (list of features or problems)

== SYNOPSIS:

  FIX (code sample of usage)

== REQUIREMENTS:

* FIX (list of requirements)

== INSTALL:

* FIX (sudo gem install, anything else)

== LICENSE:

(The MIT License)

3 ライブラリコードの追加
lib/mygemtestにライブラリコードとしてmyclass.rbを以下の内容で作成する。

module MyGemTest
  class MyClass
    def initialize
        puts "Initialized Done !!"
    end
   end
end

4 パッケージ作成
gemパッケージを作成する。
Manifest.txtに作成したmyclass.rbのパスを追加しておく。
これをしておかないとgemファイルに作成したライブラリコードが含まれない。
(これで1時間くらい悩んだ orz)

History.txt
Manifest.txt
PostInstall.txt
README.rdoc
Rakefile
lib/mygemtest.rb
lib/mygemtest/myclass.rb <- 追加
script/console
script/destroy
script/generate
spec/mygemtest_spec.rb
spec/spec.opts
spec/spec_helper.rb
tasks/rspec.rake

gemファイル生成を以下のファイルで行う。

 $ rake package 

pkgディレクトリにmygemtest-0.0.1.gemというファイルができているので、ちゃんと動作するかgemファイルをインストールしてみる。

 $ sudo gem install -l mygemtest-0.0.1.gem 
 PostInstall.txt 
 Successfully installed mygemtest-0.0.1 1 gem installed 
 Installing ri documentation for mygemtest-0.0.1... Building YARD (yri) index for mygemtest-0.0.1... 
 Installing RDoc documentation for mygemtest-0.0.1... 

irbで動作確認をする。

 $ irb 
irb(main):001:0> require "mygemtest/myclass"
irb(main):003:0> a = MyGemTest::MyClass.new
Initialized done !!
=> #

初期化メソッドが呼ばれていれば正しくインストールされている。

5 コマンドをgemに追加
gemパッケージにはライブラリコードだけでなくコマンドも追加できる。
以下のコマンドでコマンド用の雛形を生成する。

 $ ./script/generate executable mygemtest
    create  bin
      exists  lib/mygemtest
      create  bin/mygemtest
      create  lib/mygemtest/cli.rb
      exists  spec
      create  spec/mygemtest_cli_spec.rb

lib/mygemtest/cli.rbというファイルが生成されているので下のソースの39行目以降にコマンドのコードを書く。

require 'optparse'

module Mygemtest
  class CLI
    def self.execute(stdout, arguments=[])

      # NOTE: the option -p/--path= is given as an example, and should be replaced in your application.

      options = {
        :path     => '~'
      }
      mandatory_options = %w(  )

      parser = OptionParser.new do |opts|
        opts.banner = <<-BANNER.gsub(/^          /,'')
          This application is wonderful because...

          Usage: #{File.basename($0)} [options]

          Options are:
        BANNER
        opts.separator ""
        opts.on("-p", "--path PATH", String,
                "This is a sample message.",
                "For multiple lines, add more strings.",
                "Default: ~") { |arg| options[:path] = arg }
        opts.on("-h", "--help",
                "Show this help message.") { stdout.puts opts; exit }
        opts.parse!(arguments)

        if mandatory_options && mandatory_options.find { |option| options[option.to_sym].nil? }
          stdout.puts opts; exit
        end
      end

      path = options[:path]

      # do stuff ここにコードを追加
      stdout.puts "コマンド動いたよ!"
    end
  end
end

Manifest.txtにcli.rbのパスを追加。

History.txt
Manifest.txt
PostInstall.txt
README.rdoc
Rakefile
lib/mygemtest.rb
lib/mygemtest/cli.rb  <- 追加
lib/mygemtest/myclass.rb
script/console
script/destroy
script/generate
spec/mygemtest_spec.rb
spec/spec.opts
spec/spec_helper.rb
tasks/rspec.rake

再度、rake packageでgemパッケージを作りなおして再インストールすればコマンドが使えるようになる。
newgemの解説がいまいちちゃんとしたものがなかったので結構試行錯誤してしまったが、これだけおさえておけば普通に使う分には十分でしょう。
後、テストコードの書き方とか気が向いたら書くかも。

参考URL: gemパッケージの作り方

常識なのかもしれないが、コーディングしていて改めて気がついたのでメモ。

文字列の数字表現で”1234.56″といった感じのものを読んで整数なのか小数なのかをチェックする場合、マッチさせたいパターンは詳細なものから書く。
例えば以下のように書くと

全て整数として判断される。
このような場合は正規表現のより詳細なものから先に書いておく必要がある。

こうすれば小数は小数としてマッチするようになる。
もっとスマートなやり方があればコメントしていただきたい。

Rubyでは実行時にメソッドの動きを変更することができる。

例えば次のようなクラスをperson.rbというファイルに記述する。

次にchained_person.rbというファイルに次のように記述する。

aliase_methodでperson.rbのfunc1メソッドにfunc1_without_chainedという別名をつけて、次の行でfunc_with_chainedメソッドをfunc1メソッドとするように指定する。
そしてメインの処理を記述するファイルには以下のようにする。

これで環境変数CHAINEDに値が入っている場合はchained_person.rbのメソッドが呼ばれるようになる。
これはデバッグや違う環境でメソッドを変えたい場合にその部分だけ別ファイルに分離することができるので便利だ。

参考文献

実践 Rails -強力なWebアプリケーションをすばやく構築するテクニック 実践 Rails -強力なWebアプリケーションをすばやく構築するテクニック
株式会社クイープ

オライリージャパン 2008-10-27
売り上げランキング : 3881

Amazonで詳しく見る by G-Tools

LinuxのWebサーバー経由でWindows 2003サーバーのコマンドをRubyスクリプト起動する 方法としてSSH経由で実行することを考える。

まずはWindows 2003サーバーにCygwinをインストールしてその上でsshdを起動させる。
/etc/sshd_configはデフォルトのままにしておく。
sshdデーモンを以下のコマンドで起動しておく。

# cygrunsrv -S sshd  (停止するにはcygrunsrv -E sshd)

Linuxサーバー側のRubyスクリプトを実行する。
ソースコードはこんな感じ。

rubygemsをrequireしないとnet/sshが読み込めないというエラーが発生した。
またこのライブラリではsshの中でコマンド一発実行すると終了してしまうのでsession.loopという関数で複数コマンドを実行できるようにしている。
Windowsのバッチファイルを実行するためにはcmd .. callというコマンドで実行する必要があるようだ。
コマンドだけではcygwinからうまく実行できなかった。
バッチファイルで呼んでいるコマンドによるのかもしれない。