kristjan-st-elsewhere 0.1.6
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.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +64 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/changelog.rdoc +9 -0
- data/kristjan-st-elsewhere.gemspec +53 -0
- data/lib/st-elsewhere.rb +132 -0
- data/tasks/st-elsewhere_tasks.rake +4 -0
- data/test/st-elsewhere_test.rb +92 -0
- data/test/test_helper.rb +8 -0
- metadata +93 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Brian A. Doll
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
=== St. Elsewhere
|
2
|
+
|
3
|
+
An ActiveRecord plugin to support relationships across different databases
|
4
|
+
|
5
|
+
http://emphaticsolutions.com/images/st.elsewhere.jpg
|
6
|
+
|
7
|
+
=== The Scenario
|
8
|
+
|
9
|
+
For a variety of reasons, you might find yourself supporting multiple databases in your Rails application. Maybe you're connecting to a legacy database for a few models. Perhaps you have divided your Rails application into two parts, one database for your online catalog system and another for transactional data. Multiple database connections in Rails is {nothing new.}[http://www.google.com/search?hl=en&source=hp&q=multiple+database+connections+rails&aq=f&oq=&aqi=g4]
|
10
|
+
|
11
|
+
=== The Problem
|
12
|
+
|
13
|
+
While there may be great benefits to connecting to multiple databases in your app, there are also costs. One example is that <b><tt>has_many :children, :through => parent_children</tt></b> may not work.
|
14
|
+
|
15
|
+
If your database connections are available on the same host {you can prefix your ActiveRecord table names with the database name}[http://gist.github.com/239853].
|
16
|
+
|
17
|
+
If your database connections are on two different hosts, no JOINs can save you and you'll need to implement your relationships in code.
|
18
|
+
|
19
|
+
=== The Solution
|
20
|
+
|
21
|
+
St. Elsewhere adds a new class method (<tt>has_many_elsewhere</tt>) to support basic association methods across different database connections for ActiveRecord models.
|
22
|
+
|
23
|
+
Example:
|
24
|
+
|
25
|
+
http://emphaticsolutions.com/images/has_many_elsewhere.png
|
26
|
+
|
27
|
+
class Hospital < AcitveRecord::Base
|
28
|
+
has_many :hospital_doctors
|
29
|
+
has_many_elsewhere :doctors, :through => :hospital_doctors
|
30
|
+
end
|
31
|
+
|
32
|
+
class HospitalDoctor < ActiveRecord::Base
|
33
|
+
belongs_to :hospital
|
34
|
+
belongs_to :doctor
|
35
|
+
end
|
36
|
+
|
37
|
+
class TransactionalBase < ActiveRecord::Base
|
38
|
+
self.abstract_class = true
|
39
|
+
establish_connection "#{RAILS_ENV}-transactional"
|
40
|
+
end
|
41
|
+
|
42
|
+
class Doctor < TransactionalBase
|
43
|
+
has_many :hospital_doctors
|
44
|
+
has_many :hospitals, :through => :hospital_doctors
|
45
|
+
end
|
46
|
+
|
47
|
+
The following conventional methods are available for Hospital:
|
48
|
+
hospital.doctors, hospital.doctors=, hospital.doctor_ids, hospital.doctor_ids=
|
49
|
+
|
50
|
+
=== Inefficiencies
|
51
|
+
|
52
|
+
<tt>has_many_elsewhere</tt> is certainly much less efficient than a comparable has_many relationship. <tt>has_many :through</tt> relationships use SQL JOINs which while efficient, do not work across multiple database connections. St. Elsewhere implements much of the same resulting API methods in code, using less efficient SQL.
|
53
|
+
|
54
|
+
=== Install from gemcutter
|
55
|
+
|
56
|
+
gem install st-elsewhere
|
57
|
+
|
58
|
+
=== Roadmap
|
59
|
+
|
60
|
+
Currently st-elsewhere is implemented as a basic ruby module that implements some of the basic functionality of has_many :through relationships in ActiveRecord. A much more robust implementation would be to create an ActiveRecord association proxy, like HasManyThroughAssociation, that emulates the same API and could be integrated into the standard has_many class method. I will likely be waiting for Rails 3 to be released (and thus the new base ORM implementation) before attempting the association proxy route.
|
61
|
+
|
62
|
+
=== Thanks
|
63
|
+
|
64
|
+
Thanks to {James Reynolds}[http://drtoast.com/] for the great name and thanks to {Tanner Donovan}[http://github.com/ttdonovan] for patches and being the first production customer.
|
data/Rakefile
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "kristjan-st-elsewhere"
|
8
|
+
gem.summary = %Q{St. Elsewhere supports has_many :through relationships across different databases}
|
9
|
+
gem.description = %Q{This gem provides has_many_elsewhere, an ActiveRecord class method to support many to many relationships in Rails applications, across multiple database connections.}
|
10
|
+
gem.email = ["brian@emphaticsolutions.com", "kristjan@gmail.com"]
|
11
|
+
gem.homepage = "http://github.com/kristjan/st-elsewhere"
|
12
|
+
gem.authors = ["Brian Doll", "Kristján Pétursson"]
|
13
|
+
gem.add_development_dependency "rr", ">= 0"
|
14
|
+
end
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'rake/testtask'
|
21
|
+
Rake::TestTask.new(:test) do |test|
|
22
|
+
test.libs << 'lib' << 'test'
|
23
|
+
test.pattern = 'test/*test.rb'
|
24
|
+
test.verbose = true
|
25
|
+
end
|
26
|
+
|
27
|
+
task :test => :check_dependencies
|
28
|
+
|
29
|
+
task :default => :test
|
30
|
+
|
31
|
+
require 'rake/rdoctask'
|
32
|
+
Rake::RDocTask.new do |rdoc|
|
33
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
34
|
+
|
35
|
+
rdoc.rdoc_dir = 'rdoc'
|
36
|
+
rdoc.title = "st-elsewhere #{version}"
|
37
|
+
rdoc.rdoc_files.include('README*')
|
38
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
39
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.6
|
data/changelog.rdoc
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
0.1.5 "Ed Flanders"
|
2
|
+
- This is the first acceptable production release of st-elsewhere.
|
3
|
+
- Implements:
|
4
|
+
- has_many_elsewhere :association, :through => :through_association
|
5
|
+
- Provides:
|
6
|
+
- ARKlass#associations
|
7
|
+
- ARKlass#association_ids
|
8
|
+
- ARKlass#associations=
|
9
|
+
- ARKlass#association_ids=
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{kristjan-st-elsewhere}
|
8
|
+
s.version = "0.1.6"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Brian Doll", "Kristj\303\241n P\303\251tursson"]
|
12
|
+
s.date = %q{2010-05-26}
|
13
|
+
s.description = %q{This gem provides has_many_elsewhere, an ActiveRecord class method to support many to many relationships in Rails applications, across multiple database connections.}
|
14
|
+
s.email = ["brian@emphaticsolutions.com", "kristjan@gmail.com"]
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"MIT-LICENSE",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"changelog.rdoc",
|
24
|
+
"kristjan-st-elsewhere.gemspec",
|
25
|
+
"lib/st-elsewhere.rb",
|
26
|
+
"tasks/st-elsewhere_tasks.rake",
|
27
|
+
"test/st-elsewhere_test.rb",
|
28
|
+
"test/test_helper.rb"
|
29
|
+
]
|
30
|
+
s.homepage = %q{http://github.com/kristjan/st-elsewhere}
|
31
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
32
|
+
s.require_paths = ["lib"]
|
33
|
+
s.rubygems_version = %q{1.3.7}
|
34
|
+
s.summary = %q{St. Elsewhere supports has_many :through relationships across different databases}
|
35
|
+
s.test_files = [
|
36
|
+
"test/st-elsewhere_test.rb",
|
37
|
+
"test/test_helper.rb"
|
38
|
+
]
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
42
|
+
s.specification_version = 3
|
43
|
+
|
44
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
45
|
+
s.add_development_dependency(%q<rr>, [">= 0"])
|
46
|
+
else
|
47
|
+
s.add_dependency(%q<rr>, [">= 0"])
|
48
|
+
end
|
49
|
+
else
|
50
|
+
s.add_dependency(%q<rr>, [">= 0"])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
data/lib/st-elsewhere.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
module StElsewhere
|
2
|
+
|
3
|
+
# Specifies a one-to-many association across database connections.
|
4
|
+
# This is currently an incomplete implementation and does not yet use all of the options supported by has_many
|
5
|
+
#
|
6
|
+
# The following methods for retrieval and query of collections of associated objects will be added:
|
7
|
+
#
|
8
|
+
# [collection=objects]
|
9
|
+
# Replaces the collections content by deleting and adding objects as appropriate.
|
10
|
+
# [collection_singular_ids]
|
11
|
+
# Returns an array of the associated objects' ids
|
12
|
+
# [collection_singular_ids=ids]
|
13
|
+
# Replace the collection with the objects identified by the primary keys in +ids+
|
14
|
+
# [collection.empty?]
|
15
|
+
# Returns +true+ if there are no associated objects.
|
16
|
+
# [collection.size]
|
17
|
+
# Returns the number of associated objects.
|
18
|
+
#
|
19
|
+
# (*Note*: +collection+ is replaced with the symbol passed as the first argument, so
|
20
|
+
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.)
|
21
|
+
#
|
22
|
+
# === Example
|
23
|
+
#
|
24
|
+
# Example: A Firm class declares <tt>has_many_elsewhere :clients</tt>, which will add:
|
25
|
+
# * <tt>Firm#clients</tt> (similar to <tt>Clients.find :all, :conditions => ["firm_id = ?", id]</tt>)
|
26
|
+
# * <tt>Firm#clients=</tt>
|
27
|
+
# * <tt>Firm#client_ids</tt>
|
28
|
+
# * <tt>Firm#client_ids=</tt>
|
29
|
+
# * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
|
30
|
+
# * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
|
31
|
+
#
|
32
|
+
# === Supported options
|
33
|
+
# [:through]
|
34
|
+
# Specifies a Join Model through which to perform the query. You can only use a <tt>:through</tt> query through a
|
35
|
+
# <tt>belongs_to</tt> <tt>has_one</tt> or <tt>has_many</tt> association on the join model.
|
36
|
+
# [:class_name]
|
37
|
+
# Specifies a the class name to use for the association, rather than
|
38
|
+
# inferring from the association name.
|
39
|
+
#
|
40
|
+
# Option examples:
|
41
|
+
# has_many_elsewhere :subscribers, :through => :subscriptions
|
42
|
+
# has_many_elsewhere :subscribers, :through => :subscriptions, :class_name => 'User'
|
43
|
+
def has_many_elsewhere(association_id, options = {}, &extension)
|
44
|
+
association_class = (options[:class_name] || association_id.to_s).classify.constantize
|
45
|
+
through = options[:through]
|
46
|
+
raise ArgumentError.new("You must include :through => association for has_many_elsewhere") if not through
|
47
|
+
collection_accessor_methods_elsewhere(association_id, association_class, through)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Dynamically adds all accessor methods for the has_many_elsewhere association
|
51
|
+
def collection_accessor_methods_elsewhere(association_id, association_class, through)
|
52
|
+
association_singular = association_id.to_s.singularize
|
53
|
+
association_plural = association_id.to_s
|
54
|
+
through_association_singular = through.to_s.singularize
|
55
|
+
my_class = self
|
56
|
+
my_foreign_key = self.to_s.foreign_key
|
57
|
+
target_association_class = association_class
|
58
|
+
target_association_foreign_key = association_class.to_s.foreign_key
|
59
|
+
|
60
|
+
# Hospital#doctor_ids
|
61
|
+
define_method("#{association_singular}_ids") do
|
62
|
+
self.send("#{association_plural}").map{|a| a.id}
|
63
|
+
end
|
64
|
+
|
65
|
+
# Hospital#doctors
|
66
|
+
define_method("#{association_plural}") do
|
67
|
+
through_class = through.to_s.singularize.camelize.constantize
|
68
|
+
through_association_ids = self.send("#{through.to_s.singularize}_ids")
|
69
|
+
through_associations = through_class.find(through_association_ids)
|
70
|
+
through_associations.collect{|through_association| through_association.send("#{association_singular}")} || []
|
71
|
+
end
|
72
|
+
|
73
|
+
# Hospital#doctors=
|
74
|
+
define_method("#{association_plural}=") do |new_associations|
|
75
|
+
through_class = through.to_s.singularize.camelize.constantize
|
76
|
+
current_associations = self.send("#{association_singular}_ids")
|
77
|
+
desired_associations = self.class.associations_to_association_ids(new_associations)
|
78
|
+
|
79
|
+
removed_target_associations = current_associations - desired_associations
|
80
|
+
new_target_associations = desired_associations - current_associations
|
81
|
+
|
82
|
+
self.send("remove_#{association_singular}_associations", through_class, removed_target_associations)
|
83
|
+
self.send("add_#{association_singular}_associations", through_class, association_id, new_target_associations)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Hospital#doctor_ids=
|
87
|
+
define_method("#{association_singular}_ids=") do |new_association_ids|
|
88
|
+
self.send("#{association_plural}=", new_association_ids)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Hospital#remove_doctor_associations (private)
|
92
|
+
define_method("remove_#{association_singular}_associations") do |through_class, removed_target_associations|
|
93
|
+
association_instances_to_remove =
|
94
|
+
through_class.send("find_all_by_#{my_foreign_key}_and_#{target_association_foreign_key}", self.id, removed_target_associations)
|
95
|
+
through_class.delete(association_instances_to_remove)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Hospital#add_doctor_associations (private)
|
99
|
+
define_method("add_#{association_singular}_associations") do |through_class, association_id, target_association_ids|
|
100
|
+
targets_to_add = target_association_class.find(target_association_ids)
|
101
|
+
targets_to_add.each do |target_association|
|
102
|
+
new_association = through_class.new(my_foreign_key => self.id, target_association_foreign_key => target_association.id)
|
103
|
+
new_association.save
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
private "remove_#{association_singular}_associations".to_sym, "add_#{association_singular}_associations".to_sym
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def associations_to_association_ids(associations)
|
112
|
+
ids = []
|
113
|
+
if associations && !associations.empty?
|
114
|
+
associations.reject!{|a| a.to_s.empty? }
|
115
|
+
association_class = associations.first.class.to_s
|
116
|
+
ids = case association_class
|
117
|
+
when "String"
|
118
|
+
associations.map{|a| a.to_i }
|
119
|
+
when "Fixnum"
|
120
|
+
associations
|
121
|
+
else
|
122
|
+
associations.map{|a| a.id}
|
123
|
+
end
|
124
|
+
end
|
125
|
+
ids
|
126
|
+
end
|
127
|
+
|
128
|
+
private :collection_accessor_methods_elsewhere
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
ActiveRecord::Base.extend StElsewhere
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# These tests are insanely incomplete. Testing a module like this without
|
2
|
+
# depending on an encompasing Rails application is quite difficult. These
|
3
|
+
# tests use mocks on the objects under test, which feels almost useless.
|
4
|
+
# I may consider publishing an accompanyhing Rails application with a test
|
5
|
+
# suite that tests this module in a usable state.
|
6
|
+
|
7
|
+
require 'test_helper'
|
8
|
+
require 'st-elsewhere'
|
9
|
+
|
10
|
+
class Doctor < Struct.new :id, :name
|
11
|
+
end
|
12
|
+
|
13
|
+
class HospitalDoctor < Struct.new :id, :doctor_id, :hospital_id
|
14
|
+
attr_accessor :doctor, :hospital
|
15
|
+
end
|
16
|
+
|
17
|
+
class HospitalDean < Struct.new :id, :dean_id, :hospital_id
|
18
|
+
attr_accessor :dean, :hospital
|
19
|
+
end
|
20
|
+
|
21
|
+
class Hospital < Struct.new :id, :name
|
22
|
+
extend StElsewhere
|
23
|
+
has_many_elsewhere :doctors, :through => :hospital_doctors
|
24
|
+
has_many_elsewhere :deans, :through => :hospital_deans, :class_name => 'Doctor'
|
25
|
+
end
|
26
|
+
|
27
|
+
class StElsewhereTest < Test::Unit::TestCase
|
28
|
+
|
29
|
+
def setup
|
30
|
+
@hospital = Hospital.new
|
31
|
+
@hospital.id = 1
|
32
|
+
@hospital.name = "St. Elsewhere"
|
33
|
+
|
34
|
+
@doctor = Doctor.new
|
35
|
+
@doctor.id = 1
|
36
|
+
@doctor.name = "Dr. Foo"
|
37
|
+
|
38
|
+
@doctor2 = Doctor.new
|
39
|
+
@doctor2.id = 2
|
40
|
+
@doctor2.name = "Dr. Bar"
|
41
|
+
|
42
|
+
@dean = Doctor.new
|
43
|
+
@dean.id = 3
|
44
|
+
@dean.name = "Lida Cuddy"
|
45
|
+
|
46
|
+
@hospital_doctor = HospitalDoctor.new
|
47
|
+
@hospital_doctor.id = 1
|
48
|
+
@hospital_doctor.doctor_id = @doctor.id
|
49
|
+
@hospital_doctor.hospital_id = @hospital.id
|
50
|
+
|
51
|
+
@hospital_doctor2 = HospitalDoctor.new
|
52
|
+
@hospital_doctor2.id = 2
|
53
|
+
@hospital_doctor2.doctor_id = @doctor2.id
|
54
|
+
@hospital_doctor2.hospital_id = @hospital.id
|
55
|
+
|
56
|
+
@hospital_dean = HospitalDean.new
|
57
|
+
@hospital_dean.id = 1
|
58
|
+
@hospital_dean.dean_id = @dean.id
|
59
|
+
@hospital_dean.hospital_id = @hospital.id
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_basic_obj_setup
|
63
|
+
assert "St. Elsewhere".eql?(@hospital.name)
|
64
|
+
assert @hospital.respond_to? :doctors
|
65
|
+
assert @hospital.respond_to? :doctors=
|
66
|
+
assert @hospital.respond_to? :doctor_ids
|
67
|
+
assert @hospital.respond_to? :doctor_ids=
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_basic_functionality
|
71
|
+
mock(@hospital_doctor).doctor {@doctor}
|
72
|
+
mock(@hospital_doctor2).doctor {@doctor2}
|
73
|
+
mock(HospitalDoctor).find([1,2]) {[@hospital_doctor, @hospital_doctor2]}
|
74
|
+
mock(@hospital).hospital_doctor_ids {[@hospital_doctor.id, @hospital_doctor2.id]}
|
75
|
+
|
76
|
+
assert @hospital.doctors.eql?([@doctor, @doctor2])
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_manual_class_name
|
80
|
+
assert @hospital.respond_to? :deans
|
81
|
+
assert @hospital.respond_to? :deans=
|
82
|
+
assert @hospital.respond_to? :dean_ids
|
83
|
+
assert @hospital.respond_to? :dean_ids=
|
84
|
+
|
85
|
+
mock(@hospital_dean).dean {@dean}
|
86
|
+
mock(HospitalDean).find([1]) {[@hospital_dean]}
|
87
|
+
mock(@hospital).hospital_dean_ids {[@hospital_dean.id]}
|
88
|
+
|
89
|
+
assert @hospital.deans.eql?([@dean])
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kristjan-st-elsewhere
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 6
|
10
|
+
version: 0.1.6
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Brian Doll
|
14
|
+
- "Kristj\xC3\xA1n P\xC3\xA9tursson"
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-05-26 00:00:00 -07:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: rr
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 3
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
version: "0"
|
34
|
+
type: :development
|
35
|
+
version_requirements: *id001
|
36
|
+
description: This gem provides has_many_elsewhere, an ActiveRecord class method to support many to many relationships in Rails applications, across multiple database connections.
|
37
|
+
email:
|
38
|
+
- brian@emphaticsolutions.com
|
39
|
+
- kristjan@gmail.com
|
40
|
+
executables: []
|
41
|
+
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files:
|
45
|
+
- README.rdoc
|
46
|
+
files:
|
47
|
+
- MIT-LICENSE
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- changelog.rdoc
|
52
|
+
- kristjan-st-elsewhere.gemspec
|
53
|
+
- lib/st-elsewhere.rb
|
54
|
+
- tasks/st-elsewhere_tasks.rake
|
55
|
+
- test/st-elsewhere_test.rb
|
56
|
+
- test/test_helper.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://github.com/kristjan/st-elsewhere
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --charset=UTF-8
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.3.7
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: St. Elsewhere supports has_many :through relationships across different databases
|
91
|
+
test_files:
|
92
|
+
- test/st-elsewhere_test.rb
|
93
|
+
- test/test_helper.rb
|