Working on adding automated configuration support
This commit is contained in:
parent
37c021a6b9
commit
f3dd4ae06e
9 changed files with 299 additions and 26 deletions
|
@ -4,10 +4,11 @@ module CouchRest
|
|||
|
||||
extend ActiveModel::Naming
|
||||
|
||||
include CouchRest::Model::Connection
|
||||
include CouchRest::Model::Configuration
|
||||
include CouchRest::Model::Persistence
|
||||
include CouchRest::Model::Callbacks
|
||||
include CouchRest::Model::DocumentQueries
|
||||
include CouchRest::Model::DocumentQueries
|
||||
include CouchRest::Model::Views
|
||||
include CouchRest::Model::DesignDoc
|
||||
include CouchRest::Model::ExtendedAttachments
|
||||
|
|
|
@ -11,13 +11,33 @@ module CouchRest
|
|||
add_config :model_type_key
|
||||
add_config :mass_assign_any_attribute
|
||||
add_config :auto_update_design_doc
|
||||
add_config :database_config_path
|
||||
add_config :environment
|
||||
add_config :connection
|
||||
add_config :connection_config_file
|
||||
|
||||
configure do |config|
|
||||
config.model_type_key = 'model' # was 'couchrest-type'
|
||||
config.mass_assign_any_attribute = false
|
||||
config.auto_update_design_doc = true
|
||||
config.database_config_path = File.join(defined?(Rails) ? Rails.root : Dir.pwd, 'config', 'couchdb.yml')
|
||||
|
||||
config.environment = defined?(Rails) ? Rails.env : :development
|
||||
|
||||
config.connection_config_file =
|
||||
File.join(
|
||||
defined?(Rails) ? Rails.root : Dir.pwd,
|
||||
'config', 'couchdb.yml'
|
||||
)
|
||||
|
||||
app_name = defined?(Rails) ? Rails.application.class.to_s.underscore.gsub(/\/.*/, '') : 'couchrest'
|
||||
config.connection = {
|
||||
:protocol => 'http',
|
||||
:host => 'localhost',
|
||||
:port => '5984',
|
||||
:prefix => app_name,
|
||||
:suffix => nil,
|
||||
:username => nil,
|
||||
:password => nil
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
74
lib/couchrest/model/connection.rb
Normal file
74
lib/couchrest/model/connection.rb
Normal file
|
@ -0,0 +1,74 @@
|
|||
module CouchRest
|
||||
module Model
|
||||
module Connection
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def database
|
||||
self.class.database
|
||||
end
|
||||
|
||||
def server
|
||||
self.class.server
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
# Overwrite the normal use_database method so that a database
|
||||
# name can be provided instead of a full connection.
|
||||
def use_database(db)
|
||||
@_database_name = db
|
||||
end
|
||||
|
||||
# Replace CouchRest's database reader with a more advanced
|
||||
# version that will make a best guess at the database you might
|
||||
# want to use. Allows for a string to be provided instead of
|
||||
# a database object.
|
||||
def database
|
||||
@database ||= prepare_database(@_database_name)
|
||||
end
|
||||
|
||||
def server
|
||||
@server ||= CouchRest::Server.new(prepare_server_uri)
|
||||
end
|
||||
|
||||
def prepare_database(db = nil)
|
||||
unless db.is_a?(CouchRest::Database)
|
||||
conf = connection_configuration
|
||||
db = [conf[:prefix], db.to_s, conf[:suffix]].compact.join('_')
|
||||
self.server.database!(db)
|
||||
else
|
||||
db
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def prepare_server_uri
|
||||
conf = connection_configuration
|
||||
userinfo = [conf[:username], conf[:password]].compact.join(':')
|
||||
userinfo += '@' unless userinfo.empty?
|
||||
"#{conf[:protocol]}://#{userinfo}#{conf[:host]}:#{conf[:port]}"
|
||||
end
|
||||
|
||||
def connection_configuration
|
||||
@server_configuration ||=
|
||||
self.connection.update(
|
||||
(load_connection_config_file[environment] || {}).symbolize_keys
|
||||
)
|
||||
end
|
||||
|
||||
def load_connection_config_file
|
||||
connection_config_cache[connection_config_file] ||=
|
||||
File.exists?(connection_config_file) ?
|
||||
YAML::load(ERB.new(IO.read(connection_config_file)).result) :
|
||||
{ }
|
||||
end
|
||||
|
||||
def connection_config_cache
|
||||
Thread.current[:connection_config_cache] ||= {}
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -89,10 +89,6 @@ module CouchRest
|
|||
self
|
||||
end
|
||||
|
||||
def database
|
||||
self.class.database(@database)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def perform_validations(options = {})
|
||||
|
@ -108,20 +104,6 @@ module CouchRest
|
|||
|
||||
module ClassMethods
|
||||
|
||||
# Replace CouchRest's database reader with a more advanced
|
||||
# version that will make a best guess at the database you might
|
||||
# want to use. Allows for a string to be provided instead of
|
||||
# a database object.
|
||||
def database(db = nil)
|
||||
db ||= @database
|
||||
if db.nil?
|
||||
# try to grab from configuration files
|
||||
|
||||
else
|
||||
db
|
||||
end
|
||||
end
|
||||
|
||||
# Creates a new instance, bypassing attribute protection
|
||||
#
|
||||
# ==== Returns
|
||||
|
|
|
@ -4,8 +4,14 @@ module CouchRest
|
|||
module Proxyable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def proxy_database
|
||||
raise StandardError, "Please set the #proxy_database_method" if self.class.proxy_database_method.nil?
|
||||
@proxy_database ||= self.class.prepare_database(self.send(self.class.proxy_database_method))
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
||||
|
||||
# Define a collection that will use the base model for the database connection
|
||||
# details.
|
||||
def proxy_for(assoc_name, options = {})
|
||||
|
@ -13,19 +19,19 @@ module CouchRest
|
|||
options[:class_name] ||= assoc_name.to_s.singularize.camelize
|
||||
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
||||
def #{assoc_name}
|
||||
unless respond_to?('#{db_method}')
|
||||
raise "Missing ##{db_method} method for proxy"
|
||||
end
|
||||
@#{assoc_name} ||= CouchRest::Model::Proxyable::ModelProxy.new(::#{options[:class_name]}, self, self.class.to_s.underscore, #{db_method})
|
||||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
# Tell this model which other model to use a base for the database
|
||||
# connection to use.
|
||||
def proxied_by(model_name, options = {})
|
||||
raise "Model can only be proxied once or ##{model_name} already defined" if method_defined?(model_name) || !proxy_owner_method.nil?
|
||||
self.proxy_owner_method = model_name
|
||||
attr_accessor :model_proxy
|
||||
attr_accessor model_name
|
||||
overwrite_database_reader(model_name)
|
||||
end
|
||||
|
||||
# Define an a class variable accessor ready to be inherited and unique
|
||||
|
@ -34,6 +40,24 @@ module CouchRest
|
|||
def proxy_owner_method=(name); @proxy_owner_method = name; end
|
||||
def proxy_owner_method; @proxy_owner_method; end
|
||||
|
||||
# Define the name of a method to call to determine the name of
|
||||
# the database to use as a proxy.
|
||||
def proxy_database_method=(name); @proxy_database_method = name; end
|
||||
def proxy_database_method; @proxy_database_method; end
|
||||
|
||||
private
|
||||
|
||||
# Ensure that the model can no longer be used for normal requests
|
||||
# be overwriting the database reader method so that a helpful
|
||||
# error message is displayed.
|
||||
def overwrite_database_reader(model_name)
|
||||
class_eval <<-EOS, __FILE__, __LINE__ + 1
|
||||
def database
|
||||
raise StandardError, "#{self.to_s} documents must be accessed via the '#{model_name}' proxy"
|
||||
end
|
||||
EOS
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class ModelProxy
|
||||
|
|
|
@ -46,6 +46,7 @@ require "couchrest/model/proxyable"
|
|||
require "couchrest/model/collection"
|
||||
require "couchrest/model/associations"
|
||||
require "couchrest/model/configuration"
|
||||
require "couchrest/model/connection"
|
||||
require "couchrest/model/designs"
|
||||
require "couchrest/model/designs/view"
|
||||
|
||||
|
@ -61,4 +62,6 @@ require "couchrest/model/casted_model"
|
|||
require "couchrest/model/base"
|
||||
# Add rails support *after* everything has loaded
|
||||
|
||||
require "couchrest/railtie"
|
||||
if defined?(Rails)
|
||||
require "couchrest/railtie"
|
||||
end
|
||||
|
|
|
@ -56,10 +56,52 @@ describe CouchRest::Model::Base do
|
|||
end
|
||||
end
|
||||
|
||||
describe "default configuration" do
|
||||
|
||||
it "should provide environment" do
|
||||
@class.environment.should eql(:development)
|
||||
end
|
||||
it "should provide connection config file" do
|
||||
@class.connection_config_file.should eql(File.join(Dir.pwd, 'config', 'couchdb.yml'))
|
||||
end
|
||||
it "should provided simple connection details" do
|
||||
@class.connection[:prefix].should eql('couchrest')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "default configuration with Rails" do
|
||||
before do
|
||||
Rails = mock('Rails') unless defined?(Rails)
|
||||
Rails.stub!(:env).and_return(:dev)
|
||||
Rails.stub!(:root).and_return("/rails/root")
|
||||
app = mock('Application')
|
||||
app.stub!(:class).and_return("SampleCouch::Application")
|
||||
Rails.stub!(:application).and_return(app)
|
||||
|
||||
# New anon class!
|
||||
@class = Class.new()
|
||||
@class.class_eval do
|
||||
include CouchRest::Model::Configuration
|
||||
end
|
||||
end
|
||||
|
||||
it "should provide environment" do
|
||||
@class.environment.should eql(:dev)
|
||||
end
|
||||
it "should provide connection config file" do
|
||||
@class.connection_config_file.should eql(File.join("/rails/root", 'config', 'couchdb.yml'))
|
||||
end
|
||||
it "should provided simple connection details" do
|
||||
@class.connection[:prefix].should eql('sample_couch')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "General examples" do
|
||||
|
||||
before(:all) do
|
||||
@default_model_key = 'model'
|
||||
@default_model_key = 'model-type'
|
||||
end
|
||||
|
||||
|
||||
|
|
117
spec/couchrest/connection_spec.rb
Normal file
117
spec/couchrest/connection_spec.rb
Normal file
|
@ -0,0 +1,117 @@
|
|||
# encoding: utf-8
|
||||
require File.expand_path('../../spec_helper', __FILE__)
|
||||
|
||||
describe CouchRest::Model::Base do
|
||||
|
||||
before do
|
||||
@class = Class.new(CouchRest::Model::Base)
|
||||
end
|
||||
|
||||
describe "instance methods" do
|
||||
before :each do
|
||||
@obj = @class.new
|
||||
end
|
||||
|
||||
describe "#database" do
|
||||
it "should respond to" do
|
||||
@obj.should respond_to(:database)
|
||||
end
|
||||
it "should provided class's database" do
|
||||
@obj.class.should_receive :database
|
||||
@obj.database
|
||||
end
|
||||
end
|
||||
|
||||
describe "#server" do
|
||||
it "should respond to method" do
|
||||
@obj.should respond_to(:server)
|
||||
end
|
||||
it "should return class's server" do
|
||||
@obj.class.should_receive :server
|
||||
@obj.server
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "class methods" do
|
||||
|
||||
describe ".use_database" do
|
||||
it "should respond to" do
|
||||
@class.should respond_to(:use_database)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".database" do
|
||||
it "should respond to" do
|
||||
@class.should respond_to(:database)
|
||||
end
|
||||
it "should provide a database object" do
|
||||
@class.database.should be_a(CouchRest::Database)
|
||||
end
|
||||
it "should provide a database with default name" do
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe ".server" do
|
||||
it "should respond to" do
|
||||
@class.should respond_to(:server)
|
||||
end
|
||||
it "should provide a server object" do
|
||||
@class.server.should be_a(CouchRest::Server)
|
||||
end
|
||||
it "should provide a server with default config" do
|
||||
@class.server.uri.should eql("http://localhost:5984")
|
||||
end
|
||||
it "should allow the configuration to be overwritten" do
|
||||
@class.connection = {
|
||||
:protocol => "https",
|
||||
:host => "127.0.0.1",
|
||||
:port => '5985',
|
||||
:prefix => 'sample',
|
||||
:suffix => 'test',
|
||||
:username => 'foo',
|
||||
:password => 'bar'
|
||||
}
|
||||
@class.server.uri.should eql("https://foo:bar@127.0.0.1:5985")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe ".prepare_database" do
|
||||
|
||||
it "should respond to" do
|
||||
@class.should respond_to(:prepare_database)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "protected methods" do
|
||||
|
||||
describe ".connection_configuration" do
|
||||
it "should provide main config by default" do
|
||||
@class.send(:connection_configuration).should eql(@class.connection)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".load_connection_config_file" do
|
||||
it "should provide an empty hash if config not found" do
|
||||
@class.send(:load_connection_config_file).should eql({})
|
||||
end
|
||||
it "should load file if available" do
|
||||
@class.connection_config_file = File.join(FIXTURE_PATH, 'config', 'couchdb.yml')
|
||||
puts @class.send(:connection_config_cache).inspect
|
||||
hash = @class.send(:load_connection_config_file)
|
||||
hash[:development].should_not be_nil
|
||||
@class.server.uri.should eql("https://test:uesr@sample.cloudant.com:443")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
10
spec/fixtures/config/couchdb.yml
vendored
Normal file
10
spec/fixtures/config/couchdb.yml
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
development:
|
||||
protocol: 'https'
|
||||
host: sample.cloudant.com
|
||||
port: 443
|
||||
prefix: project
|
||||
suffix: text
|
||||
username: test
|
||||
password: user
|
||||
|
Loading…
Reference in a new issue