3

Sinatra にいくつかの設定を行うクラスがあります (たまたま JSON から):

class Pavo < Sinatra::Base
  configure :development do
    set :config, JSON.parse(File.open(File.dirname(__FILE__) + "/pavo.configuration.development.json", "rb").read)
    set :config_mtime, File.mtime(File.dirname(__FILE__) + "/pavo.configuration.development.json")
  end

  [...]

  get '/' do
    puts "whatever"
  end
end

そして、そのクラスには、それらの設定を読み取るために必要なモデルがあります。

class Resolver < Sinatra::Base
  def get_data(workpid)
    url_str = settings.config['public']['BOOKS_DATA_SERVICE_URL'].gsub('${WORKPID}', workpid)
    return Resolver.get_json(url_str)
  end
  [...]
end

しかし、Resolver クラスはそれを行うことができません: Resolver:Class のメソッド「config」が未定義です。

スコープが間違っているか、Sinatra::Application を使用する必要がありますか?

4

1 に答える 1

3

継承するクラスを取得するSinatra::Baseと、それを Sinatra アプリケーションにします。各アプリケーションは独自の settingsオブジェクトを取得します。アプリケーション間で設定を共有したい場合は、いくつかのオプションがあります。

  1. アプリケーションをマージします。
  2. 設定をよりグローバルにアクセスできるようにします。
  3. 継承 (以下の編集を参照)

それらをマージするのは簡単です (私たちが気付いていない特定の理由がない限り)、基本的にそれらを同じクラスに入れます。

設定をよりグローバルにアクセスできるようにするには、次のようにします。

a) アプリケーション全体をモジュールにラップして名前空間にします。
b) 使用する設定を、「getter」メソッドを介してアクセス可能なクラス インスタンス変数に入れます。

例えば

module MyNamespace

  def self.global_settings
    @gs ||= # load your settings
  end

  class App < Sinatra::Base
    configure do
      set :something_from_the_global, MyNamespace.global_settings.something
    end
  end

  class SecondaryApp < Sinatra::Base
    helpers do
      def another_method
        MyNamespace.global_settings.something_else # available anywhere
      end
    end
    configure do # they're also available here, since you set them up before the app
      set :something_from_the_global, MyNamespace.global_settings.something
    end
  end

end

非常に小さなアプリがある場合は問題ありませんが、複数のアプリを使用している場合は、少し分けた方がよいでしょう。私がアプリを整理する傾向がある方法はconfig.rurequires とrun. 通常、ミドルウェアとアプリのセットアップを別のファイルに入れているapp/config.rbので、config.ru. 次に、各アプリケーションは独自のファイルを取得します (例app/app.rb: app/secondary.rb)

# app/config.rb

require "app"
require "secondary"

module MyNamespace
  # set up your getters… e.g.

  def self.global_settings
    @gs ||= # load your settings
  end

  def self.app
    Rack::Builder.app do

      # …and middleware here
      use SecondaryApp
      run App
    end
  end
end

# config.ru

require 'rubygems'
require 'bundler'
Bundler.require

root = File.expand_path File.dirname(__FILE__)
require File.join( root , "./app/config.rb" )

map "/" do
  run MyNamespace.app
end

この種のセットアップには多くの利点があります。テストが簡単です。整理しやすくなります。アプリを簡単に移動できます。でも相変わらずYMMV。


また、継承を使用することも可能であることを忘れているので、次のように追加する必要があります。

require 'sinatra/base'    

module MyNamespace
  class Controller < Sinatra::Base
    configure :development do
      set :config, "some JSON"
      set :mtime, Time.now.to_s
    end
  end

  class App1 < Controller

    get "/app1" do
      "in App1 config: #{settings.config} mtime: #{settings.mtime}"
    end
  end

  class App2 < Controller

    get "/app2" do
      "in App2 with config: #{settings. config} mtime: #{settings.mtime}"
    end
  end
end

設定、ルート、ヘルパー、フィルターはすべて継承されるため、祖先アプリで何かを構成すると、継承者で利用できるようになります。おそらく、設定が Sinatra アプリに対して単に「グローバル」である場合や、再利用可能なアプリとコントローラーを作成したい場合などです。また、モデルやライブラリなどで使用できる設定が必要になる場合もあります。その場合は、最初に示したよりグローバルなソリューションが最適です。

于 2013-02-14T00:46:25.340 に答える