schema_monkey 0.3.2 → 0.4.0
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.
- checksums.yaml +4 -4
- data/README.md +24 -14
- data/lib/schema_monkey/active_record/connection_adapters/abstract_adapter.rb +3 -4
- data/lib/schema_monkey/active_record/connection_adapters/{mysql_adapter.rb → mysql2_adapter.rb} +1 -1
- data/lib/schema_monkey/client.rb +61 -0
- data/lib/schema_monkey/module.rb +33 -0
- data/lib/schema_monkey/version.rb +1 -1
- data/lib/schema_monkey.rb +12 -50
- metadata +5 -4
- data/lib/schema_monkey/module_support.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2d6e7678f91c469b42eeac242d5095283edcaf4a
|
4
|
+
data.tar.gz: 11e38e5ba367ced242293615096012c752150cd3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1022cc53e764a97faca78bec36a612a5a1b69a13369ba74af3b19a93ece5cbe1dd80002bb50430360e2027b717b3082aefa6c66e2f6422d8936978884ae0ae15
|
7
|
+
data.tar.gz: ff13029ef2dd6a8ecf5084e8c16526ae1439ce14df10710914c21afb69abb4927bc6d5275c141e94434c0f631471d3432a820d872e1086bb6ad4fd7b0faf3f8f
|
data/README.md
CHANGED
@@ -3,38 +3,46 @@
|
|
3
3
|
[](https://coveralls.io/r/SchemaPlus/schema_monkey)
|
4
4
|
[](https://gemnasium.com/SchemaPlus/schema_monkey)
|
5
5
|
|
6
|
-
#
|
6
|
+
# SchemaMonkey
|
7
7
|
|
8
|
-
|
8
|
+
SchemaMonkey is a behind-the-scenes gem to facilitate writing other gems that extend ActiveRecord. It provides:
|
9
|
+
|
10
|
+
* A "middleware"-style interface to key ActiveRecord internal functions. For example, there's a middleware hook to let you insert a handler for migration column definition options, and there are several hooks to insert handlers for the various parts of a schema dump.
|
11
|
+
|
12
|
+
* A convention-based protocol for `include`'ing custom modules into ActiveRecord. You just define your modules and SchemaMonkey will automatically include them in the right places.
|
13
|
+
|
14
|
+
* It takes care of setting up the Railtie appropriately to invoke the gems.
|
15
|
+
|
16
|
+
The middleware interface has two benefits: it provides a clean API so that the client gems don't need to monkey-patch ActiveRecord (SchemaMonkey does all the monkey-patching for you), and it lets the client gems operate in parallel without concern about conflicting monkey-patches.
|
9
17
|
|
10
|
-
schema_monkey is part of the [SchemaPlus](https://github.com/SchemaPlus/) family of Ruby on Rails extension gems.
|
11
18
|
|
12
19
|
## Installation
|
13
20
|
|
14
|
-
In your
|
21
|
+
In your gem's `gemspec`, specify a dependency:
|
15
22
|
|
16
23
|
```ruby
|
17
|
-
|
24
|
+
spec.add_dependency "schema_monkey", "~> <MAJOR>.<MINOR>", ">= <MAJOR>.<MINOR>.<PATCH>"
|
18
25
|
```
|
26
|
+
|
27
|
+
SchemaMonkey follows semantic versioning; it's a good idea to explicitly use the `~>` and `>=` dependencies to make sure your gem's clients don't accidentally pull in a version of SchemaMonkey that your gem isn't compatible with.
|
28
|
+
|
19
29
|
## Compatibility
|
20
30
|
|
21
|
-
|
31
|
+
SchemaMonkey is tested on:
|
22
32
|
|
23
|
-
|
24
|
-
|
33
|
+
<!-- SCHEMA_DEV: MATRIX - begin -->
|
34
|
+
<!-- These lines are auto-generated by schema_dev based on schema_dev.yml -->
|
25
35
|
* ruby **1.9.3** with rails **4.2**, using **mysql2**, **sqlite3** or **postgresql**
|
26
36
|
* ruby **2.1.5** with rails **4.2**, using **mysql2**, **sqlite3** or **postgresql**
|
27
37
|
|
28
|
-
|
38
|
+
<!-- SCHEMA_DEV: MATRIX - end -->
|
29
39
|
|
30
40
|
## Usage
|
31
41
|
|
32
|
-
TODO: Write usage instructions here
|
33
42
|
|
43
|
+
**Sorry -- no real documentation yet. Will get to that as soon as I can.**
|
34
44
|
|
35
|
-
## History
|
36
45
|
|
37
|
-
* See [CHANGELOG](CHANGELOG.md) for per-version release notes.
|
38
46
|
|
39
47
|
## Development & Testing
|
40
48
|
|
@@ -43,7 +51,9 @@ the standard protocol: fork, feature branch, develop, push, and issue pull reque
|
|
43
51
|
|
44
52
|
Some things to know about to help you develop and test:
|
45
53
|
|
46
|
-
* **
|
54
|
+
* **Ugh -- no specs yet. SchemaMonkey is currently tested indirectly by testing the client gems that use it. That's another thing to get to as soon as I can.**
|
55
|
+
|
56
|
+
* **schema_dev**: SchemaMonkey uses [schema_dev](https://github.com/SchemaPlus/schema_dev) to
|
47
57
|
facilitate running rspec tests on the matrix of ruby, rails, and database
|
48
58
|
versions that the gem supports, both locally and on
|
49
59
|
[travis-ci](http://travis-ci.org/SchemaPlus/schema_monkey)
|
@@ -57,4 +67,4 @@ Some things to know about to help you develop and test:
|
|
57
67
|
[schema_dev](https://github.com/SchemaPlus/schema_dev) README.
|
58
68
|
|
59
69
|
The matrix of configurations is specified in `schema_dev.yml` in
|
60
|
-
the project root.
|
70
|
+
the project root.
|
@@ -11,12 +11,11 @@ module SchemaMonkey
|
|
11
11
|
|
12
12
|
dbm = case adapter_name
|
13
13
|
when /^MySQL/i then :Mysql
|
14
|
-
when 'PostgreSQL', 'PostGIS' then :
|
15
|
-
when 'SQLite' then :
|
14
|
+
when 'PostgreSQL', 'PostGIS' then :PostgreSQL
|
15
|
+
when 'SQLite' then :SQLite3
|
16
16
|
end
|
17
17
|
|
18
|
-
SchemaMonkey.
|
19
|
-
SchemaMonkey.insert_middleware(dbm)
|
18
|
+
SchemaMonkey.insert(dbm: dbm)
|
20
19
|
end
|
21
20
|
|
22
21
|
module SchemaCreation
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module SchemaMonkey
|
2
|
+
class Client
|
3
|
+
def initialize(mod)
|
4
|
+
@root = mod
|
5
|
+
@inserted = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def insert(opts={})
|
9
|
+
opts = opts.keyword_args(:dbm)
|
10
|
+
include_modules(dbm: opts.dbm)
|
11
|
+
insert_middleware(dbm: opts.dbm)
|
12
|
+
@root.insert() if @root.respond_to?(:insert) and @root != ::SchemaMonkey
|
13
|
+
end
|
14
|
+
|
15
|
+
def include_modules(opts={})
|
16
|
+
opts = opts.keyword_args(:dbm)
|
17
|
+
find_modules(:ActiveRecord, dbm: opts.dbm).each do |mod|
|
18
|
+
next if mod.is_a? Class
|
19
|
+
component = mod.to_s.sub(/^#{@root}::ActiveRecord::/, '')
|
20
|
+
component = component.gsub(/#{opts.dbm}/i, opts.dbm.to_s) if opts.dbm # canonicalize case
|
21
|
+
next unless base = Module.get_const(::ActiveRecord, component)
|
22
|
+
# Kernel.warn "including #{mod}"
|
23
|
+
Module.include_once base, mod
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def insert_middleware(opts={})
|
28
|
+
opts = opts.keyword_args(:dbm)
|
29
|
+
find_modules(:Middleware, dbm: opts.dbm, and_self: true).each do |mod|
|
30
|
+
next if @inserted[mod]
|
31
|
+
next unless mod.respond_to? :insert
|
32
|
+
# Kernel.warn "inserting #{mod}"
|
33
|
+
mod.insert
|
34
|
+
@inserted[mod] = true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def find_modules(container, opts={})
|
41
|
+
opts = opts.keyword_args(dbm: nil, and_self: nil)
|
42
|
+
return [] unless (container = Module.get_const(@root, container))
|
43
|
+
|
44
|
+
if opts.dbm
|
45
|
+
accept = /\b#{opts.dbm}/i
|
46
|
+
reject = nil
|
47
|
+
else
|
48
|
+
accept = nil
|
49
|
+
reject = /\b#{SchemaMonkey::DBMS.join('|')}/i
|
50
|
+
end
|
51
|
+
|
52
|
+
modules = []
|
53
|
+
modules << container if opts.and_self
|
54
|
+
modules += Module.descendants(container, can_load: accept)
|
55
|
+
modules.select!(&it.to_s =~ accept) if accept
|
56
|
+
modules.reject!(&it.to_s =~ reject) if reject
|
57
|
+
modules
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module SchemaMonkey
|
2
|
+
module Module
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def include_once(base, mod)
|
6
|
+
base.send(:include, mod) unless base.include? mod
|
7
|
+
end
|
8
|
+
|
9
|
+
# ruby 2.* supports mod.const_get("Component::Path") but ruby 1.9.3
|
10
|
+
# doesn't. And neither has an option to return nil rather than raising
|
11
|
+
# a NameError
|
12
|
+
def get_const(mod, name)
|
13
|
+
name.to_s.split('::').map(&:to_sym).each do |component|
|
14
|
+
begin
|
15
|
+
mod = mod.const_get(component, false)
|
16
|
+
rescue NameError
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
mod
|
21
|
+
end
|
22
|
+
|
23
|
+
def descendants(mod, opts={})
|
24
|
+
opts = opts.keyword_args(can_load: nil)
|
25
|
+
consts, auto = mod.constants.group_by{|c| !!mod.autoload?(c)}.values_at(false, true)
|
26
|
+
consts ||= []
|
27
|
+
consts += auto.select &it.to_s =~ opts.can_load if opts.can_load and auto
|
28
|
+
children = consts.map{|c| mod.const_get(c) }.select &it.is_a?(::Module)
|
29
|
+
children + children.flat_map {|c| descendants(c, can_load: opts.can_load) }
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/schema_monkey.rb
CHANGED
@@ -2,9 +2,11 @@ require 'hash_keyword_args'
|
|
2
2
|
require 'its-it'
|
3
3
|
require 'key_struct'
|
4
4
|
require 'middleware'
|
5
|
+
require 'active_support/core_ext/string'
|
5
6
|
|
7
|
+
require_relative "schema_monkey/client"
|
6
8
|
require_relative "schema_monkey/middleware"
|
7
|
-
require_relative "schema_monkey/
|
9
|
+
require_relative "schema_monkey/module"
|
8
10
|
require_relative "schema_monkey/active_record/base"
|
9
11
|
require_relative "schema_monkey/active_record/connection_adapters/abstract_adapter"
|
10
12
|
require_relative "schema_monkey/active_record/connection_adapters/table_definition"
|
@@ -14,69 +16,29 @@ require_relative 'schema_monkey/active_record/schema_dumper'
|
|
14
16
|
require_relative 'schema_monkey/railtie' if defined?(Rails::Railtie)
|
15
17
|
|
16
18
|
module SchemaMonkey
|
19
|
+
extend Module
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
DBMS = [:Postgresql, :Mysql, :Sqlite3]
|
21
|
+
DBMS = [:PostgreSQL, :Mysql, :SQLite3]
|
21
22
|
|
22
23
|
module ActiveRecord
|
23
24
|
module ConnectionAdapters
|
24
25
|
autoload :PostgresqlAdapter, 'schema_monkey/active_record/connection_adapters/postgresql_adapter'
|
25
|
-
autoload :
|
26
|
+
autoload :Mysql2Adapter, 'schema_monkey/active_record/connection_adapters/mysql2_adapter'
|
26
27
|
autoload :Sqlite3Adapter, 'schema_monkey/active_record/connection_adapters/sqlite3_adapter'
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
|
-
def self.insert
|
31
|
-
insert_modules
|
32
|
-
include_adapters(::ActiveRecord::ConnectionAdapters::AbstractAdapter, :Abstract)
|
33
|
-
insert_middleware
|
34
|
-
end
|
35
|
-
|
36
31
|
def self.register(mod)
|
37
|
-
|
32
|
+
clients << Client.new(mod)
|
38
33
|
end
|
39
34
|
|
40
|
-
def self.
|
41
|
-
@
|
35
|
+
def self.clients
|
36
|
+
@clients ||= [Client.new(self)]
|
42
37
|
end
|
43
38
|
|
44
|
-
def self.
|
45
|
-
|
46
|
-
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def self.insert_modules
|
51
|
-
registered_modules.each do |mod|
|
52
|
-
get_modules(mod, prefix: 'ActiveRecord', match: /\bActiveRecord\b/, recursive: true).each do |candidate|
|
53
|
-
next if candidate.is_a?(Class)
|
54
|
-
if (base = get_const(::ActiveRecord, candidate.to_s.sub(/^#{mod}::ActiveRecord::/, '')))
|
55
|
-
patch base, mod
|
56
|
-
end
|
57
|
-
end
|
58
|
-
mod.insert if mod.respond_to?(:insert) and mod != self
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.insert_middleware(dbm=nil)
|
63
|
-
@inserted ||= {}
|
64
|
-
|
65
|
-
if dbm
|
66
|
-
match = /\b#{dbm}\b/
|
67
|
-
reject = nil
|
68
|
-
else
|
69
|
-
match = nil
|
70
|
-
reject = /\b(#{DBMS.join('|')})\b/
|
71
|
-
end
|
72
|
-
|
73
|
-
registered_modules.each do |mod|
|
74
|
-
get_modules(mod, prefix: 'Middleware', and_self: true, match: match, reject: reject, recursive: true, respond_to: :insert).each do |middleware|
|
75
|
-
next if @inserted[middleware]
|
76
|
-
middleware.insert
|
77
|
-
@inserted[middleware] = true
|
78
|
-
end
|
79
|
-
end
|
39
|
+
def self.insert(opts={})
|
40
|
+
opts = opts.keyword_args(:dbm)
|
41
|
+
clients.each &it.insert(dbm: opts.dbm)
|
80
42
|
end
|
81
43
|
|
82
44
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: schema_monkey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ronen barzel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -186,15 +186,16 @@ files:
|
|
186
186
|
- lib/schema_monkey.rb
|
187
187
|
- lib/schema_monkey/active_record/base.rb
|
188
188
|
- lib/schema_monkey/active_record/connection_adapters/abstract_adapter.rb
|
189
|
-
- lib/schema_monkey/active_record/connection_adapters/
|
189
|
+
- lib/schema_monkey/active_record/connection_adapters/mysql2_adapter.rb
|
190
190
|
- lib/schema_monkey/active_record/connection_adapters/postgresql_adapter.rb
|
191
191
|
- lib/schema_monkey/active_record/connection_adapters/schema_statements.rb
|
192
192
|
- lib/schema_monkey/active_record/connection_adapters/sqlite3_adapter.rb
|
193
193
|
- lib/schema_monkey/active_record/connection_adapters/table_definition.rb
|
194
194
|
- lib/schema_monkey/active_record/migration/command_recorder.rb
|
195
195
|
- lib/schema_monkey/active_record/schema_dumper.rb
|
196
|
+
- lib/schema_monkey/client.rb
|
196
197
|
- lib/schema_monkey/middleware.rb
|
197
|
-
- lib/schema_monkey/
|
198
|
+
- lib/schema_monkey/module.rb
|
198
199
|
- lib/schema_monkey/railtie.rb
|
199
200
|
- lib/schema_monkey/version.rb
|
200
201
|
- schema_dev.yml
|
@@ -1,48 +0,0 @@
|
|
1
|
-
module SchemaMonkey
|
2
|
-
module ModuleSupport
|
3
|
-
|
4
|
-
def include_once(base, mod)
|
5
|
-
base.send(:include, mod) unless base.include? mod
|
6
|
-
end
|
7
|
-
|
8
|
-
def include_if_defined(base, parent, subname)
|
9
|
-
if submodule = get_const(parent, subname)
|
10
|
-
include_once(base, submodule)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def patch(base, parent = SchemaMonkey)
|
15
|
-
patch = get_const(parent, base)
|
16
|
-
raise "#{parent} does not contain a definition of #{base}" unless patch
|
17
|
-
include_once(base, patch)
|
18
|
-
end
|
19
|
-
|
20
|
-
# ruby 2.* supports mod.const_get("Component::Path") but ruby 1.9.3
|
21
|
-
# doesn't. And neither has a version that can return nil rather than
|
22
|
-
# raising a NameError
|
23
|
-
def get_const(mod, name)
|
24
|
-
name.to_s.split('::').map(&:to_sym).each do |component|
|
25
|
-
begin
|
26
|
-
mod = mod.const_get(component, false)
|
27
|
-
rescue NameError
|
28
|
-
return nil
|
29
|
-
end
|
30
|
-
end
|
31
|
-
mod
|
32
|
-
end
|
33
|
-
|
34
|
-
def get_modules(parent, opts={})
|
35
|
-
opts = opts.keyword_args(:prefix, :match, :reject, :recursive, :respond_to, :and_self)
|
36
|
-
parent = get_const(parent, opts.prefix) if opts.prefix
|
37
|
-
return [] unless parent && parent.is_a?(Module)
|
38
|
-
modules = []
|
39
|
-
modules << parent if opts.and_self
|
40
|
-
modules += parent.constants.reject{|c| parent.autoload? c}.map{|c| parent.const_get(c)}.select(&it.is_a?(Module))
|
41
|
-
modules.reject! &it.to_s =~ opts.reject if opts.reject
|
42
|
-
modules += modules.flat_map { |mod| get_modules(mod, reject: opts.reject, recursive: true) } if opts.recursive
|
43
|
-
modules.select! &it.to_s =~ opts.match if opts.match
|
44
|
-
modules.select! &it.respond_to?(opts.respond_to) if opts.respond_to
|
45
|
-
modules
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|