lib/lotus/configuration.rb in lotusrb-0.1.0 vs lib/lotus/configuration.rb in lotusrb-0.2.0

- old
+ new

@@ -1,36 +1,58 @@ require 'lotus/utils/kernel' +require 'lotus/environment' +require 'lotus/config/framework_configuration' require 'lotus/config/load_paths' require 'lotus/config/assets' require 'lotus/config/routes' require 'lotus/config/mapping' +require 'lotus/config/sessions' +require 'lotus/config/configure' module Lotus # Configuration for a Lotus application # # @since 0.1.0 class Configuration + # @since 0.2.0 + # @api private + # + # @see Lotus::Configuration#ssl? + SSL_SCHEME = 'https'.freeze + # Initialize a new configuration instance # # @return [Lotus::Configuration] # # @since 0.1.0 # @api private def initialize @blk = Proc.new{} + @env = Environment.new + @configurations = Hash.new { |k, v| k[v] = [] } end - # Set a block yield when the configuration will be loaded + # Set a block yield when the configuration will be loaded or + # set a path for the specific environment. # + # @param environment [Symbol,nil] the configuration environment name + # @param environment [String,nil] the configuration path of a specific environment # @param blk [Proc] the configuration block # # @return [self] # # @since 0.1.0 # @api private - def configure(&blk) - @blk = blk if block_given? + def configure(environment = nil, path = nil, &blk) + if environment && path + @configurations[environment.to_s] << Config::Configure.new(root, path, &blk) + elsif environment + @configurations[environment.to_s] << blk + else + @blk = blk + end + self end # Load the configuration # @@ -40,11 +62,12 @@ # # @since 0.1.0 # @api private def load!(namespace = nil) @namespace = namespace - instance_eval(&@blk) + evaluate_configurations! + self end # The root of the application # @@ -296,33 +319,24 @@ else root.join @templates.to_s end end - # Assets root. - # The application will serve the static assets under this directory. + # The application will serve the static assets under these directories. # # By default it's equal to the `public/` directory under the application # `root`. # - # Otherwise, you can specify a different relative path under `root`. + # Otherwise, you can add differents relatives paths under `root`. # - # This is part of a DSL, for this reason when this method is called with - # an argument, it will set the corresponding instance variable. When - # called without, it will return the already set value, or the default. - # - # @overload assets(value) - # Sets the given value - # @param value [String] the relative path to the assets dir. - # # @overload assets # Gets the value # @return [Lotus::Config::Assets] assets root # # @since 0.1.0 # - # @see Lotus::Configuration#root + # @see Lotus::Configuration#serve_assets # # @example Getting the value # require 'lotus' # # module Bookshelf @@ -331,31 +345,227 @@ # end # # Bookshelf::Application.configuration.assets # # => #<Pathname:/root/path/public> # - # @example Setting the value + # @example Adding new assets paths # require 'lotus' # # module Bookshelf # class Application < Lotus::Application # configure do - # assets 'assets' + # serve_assets true + # assets << [ + # 'vendor/assets' + # ] # end # end # end # # Bookshelf::Application.configuration.assets - # # => #<Pathname:/root/path/assets> - def assets(value = nil) - if value - @assets = value + # # => #<Lotus::Config::Assets @root=#<Pathname:/root/path/assets>, @paths=["public"]> + # + def assets + @assets ||= Config::Assets.new(root) + end + + # Configure serving of assets + # Enable static assets (disabled by default). + # + # This is part of a DSL, for this reason when this method is called with + # an argument, it will set the corresponding instance variable. When + # called without, it will return the already set value, or the default. + # + # @since 0.2.0 + # + # @overload serve_assets(value) + # Sets the given value. + # @param value [TrueClass, FalseClass] + # + # @overload serve_assets + # Gets the value. + # @return [TrueClass, FalseClass] + # + # @see Lotus::Configuration#assets + # + # @example Getting serve assets configuration by default + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # end + # end + # + # Bookshelf::Application.configuration.serve_assets + # # => false + # + # @example Enabling static assets + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # serve_assets true + # end + # end + # end + # + # Bookshelf::Application.configuration.serve_assets + # # => true + def serve_assets(value = nil) + if value.nil? + @serve_assets || false else - Config::Assets.new(root, @assets) + @serve_assets = value end end + # Configure cookies + # Enable cookies (disabled by default). + # + # This is part of a DSL, for this reason when this method is called with + # an argument, it will set the corresponding instance variable. When + # called without, it will return the already set value, or the default. + # + # @overload cookies(value) + # Sets the given value. + # @param value [TrueClass, FalseClass] + # + # @overload cookies + # Gets the value. + # @return [TrueClass, FalseClass] + # + # @example Getting the value + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # end + # end + # + # Bookshelf::Application.configuration.cookies + # # => false + # + # @example Setting the value + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # cookies true + # end + # end + # end + # + # Bookshelf::Application.configuration.cookies + # # => true + # + # @example Setting a new value after one is set. + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # cookies false + # cookies true + # end + # end + # end + # + # Bookshelf::Application.configuration.cookies + # # => true + # + def cookies(value = nil) + if value.nil? + @cookies || false + else + @cookies = value + end + end + + # Configure sessions + # Enable sessions (disabled by default). + # + # This is part of a DSL, for this reason when this method is called with + # an argument, it will set the corresponding instance variable. When + # called without, it will return the already set value, or the default. + # + # Given Class as adapter it will be used as sessions middleware. + # Given String as adapter it will be resolved as class name and used as + # sessions middleware. + # Given Symbol as adapter it is assumed it's name of the class under + # Rack::Session namespace that will be used as sessions middleware + # (e.g. :cookie for Rack::Session::Cookie). + # + # By default options include domain inferred from host configuration, and + # secure flag inferred from scheme configuration. + # + # @overload sessions(adapter, options) + # Sets the given value. + # @param adapter [Class, String, Symbol] Rack middleware for sessions management + # @param options [Hash] options to pass to sessions middleware + # + # @overload sessions(false) + # Disables sessions + # + # @overload sessions + # Gets the value. + # @return [Lotus::Config::Sessions] sessions configuration + # + # @since 0.2.0 + # + # @see Lotus::Configuration#host + # @see Lotus::Configuration#scheme + # + # @example Getting the value + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # end + # end + # + # Bookshelf::Application.configuration.sessions + # # => #<Lotus::Config::Sessions:0x00000001ca0c28 @enabled=false> + # + # @example Setting the value with symbol + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # sessions :cookie, secret: 'abc123' + # end + # end + # end + # + # Bookshelf::Application.configuration.sessions + # # => #<Lotus::Config::Sessions:0x00000001589458 @enabled=true, @adapter=:cookie, @options={:domain=>"localhost", :secure=>false}> + # + # @example Disabling previusly enabled sessions + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # sessions :cookie + # sessions false + # end + # end + # end + # + # Bookshelf::Application.configuration.sessions + # # => #<Lotus::Config::Sessions:0x00000002460d78 @enabled=false> + # + def sessions(adapter = nil, options = {}) + if adapter.nil? + @sessions ||= Config::Sessions.new + else + @sessions = Config::Sessions.new(adapter, options, self) + end + end + # Application load paths # The application will recursively load all the Ruby files under these paths. # # By default it's empty in order to allow developers to decide their own # app structure. @@ -471,25 +681,239 @@ else @routes end end - # since 0.1.0 - # @api private + # Body parsing configuration. + # + # Specify a set of parsers for specific mime types that your application will use. This method will + # return the application's parsers which you can use to add existing and new custom parsers for your + # application to use. + # + # By default it's an empty `Array` + # + # This is part of a DSL, for this reason when this method is called with + # an argument, it will set the corresponding instance variable. When + # called without, it will return the already set value, or the default. + # + # @overload body_parsers(parsers) + # Specify a set of body parsers. + # @param parsers [Array] the body parser definitions + # + # @overload body_parsers + # Gets the value + # @return [Array] the set of parsers + # + # @since 0.2.0 + # + # @example Getting the value + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # end + # end + # + # Bookshelf::Application.configuration.body_parsers + # # => [] + # + # @example Setting the value + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # body_parsers :json, XmlParser.new + # end + # end + # end + # + # Bookshelf::Application.configuration.body_parsers + # # => [:json, XmlParser.new] + # + # @example Setting a new value after one is set. + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # body_parsers :json + # body_parsers XmlParser.new + # end + # end + # end + # + # Bookshelf::Application.configuration.body_parsers + # # => [XmlParser.new] + # + def body_parsers(*parsers) + if parsers.empty? + @body_parsers ||= [] + else + @body_parsers = parsers + end + end + + # Application middleware. + # + # Specify middleware that your application will use. This method will return + # the application's underlying Middleware stack which you can use to add new + # middleware for your application to use. By default, the middleware stack + # will contain only `Rack::Static` and `Rack::MethodOverride`. However, if + # `assets false` was specified # in the configuration block, the default + # `Rack::Static` will be removed. + # + # @since 0.2.0 + # + # @see http://rdoc.info/gems/rack/Rack/Static + # @see Lotus::Middleware#use + # + # @example + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # middleware.use Rack::MethodOverride, nil, 'max-age=0, private, must-revalidate' + # middleware.use Rack::ETag + # end + # end + # end + def middleware + @middleware ||= Lotus::Middleware.new(self) + end + + # Application collection mapping. + # + # Specify a set of collections for the application, by passing a block, or a + # relative path where to find the file that describes them. + # + # By default it's `nil`. + # + # This is part of a DSL, for this reason when this method is called with + # an argument, it will set the corresponding instance variable. When + # called without, it will return the already set value, or the default. + # + # @overload mapping(blk) + # Specify a set of mapping in the given block + # @param blk [Proc] the mapping definitions + # + # @overload mapping(path) + # Specify a relative path where to find the mapping file + # @param path [String] the relative path + # + # @overload mapping + # Gets the value + # @return [Lotus::Config::Mapping] the set of mappings + # + # @since 0.2.0 + # + # @see http://rdoc.info/gems/lotus-model/Lotus/Mapper + # + # @example Getting the value + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # end + # end + # + # Bookshelf::Application.configuration.mapping + # # => nil + # + # @example Setting the value, by passing a block + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # mapping do + # collection :users do + # entity User + # + # attribute :id, Integer + # attribute :name, String + # end + # end + # end + # end + # end + # + # Bookshelf::Application.configuration.mapping + # # => #<Lotus::Config::Mapping:0x007ff50a991388 @blk=#<Proc:0x007ff123991338@(irb):4>, @path=#<Pathname:.>> + # + # @example Setting the value, by passing a relative path + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # mapping 'config/mapping' + # end + # end + # end + # + # Bookshelf::Application.configuration.mapping + # # => #<Lotus::Config::Routes:0x007ff50a991388 @blk=nil, @path=#<Pathname:config/mapping.rb>> def mapping(path = nil, &blk) if path or block_given? @mapping = Config::Mapping.new(root, path, &blk) else @mapping end end + # Adapter configuration. + # The application will instantiate adapter instance based on this configuration. + # + # The given options must have key pairs :type and :uri + # If it isn't, at the runtime the framework will raise a + # `ArgumentError`. + # + # This is part of a DSL, for this reason when this method is called with + # an argument, it will set the corresponding instance variable. When + # called without, it will return the already set value, or the default. + # + # @overload adapter(options) + # Sets the given type and uri + # @param options [Hash] a set of options for adapter + # + # @overload adapter + # Gets the value + # @return [Hash] adapter options + # + # @since 0.2.0 + # + # @see Lotus::Configuration#adapter + # @see http://rdoc.info/gems/lotus-model/Lotus/Model/Configuration:adapter + # + # @example + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # adapter type: :sql, uri: 'sqlite3://uri' + # end + # end + # end + # + # Bookshelf::Application.configuration.adapter + # # => {type: :sql, uri: 'sqlite3://uri'} + def adapter(options = {}) + if !options.empty? + @adapter = options + else + @adapter + end + end + # Set a format as default fallback for all the requests without a strict # requirement for the mime type. # # The given format must be coercible to a symbol, and be a valid mime type - # alias. If it isn't, at the runtime the framework will raise a + # alias. If it isn't, at the runtime the framework will raise a # `Lotus::Controller::UnknownFormatError`. # # By default this value is `:html`. # # This is part of a DSL, for this reason when this method is called with @@ -588,10 +1012,21 @@ else @scheme ||= 'http' end end + # Check if the application uses SSL + # + # @return [FalseClass,TrueClass] the result of the check + # + # @since 0.2.0 + # + # @see Lotus::Configuration#scheme + def ssl? + scheme == SSL_SCHEME + end + # The URI host for this application. # This is used by the router helpers to generate absolute URLs. # # By default this value is `"localhost"`. # @@ -635,23 +1070,19 @@ # Bookshelf::Application.configuration.host # => "bookshelf.org" def host(value = nil) if value @host = value else - @host ||= 'localhost' + @host ||= @env.host end end # The URI port for this application. # This is used by the router helpers to generate absolute URLs. # - # By default this value is `80`, if `scheme` is `"http"`, or `443` if - # `scheme` is `"https"`. + # By default this value is `2300`. # - # This is optional, you should set this value only if your application - # listens on a port not listed above. - # # This is part of a DSL, for this reason when this method is called with # an argument, it will set the corresponding instance variable. When # called without, it will return the already set value, or the default. # # @overload port(value) @@ -673,33 +1104,29 @@ # module Bookshelf # class Application < Lotus::Application # end # end # - # Bookshelf::Application.configuration.port # => 80 + # Bookshelf::Application.configuration.port # => 2300 # # @example Setting the value # require 'lotus' # # module Bookshelf # class Application < Lotus::Application # configure do - # port 2323 + # port 8080 # end # end # end # - # Bookshelf::Application.configuration.port # => 2323 + # Bookshelf::Application.configuration.port # => 8080 def port(value = nil) if value @port = Integer(value) else - @port || - case scheme - when 'http' then 80 - when 'https' then 443 - end + @port || @env.port end end # Defines a relative pattern to find controllers. # @@ -954,8 +1381,239 @@ if value @view_pattern = value else @view_pattern ||= 'Views::%{controller}::%{action}' end + end + + # Decide if handle exceptions with an HTTP status or let them uncaught + # + # If this value is set to `true`, the configured exceptions will return + # the specified HTTP status, the rest of them with `500`. + # + # If this value is set to `false`, the exceptions won't be caught. + # + # This is part of a DSL, for this reason when this method is called with + # an argument, it will set the corresponding instance variable. When + # called without, it will return the already set value, or the default. + # + # @overload handle_exceptions(value) + # Sets the given value + # @param value [TrueClass, FalseClass] true or false, default to true + # + # @overload handle_exceptions + # Gets the value + # @return [TrueClass, FalseClass] + # + # @since 0.2.0 + # + # @see http://rdoc.info/gems/lotus-controller/Lotus/Controller/Configuration:handle_exceptions + # @see http://httpstatus.es/500 + # + # @example Enabled (default) + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # routes do + # get '/error', to: 'error#index' + # end + # end + # + # load! + # end + # + # module Controllers::Error + # include Bookshelf::Controller + # + # action 'Index' do + # def call(params) + # raise ArgumentError + # end + # end + # end + # end + # + # # GET '/error' # => 500 - Internal Server Error + # + # @example Disabled + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # handle_exceptions false + # + # routes do + # get '/error', to: 'error#index' + # end + # end + # + # load! + # end + # + # module Controllers::Error + # include Bookshelf::Controller + # + # action 'Index' do + # def call(params) + # raise ArgumentError + # end + # end + # end + # end + # + # # GET '/error' # => raises ArgumentError + def handle_exceptions(value = nil) + if value.nil? + @handle_exceptions + else + @handle_exceptions = value + end + end + + # It lazily collects all the low level settings for Lotus::Model's + # configuration and applies them when the application is loaded. + # + # NOTE: This forwards all the configurations to Lotus::Model, without + # checking them. Before to use this feature, please have a look at the + # current Lotus::Model version installed. + # + # NOTE: This may override some configurations of your application. + # + # @return [Lotus::Config::FrameworkConfiguration] the configuration + # + # @since 0.2.0 + # + # @see http://www.rubydoc.info/gems/lotus-model/Lotus/Model/Configuration + # + # @example Define a setting + # require 'lotus' + # require 'lotus/model' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # model.adapter type: :memory, uri: 'memory://localhost/database' + # end + # end + # end + # + # @example Override a setting + # require 'lotus' + # require 'lotus/model' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # adapter type: :sql, uri: 'postgres://localhost/database' + # model.adapter type: :memory, uri: 'memory://localhost/database' + # end + # end + # end + # + # # The memory adapter will override the SQL one + def model + @model ||= Config::FrameworkConfiguration.new + end + + # It lazily collects all the low level settings for Lotus::Controller's + # configuration and applies them when the application is loaded. + # + # NOTE: This forwards all the configurations to Lotus::Controller, without + # checking them. Before to use this feature, please have a look at the + # current Lotus::Controller version installed. + # + # NOTE: This may override some configurations of your application. + # + # @return [Lotus::Config::FrameworkConfiguration] the configuration + # + # @since 0.2.0 + # + # @see http://www.rubydoc.info/gems/lotus-controller/Lotus/Controller/Configuration + # + # @example Define a setting + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # controller.default_format :json + # end + # end + # end + # + # @example Override a setting + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # handle_exceptions false + # controller.handle_exceptions true + # end + # end + # end + # + # # Exceptions will be handled + def controller + @controller ||= Config::FrameworkConfiguration.new + end + + # It lazily collects all the low level settings for Lotus::View's + # configuration and applies them when the application is loaded. + # + # NOTE: This forwards all the configurations to Lotus::View, without + # checking them. Before to use this feature, please have a look at the + # current Lotus::View version installed. + # + # NOTE: This may override some configurations of your application. + # + # @return [Lotus::Config::FrameworkConfiguration] the configuration + # + # @since 0.2.0 + # + # @see http://www.rubydoc.info/gems/lotus-view/Lotus/View/Configuration + # + # @example Define a setting + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # view.layout :application + # end + # end + # end + # + # @example Override a setting + # require 'lotus' + # + # module Bookshelf + # class Application < Lotus::Application + # configure do + # layout :application + # view.layout :backend + # end + # end + # end + # + # # It will use `:backend` layout + def view + @view ||= Config::FrameworkConfiguration.new + end + + private + # @since 0.2.0 + # @api private + def evaluate_configurations! + configurations.each { |c| instance_eval(&c) } + end + + # @since 0.2.0 + # @api private + def configurations + [ @blk ] + @configurations[@env.environment] end end end