schema_associations 0.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,25 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ .*.sw?
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ .rvmrc
23
+ *.log
24
+ *.sqlite3
25
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (c) 2006 RedHill Consulting, Pty. Ltd.
2
+ Copyright (c) 2009 Michal Lomnicki & Ronen Barzel
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ Except as contained in this notice, the name(s) of the above copyright
16
+ holders shall not be used in advertising or otherwise to promote the sale,
17
+ use or other dealings in this Software without prior written authorization.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,89 @@
1
+ = SchemaAssociations
2
+
3
+ == Overview
4
+
5
+ One of the great things about Rails (ActiveRecord, in particular) is that it
6
+ inspects the database and automatically defines accessors for all your
7
+ columns, keeping your model class definitions simple and DRY. That's great
8
+ for simple data columns, but where it falls down is when your table
9
+ contains references to other tables: then the "accessors" you need are the
10
+ +belongs_to+, +has_one+, +has_many+, and +has_and_belongs_to_many+
11
+ associations -- and you need to put them into your model class definitions by hand, which isn't so DRY.
12
+
13
+ Enter the SchemaAssociations gem. It extends ActiveRecord to automatically
14
+ define the appropriate associations based on foreign key constraints in the
15
+ database. SchemaAssociations builds on the
16
+ {+schema_plus+}[http://rubygems.org/gems/schema_plus] gem that
17
+ automatically defines foreign key constraints. So the common case is simple -- if you have this in your migration:
18
+
19
+ create_table :posts do |t|
20
+ end
21
+
22
+ create_table :comments do |t|
23
+ t.integer post_id
24
+ # ... whatever ...
25
+ end
26
+
27
+ Then SchemaAssociations will define the corresponding associations:
28
+
29
+ Post.has_many :comments
30
+ Comment.belongs_to :post
31
+
32
+
33
+ == What if I want something special?
34
+
35
+ You're always free to define associations yourself, if for example you want
36
+ to pass special options. SchemaAssociations won't clobber any existing
37
+ definitions.
38
+
39
+ You can also control the behavior with various options, globally via
40
+ SchemaAssociations.setup or per-model via #schema_associations. See
41
+ SchemaAssociations::Config for the available options.
42
+
43
+ == Full details
44
+
45
+ === The basics
46
+
47
+ === Multiple references
48
+
49
+ === Concise names
50
+
51
+ === How do I know what it did?
52
+
53
+ == Compatibility
54
+
55
+ SchemaAssociations supports all combinations of:
56
+ * rails 3.0 or 3.1
57
+ * MRI ruby 1.8.7 or 1.9.2
58
+
59
+ == Installation
60
+
61
+ Install from http://rubygems.org via
62
+
63
+ $ gem install "schema_associations"
64
+
65
+ or in a Gemfile
66
+
67
+ gem "schema_associations"
68
+
69
+ == History
70
+
71
+ * SchemaAssociations is derived from the "Red Hill On Rails" plugin
72
+ foreign_key_associations originally created by harukizaemon
73
+ (https://github.com/harukizaemon)
74
+
75
+ * SchemaAssociations was created in 2011 by Michal Lomnicki and Ronen Barzel
76
+
77
+ == Testing
78
+
79
+ SchemaAssociations is tested using rspec and sqlite3. To run the tests, after you've forked & cloned:
80
+
81
+ $ cd schema_associations
82
+ $ bundle install
83
+ $ rake spec
84
+
85
+ If you're running ruby 1.9.2, code coverage results will be in coverage/index.html -- it should be at 100% coverage.
86
+
87
+ == License
88
+
89
+ This plugin is released under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,59 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.rspec_opts = '-Ispec'
7
+ end
8
+
9
+
10
+ task :default => :spec
11
+
12
+ require 'rake/rdoctask'
13
+ Rake::RDocTask.new do |rdoc|
14
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
15
+
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = "schema_associations #{version}"
18
+ rdoc.rdoc_files.include('README*')
19
+ rdoc.rdoc_files.include('lib/**/*.rb')
20
+ end
21
+
22
+ namespace :postgresql do
23
+ desc 'Build the PostgreSQL test databases'
24
+ task :build_databases do
25
+ %x( createdb -E UTF8 schema_associations_unittest )
26
+ end
27
+
28
+ desc 'Drop the PostgreSQL test databases'
29
+ task :drop_databases do
30
+ %x( dropdb schema_associations_unittest )
31
+ end
32
+
33
+ desc 'Rebuild the PostgreSQL test databases'
34
+ task :rebuild_databases => [:drop_databases, :build_databases]
35
+ end
36
+
37
+ task :build_postgresql_databases => 'postgresql:build_databases'
38
+ task :drop_postgresql_databases => 'postgresql:drop_databases'
39
+ task :rebuild_postgresql_databases => 'postgresql:rebuild_databases'
40
+
41
+ MYSQL_DB_USER = 'schema_assoc'
42
+ namespace :mysql do
43
+ desc 'Build the MySQL test databases'
44
+ task :build_databases do
45
+ %x( echo "create DATABASE schema_associations_unittest DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_unicode_ci " | mysql --user=#{MYSQL_DB_USER})
46
+ end
47
+
48
+ desc 'Drop the MySQL test databases'
49
+ task :drop_databases do
50
+ %x( mysqladmin --user=#{MYSQL_DB_USER} -f drop schema_associations_unittest )
51
+ end
52
+
53
+ desc 'Rebuild the MySQL test databases'
54
+ task :rebuild_databases => [:drop_databases, :build_databases]
55
+ end
56
+
57
+ task :build_mysql_databases => 'mysql:build_databases'
58
+ task :drop_mysql_databases => 'mysql:drop_databases'
59
+ task :rebuild_mysql_databases => 'mysql:rebuild_databases'
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'schema_associations' unless defined?(SchemaAssociations)
@@ -0,0 +1,223 @@
1
+ require 'ostruct'
2
+
3
+ module SchemaAssociations
4
+ module ActiveRecord
5
+ module Associations #:nodoc:
6
+
7
+ module Relation #:nodoc:
8
+ def self.included(base)
9
+ base.alias_method_chain :initialize, :schema_associations
10
+ end
11
+
12
+ def initialize_with_schema_associations(klass, *args)
13
+ klass.send :_load_schema_associations_associations
14
+ initialize_without_schema_associations(klass, *args)
15
+ end
16
+ end
17
+
18
+ def self.extended(base) #:nodoc:
19
+ class << base
20
+ alias_method_chain :reflect_on_association, :schema_associations
21
+ alias_method_chain :reflect_on_all_associations, :schema_associations
22
+ end
23
+ ::ActiveRecord::Relation.send :include, Relation
24
+ end
25
+
26
+ def reflect_on_association_with_schema_associations(*args) #:nodoc:
27
+ _load_schema_associations_associations
28
+ reflect_on_association_without_schema_associations(*args)
29
+ end
30
+
31
+ def reflect_on_all_associations_with_schema_associations(*args) #:nodoc:
32
+ _load_schema_associations_associations
33
+ reflect_on_all_associations_without_schema_associations(*args)
34
+ end
35
+
36
+ def define_attribute_methods(*args) #:nodoc:
37
+ super
38
+ _load_schema_associations_associations
39
+ end
40
+
41
+ # Per-model override of Config options. Use via, e.g.
42
+ # class MyModel < ActiveRecord::Base
43
+ # schema_associations :auto_create => false
44
+ # end
45
+ def schema_associations(opts)
46
+ @schema_associations_config = SchemaAssociations.config.merge(opts)
47
+ end
48
+
49
+ def schema_associations_config # :nodoc:
50
+ @schema_associations_config ||= SchemaAssociations.config.dup
51
+ end
52
+
53
+ private
54
+
55
+ def _load_schema_associations_associations #:nodoc:
56
+ return if @schema_associations_associations_loaded
57
+ @schema_associations_associations_loaded = true
58
+ return unless schema_associations_config.auto_create?
59
+
60
+ reverse_foreign_keys.each do | foreign_key |
61
+ if foreign_key.table_name =~ /^#{table_name}_(.*)$/ || foreign_key.table_name =~ /^(.*)_#{table_name}$/
62
+ other_table = $1
63
+ if other_table == other_table.pluralize and connection.columns(foreign_key.table_name).any?{|col| col.name == "#{other_table.singularize}_id"}
64
+ _define_association(:has_and_belongs_to_many, foreign_key, other_table)
65
+ else
66
+ _define_association(:has_one_or_many, foreign_key)
67
+ end
68
+ else
69
+ _define_association(:has_one_or_many, foreign_key)
70
+ end
71
+ end
72
+
73
+ foreign_keys.each do | foreign_key |
74
+ _define_association(:belongs_to, foreign_key)
75
+ end
76
+ end
77
+
78
+ def _define_association(macro, fk, referencing_table_name = nil) #:nodoc:
79
+ return unless fk.column_names.size == 1
80
+
81
+ referencing_table_name ||= fk.table_name
82
+
83
+ column_name = fk.column_names.first
84
+ reference_name = column_name.sub(/_id$/, '')
85
+ references_name = fk.references_table_name.singularize
86
+ referencing_name = referencing_table_name.singularize
87
+
88
+ references_class_name = references_name.classify
89
+ referencing_class_name = referencing_name.classify
90
+
91
+ references_concise = _concise_name(references_name, referencing_name)
92
+ referencing_concise = _concise_name(referencing_name, references_name)
93
+
94
+ case reference_name
95
+ when 'parent'
96
+ belongs_to = 'parent'
97
+ belongs_to_concise = 'parent'
98
+
99
+ has_one = 'child'
100
+ has_one_concise = 'child'
101
+
102
+ has_many = 'children'
103
+ has_many_concise = 'children'
104
+
105
+ when references_name
106
+ belongs_to = references_name
107
+ belongs_to_concise = references_concise
108
+
109
+ has_one = referencing_name
110
+ has_one_concise = referencing_concise
111
+
112
+ has_many = referencing_name.pluralize
113
+ has_many_concise = referencing_concise.pluralize
114
+
115
+ when /(.*)_#{references_name}$/, /(.*)_#{references_concise}$/
116
+ label = $1
117
+ belongs_to = "#{label}_#{references_name}"
118
+ belongs_to_concise = "#{label}_#{references_concise}"
119
+
120
+ has_one = "#{referencing_name}_as_#{label}"
121
+ has_one_concise = "#{referencing_concise}_as_#{label}"
122
+
123
+ has_many = "#{referencing_name.pluralize}_as_#{label}"
124
+ has_many_concise = "#{referencing_concise.pluralize}_as_#{label}"
125
+
126
+ when /^#{references_name}_(.*)$/, /^#{references_concise}_(.*)$/
127
+ label = $1
128
+ belongs_to = "#{references_name}_#{label}"
129
+ belongs_to_concise = "#{references_concise}_#{label}"
130
+
131
+ has_one = "#{referencing_name}_as_#{label}"
132
+ has_one_concise = "#{referencing_concise}_as_#{label}"
133
+
134
+ has_many = "#{referencing_name.pluralize}_as_#{label}"
135
+ has_many_concise = "#{referencing_concise.pluralize}_as_#{label}"
136
+
137
+ else
138
+ belongs_to = reference_name
139
+ belongs_to_concise = reference_name
140
+
141
+ has_one = "#{referencing_name}_as_#{reference_name}"
142
+ has_one_concise = "#{referencing_concise}_as_#{reference_name}"
143
+
144
+ has_many = "#{referencing_name.pluralize}_as_#{reference_name}"
145
+ has_many_concise = "#{referencing_concise.pluralize}_as_#{reference_name}"
146
+ end
147
+
148
+ case macro
149
+ when :has_and_belongs_to_many
150
+ name = has_many
151
+ name_concise = has_many_concise
152
+ opts = {:class_name => referencing_class_name, :join_table => fk.table_name, :foreign_key => column_name}
153
+ when :belongs_to
154
+ name = belongs_to
155
+ name_concise = belongs_to_concise
156
+ opts = {:class_name => references_class_name, :foreign_key => column_name}
157
+ when :has_one_or_many
158
+ opts = {:class_name => referencing_class_name, :foreign_key => column_name}
159
+ # use connection.indexes and connection.colums rather than class
160
+ # methods of the referencing class because using the class
161
+ # methods would require getting the class -- which might trigger
162
+ # an autoload which could start some recursion making things much
163
+ # harder to debug.
164
+ if connection.indexes(referencing_table_name, "#{referencing_table_name} Indexes").any?{|index| index.unique && index.columns == [column_name]}
165
+ macro = :has_one
166
+ name = has_one
167
+ name_concise = has_one_concise
168
+ else
169
+ macro = :has_many
170
+ name = has_many
171
+ name_concise = has_many_concise
172
+ if connection.columns(referencing_table_name, "#{referencing_table_name} Columns").any?{ |col| col.name == 'position' }
173
+ opts[:order] = :position
174
+ end
175
+ end
176
+ end
177
+ name = name_concise if _use_concise_name?
178
+ name = name.to_sym
179
+ if (_filter_association(macro, name) && !_method_exists?(name))
180
+ logger.info "[schema_associations] #{self.name || self.table_name.classify}.#{macro} #{name.inspect}, #{opts.inspect[1...-1]}"
181
+ send macro, name, opts.dup
182
+ end
183
+ end
184
+
185
+ def _concise_name(string, other) #:nodoc:
186
+ case
187
+ when string =~ /^#{other}_(.*)$/ then $1
188
+ when string =~ /(.*)_#{other}$/ then $1
189
+ when leader = _common_leader(string,other) then string[leader.length, string.length-leader.length]
190
+ else string
191
+ end
192
+ end
193
+
194
+ def _common_leader(string, other) #:nodoc:
195
+ leader = nil
196
+ other.split('_').each do |part|
197
+ test = "#{leader}#{part}_"
198
+ break unless string.start_with? test
199
+ leader = test
200
+ end
201
+ return leader
202
+ end
203
+
204
+ def _use_concise_name? #:nodoc:
205
+ schema_associations_config.concise_names?
206
+ end
207
+
208
+ def _filter_association(macro, name) #:nodoc:
209
+ config = schema_associations_config
210
+ return false if config.only and not Array.wrap(config.only).include?(name)
211
+ return false if config.except and Array.wrap(config.except).include?(name)
212
+ return false if config.only_type and not Array.wrap(config.only_type).include?(macro)
213
+ return false if config.except_type and Array.wrap(config.except_type).include?(macro)
214
+ return true
215
+ end
216
+
217
+ def _method_exists?(name) #:nodoc:
218
+ method_defined?(name) || private_method_defined?(name) and not (name == :type && [Object, Kernel].include?(instance_method(:type).owner))
219
+ end
220
+
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,9 @@
1
+ module SchemaAssociations
2
+ class Railtie < Rails::Railtie #:nodoc:
3
+
4
+ initializer 'schema_associations.insert', :after => :load_config_initializers do
5
+ SchemaAssociations.insert
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module SchemaAssociations
2
+ VERSION = "0.1.0.pre1"
3
+ end
@@ -0,0 +1,112 @@
1
+ require 'schema_plus'
2
+ require 'valuable'
3
+
4
+ require 'schema_associations/version'
5
+ require 'schema_associations/active_record/associations'
6
+ require 'schema_associations/railtie' if defined?(Rails)
7
+
8
+ module SchemaAssociations
9
+
10
+ # The configuation options for SchemaAssociations. Set them globally in
11
+ # +config/initializers/schema_associations.rb+, e.g.:
12
+ #
13
+ # SchemaAssociations.setup do |config|
14
+ # config.concise_names = false
15
+ # end
16
+ #
17
+ # or override them per-model, e.g.:
18
+ #
19
+ # class MyModel < ActiveRecord::Base
20
+ # schema_associations.config :concise_names => false
21
+ # end
22
+ #
23
+ class Config < Valuable
24
+
25
+ ##
26
+ # :attr_accessor: auto_create
27
+ #
28
+ # Whether to automatically create associations based on foreign keys.
29
+ # Boolean, default is +true+.
30
+ has_value :auto_create, :klass => :boolean, :default => true
31
+
32
+ ##
33
+ # :attr_accessor: concise_names
34
+ #
35
+ # Whether to use concise naming (strip out common prefixes from class names).
36
+ # Boolean, default is +true+.
37
+ has_value :concise_names, :klass => :boolean, :default => true
38
+
39
+ ##
40
+ # :attr_accessor: except
41
+ #
42
+ # List of association names to exclude from automatic creation.
43
+ # Value is a single name, an array of names, or +nil+. Default is +nil+.
44
+ has_value :except, :default => nil
45
+
46
+ ##
47
+ # :attr_accessor: only
48
+ #
49
+ # List of association names to include in automatic creation.
50
+ # Value is a single name, and array of names, or +nil+. Default is +nil+.
51
+ has_value :only, :default => nil
52
+
53
+ ##
54
+ # :attr_accessor: except_type
55
+ #
56
+ # List of association types to exclude from automatic creation.
57
+ # Value is one or an array of +:belongs_to+, +:has_many+, +:has_one+, and/or
58
+ # +:has_and_belongs_to_many+, or +nil+. Default is +nil+.
59
+ has_value :except_type, :default => nil
60
+
61
+ ##
62
+ # :attr_accessor: only_type
63
+ #
64
+ # List of association types to include from automatic creation.
65
+ # Value is one or an array of +:belongs_to+, +:has_many+, +:has_one+, and/or
66
+ # +:has_and_belongs_to_many+, or +nil+. Default is +nil+.
67
+ has_value :only_type, :default => nil
68
+
69
+ def dup #:nodoc:
70
+ self.class.new(Hash[attributes.collect{ |key, val| [key, Valuable === val ? val.class.new(val.attributes) : val] }])
71
+ end
72
+
73
+ def update_attributes(opts)#:nodoc:
74
+ opts = opts.dup
75
+ opts.keys.each { |key| self.send(key).update_attributes(opts.delete(key)) if self.class.attributes.include? key and Hash === opts[key] }
76
+ super(opts)
77
+ self
78
+ end
79
+
80
+ def merge(opts)#:nodoc:
81
+ dup.update_attributes(opts)
82
+ end
83
+
84
+ end
85
+
86
+ # Returns the global configuration, i.e., the singleton instance of Config
87
+ def self.config
88
+ @config ||= Config.new
89
+ end
90
+
91
+ # Initialization block is passed a global Config instance that can be
92
+ # used to configure SchemaAssociations behavior. E.g., if you want to
93
+ # disable automation creation associations put the following in
94
+ # config/initializers/schema_associations.rb :
95
+ #
96
+ # SchemaAssociations.setup do |config|
97
+ # config.auto_create = false
98
+ # end
99
+ #
100
+ def self.setup # :yields: config
101
+ yield config
102
+ end
103
+
104
+ def self.insert #:nodoc:
105
+ return if @inserted
106
+ @inserted = true
107
+ ::ActiveRecord::Base.extend SchemaAssociations::ActiveRecord::Associations
108
+ end
109
+
110
+ end
111
+
112
+ SchemaAssociations.insert unless defined? Rails::Railtie
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "schema_associations/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "schema_associations"
7
+ s.version = SchemaAssociations::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ronen Barzel", "Michał Łomnicki"]
10
+ s.email = ["ronen@barzel.org", "michal.lomnicki@gmail.com"]
11
+ s.homepage = "https://github.com/ronen/schema_associations"
12
+ s.summary = "ActiveRecord extension that automatically (DRY) creates associations based on the schema"
13
+ s.description = "SchemaAssociations extends ActiveRecord to automatically create associations by inspecting the database schema. This is more more DRY than the standard behavior, for which in addition to specifying the foreign key in the migration, you must also specify complementary associations in two model files (e.g. a :belongs_to and a :has_many)."
14
+
15
+ s.rubyforge_project = "schema_associations"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency("schema_plus")
23
+
24
+ s.add_development_dependency("rake", "~> 0.8.7")
25
+ s.add_development_dependency("rails", ">= 3.1.0.rc1")
26
+ s.add_development_dependency("rspec")
27
+ s.add_development_dependency("sqlite3")
28
+ s.add_development_dependency("simplecov")
29
+ s.add_development_dependency("simplecov-gem-adapter")
30
+ s.add_development_dependency("ruby-debug19") if RUBY_VERSION >= "1.9.2"
31
+ end
32
+
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "schema_associations/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "schema_associations"
7
+ s.version = SchemaAssociations::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ronen Barzel", "Michał Łomnicki"]
10
+ s.email = ["ronen@barzel.org", "michal.lomnicki@gmail.com"]
11
+ s.homepage = "https://github.com/ronen/schema_associations"
12
+ s.summary = "ActiveRecord extension that automatically (DRY) creates associations based on the schema"
13
+ s.description = "SchemaAssociations extends ActiveRecord to automatically create associations by inspecting the database schema. This is more more DRY than the standard behavior, for which in addition to specifying the foreign key in the migration, you must also specify complementary associations in two model files (e.g. a :belongs_to and a :has_many)."
14
+
15
+ s.rubyforge_project = "schema_associations"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency("schema_plus")
23
+ s.add_dependency("valuable")
24
+
25
+ s.add_development_dependency("rails", "~> 3.0")
26
+ s.add_development_dependency("rspec")
27
+ s.add_development_dependency("pg")
28
+ s.add_development_dependency("mysql")
29
+ s.add_development_dependency("mysql2", "0.2.6")
30
+ s.add_development_dependency("sqlite3")
31
+ s.add_development_dependency("simplecov")
32
+ s.add_development_dependency("simplecov-gem-adapter")
33
+ s.add_development_dependency("ruby-debug19") if RUBY_VERSION >= "1.9.2"
34
+ end
35
+
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "schema_associations/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "schema_associations"
7
+ s.version = SchemaAssociations::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ronen Barzel", "Michał Łomnicki"]
10
+ s.email = ["ronen@barzel.org", "michal.lomnicki@gmail.com"]
11
+ s.homepage = "https://github.com/ronen/schema_associations"
12
+ s.summary = "ActiveRecord extension that automatically (DRY) creates associations based on the schema"
13
+ s.description = "SchemaAssociations extends ActiveRecord to automatically create associations by inspecting the database schema. This is more more DRY than the standard behavior, for which in addition to specifying the foreign key in the migration, you must also specify complementary associations in two model files (e.g. a :belongs_to and a :has_many)."
14
+
15
+ s.rubyforge_project = "schema_associations"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency("schema_plus")
23
+ s.add_dependency("valuable")
24
+
25
+ s.add_development_dependency("rake", "~> 0.8.7")
26
+ s.add_development_dependency("rails", ">= 3.1.0.rc1")
27
+ s.add_development_dependency("rspec")
28
+ s.add_development_dependency("pg")
29
+ s.add_development_dependency("mysql")
30
+ s.add_development_dependency("mysql2")
31
+ s.add_development_dependency("sqlite3")
32
+ s.add_development_dependency("simplecov")
33
+ s.add_development_dependency("simplecov-gem-adapter")
34
+ s.add_development_dependency("ruby-debug19") if RUBY_VERSION >= "1.9.2"
35
+ end
36
+