spira-active_record_isomorphisms 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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +92 -0
- data/Rakefile +9 -0
- data/lib/spira/active_record_isomorphisms.rb +138 -0
- data/lib/spira/active_record_isomorphisms/version.rb +5 -0
- data/spec/integration/active_record_isomorphisms_spec.rb +278 -0
- data/spec/spec_helper.rb +22 -0
- data/spira-active_record_isomorphisms.gemspec +32 -0
- metadata +171 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0b75b9ad3cf7adb031f91a05373bf0296019d140
|
4
|
+
data.tar.gz: 53e8dda10769bb714701e638cbf238bdffe6a256
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da2faa2b2074dd3529bebcf8b1a30e0e7a881a9d6e22d1212b502fa27d84c905c960876f1ef1823b2a5913edcbd9e20b9622689a82f39a1f5c06ffe1e22d3763
|
7
|
+
data.tar.gz: 58627fa43283a7f9d4f65702afdf8a310e89c9793e43a349b1ea7f5fd7a7243abf63ac80dd4822e1e493fa6c027eec13456ad995da3b94dc5bbab003a4368990
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Nicholas Hurden
|
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,92 @@
|
|
1
|
+
# spira-active\_record\_isomorphisms [](https://travis-ci.org/nhurden/spira-active_record_isomorphisms) [](http://badge.fury.io/rb/spira-active_record_isomorphisms)
|
2
|
+
|
3
|
+
Establish isomorphisms between your Spira and ActiveRecord models.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'spira-active_record_isomorphisms'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install spira-active_record_isomorphisms
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### Defining Isomorphisms
|
24
|
+
|
25
|
+
Isomorphisms are established by adding an `isomorphic_with` call to your
|
26
|
+
Spira model declaration. For example, given an ActiveRecord `User` model:
|
27
|
+
```ruby
|
28
|
+
class User < ActiveRecord::Base; end
|
29
|
+
```
|
30
|
+
with `id`, `email` and `encrypted_password` properties, an isomorphic Spira `Person` model can be defined:
|
31
|
+
```ruby
|
32
|
+
class Person < Spira::Base
|
33
|
+
configure base_uri: 'http://example.org/example/people',
|
34
|
+
default_vocabulary: 'http://example.org/example/vocab'
|
35
|
+
|
36
|
+
isomorphic_with :user
|
37
|
+
property :name, predicate: FOAF.name, type: String
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
### Associating Models
|
42
|
+
|
43
|
+
Models can be associated by setting the corresponding attributes:
|
44
|
+
```ruby
|
45
|
+
> bob = Person.for('bob')
|
46
|
+
=> <Person:2202810640 @subject: http://example.org/example/people/bob>
|
47
|
+
> bob.user = User.find(1)
|
48
|
+
=> #<User id: 1, email: "bob@example.com", ...>
|
49
|
+
> bob.user
|
50
|
+
=> #<User id: 1, email: "bob@example.com", ...>
|
51
|
+
> bob.save
|
52
|
+
=> <Person:2202810640 @subject: http://example.org/example/people/bob>
|
53
|
+
> User.find(1).person
|
54
|
+
=> <Person:2202810640 @subject: http://example.org/example/people/bob>
|
55
|
+
> bob.user_id
|
56
|
+
=> 1
|
57
|
+
```
|
58
|
+
|
59
|
+
Note that:
|
60
|
+
|
61
|
+
- A `default_vocabulary` must be set on the Spira model.
|
62
|
+
- The Spira model must be saved before the reverse association can be
|
63
|
+
accessed.
|
64
|
+
- The two classes must have different names.
|
65
|
+
- An id property is added to the Spira model corresponding to the name
|
66
|
+
of the ActiveRecord model (in this case `user_id`).
|
67
|
+
|
68
|
+
### Delegated Attributes
|
69
|
+
|
70
|
+
By default, attributes are delegated in both directions:
|
71
|
+
```ruby
|
72
|
+
> bob = Person.for('bob')
|
73
|
+
=> <Person:2202810640 @subject: http://example.org/example/people/bob>
|
74
|
+
> bob.user = User.find(1)
|
75
|
+
=> #<User id: 1, email: "bob@example.com", ...>
|
76
|
+
> bob.email
|
77
|
+
=> "bob@example.com"
|
78
|
+
> bob.name = 'Bob'
|
79
|
+
=> "Bob"
|
80
|
+
> User.find(1).name
|
81
|
+
=> "Bob"
|
82
|
+
```
|
83
|
+
|
84
|
+
This can be disabled by setting `delegation` to `false`: `isomorphic_with :user, delegation: false`
|
85
|
+
|
86
|
+
## Contributing
|
87
|
+
|
88
|
+
1. Fork it ( https://github.com/nhurden/spira-active\_record\_isomorphisms/fork )
|
89
|
+
2. Create your feature branch (`git checkout -b feature/my-new-feature`)
|
90
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
91
|
+
4. Push to the branch (`git push origin feature/my-new-feature`)
|
92
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
2
|
+
require 'active_support/core_ext/object/try'
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
4
|
+
require 'spira/active_record_isomorphisms/version'
|
5
|
+
|
6
|
+
module Spira
|
7
|
+
module ActiveRecordIsomorphisms
|
8
|
+
class NoDefaultVocabularyError < StandardError; end
|
9
|
+
class IsomorphismAlreadyDefinedError < StandardError; end
|
10
|
+
class TypeMismatchError < StandardError; end
|
11
|
+
|
12
|
+
def self.included(model)
|
13
|
+
model.extend ClassMethods
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
# Define an isomorphism between a Spira model and an ActiveRecord model.
|
18
|
+
# @param [Symbol] ar_name The name of the ActiveRecord model in snake_case
|
19
|
+
# @option opts [Boolean] :delegation (true) Enable/disable delegation of attributes
|
20
|
+
# @raise [NoDefaultVocabularyError] if there is no default vocabulary set
|
21
|
+
# @raise [IsomorphismAlreadyDefinedError] if this isomorphism is already defined
|
22
|
+
def isomorphic_with(ar_name, opts = {})
|
23
|
+
raise NoDefaultVocabularyError, 'A default vocabulary must be set.' unless default_vocabulary
|
24
|
+
|
25
|
+
# Define the foreign key property
|
26
|
+
id_sym = id_getter(ar_name)
|
27
|
+
if properties.keys.include? id_sym.to_s
|
28
|
+
raise IsomorphismAlreadyDefinedError,
|
29
|
+
"An isomorphism with #{ar_name} has already been established or the property #{id_sym} is already in use."
|
30
|
+
end
|
31
|
+
property id_sym, type: Spira::Types::Integer
|
32
|
+
|
33
|
+
opts.reverse_merge!({ delegation: true })
|
34
|
+
|
35
|
+
ar_class = model_class_for_sym(ar_name)
|
36
|
+
define_spira_methods(ar_name, ar_class)
|
37
|
+
define_active_record_methods(ar_name, ar_class)
|
38
|
+
|
39
|
+
if opts[:delegation]
|
40
|
+
define_spira_attr_delegations(ar_name, ar_class)
|
41
|
+
define_active_record_attr_delegations(ar_name, ar_class)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def append_to_symbol(symbol, suffix)
|
48
|
+
(symbol.to_s + suffix).to_sym
|
49
|
+
end
|
50
|
+
|
51
|
+
def setter(name)
|
52
|
+
append_to_symbol(name, '=')
|
53
|
+
end
|
54
|
+
|
55
|
+
def id_getter(name)
|
56
|
+
append_to_symbol(name, '_id')
|
57
|
+
end
|
58
|
+
|
59
|
+
def id_setter(name)
|
60
|
+
append_to_symbol(name, '_id=')
|
61
|
+
end
|
62
|
+
|
63
|
+
def define_spira_methods(ar_name, ar_class)
|
64
|
+
# Get the ActiveRecord model from the Spira model
|
65
|
+
id_getter_name = id_getter(ar_name)
|
66
|
+
define_method(ar_name) do
|
67
|
+
id = self.send(id_getter_name)
|
68
|
+
id ? ar_class.find(id) : nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Set the ActiveRecord model on the Spira model
|
72
|
+
id_setter_name = id_setter(ar_name)
|
73
|
+
define_method(setter(ar_name)) do |new_model|
|
74
|
+
if new_model.class == ar_class
|
75
|
+
self.send(id_setter_name, new_model.try(:id))
|
76
|
+
elsif new_model
|
77
|
+
raise TypeMismatchError, "Expected a model of type #{ar_class.name}, but was of type #{new_model.class.name}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def define_active_record_methods(ar_name, ar_class)
|
83
|
+
spira_class = self
|
84
|
+
spira_name = spira_class.name.underscore.to_sym
|
85
|
+
|
86
|
+
# Get the Spira model from the ActiveRecord model by querying the repository
|
87
|
+
ar_class.send(:define_method, spira_name) do
|
88
|
+
predicate = RDF::Vocabulary.new(spira_class.default_vocabulary)["/#{ar_name}_id"]
|
89
|
+
object = RDF::Literal.new(id, datatype: RDF::XSD.integer)
|
90
|
+
model_iri = Spira.repository.query(predicate: predicate, object: object).first.try(:subject)
|
91
|
+
model_iri ? spira_class.for(model_iri) : nil
|
92
|
+
end
|
93
|
+
|
94
|
+
# Set the Spira model on the ActiveRecord model by updating ids on the Spira models
|
95
|
+
id_setter_name = id_setter(ar_name)
|
96
|
+
ar_class.send(:define_method, setter(spira_name)) do |new_model|
|
97
|
+
if new_model.class == spira_class
|
98
|
+
old_model = self.send(spira_name)
|
99
|
+
old_model.send(id_setter_name, nil) if old_model
|
100
|
+
new_model.send(id_setter_name, self.id) if new_model
|
101
|
+
elsif new_model
|
102
|
+
raise TypeMismatchError, "Expected a model of type #{spira_class.name}, but was of type #{new_model.class.name}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Delegate all ActiveRecord attributes, except those already defined on the Spira model
|
108
|
+
def define_spira_attr_delegations(ar_name, ar_class)
|
109
|
+
extend Forwardable
|
110
|
+
|
111
|
+
ar_attr_names = ar_class.attribute_names - properties.keys
|
112
|
+
def_delegators ar_name, *ar_attr_names
|
113
|
+
end
|
114
|
+
|
115
|
+
# Delegate all Spira attributes, except those already defined on the ActiveRecord model
|
116
|
+
def define_active_record_attr_delegations(ar_name, ar_class)
|
117
|
+
ar_class.extend Forwardable
|
118
|
+
|
119
|
+
spira_attr_names = properties.keys - ar_class.attribute_names
|
120
|
+
spira_name = self.name.underscore.to_sym
|
121
|
+
ar_class.def_delegators spira_name, *spira_attr_names
|
122
|
+
end
|
123
|
+
|
124
|
+
# Convert a class name symbol to the corresponding model class
|
125
|
+
def model_class_for_sym(model_sym)
|
126
|
+
begin
|
127
|
+
model_sym.to_s.classify.constantize
|
128
|
+
rescue NameError
|
129
|
+
raise NameError, "Cannot convert :#{model_sym} to a valid model class"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class Base
|
136
|
+
include ActiveRecordIsomorphisms
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,278 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spira::ActiveRecordIsomorphisms do
|
4
|
+
before do
|
5
|
+
Spira.repository = RDF::Repository.new
|
6
|
+
|
7
|
+
Object.send(:remove_const, :User) if defined? User
|
8
|
+
Object.send(:remove_const, :Person) if defined? Person
|
9
|
+
Object.send(:remove_const, :IsomorphicPerson) if defined? IsomorphicPerson
|
10
|
+
|
11
|
+
class User < ActiveRecord::Base; end
|
12
|
+
|
13
|
+
class Person < Spira::Base
|
14
|
+
type FOAF.Person
|
15
|
+
|
16
|
+
configure base_uri: 'http://example.org/example/people',
|
17
|
+
default_vocabulary: 'http://example.org/example/vocab'
|
18
|
+
|
19
|
+
property :name, predicate: FOAF.name, type: String
|
20
|
+
end
|
21
|
+
|
22
|
+
class IsomorphicPerson < Person
|
23
|
+
isomorphic_with :user
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:new_user_bob) { User.create(email: 'bob@example.com') }
|
28
|
+
|
29
|
+
let(:bob_pair) do
|
30
|
+
user_bob = new_user_bob
|
31
|
+
iso_bob = IsomorphicPerson.for('bob')
|
32
|
+
iso_bob.name = 'Bob'
|
33
|
+
iso_bob.user = user_bob
|
34
|
+
iso_bob.save
|
35
|
+
[iso_bob, user_bob]
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "defining isomorphisms" do
|
39
|
+
context "when the ActiveRecord class does not exist" do
|
40
|
+
it "raises an error" do
|
41
|
+
Object.send(:remove_const, :Person) if defined? Person
|
42
|
+
expect {
|
43
|
+
class Person < Spira::Base
|
44
|
+
type FOAF.Person
|
45
|
+
configure default_vocabulary: 'http://example.org/example/vocab'
|
46
|
+
property :name, predicate: FOAF.name, type: String
|
47
|
+
|
48
|
+
isomorphic_with :fake_class
|
49
|
+
end
|
50
|
+
}.to raise_error(NameError, /:fake_class/)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when no default_vocabulary has been set" do
|
55
|
+
it "raises an error" do
|
56
|
+
Object.send(:remove_const, :User) if defined? User
|
57
|
+
Object.send(:remove_const, :Person) if defined? Person
|
58
|
+
expect {
|
59
|
+
class User < ActiveRecord::Base; end
|
60
|
+
class Person < Spira::Base
|
61
|
+
type FOAF.Person
|
62
|
+
property :name, predicate: FOAF.name, type: String
|
63
|
+
|
64
|
+
isomorphic_with :user
|
65
|
+
end
|
66
|
+
}.to raise_error(Spira::ActiveRecordIsomorphisms::NoDefaultVocabularyError)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when the isomorphism has already been defined" do
|
71
|
+
it "raises an error" do
|
72
|
+
Object.send(:remove_const, :User) if defined? User
|
73
|
+
Object.send(:remove_const, :Person) if defined? Person
|
74
|
+
expect {
|
75
|
+
class User < ActiveRecord::Base; end
|
76
|
+
class Person < Spira::Base
|
77
|
+
type FOAF.Person
|
78
|
+
configure default_vocabulary: 'http://example.org/example/vocab'
|
79
|
+
property :name, predicate: FOAF.name, type: String
|
80
|
+
|
81
|
+
isomorphic_with :user
|
82
|
+
isomorphic_with :user
|
83
|
+
end
|
84
|
+
}.to raise_error(Spira::ActiveRecordIsomorphisms::IsomorphismAlreadyDefinedError,
|
85
|
+
"An isomorphism with user has already been established or the property user_id is already in use.")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "persistence" do
|
91
|
+
it "adds a foreign key property to the Spira model when there is an isomorphism" do
|
92
|
+
iso_bob = IsomorphicPerson.for('bob')
|
93
|
+
expect(iso_bob.attributes.keys).to include('user_id')
|
94
|
+
end
|
95
|
+
|
96
|
+
it "does not add a foreign key property to the Spira model when there is no isomorphism" do
|
97
|
+
person_bob = Person.for('bob')
|
98
|
+
expect(person_bob.attributes.keys).to_not include('user_id')
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "when an isomorphism has been established" do
|
103
|
+
describe "setting the associated model" do
|
104
|
+
describe "on the Spira model" do
|
105
|
+
context "with a valid ActiveRecord model" do
|
106
|
+
it "sets the user_id on the Spira model" do
|
107
|
+
iso_bob = IsomorphicPerson.for('bob')
|
108
|
+
user_bob = new_user_bob
|
109
|
+
iso_bob.user = user_bob
|
110
|
+
expect(iso_bob.user_id).to eq(user_bob.id)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context "with an invalid ActiveRecord model" do
|
115
|
+
it "raises an error" do
|
116
|
+
iso_bob = IsomorphicPerson.for('bob')
|
117
|
+
expect { iso_bob.user = "Not a user" }.to raise_error(
|
118
|
+
Spira::ActiveRecordIsomorphisms::TypeMismatchError,
|
119
|
+
"Expected a model of type User, but was of type String")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "on the ActiveRecord model" do
|
125
|
+
context "with a valid Spira model" do
|
126
|
+
it "sets the user_id on the Spira model" do
|
127
|
+
iso_bob = IsomorphicPerson.for('bob')
|
128
|
+
user_bob = new_user_bob
|
129
|
+
user_bob.isomorphic_person = iso_bob
|
130
|
+
expect(iso_bob.user_id).to eq(user_bob.id)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
context "with an invalid Spira model" do
|
135
|
+
it "raises an error" do
|
136
|
+
user_bob = new_user_bob
|
137
|
+
expect { user_bob.isomorphic_person = "Not an person" }.to raise_error(
|
138
|
+
Spira::ActiveRecordIsomorphisms::TypeMismatchError,
|
139
|
+
"Expected a model of type IsomorphicPerson, but was of type String")
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "accessing the associated model" do
|
146
|
+
context "when there is an associated model" do
|
147
|
+
describe "from the Spira model" do
|
148
|
+
it "yields the correct user" do
|
149
|
+
iso_bob, user_bob = bob_pair
|
150
|
+
expect(iso_bob.user).to eq(user_bob)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "from the ActiveRecord model" do
|
155
|
+
it "yields the correct person" do
|
156
|
+
iso_bob, user_bob = bob_pair
|
157
|
+
expect(user_bob.isomorphic_person).to eq(iso_bob)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "when there is no associated model" do
|
163
|
+
describe "from the Spira model" do
|
164
|
+
it "yields nil" do
|
165
|
+
iso_bob = IsomorphicPerson.for('bob')
|
166
|
+
expect(iso_bob.user).to be_nil
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "from the ActiveRecord model" do
|
171
|
+
it "yields nil" do
|
172
|
+
user_bob = new_user_bob
|
173
|
+
expect(user_bob.isomorphic_person).to be_nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "accessing delegated properties" do
|
180
|
+
context "when delegation is enabled" do
|
181
|
+
describe "from the Spira model" do
|
182
|
+
it "can access the email property" do
|
183
|
+
iso_bob, user_bob = bob_pair
|
184
|
+
expect(iso_bob.email).to eq(user_bob.email)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "can access the encrypted_password property" do
|
188
|
+
iso_bob, user_bob = bob_pair
|
189
|
+
expect(iso_bob.encrypted_password).to eq(user_bob.encrypted_password)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
describe "from the ActiveRecord model" do
|
194
|
+
it "can access the name property" do
|
195
|
+
iso_bob, user_bob = bob_pair
|
196
|
+
expect(user_bob.name).to eq(iso_bob.name)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context "when delegation is disabled" do
|
202
|
+
before do
|
203
|
+
Object.send(:remove_const, :User) if defined? User
|
204
|
+
Object.send(:remove_const, :IsomorphicPerson) if defined? IsomorphicPerson
|
205
|
+
Object.send(:remove_const, :IsomorphicPersonWithoutDelegation) if defined? IsomorphicPersonWithoutDelegation
|
206
|
+
|
207
|
+
class User < ActiveRecord::Base; end
|
208
|
+
|
209
|
+
class IsomorphicPersonWithoutDelegation < Person
|
210
|
+
isomorphic_with :user, delegation: false
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
let(:bob_pair_without_delegation) do
|
215
|
+
user_bob = new_user_bob
|
216
|
+
iso_bob = IsomorphicPersonWithoutDelegation.for('bob')
|
217
|
+
iso_bob.name = 'Bob'
|
218
|
+
iso_bob.user = user_bob
|
219
|
+
iso_bob.save
|
220
|
+
[iso_bob, user_bob]
|
221
|
+
end
|
222
|
+
|
223
|
+
describe "from the Spira model" do
|
224
|
+
it "cannot access the email property" do
|
225
|
+
iso_bob = bob_pair_without_delegation.first
|
226
|
+
expect { iso_bob.email }.to raise_error(NoMethodError)
|
227
|
+
end
|
228
|
+
|
229
|
+
it "cannot access the encrypted_password property" do
|
230
|
+
iso_bob = bob_pair_without_delegation.first
|
231
|
+
expect { iso_bob.encrypted_password }.to raise_error(NoMethodError)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
describe "from the ActiveRecord model" do
|
236
|
+
it "cannot access the name property" do
|
237
|
+
user_bob = bob_pair_without_delegation.second
|
238
|
+
expect { user_bob.name }.to raise_error(NoMethodError)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
context "when an isomorphism has not been established" do
|
246
|
+
describe "setting associated models" do
|
247
|
+
describe "on the Spira model" do
|
248
|
+
it "raises an error" do
|
249
|
+
person_bob = Person.for('bob')
|
250
|
+
expect { person_bob.user = new_user_bob }.to raise_error(NoMethodError)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "on the ActiveRecord model" do
|
255
|
+
it "raises an error" do
|
256
|
+
user_bob = new_user_bob
|
257
|
+
expect { user_bob.person = Person.for('bob') }.to raise_error(NoMethodError)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
describe "accessing associated models" do
|
263
|
+
describe "from the Spira model" do
|
264
|
+
it "raises an error" do
|
265
|
+
person_bob = Person.for('bob')
|
266
|
+
expect { person_bob.user }.to raise_error(NoMethodError)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
describe "from the ActiveRecord model" do
|
271
|
+
it "raises an error" do
|
272
|
+
user_bob = new_user_bob
|
273
|
+
expect { user_bob.person }.to raise_error(NoMethodError)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'spira'
|
3
|
+
require 'spira/active_record_isomorphisms'
|
4
|
+
|
5
|
+
ActiveRecord::Base.establish_connection adapter: 'sqlite3', database: ':memory:'
|
6
|
+
|
7
|
+
ActiveRecord::Migration.create_table :users do |t|
|
8
|
+
t.string :email, null: false, default: ''
|
9
|
+
t.string :encrypted_password, null: false, default: ''
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
ActiveRecord::Migration.add_index :users, :email, unique: true
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.around do |example|
|
17
|
+
ActiveRecord::Base.transaction do
|
18
|
+
example.run
|
19
|
+
raise ActiveRecord::Rollback
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'spira/active_record_isomorphisms/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "spira-active_record_isomorphisms"
|
8
|
+
spec.version = Spira::ActiveRecordIsomorphisms::VERSION
|
9
|
+
spec.authors = ["Nicholas Hurden"]
|
10
|
+
spec.email = ["git@nhurden.com"]
|
11
|
+
spec.summary = %q{Establish isomorphisms between your Spira and ActiveRecord models.}
|
12
|
+
spec.description = %q{spira-active_record_isomorphisms creates and manages bijections between Spira and ActiveRecord models}
|
13
|
+
spec.homepage = "https://github.com/nhurden/spira-active_record_isomorphisms"
|
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.required_ruby_version = ">= 1.9.3"
|
22
|
+
|
23
|
+
spec.add_runtime_dependency "spira", "~> 0.7"
|
24
|
+
spec.add_runtime_dependency "activerecord", "~> 4.1"
|
25
|
+
spec.add_runtime_dependency "activesupport", "~> 4.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.1"
|
30
|
+
spec.add_development_dependency "sqlite3", "~> 1.3"
|
31
|
+
spec.add_development_dependency "yard", "~> 0.6"
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spira-active_record_isomorphisms
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nicholas Hurden
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: spira
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.7'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.1'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.1'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.1'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: sqlite3
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.3'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.3'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: yard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.6'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.6'
|
125
|
+
description: spira-active_record_isomorphisms creates and manages bijections between
|
126
|
+
Spira and ActiveRecord models
|
127
|
+
email:
|
128
|
+
- git@nhurden.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- ".gitignore"
|
134
|
+
- ".travis.yml"
|
135
|
+
- Gemfile
|
136
|
+
- LICENSE.txt
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- lib/spira/active_record_isomorphisms.rb
|
140
|
+
- lib/spira/active_record_isomorphisms/version.rb
|
141
|
+
- spec/integration/active_record_isomorphisms_spec.rb
|
142
|
+
- spec/spec_helper.rb
|
143
|
+
- spira-active_record_isomorphisms.gemspec
|
144
|
+
homepage: https://github.com/nhurden/spira-active_record_isomorphisms
|
145
|
+
licenses:
|
146
|
+
- MIT
|
147
|
+
metadata: {}
|
148
|
+
post_install_message:
|
149
|
+
rdoc_options: []
|
150
|
+
require_paths:
|
151
|
+
- lib
|
152
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ">="
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: 1.9.3
|
157
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
version: '0'
|
162
|
+
requirements: []
|
163
|
+
rubyforge_project:
|
164
|
+
rubygems_version: 2.2.2
|
165
|
+
signing_key:
|
166
|
+
specification_version: 4
|
167
|
+
summary: Establish isomorphisms between your Spira and ActiveRecord models.
|
168
|
+
test_files:
|
169
|
+
- spec/integration/active_record_isomorphisms_spec.rb
|
170
|
+
- spec/spec_helper.rb
|
171
|
+
has_rdoc:
|