Skip to content
This repository has been archived by the owner on Jan 1, 2024. It is now read-only.

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
For #295
  • Loading branch information
phillbaker committed Sep 29, 2016
1 parent 9fed166 commit a71cb38
Show file tree
Hide file tree
Showing 16 changed files with 301 additions and 184 deletions.
1 change: 1 addition & 0 deletions lib/vanity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# @see Vanity::Configuration
# @see Vanity::Connection
module Vanity
class InvalidSpecification < StandardError; end
end

require "vanity/version"
Expand Down
3 changes: 2 additions & 1 deletion lib/vanity/adapters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ module Vanity
module Adapters
class << self
# Creates new connection to underlying datastore and returns suitable
# adapter (adapter object extends AbstractAdapter and wraps the
# adapter (adapter objects extend AbstractAdapter and wrap the
# connection).
#
# @since 1.4.0
# @deprecated
def establish_connection(spec)
begin
require "vanity/adapters/#{spec[:adapter]}_adapter"
Expand Down
17 changes: 17 additions & 0 deletions lib/vanity/adapters/abstract_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,29 @@ module Adapters
# Base class for all adapters. Adapters wrap underlying connection to a
# datastore and implement an API that Vanity can use to store/access
# metrics, experiments, etc.
#
# The `initialize` method of subclasses should accept a hash of connection
# parameters (the keys are guaranteed to be symbols). All dependencies
# should be `required` in the initialization method - allowing version
# checking at runtime.
class AbstractAdapter
# Returns true if connected.
def active?
false
end

# Hook for using an adapter that requires schema changes, useful when
# integrating into a framework that provides schema management, e.g.
# Rails' `db:migrate`.
def connect_on_schema_change?
false
end

# Open connection.
# @since 2.2.2
def connect!
end

# Close connection, release any resources.
def disconnect!
end
Expand Down
29 changes: 24 additions & 5 deletions lib/vanity/adapters/active_record_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module Vanity
module Adapters
class << self
# Creates new ActiveRecord connection and returns ActiveRecordAdapter.
# @deprecated
def active_record_connection(spec)
require "active_record"
ActiveRecordAdapter.new(spec)
Expand Down Expand Up @@ -102,23 +103,41 @@ def self.retrieve(experiment, identity, create = true, update_with = nil)
end

def initialize(options)
@options = options.inject({}) { |h,kv| h[kv.first.to_s] = kv.last ; h }
if @options["active_record_adapter"] && (@options["active_record_adapter"] != "default")
@options["adapter"] = @options["active_record_adapter"]
VanityRecord.establish_connection(@options)
require "active_record"
@options = options.clone
if @options[:active_record_adapter] && (@options[:active_record_adapter] != "default")
@options[:adapter] = @options.delete(:active_record_adapter)
else
@options.delete(:adapter)
@options.delete(:active_record_adapter)
end
end

def active?
VanityRecord.connected? && VanityRecord.connection.active?
end

# ActiveRecord adapter should connect when doing database migrations.
def connect_on_schema_change?
true
end

def connect!
if @options.empty?
# VanityRecord.connection.reconnect!
# do nothing, already connected
else
VanityRecord.establish_connection(@options)
end
end

def disconnect!
VanityRecord.connection.disconnect! if active?
end

def reconnect!
VanityRecord.connection.reconnect!
disconnect!
connect!
end

def flushdb
Expand Down
9 changes: 7 additions & 2 deletions lib/vanity/adapters/mock_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class << self
# Creates and returns new MockAdapter.
#
# @since 1.4.0
# @deprecated
def mock_connection(spec)
MockAdapter.new(spec)
end
Expand All @@ -15,14 +16,18 @@ def mock_connection(spec)
# @since 1.4.0
class MockAdapter < AbstractAdapter
def initialize(options)
@metrics = @@metrics ||= {}
@experiments = @@experiments ||= {}
# No-op
end

def active?
!!@metrics
end

def connect!
@metrics = @@metrics ||= {}
@experiments = @@experiments ||= {}
end

def disconnect!
@metrics = nil
@experiments = nil
Expand Down
3 changes: 2 additions & 1 deletion lib/vanity/adapters/mongodb_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class << self
# Creates new connection to MongoDB and returns MongoAdapter.
#
# @since 1.4.0
# @deprecated
def mongo_connection(spec)
require "mongo"
MongodbAdapter.new(spec)
Expand All @@ -18,9 +19,9 @@ class MongodbAdapter < AbstractAdapter
attr_reader :mongo

def initialize(options)
require "mongo"
@options = options.clone
@options[:database] ||= (@options[:path] && @options[:path].split("/")[1]) || "vanity"
connect!
end

def active?
Expand Down
18 changes: 16 additions & 2 deletions lib/vanity/adapters/redis_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class << self
# Creates new connection to Redis and returns RedisAdapter.
#
# @since 1.4.0
# @deprecated
def redis_connection(spec)
require "redis"
fail "redis >= 2.1 is required" unless valid_redis_version?
Expand All @@ -13,26 +14,39 @@ def redis_connection(spec)
RedisAdapter.new(spec)
end

# @deprecated
def valid_redis_version?
Gem.loaded_specs['redis'].version >= Gem::Version.create('2.1')
end

# @deprecated
def valid_redis_namespace_version?
Gem.loaded_specs['redis'].version >= Gem::Version.create('1.1.0')
Gem.loaded_specs['redis-namespace'].version >= Gem::Version.create('1.1.0')
end
end

# Redis adapter.
#
# @since 1.4.0
class RedisAdapter < AbstractAdapter
MINIMUM_REDIS_GEM = Gem::Version.create('2.1')
MINIMUM_REDIS_NAMESPACE_GEM = Gem::Version.create('1.1.0')

attr_reader :redis

def initialize(options)
require "redis"
require "redis/namespace"

valid_redis = Gem.loaded_specs['redis'].version >= MINIMUM_REDIS_GEM
valid_redis_namespace = Gem.loaded_specs['redis-namespace'].version >= MINIMUM_REDIS_NAMESPACE_GEM

fail "redis >= 2.1 is required" unless valid_redis
fail "redis-namespace >= 1.1.0 is required" unless valid_redis_namespace

@options = options.clone
@options[:db] ||= @options[:database] || (@options[:path] && @options.delete(:path).split("/")[1].to_i)
@options[:thread_safe] = true
connect!
end

def active?
Expand Down
40 changes: 29 additions & 11 deletions lib/vanity/connection.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
module Vanity
# @deprecated This class is a facade into one of the adapters in the
# Vanity::Adapters namspace, it will be merged into the top level
# Vanity.connect! helper and/or the adapters.
class Connection
class InvalidSpecification < StandardError; end

Expand Down Expand Up @@ -33,9 +36,8 @@ class InvalidSpecification < StandardError; end
def initialize(specification=nil)
@specification = specification || DEFAULT_SPECIFICATION

if Autoconnect.playground_should_autoconnect?
@adapter = setup_connection(@specification)
end
@adapter = adapter_from_specification(@specification)
connect!
end

# Closes the current connection.
Expand All @@ -45,6 +47,13 @@ def disconnect!
@adapter.disconnect! if connected?
end

# Creates a connection.
#
# @since 2.2.2
def connect!
@adapter && @adapter.connect!
end

# Returns true if connection is open.
#
# @since 2.0.0
Expand All @@ -54,27 +63,27 @@ def connected?

private

def setup_connection(spec)
def adapter_from_specification(spec)
case spec
when String
spec_hash = build_specification_hash_from_url(spec)
establish_connection(spec_hash)
spec_hash = specification_hash_from_url(spec)
initialize_adapter(spec_hash)
when Hash
validate_specification_hash(spec)
if spec[:redis]
establish_connection(
initialize_adapter(
adapter: :redis,
redis: spec[:redis]
)
else
establish_connection(spec)
initialize_adapter(spec)
end
else
raise InvalidSpecification.new("Unsupported connection specification: #{spec.inspect}")
end
end

def build_specification_hash_from_url(connection_url)
def specification_hash_from_url(connection_url)
uri = URI.parse(connection_url)
params = CGI.parse(uri.query) if uri.query
{
Expand All @@ -93,8 +102,17 @@ def validate_specification_hash(spec)
raise InvalidSpecification unless all_symbol_keys
end

def establish_connection(spec)
Adapters.establish_connection(spec)
def initialize_adapter(spec)
begin
require "vanity/adapters/#{spec[:adapter]}_adapter"
rescue LoadError
raise "Could not find #{spec[:adapter]} in your load path"
end

klass = spec[:adapter].to_s.split('_').collect(&:capitalize).join
# Get the class constant directly from the module instead of chaining
# the constant with `::` to avoid breaking on jruby in 1
Vanity::Adapters.const_get("#{klass}Adapter").new(spec)
end
end
end
3 changes: 2 additions & 1 deletion lib/vanity/frameworks/rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ def self.load!
# Do this at the very end of initialization, allowing you to change
# connection adapter, turn collection on/off, etc.
::Rails.configuration.after_initialize do
Vanity.load! if Vanity.connection.connected?
Vanity.connection # connect if necessary
Vanity.playground # load if necessary
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/vanity/playground.rb
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ def connection
# @deprecated
# @see Vanity.connection
def connected?
Vanity.connection.connected?
Vanity.connection && Vanity.connection.connected?
end

# @since 1.4.0
Expand Down
Loading

0 comments on commit a71cb38

Please sign in to comment.