Architecture for a modular, component-based Sinatra Application
I'm working on a Sinatra app that contains about 10 different components of functionality. We'd like to be able to mix and match these components into separate instances of the applicat开发者_JS百科ion, configured entirely from a config.yaml file that looks something like:
components:
- route: '/chunky'
component_type: FoodLister
component_settings:
food_type: bacon
max_items: 400
- route: 'places/paris'
component_type: Mapper
component_settings:
latitude: 48.85387273165654
longitude: 2.340087890625
- route: 'places/losangeles'
component_type: Mapper
component_settings:
latitude: 34.043556504127466
longitude: -118.23486328125
As you can see, components can be instantiated more than once, each with their own contextual settings.
Each component consists of at least one route, with the "route" property from the config file used for the base.
What is the best way to organize and instantiate the module code?
This is similar to include's proposal, but it doesn't require access to the rackup file.
Write your various Handlers like:
class FoodHandler < Sinatra::Base
get '/chunky/:food' do
"Chunky #{params[:food]}!"
end
end
Then in your main application file:
require './lib/handlers/food_handler.rb'
class Main < Sinatra::Base
enable :sessions
... bla bla bla
use FoodHandler
end
I've used this kind of structure to build some fairly complex Sinatra apps. It scales just as well as Rails.
EDIT
To have your config file define the routes, you could do something like this:
class PlacesHandler < Sinatra::Base
# Given your example, this would define 'places/paris' and 'places/losangeles'
CONFIG['components'].select { |c| c['compontent_type'] == 'Mapper' }.each do |c|
get c['route'] do
@latitude = c['component_settings']['latitude']
@longitude = c['component_settings']['longitude']
end
end
end
TIMTOWTDI - There's_more_than_one_way_to_do_it :) and that is one. But in fact I use another way. I use Sinatra/Base to dev modular apps.
I have simgle routes to each app.
# config.ru file
require 'bundler/setup' Bundler.require(:default)
require File.dirname(__FILE__) + "/main.rb"
map "/" { run BONES::Main }
map "/dashboard" { run BONES::Dashboard }
map "/app1" { run BONES::App1 }
You can have variable sets for each instance. You can develop each 'component' on its Module.
require File.dirname(__FILE__) + "/lib/helpers.rb"
module BONES
class Main < Sinatra::Base
helpers XIXA::Helpers
configure :development do
enable :sessions, :clean_trace, :inline_templates
disable :logging, :dump_errors
set :static, true
set :public, 'public'
end
enable :static, :session
set :root, File.dirname(__FILE__)
set :custom_option, 'hello'
set :haml, { :format => :html5 }
#...
That a look here. http://codex.heroku.com/
have fun :)
精彩评论