require 'hanami/model/config/adapter' require 'hanami/model/config/mapper' module Hanami module Model # Configuration for the framework, models and adapters. # # Hanami::Model has its own global configuration that can be manipulated # via `Hanami::Model.configure`. # # @since 0.2.0 class Configuration # Default migrations path # # @since 0.4.0 # @api private # # @see Hanami::Model::Configuration#migrations DEFAULT_MIGRATIONS_PATH = Pathname.new('db/migrations').freeze # Default schema path # # @since 0.4.0 # @api private # # @see Hanami::Model::Configuration#schema DEFAULT_SCHEMA_PATH = Pathname.new('db/schema.sql').freeze # The persistence mapper # # @return [Hanami::Model::Mapper] # # @since 0.2.0 attr_reader :mapper # An adapter configuration template # # @return [Hanami::Model::Config::Adapter] # # @since 0.2.0 attr_reader :adapter_config # Initialize a configuration instance # # @return [Hanami::Model::Configuration] a new configuration's # instance # # @since 0.2.0 def initialize reset! end # Reset all the values to the defaults # # @return void # # @since 0.2.0 def reset! @adapter = nil @adapter_config = nil @mapper = NullMapper.new @mapper_config = nil @migrations = DEFAULT_MIGRATIONS_PATH @schema = DEFAULT_SCHEMA_PATH end alias_method :unload!, :reset! # Load the configuration for the current framework # # @return void # # @since 0.2.0 def load! _build_mapper _build_adapter mapper.load!(@adapter) end # Register adapter # # There could only 1 adapter can be registered per application # # @overload adapter # Retrieves the configured adapter # @return [Hanami::Model::Config::Adapter,NilClass] the adapter, if # present # # @overload adapter # Register the adapter # @param @options [Hash] A set of options to register an adapter # @option options [Symbol] :type The adapter type. Eg. :sql, :memory # (mandatory) # @option options [String] :uri The database uri string (mandatory) # # @return void # # @raise [ArgumentError] if one of the mandatory options is omitted # # @see Hanami::Model.configure # @see Hanami::Model::Config::Adapter # # @example Register the adapter # require 'hanami/model' # # Hanami::Model.configure do # adapter type: :sql, uri: 'sqlite3://localhost/database' # end # # Hanami::Model.configuration.adapter_config # # @since 0.2.0 def adapter(options = nil) if options.nil? @adapter_config else _check_adapter_options!(options) @adapter_config ||= Hanami::Model::Config::Adapter.new(options) end end # Set global persistence mapping # # @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 # # @return void # # @see Hanami::Model.configure # @see Hanami::Model::Mapper # # @example Set global persistence mapper # require 'hanami/model' # # Hanami::Model.configure do # mapping do # collection :users do # entity User # # attribute :id, Integer # attribute :name, String # end # end # end # # @since 0.2.0 def mapping(path=nil, &blk) @mapper_config = Hanami::Model::Config::Mapper.new(path, &blk) end # Migrations directory # # It defaults to db/migrations. # # @overload migrations # Get migrations directory # @return [Pathname] migrations directory # # @overload migrations(path) # Set migrations directory # @param path [String,Pathname] the path # @raise [Errno::ENOENT] if the given path doesn't exist # # @since 0.4.0 # # @see Hanami::Model::Migrations::DEFAULT_MIGRATIONS_PATH # # @example Set Custom Path # require 'hanami/model' # # Hanami::Model.configure do # # ... # migrations 'path/to/migrations' # end def migrations(path = nil) if path.nil? @migrations else @migrations = root.join(path).realpath end end # Schema # # It defaults to db/schema.sql. # # @overload schema # Get schema path # @return [Pathname] schema path # # @overload schema(path) # Set schema path # @param path [String,Pathname] the path # # @since 0.4.0 # # @see Hanami::Model::Migrations::DEFAULT_SCHEMA_PATH # # @example Set Custom Path # require 'hanami/model' # # Hanami::Model.configure do # # ... # schema 'path/to/schema.sql' # end def schema(path = nil) if path.nil? @schema else @schema = root.join(path) end end # Root directory # # @since 0.4.0 # @api private def root Hanami.respond_to?(:root) ? Hanami.root : Pathname.pwd end # Duplicate by copying the settings in a new instance. # # @return [Hanami::Model::Configuration] a copy of the configuration # # @since 0.2.0 # @api private def duplicate Configuration.new.tap do |c| c.instance_variable_set(:@adapter_config, @adapter_config) c.instance_variable_set(:@mapper, @mapper) end end private # Instantiate mapper from mapping block # # @see Hanami::Model::Configuration#mapping # # @api private # @since 0.2.0 def _build_mapper @mapper = Hanami::Model::Mapper.new(&@mapper_config) if @mapper_config end # @api private # @since 0.1.0 def _build_adapter @adapter = adapter_config.build(mapper) end # @api private # @since 0.2.0 # # NOTE Drop this manual check when Ruby 2.0 will not be supported anymore. # Use keyword arguments instead. def _check_adapter_options!(options) # TODO Maybe this is a candidate for Hanami::Utils::Options # We already have two similar cases: # 1. Hanami::Router :only/:except for RESTful resources # 2. Hanami::Validations.validate_options! [:type, :uri].each do |keyword| raise ArgumentError.new("missing keyword: #{keyword}") if !options.keys.include?(keyword) end end end end end