methodmissing-mysqlplus_adapter 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +97 -0
- data/VERSION.yml +4 -0
- data/lib/active_record/connection_adapters/mysqlplus_adapter.rb +112 -0
- data/lib/active_record/connection_adapters/mysqlplus_adapter/connection_pool.rb +40 -0
- data/lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/macro.rb +99 -0
- data/lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/result.rb +46 -0
- data/test/connections/mysqlplus/connection.rb +30 -0
- data/test/deferrable_test.rb +15 -0
- data/test/helper.rb +90 -0
- data/test/models/mysql_user.rb +3 -0
- metadata +70 -0
data/README.textile
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
h1. Mysqlplus ActiveRecord Adapter
|
2
|
+
|
3
|
+
h2. Installation
|
4
|
+
|
5
|
+
Grab mysqlplus ....
|
6
|
+
|
7
|
+
git clone git://github.com/oldmoe/mysqlplus.git
|
8
|
+
cd mysqlplus
|
9
|
+
rake
|
10
|
+
|
11
|
+
... and mysqlplus_adapter ...
|
12
|
+
|
13
|
+
sudo gem install methodmissing-mysqlplus_adapter -s http://gems.github.com
|
14
|
+
|
15
|
+
... then update config/database.yml
|
16
|
+
|
17
|
+
production:
|
18
|
+
adapter: mysqlplus
|
19
|
+
database: myapp_production
|
20
|
+
username: root
|
21
|
+
password:
|
22
|
+
host: localhost
|
23
|
+
pool: 10
|
24
|
+
|
25
|
+
h2. Why Bother ?
|
26
|
+
|
27
|
+
The mysqlplus gem ( a fork of mysql-2.8.4pre ) exposes an asynchronous API that lends itself very well to decoupling the stock Mysql protocol into full duplex in a multi-threaded environment.
|
28
|
+
|
29
|
+
The ever popular "mysql ruby":http://www.tmtm.org/en/mysql/ruby/ do *not* schedule Threads and thus lock the whole MRI interpreter for any database I/O from within a given process.
|
30
|
+
|
31
|
+
Rails since release 2.2 support connection pooling and Thread safety ( at the framework level mind you, plugins, gems and user code aside ) through :
|
32
|
+
|
33
|
+
config.threadsafe!
|
34
|
+
|
35
|
+
This configuration hook removes the global Dispatcher lock and yields one connection from the pool per request / response cycle.
|
36
|
+
|
37
|
+
You'll need mysqplus and this adapter to get around the MRI lock with mysql ruby.
|
38
|
+
|
39
|
+
h2. Configuration Options
|
40
|
+
|
41
|
+
An additional connection specification element, *warmup* is available that attempts to establish the pooled connections in advance.This may be useful for high traffic environments where it makes sense to setup connections when bouncing the App and not let initial incoming requests be hogged with Mysql connection overheads.
|
42
|
+
|
43
|
+
production:
|
44
|
+
adapter: mysqlplus
|
45
|
+
database: myapp_production
|
46
|
+
username: root
|
47
|
+
password:
|
48
|
+
host: localhost
|
49
|
+
pool: 10
|
50
|
+
warmup: true
|
51
|
+
|
52
|
+
h3. Deferrable Results
|
53
|
+
|
54
|
+
Deferred results simulate lazy loading in a background Thread, through another Mysql connection, other than the one the current Thread has acquired.This type of workflow assumes a decent Connection Pool size of 5 to 10 connections.
|
55
|
+
|
56
|
+
# Immediate yield control back to the current Thread as the query is pushed to the background.
|
57
|
+
# Yields an instance of ActiveRecord::Deferrable::Result
|
58
|
+
#
|
59
|
+
Post.find( :first, :defer => true )
|
60
|
+
|
61
|
+
A deferred result blocks when any method's invoked on the result set right away.
|
62
|
+
|
63
|
+
Post.find( :first, :defer => true ).title
|
64
|
+
|
65
|
+
This concept is quite useful in an MVC context, allowing the controller to fetch results, defer fetching them to the background and reference them in the view, allowing an undefined period / time slice during which rendering, template setup etc. may occur.
|
66
|
+
|
67
|
+
class PostsController
|
68
|
+
|
69
|
+
def index
|
70
|
+
# No blocking, executes in the background, yields a deferrable result.
|
71
|
+
#
|
72
|
+
@posts = Posts.published.find(:all, :defer => true )
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
Since ActiveRecord 2.1 preloading favors multiple efficient queries to cumbersome and mostly slow JOINs.Those secondary queries can easily be pushed down different connections.
|
78
|
+
|
79
|
+
# Use 3 connections from the pool : 1 x Post, 1 x Comment and 1 x Vote
|
80
|
+
#
|
81
|
+
Post.find(:all, :limit => 10, :include => [:comments, :votes], :defer => true )
|
82
|
+
|
83
|
+
h2. Garbage Collection
|
84
|
+
|
85
|
+
There's some experimental GC patches "available":http://github.com/oldmoe/mysqlplus/tree/with_async_validation - the mysql ruby gem forces GC every 20 queries, that's a guaranteed GC cycle every 5th request for a request with a 4 query overhead.
|
86
|
+
|
87
|
+
h2. Stability
|
88
|
+
|
89
|
+
In (pre)-production use at a handful of sites and the test suite is designed to run against the existing ActiveRecord suite.
|
90
|
+
|
91
|
+
h2. TODO
|
92
|
+
|
93
|
+
* Experiment with turning off query_with_result for certain queries.
|
94
|
+
|
95
|
+
* Deferred inserts / updates - *dangerous* INSERT DELAYED for Innodb
|
96
|
+
|
97
|
+
* 1.9 compatibility testing
|
data/VERSION.yml
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
begin
|
2
|
+
require_library_or_gem('mysqlplus')
|
3
|
+
rescue LoadError
|
4
|
+
$stderr.puts <<-EOS
|
5
|
+
The mysqlplus gem is required!
|
6
|
+
'git clone git@github.com:oldmoe/mysqlplus.git && cd mysqlplus && rake'
|
7
|
+
There's some experimental GC patches available @ http://github.com/oldmoe/mysqlplus/tree/with_async_validation - the mysql gem forces GC every 20 queries, that's a guaranteed GC cycle every 5th request for a request with a 4 query overhead.
|
8
|
+
EOS
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
|
12
|
+
begin
|
13
|
+
require_library_or_gem('fastthread')
|
14
|
+
rescue => LoadError
|
15
|
+
$stderr.puts "'gem install fastthread' for better performance"
|
16
|
+
end
|
17
|
+
|
18
|
+
[ "mysqlplus_adapter/connection_pool",
|
19
|
+
"mysql_adapter",
|
20
|
+
"mysqlplus_adapter/deferrable/result",
|
21
|
+
"mysqlplus_adapter/deferrable/macro" ].each{|l| require "active_record/connection_adapters/#{l}" }
|
22
|
+
|
23
|
+
module ActiveRecord
|
24
|
+
module ConnectionAdapters
|
25
|
+
class MysqlplusAdapter < ActiveRecord::ConnectionAdapters::MysqlAdapter
|
26
|
+
|
27
|
+
DEFERRABLE_SQL = /^(INSERT|UPDATE|ALTER|DROP|SELECT|DELETE|RENAME|REPLACE|TRUNCATE)/i.freeze
|
28
|
+
|
29
|
+
# Accessor for the raw connection socket for integration with EventMachine etc.
|
30
|
+
#
|
31
|
+
def socket
|
32
|
+
@connection.socket
|
33
|
+
end
|
34
|
+
|
35
|
+
def execute(sql, name = nil, skip_logging = false) #:nodoc:
|
36
|
+
if skip_logging
|
37
|
+
@connection.c_async_query( sql )
|
38
|
+
else
|
39
|
+
log("(Socket #{socket.to_s}) #{sql}",name) do
|
40
|
+
@connection.c_async_query( sql )
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Determine if a given SQL snippet is deferrable to another Thread.
|
46
|
+
#
|
47
|
+
def deferrable?( sql )
|
48
|
+
!open_transactions? &&
|
49
|
+
initialized? &&
|
50
|
+
deferrable_sql?( sql )
|
51
|
+
end
|
52
|
+
|
53
|
+
# Determine if the raw SQL can be deferred.This excludes changing users,
|
54
|
+
# retrieving column information, per connection configuration etc.
|
55
|
+
#
|
56
|
+
def deferrable_sql?( sql )
|
57
|
+
sql =~ DEFERRABLE_SQL
|
58
|
+
end
|
59
|
+
|
60
|
+
# Only support deferring connections once the framework has been initialized.
|
61
|
+
#
|
62
|
+
def initialized?
|
63
|
+
Object.const_defined?( 'Rails' ) && ::Rails.initialized?
|
64
|
+
end
|
65
|
+
|
66
|
+
# Are there any open transactions ?
|
67
|
+
#
|
68
|
+
def open_transactions?
|
69
|
+
open_transactions != 0
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def configure_connection #:nodoc:
|
75
|
+
super
|
76
|
+
@connection.disable_gc = true if disable_gc?
|
77
|
+
end
|
78
|
+
|
79
|
+
# See http://github.com/oldmoe/mysqlplus/tree/with_async_validation
|
80
|
+
def disable_gc? #:nodoc:
|
81
|
+
@connection.respond_to?( :disable_gc= )
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module ActiveRecord
|
89
|
+
class << Base
|
90
|
+
|
91
|
+
def mysqlplus_connection(config)
|
92
|
+
config = config.symbolize_keys
|
93
|
+
host = config[:host]
|
94
|
+
port = config[:port]
|
95
|
+
socket = config[:socket]
|
96
|
+
username = config[:username] ? config[:username].to_s : 'root'
|
97
|
+
password = config[:password].to_s
|
98
|
+
|
99
|
+
if config.has_key?(:database)
|
100
|
+
database = config[:database]
|
101
|
+
else
|
102
|
+
raise ArgumentError, "No database specified. Missing argument: database."
|
103
|
+
end
|
104
|
+
|
105
|
+
mysql = Mysql.init
|
106
|
+
mysql.ssl_set(config[:sslkey], config[:sslcert], config[:sslca], config[:sslcapath], config[:sslcipher]) if config[:sslca] || config[:sslkey]
|
107
|
+
|
108
|
+
ConnectionAdapters::MysqlplusAdapter.new(mysql, logger, [host, username, password, database, port, socket], config)
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
class ConnectionPool
|
4
|
+
|
5
|
+
attr_reader :connections,
|
6
|
+
:checked_out,
|
7
|
+
:reserved_connections
|
8
|
+
|
9
|
+
def initialize(spec)
|
10
|
+
@spec = spec
|
11
|
+
# The cache of reserved connections mapped to threads
|
12
|
+
@reserved_connections = {}
|
13
|
+
# The mutex used to synchronize pool access
|
14
|
+
@connection_mutex = Monitor.new
|
15
|
+
@queue = @connection_mutex.new_cond
|
16
|
+
# default 5 second timeout
|
17
|
+
@timeout = spec.config[:wait_timeout] || 5
|
18
|
+
# default max pool size to 5
|
19
|
+
@size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
|
20
|
+
@connections = []
|
21
|
+
@checked_out = []
|
22
|
+
# warmup hook
|
23
|
+
warmup! if spec.config[:warmup]
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Establish ( warmup ) all connections for this pool in advance.
|
29
|
+
#
|
30
|
+
def warmup!
|
31
|
+
@connection_mutex.synchronize do
|
32
|
+
1.upto(@size) do
|
33
|
+
@connections << new_connection
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Deferrable
|
3
|
+
module Macro
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def install!
|
8
|
+
ActiveRecord::Base.send :extend, SingletonMethods
|
9
|
+
ar_eigenclass::VALID_FIND_OPTIONS << :defer
|
10
|
+
alias_deferred :find, :find_by_sql, :preload_associations
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def ar_eigenclass #:nodoc:
|
16
|
+
@@ar_eigneclass ||= (class << ActiveRecord::Base; self; end)
|
17
|
+
end
|
18
|
+
|
19
|
+
def alias_deferred( *method_signatures ) #:nodoc:
|
20
|
+
method_signatures.each do |method_signature|
|
21
|
+
ar_eigenclass.alias_method_chain method_signature, :defer
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
module SingletonMethods
|
30
|
+
|
31
|
+
# !! EXPERIMENTAL !!
|
32
|
+
# Since ActiveRecord 2.1, multiple lightweight queries is preferred to expensive
|
33
|
+
# JOINS when eager loading related models.In some use cases it's more performant
|
34
|
+
# to distribute those over multiple connections versus dispatching them on the same
|
35
|
+
# connection.
|
36
|
+
#
|
37
|
+
# ....
|
38
|
+
# Record.find(:first, :include => [:other. :another], :defer => true)
|
39
|
+
# ....
|
40
|
+
#
|
41
|
+
def preload_associations_with_defer(records, associations, preload_options={})
|
42
|
+
if preload_options.key?(:defer)
|
43
|
+
ActiveRecord::Deferrable::Result.new do
|
44
|
+
preload_associations_without_defer(records, associations, preload_options)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
preload_associations_without_defer(records, associations, preload_options)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Execute raw SQL in another Thread.Blocks only when the result is immediately
|
52
|
+
# referenced.
|
53
|
+
# ...
|
54
|
+
# Record.find_by_sql( "SELECT SLEEP (1)", true )
|
55
|
+
# ...
|
56
|
+
#
|
57
|
+
def find_by_sql_with_defer( sql, defer = false )
|
58
|
+
if defer
|
59
|
+
ActiveRecord::Deferrable::Result.new do
|
60
|
+
find_by_sql_without_defer( sql )
|
61
|
+
end
|
62
|
+
else
|
63
|
+
find_by_sql_without_defer( sql )
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Executes a query in another background Thread.Blocks only when the result is
|
68
|
+
# immediately referenced.
|
69
|
+
# ...
|
70
|
+
# Record.find( :first, :conditions => ['records.some_id >= ?', 100], :defer => true )
|
71
|
+
# ...
|
72
|
+
#
|
73
|
+
def find_with_defer( *args )
|
74
|
+
options = args.dup.extract_options!
|
75
|
+
if options.key?(:defer)
|
76
|
+
with_deferred_scope do
|
77
|
+
ActiveRecord::Deferrable::Result.new do
|
78
|
+
find_without_defer(*args)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
else
|
82
|
+
find_without_defer(*args)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# Deferred finder scope
|
89
|
+
#
|
90
|
+
def with_deferred_scope( &block ) #:nodoc:
|
91
|
+
with_scope( { :find => { :defer => true } }, :merge, &block )
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
ActiveRecord::Deferrable::Macro.install!
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module Deferrable
|
3
|
+
class Result < ActiveSupport::BasicObject
|
4
|
+
|
5
|
+
# Represents a Lazy Loaded resultset.
|
6
|
+
# Any method calls would block if the result hasn't yet been processed in a background
|
7
|
+
# Thread.
|
8
|
+
#
|
9
|
+
def initialize( &deferrable )
|
10
|
+
defer!( deferrable )
|
11
|
+
end
|
12
|
+
|
13
|
+
# Calls a given procedure in a background Thread, on another
|
14
|
+
# connection from the pool.Guarantees that said connection is checked
|
15
|
+
# back in on completion.
|
16
|
+
#
|
17
|
+
def defer!( deferrable )
|
18
|
+
@result = Thread.new( deferrable ) do |deferrable|
|
19
|
+
begin
|
20
|
+
deferrable.call
|
21
|
+
rescue => exception
|
22
|
+
exception
|
23
|
+
ensure
|
24
|
+
::ActiveRecord::Base.connection_pool.release_connection
|
25
|
+
end
|
26
|
+
end
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# Delegates to the background Thread.
|
31
|
+
#
|
32
|
+
def method_missing(*args, &block)
|
33
|
+
@_result ||= @result.value
|
34
|
+
validate!
|
35
|
+
@_result.send(*args, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Re-raise any Exceptions from the background Thread.
|
39
|
+
#
|
40
|
+
def validate!
|
41
|
+
raise @_result if @_result.is_a?( Exception )
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
print "Using mysqplus\n"
|
2
|
+
require "#{File.dirname(__FILE__)}/../../helper"
|
3
|
+
require_dependency "#{AR_TEST_SUITE}/models/course"
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
ActiveRecord::Base.logger = Logger.new(StringIO.new)
|
7
|
+
|
8
|
+
# GRANT ALL PRIVILEGES ON activerecord_unittest.* to 'rails'@'localhost';
|
9
|
+
# GRANT ALL PRIVILEGES ON activerecord_unittest2.* to 'rails'@'localhost';
|
10
|
+
|
11
|
+
ActiveRecord::Base.configurations = {
|
12
|
+
'arunit' => {
|
13
|
+
:adapter => 'mysqlplus',
|
14
|
+
:username => 'rails',
|
15
|
+
:encoding => 'utf8',
|
16
|
+
:database => 'activerecord_unittest',
|
17
|
+
:pool => 5,
|
18
|
+
:warmup => false
|
19
|
+
},
|
20
|
+
'arunit2' => {
|
21
|
+
:adapter => 'mysqlplus',
|
22
|
+
:username => 'rails',
|
23
|
+
:database => 'activerecord_unittest2',
|
24
|
+
:pool => 5,
|
25
|
+
:warmup => false
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
ActiveRecord::Base.establish_connection 'arunit'
|
30
|
+
Course.establish_connection 'arunit2'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/helper"
|
2
|
+
Mysqlplus::Test.prepare!
|
3
|
+
|
4
|
+
class DeferrableTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_should_be_able_to_find_records_in_a_background_thread
|
7
|
+
assert_equal MysqlUser.find(:first, :defer => true), MysqlUser.find(:first)
|
8
|
+
assert_instance_of MysqlUser, MysqlUser.find(:first, :defer => true)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_should_be_able_to_find_records_by_sql_background_thread
|
12
|
+
assert_equal MysqlUser.find_by_sql("SELECT * FROM mysql.user WHERE User = 'root'", true), MysqlUser.find(:all, :conditions => ['user.User = ?', 'root'])
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support'
|
3
|
+
require 'activerecord'
|
4
|
+
ActiveRecord.load_all!
|
5
|
+
|
6
|
+
module Mysqlplus
|
7
|
+
class Test
|
8
|
+
|
9
|
+
MODELS_DIR = "#{File.dirname(__FILE__)}/models".freeze
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
def prepare!
|
14
|
+
require 'test/unit'
|
15
|
+
connect!
|
16
|
+
require_models()
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup!
|
20
|
+
setup_constants!
|
21
|
+
setup_config!
|
22
|
+
end
|
23
|
+
|
24
|
+
def mysqlplus_connection
|
25
|
+
"#{File.dirname(__FILE__)}/connections/mysqlplus"
|
26
|
+
end
|
27
|
+
|
28
|
+
def active_record_test_files
|
29
|
+
returning([]) do |files|
|
30
|
+
files << glob( "#{AR_TEST_SUITE}/cases/**/*_test{,_mysqlplus}.rb" )
|
31
|
+
end.sort
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_files
|
35
|
+
glob( "#{File.dirname(__FILE__)}/*_test.rb" )
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def connect!
|
41
|
+
::ActiveRecord::Base.establish_connection( :adapter => 'mysqlplus',
|
42
|
+
:username => 'root',
|
43
|
+
:database => 'mysql',
|
44
|
+
:pool => 5,
|
45
|
+
:warmup => true )
|
46
|
+
end
|
47
|
+
|
48
|
+
def require_models
|
49
|
+
Dir.entries( MODELS_DIR ).grep(/.rb/).each do |model|
|
50
|
+
require_model( model )
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def require_model( model )
|
55
|
+
require "#{MODELS_DIR}/#{model}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def setup_constants!
|
59
|
+
set_constant( 'MYSQL_DB_USER' ){ 'rails' }
|
60
|
+
set_constant( 'AR_TEST_SUITE' ) do
|
61
|
+
ENV['AR_TEST_SUITE'] || find_active_record_test_suite()
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def setup_config!
|
66
|
+
unless Object.const_defined?( 'MIGRATIONS_ROOT' )
|
67
|
+
require "#{::AR_TEST_SUITE}/config"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def set_constant( constant )
|
72
|
+
Object.const_set(constant, yield ) unless Object.const_defined?( constant )
|
73
|
+
end
|
74
|
+
|
75
|
+
def find_active_record_test_suite
|
76
|
+
returning( ($:).grep( /activerecord/ ).last.split('/') ) do |ar_ts|
|
77
|
+
ar_ts.pop
|
78
|
+
ar_ts << 'test'
|
79
|
+
end.join('/')
|
80
|
+
end
|
81
|
+
|
82
|
+
def glob( pattern )
|
83
|
+
Dir.glob( pattern )
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Mysqlplus::Test.setup!
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: methodmissing-mysqlplus_adapter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Lourens Naud\xC3\xA9"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-07 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: ActiveRecord Mysqlplus Adapter
|
17
|
+
email: lourens@methodmissing.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README.textile
|
26
|
+
- VERSION.yml
|
27
|
+
- lib/active_record
|
28
|
+
- lib/active_record/connection_adapters
|
29
|
+
- lib/active_record/connection_adapters/mysqlplus_adapter
|
30
|
+
- lib/active_record/connection_adapters/mysqlplus_adapter/connection_pool.rb
|
31
|
+
- lib/active_record/connection_adapters/mysqlplus_adapter/deferrable
|
32
|
+
- lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/macro.rb
|
33
|
+
- lib/active_record/connection_adapters/mysqlplus_adapter/deferrable/result.rb
|
34
|
+
- lib/active_record/connection_adapters/mysqlplus_adapter.rb
|
35
|
+
- test/connections
|
36
|
+
- test/connections/mysqlplus
|
37
|
+
- test/connections/mysqlplus/connection.rb
|
38
|
+
- test/deferrable_test.rb
|
39
|
+
- test/helper.rb
|
40
|
+
- test/models
|
41
|
+
- test/models/mysql_user.rb
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/methodmissing/mysqplus_adapter
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options:
|
46
|
+
- --inline-source
|
47
|
+
- --charset=UTF-8
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: "0"
|
55
|
+
version:
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: "0"
|
61
|
+
version:
|
62
|
+
requirements: []
|
63
|
+
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.2.0
|
66
|
+
signing_key:
|
67
|
+
specification_version: 2
|
68
|
+
summary: ActiveRecord Mysqlplus Adapter
|
69
|
+
test_files: []
|
70
|
+
|