sinew 2.0.5 → 3.0.0
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/.github/workflows/test.yml +26 -0
- data/.rubocop.yml +9 -6
- data/.vscode/settings.json +0 -10
- data/Gemfile +9 -0
- data/README.md +13 -17
- data/Rakefile +33 -18
- data/bin/sinew +2 -0
- data/lib/sinew.rb +0 -1
- data/lib/sinew/connection.rb +52 -0
- data/lib/sinew/connection/log_formatter.rb +22 -0
- data/lib/sinew/connection/rate_limit.rb +29 -0
- data/lib/sinew/core_ext.rb +1 -1
- data/lib/sinew/dsl.rb +2 -1
- data/lib/sinew/main.rb +7 -55
- data/lib/sinew/output.rb +7 -23
- data/lib/sinew/request.rb +20 -71
- data/lib/sinew/response.rb +8 -57
- data/lib/sinew/runtime_options.rb +4 -4
- data/lib/sinew/version.rb +1 -1
- data/sample.sinew +2 -2
- data/sinew.gemspec +16 -17
- metadata +41 -99
- data/.travis.yml +0 -4
- data/lib/sinew/cache.rb +0 -79
- data/test/legacy/eu.httpbin.org/head/redirect,3 +0 -51
- data/test/legacy/eu.httpbin.org/head/status,500 +0 -1
- data/test/legacy/eu.httpbin.org/redirect,3 +0 -11
- data/test/legacy/eu.httpbin.org/status,500 +0 -1
- data/test/legacy/legacy.sinew +0 -2
- data/test/recipes/array_header.sinew +0 -6
- data/test/recipes/basic.sinew +0 -8
- data/test/recipes/dups.sinew +0 -7
- data/test/recipes/implicit_header.sinew +0 -5
- data/test/recipes/limit.sinew +0 -11
- data/test/recipes/noko.sinew +0 -9
- data/test/recipes/uri.sinew +0 -11
- data/test/recipes/xml.sinew +0 -8
- data/test/test.html +0 -45
- data/test/test_cache.rb +0 -69
- data/test/test_helper.rb +0 -126
- data/test/test_legacy.rb +0 -23
- data/test/test_main.rb +0 -34
- data/test/test_nokogiri_ext.rb +0 -18
- data/test/test_output.rb +0 -56
- data/test/test_recipes.rb +0 -60
- data/test/test_requests.rb +0 -164
- data/test/test_utf8.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: df55f2168ff4242fceb31d083b8d16f1046139fa7acb8a9c4fc3f06f7884e113
|
4
|
+
data.tar.gz: 520967eba4ea2d8446690736f2c28d34642b452c0f4e5003dcb89ce373c116e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7443bccc5fc4e1bd112ce50b3d17445f0c21f5b351a6b5be586aadd63f36396312370ec6115d8116701165b3af19fcb852f85d18d0fbe7b4bf0d797312d3fa40
|
7
|
+
data.tar.gz: 9ca4f3c424e021100f518ca4f2231f515b38dbeb402ff4fce07c13a2440f19b0fabcc2a2920e51aa3f6228507550d3c94cb70a46fd22711ba3add90e4fc28004
|
@@ -0,0 +1,26 @@
|
|
1
|
+
name: test
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
paths-ignore:
|
6
|
+
- '**.md'
|
7
|
+
pull_request:
|
8
|
+
paths-ignore:
|
9
|
+
- '**.md'
|
10
|
+
workflow_dispatch:
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
test:
|
14
|
+
strategy:
|
15
|
+
max-parallel: 3
|
16
|
+
matrix:
|
17
|
+
os: [ubuntu, macos]
|
18
|
+
ruby-version: [3.0, 2.7]
|
19
|
+
runs-on: ${{ matrix.os }}-latest
|
20
|
+
steps:
|
21
|
+
- uses: actions/checkout@v2
|
22
|
+
- uses: ruby/setup-ruby@v1
|
23
|
+
with:
|
24
|
+
ruby-version: ${{ matrix.ruby-version }}
|
25
|
+
- run: bundle install
|
26
|
+
- run: bundle exec rake test
|
data/.rubocop.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
AllCops:
|
2
|
-
|
3
|
-
|
2
|
+
TargetRubyVersion: 2.7
|
3
|
+
NewCops: enable
|
4
4
|
|
5
5
|
# amd: customizations
|
6
6
|
Layout/SpaceInsideArrayLiteralBrackets:
|
@@ -22,18 +22,19 @@ Style/TrailingCommaInHashLiteral:
|
|
22
22
|
|
23
23
|
# amd: these seem extreme
|
24
24
|
Lint/AssignmentInCondition: { Enabled: false } # I do this all the time
|
25
|
-
Lint/
|
25
|
+
Lint/SuppressedException: { Enabled: false } # blank rescues are useful
|
26
26
|
Naming/BinaryOperatorParameterName: { Enabled: false } # silly
|
27
27
|
Naming/HeredocDelimiterNaming: { Enabled: false } # silly
|
28
|
-
Naming/
|
29
|
-
|
30
|
-
|
28
|
+
Naming/MethodParameterName: { Enabled: false } # silly
|
29
|
+
Style/AccessorGrouping: { Enabled: false } # silly
|
30
|
+
Style/AsciiComments: { Enabled: false } # silly
|
31
31
|
Style/ClassAndModuleChildren: { Enabled: false } # silly
|
32
32
|
Style/Documentation: { Enabled: false } # we don't need this
|
33
33
|
Style/DoubleNegation: { Enabled: false } # silly
|
34
34
|
Style/FormatStringToken: { Enabled: false } # we like printf here
|
35
35
|
Style/FrozenStringLiteralComment: { Enabled: false } # seems excessive
|
36
36
|
Style/GuardClause: { Enabled: false } # confusing
|
37
|
+
Style/HashTransformValues: { Enabled: false } # breaks code by trying to apply to an array
|
37
38
|
Style/IfUnlessModifier: { Enabled: false } # personally I hate unless
|
38
39
|
Style/NegatedIf: { Enabled: false } # these are fine
|
39
40
|
Style/Next: { Enabled: false } # these are fine
|
@@ -41,7 +42,9 @@ Style/NumericPredicate: { Enabled: false } # silly
|
|
41
42
|
Style/ParallelAssignment: { Enabled: false } # these are fine
|
42
43
|
Style/PerlBackrefs: { Enabled: false } # these are fine
|
43
44
|
Style/RaiseArgs: { Enabled: false } # silly
|
45
|
+
Style/RedundantAssignment: { Enabled: false } # these are usually on purpose
|
44
46
|
Style/RegexpLiteral: { Enabled: false } # these are fine
|
47
|
+
Style/SoleNestedConditional: { Enabled: false } # these are fine
|
45
48
|
Style/StderrPuts: { Enabled: false } # this is awful
|
46
49
|
|
47
50
|
# amd: these Metric rules are annoying, disable
|
data/.vscode/settings.json
CHANGED
@@ -1,15 +1,5 @@
|
|
1
1
|
{
|
2
|
-
"editor.formatOnSave": true,
|
3
|
-
"editor.formatOnSaveTimeout": 1500,
|
4
|
-
"editor.tabSize": 2,
|
5
|
-
"editor.wordSeparators": "`~#$%^&*()-=+[{]}\\|;:'\",.<>/",
|
6
2
|
"files.associations": {
|
7
3
|
"*.sinew": "ruby"
|
8
|
-
},
|
9
|
-
"files.insertFinalNewline": true,
|
10
|
-
"files.trimTrailingWhitespace": true,
|
11
|
-
"ruby.format": "rubocop",
|
12
|
-
"ruby.lint": {
|
13
|
-
"rubocop": true
|
14
4
|
}
|
15
5
|
}
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
](https://github.com/gurgeous/sinew/action)
|
2
2
|
|
3
3
|
## Welcome to Sinew
|
4
4
|
|
@@ -20,7 +20,7 @@ gem 'sinew'
|
|
20
20
|
|
21
21
|
<!--- markdown-toc --no-firsth1 --maxdepth 1 readme.md -->
|
22
22
|
|
23
|
-
- [Sinew
|
23
|
+
- [Sinew 3](#sinew-3-may-2021)
|
24
24
|
- [Quick Example](#quick-example)
|
25
25
|
- [How it Works](#how-it-works)
|
26
26
|
- [DSL Reference](#dsl-reference)
|
@@ -29,27 +29,21 @@ gem 'sinew'
|
|
29
29
|
- [Changelog](#changelog)
|
30
30
|
- [License](#license)
|
31
31
|
|
32
|
-
## Sinew
|
32
|
+
## Sinew 3 (May 2021)
|
33
33
|
|
34
|
-
I am pleased to announce the release of Sinew
|
35
|
-
|
36
|
-
- Remove dependencies on active_support, curl and tidy. We use HTTParty now.
|
37
|
-
- Much easier to customize requests in `.sinew` files. For example, setting User-Agent or Bearer tokens.
|
38
|
-
- More operations like `post_json` or the generic `http`. These methods are thin wrappers around HTTParty.
|
39
|
-
- New end-of-run report.
|
40
|
-
- Tests, rubocop, vscode settings, travis, etc.
|
34
|
+
I am pleased to announce the release of Sinew 3.0. Sinew has been streamlined and updated to use the [Faraday](https://lostisland.github.io/faraday/) HTTP client with [sinew](https://github.com/gurgeous/sinew/) middleware for caching.
|
41
35
|
|
42
36
|
**Breaking change**
|
43
37
|
|
44
|
-
Sinew uses a new format for cached responses. Old Sinew
|
38
|
+
Sinew 3 uses a new format for cached responses. Old Sinew 2 cache directories should be removed before running Sinew again.
|
45
39
|
|
46
40
|
## Quick Example
|
47
41
|
|
48
|
-
Here's an example for collecting the links from
|
42
|
+
Here's an example for collecting the links from httpbingo.org:
|
49
43
|
|
50
44
|
```ruby
|
51
45
|
# get the url
|
52
|
-
get "http://
|
46
|
+
get "http://httpbingo.org"
|
53
47
|
|
54
48
|
# use nokogiri to collect links
|
55
49
|
noko.css("ul li a").each do |a|
|
@@ -114,9 +108,9 @@ Sinew creates a CSV file with the same name as the recipe, and `csv_emit(hash)`
|
|
114
108
|
|
115
109
|
#### Caching
|
116
110
|
|
117
|
-
|
111
|
+
Sinew uses [sinew](https://github.com/gurgeous/sinew/) to aggressively cache all HTTP responses to disk in `~/.sinew`. Error responses are cached as well. Each URL will be hit exactly once, and requests are rate limited to one per second. Sinew tries to be polite.
|
118
112
|
|
119
|
-
|
113
|
+
Sinew never deletes files from the cache - that's up to you!
|
120
114
|
|
121
115
|
Because all requests are cached, you can run Sinew repeatedly with confidence. Run it over and over again while you build up your recipe.
|
122
116
|
|
@@ -162,7 +156,7 @@ Writing Sinew recipes is fun and easy. The builtin caching means you can iterate
|
|
162
156
|
noko.css("table")[4].css("td").select { |i| i[:width].to_i > 80 }.map(&:text)
|
163
157
|
```
|
164
158
|
|
165
|
-
- Debug your recipes using plain old `puts`, or better yet use `ap` from [
|
159
|
+
- Debug your recipes using plain old `puts`, or better yet use `ap` from [amazing_print](https://github.com/amazing-print/amazing_print).
|
166
160
|
- Run `sinew -v` to get a report on every `csv_emit`. Very handy.
|
167
161
|
- Add the CSV files to your git repo. That way you can version them and get diffs!
|
168
162
|
|
@@ -173,8 +167,10 @@ noko.css("table")[4].css("td").select { |i| i[:width].to_i > 80 }.map(&:text)
|
|
173
167
|
|
174
168
|
## Changelog
|
175
169
|
|
176
|
-
####
|
170
|
+
#### 3.0.0 (May 2021)
|
177
171
|
|
172
|
+
- Major rewrite of network and caching layer. See above.
|
173
|
+
- Use Faraday HTTP client with sinew middleware for caching.
|
178
174
|
- Supports multiple proxies (`--proxy host1,host2,...`)
|
179
175
|
|
180
176
|
#### 2.0.4 (May 2018)
|
data/Rakefile
CHANGED
@@ -1,38 +1,53 @@
|
|
1
|
-
require 'bundler'
|
2
1
|
require 'bundler/setup'
|
3
2
|
|
4
|
-
require 'rake'
|
5
3
|
require 'rake/testtask'
|
6
4
|
require 'sinew/version'
|
7
5
|
|
6
|
+
# load the spec, we use it below
|
7
|
+
spec = Gem::Specification.load('sinew.gemspec')
|
8
|
+
|
8
9
|
#
|
9
|
-
#
|
10
|
+
# testing
|
11
|
+
# don't forget about TESTOPTS="--verbose" rake
|
12
|
+
# also: rake install && rm -rf ~/.sinew/www.amazon.com && /usr/local/bin/sinew sample.sinew
|
10
13
|
#
|
11
14
|
|
12
|
-
|
13
|
-
task :
|
14
|
-
|
15
|
+
# test (default)
|
16
|
+
task default: :test
|
17
|
+
|
18
|
+
Rake::TestTask.new do
|
19
|
+
_1.libs << 'test'
|
20
|
+
_1.warning = false # sterile has a few issues here
|
15
21
|
end
|
16
22
|
|
17
|
-
|
18
|
-
|
23
|
+
# Watch rb files, run tests whenever something changes
|
24
|
+
task :watch do
|
25
|
+
# https://superuser.com/a/665208 / https://unix.stackexchange.com/a/42288
|
26
|
+
system("while true; do find . -name '*.rb' | entr -c -d rake; test $? -gt 128 && break; done")
|
19
27
|
end
|
20
28
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
29
|
+
#
|
30
|
+
# rubocop
|
31
|
+
#
|
32
|
+
|
33
|
+
task :rubocop do
|
34
|
+
system('bundle exec rubocop -A .', exception: true)
|
25
35
|
end
|
26
36
|
|
27
37
|
#
|
28
|
-
#
|
38
|
+
# gem
|
29
39
|
#
|
30
40
|
|
31
|
-
|
32
|
-
|
41
|
+
task :build do
|
42
|
+
system 'gem build --quiet sinew.gemspec', exception: true
|
33
43
|
end
|
34
44
|
|
35
|
-
task
|
45
|
+
task install: :build do
|
46
|
+
system "gem install --quiet sinew-#{spec.version}.gem", exception: true
|
47
|
+
end
|
36
48
|
|
37
|
-
|
38
|
-
|
49
|
+
task release: %i[rubocop test build] do
|
50
|
+
system "git tag -a #{spec.version} -m 'Tagging #{spec.version}'", exception: true
|
51
|
+
system 'git push --tags', exception: true
|
52
|
+
system "gem push sinew-#{spec.version}.gem", exception: true
|
53
|
+
end
|
data/bin/sinew
CHANGED
@@ -15,6 +15,8 @@ options = Slop.parse do |o|
|
|
15
15
|
o.bool '-q', '--quiet', 'suppress some output'
|
16
16
|
o.integer '-l', '--limit', 'quit after emitting this many rows'
|
17
17
|
o.string '-c', '--cache', 'set custom cache directory', default: "#{ENV['HOME']}/.sinew"
|
18
|
+
o.bool '--force', "don't read anything from cache (but still write)"
|
19
|
+
o.bool '--force-errors', "don't read errors from cache (but still write)"
|
18
20
|
o.string '--proxy', 'use host[:port] as HTTP proxy'
|
19
21
|
o.bool '--version', 'show version and exit'
|
20
22
|
o.on('--help', 'show this help') do
|
data/lib/sinew.rb
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday-encoding'
|
3
|
+
require 'faraday/logging/formatter'
|
4
|
+
require 'httpdisk'
|
5
|
+
require 'sinew/connection/log_formatter'
|
6
|
+
require 'sinew/connection/rate_limit'
|
7
|
+
|
8
|
+
module Sinew
|
9
|
+
module Connection
|
10
|
+
def self.create(options:, runtime_options:)
|
11
|
+
connection_options = {}
|
12
|
+
connection_options[:ssl] = { verify: false } if runtime_options.insecure
|
13
|
+
|
14
|
+
Faraday.new(nil, connection_options) do
|
15
|
+
_1.use RateLimit, rate_limit: runtime_options.rate_limit
|
16
|
+
|
17
|
+
# auto-encode form bodies
|
18
|
+
_1.request :url_encoded
|
19
|
+
|
20
|
+
# Before httpdisk so each redirect segment is cached
|
21
|
+
# Keep track of redirect status for logger
|
22
|
+
_1.response :follow_redirects, callback: ->(_old_env, new_env) { new_env[:redirect] = true }
|
23
|
+
|
24
|
+
# set Ruby string encoding based on Content-Type (should be above httpdisk)
|
25
|
+
_1.response :encoding
|
26
|
+
|
27
|
+
# disk caching
|
28
|
+
httpdisk_options = {
|
29
|
+
dir: options[:cache],
|
30
|
+
force: options[:force],
|
31
|
+
force_errors: options[:force_errors],
|
32
|
+
}.merge(runtime_options.httpdisk_options)
|
33
|
+
|
34
|
+
_1.use :httpdisk, httpdisk_options
|
35
|
+
|
36
|
+
# After httpdisk so that only non-cached requests are logged.
|
37
|
+
# Before retry so that we don't log each retry attempt.
|
38
|
+
_1.response :logger, nil, formatter: LogFormatter if !options[:quiet]
|
39
|
+
|
40
|
+
# After httpdisk so transient failures are not cached
|
41
|
+
retry_options = {
|
42
|
+
interval: runtime_options.rate_limit,
|
43
|
+
max: runtime_options.retries,
|
44
|
+
methods: %w[delete get head options patch post put trace],
|
45
|
+
retry_statuses: (500..600).to_a,
|
46
|
+
retry_if: ->(_env, _err) { true },
|
47
|
+
}
|
48
|
+
_1.request :retry, retry_options
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Sinew
|
2
|
+
module Connection
|
3
|
+
class LogFormatter < Faraday::Logging::Formatter
|
4
|
+
def request(env)
|
5
|
+
info('req') do
|
6
|
+
# Only log the initial request, not the redirects
|
7
|
+
return if env[:redirect]
|
8
|
+
|
9
|
+
msg = apply_filters(env.url.to_s)
|
10
|
+
msg = "#{msg} (#{env.method})" if env.method != :get
|
11
|
+
msg = "#{msg} => #{env.request.proxy.uri}" if env.request.proxy
|
12
|
+
|
13
|
+
msg
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def response(env)
|
18
|
+
# silent
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Sinew
|
2
|
+
module Connection
|
3
|
+
class RateLimit < Faraday::Middleware
|
4
|
+
attr_reader :rate_limit
|
5
|
+
|
6
|
+
def initialize(app, options = {})
|
7
|
+
super(app)
|
8
|
+
|
9
|
+
@last_request_tm = @current_request_tm = nil
|
10
|
+
@rate_limit = options.fetch(:rate_limit, 1)
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_request(_env)
|
14
|
+
if @last_request_tm
|
15
|
+
sleep = (@last_request_tm + rate_limit) - Time.now
|
16
|
+
sleep(sleep) if sleep > 0
|
17
|
+
end
|
18
|
+
|
19
|
+
@current_request_tm = Time.now
|
20
|
+
end
|
21
|
+
|
22
|
+
def on_complete(env)
|
23
|
+
# Only rate limit on uncached requests
|
24
|
+
@last_request_tm = @current_request_tm unless env[:httpdisk]
|
25
|
+
@current_request_tm = nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/sinew/core_ext.rb
CHANGED
data/lib/sinew/dsl.rb
CHANGED
data/lib/sinew/main.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'scripto'
|
2
|
+
require 'sinew/connection'
|
2
3
|
|
3
4
|
#
|
4
5
|
# Main sinew entry point.
|
@@ -6,15 +7,13 @@ require 'scripto'
|
|
6
7
|
|
7
8
|
module Sinew
|
8
9
|
class Main < Scripto::Main
|
9
|
-
attr_reader :runtime_options
|
10
|
+
attr_reader :runtime_options
|
10
11
|
|
11
12
|
def initialize(options)
|
12
13
|
super(options)
|
13
14
|
|
14
15
|
# init
|
15
16
|
@runtime_options = RuntimeOptions.new
|
16
|
-
@request_tm = Time.at(0)
|
17
|
-
@request_count = 0
|
18
17
|
end
|
19
18
|
|
20
19
|
def run
|
@@ -31,24 +30,12 @@ module Sinew
|
|
31
30
|
end
|
32
31
|
|
33
32
|
#
|
34
|
-
# http requests
|
33
|
+
# http requests
|
35
34
|
#
|
36
35
|
|
37
|
-
def cache
|
38
|
-
@cache ||= Cache.new(self)
|
39
|
-
end
|
40
|
-
|
41
36
|
def http(method, url, options = {})
|
42
37
|
request = Request.new(self, method, url, options)
|
43
|
-
|
44
|
-
# try to get from cache
|
45
|
-
response = cache.get(request)
|
46
|
-
|
47
|
-
# perform if necessary
|
48
|
-
if !response
|
49
|
-
response = perform(request)
|
50
|
-
cache.set(response)
|
51
|
-
end
|
38
|
+
response = request.perform(connection)
|
52
39
|
|
53
40
|
# always log error messages
|
54
41
|
if response.error?
|
@@ -58,26 +45,10 @@ module Sinew
|
|
58
45
|
response
|
59
46
|
end
|
60
47
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
response = nil
|
65
|
-
|
66
|
-
tries = runtime_options.retries + 1
|
67
|
-
while tries > 0
|
68
|
-
tries -= 1
|
69
|
-
begin
|
70
|
-
@request_count += 1
|
71
|
-
response = request.perform
|
72
|
-
rescue HTTParty::RedirectionTooDeep, OpenSSL::SSL::SSLError, SocketError, SystemCallError, Timeout::Error => e
|
73
|
-
response = Response.from_error(request, e)
|
74
|
-
end
|
75
|
-
break if !response.error_500?
|
76
|
-
end
|
77
|
-
|
78
|
-
response
|
48
|
+
def connection
|
49
|
+
@connection ||= Connection.create(options: options, runtime_options: runtime_options)
|
79
50
|
end
|
80
|
-
protected :
|
51
|
+
protected :connection
|
81
52
|
|
82
53
|
#
|
83
54
|
# output
|
@@ -91,25 +62,6 @@ module Sinew
|
|
91
62
|
# helpers
|
92
63
|
#
|
93
64
|
|
94
|
-
def before_perform_request(request)
|
95
|
-
# log
|
96
|
-
if !quiet?
|
97
|
-
msg = if request.method != 'get'
|
98
|
-
"req #{request.uri} (#{request.method})"
|
99
|
-
else
|
100
|
-
"req #{request.uri}"
|
101
|
-
end
|
102
|
-
msg = "#{msg} => #{request.proxy}" if request.proxy
|
103
|
-
$stderr.puts msg
|
104
|
-
end
|
105
|
-
|
106
|
-
# rate limit
|
107
|
-
sleep = (request_tm + runtime_options.rate_limit) - Time.now
|
108
|
-
sleep(sleep) if sleep > 0
|
109
|
-
@request_tm = Time.now
|
110
|
-
end
|
111
|
-
protected :before_perform_request
|
112
|
-
|
113
65
|
def footer
|
114
66
|
output.report
|
115
67
|
finished = output.count > 0 ? "Finished #{output.filename}" : 'Finished'
|