0

私はRubyとSinatraを初めて使用し、クロージャ内のロガーEM.run do .. endオブジェクトにアクセスしようとしています( )。

これは、メッセージ「LOGGER ISNOTACCESSIBLEHERE」を含むロギングステートメントがコンパイルエラーを与える作業コードからの抜粋です。

class Connection
  def get_updates
   logger.info "LOGGER IS NOT ACCESSIBLE HERE 1"
  end
end

class Streamer < Sinatra::Base
  def stream
    logger.info "Inside stream"
    EM.run do
     logger.info "LOGGER IS NOT ACCESSIBLE HERE 3"
     Connection.new.get_updates

     EM::PeriodicTimer.new(10) do
      logger.info "LOGGER IS NOT ACCESSIBLE HERE 4"
     end
   end
  end
end
get '/' do
  logger.info "loading data"
  Streamer.new.stream  
end

私が見つけた文書から、 Sinatraはを使用していenv['rack.logger']ます。上記のコードのConnectionやStreamerなどのSinatra以外のクラスで同じものをどのように使用できますか?

4

1 に答える 1

1

実際、非常に興味深い質問です。結局のところ、loggerフィールドは実際には変数ではなく、 内のメソッドですSinatra::Base。したがって、オブジェクトのスコープ内にあるコードを実行しているときは、それを入力するだけでSinatra::Base呼び出すことがloggerでき、ロガー オブジェクトが返されます。

オブジェクトの一部であるため、Sinatra::Baseオブジェクトのスコープ内では表示されませんConnection

これで単純な Ruby の作業は終了です。次はより高度な作業です。

EM.run doさらに興味深いのは、セクション内から呼び出す場合です。そこでロガーを使用できない理由は、これらのブロックがオブジェクトのスコープ内で実行され、またはのようなものを使用しStreamereventmachine 自体によって他のスコープで実行されるためです。 EM のような DSL。instance_evalclass_evalinstance_eval

loggerこれが、ブロックからメソッドにアクセスできる理由でもあります。Sinatra は、メソッド usingget '/'を持つオブジェクトのスコープでこのブロックを実行します。loggerinstance_eval

やりたいことを行うために、ロガーを含むローカル変数を作成してみてください。

class Streamer < Sinatra::Base
  def stream
    # This will create a local variable called logger that will
    # save whatever is returned by the logger method
    logger = self.logger

    logger.info "Inside stream"
    EM.run do
     logger.info "This should now be accessible"
     Connection.new.get_updates

     EM::PeriodicTimer.new(10) do
      logger.info "This should now be accessible"
     end
   end
  end
end

Connectionこれでも、クラス内からログを記録するという問題は解決されません。これを行う方法は、グローバル ログ変数を使用するか (悪い考えです)、そうするときにロガー変数を渡すことですConnection.new(驚くべきアイデアではありませんが、グローバルよりは優れています)。

于 2012-12-13T14:53:36.677 に答える