correspondence 0.0.1
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/.gitignore +4 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/correspondence.gemspec +26 -0
- data/lib/correspondence.rb +7 -0
- data/lib/correspondence/version.rb +3 -0
- data/lib/correspondence/with.rb +29 -0
- data/lib/correspondence/with/many_proxy.rb +10 -0
- data/lib/correspondence/with/one_proxy.rb +15 -0
- data/lib/correspondence/with/proxy.rb +39 -0
- data/spec/correspondence/with/many_proxy_spec.rb +6 -0
- data/spec/correspondence/with/one_proxy_spec.rb +16 -0
- data/spec/correspondence/with/proxy_spec.rb +36 -0
- data/spec/correspondence/with_spec.rb +29 -0
- data/spec/correspondence_spec.rb +9 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/basics.rb +10 -0
- data/spec/support/profile.rb +2 -0
- data/spec/support/test_proxy.rb +5 -0
- data/spec/support/user.rb +7 -0
- metadata +145 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use --create default@correspondence
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#Correspondence
|
2
|
+
####Next generation associations
|
3
|
+
|
4
|
+
##Todo
|
5
|
+
* `one` associations<br/>
|
6
|
+
Support defining a class and method to find associated object
|
7
|
+
* `many` assocations<br/>
|
8
|
+
Support defining a class and finding multiple related objects
|
9
|
+
* Arbitrary item `many` associations<br/>
|
10
|
+
Support finding N arbitrary objects related to the querying object
|
11
|
+
* Automagically inferring inverse relationships.
|
12
|
+
|
13
|
+
##Usage
|
14
|
+
class User
|
15
|
+
corresponds_with :profile
|
16
|
+
end
|
17
|
+
|
18
|
+
This will create a `profile` method on any instance of the user class. By
|
19
|
+
default the `profile` method will call `Profile.find(id)` where `id` is a
|
20
|
+
method on the user class.
|
21
|
+
|
22
|
+
###Options
|
23
|
+
* `:class_name` specify a string for the association class name.
|
24
|
+
* `:class` allows specifying a string, class, symbol or proc. Symbols must be
|
25
|
+
class methods on the associating class, procs should resolve to the
|
26
|
+
association class.
|
27
|
+
* `:on` a symbol or string specifying the method that should be called on the
|
28
|
+
associating class as a reference to the association. Defaults to `:id`.
|
29
|
+
* `:using` a symbol or string that is the method that will be called on the
|
30
|
+
association call. This method will be passed the results of `:on`. Defaults
|
31
|
+
to `:find`.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "correspondence/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "correspondence"
|
7
|
+
s.version = Correspondence::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Adam Hunter", "Ben Vandgrift"]
|
10
|
+
s.email = ["adamhunter@me.com", "ben@vandgrift.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q[Next generation object associations.]
|
13
|
+
s.description = %q[Associate related ruby objects, like ActiveRecord assocations for arbitrary classes. Useful for polyglot programming across seperate data stores using different Object Mappers.]
|
14
|
+
|
15
|
+
s.add_dependency 'activesupport', '~> 3.0.0'
|
16
|
+
s.add_dependency 'i18n', '~> 0.5'
|
17
|
+
|
18
|
+
s.add_development_dependency 'rspec', '~> 2.5'
|
19
|
+
|
20
|
+
s.rubyforge_project = "correspondence"
|
21
|
+
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
25
|
+
s.require_paths = ["lib"]
|
26
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'correspondence'
|
2
|
+
|
3
|
+
module Correspondence
|
4
|
+
module With
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
extend ActiveSupport::Autoload
|
7
|
+
|
8
|
+
autoload :ManyProxy
|
9
|
+
autoload :OneProxy
|
10
|
+
autoload :Proxy
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def corresponds_with(association, options={}, &block)
|
14
|
+
type = plural_association?(association) ? 'Many' : 'One'
|
15
|
+
correspondences[association.to_sym] = const_get("#{type}Proxy").new(self, association, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def correspondences
|
19
|
+
@correspondences ||= Hash.new
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def plural_association?(association)
|
25
|
+
association.to_s.pluralize == association.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Correspondence
|
2
|
+
module With
|
3
|
+
class Proxy
|
4
|
+
attr_reader :root, :name, :target
|
5
|
+
|
6
|
+
def initialize(root, name, options)
|
7
|
+
@root = root
|
8
|
+
@name = name.to_sym
|
9
|
+
@options = options
|
10
|
+
@target = set_target
|
11
|
+
@options[:on] ||= :id
|
12
|
+
@options[:using] ||= :find
|
13
|
+
create_association
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
def set_target
|
18
|
+
@options[:class] = @options[:class_name] if @options[:class_name]
|
19
|
+
|
20
|
+
if @options[:class].is_a?(Class)
|
21
|
+
@options[:class]
|
22
|
+
elsif @options[:class].is_a?(String)
|
23
|
+
@options[:class].constantize
|
24
|
+
elsif @options[:class].is_a?(Symbol)
|
25
|
+
root.send(@options[:class])
|
26
|
+
elsif @options[:class].respond_to?(:call)
|
27
|
+
@options[:class].call
|
28
|
+
else
|
29
|
+
@name.to_s.classify.constantize
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_association
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Correspondence::With::OneProxy do
|
4
|
+
before :all do
|
5
|
+
Bar.corresponds_with :foo
|
6
|
+
end
|
7
|
+
|
8
|
+
after :all do
|
9
|
+
Bar.instance_variable_set(:@correspondences, {})
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should add the associated method to the associating class" do
|
13
|
+
Bar.new.should respond_to(:foo)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Correspondence::With::Proxy do
|
4
|
+
|
5
|
+
it "should assume the target is association name" do
|
6
|
+
proxy = TestProxy.new(Bar, :foo, {})
|
7
|
+
proxy.target.should eq(Foo)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should allow specifiying the target's class_name" do
|
11
|
+
proxy = TestProxy.new(Bar, :foo, {:class_name => 'Box'})
|
12
|
+
proxy.target.should eq(Box)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should allow specifiying the target's class" do
|
16
|
+
proxy = TestProxy.new(Bar, :foo, {:class => Foo})
|
17
|
+
proxy.target.should eq(Foo)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should allow using a string to specify the target's class" do
|
21
|
+
proxy = TestProxy.new(Bar, :foo, {:class => 'Foo'})
|
22
|
+
proxy.target.should eq(Foo)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should allow using a proc to specify the target's class" do
|
26
|
+
proxy = TestProxy.new(Bar, :foo, {:class => proc { Foo }})
|
27
|
+
proxy.target.should eq(Foo)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should allow passing a symbol to reference a method to determine the target's class" do
|
31
|
+
proxy = TestProxy.new(Bar, :foo, {:class => :foo_class_name})
|
32
|
+
proxy.target.should eq(Foo)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Correspondence::With do
|
4
|
+
|
5
|
+
describe "creating an association" do
|
6
|
+
it "should instantiate a one association when corresponding with a singular symbol" do
|
7
|
+
Foo.corresponds_with :bar
|
8
|
+
Foo.correspondences[:bar].should be_a(Correspondence::With::OneProxy)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should instantiate a many association when corresponding with a plural symbol" do
|
12
|
+
Bar.corresponds_with :boxes
|
13
|
+
Bar.correspondences[:boxes].should be_a(Correspondence::With::ManyProxy)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should create an assocation with the associated class" do
|
17
|
+
Profile.stub!(:find).with(1).and_return(@profile = mock('Profile', :id => 1))
|
18
|
+
@user = User.new
|
19
|
+
@user.id = 1
|
20
|
+
@user.profile.should eq(@profile)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should assume the default finder method is :find"
|
24
|
+
it "should allow specifiying the :finder_method"
|
25
|
+
it "should assume the default correspondence method is :id"
|
26
|
+
it "should allow specifiying the method to use to correspond to the associated object"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
|
3
|
+
require 'rubygems' # Use the gems path only for the spec suite
|
4
|
+
require 'correspondence'
|
5
|
+
require 'rspec'
|
6
|
+
|
7
|
+
Dir[File.join(File.dirname(__FILE__), "support", "*.rb")].each {|f| require f }
|
8
|
+
|
9
|
+
RSpec.configure do |config|
|
10
|
+
config.mock_with :rspec
|
11
|
+
end
|
12
|
+
|
metadata
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: correspondence
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Adam Hunter
|
14
|
+
- Ben Vandgrift
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2011-03-07 00:00:00 -05:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: activesupport
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 7
|
31
|
+
segments:
|
32
|
+
- 3
|
33
|
+
- 0
|
34
|
+
- 0
|
35
|
+
version: 3.0.0
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: i18n
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 1
|
47
|
+
segments:
|
48
|
+
- 0
|
49
|
+
- 5
|
50
|
+
version: "0.5"
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: rspec
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 9
|
62
|
+
segments:
|
63
|
+
- 2
|
64
|
+
- 5
|
65
|
+
version: "2.5"
|
66
|
+
type: :development
|
67
|
+
version_requirements: *id003
|
68
|
+
description: Associate related ruby objects, like ActiveRecord assocations for arbitrary classes. Useful for polyglot programming across seperate data stores using different Object Mappers.
|
69
|
+
email:
|
70
|
+
- adamhunter@me.com
|
71
|
+
- ben@vandgrift.com
|
72
|
+
executables: []
|
73
|
+
|
74
|
+
extensions: []
|
75
|
+
|
76
|
+
extra_rdoc_files: []
|
77
|
+
|
78
|
+
files:
|
79
|
+
- .gitignore
|
80
|
+
- .rvmrc
|
81
|
+
- Gemfile
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- correspondence.gemspec
|
85
|
+
- lib/correspondence.rb
|
86
|
+
- lib/correspondence/version.rb
|
87
|
+
- lib/correspondence/with.rb
|
88
|
+
- lib/correspondence/with/many_proxy.rb
|
89
|
+
- lib/correspondence/with/one_proxy.rb
|
90
|
+
- lib/correspondence/with/proxy.rb
|
91
|
+
- spec/correspondence/with/many_proxy_spec.rb
|
92
|
+
- spec/correspondence/with/one_proxy_spec.rb
|
93
|
+
- spec/correspondence/with/proxy_spec.rb
|
94
|
+
- spec/correspondence/with_spec.rb
|
95
|
+
- spec/correspondence_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
- spec/support/basics.rb
|
98
|
+
- spec/support/profile.rb
|
99
|
+
- spec/support/test_proxy.rb
|
100
|
+
- spec/support/user.rb
|
101
|
+
has_rdoc: true
|
102
|
+
homepage: ""
|
103
|
+
licenses: []
|
104
|
+
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
hash: 3
|
116
|
+
segments:
|
117
|
+
- 0
|
118
|
+
version: "0"
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
none: false
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
hash: 3
|
125
|
+
segments:
|
126
|
+
- 0
|
127
|
+
version: "0"
|
128
|
+
requirements: []
|
129
|
+
|
130
|
+
rubyforge_project: correspondence
|
131
|
+
rubygems_version: 1.5.2
|
132
|
+
signing_key:
|
133
|
+
specification_version: 3
|
134
|
+
summary: Next generation object associations.
|
135
|
+
test_files:
|
136
|
+
- spec/correspondence/with/many_proxy_spec.rb
|
137
|
+
- spec/correspondence/with/one_proxy_spec.rb
|
138
|
+
- spec/correspondence/with/proxy_spec.rb
|
139
|
+
- spec/correspondence/with_spec.rb
|
140
|
+
- spec/correspondence_spec.rb
|
141
|
+
- spec/spec_helper.rb
|
142
|
+
- spec/support/basics.rb
|
143
|
+
- spec/support/profile.rb
|
144
|
+
- spec/support/test_proxy.rb
|
145
|
+
- spec/support/user.rb
|