lib/hanami/application.rb in hanami-0.8.0 vs lib/hanami/application.rb in hanami-0.9.0
- old
+ new
@@ -1,12 +1,12 @@
-require 'hanami/utils/class_attribute'
-require 'hanami/frameworks'
-require 'hanami/configuration'
-require 'hanami/loader'
-require 'hanami/logger'
+require 'thread'
+require 'concurrent'
+require 'hanami/application_name'
+require 'hanami/application_namespace'
+require 'hanami/application_configuration'
+require 'hanami/environment_application_configurations'
require 'hanami/rendering_policy'
-require 'hanami/middleware'
module Hanami
# A full stack Hanami application
#
# @since 0.1.0
@@ -26,131 +26,120 @@
#
# @see http://www.ruby-doc.org/core/Class.html#method-i-inherited
def self.inherited(base)
super
- base.class_eval do
- include Hanami::Utils::ClassAttribute
+ base.extend(ClassMethods)
+ base.namespace.module_eval do
+ class << self
+ # Logger for this application
+ #
+ # @return [Hanami::Logger] the logger for this Hanami application
+ #
+ # @since 0.9.0
+ # @api public
+ #
+ # @example
+ #
+ # Web.logger
+ # Admin.logger
+ attr_accessor :logger
- class_attribute :configuration
- self.configuration = Configuration.new
+ # Routes for this application
+ #
+ # @return [Hanami::Routes] the routes for this Hanami application
+ #
+ # @since 0.9.0
+ # @api public
+ #
+ # @example
+ #
+ # Web.routes
+ # Admin.routes
+ attr_accessor :routes
+ end
end
-
- synchronize do
- applications.add(base)
- end
end
- # @since 0.8.0
- # @api private
- LOCK = Mutex.new
-
- # Return the routes for this application
+ # Class interface for Hanami applications
#
- # @return [Hanami::Router] a route set
- #
- # @since 0.1.0
- #
- # @see Hanami::Configuration#routes
- attr_reader :routes
+ # @since 0.9.0
+ module ClassMethods
+ # Override Ruby's Class#extended
+ #
+ # @since 0.9.0
+ # @api private
+ #
+ # @see http://www.ruby-doc.org/core/Class.html#method-i-extended
+ def self.extended(base) # rubocop:disable Metrics/MethodLength
+ super
- # Set the routes for this application
- #
- # @param [Hanami::Router]
- #
- # @since 0.1.0
- # @api private
- attr_writer :routes
+ base.class_eval do
+ @namespace = ApplicationNamespace.resolve(name)
+ @configurations = EnvironmentApplicationConfigurations.new
+ @_lock = Mutex.new
- # Rendering policy
- #
- # @param [Hanami::RenderingPolicy]
- #
- # @since 0.2.0
- # @api private
- attr_accessor :renderer
+ class << self
+ # @since 0.9.0
+ # @api private
+ attr_reader :namespace
- # Initialize and load a new instance of the application
- #
- # @return [Hanami::Application] a new instance of the application
- #
- # @since 0.1.0
- def initialize(options = {})
- self.class.configuration.path_prefix options[:path_prefix]
- self.class.load!(self)
- end
+ # @since 0.9.0
+ # @api private
+ attr_reader :configurations
- # Return the configuration for this application
- #
- # @since 0.1.0
- # @api private
- #
- # @see Hanami::Application.configuration
- def configuration
- self.class.configuration
- end
+ # @since 0.9.0
+ # @api private
+ attr_reader :configuration
+ end
+ end
+ end
- # Return the application name
- #
- # @since 0.2.0
- # @api private
- def name
- self.class.name
- end
-
- # Process a request.
- # This method makes Hanami applications compatible with the Rack protocol.
- #
- # @param env [Hash] a Rack env
- #
- # @return [Array] a serialized Rack response
- #
- # @since 0.1.0
- #
- # @see http://rack.github.io
- # @see Hanami::RenderingPolicy#render
- # @see Hanami::Application#middleware
- def call(env)
- renderer.render(env, middleware.call(env))
- end
-
- # Rack middleware stack
- #
- # @return [Hanami::Middleware] the middleware stack
- #
- # @since 0.1.0
- # @api private
- #
- # @see Hanami::Middleware
- def middleware
- @middleware ||= configuration.middleware
- end
-
- class << self
- # @since 0.2.0
+ # Hanami application name
+ #
+ # @return [String] the Hanami application name
+ #
+ # @since 0.9.0
# @api private
- @@applications = Set.new
+ #
+ # @example
+ # require 'hanami'
+ #
+ # module Web
+ # class Application < Hanami::Application
+ # end
+ # end
+ #
+ # Web::Application.app_name # => "web"
+ def app_name
+ ApplicationName.new(name).to_s
+ end
- # Registry of Hanami applications in the current Ruby process
+ # Set configuration
#
- # @return [Set] a set of all the registered applications
+ # @param configuration [Hanami::ApplicationConfiguration] the application configuration
#
- # @since 0.2.0
+ # @raise [RuntimeError] if the configuration is assigned more than once
+ #
+ # @since 0.1.0
# @api private
- def applications
- @@applications
+ def configuration=(configuration)
+ @_lock.synchronize do
+ raise "Can't assign configuration more than once (#{app_name})" unless @configuration.nil?
+ @configuration = configuration
+ end
end
# Configure the application.
# It yields the given block in the context of the configuration
#
# @param environment [Symbol,nil] the configuration environment name
# @param blk [Proc] the configuration block
#
# @since 0.1.0
#
- # @see Hanami::Configuration
+ # @see Hanami::ApplicationConfiguration
#
# @example
# require 'hanami'
#
# module Bookshelf
@@ -159,94 +148,66 @@
# # ...
# end
# end
# end
def configure(environment = nil, &blk)
- configuration.configure(environment, &blk)
+ configurations.add(environment, &blk)
end
+ end
- # Eager load the application configuration, by activating the framework
- # duplication mechanisms.
- #
- # @param application [Hanami::Application, Class<Hanami::Application>]
- # @return void
- #
- # @since 0.1.1
- #
- # @example
- # require 'hanami'
- #
- # module OneFile
- # class Application < Hanami::Application
- # configure do
- # routes do
- # get '/', to: 'dashboard#index'
- # end
- # end
- #
- # load!
- # end
- #
- # module Controllers::Dashboard
- # class Index
- # include OneFile::Action
- #
- # def call(params)
- # self.body = 'Hello!'
- # end
- # end
- # end
- # end
- def load!(application = self)
- Hanami::Loader.new(application).load!
- end
+ # Initialize and load a new instance of the application
+ #
+ # @return [Hanami::Application] a new instance of the application
+ #
+ # @since 0.1.0
+ def initialize
+ @renderer = RenderingPolicy.new(configuration)
+ @middleware = configuration.middleware
+ end
- # Preload all the registered applications, by yielding their configurations
- # and preparing the frameworks.
- #
- # This is useful for testing suites, where we want to make Hanami frameworks
- # ready, but not preload applications code.
- #
- # This allows to test components such as views or actions in isolation and
- # to have faster boot times.
- #
- # @return [void]
- #
- # @since 0.2.0
- def preload!
- synchronize do
- applications.each(&:load!)
- end
+ # Process a request.
+ # This method makes Hanami applications compatible with the Rack protocol.
+ #
+ # @param env [Hash] a Rack env
+ #
+ # @return [Array] a serialized Rack response
+ #
+ # @since 0.1.0
+ #
+ # @see http://rack.github.io
+ # @see Hanami::RenderingPolicy#render
+ # @see Hanami::Application#middleware
+ def call(env)
+ renderer.render(env, middleware.call(env))
+ end
- nil
- end
+ private
- # Full preload for all the registered applications.
- #
- # This is useful in console where we want all the application code available.
- #
- # @return [void]
- #
- # @since 0.2.1
- # @api private
- def preload_applications!
- synchronize do
- applications.each { |app| app.new }
- end
+ # Return the configuration for this application
+ #
+ # @since 0.1.0
+ # @api private
+ #
+ # @see Hanami::Application.configuration
+ def configuration
+ self.class.configuration
+ end
- nil
- end
+ # Rendering policy
+ #
+ # @since 0.2.0
+ # @api private
+ #
+ # @see Hanami::RenderingPolicy
+ attr_reader :renderer
- private
-
- # Yields the given block in a critical section
- #
- # @since 0.2.0
- # @api private
- def synchronize
- LOCK.synchronize do
- yield
- end
- end
- end
+ # Rack middleware stack
+ #
+ # @return [Hanami::Middleware] the middleware stack
+ #
+ # @since 0.1.0
+ # @api private
+ #
+ # @see Hanami::Middleware
+ attr_reader :middleware
end
end