10

コードが重複し始めている config.ru ファイルがあります。

map '/route1' do
  run SampleApp.new
end

map '/route2' do
  run SampleApp.new
end

このconfig.ruファイルを独自のRackアプリケーションに変えたいので、私がしなければならないことは次のとおりです。

map '/' do
  run MyApp.new
end

独自の Rack アプリケーションを作成する正しい方法は何ですか? 具体的には、mapクラス内でメソッドを使用して一連のルートを定義できるように、クラスを作成するにはどうすればよいですか?


解決:

これが実用的な解決策です:

class MyApp

  def initialize
    @app = Rack::Builder.new do
      # copy contents of your config.ru into this block
      map '/route1' do
        run SampleApp.new
      end

      map '/route2' do
        run SampleApp.new
      end
    end
  end

  def call(env)
    @app.call(env)
  end
end

map以前にこれを試しましたが、インスタンス変数をブロックに渡そうとしていたため、機能しませんでした。例えば:

def initialize
  @sample_app = SampleApp.new
  @app = Rack::Builder.new do
    map '/route1' do
      run @sample_app   # will not work
    end
  end
end

これが機能しない理由は、渡されるブロックがインスタンスのコンテキストで評価されるためmapです。Rack::Builder

ただし、ローカル変数を渡すと機能します。

def initialize
  sample_app = SampleApp.new
  @app = Rack::Builder.new do
    map '/route1' do
      run sample_app   # will work
    end
  end
end
4

4 に答える 4

11

で使用される DSLconfig.ruは で定義されていRack::Builderます。を使用するconfig.ruと、ファイルの内容が のインスタンスに渡されBuilder、Rack アプリが作成されます。これはコードで直接行うことができます。

たとえば、既存の の内容を取得して、config.ruそこから新しいクラスを作成できます。

require 'rack'

class MyApp

  def initialize
    @app = Rack::Builder.new do
      # copy contents of your config.ru into this block
      map '/route1' do
        run SampleApp.new
      end

      map '/route2' do
        run SampleApp.new
      end
    end
  end

  def call(env)
    @app.call(env)
  end
end

クラスが Rack アプリになるようにメソッドが必要ですが、callで作成したアプリにリクエストを転送するだけですBuilderconfig.ru次に、新しいアプリを使用する新しいアプリを作成できます。

require './my_app'

run MyApp.new
于 2012-07-16T21:50:43.263 に答える
4

これは本当に基本的な例です。おそらくRack::Response、自分で応答を構築するよりも、応答を処理する方法を検討する必要がありますが、基本的な Rack ミドルウェアがどのように機能するかについての良いアイデアが得られます。

class MyApp
  def call(env)
    request = Rack::Request.new(env)
    headers = { 'Content-Type' => 'text/html' }

    case request.path
    when '/'
      [200, headers, ["You're at the root url!"]]
    when '/foo'
      [200, headers, ["You're at /foo!"]]
    else
      [404, headers, ["Uh oh, path not found!"]]
    end
  end
end

編集:

複数の Rack アプリを 1 つにマッピングする:

class RootApp
  def call(env)
    [200, {'Content-Type' => 'text/html' }, ['Main root url']]
  end
end

class FooApp
  def call(env)
    [200, {'Content-Type' => 'text/html' }, ['Foo app url!']]
  end
end

class MyApp
  def initialize
    @apps = {}
  end

  def map(route, app)
    @apps[route] = app
  end

  def call(env)
    request = Rack::Request.new(env)

    if @apps[request.path]
      @apps[request.path].call(env)
    else
      [404, {'Content-Type' => 'text/html' }, ['404 not found']]
    end
  end
end

app = MyApp.new
app.map '/', RootApp.new
app.map '/foo', FooApp.new

run app
于 2012-07-16T21:26:09.627 に答える
3

URLMap を使用するのはどうですか。

app = Rack::URLMap.new(
  "/path1" => Path1App.new,
  "/path2" => Path2App.new
)

run app
于 2013-12-11T04:42:14.050 に答える
0

私はこれをします:

class MyApp 
  def call(env)
    @env = env

    # REQUEST_URI is still encoded; split before decoding to allow encoded slashes
    @path = env['REQUEST_URI'].split('/')

    # REQUEST_URI starts with a slash, so delete blank first element
    @path.delete_at(0)

    @path.each_index do |i|
      @path[i]= CGI.unescape(@path[i])
    end

    route()
  end
end

そしてroute()、リクエストをルーティングするために必要なことは何でもできます。たとえば、次のようになります。

class MyApp 
  def route
    m = @env['REQUEST_METHOD']
    @section = @path.shift

    if not @section
      home()
    elsif @section == 'route1' and m == 'GET'
      route1()
    # else ...
    end
  end
end
于 2012-07-16T21:29:46.723 に答える