remotable 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ddc9f37b1e04cbd48e85ae0b05e75e6b72f6e145
4
- data.tar.gz: e019957e6c601abba1a6fc6c88ed1f2d357691cb
2
+ SHA256:
3
+ metadata.gz: eb1390c1e1b04414cc0c44807a064f1d5d879c891a01988abcd7b919d9d53f37
4
+ data.tar.gz: 5f5b316b09904143182ba07de7225f1151328bc1dd12b52a3e5797b0b1f8dc03
5
5
  SHA512:
6
- metadata.gz: c50f5da9c4150f66a92d1ceb12e97f473e19d7c15f2743777885112b8e0b04b1b83aa2ee78113e225557a17a280a34d1bebaf8b25f060a0c564279eb9aa16f0a
7
- data.tar.gz: 88b1a55add081c7312221d1855f03305d039e72603f093b1656f043bbba71d89dccd2f644d78ae0fd373cd2e266307663d15ef9fec529e6187d4259eca76f375
6
+ metadata.gz: ef0d217377d44f7ea675da8ff0faf6718654502abec68cc2f388bc1d1ab95ecf7325aa20733608575d51842390510e9799326149b7ab31b075bcc8fe9902e188
7
+ data.tar.gz: 134e43c05eb6da221d66d1ae14bdb93f42d89c22a7b32336d505a81c3ad11e18f63ca5e52ca7838cebb52035221abbd9638473aa32c2bdef310c84bbd39e687c
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
+ Gemfile.lock
2
+ gemfiles/*.gemfile.lock
1
3
  *.gem
2
4
  .bundle
3
5
  pkg/*
@@ -1,11 +1,28 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.3.1
4
- - 2.5.1
3
+ - 2.3
4
+ - 2.5
5
+ - 2.6
5
6
 
6
- matrix:
7
+ gemfile:
8
+ - gemfiles/rails_5.0.gemfile
9
+ - gemfiles/rails_5.1.gemfile
10
+ - gemfiles/rails_5.2.gemfile
11
+ - gemfiles/rails_6.0.gemfile
12
+ - gemfiles/rails_edge.gemfile
13
+
14
+ jobs:
15
+ exclude:
16
+ - rvm: 2.3
17
+ gemfile: gemfiles/rails_6.0.gemfile
18
+ - rvm: 2.3
19
+ gemfile: gemfiles/rails_edge.gemfile
20
+ - rvm: 2.4
21
+ gemfile: gemfiles/rails_6.0.gemfile
22
+ - rvm: 2.4
23
+ gemfile: gemfiles/rails_edge.gemfile
7
24
  allow_failures:
8
- - rvm: 2.5.1
25
+ - gemfile: gemfiles/rails_edge.gemfile
9
26
 
10
27
  script: bundle exec rake test
11
28
 
@@ -0,0 +1,24 @@
1
+ appraise "rails-5.0" do
2
+ gem "activerecord", "~> 5.0.0"
3
+ gem "sqlite3", "~> 1.3.6"
4
+ end
5
+
6
+ appraise "rails-5.1" do
7
+ gem "activerecord", "~> 5.1.0"
8
+ gem "sqlite3", "~> 1.3.6"
9
+ end
10
+
11
+ appraise "rails-5.2" do
12
+ gem "activerecord", "~> 5.2.0"
13
+ gem "sqlite3", "~> 1.3.6"
14
+ end
15
+
16
+ appraise "rails-6.0" do
17
+ gem "activerecord", "~> 6.0.0"
18
+ gem "sqlite3", "~> 1.4.0"
19
+ end
20
+
21
+ appraise "rails-edge" do
22
+ gem "rails", git: "https://github.com/rails/rails.git", branch: "master", require: "activerecord"
23
+ gem "sqlite3", "~> 1.4.0"
24
+ end
@@ -20,29 +20,34 @@ Just add the following to your Gemfile:
20
20
 
21
21
  **1.** Remotable requires that your local model have an `expires_at` column.
22
22
 
23
- class AddExpiresAtToTenants < ActiveRecord::Migration
24
- def self.up
25
- add_column :tenants, :expires_at, :timestamp, :null => false
26
- end
27
- end
23
+ ```ruby
24
+ class AddExpiresAtToTenants < ActiveRecord::Migration
25
+ def self.up
26
+ add_column :tenants, :expires_at, :timestamp, :null => false
27
+ end
28
+ end
29
+ ```
28
30
 
29
31
  **2.** Your local model has to be associated with a remote model: (Let's say `RemoteTenant` is the name of an ActiveResource model.)
30
32
 
31
- class Tenant < ActiveRecord::Base
32
- remote_model RemoteTenant
33
- end
34
-
33
+ ```ruby
34
+ class Tenant < ActiveRecord::Base
35
+ remote_model RemoteTenant
36
+ end
37
+ ```
35
38
 
36
39
  ### Configuration
37
40
 
38
41
  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`.
39
42
 
40
- class Tenant < ActiveRecord::Base
41
- remote_model RemoteTenant
42
- attr_remote :slug,
43
- :customer_name => :name,
44
- :id => :remote_id
45
- end
43
+ ```ruby
44
+ class Tenant < ActiveRecord::Base
45
+ remote_model RemoteTenant
46
+ attr_remote :slug,
47
+ :customer_name => :name,
48
+ :id => :remote_id
49
+ end
50
+ ```
46
51
 
47
52
  ### Remote Keys
48
53
 
@@ -50,24 +55,28 @@ By default Remotable assumes that the local model and remote model are joined wi
50
55
 
51
56
  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:
52
57
 
53
- class Tenant < ActiveRecord::Base
54
- remote_model RemoteTenant
55
- attr_remote :slug,
56
- :customer_name => :name,
57
- :id => :remote_id
58
- remote_key :slug
59
- end
58
+ ```ruby
59
+ class Tenant < ActiveRecord::Base
60
+ remote_model RemoteTenant
61
+ attr_remote :slug,
62
+ :customer_name => :name,
63
+ :id => :remote_id
64
+ remote_key :slug
65
+ end
66
+ ```
60
67
 
61
68
  Now, the join could be expressed this way: `local_model.slug=remote_model.slug`.
62
69
 
63
70
  If you must look up a remote model with more than one attribute, you can express a composite key this way:
64
71
 
65
- class Event < ActiveRecord::Base
66
- remote_model RemoteEvent
67
- attr_remote :calendar_id,
68
- :id => :remote_id
69
- remote_key [:calendar_id, :remote_id]
70
- end
72
+ ```ruby
73
+ class Event < ActiveRecord::Base
74
+ remote_model RemoteEvent
75
+ attr_remote :calendar_id,
76
+ :id => :remote_id
77
+ remote_key [:calendar_id, :remote_id]
78
+ end
79
+ ```
71
80
 
72
81
  ### Finders
73
82
 
@@ -75,33 +84,38 @@ For `:id` or whatever you chose to be the remote key, Remotable will create a fi
75
84
 
76
85
  You can create additional finder with the `fetch_with` method:
77
86
 
78
- class Tenant < ActiveRecord::Base
79
- remote_model RemoteTenant
80
- attr_remote :slug,
81
- :customer_name => :name,
82
- :id => :remote_id
83
- fetch_with :slug
84
- fetch_with :name
85
- end
87
+ ```ruby
88
+ class Tenant < ActiveRecord::Base
89
+ remote_model RemoteTenant
90
+ attr_remote :slug,
91
+ :customer_name => :name,
92
+ :id => :remote_id
93
+ fetch_with :slug
94
+ fetch_with :name
95
+ end
96
+ ```
86
97
 
87
98
  Remotable will create the following methods and assume the URI for the custom finders from the attribute. The example above will create the following methods:
88
99
 
100
+ ```ruby
89
101
  find_by_remote_id(...) # Looks in api_path/tenants/:id
90
102
  find_by_slug(...) # Looks in api_path/tenants/by_slug/:slug
91
103
  find_by_name(...) # Looks in api_path/tenants/by_name/:name
104
+ ```
92
105
 
93
106
  Note that the finder methods are named with the _local_ attributes.
94
107
 
95
108
  You can specify a custom path with the `fetch_with` method:
96
109
 
97
- class Tenant < ActiveRecord::Base
98
- remote_model RemoteTenant
99
- attr_remote :slug,
100
- :customer_name => :name,
101
- :id => :remote_id
102
- fetch_with :name, :path => "by_nombre/:name"
103
- end
104
-
110
+ ```ruby
111
+ class Tenant < ActiveRecord::Base
112
+ remote_model RemoteTenant
113
+ attr_remote :slug,
114
+ :customer_name => :name,
115
+ :id => :remote_id
116
+ fetch_with :name, :path => "by_nombre/:name"
117
+ end
118
+ ```
105
119
 
106
120
  When you use `fetch_with`, 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.
107
121
 
@@ -109,10 +123,12 @@ When you use `fetch_with`, give the name of the _local_ attribute not the remote
109
123
 
110
124
  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:
111
125
 
112
- class Tenant < ActiveRecord::Base
113
- remote_model RemoteTenant
114
- expires_after 1.hour
115
- end
126
+ ```ruby
127
+ class Tenant < ActiveRecord::Base
128
+ remote_model RemoteTenant
129
+ expires_after 1.hour
130
+ end
131
+ ```
116
132
 
117
133
  ### Adapters
118
134
 
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.0.0"
6
+ gem "sqlite3", "~> 1.3.6"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.1.0"
6
+ gem "sqlite3", "~> 1.3.6"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.2.0"
6
+ gem "sqlite3", "~> 1.3.6"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "activerecord", "~> 6.0.0"
6
+ gem "sqlite3", "~> 1.4.0"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rails", git: "https://github.com/rails/rails.git", branch: "master", require: "activerecord"
6
+ gem "sqlite3", "~> 1.4.0"
7
+
8
+ gemspec path: "../"
@@ -1,6 +1,7 @@
1
1
  require "remotable/core_ext"
2
2
  require "active_support/concern"
3
3
  require "active_support/core_ext/array/wrap"
4
+ require "active_resource/threadsafe_attributes"
4
5
  require "benchmark"
5
6
 
6
7
 
@@ -25,10 +26,10 @@ module Remotable
25
26
 
26
27
  validates_presence_of :expires_at
27
28
 
28
- @remote_attribute_map ||= default_remote_attributes.map_to_self
29
- @local_attribute_routes ||= {}
30
- @expires_after ||= 1.day
31
- @remote_timeout = {
29
+ self._remote_attribute_map ||= default_remote_attributes.map_to_self
30
+ self._local_attribute_routes ||= {}
31
+ self._expires_after ||= 1.day
32
+ self._remote_timeout = {
32
33
  :list => 4, # when we're getting many remote resources
33
34
  :fetch => 4, # when we're getting a remote resource that doesn't exist locally
34
35
  :pull => 1, # when we're getting a remote resource to refresh a local one
@@ -42,6 +43,10 @@ module Remotable
42
43
 
43
44
  module ClassMethods
44
45
  include Nosync
46
+ include ThreadsafeAttributes
47
+
48
+ threadsafe_attribute :_remote_key, :_expires_after, :_remote_attribute_map,
49
+ :_local_attribute_routes, :_remote_timeout, :remotable_skip_validation_on_sync
45
50
 
46
51
  def nosync?
47
52
  return true if remote_model.nil?
@@ -78,37 +83,43 @@ module Remotable
78
83
  # Set up a finder method for the remote_key
79
84
  fetch_with(local_key(remote_key), options)
80
85
 
81
- @remote_key = remote_key
86
+ self._remote_key = remote_key
82
87
  else
83
- @remote_key || generate_default_remote_key
88
+ _remote_key || generate_default_remote_key
84
89
  end
85
90
  end
86
91
 
87
92
  def expires_after(*args)
88
- @expires_after = args.first if args.any?
89
- @expires_after
93
+ self._expires_after = args.first if args.any?
94
+ _expires_after
90
95
  end
91
96
 
92
97
  def attr_remote(*attrs)
93
98
  map = attrs.extract_options!
94
99
  map = attrs.map_to_self.merge(map)
95
- @remote_attribute_map = map
96
- @local_attribute_routes = {} # reset routes
100
+ self._remote_attribute_map = map
101
+ self._local_attribute_routes = {} # reset routes
97
102
  end
98
103
 
99
104
  def remote_timeout(*args)
100
105
  if args.any?
101
- @remote_timeout = n = args.first
102
- @remote_timeout = {:list => n, :fetch => n, :pull => n, :create => n, :update => n, :destroy => n} if n.is_a?(Numeric)
106
+ self._remote_timeout = n = args.first
107
+ self._remote_timeout = {:list => n, :fetch => n, :pull => n, :create => n, :update => n, :destroy => n} if n.is_a?(Numeric)
103
108
  end
104
- @remote_timeout
109
+ _remote_timeout
105
110
  end
106
111
 
107
- def fetch_with(local_key, options={})
108
- @local_attribute_routes.merge!(local_key => options[:path])
112
+ def remote_attribute_map
113
+ self._remote_attribute_map
109
114
  end
110
115
 
111
- attr_accessor :remotable_skip_validation_on_sync
116
+ def local_attribute_routes
117
+ self._local_attribute_routes
118
+ end
119
+
120
+ def fetch_with(local_key, options={})
121
+ self._local_attribute_routes.merge!(local_key => options[:path])
122
+ end
112
123
 
113
124
  def remotable_skip_validation!
114
125
  self.remotable_skip_validation_on_sync = true
@@ -119,10 +130,6 @@ module Remotable
119
130
  end
120
131
 
121
132
 
122
-
123
- attr_reader :remote_attribute_map,
124
- :local_attribute_routes
125
-
126
133
  def local_key(remote_key=nil)
127
134
  remote_key ||= self.remote_key
128
135
  if remote_key.is_a?(Array)
@@ -133,24 +140,24 @@ module Remotable
133
140
  end
134
141
 
135
142
  def remote_attribute_names
136
- remote_attribute_map.keys
143
+ _remote_attribute_map.keys
137
144
  end
138
145
 
139
146
  def local_attribute_names
140
- remote_attribute_map.values
147
+ _remote_attribute_map.values
141
148
  end
142
149
 
143
150
  def remote_attribute_name(local_attr)
144
- remote_attribute_map.key(local_attr) || local_attr
151
+ _remote_attribute_map.key(local_attr) || local_attr
145
152
  end
146
153
 
147
154
  def local_attribute_name(remote_attr)
148
- remote_attribute_map[remote_attr] || remote_attr
155
+ _remote_attribute_map[remote_attr] || remote_attr
149
156
  end
150
157
 
151
158
  def route_for(remote_key)
152
159
  local_key = self.local_key(remote_key)
153
- local_attribute_routes[local_key] || default_route_for(local_key, remote_key)
160
+ _local_attribute_routes[local_key] || default_route_for(local_key, remote_key)
154
161
  end
155
162
 
156
163
  def default_route_for(local_key, remote_key=nil)
@@ -167,10 +174,23 @@ module Remotable
167
174
  # !nb: this method is called when associations are loaded
168
175
  # so you can use the remoted record in associations.
169
176
  def instantiate(*args)
170
- record = super
177
+ super.tap do |record|
178
+ sync_on_instantiate(record) unless ActiveRecord.version.segments.first > 5
179
+ end
180
+ end
181
+
182
+ # !nb: In Rails 6+, this has been extracted from instantiate and can be called
183
+ # to instantiate homogenous sets of records without calling instantiate
184
+ def instantiate_instance_of(*args)
185
+ super.tap do |record|
186
+ sync_on_instantiate(record)
187
+ end
188
+ end
189
+
190
+ def sync_on_instantiate(record)
171
191
  if record.expired? && !record.nosync?
172
192
  begin
173
- Remotable.logger.debug "[remotable:#{name.underscore}:instantiate](#{record.fetch_value.inspect}) expired #{record.expires_at}"
193
+ Remotable.logger.debug "[remotable:#{name.underscore}:sync_on_instantiate](#{record.fetch_value.inspect}) expired #{record.expires_at}"
174
194
  record.pull_remote_data!
175
195
  rescue Remotable::TimeoutError
176
196
  report_ignored_timeout_error($!)
@@ -182,7 +202,6 @@ module Remotable
182
202
  report_ignored_ssl_error($!)
183
203
  end
184
204
  end
185
- record
186
205
  end
187
206
 
188
207
  def report_ignored_timeout_error(error)
@@ -254,7 +273,7 @@ module Remotable
254
273
  generate_default_remote_key # <- Make sure we've figured out the remote
255
274
  # primary key if we're evaluating a finder
256
275
 
257
- return false unless local_attribute_routes.key?(local_key)
276
+ return false unless _local_attribute_routes.key?(local_key)
258
277
 
259
278
  { :local_attributes => local_attributes,
260
279
  :remote_key => remote_key }
@@ -412,7 +431,7 @@ module Remotable
412
431
 
413
432
 
414
433
  def generate_default_remote_key
415
- return @remote_key if @remote_key
434
+ return _remote_key if _remote_key
416
435
  raise("No remote key supplied and :id is not a remote attribute") unless remote_attribute_names.member?(:id)
417
436
  remote_key(:id)
418
437
  end
@@ -554,7 +573,7 @@ module Remotable
554
573
  true
555
574
  else
556
575
  merge_remote_errors(remote_resource.errors)
557
- false
576
+ ActiveRecord.version.segments.first > 4 ? throw(:abort) : false
558
577
  end
559
578
  rescue Remotable::NotFound
560
579
  report_ignored_404_on_destroy $!
@@ -1,10 +1,6 @@
1
1
  require "active_resource"
2
- require "active_support/concern"
3
-
4
2
 
5
3
  module ActiveResourceFixes
6
- extend ActiveSupport::Concern
7
-
8
4
 
9
5
  # ! ActiveModel::AttributeMethods assumes that :attribute is the target
10
6
  # for attribute lookup. ActiveResource doesn't define that method.
@@ -12,17 +8,11 @@ module ActiveResourceFixes
12
8
  attributes[method]
13
9
  end
14
10
 
15
-
16
- included do
17
- alias_method_chain :destroy, :validation
18
- end
19
-
20
-
21
11
  # ActiveResource::Validations overrides ActiveResource::Base#save
22
12
  # to rescue from ActiveResource::ResourceInvalid and record the
23
13
  # resource's errors. Do the same for `destroy`.
24
- def destroy_with_validation
25
- destroy_without_validation
14
+ def destroy
15
+ super
26
16
  rescue ActiveResource::ResourceInvalid => error
27
17
  # cache the remote errors because every call to <tt>valid?</tt> clears
28
18
  # all errors. We must keep a copy to add these back after local
@@ -34,7 +24,7 @@ module ActiveResourceFixes
34
24
 
35
25
  end
36
26
 
37
- ActiveResource::Base.send(:include, ActiveResourceFixes)
27
+ ActiveResource::Base.send(:prepend, ActiveResourceFixes)
38
28
 
39
29
 
40
30
 
@@ -1,37 +1,69 @@
1
+ require "active_resource/threadsafe_attributes"
2
+
1
3
  module Remotable
2
4
  module Nosync
3
5
 
4
-
5
- def nosync!
6
- self.nosync = true
6
+ def self.included(base)
7
+ base.include InstanceMethods
7
8
  end
8
9
 
9
- def nosync(new_value=true)
10
- old_value = _nosync
11
- self.nosync = new_value
12
- yield
13
- ensure
14
- @nosync = old_value
10
+ def self.extended(base)
11
+ base.extend ClassMethods
15
12
  end
16
13
 
17
- def nosync=(val)
18
- @nosync = val
19
- end
14
+ module InstanceMethods
20
15
 
21
- def nosync_value?
22
- !_nosync.nil?
23
- end
16
+ def nosync!
17
+ self.nosync = true
18
+ end
24
19
 
25
- def nosync?
26
- @nosync == true
27
- end
20
+ def reset_nosync!
21
+ remove_instance_variable(:@nosync) if instance_variable_defined?(:@nosync)
22
+ end
23
+
24
+ def nosync(new_value=true)
25
+ old_value = _nosync
26
+ self.nosync = new_value
27
+ yield
28
+ ensure
29
+ self.nosync = old_value
30
+ end
31
+
32
+ def nosync=(val)
33
+ @nosync = val
34
+ end
28
35
 
29
- private
36
+ def nosync_value?
37
+ !_nosync.nil?
38
+ end
39
+
40
+ def nosync?
41
+ !!_nosync
42
+ end
43
+
44
+ private
45
+
46
+ def _nosync
47
+ @nosync if instance_variable_defined?(:@nosync)
48
+ end
30
49
 
31
- def _nosync
32
- @nosync if instance_variable_defined?(:@nosync)
33
50
  end
34
51
 
52
+ module ClassMethods
53
+ include ThreadsafeAttributes
54
+ include InstanceMethods
55
+
56
+ def reset_nosync!
57
+ self.nosync = nil
58
+ end
59
+
60
+ def nosync=(val)
61
+ self._nosync = val
62
+ end
63
+
64
+ private
65
+ threadsafe_attribute :_nosync
66
+ end
35
67
 
36
68
  end
37
69
  end
@@ -1,13 +1,19 @@
1
+ require "active_resource/threadsafe_attributes"
2
+
1
3
  module Remotable
2
4
  module ValidateModels
5
+ include ThreadsafeAttributes
3
6
 
7
+ def self.extended(*args)
8
+ threadsafe_attribute :_validate_models
9
+ end
4
10
 
5
11
  def validate_models=(val)
6
- @validate_models = (val == true)
12
+ self._validate_models = (val == true)
7
13
  end
8
14
 
9
15
  def validate_models?
10
- @validate_models == true
16
+ _validate_models == true
11
17
  end
12
18
 
13
19
  def without_validation
@@ -1,3 +1,3 @@
1
1
  module Remotable
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -11,17 +11,18 @@ Gem::Specification.new do |s|
11
11
  s.summary = %q{Binds an ActiveRecord model to a remote resource and keeps the two synchronized}
12
12
  s.description = %q{Remotable keeps a locally-stored ActiveRecord synchronized with a remote resource.}
13
13
 
14
- s.rubyforge_project = "remotable"
15
-
16
14
  s.add_dependency "activeresource", ">= 3.2"
17
15
  s.add_dependency "activerecord"
18
16
  s.add_dependency "activesupport"
19
17
 
18
+ s.add_development_dependency "appraisal"
20
19
  s.add_development_dependency "rake"
21
- s.add_development_dependency "turn"
20
+ s.add_development_dependency "minitest", "~> 5.10.3"
21
+ s.add_development_dependency "minitest-reporters"
22
+ s.add_development_dependency "minitest-reporters-turn_reporter"
22
23
  s.add_development_dependency "pry"
23
- s.add_development_dependency "factory_girl", "~> 2.0.4"
24
- s.add_development_dependency "sqlite3", "~> 1.3.13"
24
+ s.add_development_dependency "factory_bot"
25
+ s.add_development_dependency "sqlite3"
25
26
  s.add_development_dependency "active_resource_simulator"
26
27
  s.add_development_dependency "simplecov"
27
28
  s.add_development_dependency "rr"
@@ -7,7 +7,6 @@ require "rr"
7
7
 
8
8
 
9
9
  class ActiveResourceTest < ActiveSupport::TestCase
10
- include RR::Adapters::TestUnit
11
10
 
12
11
  test "should make an absolute path and add the format" do
13
12
  assert_equal "/api/accounts/by_slug/value.json", RemoteTenant.expanded_path_for("by_slug/value")
@@ -154,7 +153,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
154
153
  # ========================================================================= #
155
154
 
156
155
  test "should not fetch a remote record when a local record is not expired" do
157
- tenant = Factory(:tenant, :expires_at => 100.years.from_now)
156
+ tenant = create(:tenant, :expires_at => 100.years.from_now)
158
157
  unexpected_name = "Totally Wonky"
159
158
 
160
159
  RemoteTenant.run_simulation do |s|
@@ -170,7 +169,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
170
169
  end
171
170
 
172
171
  test "should fetch a remote record when a local record is expired" do
173
- tenant = Factory(:tenant, :expires_at => 1.year.ago)
172
+ tenant = create(:tenant, :expires_at => 1.year.ago)
174
173
  unexpected_name = "Totally Wonky"
175
174
 
176
175
  RemoteTenant.run_simulation do |s|
@@ -186,7 +185,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
186
185
  end
187
186
 
188
187
  test "should treat a 304 response as no changes" do
189
- tenant = Factory(:tenant, :expires_at => 1.year.ago)
188
+ tenant = create(:tenant, :expires_at => 1.year.ago)
190
189
 
191
190
  RemoteTenant.run_simulation do |s|
192
191
  s.show(tenant.remote_id, nil, :status => 304, :headers => if_modified_since(tenant))
@@ -199,7 +198,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
199
198
 
200
199
  test "should ignore a 503 response" do
201
200
  expired_at = 1.year.ago
202
- tenant = Factory(:tenant, :expires_at => expired_at)
201
+ tenant = create(:tenant, :expires_at => expired_at)
203
202
 
204
203
  RemoteTenant.run_simulation do |s|
205
204
  s.show(tenant.remote_id, nil, :status => 503, :headers => if_modified_since(tenant))
@@ -219,7 +218,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
219
218
  # ========================================================================= #
220
219
 
221
220
  test "should update a record remotely when updating one locally" do
222
- tenant = Factory(:tenant)
221
+ tenant = create(:tenant)
223
222
  new_name = "Totally Wonky"
224
223
 
225
224
  RemoteTenant.run_simulation do |s|
@@ -242,7 +241,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
242
241
  end
243
242
 
244
243
  test "should be able to update resources by different attributes" do
245
- tenant = RemoteWithKey.where(id: Factory(:tenant).id).first
244
+ tenant = RemoteWithKey.where(id: create(:tenant).id).first
246
245
  new_name = "Totally Wonky"
247
246
 
248
247
  RemoteTenant.run_simulation do |s|
@@ -265,7 +264,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
265
264
  end
266
265
 
267
266
  test "should fail to update a record locally when failing to update one remotely" do
268
- tenant = Factory(:tenant)
267
+ tenant = create(:tenant)
269
268
  new_name = "Totally Wonky"
270
269
 
271
270
  RemoteTenant.run_simulation do |s|
@@ -363,7 +362,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
363
362
  # ========================================================================= #
364
363
 
365
364
  test "should destroy a record remotely when destroying one locally" do
366
- tenant = Factory(:tenant)
365
+ tenant = create(:tenant)
367
366
 
368
367
  RemoteTenant.run_simulation do |s|
369
368
  s.show(tenant.remote_id, {
@@ -381,7 +380,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
381
380
  end
382
381
 
383
382
  test "should destroy resources by different attributes" do
384
- tenant = RemoteWithKey.where(id: Factory(:tenant).id).first
383
+ tenant = RemoteWithKey.where(id: create(:tenant).id).first
385
384
  new_name = "Totally Wonky"
386
385
 
387
386
  RemoteTenant.run_simulation do |s|
@@ -399,7 +398,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
399
398
  end
400
399
 
401
400
  test "should fail to destroy a record locally when failing to destroy one remotely" do
402
- tenant = Factory(:tenant)
401
+ tenant = create(:tenant)
403
402
 
404
403
  RemoteTenant.run_simulation do |s|
405
404
  s.show(tenant.remote_id, {
@@ -420,7 +419,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
420
419
  end
421
420
 
422
421
  test "should succeed in destroying a record locally when the remote source is not found" do
423
- tenant = Factory(:tenant)
422
+ tenant = create(:tenant)
424
423
 
425
424
  RemoteTenant.run_simulation do |s|
426
425
  s.show(tenant.remote_id, {
@@ -439,7 +438,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
439
438
  end
440
439
 
441
440
  test "should delete a local record when a remote record has been deleted" do
442
- tenant = Factory(:tenant, :expires_at => 1.year.ago)
441
+ tenant = create(:tenant, :expires_at => 1.year.ago)
443
442
 
444
443
  assert_difference "Tenant.count", -1 do
445
444
  RemoteTenant.run_simulation do |s|
@@ -459,7 +458,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
459
458
  # ========================================================================= #
460
459
 
461
460
  test "should be able to find all remote resources and sync them with local resources" do
462
- tenant = Factory(:tenant, :expires_at => 1.year.ago)
461
+ tenant = create(:tenant, :expires_at => 1.year.ago)
463
462
 
464
463
  assert_equal 1, Tenant.count, "There's supposed to be 1 tenant"
465
464
 
@@ -467,10 +466,10 @@ class ActiveResourceTest < ActiveSupport::TestCase
467
466
  assert_difference "Tenant.count", +1 do
468
467
  RemoteTenant.run_simulation do |s|
469
468
  s.show(nil, [
470
- { :id => tenant.id,
469
+ { :id => tenant.remote_id,
471
470
  :slug => "a-different-slug",
472
471
  :church_name => "A Different Name" },
473
- { :id => tenant.id + 1,
472
+ { :id => tenant.remote_id + 1,
474
473
  :slug => "generic-slug",
475
474
  :church_name => "Generic Name" }],
476
475
  :path => "/api/accounts.json")
@@ -501,7 +500,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
501
500
  end
502
501
 
503
502
  test "should ignore a Remotable::TimeoutError when instantiating a record" do
504
- tenant = Factory(:tenant, :expires_at => 1.year.ago)
503
+ tenant = create(:tenant, :expires_at => 1.year.ago)
505
504
 
506
505
  assert_nothing_raised do
507
506
  stub(Tenant.remote_model).find do |*args|
@@ -5,8 +5,6 @@ require "rr"
5
5
 
6
6
 
7
7
  class BespokeTest < ActiveSupport::TestCase
8
- include RR::Adapters::TestUnit
9
-
10
8
 
11
9
  teardown do
12
10
  def model.new_resource
@@ -68,7 +66,7 @@ class BespokeTest < ActiveSupport::TestCase
68
66
  # ========================================================================= #
69
67
 
70
68
  test "should update a record remotely when updating one locally" do
71
- @tenant = Factory(:bespoke_tenant)
69
+ @tenant = create(:bespoke_tenant)
72
70
  new_name = "Totally Wonky"
73
71
 
74
72
  # RemoteTenant.run_simulation do |s|
@@ -90,7 +88,7 @@ class BespokeTest < ActiveSupport::TestCase
90
88
  end
91
89
 
92
90
  test "should fail to update a record locally when failing to update one remotely" do
93
- @tenant = Factory(:bespoke_tenant, :nosync => false)
91
+ @tenant = create(:bespoke_tenant, :nosync => false)
94
92
 
95
93
  def model.find_by(attribute, value)
96
94
  BespokeResource.new(attribute => value)
@@ -156,13 +154,13 @@ class BespokeTest < ActiveSupport::TestCase
156
154
  # ========================================================================= #
157
155
 
158
156
  test "should destroy a record remotely when destroying one locally" do
159
- @tenant = Factory(:bespoke_tenant, :nosync => false)
157
+ @tenant = create(:bespoke_tenant, :nosync => false)
160
158
  mock(resource).destroy { true }
161
159
  @tenant.destroy
162
160
  end
163
161
 
164
162
  test "should fail to destroy a record locally when failing to destroy one remotely" do
165
- @tenant = Factory(:bespoke_tenant, :nosync => false)
163
+ @tenant = create(:bespoke_tenant, :nosync => false)
166
164
  mock(resource).destroy { raise StandardError }
167
165
  assert_raises(StandardError) do
168
166
  @tenant.destroy
@@ -170,7 +168,7 @@ class BespokeTest < ActiveSupport::TestCase
170
168
  end
171
169
 
172
170
  test "should delete a local record when a remote record has been deleted" do
173
- @tenant = Factory(:bespoke_tenant, :expires_at => 1.year.ago)
171
+ @tenant = create(:bespoke_tenant, :expires_at => 1.year.ago)
174
172
 
175
173
  def model.find_by(remote_attr, value)
176
174
  nil
@@ -1,23 +1,28 @@
1
- Factory.define :tenant do |f|
2
- f.sequence(:slug) { |n| "test#{n}" }
3
- f.name "Test"
4
- f.sequence(:remote_id)
5
- f.expires_at 100.years.from_now
6
- f.nosync true
7
- end
1
+ FactoryBot.define do
8
2
 
9
- Factory.define :bespoke_tenant do |f|
10
- f.sequence(:slug) { |n| "test#{n}" }
11
- f.name "Test"
12
- f.sequence(:remote_id)
13
- f.expires_at 100.years.from_now
14
- f.nosync true
15
- end
3
+ factory :tenant do
4
+ sequence(:slug) { |n| "test#{n}" }
5
+ name { "Test" }
6
+ sequence :remote_id
7
+ expires_at { 100.years.from_now }
8
+ nosync { true }
9
+ end
10
+
11
+ factory :bespoke_tenant do
12
+ sequence(:slug) { |n| "test#{n}" }
13
+ name { "Test" }
14
+ sequence :remote_id
15
+ expires_at { 100.years.from_now }
16
+ nosync { true }
17
+ end
18
+
19
+ factory :null_test_tenant do
20
+ sequence(:slug) { |n| "test#{n}" }
21
+ name { "Test" }
22
+ sequence :remote_id
23
+ expires_at { 100.years.from_now }
24
+ nosync { true }
25
+ end
16
26
 
17
- Factory.define :null_test_tenant do |f|
18
- f.sequence(:slug) { |n| "test#{n}" }
19
- f.name "Test"
20
- f.sequence(:remote_id)
21
- f.expires_at 100.years.from_now
22
- f.nosync true
23
27
  end
28
+
@@ -6,7 +6,6 @@ require "support/active_resource"
6
6
  class NoSyncTest < ActiveSupport::TestCase
7
7
 
8
8
 
9
-
10
9
  test "nosync? should be false by default" do
11
10
  assert_equal false, Tenant.new.nosync?
12
11
  end
@@ -56,7 +55,7 @@ class NoSyncTest < ActiveSupport::TestCase
56
55
  # ========================================================================= #
57
56
 
58
57
  test "should do nothing if a tenant is expired" do
59
- tenant = Factory(:tenant, :expires_at => 1.year.ago)
58
+ tenant = create(:tenant, :expires_at => 1.year.ago)
60
59
 
61
60
  Remotable.nosync do
62
61
  result = Tenant.find_by_remote_id(tenant.remote_id)
@@ -4,16 +4,13 @@ require "support/null"
4
4
 
5
5
 
6
6
  class NullRemoteTest < ActiveSupport::TestCase
7
- include RR::Adapters::TestUnit
8
-
9
-
10
7
 
11
8
  # ========================================================================= #
12
9
  # Finding #
13
10
  # ========================================================================= #
14
11
 
15
12
  test "should do nothing if a tenant is expired" do
16
- tenant = Factory(:null_test_tenant, expires_at: 2.days.ago)
13
+ tenant = create(:null_test_tenant, expires_at: 2.days.ago)
17
14
  result = NullTestTenant.find_by_slug(tenant.slug)
18
15
  assert_equal tenant, result
19
16
  end
@@ -35,7 +32,7 @@ class NullRemoteTest < ActiveSupport::TestCase
35
32
  # ========================================================================= #
36
33
 
37
34
  test "should update a record locally without any interference" do
38
- tenant = Factory(:null_test_tenant)
35
+ tenant = create(:null_test_tenant)
39
36
  new_name = "Totally Wonky"
40
37
 
41
38
  tenant.name = new_name
@@ -63,7 +60,7 @@ class NullRemoteTest < ActiveSupport::TestCase
63
60
  # ========================================================================= #
64
61
 
65
62
  test "should destroy a record locally without any interference" do
66
- tenant = Factory(:null_test_tenant)
63
+ tenant = create(:null_test_tenant)
67
64
  tenant.nosync = false
68
65
  tenant.destroy
69
66
  end
@@ -1,13 +1,16 @@
1
1
  require "rubygems"
2
- require "simplecov"
2
+ require "active_support"
3
3
  require "active_support/core_ext"
4
- require "factory_girl"
5
- require "turn"
4
+ require "simplecov"
5
+ require "factory_bot"
6
6
  require "pry"
7
7
  require "database_cleaner"
8
8
  require "active_record"
9
9
  require "factories/tenants"
10
10
  require "minitest/autorun"
11
+ require "minitest/reporters/turn_reporter"
12
+
13
+ Minitest::Reporters.use! Minitest::Reporters::TurnReporter.new
11
14
 
12
15
  ActiveRecord::Base.establish_connection(
13
16
  :adapter => "sqlite3",
@@ -19,10 +22,19 @@ load File.join(File.dirname(__FILE__), "support", "schema.rb")
19
22
  DatabaseCleaner.strategy = :transaction
20
23
 
21
24
  class ActiveSupport::TestCase
25
+ include FactoryBot::Syntax::Methods
26
+
22
27
  setup do
23
28
  DatabaseCleaner.start
24
29
  end
25
30
  teardown do
26
31
  DatabaseCleaner.clean
32
+
33
+ Remotable.reset_nosync!
34
+ Tenant.reset_nosync!
35
+ BespokeTenant.reset_nosync!
36
+ RemoteWithoutKey.reset_nosync!
37
+ RemoteWithKey.reset_nosync!
38
+ RemoteWithCompositeKey.reset_nosync!
27
39
  end
28
40
  end
@@ -4,8 +4,6 @@ require "rr"
4
4
 
5
5
 
6
6
  class UnderstandingTest < ActiveSupport::TestCase
7
- include RR::Adapters::TestUnit
8
-
9
7
  # This test fails with an Error if `hello` is never called on `o`
10
8
  test "I know how rr works :)" do
11
9
  o = Object.new
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remotable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Lail
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-31 00:00:00.000000000 Z
11
+ date: 2019-11-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeresource
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: appraisal
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +81,35 @@ dependencies:
67
81
  - !ruby/object:Gem::Version
68
82
  version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
- name: turn
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 5.10.3
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 5.10.3
97
+ - !ruby/object:Gem::Dependency
98
+ name: minitest-reporters
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: minitest-reporters-turn_reporter
71
113
  requirement: !ruby/object:Gem::Requirement
72
114
  requirements:
73
115
  - - ">="
@@ -95,33 +137,33 @@ dependencies:
95
137
  - !ruby/object:Gem::Version
96
138
  version: '0'
97
139
  - !ruby/object:Gem::Dependency
98
- name: factory_girl
140
+ name: factory_bot
99
141
  requirement: !ruby/object:Gem::Requirement
100
142
  requirements:
101
- - - "~>"
143
+ - - ">="
102
144
  - !ruby/object:Gem::Version
103
- version: 2.0.4
145
+ version: '0'
104
146
  type: :development
105
147
  prerelease: false
106
148
  version_requirements: !ruby/object:Gem::Requirement
107
149
  requirements:
108
- - - "~>"
150
+ - - ">="
109
151
  - !ruby/object:Gem::Version
110
- version: 2.0.4
152
+ version: '0'
111
153
  - !ruby/object:Gem::Dependency
112
154
  name: sqlite3
113
155
  requirement: !ruby/object:Gem::Requirement
114
156
  requirements:
115
- - - "~>"
157
+ - - ">="
116
158
  - !ruby/object:Gem::Version
117
- version: 1.3.13
159
+ version: '0'
118
160
  type: :development
119
161
  prerelease: false
120
162
  version_requirements: !ruby/object:Gem::Requirement
121
163
  requirements:
122
- - - "~>"
164
+ - - ">="
123
165
  - !ruby/object:Gem::Version
124
- version: 1.3.13
166
+ version: '0'
125
167
  - !ruby/object:Gem::Dependency
126
168
  name: active_resource_simulator
127
169
  requirement: !ruby/object:Gem::Requirement
@@ -189,11 +231,16 @@ files:
189
231
  - ".gitignore"
190
232
  - ".simplecov"
191
233
  - ".travis.yml"
234
+ - Appraisals
192
235
  - Gemfile
193
- - Gemfile.lock
194
236
  - MIT-LICENSE
195
237
  - README.mdown
196
238
  - Rakefile
239
+ - gemfiles/rails_5.0.gemfile
240
+ - gemfiles/rails_5.1.gemfile
241
+ - gemfiles/rails_5.2.gemfile
242
+ - gemfiles/rails_6.0.gemfile
243
+ - gemfiles/rails_edge.gemfile
197
244
  - lib/remotable.rb
198
245
  - lib/remotable/active_record_extender.rb
199
246
  - lib/remotable/active_resource_fixes.rb
@@ -242,8 +289,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
289
  - !ruby/object:Gem::Version
243
290
  version: '0'
244
291
  requirements: []
245
- rubyforge_project: remotable
246
- rubygems_version: 2.6.11
292
+ rubygems_version: 3.0.3
247
293
  signing_key:
248
294
  specification_version: 4
249
295
  summary: Binds an ActiveRecord model to a remote resource and keeps the two synchronized
@@ -1,82 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- remotable (0.4.0)
5
- activerecord
6
- activeresource (>= 3.2)
7
- activesupport
8
-
9
- GEM
10
- remote: http://rubygems.org/
11
- specs:
12
- active_resource_simulator (0.0.2)
13
- activeresource
14
- activemodel (4.0.13)
15
- activesupport (= 4.0.13)
16
- builder (~> 3.1.0)
17
- activerecord (4.0.13)
18
- activemodel (= 4.0.13)
19
- activerecord-deprecated_finders (~> 1.0.2)
20
- activesupport (= 4.0.13)
21
- arel (~> 4.0.0)
22
- activerecord-deprecated_finders (1.0.4)
23
- activeresource (4.1.0)
24
- activemodel (~> 4.0)
25
- activesupport (~> 4.0)
26
- rails-observers (~> 0.1.2)
27
- activesupport (4.0.13)
28
- i18n (~> 0.6, >= 0.6.9)
29
- minitest (~> 4.2)
30
- multi_json (~> 1.3)
31
- thread_safe (~> 0.1)
32
- tzinfo (~> 0.3.37)
33
- ansi (1.5.0)
34
- arel (4.0.2)
35
- builder (3.1.4)
36
- coderay (1.1.2)
37
- concurrent-ruby (1.0.5)
38
- database_cleaner (1.2.0)
39
- docile (1.3.1)
40
- factory_girl (2.0.5)
41
- i18n (0.9.5)
42
- concurrent-ruby (~> 1.0)
43
- json (2.1.0)
44
- method_source (0.9.0)
45
- minitest (4.7.5)
46
- multi_json (1.13.1)
47
- pry (0.11.3)
48
- coderay (~> 1.1.0)
49
- method_source (~> 0.9.0)
50
- rails-observers (0.1.5)
51
- activemodel (>= 4.0)
52
- rake (12.3.1)
53
- rr (1.1.2)
54
- simplecov (0.16.1)
55
- docile (~> 1.1)
56
- json (>= 1.8, < 3)
57
- simplecov-html (~> 0.10.0)
58
- simplecov-html (0.10.2)
59
- sqlite3 (1.3.13)
60
- thread_safe (0.3.6)
61
- turn (0.9.7)
62
- ansi
63
- minitest (~> 4)
64
- tzinfo (0.3.54)
65
-
66
- PLATFORMS
67
- ruby
68
-
69
- DEPENDENCIES
70
- active_resource_simulator
71
- database_cleaner
72
- factory_girl (~> 2.0.4)
73
- pry
74
- rake
75
- remotable!
76
- rr
77
- simplecov
78
- sqlite3 (~> 1.3.13)
79
- turn
80
-
81
- BUNDLED WITH
82
- 1.16.1