schema_monkey 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 72a64abeef5d3b9c5b59cfb54214e5158246b7c9
4
+ data.tar.gz: 9e8d840289ac07f0efeb97d3aef091ab1fbb5cde
5
+ SHA512:
6
+ metadata.gz: 0d52996ac73f76b495b88b6a4122eac06e4cf2b1088ee18d2654f97f492468ecc7fa8fb855cebe654ba4fee2a9ddf831dfa40e2242ccdb0b0fd8899c981abef5
7
+ data.tar.gz: 6994d391d237b4e322ec4808d11b1e734ae144df725f5b297f250a722efb8f3e9de2479843eaed54592432ed06b913e195d19d041838873352f59f37e7526c8e
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /coverage
2
+ /tmp
3
+ /pkg
4
+
5
+ *.lock
6
+ *.log
7
+ *.sqlite3
8
+ !gemfiles/**/*.sqlite3
data/.travis.yml ADDED
@@ -0,0 +1,19 @@
1
+ # This file was auto-generated by the schema_dev tool, based on the data in
2
+ # ./schema_dev.yml
3
+ # Please do not edit this file; any changes will be overwritten next time
4
+ # schema_dev gets run.
5
+ ---
6
+ sudo: false
7
+ rvm:
8
+ - 1.9.3
9
+ - 2.1.5
10
+ gemfile:
11
+ - gemfiles/rails-4.2/Gemfile.mysql2
12
+ - gemfiles/rails-4.2/Gemfile.postgresql
13
+ - gemfiles/rails-4.2/Gemfile.sqlite3
14
+ env: POSTGRESQL_DB_USER=postgres MYSQL_DB_USER=travis
15
+ addons:
16
+ postgresql: '9.3'
17
+ before_script: bundle exec rake create_databases
18
+ after_script: bundle exec rake drop_databases
19
+ script: bundle exec rake travis
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 ronen barzel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,60 @@
1
+ [![Gem Version](https://badge.fury.io/rb/schema_monkey.svg)](http://badge.fury.io/rb/schema_monkey)
2
+ [![Build Status](https://secure.travis-ci.org/SchemaPlus/schema_monkey.svg)](http://travis-ci.org/SchemaPlus/schema_monkey)
3
+ [![Coverage Status](https://img.shields.io/coveralls/SchemaPlus/schema_monkey.svg)](https://coveralls.io/r/SchemaPlus/schema_monkey)
4
+ [![Dependency Status](https://gemnasium.com/lomba/schema_monkey.svg)](https://gemnasium.com/SchemaPlus/schema_monkey)
5
+
6
+ # schema_monkey
7
+
8
+ TODO: Write a gem description
9
+
10
+ schema_monkey is part of the [SchemaPlus](https://github.com/SchemaPlus/) family of Ruby on Rails extension gems.
11
+
12
+ ## Installation
13
+
14
+ In your application's Gemfile
15
+
16
+ ```ruby
17
+ gem "schema_monkey"
18
+ ```
19
+ ## Compatibility
20
+
21
+ schema_monkey is tested on
22
+
23
+ [//]: # SCHEMA_DEV: MATRIX - begin
24
+ [//]: # These lines are auto-generated by schema_dev based on schema_dev.yml
25
+ * ruby **1.9.3** with rails **4.2**, using **mysql2**, **sqlite3** or **postgresql**
26
+ * ruby **2.1.5** with rails **4.2**, using **mysql2**, **sqlite3** or **postgresql**
27
+
28
+ [//]: # SCHEMA_DEV: MATRIX - end
29
+
30
+ ## Usage
31
+
32
+ TODO: Write usage instructions here
33
+
34
+
35
+ ## History
36
+
37
+ * See [CHANGELOG](CHANGELOG.md) for per-version release notes.
38
+
39
+ ## Development & Testing
40
+
41
+ Are you interested in contributing to schema_monkey? Thanks! Please follow
42
+ the standard protocol: fork, feature branch, develop, push, and issue pull request.
43
+
44
+ Some things to know about to help you develop and test:
45
+
46
+ * **schema_dev**: schema_monkey uses [schema_dev](https://github.com/SchemaPlus/schema_dev) to
47
+ facilitate running rspec tests on the matrix of ruby, rails, and database
48
+ versions that the gem supports, both locally and on
49
+ [travis-ci](http://travis-ci.org/SchemaPlus/schema_monkey)
50
+
51
+ To to run rspec locally on the full matrix, do:
52
+
53
+ $ schema_dev bundle install
54
+ $ schema_dev rspec
55
+
56
+ You can also run on just one configuration at a time; For info, see `schema_dev --help` or the
57
+ [schema_dev](https://github.com/SchemaPlus/schema_dev) README.
58
+
59
+ The matrix of configurations is specified in `schema_dev.yml` in
60
+ the project root.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'schema_dev/tasks'
5
+
6
+ task :default => :spec
7
+
8
+ require 'rspec/core/rake_task'
9
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ gemspec :path => File.expand_path('..', __FILE__)
3
+
4
+ platform :ruby do
5
+ gem "byebug" if RUBY_VERSION > "2"
6
+ end
@@ -0,0 +1,3 @@
1
+ eval File.read File.expand_path('../../Gemfile.base', __FILE__)
2
+
3
+ gem "rails", "~> 4.2.0"
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "mysql2"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcmysql-adapter'
10
+ end
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "pg"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcpostgresql-adapter'
10
+ end
@@ -0,0 +1,10 @@
1
+ require "pathname"
2
+ eval(Pathname.new(__FILE__).dirname.join("Gemfile.base").read, binding)
3
+
4
+ platform :ruby do
5
+ gem "sqlite3"
6
+ end
7
+
8
+ platform :jruby do
9
+ gem 'activerecord-jdbcsqlite3-adapter', '>=1.3.0.beta2'
10
+ end
@@ -0,0 +1,31 @@
1
+ module SchemaMonkey
2
+ module ActiveRecord
3
+
4
+ module Base
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def self.extended(base)
11
+ class << base
12
+ alias_method_chain :columns, :schema_monkey
13
+ alias_method_chain :reset_column_information, :schema_monkey
14
+ end
15
+ end
16
+
17
+ def columns_with_schema_monkey
18
+ Middleware::Model::Columns.start model: self, columns: [] do |env|
19
+ env.columns += columns_without_schema_monkey
20
+ end
21
+ end
22
+
23
+ def reset_column_information_with_schema_monkey
24
+ Middleware::Model::ResetColumnInformation.start model: self do |env|
25
+ reset_column_information_without_schema_monkey
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ module SchemaMonkey
2
+ module ActiveRecord
3
+ module ConnectionAdapters
4
+ module AbstractAdapter
5
+ def self.included(base) #:nodoc:
6
+ base.alias_method_chain :initialize, :schema_monkey
7
+ end
8
+
9
+ def initialize_with_schema_monkey(*args) #:nodoc:
10
+ initialize_without_schema_monkey(*args)
11
+
12
+ dbm = case adapter_name
13
+ when /^MySQL/i then :Mysql
14
+ when 'PostgreSQL', 'PostGIS' then :Postgresql
15
+ when 'SQLite' then :Sqlite3
16
+ end
17
+
18
+ SchemaMonkey.include_adapters(self.class, dbm)
19
+ SchemaMonkey.insert_middleware(dbm)
20
+ end
21
+
22
+ module SchemaCreation
23
+ def self.included(base)
24
+ base.class_eval do
25
+ alias_method_chain :add_column_options!, :schema_monkey
26
+ public :options_include_default?
27
+ end
28
+ end
29
+
30
+ def add_column_options_with_schema_monkey!(sql, options)
31
+ Middleware::Migration::ColumnOptionsSql.start caller: self, connection: self.instance_variable_get('@conn'), sql: sql, options: options do |env|
32
+ add_column_options_without_schema_monkey! env.sql, env.options
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,31 @@
1
+ module SchemaMonkey
2
+ module ActiveRecord
3
+ module ConnectionAdapters
4
+ module MysqlAdapter
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+ alias_method_chain :indexes, :schema_monkey
9
+ alias_method_chain :tables, :schema_monkey
10
+ end
11
+ SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter, SchemaMonkey::ActiveRecord::ConnectionAdapters::SchemaStatements::Column
12
+ SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter, SchemaMonkey::ActiveRecord::ConnectionAdapters::SchemaStatements::Reference
13
+ SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter, SchemaMonkey::ActiveRecord::ConnectionAdapters::SchemaStatements::Index
14
+ end
15
+
16
+ def indexes_with_schema_monkey(table_name, query_name=nil)
17
+ Middleware::Query::Indexes.start connection: self, table_name: table_name, query_name: query_name do |env|
18
+ env.index_definitions += indexes_without_schema_monkey env.table_name, env.query_name
19
+ end
20
+ end
21
+
22
+ def tables_with_schema_monkey(query_name=nil, database=nil, like=nil)
23
+ Middleware::Query::Tables.start connection: self, query_name: query_name, database: database, like: like do |env|
24
+ env.tables += tables_without_schema_monkey env.query_name, env.database, env.like
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+
@@ -0,0 +1,30 @@
1
+ module SchemaMonkey
2
+ module ActiveRecord
3
+ module ConnectionAdapters
4
+ module PostgresqlAdapter
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+ alias_method_chain :exec_cache, :schema_monkey
9
+ alias_method_chain :indexes, :schema_monkey
10
+ end
11
+ SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::SchemaStatements, SchemaMonkey::ActiveRecord::ConnectionAdapters::SchemaStatements::Reference
12
+ SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements, SchemaMonkey::ActiveRecord::ConnectionAdapters::SchemaStatements::Column
13
+ SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements, SchemaMonkey::ActiveRecord::ConnectionAdapters::SchemaStatements::Index
14
+ end
15
+
16
+ def exec_cache_with_schema_monkey(sql, name, binds)
17
+ Middleware::Query::ExecCache.start connection: self, sql: sql, name: name, binds: binds do |env|
18
+ exec_cache_without_schema_monkey(env.sql, env.name, env.binds)
19
+ end
20
+ end
21
+
22
+ def indexes_with_schema_monkey(table_name, query_name=nil)
23
+ Middleware::Query::Indexes.start connection: self, table_name: table_name, query_name: query_name do |env|
24
+ env.index_definitions += indexes_without_schema_monkey env.table_name, env.query_name
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,86 @@
1
+ module SchemaMonkey
2
+ module ActiveRecord
3
+ module ConnectionAdapters
4
+ module SchemaStatements
5
+
6
+ #
7
+ # The hooks at the top level of this module are for the base class, which are not overriden by
8
+ # any specific adapters in AR.
9
+ #
10
+ def self.included(base)
11
+ base.class_eval do
12
+ alias_method_chain :add_index_options, :schema_monkey
13
+ end
14
+ end
15
+
16
+ def add_index_options_with_schema_monkey(table_name, column_names, options={})
17
+ cache = []
18
+ Middleware::Migration::IndexComponentsSql.start connection: self, table_name: table_name, column_names: Array.wrap(column_names), options: options.deep_dup do |env|
19
+ cache << env
20
+ env.sql.name, env.sql.type, env.sql.columns, env.sql.options, env.sql.algorithm, env.sql.using = add_index_options_without_schema_monkey(env.table_name, env.column_names, env.options)
21
+ end
22
+ env = cache[0]
23
+ [env.sql.name, env.sql.type, env.sql.columns, env.sql.options, env.sql.algorithm, env.sql.using]
24
+ end
25
+
26
+ #
27
+ # The hooks below here are grouped into modules. Different
28
+ # connection adapters define this methods in different places, so
29
+ # each will include the hooks into the appropriate class
30
+ #
31
+
32
+ module Column
33
+ def self.included(base)
34
+ base.class_eval do
35
+ alias_method_chain :add_column, :schema_monkey
36
+ alias_method_chain :change_column, :schema_monkey
37
+ end
38
+ end
39
+
40
+ def add_column_with_schema_monkey(table_name, name, type, options = {})
41
+ Middleware::Migration::Column.start caller: self, operation: :add, table_name: table_name, column_name: name, type: type, options: options.deep_dup do |env|
42
+ add_column_without_schema_monkey env.table_name, env.column_name, env.type, env.options
43
+ end
44
+ end
45
+
46
+ def change_column_with_schema_monkey(table_name, name, type, options = {})
47
+ Middleware::Migration::Column.start caller: self, operation: :change, table_name: table_name, column_name: name, type: type, options: options.deep_dup do |env|
48
+ change_column_without_schema_monkey env.table_name, env.column_name, env.type, env.options
49
+ end
50
+ end
51
+ end
52
+
53
+ module Reference
54
+ def self.included(base)
55
+ base.class_eval do
56
+ alias_method_chain :add_reference, :schema_monkey
57
+ end
58
+ end
59
+ def add_reference_with_schema_monkey(table_name, name, options = {})
60
+ Middleware::Migration::Column.start caller: self, operation: :add, table_name: table_name, column_name: "#{name}_id", type: :reference, options: options.deep_dup do |env|
61
+ add_reference_without_schema_monkey env.table_name, env.column_name.sub(/_id$/, ''), env.options
62
+ end
63
+ end
64
+ end
65
+
66
+ module Index
67
+ def self.included(base)
68
+ base.class_eval do
69
+ alias_method_chain :add_index, :schema_monkey
70
+ end
71
+ end
72
+ def add_index_with_schema_monkey(table_name, column_names, options={})
73
+ if column_names.is_a? Hash and options.empty?
74
+ options = column_names
75
+ column_names = nil
76
+ end
77
+ Middleware::Migration::Index.start caller: self, operation: :add, table_name: table_name, column_names: column_names, options: options.deep_dup do |env|
78
+ add_index_without_schema_monkey env.table_name, env.column_names, env.options
79
+ end
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,33 @@
1
+ module SchemaMonkey
2
+ module ActiveRecord
3
+ module ConnectionAdapters
4
+ module Sqlite3Adapter
5
+
6
+ def self.included(base)
7
+ base.class_eval do
8
+ alias_method_chain :indexes, :schema_monkey
9
+ alias_method_chain :tables, :schema_monkey
10
+ end
11
+ SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::SchemaStatements, SchemaMonkey::ActiveRecord::ConnectionAdapters::SchemaStatements::Column
12
+ SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::SchemaStatements, SchemaMonkey::ActiveRecord::ConnectionAdapters::SchemaStatements::Reference
13
+ SchemaMonkey.include_once ::ActiveRecord::ConnectionAdapters::SchemaStatements, SchemaMonkey::ActiveRecord::ConnectionAdapters::SchemaStatements::Index
14
+ end
15
+
16
+ def indexes_with_schema_monkey(table_name, query_name=nil)
17
+ Middleware::Query::Indexes.start connection: self, table_name: table_name, query_name: query_name do |env|
18
+ env.index_definitions += indexes_without_schema_monkey env.table_name, env.query_name
19
+ end
20
+ end
21
+
22
+ def tables_with_schema_monkey(query_name=nil, table_name=nil)
23
+ Middleware::Query::Tables.start connection: self, query_name: query_name, table_name: table_name do |env|
24
+ env.tables += tables_without_schema_monkey env.query_name, env.table_name
25
+ end
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+
@@ -0,0 +1,40 @@
1
+ module SchemaMonkey
2
+ module ActiveRecord
3
+ module ConnectionAdapters
4
+ module TableDefinition
5
+ def self.included(base)
6
+ base.class_eval do
7
+ alias_method_chain :column, :schema_monkey
8
+ alias_method_chain :references, :schema_monkey
9
+ alias_method_chain :belongs_to, :schema_monkey
10
+ alias_method_chain :index, :schema_monkey
11
+ end
12
+ end
13
+
14
+ def column_with_schema_monkey(name, type, options = {})
15
+ Middleware::Migration::Column.start caller: self, operation: :define, table_name: self.name, column_name: name, type: type, options: options.deep_dup do |env|
16
+ column_without_schema_monkey env.column_name, env.type, env.options
17
+ end
18
+ end
19
+
20
+ def references_with_schema_monkey(name, options = {})
21
+ Middleware::Migration::Column.start caller: self, operation: :define, table_name: self.name, column_name: "#{name}_id", type: :reference, options: options.deep_dup do |env|
22
+ references_without_schema_monkey env.column_name.sub(/_id$/, ''), env.options
23
+ end
24
+ end
25
+
26
+ def belongs_to_with_schema_monkey(name, options = {})
27
+ Middleware::Migration::Column.start caller: self, operation: :define, table_name: self.name, column_name: "#{name}_id", type: :reference, options: options.deep_dup do |env|
28
+ belongs_to_without_schema_monkey env.column_name.sub(/_id$/, ''), env.options
29
+ end
30
+ end
31
+
32
+ def index_with_schema_monkey(column_name, options = {})
33
+ Middleware::Migration::Index.start caller: self, operation: :define, table_name: self.name, column_names: column_name, options: options.deep_dup do |env|
34
+ index_without_schema_monkey env.column_names, env.options
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ module SchemaMonkey
2
+ module ActiveRecord
3
+ module Migration
4
+ module CommandRecorder
5
+ def self.included(base)
6
+ base.class_eval do
7
+ alias_method_chain :add_column, :schema_monkey
8
+ end
9
+ end
10
+
11
+ def add_column_with_schema_monkey(table_name, column_name, type, options = {})
12
+ Middleware::Migration::Column.start caller: self, operation: :record, table_name: table_name, column_name: column_name, type: type, options: options.deep_dup do |env|
13
+ add_column_without_schema_monkey env.table_name, env.column_name, env.type, env.options
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,179 @@
1
+ require 'ostruct'
2
+ require 'tsort'
3
+
4
+ module SchemaMonkey
5
+ module ActiveRecord
6
+ module SchemaDumper
7
+
8
+ class Dump
9
+ include TSort
10
+
11
+ attr_reader :extensions, :tables, :dependencies, :data
12
+ attr_accessor :foreign_keys, :trailer
13
+
14
+ def initialize(dumper)
15
+ @dumper = dumper
16
+ @dependencies = Hash.new { |h, k| h[k] = [] }
17
+ @extensions = []
18
+ @tables = {}
19
+ @foreign_keys = []
20
+ @data = OpenStruct.new # a place for middleware to leave data
21
+ end
22
+
23
+ def depends(tablename, dependents)
24
+ @tables[tablename] ||= false # placeholder for dependencies applied before defining the table
25
+ @dependencies[tablename] += Array.wrap(dependents)
26
+ end
27
+
28
+ def assemble(stream)
29
+ stream.puts @extensions.join("\n") if extensions.any?
30
+ assemble_tables(stream)
31
+ foreign_keys.each do |statement|
32
+ stream.puts " #{statement}"
33
+ end
34
+ stream.puts @trailer
35
+ end
36
+
37
+ def assemble_tables(stream)
38
+ tsort().each do |table|
39
+ @tables[table].assemble(stream) if @tables[table]
40
+ end
41
+ end
42
+
43
+ def tsort_each_node(&block)
44
+ @tables.keys.sort.each(&block)
45
+ end
46
+
47
+ def tsort_each_child(tablename, &block)
48
+ @dependencies[tablename].sort.uniq.reject{|t| @dumper.ignored? t}.each(&block)
49
+ end
50
+
51
+ class Table < KeyStruct[:name, :pname, :options, :columns, statements: [], trailer: []]
52
+
53
+ def assemble(stream)
54
+ stream.write " create_table #{pname.inspect}"
55
+ stream.write ", #{options}" unless options.blank?
56
+ stream.puts " do |t|"
57
+ typelen = @columns.map{|col| col.type.length}.max
58
+ namelen = @columns.map{|col| col.name.length}.max
59
+ @columns.each do |column|
60
+ stream.write " "
61
+ column.assemble(stream, typelen, namelen)
62
+ stream.puts ""
63
+ end
64
+ statements.each do |statement|
65
+ stream.puts " #{statement}"
66
+ end
67
+ stream.puts " end"
68
+ trailer.each do |statement|
69
+ stream.puts " #{statement}"
70
+ end
71
+ stream.puts ""
72
+ end
73
+
74
+ class Column < KeyStruct[:name, :type, :options, :comments]
75
+
76
+ def add_option(option)
77
+ self.options = [options, option].reject(&:blank?).join(', ')
78
+ end
79
+
80
+ def add_comment(comment)
81
+ self.comments = [comments, comment].reject(&:blank?).join('; ')
82
+ end
83
+
84
+ def assemble(stream, typelen, namelen)
85
+ stream.write "t.%-#{typelen}s " % type
86
+ if options.blank? && comments.blank?
87
+ stream.write name.inspect
88
+ else
89
+ pr = name.inspect
90
+ pr += "," unless options.blank?
91
+ stream.write "%-#{namelen+3}s " % pr
92
+ end
93
+ stream.write "#{options}" unless options.blank?
94
+ stream.write " " unless options.blank? or comments.blank?
95
+ stream.write "# #{comments}" unless comments.blank?
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ def self.included(base)
102
+ base.class_eval do
103
+ alias_method_chain :dump, :schema_monkey
104
+ alias_method_chain :extensions, :schema_monkey
105
+ alias_method_chain :tables, :schema_monkey
106
+ alias_method_chain :table, :schema_monkey
107
+ alias_method_chain :foreign_keys, :schema_monkey
108
+ alias_method_chain :trailer, :schema_monkey
109
+ public :ignored?
110
+ end
111
+ end
112
+
113
+ def dump_with_schema_monkey(stream)
114
+ @dump = Dump.new(self)
115
+ dump_without_schema_monkey(stream)
116
+ @dump.assemble(stream)
117
+ end
118
+
119
+ def foreign_keys_with_schema_monkey(table, _)
120
+ stream = StringIO.new
121
+ foreign_keys_without_schema_monkey(table, stream)
122
+ @dump.foreign_keys += stream.string.split("\n").map(&:strip)
123
+ end
124
+
125
+ def trailer_with_schema_monkey(_)
126
+ stream = StringIO.new
127
+ trailer_without_schema_monkey(stream)
128
+ @dump.trailer = stream.string
129
+ end
130
+
131
+ def extensions_with_schema_monkey(_)
132
+ Middleware::Dumper::Extensions.start dumper: self, connection: @connection, extensions: @dump.extensions do |env|
133
+ stream = StringIO.new
134
+ extensions_without_schema_monkey(stream)
135
+ @dump.extensions << stream.string unless stream.string.blank?
136
+ end
137
+ end
138
+
139
+ def tables_with_schema_monkey(_)
140
+ Middleware::Dumper::Tables.start dumper: self, connection: @connection, dump: @dump do |env|
141
+ tables_without_schema_monkey(nil)
142
+ end
143
+ end
144
+
145
+ def table_with_schema_monkey(table, _)
146
+ Middleware::Dumper::Table.start dumper: self, connection: @connection, dump: @dump, table: @dump.tables[table] = Dump::Table.new(name: table) do |env|
147
+ stream = StringIO.new
148
+ table_without_schema_monkey(env.table.name, stream)
149
+ m = stream.string.match %r{
150
+ \A \s*
151
+ create_table \s*
152
+ [:'"](?<name>[^'"\s]+)['"]? \s*
153
+ ,? \s*
154
+ (?<options>.*) \s+
155
+ do \s* \|t\| \s* $
156
+ (?<columns>.*)
157
+ ^\s*end\s*$
158
+ (?<trailer>.*)
159
+ \Z
160
+ }xm
161
+ env.table.pname = m[:name]
162
+ env.table.options = m[:options].strip
163
+ env.table.trailer = m[:trailer].split("\n").map(&:strip).reject{|s| s.blank?}
164
+ env.table.columns = m[:columns].strip.split("\n").map { |col|
165
+ m = col.strip.match %r{
166
+ ^
167
+ t\.(?<type>\S+) \s*
168
+ [:'"](?<name>[^"\s]+)[,"]? \s*
169
+ ,? \s*
170
+ (?<options>.*)
171
+ $
172
+ }x
173
+ Dump::Table::Column.new(name: m[:name], type: m[:type], options: m[:options])
174
+ }
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,113 @@
1
+ module SchemaMonkey
2
+ module Middleware
3
+
4
+ class Base
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+ def continue(env)
9
+ @app.call env
10
+ end
11
+ end
12
+
13
+ module Stack
14
+ def stack
15
+ @stack ||= ::Middleware::Builder.new do
16
+ use Root
17
+ end
18
+ end
19
+
20
+ def append(middleware)
21
+ stack.insert_before(Root, middleware)
22
+ end
23
+
24
+ def prepend(middleware)
25
+ stack.insert(0, middleware)
26
+ end
27
+
28
+ def start(*args, &block)
29
+ env = self.const_get(:Env).new(*args)
30
+ env.instance_variable_set('@root', block)
31
+ stack.call(env)
32
+ end
33
+
34
+ class Root < Base
35
+ def call(env)
36
+ env.instance_variable_get('@root').call(env)
37
+ end
38
+ end
39
+ end
40
+
41
+ module Query
42
+ module ExecCache
43
+ extend Stack
44
+ Env = KeyStruct[:connection, :sql, :name, :binds]
45
+ end
46
+
47
+ module Tables
48
+ extend Stack
49
+ # :database and :like are only for mysql
50
+ # :table_name is only for sqlite3
51
+ Env = KeyStruct[:connection, :query_name, :table_name, :database, :like, tables: []]
52
+ end
53
+
54
+ module Indexes
55
+ extend Stack
56
+ Env = KeyStruct[:connection, :table_name, :query_name, index_definitions: []]
57
+ end
58
+ end
59
+
60
+ module Migration
61
+
62
+ module Column
63
+ extend Stack
64
+ Env = KeyStruct[:caller, :operation, :table_name, :column_name, :type, :options]
65
+ end
66
+
67
+ module ColumnOptionsSql
68
+ extend Stack
69
+ Env = KeyStruct[:caller, :connection, :sql, :options]
70
+ end
71
+
72
+ module Index
73
+ extend Stack
74
+ Env = KeyStruct[:caller, :operation, :table_name, :column_names, :options]
75
+ end
76
+
77
+ module IndexComponentsSql
78
+ extend Stack
79
+ Sql = KeyStruct[:name, :type, :columns, :options, :algorithm, :using]
80
+ Env = KeyStruct[:connection, :table_name, :column_names, :options, sql: Sql.new]
81
+ end
82
+
83
+ end
84
+
85
+ module Dumper
86
+ module Extensions
87
+ extend Stack
88
+ Env = KeyStruct[:dumper, :connection, :extensions]
89
+ end
90
+ module Tables
91
+ extend Stack
92
+ Env = KeyStruct[:dumper, :connection, :dump]
93
+ end
94
+ module Table
95
+ extend Stack
96
+ Env = KeyStruct[:dumper, :connection, :dump, :table]
97
+ end
98
+ end
99
+
100
+ module Model
101
+ module Columns
102
+ extend Stack
103
+ Env = KeyStruct[:model, :columns]
104
+ end
105
+ module ResetColumnInformation
106
+ extend Stack
107
+ Env = KeyStruct[:model]
108
+ end
109
+ end
110
+
111
+
112
+ end
113
+ end
@@ -0,0 +1,48 @@
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.select! &it.to_s =~ opts.match if opts.match
43
+ modules.select! &it.respond_to?(opts.respond_to) if opts.respond_to
44
+ modules += modules.flat_map { |mod| get_modules(mod, opts.except(:prefix, :and_self)) } if opts.recursive
45
+ modules
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,20 @@
1
+ module SchemaMonkey
2
+ class Railtie < Rails::Railtie #:nodoc:
3
+
4
+ initializer 'schema_monkey.insert', :before => "active_record.initialize_database" do
5
+ ActiveSupport.on_load(:active_record) do
6
+ SchemaMonkey.insert
7
+ end
8
+ end
9
+
10
+ rake_tasks do
11
+ load 'rails/tasks/database.rake'
12
+ ['db:schema:dump', 'db:schema:load'].each do |name|
13
+ if task = Rake.application.tasks.find { |task| task.name == name }
14
+ task.enhance(["schema_monkey:load"])
15
+ end
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module SchemaMonkey
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,81 @@
1
+ require 'hash_keyword_args'
2
+ require 'key_struct'
3
+ require 'middleware'
4
+
5
+ require_relative "schema_monkey/middleware"
6
+ require_relative "schema_monkey/module_support"
7
+ require_relative "schema_monkey/active_record/base"
8
+ require_relative "schema_monkey/active_record/connection_adapters/abstract_adapter"
9
+ require_relative "schema_monkey/active_record/connection_adapters/table_definition"
10
+ require_relative 'schema_monkey/active_record/connection_adapters/schema_statements'
11
+ require_relative 'schema_monkey/active_record/migration/command_recorder'
12
+ require_relative 'schema_monkey/active_record/schema_dumper'
13
+ require_relative 'schema_monkey/railtie' if defined?(Rails::Railtie)
14
+
15
+ module SchemaMonkey
16
+
17
+ extend SchemaMonkey::ModuleSupport
18
+
19
+ DBMS = [:Postgresql, :Mysql, :Sqlite3]
20
+
21
+ module ActiveRecord
22
+ module ConnectionAdapters
23
+ autoload :PostgresqlAdapter, 'schema_monkey/active_record/connection_adapters/postgresql_adapter'
24
+ autoload :MysqlAdapter, 'schema_monkey/active_record/connection_adapters/mysql_adapter'
25
+ autoload :Sqlite3Adapter, 'schema_monkey/active_record/connection_adapters/sqlite3_adapter'
26
+ end
27
+ end
28
+
29
+ def self.insert
30
+ insert_modules
31
+ include_adapters(::ActiveRecord::ConnectionAdapters::AbstractAdapter, :Abstract)
32
+ insert_middleware
33
+ end
34
+
35
+ def self.register(mod)
36
+ registered_modules << mod
37
+ end
38
+
39
+ def self.registered_modules
40
+ @registered_modules ||= [self]
41
+ end
42
+
43
+ def self.include_adapters(base, dbm)
44
+ registered_modules.each do |mod|
45
+ include_if_defined(base, mod, "ActiveRecord::ConnectionAdapters::#{dbm}Adapter")
46
+ end
47
+ end
48
+
49
+ def self.insert_modules
50
+ registered_modules.each do |mod|
51
+ get_modules(mod, prefix: 'ActiveRecord', match: /\bActiveRecord\b/, recursive: true).each do |candidate|
52
+ next if candidate.is_a?(Class)
53
+ if (base = get_const(::ActiveRecord, candidate.to_s.sub(/^#{mod}::ActiveRecord::/, '')))
54
+ patch base, mod
55
+ end
56
+ end
57
+ mod.insert if mod.respond_to?(:insert) and mod != self
58
+ end
59
+ end
60
+
61
+ def self.insert_middleware(dbm=nil)
62
+ @inserted ||= {}
63
+
64
+ if dbm
65
+ match = /\b#{dbm}\b/
66
+ reject = nil
67
+ else
68
+ match = nil
69
+ reject = /\b(#{DBMS.join('|')})\b/
70
+ end
71
+
72
+ registered_modules.each do |mod|
73
+ get_modules(mod, prefix: 'Middleware', and_self: true, match: match, reject: reject, recursive: true, respond_to: :insert).each do |middleware|
74
+ next if @inserted[middleware]
75
+ middleware.insert
76
+ @inserted[middleware] = true
77
+ end
78
+ end
79
+ end
80
+
81
+ end
data/schema_dev.yml ADDED
@@ -0,0 +1,9 @@
1
+ ruby:
2
+ - 1.9.3
3
+ - 2.1.5
4
+ rails:
5
+ - 4.2
6
+ db:
7
+ - mysql2
8
+ - sqlite3
9
+ - postgresql
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'schema_monkey/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "schema_monkey"
8
+ spec.version = SchemaMonkey::VERSION
9
+ spec.authors = ["ronen barzel"]
10
+ spec.email = ["ronen@barzel.org"]
11
+ spec.summary = %q{Provides an internal API and module inclusion protocol to facilitate adding features to ActiveRecord}
12
+ spec.description = %q{Provides an internal API and module inclusion protocol to facilitate adding features to ActiveRecord}
13
+ spec.homepage = "https://github.com/SchemaPlus/schema_monkey"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activerecord", "~> 4.2"
22
+ spec.add_dependency "hash_keyword_args"
23
+ spec.add_dependency "its-it"
24
+ spec.add_dependency "key_struct"
25
+ spec.add_dependency "middleware", "~> 0.1"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.7"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "rspec", "~> 3.0.0"
30
+ spec.add_development_dependency "schema_dev", "~> 1.4"
31
+ spec.add_development_dependency "simplecov"
32
+ spec.add_development_dependency "simplecov-gem-profile"
33
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ # A basic sanity check to have as a spec when first starting. Feel free to delete this
5
+ # once you've got real content.
6
+
7
+ describe "Sanity Check" do
8
+
9
+ it "database is connected" do
10
+ expect(ActiveRecord::Base).to be_connected
11
+ end
12
+
13
+ end
@@ -0,0 +1,22 @@
1
+ require 'simplecov'
2
+ require 'simplecov-gem-profile'
3
+ SimpleCov.start "gem"
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+
8
+ require 'rspec'
9
+ require 'active_record'
10
+ require 'schema_monkey'
11
+ require 'schema_dev/rspec'
12
+
13
+ SchemaDev::Rspec.setup
14
+
15
+ Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each {|f| require f}
16
+
17
+ RSpec.configure do |config|
18
+ config.warnings = true
19
+ end
20
+
21
+ SimpleCov.command_name "[ruby #{RUBY_VERSION} - ActiveRecord #{::ActiveRecord::VERSION::STRING} - #{ActiveRecord::Base.connection.adapter_name}]"
22
+
metadata ADDED
@@ -0,0 +1,231 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schema_monkey
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - ronen barzel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: hash_keyword_args
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: its-it
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: key_struct
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: middleware
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.1'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.7'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.7'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 3.0.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 3.0.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: schema_dev
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.4'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.4'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov-gem-profile
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: Provides an internal API and module inclusion protocol to facilitate
168
+ adding features to ActiveRecord
169
+ email:
170
+ - ronen@barzel.org
171
+ executables: []
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - ".gitignore"
176
+ - ".travis.yml"
177
+ - Gemfile
178
+ - LICENSE.txt
179
+ - README.md
180
+ - Rakefile
181
+ - gemfiles/Gemfile.base
182
+ - gemfiles/rails-4.2/Gemfile.base
183
+ - gemfiles/rails-4.2/Gemfile.mysql2
184
+ - gemfiles/rails-4.2/Gemfile.postgresql
185
+ - gemfiles/rails-4.2/Gemfile.sqlite3
186
+ - lib/schema_monkey.rb
187
+ - lib/schema_monkey/active_record/base.rb
188
+ - lib/schema_monkey/active_record/connection_adapters/abstract_adapter.rb
189
+ - lib/schema_monkey/active_record/connection_adapters/mysql_adapter.rb
190
+ - lib/schema_monkey/active_record/connection_adapters/postgresql_adapter.rb
191
+ - lib/schema_monkey/active_record/connection_adapters/schema_statements.rb
192
+ - lib/schema_monkey/active_record/connection_adapters/sqlite3_adapter.rb
193
+ - lib/schema_monkey/active_record/connection_adapters/table_definition.rb
194
+ - lib/schema_monkey/active_record/migration/command_recorder.rb
195
+ - lib/schema_monkey/active_record/schema_dumper.rb
196
+ - lib/schema_monkey/middleware.rb
197
+ - lib/schema_monkey/module_support.rb
198
+ - lib/schema_monkey/railtie.rb
199
+ - lib/schema_monkey/version.rb
200
+ - schema_dev.yml
201
+ - schema_monkey.gemspec
202
+ - spec/sanity_spec.rb
203
+ - spec/spec_helper.rb
204
+ homepage: https://github.com/SchemaPlus/schema_monkey
205
+ licenses:
206
+ - MIT
207
+ metadata: {}
208
+ post_install_message:
209
+ rdoc_options: []
210
+ require_paths:
211
+ - lib
212
+ required_ruby_version: !ruby/object:Gem::Requirement
213
+ requirements:
214
+ - - ">="
215
+ - !ruby/object:Gem::Version
216
+ version: '0'
217
+ required_rubygems_version: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - ">="
220
+ - !ruby/object:Gem::Version
221
+ version: '0'
222
+ requirements: []
223
+ rubyforge_project:
224
+ rubygems_version: 2.2.2
225
+ signing_key:
226
+ specification_version: 4
227
+ summary: Provides an internal API and module inclusion protocol to facilitate adding
228
+ features to ActiveRecord
229
+ test_files:
230
+ - spec/sanity_spec.rb
231
+ - spec/spec_helper.rb