Hatena::ブログ(Diary)

わからん

2011.12.25

[] bundler gem での外部コマンド実行のための枠組み

bundler gem の gem_helper.rb の該当箇所を読んだメモです。これといって独特なところ、読みにくいところはなく、使いまわせそうな普通のコードでした。次の 2 つがおもな特徴です。

  • 実行結果と実行したコマンドの終了ステータスが取得できる
  • コマンドが成功だった場合に実行する処理を可変にしてある(ブロック渡しで指定)

▼ 定義

    def sh(cmd, &block)
      out, code = sh_with_code(cmd, &block)  # 丸投げ
      code == 0 ? out : raise(out.empty? ? "Running `#{cmd}' failed. Run this command directly for more detailed output." : out)
    end

    def sh_with_code(cmd, &block)
      cmd << " 2>&1"            # 2 の出力先を 1 の出力先と同じものに設定する、という指定を追加しておく
      outbuf = ''
      Bundler.ui.debug(cmd)
      Dir.chdir(base) {         # コマンドを実行するディレクトリは可変
        outbuf = `#{cmd}`
        if $? == 0
          block.call(outbuf) if block  # コマンド実行成功時の処理も可変
        end
      }
      [outbuf, $?]
    end

▼ 呼び出し

    def build_gem
      file_name = nil
      sh("gem build -V '#{spec_path}'") { |out, code|
        # 文字列[/正規表現/] で部分文字列の存在チェック
        raise out unless out[/Successfully/]
        file_name = File.basename(built_gem_path)
        FileUtils.mkdir_p(File.join(base, 'pkg'))
        FileUtils.mv(built_gem_path, 'pkg')
        Bundler.ui.confirm "#{name} #{version} built to pkg/#{file_name}"
      }
      File.join(base, 'pkg', file_name)
    end

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

Google