schema_monkey 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6d7581fe8672d2cf1ef4115bbfc10955a0a2e4c1
4
- data.tar.gz: 5d05d31605887dfcd26fb82f546b94adc73a8d9e
3
+ metadata.gz: 2d6e7678f91c469b42eeac242d5095283edcaf4a
4
+ data.tar.gz: 11e38e5ba367ced242293615096012c752150cd3
5
5
  SHA512:
6
- metadata.gz: 210fc83e5898dec122f9a20441e04a4386eaf5fd68dca7b0ff20d3c69641bee79363f945dd6bc247101468bc71a3be0df5dfcb6da89a4045383e2ab093014b6a
7
- data.tar.gz: f3ca1407f7c2f19cc329eb382ccab6279e5403b1016855f323cb8007a55058b73aa584957d23e8245c0196be4f49d22ebf39456effbc207c708b498d01ade76a
6
+ metadata.gz: 1022cc53e764a97faca78bec36a612a5a1b69a13369ba74af3b19a93ece5cbe1dd80002bb50430360e2027b717b3082aefa6c66e2f6422d8936978884ae0ae15
7
+ data.tar.gz: ff13029ef2dd6a8ecf5084e8c16526ae1439ce14df10710914c21afb69abb4927bc6d5275c141e94434c0f631471d3432a820d872e1086bb6ad4fd7b0faf3f8f
data/README.md CHANGED
@@ -3,38 +3,46 @@
3
3
  [![Coverage Status](https://img.shields.io/coveralls/SchemaPlus/schema_monkey.svg)](https://coveralls.io/r/SchemaPlus/schema_monkey)
4
4
  [![Dependency Status](https://gemnasium.com/lomba/schema_monkey.svg)](https://gemnasium.com/SchemaPlus/schema_monkey)
5
5
 
6
- # schema_monkey
6
+ # SchemaMonkey
7
7
 
8
- TODO: Write a gem description
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 application's Gemfile
21
+ In your gem's `gemspec`, specify a dependency:
15
22
 
16
23
  ```ruby
17
- gem "schema_monkey"
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
- schema_monkey is tested on
31
+ SchemaMonkey is tested on:
22
32
 
23
- [//]: # SCHEMA_DEV: MATRIX - begin
24
- [//]: # These lines are auto-generated by schema_dev based on schema_dev.yml
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
- [//]: # SCHEMA_DEV: MATRIX - end
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
- * **schema_dev**: schema_monkey uses [schema_dev](https://github.com/SchemaPlus/schema_dev) to
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 :Postgresql
15
- when 'SQLite' then :Sqlite3
14
+ when 'PostgreSQL', 'PostGIS' then :PostgreSQL
15
+ when 'SQLite' then :SQLite3
16
16
  end
17
17
 
18
- SchemaMonkey.include_adapters(self.class, dbm)
19
- SchemaMonkey.insert_middleware(dbm)
18
+ SchemaMonkey.insert(dbm: dbm)
20
19
  end
21
20
 
22
21
  module SchemaCreation
@@ -1,7 +1,7 @@
1
1
  module SchemaMonkey
2
2
  module ActiveRecord
3
3
  module ConnectionAdapters
4
- module MysqlAdapter
4
+ module Mysql2Adapter
5
5
 
6
6
  def self.included(base)
7
7
  base.class_eval do
@@ -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
@@ -1,3 +1,3 @@
1
1
  module SchemaMonkey
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.0"
3
3
  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/module_support"
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
- extend SchemaMonkey::ModuleSupport
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 :MysqlAdapter, 'schema_monkey/active_record/connection_adapters/mysql_adapter'
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
- registered_modules << mod
32
+ clients << Client.new(mod)
38
33
  end
39
34
 
40
- def self.registered_modules
41
- @registered_modules ||= [self]
35
+ def self.clients
36
+ @clients ||= [Client.new(self)]
42
37
  end
43
38
 
44
- def self.include_adapters(base, dbm)
45
- registered_modules.each do |mod|
46
- include_if_defined(base, mod, "ActiveRecord::ConnectionAdapters::#{dbm}Adapter")
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.3.2
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-26 00:00:00.000000000 Z
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/mysql_adapter.rb
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/module_support.rb
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