fetch 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +313 -0
- data/lib/fetch.rb +1 -0
- data/lib/fetch/async.rb +9 -4
- data/lib/fetch/base.rb +12 -2
- data/lib/fetch/callbacks.rb +15 -1
- data/lib/fetch/json.rb +9 -0
- data/lib/fetch/module.rb +9 -0
- data/lib/fetch/request.rb +14 -0
- data/lib/fetch/version.rb +1 -1
- data/test/defaults_test.rb +23 -0
- data/test/fetch_test.rb +7 -21
- data/test/init_test.rb +47 -0
- data/test/json_test.rb +19 -0
- data/test/load_test.rb +52 -0
- data/test/parse_test.rb +21 -0
- data/test/test_helper.rb +2 -0
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f2e34b25ea8efe2d5681328da56ba8d5141775b
|
4
|
+
data.tar.gz: 582f71ff59b4e30b02733a5f777096e4ac785aad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 750a2cbaca8debe5512947da70ae5c01a35eb72e71873390013f059ce9694d7777fc3978d224b4292c7039900673c171842438df1c3c15524f584e64f03b3bd3
|
7
|
+
data.tar.gz: 1da726ec7708099401e988d66702f37d4b49ba90b0d80be9dcbdfe667808d49f16e1e37b361a9b04c890b9eb910b4c9e7512269325db9b25ba648d5d60957439
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## Version 0.0.2
|
4
|
+
|
5
|
+
* Sends fetchable to fetch modules by default.
|
6
|
+
* The `init` callback only runs once.
|
7
|
+
* Adds a `defaults` callback for setting up requests.
|
8
|
+
* Adds a `parse` callback for parsing response bodies before they are processed.
|
9
|
+
* Adds a `Fetch::JSON` module for automatic JSON parsing.
|
10
|
+
* Adds a `load` callback for loading fetch modules.
|
11
|
+
|
12
|
+
## Version 0.0.1
|
13
|
+
|
14
|
+
* Initial release
|
data/README.md
CHANGED
@@ -27,6 +27,319 @@ Then run:
|
|
27
27
|
$ bundle
|
28
28
|
```
|
29
29
|
|
30
|
+
## Example
|
31
|
+
|
32
|
+
In *app/models/user.rb*:
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
class User < ActiveRecord::Base
|
36
|
+
def fetcher
|
37
|
+
@fetcher ||= UserFetcher.new(self)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
In *app/fetchers/user_fetcher.rb*:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
class UserFetcher < Fetch::Base
|
46
|
+
modules Facebook::UserInfoFetch,
|
47
|
+
Github::UserInfoFetch
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
In *lib/facebook/user_info_fetch.rb*:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
module Facebook
|
55
|
+
class UserInfoFetch < Fetch::Module
|
56
|
+
include Fetch::Simple
|
57
|
+
include Fetch::JSON
|
58
|
+
|
59
|
+
url do
|
60
|
+
"http://graph.facebook.com/#{fetchable.login}"
|
61
|
+
end
|
62
|
+
|
63
|
+
process do |user_info|
|
64
|
+
fetchable.update_attribute :facebook_id, user_info["id"]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
In *lib/github/user_info_fetch.rb*
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
module Github
|
74
|
+
class UserInfoFetch < Fetch::Module
|
75
|
+
include Fetch::JSON
|
76
|
+
|
77
|
+
# Request for user ID
|
78
|
+
request do |req|
|
79
|
+
req.url = "https://api.github.com/users/#{fetchable.login}"
|
80
|
+
req.process do |user|
|
81
|
+
fetchable.update_attribute :github_id, user["id"]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Request for repos
|
86
|
+
request do |req|
|
87
|
+
req.url = "https://api.github.com/users/#{fetchable.login}/repos"
|
88
|
+
req.process do |repos|
|
89
|
+
repo_names = repos.map { |r| r["name"] }
|
90
|
+
fetchable.update_attribute :github_repos, repo_names
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
Then, when everything is set up, you can do:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
user = User.find(123)
|
101
|
+
user.fetcher.fetch
|
102
|
+
```
|
103
|
+
|
104
|
+
This will run three requests – one for Facebook and two for GitHub – and update
|
105
|
+
the user model with a Facebook user ID, a GitHub user ID, and a list of GitHub
|
106
|
+
repos.
|
107
|
+
|
108
|
+
## Good to know
|
109
|
+
|
110
|
+
### Adding defaults to your requests
|
111
|
+
|
112
|
+
Each fetch module has a `defaults` callback that you can use to set up defaults
|
113
|
+
for all requests in that modules.
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
class UserInfoFetch < Fetch::Module
|
117
|
+
defaults do |req|
|
118
|
+
req.user_agent = "My Awesome Bot!"
|
119
|
+
end
|
120
|
+
|
121
|
+
request do |req|
|
122
|
+
req.url = "http://test.com"
|
123
|
+
req.process do |body|
|
124
|
+
# Do some processing
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
This will add the user agent `My Awesome Bot!` to all requests in the
|
131
|
+
`UserInfoFetch` module.
|
132
|
+
|
133
|
+
The `defaults` callback is inherited, like all other callbacks, so if you have
|
134
|
+
a base fetch class that you subclass, the `defaults` callback in the superclass
|
135
|
+
will be run in all subclasses.
|
136
|
+
|
137
|
+
### Handling HTTP failures
|
138
|
+
|
139
|
+
HTTP failures can be handled using the `failure` callback. If you want to
|
140
|
+
handle failures for all requests generally, you can use the module-wide
|
141
|
+
`failure` callback:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
class UserInfoFetch < Fetch::Module
|
145
|
+
request do |req|
|
146
|
+
req.url = "http://test.com/something-failing"
|
147
|
+
req.process do |body|
|
148
|
+
# Do something if successful.
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
failure do |code, url|
|
153
|
+
Rails.logger.info "Fetching from #{url} failed: #{code}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
If you want to handle failures on the specific requests instead:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
class UserInfoFetch < Fetch::Module
|
162
|
+
request do |req|
|
163
|
+
req.url = "http://test.com/something-failing"
|
164
|
+
req.process do |body|
|
165
|
+
# Do something if successful.
|
166
|
+
end
|
167
|
+
req.failure do |code, url|
|
168
|
+
# Handle the failure
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
```
|
173
|
+
|
174
|
+
When you handle failures directly on the request, the general `failure`
|
175
|
+
callback isn't called.
|
176
|
+
|
177
|
+
**Note:** If you don't specify a `failure` callback at all, HTTP failures are ignored,
|
178
|
+
and processing skipped for the failed request.
|
179
|
+
|
180
|
+
### Handling errors
|
181
|
+
|
182
|
+
Sometimes a URL will return something that potentially makes your processing
|
183
|
+
code fail. To prevent this from breaking your whole fetch, you can handle
|
184
|
+
errors using the `error` callback:
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
class UserInfoFetch < Fetch::Module
|
188
|
+
request do |req|
|
189
|
+
req.url = "http://test.com/something-failing"
|
190
|
+
req.process do |body|
|
191
|
+
# Do something if successful.
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
error do |exception|
|
196
|
+
Rails.logger.info "An error occured: #{exception.message}\n" +
|
197
|
+
exception.backtrace.join("\n")
|
198
|
+
raise exception if ["development", "test"].include?(Rails.env)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
You can also do it directly on the requests:
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
class UserInfoFetch < Fetch::Module
|
207
|
+
request do |req|
|
208
|
+
req.url = "http://test.com/something-failing"
|
209
|
+
req.process do |body|
|
210
|
+
# Do something if successful.
|
211
|
+
end
|
212
|
+
req.error do |exception|
|
213
|
+
# Handle the error
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
If you handle errors directly on the requests, the general `error` callback
|
220
|
+
isn't run.
|
221
|
+
|
222
|
+
**Note:** If you don't do any error handling in one of the two ways shown
|
223
|
+
above, any exceptions that occur when processing will be raised, causing the
|
224
|
+
whole fetch to fail. So please add error handling :blush:
|
225
|
+
|
226
|
+
### Parsing JSON
|
227
|
+
|
228
|
+
Fetch has a module for automatically parsing the request body as JSON before
|
229
|
+
it is sent to the process block.
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
class UserInfoFetch < Fetch::Module
|
233
|
+
include Fetch::JSON
|
234
|
+
|
235
|
+
request do |req|
|
236
|
+
req.url = "http://api.test.com/user"
|
237
|
+
req.process do |json|
|
238
|
+
# Do something with the JSON.
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
```
|
243
|
+
|
244
|
+
### Dynamically loading fetch modules
|
245
|
+
|
246
|
+
You can load fetch modules dynamically using the `load` callback. Normally, the
|
247
|
+
modules defined with `modules` are instantiated directly. When you use the
|
248
|
+
`load` callback, this will determine how your modules are loaded.
|
249
|
+
|
250
|
+
```ruby
|
251
|
+
class UserFetcher < Fetch::Base
|
252
|
+
modules :user_info_fetch, :status_fetch
|
253
|
+
|
254
|
+
load do |modules|
|
255
|
+
namespaces.product(modules).map do |path|
|
256
|
+
path.join("/").camelize.safe_constantize
|
257
|
+
end.compact
|
258
|
+
end
|
259
|
+
|
260
|
+
private
|
261
|
+
|
262
|
+
def namespaces
|
263
|
+
[:github, :facebook]
|
264
|
+
end
|
265
|
+
end
|
266
|
+
```
|
267
|
+
|
268
|
+
This will load the modules `Github::UserInfoFetch`, `Github::StatusFetch`,
|
269
|
+
`Facebook::UserInfoFetch` and `Facebook::StatusFetch`, if they are present.
|
270
|
+
|
271
|
+
The `load` callback is only run once, so you can safely inherit it – only the
|
272
|
+
last one defined will be run.
|
273
|
+
|
274
|
+
### Initializing fetch modules
|
275
|
+
|
276
|
+
Normally, a fetcher is initialized with an optional `fetchable` that is sent
|
277
|
+
along to the fetch modules when they are initialized. You can change how this
|
278
|
+
works with the `init` callback.
|
279
|
+
|
280
|
+
Let's say you have a `Search` model with a `SearchFetcher` that gets results
|
281
|
+
from various search engines. Normally, the `Search` instance would be sent to
|
282
|
+
the fetch modules as a fetchable. Let's say you just want to send the keyword
|
283
|
+
to reduce coupling.
|
284
|
+
|
285
|
+
In *app/fetchers/search_fetcher.rb*:
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
class SearchFetcher < Fetch::Base
|
289
|
+
modules Google::KeywordFetch,
|
290
|
+
Bing::KeywordFetch
|
291
|
+
|
292
|
+
init do |klass|
|
293
|
+
klass.new(fetchable.keyword)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
```
|
297
|
+
|
298
|
+
In *lib/base/keyword_fetch.rb*:
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
module Base
|
302
|
+
class KeywordFetch < Fetch::Module
|
303
|
+
attr_reader :keyword
|
304
|
+
|
305
|
+
def initialize(keyword)
|
306
|
+
@keyword = keyword
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
```
|
311
|
+
|
312
|
+
In *lib/google/keyword_fetch.rb*:
|
313
|
+
|
314
|
+
```ruby
|
315
|
+
module Google
|
316
|
+
class KeywordFetch < Base::KeywordFetch
|
317
|
+
request do |req|
|
318
|
+
req.url = "https://www.google.com/search?q=#{CGI::escape(keyword)}"
|
319
|
+
req.process do |body|
|
320
|
+
# Do something with the body.
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
```
|
326
|
+
|
327
|
+
And *lib/bing/keyword_fetch.rb* something similar to Google.
|
328
|
+
|
329
|
+
Then:
|
330
|
+
|
331
|
+
```ruby
|
332
|
+
search = Search.find(123)
|
333
|
+
SearchFetcher.new(search).fetch
|
334
|
+
```
|
335
|
+
|
336
|
+
Now the keyword will be sent to the fetch modules instead of the fetchable.
|
337
|
+
|
338
|
+
## Changelog
|
339
|
+
|
340
|
+
See the [changelog](https://github.com/bogrobotten/fetch/blob/master/CHANGELOG.md)
|
341
|
+
for changes in the different versions.
|
342
|
+
|
30
343
|
## Contributing
|
31
344
|
|
32
345
|
Contributions are much appreciated. To contribute:
|
data/lib/fetch.rb
CHANGED
data/lib/fetch/async.rb
CHANGED
@@ -2,17 +2,22 @@ module Fetch
|
|
2
2
|
module Async
|
3
3
|
def self.included(base)
|
4
4
|
base.define_callback :request,
|
5
|
+
:defaults,
|
5
6
|
:before_process,
|
6
7
|
:after_process
|
8
|
+
|
9
|
+
base.defaults do |req|
|
10
|
+
req.before_process { before_process } if callback?(:before_process)
|
11
|
+
req.after_process { after_process } if callback?(:after_process)
|
12
|
+
req.failure { |code, url| failure(code, url) } if callback?(:failure)
|
13
|
+
req.error { |e| error(e) } if callback?(:error)
|
14
|
+
end
|
7
15
|
end
|
8
16
|
|
9
17
|
def requests
|
10
18
|
self.class.callbacks[:request].map do |callback|
|
11
19
|
Request.new.tap do |req|
|
12
|
-
req
|
13
|
-
req.after_process { after_process } if callback?(:after_process)
|
14
|
-
req.failure { |code, url| failure(code, url) } if callback?(:failure)
|
15
|
-
req.error { |e| error(e) } if callback?(:error)
|
20
|
+
defaults(req)
|
16
21
|
instance_exec(req, &callback)
|
17
22
|
end
|
18
23
|
end.select(&:url)
|
data/lib/fetch/base.rb
CHANGED
@@ -17,11 +17,16 @@ module Fetch
|
|
17
17
|
# # update progress in percent
|
18
18
|
# end
|
19
19
|
define_callback :modules,
|
20
|
+
:load,
|
20
21
|
:init,
|
21
22
|
:before_fetch,
|
22
23
|
:after_fetch,
|
23
24
|
:progress
|
24
25
|
|
26
|
+
def initialize(fetchable = nil)
|
27
|
+
@fetchable = fetchable
|
28
|
+
end
|
29
|
+
|
25
30
|
# Begin fetching.
|
26
31
|
# Will run synchronous fetches first and async fetches afterwards.
|
27
32
|
# Updates progress when each module finishes its fetch.
|
@@ -44,10 +49,15 @@ module Fetch
|
|
44
49
|
|
45
50
|
private
|
46
51
|
|
52
|
+
# The optional instance being fetched.
|
53
|
+
attr_reader :fetchable
|
54
|
+
|
47
55
|
# Array of instantiated fetch modules.
|
48
56
|
def instantiate_modules
|
49
|
-
Array(modules)
|
50
|
-
|
57
|
+
mods = Array(modules)
|
58
|
+
mods = load!(mods) if callback?(:load)
|
59
|
+
Array(mods).map do |klass|
|
60
|
+
init!(klass) || klass.new(fetchable)
|
51
61
|
end
|
52
62
|
end
|
53
63
|
|
data/lib/fetch/callbacks.rb
CHANGED
@@ -17,10 +17,20 @@ module Fetch
|
|
17
17
|
# run_callbacks_for(:progress, 12) # 12 percent done
|
18
18
|
def run_callbacks_for(name, *args)
|
19
19
|
self.class.callbacks[name].map do |block|
|
20
|
-
|
20
|
+
run_callback(*args, &block)
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
def run_last_callback_for(name, *args)
|
25
|
+
if callback = self.class.callbacks[name].last
|
26
|
+
run_callback(*args, &callback)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def run_callback(*args, &block)
|
31
|
+
instance_exec(*args, &block)
|
32
|
+
end
|
33
|
+
|
24
34
|
module ClassMethods
|
25
35
|
# Hash of callback blocks to be called.
|
26
36
|
def callbacks
|
@@ -37,6 +47,10 @@ module Fetch
|
|
37
47
|
define_method name do |*args|
|
38
48
|
run_callbacks_for(name, *args).last
|
39
49
|
end
|
50
|
+
|
51
|
+
define_method "#{name}!" do |*args|
|
52
|
+
run_last_callback_for(name, *args)
|
53
|
+
end
|
40
54
|
end
|
41
55
|
end
|
42
56
|
|
data/lib/fetch/json.rb
ADDED
data/lib/fetch/module.rb
CHANGED
@@ -7,11 +7,20 @@ module Fetch
|
|
7
7
|
:failure,
|
8
8
|
:error
|
9
9
|
|
10
|
+
def initialize(fetchable = nil)
|
11
|
+
@fetchable = fetchable
|
12
|
+
end
|
13
|
+
|
10
14
|
# Whether or not the module should be used when fetching.
|
11
15
|
# Set with `fetch_if do ... end`.
|
12
16
|
def fetch?
|
13
17
|
return true unless callback?(:fetch_if)
|
14
18
|
!!fetch_if
|
15
19
|
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# The optional instance being fetched.
|
24
|
+
attr_reader :fetchable
|
16
25
|
end
|
17
26
|
end
|
data/lib/fetch/request.rb
CHANGED
@@ -99,6 +99,19 @@ module Fetch
|
|
99
99
|
@before_process_callback.call if @before_process_callback
|
100
100
|
end
|
101
101
|
|
102
|
+
# Sets a parse callback to be run on the body returned from the request.
|
103
|
+
# It is run before processing and its result send to process.
|
104
|
+
def parse(&block)
|
105
|
+
raise "You must supply a block to #{self.class.name}#parse" unless block
|
106
|
+
@parse_callback = block
|
107
|
+
end
|
108
|
+
|
109
|
+
# Runs the before process callback.
|
110
|
+
def parse!(body)
|
111
|
+
return body unless @parse_callback
|
112
|
+
@parse_callback.call(body)
|
113
|
+
end
|
114
|
+
|
102
115
|
# Sets the callback to be run when the request completes.
|
103
116
|
def process(&block)
|
104
117
|
raise "You must supply a block to #{self.class.name}#process" unless block
|
@@ -109,6 +122,7 @@ module Fetch
|
|
109
122
|
# the exception to the error callback.
|
110
123
|
def process!(body, url, effective_url)
|
111
124
|
before_process!
|
125
|
+
body = parse!(body)
|
112
126
|
@process_callback.call(body, url, effective_url) if @process_callback
|
113
127
|
after_process!
|
114
128
|
rescue => e
|
data/lib/fetch/version.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class DefaultsTest < Minitest::Test
|
4
|
+
def test_simple_fetch
|
5
|
+
words = %w{one two}
|
6
|
+
words.each { |w| stub_request(:get, "http://test.com/#{w}").to_return(body: "got #{w}") }
|
7
|
+
actions = []
|
8
|
+
mod = Class.new(Fetch::Module) do
|
9
|
+
defaults do |req|
|
10
|
+
req.process do |body|
|
11
|
+
actions << "process: #{body}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
words.each do |word|
|
15
|
+
request do |req|
|
16
|
+
req.url = "http://test.com/#{word}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
MockFetcher(mod).new.fetch
|
21
|
+
assert_equal ["process: got one", "process: got two"], actions
|
22
|
+
end
|
23
|
+
end
|
data/test/fetch_test.rb
CHANGED
@@ -67,34 +67,20 @@ class FetchTest < Minitest::Test
|
|
67
67
|
assert_equal [0, 50, 100], updates
|
68
68
|
end
|
69
69
|
|
70
|
-
def
|
71
|
-
stub_request(:get, "
|
70
|
+
def test_sends_fetchable_to_modules
|
71
|
+
stub_request(:get, "https://api.github.com/users/lassebunk").to_return(body: "id: 1234")
|
72
72
|
actions = []
|
73
73
|
mod = Class.new(Fetch::Module) do
|
74
|
-
attr_reader :word
|
75
|
-
def initialize(word)
|
76
|
-
@word = word
|
77
|
-
end
|
78
74
|
request do |req|
|
79
|
-
req.url = "
|
75
|
+
req.url = "https://api.github.com/users/#{fetchable.login}"
|
80
76
|
req.process do |body|
|
81
|
-
actions << "process: #{body}
|
77
|
+
actions << "process: #{body}"
|
82
78
|
end
|
83
79
|
end
|
84
80
|
end
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
def initialize(something)
|
89
|
-
@something = something
|
90
|
-
end
|
91
|
-
init do |klass|
|
92
|
-
klass.new(something)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
klass.new("a word").fetch
|
97
|
-
assert_equal ["process: got one (a word)"], actions
|
81
|
+
user = OpenStruct.new(login: "lassebunk")
|
82
|
+
MockFetcher(mod).new(user).fetch
|
83
|
+
assert_equal ["process: id: 1234"], actions
|
98
84
|
end
|
99
85
|
|
100
86
|
def test_process_block_scope
|
data/test/init_test.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class InitTest < Minitest::Test
|
4
|
+
def test_initializes_modules
|
5
|
+
stub_request(:get, "https://api.github.com/users/lassebunk").to_return(body: "id: 1234")
|
6
|
+
actions = []
|
7
|
+
mod = Class.new(Fetch::Module) do
|
8
|
+
attr_reader :email, :login
|
9
|
+
def initialize(email, login)
|
10
|
+
@email, @login = email, login
|
11
|
+
end
|
12
|
+
request do |req|
|
13
|
+
req.url = "https://api.github.com/users/#{login}"
|
14
|
+
req.process do |body|
|
15
|
+
actions << "process: #{body} (email: #{email}, login: #{login})"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
klass = Class.new(MockFetcher(mod)) do
|
21
|
+
alias :user :fetchable
|
22
|
+
init do |klass|
|
23
|
+
klass.new(user.email, user.login)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
user = OpenStruct.new(email: "lasse@bogrobotten.dk", login: "lassebunk")
|
28
|
+
klass.new(user).fetch
|
29
|
+
assert_equal ["process: id: 1234 (email: lasse@bogrobotten.dk, login: lassebunk)"], actions
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_init_runs_only_once
|
33
|
+
actions = []
|
34
|
+
mod = Class.new(Fetch::Module)
|
35
|
+
klass = Class.new(MockFetcher(mod)) do
|
36
|
+
init do |klass|
|
37
|
+
this_cant_be_run!
|
38
|
+
end
|
39
|
+
init do |klass|
|
40
|
+
actions << "got init"
|
41
|
+
klass.new
|
42
|
+
end
|
43
|
+
end
|
44
|
+
klass.new.fetch
|
45
|
+
assert_equal ["got init"], actions
|
46
|
+
end
|
47
|
+
end
|
data/test/json_test.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class JsonTest < Minitest::Test
|
4
|
+
def test_parsing_json
|
5
|
+
stub_request(:get, "http://api.test.com/user").to_return(body: '{"id":123}')
|
6
|
+
actions = []
|
7
|
+
mod = Class.new(Fetch::Module) do
|
8
|
+
include Fetch::JSON
|
9
|
+
request do |req|
|
10
|
+
req.url = "http://api.test.com/user"
|
11
|
+
req.process do |json|
|
12
|
+
actions << "user id: #{json['id'].inspect}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
MockFetcher(mod).new.fetch
|
17
|
+
assert_equal ["user id: 123"], actions
|
18
|
+
end
|
19
|
+
end
|
data/test/load_test.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class LoadTest < Minitest::Test
|
4
|
+
def test_loading_modules
|
5
|
+
%w{one two}.each { |w| stub_request(:get, "http://test.com/#{w}").to_return(body: "got #{w}") }
|
6
|
+
actions = []
|
7
|
+
mod1 = Class.new(Fetch::Module) do
|
8
|
+
request do |req|
|
9
|
+
req.url = "http://test.com/one"
|
10
|
+
req.process do |body|
|
11
|
+
actions << "process: #{body}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
mod2 = Class.new(Fetch::Module) do
|
16
|
+
request do |req|
|
17
|
+
req.url = "http://test.com/two"
|
18
|
+
req.process do |body|
|
19
|
+
actions << "process: #{body}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
klass = Class.new(Fetch::Base) do
|
24
|
+
modules :one, :two
|
25
|
+
|
26
|
+
load do |mods|
|
27
|
+
actions << "got #{mods.inspect}"
|
28
|
+
[mod1, mod2]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
klass.new.fetch
|
32
|
+
|
33
|
+
assert_equal ["got [:one, :two]", "process: got one", "process: got two"], actions
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_only_last_load_callback_is_called
|
37
|
+
actions = []
|
38
|
+
mod = Class.new(Fetch::Module)
|
39
|
+
klass = Class.new(Fetch::Base) do
|
40
|
+
load do |mods|
|
41
|
+
this_cant_be_run!
|
42
|
+
end
|
43
|
+
load do |mods|
|
44
|
+
actions << "got last callback"
|
45
|
+
[mod]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
klass.new.fetch
|
49
|
+
|
50
|
+
assert_equal ["got last callback"], actions
|
51
|
+
end
|
52
|
+
end
|
data/test/parse_test.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ParseTest < Minitest::Test
|
4
|
+
def test_parsing_body
|
5
|
+
stub_request(:get, "http://test.com/one").to_return(body: "got one")
|
6
|
+
actions = []
|
7
|
+
mod = Class.new(Fetch::Module) do
|
8
|
+
request do |req|
|
9
|
+
req.url = "http://test.com/one"
|
10
|
+
req.parse do |body|
|
11
|
+
"parsed(#{body})"
|
12
|
+
end
|
13
|
+
req.process do |body|
|
14
|
+
actions << "process: #{body}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
MockFetcher(mod).new.fetch
|
19
|
+
assert_equal ["process: parsed(got one)"], actions
|
20
|
+
end
|
21
|
+
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fetch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lasse Bunk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: typhoeus
|
@@ -89,6 +89,7 @@ extra_rdoc_files: []
|
|
89
89
|
files:
|
90
90
|
- ".gitignore"
|
91
91
|
- ".travis.yml"
|
92
|
+
- CHANGELOG.md
|
92
93
|
- Gemfile
|
93
94
|
- LICENSE.txt
|
94
95
|
- README.md
|
@@ -102,12 +103,18 @@ files:
|
|
102
103
|
- lib/fetch/base.rb
|
103
104
|
- lib/fetch/callbacks.rb
|
104
105
|
- lib/fetch/configuration.rb
|
106
|
+
- lib/fetch/json.rb
|
105
107
|
- lib/fetch/module.rb
|
106
108
|
- lib/fetch/request.rb
|
107
109
|
- lib/fetch/simple.rb
|
108
110
|
- lib/fetch/version.rb
|
109
111
|
- test/callbacks_test.rb
|
112
|
+
- test/defaults_test.rb
|
110
113
|
- test/fetch_test.rb
|
114
|
+
- test/init_test.rb
|
115
|
+
- test/json_test.rb
|
116
|
+
- test/load_test.rb
|
117
|
+
- test/parse_test.rb
|
111
118
|
- test/simple_test.rb
|
112
119
|
- test/test_helper.rb
|
113
120
|
homepage: https://github.com/lassebunk/fetch
|
@@ -136,6 +143,11 @@ specification_version: 4
|
|
136
143
|
summary: Coming
|
137
144
|
test_files:
|
138
145
|
- test/callbacks_test.rb
|
146
|
+
- test/defaults_test.rb
|
139
147
|
- test/fetch_test.rb
|
148
|
+
- test/init_test.rb
|
149
|
+
- test/json_test.rb
|
150
|
+
- test/load_test.rb
|
151
|
+
- test/parse_test.rb
|
140
152
|
- test/simple_test.rb
|
141
153
|
- test/test_helper.rb
|