check_dependencies

古い作り方のまんまになっているgem(rubeus)をbundlerを使う形にしようとして、まずGemfileを作ってrakeしたらこんなエラーが。

$ rake
rake aborted!
Don't know how to build task 'check_dependencies'

ぐぐってもよく分からないのでjewelerのソースコード読んだらcheck_dependenciesタスクはGemfileがないときだけ定義されるということが分かりました。最初からソース読めば良かったw
https://github.com/technicalpickles/jeweler/blob/master/lib/jeweler/tasks.rb#L187

結局Rakefileからcheck_dependenciesを削除して事なきを得ました

[java][ruby] JRubyからJavaのHttpClientを使う

今日、railsで作ってるサーバへの疎通確認をしてもらってたんですが、サーバとクライアントのどちらに問題があるのかわからなかったので、問題を切り分けるためにクライアント側で使うライブラリでちゃんとアクセスできるかどうか確認することにしました。

クライアントはJavaのhttpclientを使っているので、僕としては当然JRubyで使うわけです。書いたコードはこんな感じです。

localhostに対してGET /foo.json で得られたbarを POST /bazのパラメータとして使って送信してます

# -*- coding: utf-8 -*-

require 'java'
require 'rubygems'
require 'json'

# カレントディレクトリのlib以下に使用するjarを置いてください。
# jarは http://hc.apache.org/downloads.cgi のBinary とかからゲット可能です。
Dir['./lib/*.jar'].each{|f| require f}

import "java.io.BufferedReader"
import "java.io.InputStreamReader"
import "java.net.URLEncoder"
import "java.util.ArrayList"

import "org.apache.http.client.entity.UrlEncodedFormEntity"
import "org.apache.http.client.methods.HttpPost"
import "org.apache.http.client.methods.HttpGet"
import "org.apache.http.entity.StringEntity"
import "org.apache.http.impl.client.DefaultHttpClient"
import "org.apache.http.message.BasicNameValuePair"
import "org.apache.http.protocol.HTTP"

client = DefaultHttpClient.new

req = HttpGet.new("http://localhost/foo.json")
res = client.execute(req)
puts "status_code: #{res.getStatusLine.toString}"
rd = BufferedReader.new(InputStreamReader.new(res.getEntity.getContent))
lines = []
while line = rd.readLine
  lines << line
end
res_obj = JSON.parse(lines.join) # このJSONのparseはRubyのgemである"json"を使って行っています。
bar = res_obj['bar']

# GET /foo.json で得られたbarを POST /bazのパラメータとして使う

req = HttpPost.new("http://localhost/baz")
values = ArrayList.new(1)
values.add(BasicNameValuePair.new("bar", bar))
req.setEntity(UrlEncodedFormEntity.new(values, HTTP::UTF_8))

res = client.execute(req)
puts "status_code: #{res.getStatusLine.toString}"
rd = BufferedReader.new(InputStreamReader.new(res.getEntity.getContent))
while line = rd.readLine
  puts line
end

難しいRubyの文法を使わなかったのでJavaでクライアント側の実装をやってる人に読んでもらえたのが良かったです。

でも通信自身とは関係ない部分で、さりげなくJSON.parseとかRubyのライブラリを組み合わせて使っています。

rvmさえインストールされていれば、

$ rvm install jruby
$ rvm jruby
$ gem install json

で上記に必要なインストールは完了するはず。

あとは上のファイルの名前を java_httpclient_example.rb とするなら

$ jruby -S java_httpclient_example.rb

とかで実行できちゃいます。コンパイル不要です。

ちょっとだけJavaのライブラリを触るときにはこんな感じでやれると楽だなーと久しぶりに実感しました。

pushしちゃったコミットのコメントを直す方法

結論。そのリポジトリは捨てて作り直そう。

方法。git filter-branchやgit rebase -i (のreword)などでコメントを変更することはできるけど、そうすると変更されたコメントの新しいコミットが作られるだけで古いコメントのコミットも残る。

この古いコメントのコミットは、新たに作るリポジトリにはコミットしないで、新しいコミットの方のブランチだけをコミットすればOK。

あと、新しいリポジトリに移行したいブランチはちゃんとローカルに作っておかないと、pushできないのでちゃんとbranchをローカルに作るべし。

$ git checkout 移行したいブランチ名

でoriginを削除

$ git remote rm origin

コメントの修正はfilter-branchが楽です。 ( http://www.clear-code.com/blog/2012/1/5.html で紹介されている例 )

$ git filter-branch --msg-filter 'sed -e "s/Merge.*internal.*\$/Merge/"' -f

で、ここで新しく作られたブランチと、古いブランチがちゃんと分かれていることを確認したら、それを新しいリポジトリに移行しよう。

まず新しいリポジトリを作る。
githubならadmin画面からdeleteして、もう一回同じ名前で作るのはアリ。
ただしチームのメンバーに同じ名前だけど別物だから気を付けてね、と話しておく必要がある。

次にoriginを再設定する

$ git remote add origin 新しいリポジトリのURL

移行したいブランチをpushしまくる

$ git push origin 移行したいブランチ名

それからタグ関係も一緒に移行できればいいんだけど、古いブランチの方に付けられているので、無理っぽい。
自分で新旧のコミットのコメントを読んで新しい方に手動でタグを貼るしかなさそう。

これで多分オッケーなはず。

developmentを実現したいのでコードを読んでみる#5

昨日ログを出力するように変更したrailsを使って、ほとんど素のrails3のアプリでサーバの起動、GETリクエストx3、サーバの停止までにActionDispatch::Reloaderの各メソッドがどのように呼びだされるのか、developmentとproductionの場合それぞれについて出力してみました。
https://github.com/akm/rails3_reloader_study/blob/master/actiondispatch_reloader_method_invocations_development.log
https://github.com/akm/rails3_reloader_study/blob/master/actiondispatch_reloader_method_invocations_production.log

production

起動時

ActionDispatch::Reloader.to_cleanup(&#)

module Rails
  class Application
    module Bootstrap
      include Initializable

    # (中略)

      initializer :set_clear_dependencies_hook, :group => :all do
        ActionDispatch::Reloader.to_cleanup do
          ActiveSupport::DescendantsTracker.clear
          ActiveSupport::Dependencies.clear
        end
      end

ActionDispatch::Reloader.to_prepare(&#)

module I18n
  class Railtie < Rails::Railtie

    # (中略)

    initializer "i18n.callbacks" do
      ActionDispatch::Reloader.to_prepare do
        I18n::Railtie.reloader.execute_if_updated
      end
    end

ActionDispatch::Reloader.prepare!
ActionDispatch::Reloader#initialize(nil)

module Rails
  class Application
    module Finisher
      include Initializable

      # (中略)

      initializer :run_prepare_callbacks do
        ActionDispatch::Reloader.prepare!
      end
module ActionDispatch
  class Reloader
    include ActiveSupport::Callbacks

    # (中略)

    # Execute all prepare callbacks.
    def self.prepare!
      self.trace_log(:prepare!)
      new(nil).run_callbacks :prepare
    end
GET /tests/foo?idx=1

ActionDispatch::Reloader.to_prepare(&#)

module Rails
  class Application
    module Finisher
      include Initializable

      # (中略)

      initializer :set_routes_reloader do |app|
        reloader = lambda { app.routes_reloader.execute_if_updated }
        reloader.call
        ActionDispatch::Reloader.to_prepare(&reloader)
      end


ActionDispatch::Reloader.to_cleanup(&#)
ActionDispatch::Reloader.to_prepare(&#)

module ActiveRecord
  # = Active Record Railtie
  class Railtie < Rails::Railtie

    # (中略)

    initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
      ActiveSupport.on_load(:active_record) do
        ActionDispatch::Reloader.to_cleanup do
          ActiveRecord::Base.clear_reloadable_connections!
          ActiveRecord::Base.clear_cache!
        end
      end
    end

    config.after_initialize do
      ActiveSupport.on_load(:active_record) do
        instantiate_observers

        ActionDispatch::Reloader.to_prepare do
          ActiveRecord::Base.instantiate_observers
        end
      end
    end
GET /tests/foo?idx=2

なし

GET /tests/foo?idx=3

なし

サーバを停止

なし

まとめ

development

起動時

ActionDispatch::Reloader.to_cleanup(&#)
ActionDispatch::Reloader.to_prepare(&#)
これらはproductionと同じ。

ActionDispatch::Reloader#initialize(#

  /Users/akima/workspace/rails/actionpack/lib/action_dispatch/middleware/stack.rb:112:in `build'
  /Users/akima/workspace/rails/railties/lib/rails/engine.rb:447:in `app'
module ActionDispatch
  class MiddlewareStack

    # (中略)

    def build(app = nil, &block)
      app ||= block
      raise "MiddlewareStack#build requires an app" unless app
      middlewares.reverse.inject(app) { |a, e| e.build(a) }
    end
module Rails
  class Engine < Railtie

    # (中略)

    def app
      @app ||= begin
        config.middleware = config.middleware.merge_into(default_middleware_stack)
        config.middleware.build(endpoint)
      end
    end
GET /tests/foo?idx=1

ActionDispatch::Reloader.prepare!
ActionDispatch::Reloader#initialize(nil)
これらはproductionの起動時に実行されるものと同じ

ActionDispatch::Reloader.to_prepare(&#)
productionのGET /tests/foo?idx=1で実行されるものと同じ


ActionDispatch::Reloader#call({"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/tests/foo", "QUERY_STRING"=>"idx=1", ...)

module Rack

  class Sendfile

    # (中略)

    def call(env)
      status, headers, body = @app.call(env)
      if body.respond_to?(:to_path)
        case type = variation(env)

ActionDispatch::Reloader.to_cleanup(&#)
ActionDispatch::Reloader.to_prepare(&#)
productionのGET /tests/foo?idx=1で実行されるものと同じ


ActiveRecord::ConnectionAdapters::ConnectionManagement::Proxy#close
ActionDispatch::Reloader.cleanup!
ActionDispatch::Reloader#initialize(nil)

module Rack
  module Handler
      def service(req, res)

        # (中略)

        status, headers, body = @app.call(env)
        begin
          res.status = status.to_i
          headers.each { |k, vs|
            if k.downcase == "set-cookie"
              res.cookies.concat vs.split("\n")
            else
              # Since WEBrick won't accept repeated headers,
              # merge the values per RFC 1945 section 4.2.
              res[k] = vs.split("\n").join(", ")
            end
          }
          body.each { |part|
            res.body << part
          }
        ensure
          body.close  if body.respond_to? :close
        end
      end
module ActionDispatch
  class Reloader

    # (中略)

    # Execute all cleanup callbacks.
    def self.cleanup!
      self.trace_log(:cleanup!)
      new(nil).run_callbacks :cleanup
    end

    # (中略)

    module CleanupOnClose
      def close
        ActionDispatch::Reloader.trace_log_impl("#{self.class.name}#close")
        super if defined?(super)
      ensure
        ActionDispatch::Reloader.cleanup!
      end
    end
GET /tests/foo?idx=2

ActionDispatch::Reloader#call({"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/tests/foo", "QUERY_STRING"=>"idx=2", ...)

GET /tests/foo?idx=3

ActiveRecord::ConnectionAdapters::ConnectionManagement::Proxy#close
ActionDispatch::Reloader.cleanup!
ActionDispatch::Reloader#initialize(nil)
ActionDispatch::Reloader#call({"GATEWAY_INTERFACE"=>"CGI/1.1", "PATH_INFO"=>"/tests/foo", "QUERY_STRING"=>"idx=3", ...)

サーバを停止

ActiveRecord::ConnectionAdapters::ConnectionManagement::Proxy#close
ActionDispatch::Reloader.cleanup!
ActionDispatch::Reloader#initialize(nil)