perpetuity 0.6.2 → 0.7.0

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: f8013375d75e8b9cdc7a171ff15c51624709b3ba
4
+ data.tar.gz: 5f2a8546b037800548e2ec5588302552ba09323d
5
+ SHA512:
6
+ metadata.gz: fbdf6dc761c95fffa557e4a430f0b711cd52bbedf1aecf8e85200d9287bd385f27620c7c61606597dc51044312929d4576ac063a9ecde7c223c087e6b2438851
7
+ data.tar.gz: 101f30e6be3207d717dc3e0d2cfbbf27b20793fc6550c2bdd2c998cd34175444eb68a3acc54443c35535950709f3a25b28c256bb201809237cd98fa97067c70f
data/.travis.yml CHANGED
@@ -3,7 +3,6 @@ rvm:
3
3
  - 1.9.3
4
4
  - rbx-19mode
5
5
  - jruby-19mode
6
- - ruby-head
7
6
  - 2.0.0
8
7
  services:
9
8
  - mongodb
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## Version 0.7.0
2
+
3
+ - Add `Perpetuity::RailsModel`, an ActiveModel-compliant mixin
4
+ - Check Rails app directory for mappers dynamically if the mapper registry is missing a particular model class
5
+
1
6
  ## Version 0.6.2
2
7
 
3
8
  - Make sure `Retrieval#first` limits the query to a single item
data/README.md CHANGED
@@ -27,7 +27,10 @@ Perpetuity.data_source :mongodb, 'my_database'
27
27
  If your database is on another server or you need authentication, you can specify those as options:
28
28
 
29
29
  ```ruby
30
- Perpetuity.data_source :mongodb, 'my_database', host: 'mongo.example.com', port: 27017, username: 'mongo', password: 'password'
30
+ Perpetuity.data_source :mongodb, 'my_database', host: 'mongo.example.com',
31
+ port: 27017,
32
+ username: 'mongo',
33
+ password: 'password'
31
34
  ```
32
35
 
33
36
  ## Setting up object mappers
@@ -210,6 +213,30 @@ Perpetuity[Article].reindex!
210
213
 
211
214
  You could put this in a rake task to be executed when you deploy your app.
212
215
 
216
+ ## Rails Integration
217
+
218
+ Let's face it, most Ruby apps run on Rails, so we need to be able to support it. Beginning with 0.7.0, Perpetuity automatically detects Rails when you configure it and will load Rails support at that point.
219
+
220
+ ### Dynamic mapper reloading
221
+
222
+ Previous versions of Perpetuity would break when Rails reloaded your models in development mode due to class objects being different. It now reloads mappers dynamically based on whether the class has been reloaded.
223
+
224
+ In order for this to work, your mapper files need to be named `*_mapper.rb` and be stored anywhere inside your project's `app` directory.
225
+
226
+ ### ActiveModel-compliant API
227
+
228
+ Perpetuity deals with POROs just fine but Rails does not. This is why you have to include `ActiveModel::Model` in your objects that you want to pass to various Rails methods (such as `redirect_to`, `form_for` and `render`).
229
+
230
+ In your models, including `ActiveModel::Model` in Rails 4 (or the underlying modules in Rails 3) will give you the API that Rails expects but that won't work with Perpetuity. For example, ActiveModel assumes an `id` method but your model may not provide it, so instead of including ActiveModel we provide a `RailsModel` mixin.
231
+
232
+ ```ruby
233
+ class Person
234
+ include Perpetuity::RailsModel
235
+ end
236
+ ```
237
+
238
+ This will let Rails know how to talk to your models in the way that Perpetuity handles them.
239
+
213
240
  ## Contributing
214
241
 
215
242
  There are plenty of opportunities to improve what's here and possibly some design decisions that need some more refinement. You can help. If you have ideas to build on this, send some love in the form of pull requests, issues or [tweets](http://twitter.com/jamie_gaskins) and I'll do what I can for them.
@@ -1,7 +1,9 @@
1
1
  module Perpetuity
2
2
  class MapperRegistry
3
+ include Enumerable
4
+
3
5
  def initialize
4
- @mappers = Hash.new { |_, klass| raise KeyError, "No mapper for #{klass}" }
6
+ @mappers = Hash.new
5
7
  end
6
8
 
7
9
  def has_mapper? klass
@@ -9,11 +11,30 @@ module Perpetuity
9
11
  end
10
12
 
11
13
  def [] klass
14
+ mapper_class = @mappers.fetch(klass) do
15
+ load_mappers
16
+ unless @mappers.has_key? klass
17
+ raise KeyError, "No mapper for #{klass}"
18
+ end
19
+ end
20
+
12
21
  @mappers[klass].new(self)
13
22
  end
14
23
 
15
24
  def []= klass, mapper
16
25
  @mappers[klass] = mapper
17
26
  end
27
+
28
+ def each &block
29
+ @mappers.each &block
30
+ end
31
+
32
+ def load_mappers
33
+ check_rails_app_for_mappers.each(&method(:load))
34
+ end
35
+
36
+ def check_rails_app_for_mappers
37
+ Dir['app/**/*_mapper.rb']
38
+ end
18
39
  end
19
40
  end
@@ -0,0 +1 @@
1
+ require 'perpetuity/rails_model'
@@ -0,0 +1,41 @@
1
+ module Perpetuity
2
+ module RailsModel
3
+ def self.included klass
4
+ klass.extend ActiveModelish
5
+ end
6
+
7
+ def persisted?
8
+ defined? @id
9
+ end
10
+
11
+ def to_param
12
+ @id if persisted?
13
+ end
14
+
15
+ def to_key
16
+ [to_param] if persisted?
17
+ end
18
+
19
+ module ActiveModelish
20
+ def model_name
21
+ self
22
+ end
23
+
24
+ def param_key
25
+ self.to_s.downcase.gsub('::', '_')
26
+ end
27
+
28
+ def route_key
29
+ if defined? ActiveSupport::Inflector
30
+ ActiveSupport::Inflector.pluralize(param_key)
31
+ else
32
+ param_key + 's'
33
+ end
34
+ end
35
+
36
+ def singular_route_key
37
+ param_key
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  module Perpetuity
2
- VERSION = "0.6.2"
2
+ VERSION = "0.7.0"
3
3
  end
data/lib/perpetuity.rb CHANGED
@@ -6,6 +6,7 @@ require "perpetuity/mapper_registry"
6
6
 
7
7
  module Perpetuity
8
8
  def self.configure &block
9
+ detect_rails
9
10
  configuration.instance_exec(&block)
10
11
  end
11
12
 
@@ -32,4 +33,9 @@ module Perpetuity
32
33
 
33
34
  configure { data_source adapters[adapter].new(options.merge(db: db_name)) }
34
35
  end
36
+
37
+ # Necessary to be able to check whether Rails is loaded and initialized
38
+ def self.detect_rails
39
+ require File.expand_path('../perpetuity/rails.rb', __FILE__) if defined? Rails
40
+ end
35
41
  end
data/perpetuity.gemspec CHANGED
@@ -18,6 +18,6 @@ Gem::Specification.new do |s|
18
18
 
19
19
  # specify any dependencies here; for example:
20
20
  s.add_development_dependency "rake"
21
- s.add_development_dependency "rspec", "~> 2.8.0"
21
+ s.add_development_dependency "rspec", "~> 2.13"
22
22
  s.add_runtime_dependency "moped"
23
23
  end
@@ -12,5 +12,23 @@ module Perpetuity
12
12
  it 'maps classes to instances of their mappers' do
13
13
  registry[Object].should be_a mapper
14
14
  end
15
+
16
+ it 'raises a KeyError when trying to find a mapper for a missing class' do
17
+ expect { registry[Class] }.to raise_error KeyError, 'No mapper for Class'
18
+ end
19
+
20
+ describe 'searching for specified mapper when it is not in the registry' do
21
+ let(:mapper_file) { 'app/mappers/status_mapper.rb' }
22
+
23
+ before do
24
+ stub_const 'Status', Class.new
25
+ end
26
+
27
+ it 'loads the definition for the specified mapper class' do
28
+ Dir.should_receive(:[]).with('app/**/*_mapper.rb') { [mapper_file] }
29
+ registry.should_receive(:load).with(mapper_file)
30
+ registry.load_mappers
31
+ end
32
+ end
15
33
  end
16
34
  end
@@ -0,0 +1,51 @@
1
+ require 'perpetuity/rails_model'
2
+
3
+ module Perpetuity
4
+ describe RailsModel do
5
+ let(:klass) do
6
+ Class.new do
7
+ include Perpetuity::RailsModel
8
+ attr_accessor :id
9
+ end
10
+ end
11
+ let(:object) { klass.new }
12
+ let(:wrapper) { object.to_model }
13
+
14
+ it 'determines whether it is persisted based on @id ivar' do
15
+ object.should_not be_persisted
16
+ object.id = 'lol'
17
+ object.should be_persisted
18
+ end
19
+
20
+ it 'returns the id as to_param' do
21
+ object.to_param.should == nil
22
+ object.id = 'foo'
23
+ object.to_param.should == 'foo'
24
+ end
25
+
26
+ it 'returns the keys on the object' do
27
+ object.to_key.should == nil
28
+ object.id = 'bar'
29
+ object.to_key.should == ['bar']
30
+ end
31
+
32
+ it 'returns the model name' do
33
+ klass.model_name.should == klass
34
+ end
35
+
36
+ it 'returns the param_key' do
37
+ stub_const 'Foo::Bar', klass
38
+ Foo::Bar.param_key.should == 'foo_bar'
39
+ end
40
+
41
+ it 'returns the route_key' do
42
+ stub_const 'Foo::Bar', klass
43
+ Foo::Bar.route_key.should == 'foo_bars'
44
+ end
45
+
46
+ it 'returns the singular_route_key' do
47
+ stub_const 'Foo::Bar', klass
48
+ Foo::Bar.singular_route_key.should == 'foo_bar'
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,33 @@
1
+ module Rails
2
+ def self.application
3
+ @application ||= Application.new
4
+ end
5
+
6
+ class Application
7
+ def config
8
+ @config ||= Configuration.new
9
+ end
10
+ end
11
+
12
+ class Configuration
13
+ def middleware
14
+ @middleware ||= MiddlewareStack.new
15
+ end
16
+ end
17
+
18
+ class MiddlewareStack
19
+ include Enumerable
20
+
21
+ def initialize
22
+ @stack = []
23
+ end
24
+
25
+ def use klass
26
+ @stack << klass
27
+ end
28
+
29
+ def each &block
30
+ @stack.each &block
31
+ end
32
+ end
33
+ end
metadata CHANGED
@@ -1,62 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perpetuity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
5
- prerelease:
4
+ version: 0.7.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jamie Gaskins
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-06-12 00:00:00.000000000 Z
11
+ date: 2013-06-21 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rake
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: rspec
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
31
  - - ~>
36
32
  - !ruby/object:Gem::Version
37
- version: 2.8.0
33
+ version: '2.13'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
38
  - - ~>
44
39
  - !ruby/object:Gem::Version
45
- version: 2.8.0
40
+ version: '2.13'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: moped
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  description: Persistence layer for Ruby objects
@@ -92,6 +85,8 @@ files:
92
85
  - lib/perpetuity/mongodb/query_intersection.rb
93
86
  - lib/perpetuity/mongodb/query_union.rb
94
87
  - lib/perpetuity/mongodb/serializer.rb
88
+ - lib/perpetuity/rails.rb
89
+ - lib/perpetuity/rails_model.rb
95
90
  - lib/perpetuity/reference.rb
96
91
  - lib/perpetuity/retrieval.rb
97
92
  - lib/perpetuity/validations.rb
@@ -126,6 +121,7 @@ files:
126
121
  - spec/perpetuity/mongodb/query_spec.rb
127
122
  - spec/perpetuity/mongodb/query_union_spec.rb
128
123
  - spec/perpetuity/mongodb/serializer_spec.rb
124
+ - spec/perpetuity/rails_model_spec.rb
129
125
  - spec/perpetuity/reference_spec.rb
130
126
  - spec/perpetuity/retrieval_spec.rb
131
127
  - spec/perpetuity/validations/length_spec.rb
@@ -133,6 +129,7 @@ files:
133
129
  - spec/perpetuity/validations_spec.rb
134
130
  - spec/perpetuity_spec.rb
135
131
  - spec/spec_helper.rb
132
+ - spec/support/stubbed_rails.rb
136
133
  - spec/support/test_classes.rb
137
134
  - spec/support/test_classes/article.rb
138
135
  - spec/support/test_classes/book.rb
@@ -145,27 +142,26 @@ files:
145
142
  - spec/support/test_classes/user.rb
146
143
  homepage: https://github.com/jgaskins/perpetuity.git
147
144
  licenses: []
145
+ metadata: {}
148
146
  post_install_message:
149
147
  rdoc_options: []
150
148
  require_paths:
151
149
  - lib
152
150
  required_ruby_version: !ruby/object:Gem::Requirement
153
- none: false
154
151
  requirements:
155
- - - ! '>='
152
+ - - '>='
156
153
  - !ruby/object:Gem::Version
157
154
  version: '0'
158
155
  required_rubygems_version: !ruby/object:Gem::Requirement
159
- none: false
160
156
  requirements:
161
- - - ! '>='
157
+ - - '>='
162
158
  - !ruby/object:Gem::Version
163
159
  version: '0'
164
160
  requirements: []
165
161
  rubyforge_project:
166
- rubygems_version: 1.8.24
162
+ rubygems_version: 2.0.3
167
163
  signing_key:
168
- specification_version: 3
164
+ specification_version: 4
169
165
  summary: Persistence library allowing serialization of Ruby objects
170
166
  test_files:
171
167
  - spec/integration/associations_spec.rb
@@ -194,6 +190,7 @@ test_files:
194
190
  - spec/perpetuity/mongodb/query_spec.rb
195
191
  - spec/perpetuity/mongodb/query_union_spec.rb
196
192
  - spec/perpetuity/mongodb/serializer_spec.rb
193
+ - spec/perpetuity/rails_model_spec.rb
197
194
  - spec/perpetuity/reference_spec.rb
198
195
  - spec/perpetuity/retrieval_spec.rb
199
196
  - spec/perpetuity/validations/length_spec.rb
@@ -201,6 +198,7 @@ test_files:
201
198
  - spec/perpetuity/validations_spec.rb
202
199
  - spec/perpetuity_spec.rb
203
200
  - spec/spec_helper.rb
201
+ - spec/support/stubbed_rails.rb
204
202
  - spec/support/test_classes.rb
205
203
  - spec/support/test_classes/article.rb
206
204
  - spec/support/test_classes/book.rb