fetch 0.0.1 → 0.0.2
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/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
|