remotable 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,3 +2,5 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ coverage
6
+
data/.simplecov ADDED
@@ -0,0 +1,3 @@
1
+ SimpleCov.start do
2
+ end
3
+
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Bob Lail
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.mdown ADDED
@@ -0,0 +1,103 @@
1
+ # Remotable
2
+
3
+ Remotable associates an ActiveRecord model with a remote resource (like an ActiveResource model) and keeps the two synchronized.
4
+
5
+ - When a local record is loaded, Remotable ensures that it is up-to-date.
6
+ - When a local record is requested (by an ActiveRecord `find_by_` method) but not found, Remotable fetches the remote resource and creates a local copy.
7
+ - When a local record is created, updated, or destroyed, Remotable ensures that the corresponding remote resource is created, updated, or destroyed.
8
+
9
+ ## Using Remotable
10
+
11
+ ### Installation
12
+
13
+ Just add the following to your Gemfile:
14
+
15
+ gem "remotable"
16
+
17
+ ### Getting Started
18
+
19
+ **1.** Remotable requires that your local model have an `expires_at` column.
20
+
21
+ class AddExpiresAtToTenants < ActiveRecord::Migration
22
+ def self.up
23
+ add_column :tenants, :expires_at, :timestamp, :null => false
24
+ end
25
+ end
26
+
27
+ **2.** Your local model has to be associated with a remote model: (Let's say `RemoteTenant` is the name of an ActiveResource model.)
28
+
29
+ class Tenant < ActiveRecord::Base
30
+ remote_model RemoteTenant
31
+ end
32
+
33
+
34
+ ### Configuration
35
+
36
+ Specify the attributes of the local model that you want to keep in sync with the remote model. You can also specify mappings by using the hash rocket. The line `:customer_name => :name` tells Remotable to keep `RemoteTenant#customer_name` in sync with `Tenant#name`.
37
+
38
+ class Tenant < ActiveRecord::Base
39
+ remote_model RemoteTenant
40
+ attr_remote :slug,
41
+ :customer_name => :name,
42
+ :id => :remote_id
43
+ end
44
+
45
+ By default Remotable assumes that the local model and remote model are joined with the connection you would express in SQL this way: `local_model INNER JOIN remote_model ON local_model.id=remote_model.id`. But it is generally impractical to join on `local_model.id`.
46
+
47
+ If you specify `attr_remote :id => :remote_id`, then the join will be on `local_model.remote_id=remote_model.id`, but you can also use a different attribute as the join key:
48
+
49
+ class Tenant < ActiveRecord::Base
50
+ remote_model RemoteTenant
51
+ attr_remote :slug,
52
+ :customer_name => :name,
53
+ :id => :remote_id
54
+ remote_key :slug
55
+ end
56
+
57
+ Now, the join could be expressed this way: `local_model.slug=remote_model.slug`.
58
+
59
+ ### Finders
60
+
61
+ For all of the local attributes that you've remoted (`slug`, `name`, and `remote_id` in the example above), the remoted model will respond to custom finders (e.g. `find_by_slug`, `find_by_name`, and `find_by_remote_id`). These finders will _first_ look in the local database for the requested record and, if it isn't found, look for the resource remotely. If a finder finds the resource remotely, it creates a local copy and returns that.
62
+
63
+ Without any further configuration, Remotable will assume the route to for the customer finder from the attribute. For example,
64
+
65
+ find_by_id(...) # Looks in api_path/tenants/:id
66
+ find_by_slug(...) # Looks in api_path/tenants/by_slug/:slug
67
+ find_by_customer_name(...) # Looks in api_path/tenants/by_customer_name/:customer_name
68
+
69
+ You can specify a custom path with the `find_by` method or you can always write an appropriate `find_by_whatever` method on your remote resource.
70
+
71
+ class Tenant < ActiveRecord::Base
72
+ remote_model RemoteTenant
73
+ attr_remote :slug,
74
+ :customer_name => :name,
75
+ :id => :remote_id
76
+ find_by :name, :path => "by_nombre/:name"
77
+ end
78
+
79
+ When you use `find_by`, give the name of the _local_ attribute not the remote one (if they differ). Also, the name of the symbolic part of the path should match the local attribute name as well.
80
+
81
+ ### Expiration
82
+
83
+ Whenever a remoted record is instantiated, Remotable checks the value of its `expires_at` attribute. If the date is in the past, Remotable pulls changes from the remote resource. Whenever a record is saved, `expires_at` is set to a time in the future&mdash;by default, 1 day. You can change how frequently a record expires by setting `expires_after` to a duration:
84
+
85
+ class Tenant < ActiveRecord::Base
86
+ remote_model RemoteTenant
87
+ expires_after 1.hour
88
+ end
89
+
90
+ ### Adapters
91
+
92
+ Remotable checks class you hand to `remote_model` to see what it inherits from. Remotable checks this to use the correct adapter with the remote model. Currently, the only adapter included in Remotable is for ActiveResource::Base.
93
+
94
+ ## Development
95
+
96
+ ### To Do
97
+
98
+ - Add additional adapters
99
+ - Write a generator
100
+
101
+ ### License
102
+
103
+ Remotable is available under the terms of the MIT license.
data/lib/remotable.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "remotable/version"
2
+ require "remotable/nosync"
2
3
 
3
4
 
4
5
  # Remotable keeps a locally-stored ActiveRecord
@@ -28,6 +29,7 @@ require "remotable/version"
28
29
  #
29
30
  #
30
31
  module Remotable
32
+ extend Nosync
31
33
 
32
34
 
33
35
 
@@ -5,6 +5,11 @@ require "active_support/concern"
5
5
  module Remotable
6
6
  module ActiveRecordExtender
7
7
  extend ActiveSupport::Concern
8
+ include Nosync
9
+
10
+ def nosync?
11
+ self.class.nosync? || super
12
+ end
8
13
 
9
14
 
10
15
 
@@ -28,6 +33,11 @@ module Remotable
28
33
 
29
34
 
30
35
  module ClassMethods
36
+ include Nosync
37
+
38
+ def nosync?
39
+ Remotable.nosync? || super
40
+ end
31
41
 
32
42
  def remote_key(*args)
33
43
  if args.any?
@@ -51,13 +61,16 @@ module Remotable
51
61
 
52
62
  def attr_remote(*attrs)
53
63
  map = attrs.extract_options!
54
- map = attrs.map_to_self(map)
64
+ map = attrs.map_to_self.merge(map)
55
65
  @remote_attribute_map = map
66
+
67
+ @remote_attribute_routes = {}
68
+ fetch_with(*local_attribute_names)
56
69
  end
57
70
 
58
- def fetch_with(*args)
59
- keys_and_routes = extract_keys_and_routes(*args)
60
- @remote_attribute_routes.merge!(keys_and_routes)
71
+ def fetch_with(*local_keys)
72
+ remote_keys_and_routes = extract_remote_keys_and_routes(*local_keys)
73
+ @remote_attribute_routes.merge!(remote_keys_and_routes)
61
74
  end
62
75
  alias :find_by :fetch_with
63
76
 
@@ -93,7 +106,11 @@ module Remotable
93
106
 
94
107
  def default_route_for(local_key, remote_key=nil)
95
108
  remote_key ||= remote_attribute_name(local_key)
96
- "by_#{remote_key}/:#{local_key}.json"
109
+ if remote_key.to_s == primary_key
110
+ ":#{local_key}"
111
+ else
112
+ "by_#{remote_key}/:#{local_key}"
113
+ end
97
114
  end
98
115
 
99
116
 
@@ -102,8 +119,10 @@ module Remotable
102
119
  # so you can use the remoted record in associations.
103
120
  def instantiate(*args)
104
121
  record = super
105
- record.pull_remote_data! if record.expired?
106
- record = nil if record.destroyed?
122
+ if record.expired? && !Remotable.nosync?
123
+ record.pull_remote_data!
124
+ record = nil if record.destroyed?
125
+ end
107
126
  record
108
127
  end
109
128
 
@@ -112,7 +131,7 @@ module Remotable
112
131
  def method_missing(method_sym, *args, &block)
113
132
  method_name = method_sym.to_s
114
133
 
115
- if method_name =~ /find_by_(.*)(!?)/
134
+ if method_name =~ /find_by_([^!]*)(!?)/
116
135
  local_attr, bang, value = $1.to_sym, !$2.blank?, args.first
117
136
  remote_attr = remote_attribute_name(local_attr)
118
137
 
@@ -120,11 +139,8 @@ module Remotable
120
139
  # primary key if we're evaluating a finder
121
140
 
122
141
  if remote_attribute_routes.key?(remote_attr)
123
- local_resource = where(local_attr => value).first
124
- unless local_resource
125
- remote_resource = remote_model.find_by(remote_attr, value)
126
- local_resource = new_from_remote(remote_resource) if remote_resource
127
- end
142
+ local_resource = where(local_attr => value).first ||
143
+ fetch_by(remote_attr, value)
128
144
 
129
145
  raise ActiveRecord::RecordNotFound if local_resource.nil? && bang
130
146
  return local_resource
@@ -136,6 +152,22 @@ module Remotable
136
152
 
137
153
 
138
154
 
155
+ def expire_all!
156
+ update_all(["expires_at=?", 1.day.ago])
157
+ end
158
+
159
+
160
+
161
+ # Looks the resource up remotely, by the given attribute
162
+ # If the resource is found, wraps it in a new local resource
163
+ # and returns that.
164
+ def fetch_by(remote_attr, value)
165
+ remote_resource = remote_model.find_by(remote_attr, value)
166
+ remote_resource && new_from_remote(remote_resource)
167
+ end
168
+
169
+
170
+
139
171
  private
140
172
 
141
173
 
@@ -156,7 +188,7 @@ module Remotable
156
188
  end
157
189
 
158
190
 
159
- def extract_keys_and_routes(*local_keys)
191
+ def extract_remote_keys_and_routes(*local_keys)
160
192
  keys_and_routes = local_keys.extract_options!
161
193
  {}.tap do |hash|
162
194
  local_keys.each {|local_key| hash[remote_attribute_name(local_key)] = nil}
@@ -220,28 +252,6 @@ module Remotable
220
252
 
221
253
 
222
254
 
223
- def nosync!
224
- @nosync = true
225
- end
226
-
227
- def nosync
228
- value = @nosync
229
- @nosync = true
230
- yield
231
- ensure
232
- @nosync = value
233
- end
234
-
235
- def nosync=(val)
236
- @nosync = (val == true)
237
- end
238
-
239
- def nosync?
240
- @nosync == true
241
- end
242
-
243
-
244
-
245
255
  private
246
256
 
247
257
  def fetch_remote_resource
@@ -1,4 +1,5 @@
1
1
  require "remotable/active_resource_fixes"
2
+ require "remotable/core_ext/uri"
2
3
  require "active_support/concern"
3
4
 
4
5
 
@@ -19,11 +20,7 @@ module Remotable
19
20
 
20
21
 
21
22
  def find_by!(key, value)
22
- if key == :id
23
- find(value)
24
- else
25
- find(:one, :from => path_for(key, value))
26
- end
23
+ find(:one, :from => path_for(key, value))
27
24
  end
28
25
 
29
26
  def find_by(key, value)
@@ -39,9 +36,9 @@ module Remotable
39
36
  route = route_for(local_key)
40
37
  path = route.gsub(/:#{local_key}/, value.to_s)
41
38
  if relative_path?(path)
42
- path
39
+ URI.join_url_segments(prefix, collection_name, "#{path}.#{format.extension}")
43
40
  else
44
- join_url_segments(prefix, collection_name, path)
41
+ path
45
42
  end
46
43
  end
47
44
 
@@ -52,11 +49,7 @@ module Remotable
52
49
 
53
50
 
54
51
  def relative_path?(path)
55
- path.start_with?("/") || path["://"]
56
- end
57
-
58
- def join_url_segments(*segments)
59
- segments.flatten.join("/").gsub(/\/+/, "/")
52
+ !(path.start_with?("/") || path["://"])
60
53
  end
61
54
 
62
55
 
@@ -0,0 +1,22 @@
1
+ require "uri"
2
+
3
+
4
+ module Remotable
5
+ module CoreExt
6
+ module URI
7
+
8
+
9
+ def join_url_segments(*segments)
10
+ segments = segments.dup.flatten.map(&:to_s)
11
+ first_segment = segments.shift.gsub(/\/$/, "")
12
+ segments.map! { |seg| seg.gsub(/(^\/)|(\/$)/, "") }
13
+ [first_segment, *segments].join("/")
14
+ end
15
+
16
+
17
+ end
18
+ end
19
+ end
20
+
21
+
22
+ ::URI.extend(Remotable::CoreExt::URI)
@@ -0,0 +1,28 @@
1
+
2
+ module Remotable
3
+ module Nosync
4
+
5
+
6
+ def nosync!
7
+ self.nosync = true
8
+ end
9
+
10
+ def nosync
11
+ value = @nosync
12
+ nosync!
13
+ yield
14
+ ensure
15
+ self.nosync = value
16
+ end
17
+
18
+ def nosync=(val)
19
+ @nosync = (val == true)
20
+ end
21
+
22
+ def nosync?
23
+ @nosync == true
24
+ end
25
+
26
+
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module Remotable
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
data/remotable.gemspec CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency "factory_girl"
23
23
  s.add_development_dependency "sqlite3"
24
24
  s.add_development_dependency "active_resource_simulator"
25
+ s.add_development_dependency "simplecov"
25
26
 
26
27
  s.files = `git ls-files`.split("\n")
27
28
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -0,0 +1,30 @@
1
+ require "test_helper"
2
+ require "remotable"
3
+ require "support/active_resource"
4
+
5
+
6
+ class NoSyncTest < ActiveSupport::TestCase
7
+
8
+
9
+
10
+ test "nosync? should be false by default" do
11
+ assert_equal false, Tenant.new.nosync?
12
+ end
13
+
14
+ test "nosync? should be true if remotable is turned off globally" do
15
+ Remotable.nosync do
16
+ assert_equal true, Tenant.new.nosync?
17
+ assert_equal true, RemoteWithoutKey.new.nosync?
18
+ end
19
+ end
20
+
21
+ test "nosync? should be true if remotable is turned off for the model" do
22
+ Tenant.nosync do
23
+ assert_equal true, Tenant.new.nosync?
24
+ assert_equal false, RemoteWithoutKey.new.nosync?
25
+ end
26
+ end
27
+
28
+
29
+
30
+ end
@@ -45,6 +45,43 @@ class RemotableTest < ActiveSupport::TestCase
45
45
  end
46
46
  end
47
47
 
48
+ test "should be able to find resources with the bang method" do
49
+ new_tenant_slug = "not_found2"
50
+
51
+ assert_equal 0, Tenant.where(:slug => new_tenant_slug).count,
52
+ "There's not supposed to be a Tenant with the slug #{new_tenant_slug}."
53
+
54
+ assert_difference "Tenant.count", +1 do
55
+ RemoteTenant.run_simulation do |s|
56
+ s.show(nil, {
57
+ :id => 46,
58
+ :slug => new_tenant_slug,
59
+ :church_name => "Not Found"
60
+ }, :path => "/api/accounts/by_slug/#{new_tenant_slug}.json")
61
+
62
+ new_tenant = Tenant.find_by_slug!(new_tenant_slug)
63
+ assert_not_nil new_tenant, "A remote tenant was not found with the slug #{new_tenant_slug.inspect}"
64
+ end
65
+ end
66
+ end
67
+
68
+ test "if a resource is neither local nor remote, raise an exception with the bang method" do
69
+ new_tenant_slug = "not_found3"
70
+
71
+ assert_equal 0, Tenant.where(:slug => new_tenant_slug).count,
72
+ "There's not supposed to be a Tenant with the slug #{new_tenant_slug}."
73
+
74
+ RemoteTenant.run_simulation do |s|
75
+ s.show(nil, nil, :status => 404, :path => "/api/accounts/by_slug/#{new_tenant_slug}.json")
76
+
77
+ assert_raises ActiveRecord::RecordNotFound do
78
+ Tenant.find_by_slug!(new_tenant_slug)
79
+ end
80
+ end
81
+ end
82
+
83
+
84
+
48
85
  test "should be able to find resources by different attributes and specify a path" do
49
86
  new_tenant_name = "JohnnyG"
50
87
 
@@ -14,8 +14,7 @@ end
14
14
  class Tenant < ActiveRecord::Base
15
15
  remote_model RemoteTenant
16
16
  attr_remote :slug, :church_name => :name, :id => :remote_id
17
- find_by :slug
18
- find_by :name => "by_nombre/:name.json"
17
+ find_by :name => "by_nombre/:name"
19
18
  end
20
19
 
21
20
 
data/test/test_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'rubygems'
2
+ require 'simplecov'
2
3
  require 'rails'
3
4
  require 'rails/test_help'
4
5
  require 'active_support/core_ext'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: remotable
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.1
5
+ version: 0.1.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Robert Lail
@@ -10,12 +10,11 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-08-26 00:00:00 -05:00
13
+ date: 2011-09-19 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activeresource
18
- prerelease: false
19
18
  requirement: &id001 !ruby/object:Gem::Requirement
20
19
  none: false
21
20
  requirements:
@@ -23,10 +22,10 @@ dependencies:
23
22
  - !ruby/object:Gem::Version
24
23
  version: "0"
25
24
  type: :runtime
25
+ prerelease: false
26
26
  version_requirements: *id001
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activerecord
29
- prerelease: false
30
29
  requirement: &id002 !ruby/object:Gem::Requirement
31
30
  none: false
32
31
  requirements:
@@ -34,10 +33,10 @@ dependencies:
34
33
  - !ruby/object:Gem::Version
35
34
  version: "0"
36
35
  type: :runtime
36
+ prerelease: false
37
37
  version_requirements: *id002
38
38
  - !ruby/object:Gem::Dependency
39
39
  name: activesupport
40
- prerelease: false
41
40
  requirement: &id003 !ruby/object:Gem::Requirement
42
41
  none: false
43
42
  requirements:
@@ -45,10 +44,10 @@ dependencies:
45
44
  - !ruby/object:Gem::Version
46
45
  version: "0"
47
46
  type: :runtime
47
+ prerelease: false
48
48
  version_requirements: *id003
49
49
  - !ruby/object:Gem::Dependency
50
50
  name: rails
51
- prerelease: false
52
51
  requirement: &id004 !ruby/object:Gem::Requirement
53
52
  none: false
54
53
  requirements:
@@ -56,10 +55,10 @@ dependencies:
56
55
  - !ruby/object:Gem::Version
57
56
  version: "0"
58
57
  type: :development
58
+ prerelease: false
59
59
  version_requirements: *id004
60
60
  - !ruby/object:Gem::Dependency
61
61
  name: turn
62
- prerelease: false
63
62
  requirement: &id005 !ruby/object:Gem::Requirement
64
63
  none: false
65
64
  requirements:
@@ -67,10 +66,10 @@ dependencies:
67
66
  - !ruby/object:Gem::Version
68
67
  version: "0"
69
68
  type: :development
69
+ prerelease: false
70
70
  version_requirements: *id005
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: factory_girl
73
- prerelease: false
74
73
  requirement: &id006 !ruby/object:Gem::Requirement
75
74
  none: false
76
75
  requirements:
@@ -78,10 +77,10 @@ dependencies:
78
77
  - !ruby/object:Gem::Version
79
78
  version: "0"
80
79
  type: :development
80
+ prerelease: false
81
81
  version_requirements: *id006
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: sqlite3
84
- prerelease: false
85
84
  requirement: &id007 !ruby/object:Gem::Requirement
86
85
  none: false
87
86
  requirements:
@@ -89,10 +88,10 @@ dependencies:
89
88
  - !ruby/object:Gem::Version
90
89
  version: "0"
91
90
  type: :development
91
+ prerelease: false
92
92
  version_requirements: *id007
93
93
  - !ruby/object:Gem::Dependency
94
94
  name: active_resource_simulator
95
- prerelease: false
96
95
  requirement: &id008 !ruby/object:Gem::Requirement
97
96
  none: false
98
97
  requirements:
@@ -100,7 +99,19 @@ dependencies:
100
99
  - !ruby/object:Gem::Version
101
100
  version: "0"
102
101
  type: :development
102
+ prerelease: false
103
103
  version_requirements: *id008
104
+ - !ruby/object:Gem::Dependency
105
+ name: simplecov
106
+ requirement: &id009 !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: "0"
112
+ type: :development
113
+ prerelease: false
114
+ version_requirements: *id009
104
115
  description: Remotable keeps a locally-stored ActiveRecord synchronized with a remote resource.
105
116
  email:
106
117
  - robert.lail@cph.org
@@ -112,7 +123,10 @@ extra_rdoc_files: []
112
123
 
113
124
  files:
114
125
  - .gitignore
126
+ - .simplecov
115
127
  - Gemfile
128
+ - MIT-LICENSE
129
+ - README.mdown
116
130
  - Rakefile
117
131
  - lib/remotable.rb
118
132
  - lib/remotable/active_record_extender.rb
@@ -120,9 +134,12 @@ files:
120
134
  - lib/remotable/adapters/active_resource.rb
121
135
  - lib/remotable/core_ext.rb
122
136
  - lib/remotable/core_ext/enumerable.rb
137
+ - lib/remotable/core_ext/uri.rb
138
+ - lib/remotable/nosync.rb
123
139
  - lib/remotable/version.rb
124
140
  - remotable.gemspec
125
141
  - test/factories/tenants.rb
142
+ - test/nosync_test.rb
126
143
  - test/remotable_test.rb
127
144
  - test/support/active_resource.rb
128
145
  - test/support/schema.rb
@@ -141,12 +158,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
141
158
  requirements:
142
159
  - - ">="
143
160
  - !ruby/object:Gem::Version
161
+ hash: -3964453781744969533
162
+ segments:
163
+ - 0
144
164
  version: "0"
145
165
  required_rubygems_version: !ruby/object:Gem::Requirement
146
166
  none: false
147
167
  requirements:
148
168
  - - ">="
149
169
  - !ruby/object:Gem::Version
170
+ hash: -3964453781744969533
171
+ segments:
172
+ - 0
150
173
  version: "0"
151
174
  requirements: []
152
175
 
@@ -157,6 +180,7 @@ specification_version: 3
157
180
  summary: Binds an ActiveRecord model to a remote resource and keeps the two synchronized
158
181
  test_files:
159
182
  - test/factories/tenants.rb
183
+ - test/nosync_test.rb
160
184
  - test/remotable_test.rb
161
185
  - test/support/active_resource.rb
162
186
  - test/support/schema.rb