schema_monkey 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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