copycopter_client 1.0.0.beta8 → 1.0.0.beta9
Sign up to get free protection for your applications and to get access to all the features.
- data/features/rails.feature +1 -4
- data/lib/copycopter_client/client.rb +21 -9
- data/lib/copycopter_client/configuration.rb +16 -4
- data/lib/copycopter_client/rails.rb +1 -0
- data/lib/copycopter_client/request_sync.rb +23 -0
- data/lib/copycopter_client/sync.rb +13 -12
- data/lib/copycopter_client/version.rb +1 -1
- data/spec/copycopter_client/client_spec.rb +34 -11
- data/spec/copycopter_client/configuration_spec.rb +46 -1
- data/spec/copycopter_client/request_sync_spec.rb +27 -0
- data/spec/copycopter_client/sync_spec.rb +34 -4
- data/spec/support/fake_client.rb +2 -1
- data/spec/support/fake_copycopter_app.rb +15 -2
- data/spec/support/middleware_stack.rb +13 -0
- metadata +6 -3
data/features/rails.feature
CHANGED
@@ -71,13 +71,11 @@ Feature: Using copycopter in a rails app
|
|
71
71
|
<%= @text %>
|
72
72
|
"""
|
73
73
|
When I start the application
|
74
|
-
And I wait for changes to be synchronized
|
75
74
|
And I visit /users/
|
76
75
|
Then the response should contain "Old content"
|
77
76
|
When the the following blurbs are updated in the "abc123" project:
|
78
77
|
| key | draft content |
|
79
78
|
| en.users.index.controller-test | New content |
|
80
|
-
And I wait for changes to be synchronized
|
81
79
|
And I visit /users/
|
82
80
|
Then the response should contain "New content"
|
83
81
|
|
@@ -98,8 +96,7 @@ Feature: Using copycopter in a rails app
|
|
98
96
|
When I start the application
|
99
97
|
And I visit /users/
|
100
98
|
Then the response should contain "not found"
|
101
|
-
|
102
|
-
Then the "abc123" project should have the following blurbs:
|
99
|
+
And the "abc123" project should have the following blurbs:
|
103
100
|
| key | draft content |
|
104
101
|
| en.users.index.404 | not found |
|
105
102
|
And the log should contain "Uploaded missing translations"
|
@@ -35,14 +35,23 @@ module CopycopterClient
|
|
35
35
|
# If the +public+ option was set to +true+, this will use published blurbs.
|
36
36
|
# Otherwise, draft content is fetched.
|
37
37
|
#
|
38
|
-
#
|
38
|
+
# The client tracks ETags between download requests, and will return
|
39
|
+
# without yielding anything if the server returns a not modified response.
|
40
|
+
#
|
41
|
+
# @yield [Hash] downloaded blurbs
|
39
42
|
# @raise [ConnectionError] if the connection fails
|
40
43
|
def download
|
41
44
|
connect do |http|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
45
|
+
request = Net::HTTP::Get.new(uri(download_resource))
|
46
|
+
request['If-None-Match'] = @etag
|
47
|
+
response = http.request(request)
|
48
|
+
if check(response)
|
49
|
+
log("Downloaded translations")
|
50
|
+
yield JSON.parse(response.body)
|
51
|
+
else
|
52
|
+
log("No new translations")
|
53
|
+
end
|
54
|
+
@etag = response['ETag']
|
46
55
|
end
|
47
56
|
end
|
48
57
|
|
@@ -101,11 +110,14 @@ module CopycopterClient
|
|
101
110
|
end
|
102
111
|
|
103
112
|
def check(response)
|
104
|
-
|
113
|
+
case response
|
114
|
+
when Net::HTTPNotFound
|
105
115
|
raise InvalidApiKey, "Invalid API key: #{api_key}"
|
106
|
-
|
107
|
-
|
108
|
-
|
116
|
+
when Net::HTTPNotModified
|
117
|
+
false
|
118
|
+
when Net::HTTPSuccess
|
119
|
+
true
|
120
|
+
else
|
109
121
|
raise ConnectionError, "#{response.code}: #{response.body}"
|
110
122
|
end
|
111
123
|
end
|
@@ -3,6 +3,7 @@ require 'copycopter_client/i18n_backend'
|
|
3
3
|
require 'copycopter_client/client'
|
4
4
|
require 'copycopter_client/sync'
|
5
5
|
require 'copycopter_client/prefixed_logger'
|
6
|
+
require 'copycopter_client/request_sync'
|
6
7
|
|
7
8
|
module CopycopterClient
|
8
9
|
# Used to set up and modify settings for the client.
|
@@ -13,7 +14,7 @@ module CopycopterClient
|
|
13
14
|
:http_open_timeout, :http_read_timeout, :client_name, :client_url,
|
14
15
|
:client_version, :port, :protocol, :proxy_host, :proxy_pass,
|
15
16
|
:proxy_port, :proxy_user, :secure, :polling_delay, :logger,
|
16
|
-
:framework].freeze
|
17
|
+
:framework, :middleware].freeze
|
17
18
|
|
18
19
|
# @return [String] The API key for your project, found on the project edit form.
|
19
20
|
attr_accessor :api_key
|
@@ -72,6 +73,9 @@ module CopycopterClient
|
|
72
73
|
# @return [Logger] Where to log messages. Must respond to same interface as Logger.
|
73
74
|
attr_reader :logger
|
74
75
|
|
76
|
+
# @return the middleware stack, if any, which should respond to +use+
|
77
|
+
attr_accessor :middleware
|
78
|
+
|
75
79
|
alias_method :secure?, :secure
|
76
80
|
|
77
81
|
# Instantiated from {CopycopterClient.configure}. Sets defaults.
|
@@ -116,12 +120,19 @@ module CopycopterClient
|
|
116
120
|
to_hash.merge(hash)
|
117
121
|
end
|
118
122
|
|
119
|
-
# Determines if the content will be
|
120
|
-
# @return [Boolean] Returns +false+ if in a development
|
123
|
+
# Determines if the published or draft content will be used
|
124
|
+
# @return [Boolean] Returns +false+ if in a development or test
|
125
|
+
# environment, +true+ otherwise.
|
121
126
|
def public?
|
122
127
|
!(development_environments + test_environments).include?(environment_name)
|
123
128
|
end
|
124
129
|
|
130
|
+
# Determines if the content will be editable
|
131
|
+
# @return [Boolean] Returns +true+ if in a development environment, +false+ otherwise.
|
132
|
+
def development?
|
133
|
+
development_environments.include?(environment_name)
|
134
|
+
end
|
135
|
+
|
125
136
|
# Determines if the content will fetched from the server
|
126
137
|
# @return [Boolean] Returns +true+ if in a test environment, +false+ otherwise.
|
127
138
|
def test?
|
@@ -134,7 +145,7 @@ module CopycopterClient
|
|
134
145
|
@applied
|
135
146
|
end
|
136
147
|
|
137
|
-
|
148
|
+
# Applies the configuration (internal).
|
138
149
|
#
|
139
150
|
# Called automatically when {CopycopterClient.configure} is called in the application.
|
140
151
|
#
|
@@ -147,6 +158,7 @@ module CopycopterClient
|
|
147
158
|
I18n.backend = I18nBackend.new(sync)
|
148
159
|
CopycopterClient.client = client
|
149
160
|
CopycopterClient.sync = sync
|
161
|
+
middleware.use(RequestSync, :sync => sync) if middleware && development?
|
150
162
|
@applied = true
|
151
163
|
logger.info("Client #{VERSION} ready")
|
152
164
|
logger.info("Environment Info: #{environment_info}")
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module CopycopterClient
|
2
|
+
# Rack middleware that synchronizes with Copycopter during each request.
|
3
|
+
#
|
4
|
+
# This is injected into the Rails middleware stack in development environments.
|
5
|
+
class RequestSync
|
6
|
+
# @param app [Rack] the upstream app into whose responses to inject the editor
|
7
|
+
# @param options [Hash]
|
8
|
+
# @option options [Sync] :sync agent that should be flushed after each request
|
9
|
+
def initialize(app, options)
|
10
|
+
@app = app
|
11
|
+
@sync = options[:sync]
|
12
|
+
end
|
13
|
+
|
14
|
+
# Invokes the upstream Rack application and flushes the sync after each
|
15
|
+
# request.
|
16
|
+
def call(env)
|
17
|
+
@sync.download
|
18
|
+
response = @app.call(env)
|
19
|
+
@sync.flush
|
20
|
+
response
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -86,6 +86,17 @@ module CopycopterClient
|
|
86
86
|
with_queued_changes do |queued|
|
87
87
|
client.upload(queued)
|
88
88
|
end
|
89
|
+
rescue ConnectionError => error
|
90
|
+
logger.error(error.message)
|
91
|
+
end
|
92
|
+
|
93
|
+
def download
|
94
|
+
client.download do |downloaded_blurbs|
|
95
|
+
downloaded_blurbs.reject! { |key, value| value == "" }
|
96
|
+
lock { @blurbs = downloaded_blurbs }
|
97
|
+
end
|
98
|
+
rescue ConnectionError => error
|
99
|
+
logger.error(error.message)
|
89
100
|
end
|
90
101
|
|
91
102
|
private
|
@@ -103,12 +114,8 @@ module CopycopterClient
|
|
103
114
|
end
|
104
115
|
|
105
116
|
def sync
|
106
|
-
|
107
|
-
|
108
|
-
flush
|
109
|
-
rescue ConnectionError => error
|
110
|
-
logger.error(error.message)
|
111
|
-
end
|
117
|
+
download
|
118
|
+
flush
|
112
119
|
ensure
|
113
120
|
@pending = false
|
114
121
|
end
|
@@ -124,12 +131,6 @@ module CopycopterClient
|
|
124
131
|
yield(changes_to_push) if changes_to_push
|
125
132
|
end
|
126
133
|
|
127
|
-
def download
|
128
|
-
downloaded_blurbs = client.download
|
129
|
-
downloaded_blurbs.reject! { |key, value| value == "" }
|
130
|
-
lock { @blurbs = downloaded_blurbs }
|
131
|
-
end
|
132
|
-
|
133
134
|
def lock(&block)
|
134
135
|
@mutex.synchronize(&block)
|
135
136
|
end
|
@@ -29,28 +29,28 @@ describe CopycopterClient do
|
|
29
29
|
it "should timeout when connecting" do
|
30
30
|
project = add_project
|
31
31
|
client = build_client(:api_key => project.api_key, :http_open_timeout => 4)
|
32
|
-
client.download
|
32
|
+
client.download { |ignore| }
|
33
33
|
http.open_timeout.should == 4
|
34
34
|
end
|
35
35
|
|
36
36
|
it "should timeout when reading" do
|
37
37
|
project = add_project
|
38
38
|
client = build_client(:api_key => project.api_key, :http_read_timeout => 4)
|
39
|
-
client.download
|
39
|
+
client.download { |ignore| }
|
40
40
|
http.read_timeout.should == 4
|
41
41
|
end
|
42
42
|
|
43
43
|
it "uses ssl when secure" do
|
44
44
|
project = add_project
|
45
45
|
client = build_client(:api_key => project.api_key, :secure => true)
|
46
|
-
client.download
|
46
|
+
client.download { |ignore| }
|
47
47
|
http.use_ssl.should == true
|
48
48
|
end
|
49
49
|
|
50
50
|
it "doesn't use ssl when insecure" do
|
51
51
|
project = add_project
|
52
52
|
client = build_client(:api_key => project.api_key, :secure => false)
|
53
|
-
client.download
|
53
|
+
client.download { |ignore| }
|
54
54
|
http.use_ssl.should == false
|
55
55
|
end
|
56
56
|
|
@@ -66,9 +66,9 @@ describe CopycopterClient do
|
|
66
66
|
]
|
67
67
|
|
68
68
|
errors.each do |original_error|
|
69
|
-
http.stubs(:
|
69
|
+
http.stubs(:request).raises(original_error)
|
70
70
|
client = build_client_with_project
|
71
|
-
expect { client.download }.
|
71
|
+
expect { client.download { |ignore| } }.
|
72
72
|
to raise_error(CopycopterClient::ConnectionError) { |error|
|
73
73
|
error.message.
|
74
74
|
should == "#{original_error.class.name}: #{original_error.message}"
|
@@ -78,7 +78,8 @@ describe CopycopterClient do
|
|
78
78
|
|
79
79
|
it "handles 500 errors from downloads with ConnectionError" do
|
80
80
|
client = build_client(:api_key => 'raise_error')
|
81
|
-
expect { client.download }.
|
81
|
+
expect { client.download { |ignore| } }.
|
82
|
+
to raise_error(CopycopterClient::ConnectionError)
|
82
83
|
end
|
83
84
|
|
84
85
|
it "handles 500 errors from uploads with ConnectionError" do
|
@@ -88,7 +89,8 @@ describe CopycopterClient do
|
|
88
89
|
|
89
90
|
it "handles 404 errors from downloads with ConnectionError" do
|
90
91
|
client = build_client(:api_key => 'bogus')
|
91
|
-
expect { client.download }.
|
92
|
+
expect { client.download { |ignore| } }.
|
93
|
+
to raise_error(CopycopterClient::InvalidApiKey)
|
92
94
|
end
|
93
95
|
|
94
96
|
it "handles 404 errors from uploads with ConnectionError" do
|
@@ -109,8 +111,10 @@ describe CopycopterClient do
|
|
109
111
|
'key.two' => "expected two"
|
110
112
|
}
|
111
113
|
})
|
114
|
+
client = build_client(:api_key => project.api_key, :public => true)
|
115
|
+
blurbs = nil
|
112
116
|
|
113
|
-
|
117
|
+
client.download { |yielded| blurbs = yielded }
|
114
118
|
|
115
119
|
blurbs.should == {
|
116
120
|
'key.one' => 'expected one',
|
@@ -121,7 +125,7 @@ describe CopycopterClient do
|
|
121
125
|
it "logs that it performed a download" do
|
122
126
|
logger = FakeLogger.new
|
123
127
|
client = build_client_with_project(:logger => logger)
|
124
|
-
client.download
|
128
|
+
client.download { |ignore| }
|
125
129
|
logger.should have_entry(:info, "Downloaded translations")
|
126
130
|
end
|
127
131
|
|
@@ -137,8 +141,10 @@ describe CopycopterClient do
|
|
137
141
|
'key.three' => "unexpected three"
|
138
142
|
}
|
139
143
|
})
|
144
|
+
client = build_client(:api_key => project.api_key, :public => false)
|
145
|
+
blurbs = nil
|
140
146
|
|
141
|
-
|
147
|
+
client.download { |yielded| blurbs = yielded }
|
142
148
|
|
143
149
|
blurbs.should == {
|
144
150
|
'key.one' => 'expected one',
|
@@ -146,6 +152,23 @@ describe CopycopterClient do
|
|
146
152
|
}
|
147
153
|
end
|
148
154
|
|
155
|
+
it "handles a 304 response when downloading" do
|
156
|
+
project = add_project
|
157
|
+
project.update('draft' => { 'key.one' => "expected one" })
|
158
|
+
logger = FakeLogger.new
|
159
|
+
client = build_client(:api_key => project.api_key,
|
160
|
+
:public => false,
|
161
|
+
:logger => logger)
|
162
|
+
yields = 0
|
163
|
+
|
164
|
+
2.times do
|
165
|
+
client.download { |ignore| yields += 1 }
|
166
|
+
end
|
167
|
+
|
168
|
+
yields.should == 1
|
169
|
+
logger.should have_entry(:info, "No new translations")
|
170
|
+
end
|
171
|
+
|
149
172
|
it "uploads defaults for missing blurbs in an existing project" do
|
150
173
|
project = add_project
|
151
174
|
|
@@ -42,6 +42,7 @@ describe CopycopterClient::Configuration do
|
|
42
42
|
it { should have_config_option(:api_key). overridable }
|
43
43
|
it { should have_config_option(:polling_delay). overridable.default(300) }
|
44
44
|
it { should have_config_option(:framework). overridable }
|
45
|
+
it { should have_config_option(:middleware). overridable }
|
45
46
|
|
46
47
|
it "should provide default values for secure connections" do
|
47
48
|
config = CopycopterClient::Configuration.new
|
@@ -105,12 +106,14 @@ describe CopycopterClient::Configuration do
|
|
105
106
|
config.development_environments = %w(development)
|
106
107
|
config.environment_name = 'production'
|
107
108
|
config.should be_public
|
109
|
+
config.should_not be_development
|
108
110
|
end
|
109
111
|
|
110
|
-
it "should
|
112
|
+
it "should be development in a development environment" do
|
111
113
|
config = CopycopterClient::Configuration.new
|
112
114
|
config.development_environments = %w(staging)
|
113
115
|
config.environment_name = 'staging'
|
116
|
+
config.should be_development
|
114
117
|
config.should_not be_public
|
115
118
|
end
|
116
119
|
|
@@ -249,3 +252,45 @@ describe CopycopterClient::Configuration, "applied when not testing" do
|
|
249
252
|
end
|
250
253
|
end
|
251
254
|
|
255
|
+
describe CopycopterClient::Configuration, "applied when developing with middleware" do
|
256
|
+
it_should_behave_like "applied configuration"
|
257
|
+
|
258
|
+
let(:middleware) { MiddlewareStack.new }
|
259
|
+
|
260
|
+
before do
|
261
|
+
subject.middleware = middleware
|
262
|
+
subject.environment_name = 'development'
|
263
|
+
subject.apply
|
264
|
+
end
|
265
|
+
|
266
|
+
it "adds the sync middleware" do
|
267
|
+
middleware.should include(CopycopterClient::RequestSync)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe CopycopterClient::Configuration, "applied when developing without middleware" do
|
272
|
+
it_should_behave_like "applied configuration"
|
273
|
+
|
274
|
+
before do
|
275
|
+
subject.middleware = nil
|
276
|
+
subject.environment_name = 'development'
|
277
|
+
subject.apply
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe CopycopterClient::Configuration, "applied with middleware when not developing" do
|
282
|
+
it_should_behave_like "applied configuration"
|
283
|
+
|
284
|
+
let(:middleware) { MiddlewareStack.new }
|
285
|
+
|
286
|
+
before do
|
287
|
+
subject.middleware = middleware
|
288
|
+
subject.environment_name = 'test'
|
289
|
+
subject.apply
|
290
|
+
end
|
291
|
+
|
292
|
+
it "doesn't add the sync middleware" do
|
293
|
+
middleware.should_not include(CopycopterClient::RequestSync)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CopycopterClient::RequestSync do
|
4
|
+
|
5
|
+
let(:sync) { {} }
|
6
|
+
let(:response) { 'response' }
|
7
|
+
let(:env) { 'env' }
|
8
|
+
let(:app) { stub('app', :call => response) }
|
9
|
+
before { sync.stubs(:flush => nil, :download => nil) }
|
10
|
+
subject { CopycopterClient::RequestSync.new(app, :sync => sync) }
|
11
|
+
|
12
|
+
it "invokes the upstream app" do
|
13
|
+
result = subject.call(env)
|
14
|
+
app.should have_received(:call).with(env)
|
15
|
+
result.should == response
|
16
|
+
end
|
17
|
+
|
18
|
+
it "flushes defaults" do
|
19
|
+
subject.call(env)
|
20
|
+
sync.should have_received(:flush)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "downloads new copy" do
|
24
|
+
subject.call(env)
|
25
|
+
sync.should have_received(:download)
|
26
|
+
end
|
27
|
+
end
|
@@ -100,16 +100,46 @@ describe CopycopterClient::Sync do
|
|
100
100
|
end
|
101
101
|
|
102
102
|
it "uploads changes when flushed" do
|
103
|
-
sync = build_sync
|
104
|
-
sync.start
|
105
|
-
sleep 2
|
103
|
+
sync = build_sync
|
106
104
|
sync['test.key'] = 'test value'
|
105
|
+
|
107
106
|
sync.flush
|
108
|
-
sleep(2)
|
109
107
|
|
110
108
|
client.uploaded.should == { 'test.key' => 'test value' }
|
111
109
|
end
|
112
110
|
|
111
|
+
it "downloads changes" do
|
112
|
+
client['test.key'] = 'test value'
|
113
|
+
sync = build_sync
|
114
|
+
|
115
|
+
sync.download
|
116
|
+
|
117
|
+
sync['test.key'].should == 'test value'
|
118
|
+
end
|
119
|
+
|
120
|
+
it "handles connection errors when flushing" do
|
121
|
+
failure = "server is napping"
|
122
|
+
logger = FakeLogger.new
|
123
|
+
client.stubs(:upload).raises(CopycopterClient::ConnectionError.new(failure))
|
124
|
+
sync = build_sync(:logger => logger)
|
125
|
+
sync['upload.key'] = 'upload'
|
126
|
+
|
127
|
+
sync.flush
|
128
|
+
|
129
|
+
logger.should have_entry(:error, failure)
|
130
|
+
end
|
131
|
+
|
132
|
+
it "handles connection errors when downloading" do
|
133
|
+
failure = "server is napping"
|
134
|
+
logger = FakeLogger.new
|
135
|
+
client.stubs(:download).raises(CopycopterClient::ConnectionError.new(failure))
|
136
|
+
sync = build_sync(:logger => logger)
|
137
|
+
|
138
|
+
sync.download
|
139
|
+
|
140
|
+
logger.should have_entry(:error, failure)
|
141
|
+
end
|
142
|
+
|
113
143
|
it "handles connection errors when polling" do
|
114
144
|
failure = "server is napping"
|
115
145
|
logger = FakeLogger.new
|
data/spec/support/fake_client.rb
CHANGED
@@ -37,11 +37,17 @@ class FakeCopycopterApp < Sinatra::Base
|
|
37
37
|
end
|
38
38
|
|
39
39
|
get "/api/v2/projects/:api_key/published_blurbs" do |api_key|
|
40
|
-
with_project(api_key)
|
40
|
+
with_project(api_key) do |project|
|
41
|
+
etag project.etag
|
42
|
+
project.published.to_json
|
43
|
+
end
|
41
44
|
end
|
42
45
|
|
43
46
|
get "/api/v2/projects/:api_key/draft_blurbs" do |api_key|
|
44
|
-
with_project(api_key)
|
47
|
+
with_project(api_key) do |project|
|
48
|
+
etag project.etag
|
49
|
+
project.draft.to_json
|
50
|
+
end
|
45
51
|
end
|
46
52
|
|
47
53
|
post "/api/v2/projects/:api_key/draft_blurbs" do |api_key|
|
@@ -66,10 +72,12 @@ class FakeCopycopterApp < Sinatra::Base
|
|
66
72
|
@api_key = attrs['api_key']
|
67
73
|
@draft = attrs['draft'] || {}
|
68
74
|
@published = attrs['published'] || {}
|
75
|
+
@etag = attrs['etag'] || 1
|
69
76
|
end
|
70
77
|
|
71
78
|
def to_hash
|
72
79
|
{ 'api_key' => @api_key,
|
80
|
+
'etag' => @etag,
|
73
81
|
'draft' => @draft,
|
74
82
|
'published' => @published }
|
75
83
|
end
|
@@ -77,6 +85,7 @@ class FakeCopycopterApp < Sinatra::Base
|
|
77
85
|
def update(attrs)
|
78
86
|
@draft. update(attrs['draft']) if attrs['draft']
|
79
87
|
@published.update(attrs['published']) if attrs['published']
|
88
|
+
@etag += 1
|
80
89
|
self.class.save(self)
|
81
90
|
end
|
82
91
|
|
@@ -89,6 +98,10 @@ class FakeCopycopterApp < Sinatra::Base
|
|
89
98
|
self.class.save(self)
|
90
99
|
end
|
91
100
|
|
101
|
+
def etag
|
102
|
+
@etag.to_s
|
103
|
+
end
|
104
|
+
|
92
105
|
def self.create(api_key)
|
93
106
|
project = Project.new('api_key' => api_key)
|
94
107
|
save(project)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: copycopter_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 299253589
|
5
5
|
prerelease: true
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
9
|
- 0
|
10
|
-
-
|
11
|
-
version: 1.0.0.
|
10
|
+
- beta9
|
11
|
+
version: 1.0.0.beta9
|
12
12
|
platform: ruby
|
13
13
|
authors:
|
14
14
|
- thoughtbot
|
@@ -69,6 +69,7 @@ files:
|
|
69
69
|
- lib/copycopter_client/prefixed_logger.rb
|
70
70
|
- lib/copycopter_client/rails.rb
|
71
71
|
- lib/copycopter_client/railtie.rb
|
72
|
+
- lib/copycopter_client/request_sync.rb
|
72
73
|
- lib/copycopter_client/sync.rb
|
73
74
|
- lib/copycopter_client/version.rb
|
74
75
|
- lib/copycopter_client.rb
|
@@ -78,6 +79,7 @@ files:
|
|
78
79
|
- spec/copycopter_client/helper_spec.rb
|
79
80
|
- spec/copycopter_client/i18n_backend_spec.rb
|
80
81
|
- spec/copycopter_client/prefixed_logger_spec.rb
|
82
|
+
- spec/copycopter_client/request_sync_spec.rb
|
81
83
|
- spec/copycopter_client/sync_spec.rb
|
82
84
|
- spec/spec.opts
|
83
85
|
- spec/spec_helper.rb
|
@@ -90,6 +92,7 @@ files:
|
|
90
92
|
- spec/support/fake_passenger.rb
|
91
93
|
- spec/support/fake_resque_job.rb
|
92
94
|
- spec/support/fake_unicorn.rb
|
95
|
+
- spec/support/middleware_stack.rb
|
93
96
|
- features/rails.feature
|
94
97
|
- features/step_definitions/copycopter_server_steps.rb
|
95
98
|
- features/step_definitions/rails_steps.rb
|