database_introspection 0.0.9

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: cb2ff4ce8131add8f4e7cfc4830240d8ba45df98
4
+ data.tar.gz: 524b268bdb6f8f11bd6ef6798c00dbf5c5e34bff
5
+ SHA512:
6
+ metadata.gz: ac56205a6698c903436d4d5935861abad37fce34a7fc0e3652b5f33def754270fb71af500e4dff03a77d9a5ac93efd6456e29787ca0036302cfc83f5d2fc397c
7
+ data.tar.gz: 3f8fd05f31a29d3cecf0b72d29427c1d5c9121cb42736a96cde92a49bff786f62026ac59e1e6c893ca619dd28a989503bc0050be6026c5c040c703dc059edf70
data/.gitignore ADDED
@@ -0,0 +1,47 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ # Standard
19
+ *~
20
+ # Standard Rails project
21
+ /tmp/
22
+ /log/
23
+ /db/*.sqlite3
24
+ # SASS CSS generation
25
+ /public/stylesheets/.sass-cache/
26
+ # Netbeans
27
+ /nbproject/
28
+ # Sublime Text 2 project
29
+ *.sublime-project
30
+ *.sublime-workspace
31
+ *(copie)*
32
+ # RVM
33
+ .rvmrc
34
+ # VisualRuby
35
+ .vr_settings.yaml
36
+ # Emacs
37
+ *#
38
+ *\#
39
+ \#*
40
+ .#*
41
+ \#*\#
42
+ # Geany
43
+ *.geany
44
+ # RubyMine
45
+ .idea
46
+ #RedCar
47
+ .redcar
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in database_introspection.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Laurent
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,107 @@
1
+ # Database Introspection
2
+
3
+ This gem will introspect the database and create __dynamically__ ActiveRecord::Base descendants that can be used by your application, including some Rails associations helper methods.
4
+
5
+ It is intended to be primarily used within rails applications but nothing prevents you to use standalone, provided the fact you are already connected to a database.
6
+ This gem does a bit the reverse action of what you do with Rails generator, when you want to generate the database from you migrations.
7
+
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'database_introspection'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install database_introspection
22
+
23
+ ## Usage
24
+
25
+ ### Basic database introspection
26
+
27
+ To introspect the database, you just have to call the following method:
28
+
29
+ ```ruby
30
+ DynamicModel.introspect_database
31
+ ```
32
+
33
+ By default it will analyse all database tables starting by "user_defined_", and will create ActiveRecord::Base descendant to handle them.
34
+
35
+ For example if your database contains the following tables:
36
+
37
+ ```
38
+ user_defined_table1
39
+ user_defined_table2
40
+ user_defined_table3
41
+ user_defined_table4
42
+ ```
43
+ The call to `DynamicModel.introspect_database`, will inject the following classes in your application:
44
+
45
+ ```ruby
46
+ DynamicModel::ManagedDomains::UserDefined::Table1
47
+ DynamicModel::ManagedDomains::UserDefined::Table2
48
+ DynamicModel::ManagedDomains::UserDefined::Table3
49
+ DynamicModel::ManagedDomains::UserDefined::Table4
50
+ ```
51
+
52
+ ### Architecture
53
+
54
+ #### Classes and modules generated
55
+
56
+ * `DynamicModel` is the module that contains methods to introspect the database.
57
+ * `DynamicModel::ManagedDomain` contains some methods to manipulate the domains introspected.
58
+ * Then for example in the first example, `DynamicModel::ManagedDomains::UserDefined` is a module created dynamically from the domain name (ie tables prefix). It contains itself some methods to easily manipulate the tables or generated classes of this particular domain.
59
+ * The `DynamicModel::ManagedDomains::UserDefined::Tablex` classes are descendants of ActiveRecord::Base that you will use in your application.
60
+
61
+ Of course if you provide another domain name (ie tables prefix) the corresponding modules and classes will be created accordingly. Running:
62
+
63
+ ```ruby
64
+ DynamicModel.introspect_database :another_domain
65
+ ```
66
+
67
+ On a database containing the following tables:
68
+
69
+ ```
70
+ another_domain_table1
71
+ another_domain_table2
72
+ ```
73
+
74
+ Will inject the following classes in your application:
75
+
76
+ ```ruby
77
+ DynamicModel::ManagedDomains::AnotherDomain::Table1
78
+ DynamicModel::ManagedDomains::AnotherDomain::Table2
79
+ ```
80
+ and of course the following module:
81
+ ```ruby
82
+ DynamicModel::ManagedDomains::AnotherDomain
83
+ ```
84
+
85
+ #### Generated classes
86
+
87
+ The classes generated will actually have some behaviour added by extending the module `DynamicModel::ActiveRecordExtension` to basically be aware of the domain they belong to.
88
+
89
+ ### Database relationships
90
+
91
+ Provided you follow the standard rails rules for ids, for example:
92
+
93
+ if `user_defined_table1` contains `user_defined_table2_id` (not yet implemented) or `table2_id`, the introspector will understand there is a relationship between the tables and create the ActiveRecord associations accordingly adding all the standard helper methods to the generated classes !
94
+
95
+ ## To do
96
+
97
+ * Improve Readme.
98
+ * Add code comments.
99
+ * Improve table relationship introspection.
100
+
101
+ ## Contributing
102
+
103
+ 1. Fork it
104
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
105
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
106
+ 4. Push to the branch (`git push origin my-new-feature`)
107
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'database_introspection/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "database_introspection"
8
+ spec.version = DatabaseIntrospection::VERSION
9
+ spec.authors = ["L.Briais"]
10
+ spec.email = ["lbnetid+rb@gmail.com"]
11
+ spec.description = %q{This gem will generate classes (by default ActiveRecord::Base descendants) from database introspection}
12
+ spec.summary = %q{Database Introspection}
13
+ spec.homepage = "https://github.com/lbriais/database_introspection"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
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_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_runtime_dependency "activemodel", ">= 3.2.13"
25
+ spec.add_runtime_dependency "activerecord", ">= 3.2.13"
26
+ spec.add_runtime_dependency "activeresource", ">= 3.2.13"
27
+ spec.add_runtime_dependency "activesupport", ">= 3.2.13"
28
+
29
+
30
+ end
@@ -0,0 +1,39 @@
1
+ module DynamicModel::ActiveRecordExtension
2
+
3
+ def self.included(base) # :nodoc:
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ # Be very careful with what is added here as it may conflict with whatever is generated by active record.
8
+ module InstanceMethods
9
+
10
+ end
11
+
12
+ # This one, only for the class
13
+ module ClassMethods
14
+ def to_param
15
+ "#{self.name_space}/#{self.list_name}"
16
+ end
17
+
18
+ def display_name
19
+ self.name.gsub(/^.*::([^:]+)$/, "\\1").titleize
20
+ end
21
+
22
+ def domain
23
+ puts name.gsub(/^.*::[^:]+$/, '')
24
+ name.gsub(/::[^:]+$/, '').constantize
25
+ end
26
+
27
+ def name_space
28
+ self.name.gsub( /DynamicModel::ManagedDomains::([^:]+)::.*$/, "\\1") .underscore
29
+ end
30
+
31
+ def list_name
32
+ self.name.gsub( /^.*::([^:]+)$/, "\\1") .underscore.pluralize
33
+ end
34
+
35
+ end
36
+
37
+ include InstanceMethods
38
+
39
+ end
@@ -0,0 +1,28 @@
1
+ require 'active_record'
2
+
3
+ module DynamicModel::DomainExtension
4
+
5
+ def model_classes
6
+ self.constants.map {|sym| "#{self.name}::#{sym.to_s}".constantize}
7
+ end
8
+
9
+ def table_names
10
+ ActiveRecord::Base.connection.tables.grep(/^#{prefix}_/)
11
+ end
12
+
13
+ def scoped_table_names
14
+ table_names.map{|table_name| table_name.gsub /^#{prefix}_/, ''}
15
+ end
16
+
17
+ def prefix
18
+ DynamicModel::ManagedDomains.to_hash[self]
19
+ end
20
+
21
+ def add_table(scoped_table_name, &block)
22
+ DynamicModel.add_table scoped_table_name, table_prefix: prefix, &block
23
+ end
24
+
25
+ def model_class(scoped_table_name)
26
+ Hash[scoped_table_names.zip model_classes][scoped_table_name]
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ # Namespace for domains
2
+ module DynamicModel::ManagedDomains
3
+ def self.domain_prefixes
4
+ constants.map {|c| c.to_s.underscore}
5
+ end
6
+
7
+ def self.domain_modules
8
+ constants.map {|c| "#{self.name}::#{c.to_s}".constantize}
9
+ end
10
+
11
+ def self.to_hash
12
+ Hash[domain_modules.zip domain_prefixes]
13
+ end
14
+
15
+ def self.tables
16
+ self.domain_modules.map {|mod| mod.table_names}.flatten
17
+ end
18
+
19
+ def self.domain_module(table_prefix)
20
+ Hash[domain_prefixes.zip domain_modules][table_prefix]
21
+ end
22
+
23
+ end
@@ -0,0 +1,13 @@
1
+ require 'active_record'
2
+ class DynamicModel::Migration < ActiveRecord::Migration
3
+ def self.create_with(name, &block)
4
+ create_table name.to_sym do |t|
5
+ block.call(t) if block_given?
6
+ begin
7
+ t.timestamps
8
+ rescue
9
+ puts "Cannot create timestamps... Probably already created."
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,163 @@
1
+ # -*- coding: utf-8 -*-
2
+ class DynamicModel::RelationsAnalyser
3
+ KEY_IDENTIFIER = /_id$/
4
+
5
+ attr_reader :alterations
6
+
7
+ def initialize(klasses)
8
+ @klasses = klasses
9
+ @alterations = {}
10
+ end
11
+
12
+ def run
13
+ raise "cannot rerun analysis with the same object... Create a new instance !" if @did_run
14
+ return if @klasses.empty?
15
+ @domain = @klasses[0].domain
16
+ introspect_belongs_to
17
+ verify_if_has_many_relations_could_be_actually_has_one
18
+ discover_has_many_through_from_belongs_to
19
+ apply_alterations
20
+ @did_run = true
21
+ end
22
+
23
+
24
+ private
25
+
26
+ def discover_has_many_through_from_belongs_to
27
+ puts "Has_many_through analysis started."
28
+ @alterations.each do |model, alterations|
29
+ alterations[:has_many_though] ||= []
30
+ alterations.each do |association_type, associations|
31
+ next unless association_type == :belongs_to
32
+ # If there is only one belongs_to, there cannot be a has_many_through
33
+ next if associations.size < 2
34
+ analyses_has_many_through_association model, associations
35
+ end
36
+ end
37
+ ensure
38
+ puts "Has_many_though analysis completed."
39
+ end
40
+
41
+ def introspect_belongs_to
42
+ puts "Belongs_to analysis started."
43
+ scoped_table_names_hash = Hash[@domain.scoped_table_names.zip @domain.model_classes]
44
+ @klasses.each do |klass|
45
+ @alterations[klass] ||= {}
46
+ # Find attributes ending by "_id"
47
+ klass.attribute_names.grep(KEY_IDENTIFIER) do |attr_name|
48
+ if klass.columns_hash[attr_name].type == :integer
49
+ # Check if there is a table in the domain that may be linked to this field
50
+ candidate_table_name = attr_name.gsub(KEY_IDENTIFIER, '').pluralize
51
+ candidate_target_class = scoped_table_names_hash[candidate_table_name]
52
+ # Creates a belongs_to relation
53
+ if scoped_table_names_hash.keys.include? candidate_table_name
54
+ @alterations[klass][:belongs_to] ||= []
55
+ @alterations[klass][:belongs_to] << {
56
+ key: attr_name,
57
+ class: candidate_target_class
58
+ }
59
+ # and the reverse, by default has_many
60
+ @alterations[candidate_target_class] ||= {}
61
+ @alterations[candidate_target_class][:has_many] ||= []
62
+ @alterations[candidate_target_class][:has_many] << {
63
+ class: klass
64
+ }
65
+ end
66
+ end
67
+ end
68
+ end
69
+ ensure
70
+ puts "Belongs_to analysis completed."
71
+ end
72
+
73
+
74
+ def verify_if_has_many_relations_could_be_actually_has_one
75
+ puts "Has_many analysis started."
76
+ @alterations.each do |model, alterations|
77
+ alterations[:has_one] ||= []
78
+ alterations.each do |association_type, associations|
79
+ next unless association_type == :has_many
80
+ associations.map! do |description|
81
+ if analyses_has_many_association model, description
82
+ # This is actually a has_one
83
+ alterations[:has_one] << description
84
+ nil
85
+ else
86
+ description
87
+ end
88
+ end
89
+ associations.compact!
90
+ end
91
+ end
92
+ ensure
93
+ puts "Has_many analysis completed."
94
+ end
95
+
96
+ def analyses_has_many_through_association(model, associations)
97
+ # As there are multiple belongs_to in this class, all combinations
98
+ # should lead to a has_many_through
99
+ # Waouh, Ruby rocks !!
100
+ associations.combination(2).each do |left, right|
101
+ @alterations[left[:class]][:has_many_through] ||= []
102
+ @alterations[right[:class]][:has_many_through] ||= []
103
+
104
+
105
+ @alterations[left[:class]][:has_many_through] << {
106
+ self_key: left[:key],
107
+ key: right[:key],
108
+ middle_class: model,
109
+ class: right[:class]
110
+ }
111
+ @alterations[right[:class]][:has_many_through] << {
112
+ self_key: right[:key],
113
+ key: left[:key],
114
+ middle_class: model,
115
+ class: left[:class]
116
+ }
117
+ end
118
+ end
119
+
120
+ def analyses_has_many_association(model, description)
121
+ # If one day I figure out how to determine if a has_many relation could be a has_one,
122
+ # should be implemented here... Doesn't look like solvable...
123
+ false
124
+ end
125
+
126
+
127
+ def apply_alterations
128
+ @alterations.each do |model, alterations|
129
+ puts "Processing alterations for #{model.list_name}"
130
+ alterations.each do |association_type, associations|
131
+ associations.each do |description|
132
+ method_name = "add_#{association_type}_behaviour"
133
+ self.send method_name, model, description
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+
140
+ def add_belongs_to_behaviour(model, description)
141
+ field_name = description[:key].gsub KEY_IDENTIFIER, ''
142
+ model.belongs_to field_name, :foreign_key => description[:key], :class_name => description[:class].name
143
+ puts " - belongs_to :#{field_name}, :foreign_key => #{description[:key]}, :class_name => #{description[:class].name}"
144
+ end
145
+
146
+ def add_has_many_behaviour(model, description)
147
+ field_name = description[:class].list_name
148
+ model.has_many field_name, :class_name => description[:class].name
149
+ puts " - has_many :#{field_name}, :class_name => #{description[:class].name}"
150
+ end
151
+
152
+ def add_has_many_through_behaviour(model, description)
153
+ puts " - has_many #{description[:class]} through #{description[:middle_class]}"
154
+ end
155
+
156
+
157
+ def add_has_one_behaviour(model, description)
158
+ field_name = description[:class].list_name.singularize
159
+ model.has_one field_name, :class_name => description[:class].name
160
+ puts " - has_one :#{field_name}, :class_name => #{description[:class].name}"
161
+ end
162
+
163
+ end
@@ -0,0 +1,56 @@
1
+ require 'active_record'
2
+
3
+ class DynamicModel::TablesAnalyser
4
+
5
+ attr_reader :domain, :klasses_analysed
6
+
7
+ def initialize(domain, base_class = ActiveRecord::Base)
8
+ @domain = domain
9
+ @base_class = base_class
10
+ define_domain_module
11
+ @klasses_analysed = []
12
+ end
13
+
14
+ def scan_database
15
+ # Introspect database tables and creates ActiveRecord descendants in the name space module
16
+ @domain_module.table_names.map do |table_name|
17
+ inject_class table_name
18
+ end
19
+ @domain_module.model_classes
20
+ end
21
+
22
+ private
23
+
24
+
25
+ def inject_class(table_name)
26
+ short_model_name = table_name.gsub(/#{@domain_module.prefix}_/, '').singularize.camelize
27
+ klass = nil
28
+ if @domain_module.constants.include? short_model_name.to_sym
29
+ klass = @domain_module.const_get short_model_name
30
+ puts "Found #{klass.name} that already handles #{table_name}"
31
+ else
32
+ klass = @domain_module.const_set short_model_name, Class.new(@base_class)
33
+ puts "Created #{klass.name} to handle #{table_name}"
34
+ # Adds some class methods
35
+ klass.send :include, DynamicModel::ActiveRecordExtension
36
+ end
37
+
38
+ # Maps the class to the correct table
39
+ klass.table_name = table_name
40
+ # Adds attributes accessible for mass assign
41
+ klass.attr_accessible *(klass.attribute_names - [klass.primary_key])
42
+ end
43
+
44
+ def define_domain_module
45
+ domain_name = @domain.singularize.camelize
46
+ @domain_module = nil
47
+ if DynamicModel::ManagedDomains.constants.include? domain_name.to_sym
48
+ @domain_module = DynamicModel::ManagedDomains.const_get domain_name
49
+ else
50
+ @domain_module = DynamicModel::ManagedDomains.const_set(domain_name, Module.new)
51
+ @domain_module.extend DynamicModel::DomainExtension
52
+ end
53
+ end
54
+
55
+
56
+ end
@@ -0,0 +1,31 @@
1
+ require 'active_record'
2
+
3
+ module DynamicModel
4
+
5
+ # Creates ActiveRecord::Base descendants from the database.
6
+ # ActiveRecord descendant classes are dynamically created from database introspection in their own namespace
7
+ # (DynamicModel::<NameSpace>::) The name of the module NameSpace is derived from table_prefix.
8
+ def self.introspect_database(table_prefix = :user_defined, base_class = ActiveRecord::Base)
9
+ table_prefix = table_prefix.to_s
10
+ @domain_analyser ||= {}
11
+
12
+ # Confines Activerecord classes into a module named from table_prefix
13
+ @domain_analyser[table_prefix] ||= DynamicModel::TablesAnalyser.new table_prefix, base_class
14
+ klasses = @domain_analyser[table_prefix].scan_database
15
+ relation_analyser = RelationsAnalyser.new klasses
16
+ relation_analyser.run
17
+ end
18
+
19
+ # Creates a new table with auto numbered id in the database with the name prefix provided
20
+ # by creating a live migration.
21
+ # If block is provided it will behave like create_table method for migrations, allowing
22
+ # to create any other column.
23
+ def self.add_table(scoped_table_name, table_prefix: :user_defined, &block)
24
+ scoped_table_name = scoped_table_name.to_s
25
+ table_prefix = table_prefix.to_s
26
+ real_table_name = scoped_table_name.underscore.pluralize
27
+ Migration::create_with "#{table_prefix}_#{real_table_name}", &block
28
+ end
29
+
30
+
31
+ end
@@ -0,0 +1,3 @@
1
+ module DatabaseIntrospection
2
+ VERSION = "0.0.9"
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'database_introspection/version'
2
+ require 'database_introspection/dynamic_model'
3
+ require 'database_introspection/dynamic_model/active_record_extension'
4
+ require 'database_introspection/dynamic_model/domain_extension'
5
+ require 'database_introspection/dynamic_model/managed_domains'
6
+ require 'database_introspection/dynamic_model/tables_analyser'
7
+ require 'database_introspection/dynamic_model/relations_analyser'
8
+ require 'database_introspection/dynamic_model/migration'
9
+
10
+
11
+ module DatabaseIntrospection
12
+ # Your code goes here...
13
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: database_introspection
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.9
5
+ platform: ruby
6
+ authors:
7
+ - L.Briais
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: activemodel
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 3.2.13
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 3.2.13
55
+ - !ruby/object:Gem::Dependency
56
+ name: activerecord
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 3.2.13
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: 3.2.13
69
+ - !ruby/object:Gem::Dependency
70
+ name: activeresource
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: 3.2.13
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: 3.2.13
83
+ - !ruby/object:Gem::Dependency
84
+ name: activesupport
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: 3.2.13
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 3.2.13
97
+ description: This gem will generate classes (by default ActiveRecord::Base descendants)
98
+ from database introspection
99
+ email:
100
+ - lbnetid+rb@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - .gitignore
106
+ - Gemfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - database_introspection.gemspec
111
+ - lib/database_introspection.rb
112
+ - lib/database_introspection/dynamic_model.rb
113
+ - lib/database_introspection/dynamic_model/active_record_extension.rb
114
+ - lib/database_introspection/dynamic_model/domain_extension.rb
115
+ - lib/database_introspection/dynamic_model/managed_domains.rb
116
+ - lib/database_introspection/dynamic_model/migration.rb
117
+ - lib/database_introspection/dynamic_model/relations_analyser.rb
118
+ - lib/database_introspection/dynamic_model/tables_analyser.rb
119
+ - lib/database_introspection/version.rb
120
+ homepage: https://github.com/lbriais/database_introspection
121
+ licenses:
122
+ - MIT
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubyforge_project:
140
+ rubygems_version: 2.0.0.rc.2
141
+ signing_key:
142
+ specification_version: 4
143
+ summary: Database Introspection
144
+ test_files: []
145
+ has_rdoc: