remotable 0.2.4 → 0.2.5.beta1
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 +4 -4
- data/Gemfile.lock +82 -82
- data/MIT-LICENSE +0 -0
- data/lib/remotable/active_record_extender.rb +96 -20
- data/lib/remotable/active_resource_fixes.rb +14 -0
- data/lib/remotable/adapters/active_resource.rb +50 -4
- data/lib/remotable/errors.rb +5 -0
- data/lib/remotable/logger_wrapper.rb +37 -0
- data/lib/remotable/nosync.rb +9 -5
- data/lib/remotable/null_remote.rb +5 -2
- data/lib/remotable/version.rb +1 -1
- data/lib/remotable.rb +30 -0
- data/remotable.gemspec +2 -3
- data/test/active_resource_test.rb +78 -7
- data/test/nosync_test.rb +24 -0
- data/test/support/bespoke.rb +2 -3
- metadata +18 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dced86b6d1612537910a489e785e2dbb9b280018
|
|
4
|
+
data.tar.gz: db13ecad5bf99f21719f5e03ed4057fce8ed14f1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9fcb24667b7b4914f7d64efd18a7e27f8906e22adbc17c14ca2191d05a53f31d3e25a9d9fb58dbd244d47fad34bd63a9b7908d1526d871271dd980664a7bddbb
|
|
7
|
+
data.tar.gz: 189ac92190ec9add70eb40d364d434b7706dba41b49459e276500db31db14f99b15f63cd1270d5ca33aebf9e2bf8399bdf32731c445620634c33c45f6b17d1df
|
data/Gemfile.lock
CHANGED
|
@@ -9,104 +9,105 @@ PATH
|
|
|
9
9
|
GEM
|
|
10
10
|
remote: http://rubygems.org/
|
|
11
11
|
specs:
|
|
12
|
-
actionmailer (
|
|
13
|
-
actionpack (=
|
|
14
|
-
mail (~> 2.5.
|
|
15
|
-
actionpack (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
builder (~> 3.0.0)
|
|
12
|
+
actionmailer (4.0.2)
|
|
13
|
+
actionpack (= 4.0.2)
|
|
14
|
+
mail (~> 2.5.4)
|
|
15
|
+
actionpack (4.0.2)
|
|
16
|
+
activesupport (= 4.0.2)
|
|
17
|
+
builder (~> 3.1.0)
|
|
19
18
|
erubis (~> 2.7.0)
|
|
20
|
-
|
|
21
|
-
rack (~>
|
|
22
|
-
|
|
23
|
-
rack-test (~> 0.6.1)
|
|
24
|
-
sprockets (~> 2.2.1)
|
|
25
|
-
active_resource_simulator (0.0.1)
|
|
19
|
+
rack (~> 1.5.2)
|
|
20
|
+
rack-test (~> 0.6.2)
|
|
21
|
+
active_resource_simulator (0.0.2)
|
|
26
22
|
activeresource
|
|
27
|
-
activemodel (
|
|
28
|
-
activesupport (=
|
|
29
|
-
builder (~> 3.
|
|
30
|
-
activerecord (
|
|
31
|
-
activemodel (=
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
23
|
+
activemodel (4.0.2)
|
|
24
|
+
activesupport (= 4.0.2)
|
|
25
|
+
builder (~> 3.1.0)
|
|
26
|
+
activerecord (4.0.2)
|
|
27
|
+
activemodel (= 4.0.2)
|
|
28
|
+
activerecord-deprecated_finders (~> 1.0.2)
|
|
29
|
+
activesupport (= 4.0.2)
|
|
30
|
+
arel (~> 4.0.0)
|
|
31
|
+
activerecord-deprecated_finders (1.0.3)
|
|
32
|
+
activeresource (4.0.0)
|
|
33
|
+
activemodel (~> 4.0)
|
|
34
|
+
activesupport (~> 4.0)
|
|
35
|
+
rails-observers (~> 0.1.1)
|
|
36
|
+
activesupport (4.0.2)
|
|
37
|
+
i18n (~> 0.6, >= 0.6.4)
|
|
38
|
+
minitest (~> 4.2)
|
|
39
|
+
multi_json (~> 1.3)
|
|
40
|
+
thread_safe (~> 0.1)
|
|
41
|
+
tzinfo (~> 0.3.37)
|
|
41
42
|
ansi (1.4.3)
|
|
42
|
-
arel (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
arel (4.0.1)
|
|
44
|
+
atomic (1.1.14)
|
|
45
|
+
builder (3.1.4)
|
|
46
|
+
coderay (1.1.0)
|
|
47
|
+
database_cleaner (1.2.0)
|
|
48
|
+
docile (1.1.2)
|
|
46
49
|
erubis (2.7.0)
|
|
47
|
-
factory_girl (2.0.
|
|
48
|
-
hike (1.2.
|
|
49
|
-
i18n (0.6.
|
|
50
|
-
|
|
51
|
-
json (1.7.7)
|
|
52
|
-
mail (2.5.3)
|
|
53
|
-
i18n (>= 0.4.0)
|
|
50
|
+
factory_girl (2.0.5)
|
|
51
|
+
hike (1.2.3)
|
|
52
|
+
i18n (0.6.9)
|
|
53
|
+
mail (2.5.4)
|
|
54
54
|
mime-types (~> 1.16)
|
|
55
55
|
treetop (~> 1.4.8)
|
|
56
|
-
method_source (0.8.
|
|
57
|
-
mime-types (1.
|
|
58
|
-
minitest (
|
|
59
|
-
multi_json (1.
|
|
56
|
+
method_source (0.8.2)
|
|
57
|
+
mime-types (1.25.1)
|
|
58
|
+
minitest (4.7.5)
|
|
59
|
+
multi_json (1.8.4)
|
|
60
60
|
polyglot (0.3.3)
|
|
61
|
-
pry (0.9.
|
|
62
|
-
coderay (~> 1.0
|
|
61
|
+
pry (0.9.12.4)
|
|
62
|
+
coderay (~> 1.0)
|
|
63
63
|
method_source (~> 0.8)
|
|
64
|
-
slop (~> 3.
|
|
65
|
-
rack (1.
|
|
66
|
-
rack-cache (1.2)
|
|
67
|
-
rack (>= 0.4)
|
|
68
|
-
rack-ssl (1.3.3)
|
|
69
|
-
rack
|
|
64
|
+
slop (~> 3.4)
|
|
65
|
+
rack (1.5.2)
|
|
70
66
|
rack-test (0.6.2)
|
|
71
67
|
rack (>= 1.0)
|
|
72
|
-
rails (
|
|
73
|
-
actionmailer (=
|
|
74
|
-
actionpack (=
|
|
75
|
-
activerecord (=
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
68
|
+
rails (4.0.2)
|
|
69
|
+
actionmailer (= 4.0.2)
|
|
70
|
+
actionpack (= 4.0.2)
|
|
71
|
+
activerecord (= 4.0.2)
|
|
72
|
+
activesupport (= 4.0.2)
|
|
73
|
+
bundler (>= 1.3.0, < 2.0)
|
|
74
|
+
railties (= 4.0.2)
|
|
75
|
+
sprockets-rails (~> 2.0.0)
|
|
76
|
+
rails-observers (0.1.2)
|
|
77
|
+
activemodel (~> 4.0)
|
|
78
|
+
railties (4.0.2)
|
|
79
|
+
actionpack (= 4.0.2)
|
|
80
|
+
activesupport (= 4.0.2)
|
|
84
81
|
rake (>= 0.8.7)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
slop (3.3.3)
|
|
96
|
-
sprockets (2.2.2)
|
|
82
|
+
thor (>= 0.18.1, < 2.0)
|
|
83
|
+
rake (10.1.1)
|
|
84
|
+
rr (1.1.2)
|
|
85
|
+
simplecov (0.8.2)
|
|
86
|
+
docile (~> 1.1.0)
|
|
87
|
+
multi_json
|
|
88
|
+
simplecov-html (~> 0.8.0)
|
|
89
|
+
simplecov-html (0.8.0)
|
|
90
|
+
slop (3.4.7)
|
|
91
|
+
sprockets (2.10.1)
|
|
97
92
|
hike (~> 1.2)
|
|
98
93
|
multi_json (~> 1.0)
|
|
99
94
|
rack (~> 1.0)
|
|
100
95
|
tilt (~> 1.1, != 1.3.0)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
96
|
+
sprockets-rails (2.0.1)
|
|
97
|
+
actionpack (>= 3.0)
|
|
98
|
+
activesupport (>= 3.0)
|
|
99
|
+
sprockets (~> 2.8)
|
|
100
|
+
sqlite3 (1.3.8)
|
|
101
|
+
thor (0.18.1)
|
|
102
|
+
thread_safe (0.1.3)
|
|
103
|
+
atomic
|
|
104
|
+
tilt (1.4.1)
|
|
105
|
+
treetop (1.4.15)
|
|
105
106
|
polyglot
|
|
106
107
|
polyglot (>= 0.3.1)
|
|
107
108
|
turn (0.9.6)
|
|
108
109
|
ansi
|
|
109
|
-
tzinfo (0.3.
|
|
110
|
+
tzinfo (0.3.38)
|
|
110
111
|
|
|
111
112
|
PLATFORMS
|
|
112
113
|
ruby
|
|
@@ -114,10 +115,9 @@ PLATFORMS
|
|
|
114
115
|
DEPENDENCIES
|
|
115
116
|
active_resource_simulator
|
|
116
117
|
database_cleaner
|
|
117
|
-
factory_girl
|
|
118
|
-
minitest
|
|
118
|
+
factory_girl (~> 2.0.4)
|
|
119
119
|
pry
|
|
120
|
-
rails
|
|
120
|
+
rails (>= 3.1.0, < 5.0.0)
|
|
121
121
|
remotable!
|
|
122
122
|
rr
|
|
123
123
|
simplecov
|
data/MIT-LICENSE
CHANGED
|
File without changes
|
|
@@ -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 "benchmark"
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
module Remotable
|
|
@@ -9,7 +10,8 @@ module Remotable
|
|
|
9
10
|
include Nosync
|
|
10
11
|
|
|
11
12
|
def nosync?
|
|
12
|
-
|
|
13
|
+
return super if nosync_value?
|
|
14
|
+
self.class.nosync?
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
|
|
@@ -26,6 +28,7 @@ module Remotable
|
|
|
26
28
|
@remote_attribute_map ||= default_remote_attributes.map_to_self
|
|
27
29
|
@local_attribute_routes ||= {}
|
|
28
30
|
@expires_after ||= 1.day
|
|
31
|
+
@remote_timeout = { :index => 4, :show => 1, :update => 2, :create => 2, :destroy => 2 }
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
|
|
@@ -34,7 +37,9 @@ module Remotable
|
|
|
34
37
|
include Nosync
|
|
35
38
|
|
|
36
39
|
def nosync?
|
|
37
|
-
|
|
40
|
+
return true if remote_model.nil?
|
|
41
|
+
return super if nosync_value?
|
|
42
|
+
Remotable.nosync?
|
|
38
43
|
end
|
|
39
44
|
|
|
40
45
|
# Sets the key with which a resource is identified remotely.
|
|
@@ -84,6 +89,14 @@ module Remotable
|
|
|
84
89
|
@local_attribute_routes = {} # reset routes
|
|
85
90
|
end
|
|
86
91
|
|
|
92
|
+
def remote_timeout(*args)
|
|
93
|
+
if args.any?
|
|
94
|
+
@remote_timeout = n = args.first
|
|
95
|
+
@remote_timeout = {:index => n, :show => n, :create => n, :update => n, :destroy => n} if n.is_a?(Numeric)
|
|
96
|
+
end
|
|
97
|
+
@remote_timeout
|
|
98
|
+
end
|
|
99
|
+
|
|
87
100
|
def fetch_with(local_key, options={})
|
|
88
101
|
@local_attribute_routes.merge!(local_key => options[:path])
|
|
89
102
|
end
|
|
@@ -140,12 +153,27 @@ module Remotable
|
|
|
140
153
|
def instantiate(*args)
|
|
141
154
|
record = super
|
|
142
155
|
if record.expired? && !record.nosync?
|
|
143
|
-
|
|
144
|
-
|
|
156
|
+
begin
|
|
157
|
+
Remotable.logger.debug "[remotable:#{name.underscore}:instantiate](#{record.fetch_value.inspect}) expired #{record.expires_at}"
|
|
158
|
+
record.pull_remote_data!
|
|
159
|
+
record = nil if record.destroyed?
|
|
160
|
+
rescue Remotable::TimeoutError
|
|
161
|
+
report_ignored_timeout_error($!)
|
|
162
|
+
rescue Remotable::ServiceUnavailableError
|
|
163
|
+
report_ignored_503_error($!)
|
|
164
|
+
end
|
|
145
165
|
end
|
|
146
166
|
record
|
|
147
167
|
end
|
|
148
168
|
|
|
169
|
+
def report_ignored_timeout_error(error)
|
|
170
|
+
Remotable.logger.error "[remotable:#{name.underscore}:instantiate] #{error.message}"
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def report_ignored_503_error(error)
|
|
174
|
+
Remotable.logger.error "[remotable:#{name.underscore}:instantiate] #{error.message}"
|
|
175
|
+
end
|
|
176
|
+
|
|
149
177
|
|
|
150
178
|
|
|
151
179
|
def respond_to?(method_sym, include_private=false)
|
|
@@ -163,7 +191,7 @@ module Remotable
|
|
|
163
191
|
raise ArgumentError, "#{method_sym} was called with #{values.length} but #{local_attributes.length} was expected"
|
|
164
192
|
end
|
|
165
193
|
|
|
166
|
-
local_resource = ((0...local_attributes.length).inject(
|
|
194
|
+
local_resource = ((0...local_attributes.length).inject(self) do |scope, i|
|
|
167
195
|
scope.where(local_attributes[i] => values[i])
|
|
168
196
|
end).first || fetch_by(method_details[:remote_key], *values)
|
|
169
197
|
|
|
@@ -215,9 +243,21 @@ module Remotable
|
|
|
215
243
|
remote_resource && new_from_remote(remote_resource)
|
|
216
244
|
end
|
|
217
245
|
|
|
218
|
-
# Looks the resource up remotely;
|
|
219
|
-
# Returns the remote resource.
|
|
220
246
|
def find_remote_resource_by(remote_attr, *values)
|
|
247
|
+
invoke_remote_model_find_by(remote_attr, *values)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def find_remote_resource_for_local_by(local_resource, remote_attr, *values)
|
|
251
|
+
if remote_model.respond_to?(:find_by_for_local)
|
|
252
|
+
invoke_remote_model_find_by_for_local(local_resource, remote_attr, *values)
|
|
253
|
+
else
|
|
254
|
+
invoke_remote_model_find_by(remote_attr, *values)
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def invoke_remote_model_find_by(remote_attr, *values)
|
|
259
|
+
remote_set_timeout :show
|
|
260
|
+
|
|
221
261
|
find_by = remote_model.method(:find_by)
|
|
222
262
|
case find_by.arity
|
|
223
263
|
when 1; find_by.call(remote_path_for(remote_attr, *values))
|
|
@@ -227,6 +267,20 @@ module Remotable
|
|
|
227
267
|
end
|
|
228
268
|
end
|
|
229
269
|
|
|
270
|
+
def invoke_remote_model_find_by_for_local(local_resource, remote_attr, *values)
|
|
271
|
+
remote_set_timeout :show
|
|
272
|
+
|
|
273
|
+
find_by_for_local = remote_model.method(:find_by_for_local)
|
|
274
|
+
case find_by_for_local.arity
|
|
275
|
+
when 2; find_by_for_local.call(local_resource, remote_path_for(remote_attr, *values))
|
|
276
|
+
when 3; find_by_for_local.call(local_resource, remote_attr, *values)
|
|
277
|
+
else
|
|
278
|
+
raise InvalidRemoteModel, "#{remote_model}.find_by_for_local should take either 2 or 3 parameters"
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
|
|
230
284
|
def remote_path_for(remote_key, *values)
|
|
231
285
|
route = route_for(remote_key)
|
|
232
286
|
local_key = self.local_key(remote_key)
|
|
@@ -260,12 +314,13 @@ module Remotable
|
|
|
260
314
|
end
|
|
261
315
|
|
|
262
316
|
def find_by_remote_query(remote_method_name, *args)
|
|
263
|
-
|
|
317
|
+
remote_set_timeout :index
|
|
318
|
+
remote_resources = Array.wrap(remote_model.send(remote_method_name, *args))
|
|
264
319
|
map_remote_resources_to_local(remote_resources)
|
|
265
320
|
end
|
|
266
321
|
|
|
267
322
|
def map_remote_resources_to_local(remote_resources)
|
|
268
|
-
return [] if remote_resources.empty?
|
|
323
|
+
return [] if remote_resources.nil? || remote_resources.empty?
|
|
269
324
|
|
|
270
325
|
local_resources = nosync { fetch_corresponding_local_resources(remote_resources).to_a }
|
|
271
326
|
|
|
@@ -279,7 +334,7 @@ module Remotable
|
|
|
279
334
|
local_resource = local_resources.detect { |local_resource|
|
|
280
335
|
Array.wrap(remote_key).all? { |remote_attr|
|
|
281
336
|
local_attr = local_attribute_name(remote_attr)
|
|
282
|
-
local_resource.send(local_attr) == remote_resource
|
|
337
|
+
local_resource.send(local_attr) == remote_resource[remote_attr]
|
|
283
338
|
}
|
|
284
339
|
}
|
|
285
340
|
|
|
@@ -298,7 +353,7 @@ module Remotable
|
|
|
298
353
|
def fetch_corresponding_local_resources(remote_resources)
|
|
299
354
|
conditions = Array.wrap(remote_key).each_with_object({}) do |remote_attr, query|
|
|
300
355
|
local_attr = local_attribute_name(remote_attr)
|
|
301
|
-
query[local_attr] = remote_resources.map
|
|
356
|
+
query[local_attr] = remote_resources.map { |resource| resource[remote_attr] }
|
|
302
357
|
end
|
|
303
358
|
|
|
304
359
|
where(conditions)
|
|
@@ -306,6 +361,12 @@ module Remotable
|
|
|
306
361
|
|
|
307
362
|
|
|
308
363
|
|
|
364
|
+
def remote_set_timeout(mode)
|
|
365
|
+
remote_model.timeout = remote_timeout[mode] if remote_model.respond_to?(:timeout=)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
|
|
309
370
|
private
|
|
310
371
|
|
|
311
372
|
def default_remote_attributes
|
|
@@ -339,6 +400,7 @@ module Remotable
|
|
|
339
400
|
:local_attribute_names,
|
|
340
401
|
:local_attribute_name,
|
|
341
402
|
:expires_after,
|
|
403
|
+
:remote_set_timeout,
|
|
342
404
|
:to => "self.class"
|
|
343
405
|
|
|
344
406
|
def expired?
|
|
@@ -371,8 +433,6 @@ module Remotable
|
|
|
371
433
|
|
|
372
434
|
|
|
373
435
|
|
|
374
|
-
private
|
|
375
|
-
|
|
376
436
|
def fetch_value
|
|
377
437
|
if local_key.is_a?(Array)
|
|
378
438
|
local_key.map(&method(:send))
|
|
@@ -381,16 +441,21 @@ module Remotable
|
|
|
381
441
|
end
|
|
382
442
|
end
|
|
383
443
|
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
private
|
|
447
|
+
|
|
384
448
|
def fetch_remote_resource
|
|
385
449
|
fetch_value && find_remote_resource_by(remote_key, fetch_value)
|
|
386
450
|
end
|
|
387
451
|
|
|
388
452
|
def find_remote_resource_by(remote_key, fetch_value)
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
self.class.find_remote_resource_by(remote_key, fetch_value)
|
|
453
|
+
result = nil
|
|
454
|
+
ms = Benchmark.ms do
|
|
455
|
+
result = self.class.find_remote_resource_for_local_by(self, remote_key, fetch_value)
|
|
393
456
|
end
|
|
457
|
+
Remotable.logger.info "[remotable:#{self.class.name.underscore}:find_remote_resource_by](#{fetch_value.inspect}) %.1fms" % [ ms ]
|
|
458
|
+
result
|
|
394
459
|
end
|
|
395
460
|
|
|
396
461
|
def merge_remote_data!(remote_resource)
|
|
@@ -401,6 +466,7 @@ module Remotable
|
|
|
401
466
|
end
|
|
402
467
|
|
|
403
468
|
def remote_model_has_been_destroyed!
|
|
469
|
+
Remotable.logger.info "[remotable:#{self.class.name.underscore}:remote_model_has_been_destroyed!](#{fetch_value.inspect})"
|
|
404
470
|
nosync { destroy }
|
|
405
471
|
end
|
|
406
472
|
|
|
@@ -409,6 +475,8 @@ module Remotable
|
|
|
409
475
|
def update_remote_resource
|
|
410
476
|
if any_remote_changes? && remote_resource
|
|
411
477
|
merge_local_data(remote_resource, true)
|
|
478
|
+
|
|
479
|
+
remote_set_timeout :update
|
|
412
480
|
if remote_resource.save
|
|
413
481
|
merge_remote_data!(remote_resource)
|
|
414
482
|
else
|
|
@@ -422,6 +490,7 @@ module Remotable
|
|
|
422
490
|
@remote_resource = remote_model.new_resource
|
|
423
491
|
merge_local_data(@remote_resource)
|
|
424
492
|
|
|
493
|
+
remote_set_timeout :create
|
|
425
494
|
if @remote_resource.save
|
|
426
495
|
|
|
427
496
|
# This line is especially crucial if the primary key
|
|
@@ -436,6 +505,8 @@ module Remotable
|
|
|
436
505
|
|
|
437
506
|
def destroy_remote_resource
|
|
438
507
|
return nil unless remote_resource
|
|
508
|
+
|
|
509
|
+
remote_set_timeout :destroy
|
|
439
510
|
if remote_resource.destroy
|
|
440
511
|
true
|
|
441
512
|
else
|
|
@@ -467,6 +538,7 @@ module Remotable
|
|
|
467
538
|
|
|
468
539
|
|
|
469
540
|
def merge_remote_errors(errors)
|
|
541
|
+
Remotable.logger.debug "[remotable:#{self.class.name.underscore}:merge_remote_errors](#{fetch_value.inspect}) #{errors.inspect}"
|
|
470
542
|
errors.each do |attribute, messages|
|
|
471
543
|
Array.wrap(messages).each do |message|
|
|
472
544
|
self.errors.add(local_attribute_name(attribute), message)
|
|
@@ -477,8 +549,10 @@ module Remotable
|
|
|
477
549
|
|
|
478
550
|
def merge_remote_data(remote_resource)
|
|
479
551
|
remote_attribute_map.each do |remote_attr, local_attr|
|
|
480
|
-
if remote_resource.
|
|
481
|
-
|
|
552
|
+
if remote_resource.key?(remote_attr)
|
|
553
|
+
remote_value = remote_resource[remote_attr]
|
|
554
|
+
Remotable.logger.debug "[remotable:#{self.class.name.underscore}:merge_remote_data](#{fetch_value.inspect}) local.#{local_attr} = #{remote_value.inspect}"
|
|
555
|
+
send("#{local_attr}=", remote_value)
|
|
482
556
|
end
|
|
483
557
|
end
|
|
484
558
|
self
|
|
@@ -487,7 +561,9 @@ module Remotable
|
|
|
487
561
|
def merge_local_data(remote_resource, changes_only=false)
|
|
488
562
|
remote_attribute_map.each do |remote_attr, local_attr|
|
|
489
563
|
if !changes_only || local_attribute_changed?(local_attr)
|
|
490
|
-
|
|
564
|
+
local_value = send(local_attr)
|
|
565
|
+
Remotable.logger.debug "[remotable:#{self.class.name.underscore}:merge_local_data](#{fetch_value.inspect}) remote.#{remote_attr} = #{local_value.inspect}"
|
|
566
|
+
remote_resource[remote_attr] = local_value
|
|
491
567
|
end
|
|
492
568
|
end
|
|
493
569
|
self
|
|
@@ -99,6 +99,20 @@ end
|
|
|
99
99
|
ActiveResource::Base.send(:include, ActiveResourceFixes)
|
|
100
100
|
|
|
101
101
|
|
|
102
|
+
|
|
103
|
+
module ActiveResourceJsonFormatFixes
|
|
104
|
+
|
|
105
|
+
def decode(json)
|
|
106
|
+
return {} if json.blank? # <-- insert this line. json will be nil if response is 304
|
|
107
|
+
super
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
ActiveResource::Formats::JsonFormat.extend ActiveResourceJsonFormatFixes
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
102
116
|
# ActiveResource expects that errors will be an array of string
|
|
103
117
|
# However, this is not what Rails Responders are inclined to return.
|
|
104
118
|
|
|
@@ -8,16 +8,50 @@ module Remotable
|
|
|
8
8
|
module ActiveResource
|
|
9
9
|
extend ActiveSupport::Concern
|
|
10
10
|
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def key?(attribute)
|
|
14
|
+
attributes.key?(attribute.to_s)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def [](attribute)
|
|
18
|
+
attributes[attribute.to_s]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def []=(attribute, value)
|
|
22
|
+
attributes[attribute.to_s] = value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
11
27
|
module ClassMethods
|
|
12
28
|
|
|
29
|
+
IF_MODIFIED_SINCE = "If-Modified-Since".freeze
|
|
30
|
+
|
|
31
|
+
|
|
13
32
|
|
|
14
33
|
def new_resource
|
|
15
34
|
new
|
|
16
35
|
end
|
|
17
36
|
|
|
18
37
|
|
|
19
|
-
|
|
20
|
-
|
|
38
|
+
|
|
39
|
+
# This is always invoked by instance#fetch_remote_resource.
|
|
40
|
+
# It expects to find a remote counterpart for a local resource.
|
|
41
|
+
# It should always return a NullRemote object that doesn't
|
|
42
|
+
# alter the behavior of a normal model at all.
|
|
43
|
+
def find_by_for_local(local_record, path)
|
|
44
|
+
had_previous_value = headers.key?(IF_MODIFIED_SINCE)
|
|
45
|
+
previous_value = headers[IF_MODIFIED_SINCE]
|
|
46
|
+
|
|
47
|
+
headers[IF_MODIFIED_SINCE] = Remotable.http_format_time(local_record.updated_at) if local_record.respond_to?(:updated_at)
|
|
48
|
+
find_by(path)
|
|
49
|
+
ensure
|
|
50
|
+
if had_previous_value
|
|
51
|
+
headers[IF_MODIFIED_SINCE] = previous_value
|
|
52
|
+
else
|
|
53
|
+
headers.delete(IF_MODIFIED_SINCE)
|
|
54
|
+
end
|
|
21
55
|
end
|
|
22
56
|
|
|
23
57
|
def find_by(path)
|
|
@@ -26,6 +60,19 @@ module Remotable
|
|
|
26
60
|
nil
|
|
27
61
|
end
|
|
28
62
|
|
|
63
|
+
def find_by!(path)
|
|
64
|
+
expanded_path = expanded_path_for(path)
|
|
65
|
+
Remotable.logger.info "[remotable:#{name.underscore}] GET #{expanded_path} (timeout: #{timeout})"
|
|
66
|
+
find(:one, :from => expanded_path)
|
|
67
|
+
rescue ::ActiveResource::TimeoutError
|
|
68
|
+
$!.extend Remotable::TimeoutError
|
|
69
|
+
raise
|
|
70
|
+
rescue ::ActiveResource::ServerError
|
|
71
|
+
$!.extend Remotable::ServiceUnavailableError if $!.response.code == 503
|
|
72
|
+
raise
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
|
|
29
76
|
|
|
30
77
|
def expanded_path_for(path)
|
|
31
78
|
if relative_path?(path)
|
|
@@ -36,14 +83,13 @@ module Remotable
|
|
|
36
83
|
end
|
|
37
84
|
|
|
38
85
|
|
|
39
|
-
private
|
|
40
86
|
|
|
87
|
+
private
|
|
41
88
|
|
|
42
89
|
def relative_path?(path)
|
|
43
90
|
!(path.start_with?("/") || path["://"])
|
|
44
91
|
end
|
|
45
92
|
|
|
46
|
-
|
|
47
93
|
end
|
|
48
94
|
end
|
|
49
95
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Remotable
|
|
2
|
+
class LoggerWrapper
|
|
3
|
+
|
|
4
|
+
def initialize(logger)
|
|
5
|
+
@logger = logger
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
attr_reader :logger
|
|
9
|
+
|
|
10
|
+
def debug(*args)
|
|
11
|
+
logger.debug(*args) if log? :debug
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def info(*args)
|
|
15
|
+
logger.info(*args) if log? :info
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def warn(*args)
|
|
19
|
+
logger.warn(*args) if log? :warn
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def error(*args)
|
|
23
|
+
logger.error(*args) if log? :error
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
LEVELS = [:debug, :info, :warn, :error].freeze
|
|
29
|
+
|
|
30
|
+
def log?(value)
|
|
31
|
+
level = LEVELS.index(Remotable.log_level)
|
|
32
|
+
value = LEVELS.index(value)
|
|
33
|
+
value >= level
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/remotable/nosync.rb
CHANGED
|
@@ -6,16 +6,20 @@ module Remotable
|
|
|
6
6
|
self.nosync = true
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def nosync
|
|
10
|
-
|
|
11
|
-
nosync
|
|
9
|
+
def nosync(new_value=true)
|
|
10
|
+
old_value = @nosync
|
|
11
|
+
self.nosync = new_value
|
|
12
12
|
yield
|
|
13
13
|
ensure
|
|
14
|
-
|
|
14
|
+
@nosync = old_value
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def nosync=(val)
|
|
18
|
-
@nosync =
|
|
18
|
+
@nosync = val
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def nosync_value?
|
|
22
|
+
!@nosync.nil?
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
def nosync?
|
|
@@ -27,13 +27,16 @@ module Remotable
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
|
|
30
31
|
# NullRemote needs to receive setter messages and
|
|
31
32
|
# swallow them. It doesn't need to respond to getter
|
|
32
33
|
# messages since it has nothing to say.
|
|
33
|
-
def
|
|
34
|
-
super unless method_name.to_s =~ /=$/
|
|
34
|
+
def []=(attribute, value)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
def key?(attribute)
|
|
38
|
+
false
|
|
39
|
+
end
|
|
37
40
|
|
|
38
41
|
def save
|
|
39
42
|
true
|
data/lib/remotable/version.rb
CHANGED
data/lib/remotable.rb
CHANGED
|
@@ -3,6 +3,8 @@ require "remotable/nosync"
|
|
|
3
3
|
require "remotable/null_remote"
|
|
4
4
|
require "remotable/validate_models"
|
|
5
5
|
require "remotable/with_remote_model_proxy"
|
|
6
|
+
require "remotable/errors"
|
|
7
|
+
require "remotable/logger_wrapper"
|
|
6
8
|
|
|
7
9
|
|
|
8
10
|
# Remotable keeps a locally-stored ActiveRecord
|
|
@@ -42,6 +44,16 @@ module Remotable
|
|
|
42
44
|
# but turn it off in production.
|
|
43
45
|
self.validate_models = true
|
|
44
46
|
|
|
47
|
+
# Logger
|
|
48
|
+
def self.logger; @logger ||= LoggerWrapper.new(FakeLogger.new); end
|
|
49
|
+
def self.logger=(logger); @logger = LoggerWrapper.new(logger); end
|
|
50
|
+
|
|
51
|
+
class << self
|
|
52
|
+
attr_accessor :log_level
|
|
53
|
+
Remotable.log_level = :debug
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
45
57
|
|
|
46
58
|
# == remote_model( model [optional] )
|
|
47
59
|
#
|
|
@@ -112,6 +124,24 @@ module Remotable
|
|
|
112
124
|
|
|
113
125
|
class InvalidRemoteModel < ArgumentError; end
|
|
114
126
|
|
|
127
|
+
class FakeLogger
|
|
128
|
+
|
|
129
|
+
def write(s)
|
|
130
|
+
puts s
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
alias :debug :write
|
|
134
|
+
alias :info :write
|
|
135
|
+
alias :warn :write
|
|
136
|
+
alias :error :write
|
|
137
|
+
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def self.http_format_time(time)
|
|
142
|
+
time.utc.strftime("%a, %e %b %Y %H:%M:%S %Z")
|
|
143
|
+
end
|
|
144
|
+
|
|
115
145
|
|
|
116
146
|
|
|
117
147
|
private
|
data/remotable.gemspec
CHANGED
|
@@ -17,11 +17,10 @@ Gem::Specification.new do |s|
|
|
|
17
17
|
s.add_dependency "activerecord"
|
|
18
18
|
s.add_dependency "activesupport"
|
|
19
19
|
|
|
20
|
-
s.add_development_dependency "rails"
|
|
21
|
-
s.add_development_dependency "minitest"
|
|
20
|
+
s.add_development_dependency "rails", ">= 3.1.0", "< 5.0.0"
|
|
22
21
|
s.add_development_dependency "turn"
|
|
23
22
|
s.add_development_dependency "pry"
|
|
24
|
-
s.add_development_dependency "factory_girl"
|
|
23
|
+
s.add_development_dependency "factory_girl", "~> 2.0.4"
|
|
25
24
|
s.add_development_dependency "sqlite3"
|
|
26
25
|
s.add_development_dependency "active_resource_simulator"
|
|
27
26
|
s.add_development_dependency "simplecov"
|
|
@@ -14,6 +14,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
|
|
17
18
|
# ========================================================================= #
|
|
18
19
|
# Finding #
|
|
19
20
|
# ========================================================================= #
|
|
@@ -117,6 +118,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
117
118
|
|
|
118
119
|
|
|
119
120
|
|
|
121
|
+
|
|
120
122
|
# ========================================================================= #
|
|
121
123
|
# Expiration #
|
|
122
124
|
# ========================================================================= #
|
|
@@ -146,13 +148,40 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
146
148
|
:id => tenant.remote_id,
|
|
147
149
|
:slug => tenant.slug,
|
|
148
150
|
:church_name => unexpected_name
|
|
149
|
-
})
|
|
151
|
+
}, :headers => if_modified_since(tenant))
|
|
150
152
|
|
|
151
153
|
tenant = Tenant.find_by_remote_id(tenant.remote_id)
|
|
152
154
|
assert_equal unexpected_name, tenant.name
|
|
153
155
|
end
|
|
154
156
|
end
|
|
155
157
|
|
|
158
|
+
test "should treat a 304 response as no changes" do
|
|
159
|
+
tenant = Factory(:tenant, :expires_at => 1.year.ago)
|
|
160
|
+
|
|
161
|
+
RemoteTenant.run_simulation do |s|
|
|
162
|
+
s.show(tenant.remote_id, nil, :status => 304, :headers => if_modified_since(tenant))
|
|
163
|
+
|
|
164
|
+
tenant = Tenant.find_by_remote_id(tenant.remote_id)
|
|
165
|
+
assert tenant.expires_at > Time.now, "Tenant should be considered fresh"
|
|
166
|
+
assert_not_nil tenant.remote_id, "The Remote Tenant's id should not be considered nil just because there was no body in the remote response"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
test "should ignore a 503 response" do
|
|
171
|
+
expired_at = 1.year.ago
|
|
172
|
+
tenant = Factory(:tenant, :expires_at => expired_at)
|
|
173
|
+
|
|
174
|
+
RemoteTenant.run_simulation do |s|
|
|
175
|
+
s.show(tenant.remote_id, nil, :status => 503, :headers => if_modified_since(tenant))
|
|
176
|
+
|
|
177
|
+
assert_nothing_raised do
|
|
178
|
+
tenant = Tenant.find_by_remote_id(tenant.remote_id)
|
|
179
|
+
end
|
|
180
|
+
assert_equal expired_at, tenant.expires_at, "Tenant's expiration date should not have changed"
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
|
|
156
185
|
|
|
157
186
|
|
|
158
187
|
# ========================================================================= #
|
|
@@ -168,7 +197,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
168
197
|
:id => tenant.remote_id,
|
|
169
198
|
:slug => "totally-wonky",
|
|
170
199
|
:church_name => tenant.name
|
|
171
|
-
})
|
|
200
|
+
}, :headers => if_modified_since(tenant))
|
|
172
201
|
|
|
173
202
|
tenant.nosync = false
|
|
174
203
|
tenant.name = "Totally Wonky"
|
|
@@ -191,7 +220,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
191
220
|
:id => tenant.remote_id,
|
|
192
221
|
:slug => tenant.slug,
|
|
193
222
|
:church_name => tenant.name
|
|
194
|
-
})
|
|
223
|
+
}, :headers => if_modified_since(tenant))
|
|
195
224
|
s.update(tenant.remote_id, :status => 422, :body => {
|
|
196
225
|
:errors => {:church_name => ["is already taken"]}
|
|
197
226
|
})
|
|
@@ -275,6 +304,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
275
304
|
|
|
276
305
|
|
|
277
306
|
|
|
307
|
+
|
|
278
308
|
# ========================================================================= #
|
|
279
309
|
# Destroying #
|
|
280
310
|
# ========================================================================= #
|
|
@@ -287,7 +317,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
287
317
|
:id => tenant.remote_id,
|
|
288
318
|
:slug => tenant.slug,
|
|
289
319
|
:church_name => tenant.name
|
|
290
|
-
})
|
|
320
|
+
}, :headers => if_modified_since(tenant))
|
|
291
321
|
|
|
292
322
|
# Throws an error if save is not called on the remote resource
|
|
293
323
|
mock(tenant.remote_resource).destroy { true }
|
|
@@ -305,7 +335,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
305
335
|
:id => tenant.remote_id,
|
|
306
336
|
:slug => tenant.slug,
|
|
307
337
|
:church_name => tenant.name
|
|
308
|
-
})
|
|
338
|
+
}, :headers => if_modified_since(tenant))
|
|
309
339
|
|
|
310
340
|
s.destroy(tenant.remote_id,
|
|
311
341
|
:body => { :errors => { :base => ["nope"] } },
|
|
@@ -323,9 +353,9 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
323
353
|
|
|
324
354
|
assert_difference "Tenant.count", -1 do
|
|
325
355
|
RemoteTenant.run_simulation do |s|
|
|
326
|
-
s.show(tenant.remote_id, nil, :status => 404)
|
|
356
|
+
s.show(tenant.remote_id, nil, :status => 404, :headers => if_modified_since(tenant))
|
|
327
357
|
|
|
328
|
-
tenant = Tenant.
|
|
358
|
+
tenant = Tenant.where(:remote_id => tenant.remote_id).first
|
|
329
359
|
assert_equal nil, tenant
|
|
330
360
|
end
|
|
331
361
|
end
|
|
@@ -333,6 +363,7 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
333
363
|
|
|
334
364
|
|
|
335
365
|
|
|
366
|
+
|
|
336
367
|
# ========================================================================= #
|
|
337
368
|
# Listing #
|
|
338
369
|
# ========================================================================= #
|
|
@@ -365,4 +396,44 @@ class ActiveResourceTest < ActiveSupport::TestCase
|
|
|
365
396
|
|
|
366
397
|
|
|
367
398
|
|
|
399
|
+
# ========================================================================= #
|
|
400
|
+
# Timeouts #
|
|
401
|
+
# ========================================================================= #
|
|
402
|
+
|
|
403
|
+
test "should raise a Remotable::TimeoutError when a timeout occurs" do
|
|
404
|
+
assert_raise Remotable::TimeoutError do
|
|
405
|
+
stub(Tenant.remote_model).find do |*args|
|
|
406
|
+
raise ActiveResource::TimeoutError, "it timed out"
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
Tenant.find_by_remote_id(15)
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
test "should ignore a Remotable::TimeoutError when instantiating a record" do
|
|
414
|
+
tenant = Factory(:tenant, :expires_at => 1.year.ago)
|
|
415
|
+
|
|
416
|
+
assert_nothing_raised do
|
|
417
|
+
stub(Tenant.remote_model).find do |*args|
|
|
418
|
+
raise ActiveResource::TimeoutError, "it timed out"
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
tenant = Tenant.find_by_remote_id(tenant.remote_id)
|
|
422
|
+
assert_not_nil tenant
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
private
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def if_modified_since(record)
|
|
434
|
+
{"If-Modified-Since" => Remotable.http_format_time(record.updated_at)}
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
|
|
368
439
|
end
|
data/test/nosync_test.rb
CHANGED
|
@@ -25,6 +25,30 @@ class NoSyncTest < ActiveSupport::TestCase
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
test "nosync? should be false if syncing is resumed temporarily on a model that prevents it by default" do
|
|
29
|
+
Tenant.nosync!
|
|
30
|
+
assert_equal true, Tenant.new.nosync?
|
|
31
|
+
Tenant.nosync(false) do
|
|
32
|
+
assert_equal false, Tenant.new.nosync?
|
|
33
|
+
end
|
|
34
|
+
assert_equal true, Tenant.new.nosync?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
test "nosync? should take the value further up the chain if a model's value is temporarily cleared" do
|
|
38
|
+
assert_not_nil Tenant.remote_model
|
|
39
|
+
|
|
40
|
+
Remotable.nosync!
|
|
41
|
+
Tenant.nosync(false) do
|
|
42
|
+
Tenant.nosync(nil) do
|
|
43
|
+
assert_equal false, Tenant.nosync_value?
|
|
44
|
+
assert_equal true, Tenant.nosync?
|
|
45
|
+
end
|
|
46
|
+
assert_equal true, Tenant.nosync_value?
|
|
47
|
+
assert_equal false, Tenant.nosync?
|
|
48
|
+
end
|
|
49
|
+
assert_equal true, Tenant.nosync?
|
|
50
|
+
end
|
|
51
|
+
|
|
28
52
|
|
|
29
53
|
|
|
30
54
|
# ========================================================================= #
|
data/test/support/bespoke.rb
CHANGED
|
@@ -28,11 +28,10 @@ end
|
|
|
28
28
|
class BespokeResource
|
|
29
29
|
|
|
30
30
|
def initialize(attributes={})
|
|
31
|
-
|
|
32
|
-
self.name = attributes[:name]
|
|
31
|
+
@attributes = attributes
|
|
33
32
|
end
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
delegate :key?, :[], :[]=, :to => :@attributes
|
|
36
35
|
|
|
37
36
|
def save
|
|
38
37
|
true
|
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.2.
|
|
4
|
+
version: 0.2.5.beta1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Robert Lail
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2014-02-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activeresource
|
|
@@ -58,28 +58,20 @@ dependencies:
|
|
|
58
58
|
requirements:
|
|
59
59
|
- - '>='
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
62
|
-
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - '>='
|
|
61
|
+
version: 3.1.0
|
|
62
|
+
- - <
|
|
67
63
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: minitest
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - '>='
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '0'
|
|
64
|
+
version: 5.0.0
|
|
76
65
|
type: :development
|
|
77
66
|
prerelease: false
|
|
78
67
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
68
|
requirements:
|
|
80
69
|
- - '>='
|
|
81
70
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
71
|
+
version: 3.1.0
|
|
72
|
+
- - <
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: 5.0.0
|
|
83
75
|
- !ruby/object:Gem::Dependency
|
|
84
76
|
name: turn
|
|
85
77
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -112,16 +104,16 @@ dependencies:
|
|
|
112
104
|
name: factory_girl
|
|
113
105
|
requirement: !ruby/object:Gem::Requirement
|
|
114
106
|
requirements:
|
|
115
|
-
- -
|
|
107
|
+
- - ~>
|
|
116
108
|
- !ruby/object:Gem::Version
|
|
117
|
-
version:
|
|
109
|
+
version: 2.0.4
|
|
118
110
|
type: :development
|
|
119
111
|
prerelease: false
|
|
120
112
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
113
|
requirements:
|
|
122
|
-
- -
|
|
114
|
+
- - ~>
|
|
123
115
|
- !ruby/object:Gem::Version
|
|
124
|
-
version:
|
|
116
|
+
version: 2.0.4
|
|
125
117
|
- !ruby/object:Gem::Dependency
|
|
126
118
|
name: sqlite3
|
|
127
119
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -215,6 +207,8 @@ files:
|
|
|
215
207
|
- lib/remotable/core_ext/enumerable.rb
|
|
216
208
|
- lib/remotable/core_ext/object.rb
|
|
217
209
|
- lib/remotable/core_ext/uri.rb
|
|
210
|
+
- lib/remotable/errors.rb
|
|
211
|
+
- lib/remotable/logger_wrapper.rb
|
|
218
212
|
- lib/remotable/nosync.rb
|
|
219
213
|
- lib/remotable/null_remote.rb
|
|
220
214
|
- lib/remotable/validate_models.rb
|
|
@@ -247,12 +241,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
247
241
|
version: '0'
|
|
248
242
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
249
243
|
requirements:
|
|
250
|
-
- - '
|
|
244
|
+
- - '>'
|
|
251
245
|
- !ruby/object:Gem::Version
|
|
252
|
-
version:
|
|
246
|
+
version: 1.3.1
|
|
253
247
|
requirements: []
|
|
254
248
|
rubyforge_project: remotable
|
|
255
|
-
rubygems_version: 2.
|
|
249
|
+
rubygems_version: 2.2.1
|
|
256
250
|
signing_key:
|
|
257
251
|
specification_version: 4
|
|
258
252
|
summary: Binds an ActiveRecord model to a remote resource and keeps the two synchronized
|