lib/ardb.rb in ardb-0.27.3 vs lib/ardb.rb in ardb-0.28.0
- old
+ new
@@ -1,115 +1,182 @@
-require 'pathname'
-require 'singleton'
require 'active_record'
-require 'ns-options'
+require 'logger'
require 'ardb/version'
-require 'ardb/root_path'
ENV['ARDB_DB_FILE'] ||= 'config/db'
module Ardb
- NotConfiguredError = Class.new(RuntimeError)
- def self.config; Config; end
- def self.configure(&block); Config.define(&block); end
+ def self.config
+ @config ||= Config.new
+ end
- def self.adapter; Adapter.current; end
-
- def self.validate!
- if !self.config.required_set?
- raise NotConfiguredError, "missing required configs"
- end
+ def self.configure(&block)
+ self.config.tap(&block)
end
+ def self.adapter; @adapter; end
+
def self.init(establish_connection = true)
require 'ardb/require_autoloaded_active_record_files'
- require self.config.db_file
- validate!
- Adapter.init
+ begin
+ require_db_file
+ rescue InvalidDBFileError => exception
+ raise exception.tap{ |e| e.set_backtrace(caller) }
+ end
+ self.config.validate!
+ @adapter = Adapter.new(self.config)
+
# setup AR
ActiveRecord::Base.logger = self.config.logger
- if establish_connection
- ActiveRecord::Base.establish_connection(self.config.db_settings)
- end
+ self.adapter.connect_db if establish_connection
end
def self.escape_like_pattern(pattern, escape_char = nil)
self.adapter.escape_like_pattern(pattern, escape_char)
end
- class Config
- include NsOptions::Proxy
+ private
- namespace :db do
- option :adapter, String, :required => true
- option :database, String, :required => true
- option :encoding, String, :required => false
- option :host, String, :required => false
- option :port, Integer, :required => false
- option :username, String, :required => false
- option :password, String, :required => false
- option :pool, Integer, :required => false
- option :checkout_timeout, Integer, :required => false
+ # try requiring the db file via the load path or as an absolute path, if
+ # that fails it tries requiring relative to the current working directory
+ def self.require_db_file
+ begin
+ require ENV['ARDB_DB_FILE']
+ rescue LoadError
+ require File.expand_path(ENV['ARDB_DB_FILE'], ENV['PWD'])
end
+ rescue LoadError
+ raise InvalidDBFileError, "can't require `#{ENV['ARDB_DB_FILE']}`, " \
+ "check that the ARDB_DB_FILE env var is set to " \
+ "the file path of your db file"
+ end
- option :db_file, Pathname, :default => ENV['ARDB_DB_FILE']
- option :root_path, Pathname, :required => true
- option :logger, :required => true
- option :migrations_path, RootPath, :default => proc{ "db/migrations" }
- option :schema_path, RootPath, :default => proc{ "db/schema" }
- option :schema_format, Symbol, :default => :ruby
+ class Config
- def self.db_settings
- db.to_hash.inject({}) do |settings, (k, v)|
- settings[k.to_s] = v if !v.nil?
- settings
- end
+ ACTIVERECORD_ATTRS = [
+ :adapter,
+ :database,
+ :encoding,
+ :host,
+ :port,
+ :username,
+ :password,
+ :pool,
+ :checkout_timeout,
+ :min_messages
+ ].freeze
+ DEFAULT_MIGRATIONS_PATH = 'db/migrations'.freeze
+ DEFAULT_SCHEMA_PATH = 'db/schema'.freeze
+ RUBY_SCHEMA_FORMAT = :ruby.freeze
+ SQL_SCHEMA_FORMAT = :sql.freeze
+ VALID_SCHEMA_FORMATS = [RUBY_SCHEMA_FORMAT, SQL_SCHEMA_FORMAT].freeze
+
+ attr_accessor *ACTIVERECORD_ATTRS
+ attr_accessor :logger, :root_path
+ attr_reader :schema_format
+ attr_writer :migrations_path, :schema_path
+
+ def initialize
+ @logger = Logger.new(STDOUT)
+ @root_path = ENV['PWD']
+ @migrations_path = DEFAULT_MIGRATIONS_PATH
+ @schema_path = DEFAULT_SCHEMA_PATH
+ @schema_format = RUBY_SCHEMA_FORMAT
end
- end
+ def migrations_path
+ File.expand_path(@migrations_path.to_s, @root_path.to_s)
+ end
- class Adapter
- include Singleton
+ def schema_path
+ File.expand_path(@schema_path.to_s, @root_path.to_s)
+ end
- attr_accessor :current
+ def schema_format=(new_value)
+ @schema_format = begin
+ new_value.to_sym
+ rescue NoMethodError
+ raise ArgumentError, "schema format must be a `Symbol`", caller
+ end
+ end
- def init
- @current = Adapter.send(Ardb.config.db.adapter)
+ def activerecord_connect_hash
+ ACTIVERECORD_ATTRS.inject({}) do |h, attr_name|
+ value = self.send(attr_name)
+ !value.nil? ? h.merge!(attr_name.to_s => value) : h
+ end
end
- def reset
- @current = nil
+ def validate!
+ if self.adapter.to_s.empty? || self.database.to_s.empty?
+ raise ConfigurationError, "an adapter and database must be provided"
+ elsif !VALID_SCHEMA_FORMATS.include?(self.schema_format)
+ raise ConfigurationError, "schema format must be one of: " \
+ "#{VALID_SCHEMA_FORMATS.join(', ')}"
+ end
+ true
end
- def sqlite
- require 'ardb/adapter/sqlite'
- Adapter::Sqlite.new
+ def ==(other)
+ if other.kind_of?(self.class)
+ self.activerecord_connect_hash == other.activerecord_connect_hash &&
+ self.logger == other.logger &&
+ self.root_path == other.root_path &&
+ self.schema_format == other.schema_format &&
+ self.migrations_path == other.migrations_path &&
+ self.schema_path == other.schema_path
+ else
+ super
+ end
end
- alias_method :sqlite3, :sqlite
- def postgresql
- require 'ardb/adapter/postgresql'
- Adapter::Postgresql.new
+ end
+
+ module Adapter
+
+ VALID_ADAPTERS = [
+ 'sqlite',
+ 'sqlite3',
+ 'postgresql',
+ 'postgres',
+ 'mysql',
+ 'mysql2'
+ ].freeze
+
+ def self.new(config)
+ if !VALID_ADAPTERS.include?(config.adapter)
+ raise InvalidAdapterError, "invalid adapter: `#{config.adapter}`"
+ end
+ self.send(config.adapter, config)
end
- def mysql
- require 'ardb/adapter/mysql'
- Adapter::Mysql.new
+ def self.sqlite(config)
+ require 'ardb/adapter/sqlite'
+ Adapter::Sqlite.new(config)
end
- alias_method :mysql2, :mysql
- # nice singleton api
+ def self.sqlite3(config); self.sqlite(config); end
- def self.method_missing(method, *args, &block)
- self.instance.send(method, *args, &block)
+ def self.postgresql(config)
+ require 'ardb/adapter/postgresql'
+ Adapter::Postgresql.new(config)
end
- def self.respond_to?(method)
- super || self.instance.respond_to?(method)
+ def self.postgres(config); self.postgresql(config); end
+
+ def self.mysql(config)
+ require 'ardb/adapter/mysql'
+ Adapter::Mysql.new(config)
end
+ def self.mysql2(config); self.mysql(config); end
+
end
+
+ InvalidDBFileError = Class.new(ArgumentError)
+ ConfigurationError = Class.new(ArgumentError)
+ InvalidAdapterError = Class.new(RuntimeError)
end