heroics 0.0.14 → 0.0.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -3
- data/heroics.gemspec +1 -1
- data/lib/heroics.rb +1 -0
- data/lib/heroics/cli.rb +1 -0
- data/lib/heroics/client.rb +1 -0
- data/lib/heroics/client_generator.rb +1 -0
- data/lib/heroics/command.rb +1 -0
- data/lib/heroics/errors.rb +1 -0
- data/lib/heroics/link.rb +43 -17
- data/lib/heroics/naming.rb +1 -0
- data/lib/heroics/resource.rb +1 -0
- data/lib/heroics/schema.rb +1 -0
- data/lib/heroics/version.rb +2 -1
- data/lib/heroics/views/client.erb +2 -3
- data/test.rb +1 -0
- data/test/cli_test.rb +1 -0
- data/test/client_generator_test.rb +1 -0
- data/test/client_test.rb +1 -0
- data/test/command_test.rb +1 -0
- data/test/helper.rb +1 -0
- data/test/link_test.rb +46 -0
- data/test/naming_test.rb +1 -0
- data/test/resource_test.rb +1 -0
- data/test/schema_test.rb +1 -0
- data/test/version_test.rb +1 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fdba196ca9514256d462ec682debf617bf37f16
|
4
|
+
data.tar.gz: af76b3f90fd215ee446b0c954b35dbf9071c3b2e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a73cb1eba0b3ae7f3390612af5b99fdbd323a73838f810c569179bd0d6f25a15f85b500d1d934e37f627de84e802fc5b9c1d6674b3b0c3e81f6bf3bd66fd50e6
|
7
|
+
data.tar.gz: 313d065db244cb6c99c5ccb02ec781188125f5de45c35c77630966d046c3b6443a6e3217c20637fbbebb7b4dd5a6eb5c0279b0c14e9d4987790dc3db2dc013ee
|
data/.travis.yml
CHANGED
data/heroics.gemspec
CHANGED
@@ -25,7 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_development_dependency 'rake'
|
26
26
|
spec.add_development_dependency 'turn'
|
27
27
|
|
28
|
-
spec.add_dependency 'erubis', '~> 2.
|
28
|
+
spec.add_dependency 'erubis', '~> 2.0'
|
29
29
|
spec.add_dependency 'excon'
|
30
30
|
spec.add_dependency 'moneta'
|
31
31
|
spec.add_dependency 'multi_json', '>= 1.9.2'
|
data/lib/heroics.rb
CHANGED
data/lib/heroics/cli.rb
CHANGED
data/lib/heroics/client.rb
CHANGED
data/lib/heroics/command.rb
CHANGED
data/lib/heroics/errors.rb
CHANGED
data/lib/heroics/link.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Heroics
|
2
3
|
# A link invokes requests with an HTTP server.
|
3
4
|
class Link
|
@@ -50,25 +51,14 @@ module Heroics
|
|
50
51
|
headers = headers.merge({'Content-Type' => @link_schema.content_type})
|
51
52
|
body = @link_schema.encode(body)
|
52
53
|
end
|
53
|
-
cache_key = "#{path}:#{headers.hash}"
|
54
|
-
if @link_schema.method == :get
|
55
|
-
etag = @cache["etag:#{cache_key}"]
|
56
|
-
headers = headers.merge({'If-None-Match' => etag}) if etag
|
57
|
-
end
|
58
54
|
|
59
|
-
connection = Excon.new(@root_url)
|
60
|
-
response = connection
|
55
|
+
connection = Excon.new(@root_url, thread_safe_sockets: true)
|
56
|
+
response = request_with_cache(connection,
|
57
|
+
method: @link_schema.method, path: path,
|
61
58
|
headers: headers, body: body,
|
62
|
-
expects: [200, 201, 202, 204, 206
|
59
|
+
expects: [200, 201, 202, 204, 206])
|
63
60
|
content_type = response.headers['Content-Type']
|
64
|
-
if
|
65
|
-
MultiJson.load(@cache["data:#{cache_key}"])
|
66
|
-
elsif content_type && content_type =~ /application\/.*json/
|
67
|
-
etag = response.headers['ETag']
|
68
|
-
if etag
|
69
|
-
@cache["etag:#{cache_key}"] = etag
|
70
|
-
@cache["data:#{cache_key}"] = response.body
|
71
|
-
end
|
61
|
+
if content_type && content_type =~ /application\/.*json/
|
72
62
|
body = MultiJson.load(response.body)
|
73
63
|
if response.status == 206
|
74
64
|
next_range = response.headers['Next-Range']
|
@@ -83,7 +73,8 @@ module Heroics
|
|
83
73
|
# next range.
|
84
74
|
break unless next_range
|
85
75
|
headers = headers.merge({'Range' => next_range})
|
86
|
-
response = connection
|
76
|
+
response = request_with_cache(connection,
|
77
|
+
method: @link_schema.method,
|
87
78
|
path: path, headers: headers,
|
88
79
|
expects: [200, 201, 206])
|
89
80
|
body = MultiJson.load(response.body)
|
@@ -100,6 +91,31 @@ module Heroics
|
|
100
91
|
|
101
92
|
private
|
102
93
|
|
94
|
+
def request_with_cache(connection, options)
|
95
|
+
options[:expects] << 304
|
96
|
+
cache_key = "#{options[:path]}:#{options[:headers].hash}"
|
97
|
+
if options[:method] == :get
|
98
|
+
etag = @cache["etag:#{cache_key}"]
|
99
|
+
options[:headers] = options[:headers].merge({'If-None-Match' => etag}) if etag
|
100
|
+
end
|
101
|
+
response = connection.request(options)
|
102
|
+
|
103
|
+
if response.status == 304
|
104
|
+
body = @cache["data:#{cache_key}"]
|
105
|
+
status = @cache["status:#{cache_key}"]
|
106
|
+
headers = @cache["headers:#{cache_key}"]
|
107
|
+
CachedResponse.new(status, body, headers)
|
108
|
+
else
|
109
|
+
if etag = response.headers['ETag']
|
110
|
+
@cache["etag:#{cache_key}"] = etag
|
111
|
+
@cache["data:#{cache_key}"] = response.body
|
112
|
+
@cache["status:#{cache_key}"] = response.status
|
113
|
+
@cache["headers:#{cache_key}"] = response.headers
|
114
|
+
end
|
115
|
+
response
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
103
119
|
# Unpack the URL and split it into a root URL and a path prefix, if one
|
104
120
|
# exists.
|
105
121
|
#
|
@@ -116,5 +132,15 @@ module Heroics
|
|
116
132
|
path_prefix = parts[5]
|
117
133
|
return root_url.join(''), path_prefix
|
118
134
|
end
|
135
|
+
|
136
|
+
class CachedResponse
|
137
|
+
attr_reader :status, :body, :headers
|
138
|
+
def initialize(status, body, headers)
|
139
|
+
@status = status
|
140
|
+
@body = body
|
141
|
+
@headers = headers
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
119
145
|
end
|
120
146
|
end
|
data/lib/heroics/naming.rb
CHANGED
data/lib/heroics/resource.rb
CHANGED
data/lib/heroics/schema.rb
CHANGED
data/lib/heroics/version.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
#
|
4
5
|
# WARNING: Do not edit by hand, this file was generated by Heroics:
|
@@ -66,7 +67,7 @@ module <%= @module_name %>
|
|
66
67
|
final_options[:default_headers].merge!(options[:default_headers])
|
67
68
|
end
|
68
69
|
final_options[:cache] = options[:cache] if options[:cache]
|
69
|
-
final_options[:url] = options[:url]
|
70
|
+
final_options[:url] = options[:url] || <%= @cache %>
|
70
71
|
final_options[:user] = options[:user] if options[:user]
|
71
72
|
final_options
|
72
73
|
end
|
@@ -74,10 +75,8 @@ module <%= @module_name %>
|
|
74
75
|
# Get the default options.
|
75
76
|
def self.default_options
|
76
77
|
default_headers = <%= @default_headers %>
|
77
|
-
cache = <%= @cache %>
|
78
78
|
{
|
79
79
|
default_headers: default_headers,
|
80
|
-
cache: cache,
|
81
80
|
url: "<%= @url %>"
|
82
81
|
}
|
83
82
|
end
|
data/test.rb
CHANGED
data/test/cli_test.rb
CHANGED
data/test/client_test.rb
CHANGED
data/test/command_test.rb
CHANGED
data/test/helper.rb
CHANGED
data/test/link_test.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'helper'
|
2
3
|
|
3
4
|
class LinkTest < MiniTest::Unit::TestCase
|
@@ -339,6 +340,8 @@ class LinkTest < MiniTest::Unit::TestCase
|
|
339
340
|
cache = Moneta.new(:Memory)
|
340
341
|
cache["etag:/resource:#{headers.hash}"] = 'etag-contents'
|
341
342
|
cache["data:/resource:#{headers.hash}"] = MultiJson.dump(body)
|
343
|
+
cache["status:/resource:#{headers.hash}"] = 200
|
344
|
+
cache["headers:/resource:#{headers.hash}"] = {'Content-Type' => 'application/json'}
|
342
345
|
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
343
346
|
link = Heroics::Link.new('https://example.com',
|
344
347
|
schema.resource('resource').link('list'),
|
@@ -395,4 +398,47 @@ class LinkTest < MiniTest::Unit::TestCase
|
|
395
398
|
schema.resource('resource').link('list'))
|
396
399
|
assert_equal([1, 2], link.run.to_a)
|
397
400
|
end
|
401
|
+
|
402
|
+
# Ensure that caching does not prevent pagination from working correctly.
|
403
|
+
# See https://github.com/heroku/platform-api/issues/16
|
404
|
+
def test_run_with_range_response_and_cache
|
405
|
+
Excon.stub(method: :get) do |request|
|
406
|
+
Excon.stubs.shift
|
407
|
+
{status: 206, headers: {'Content-Type' => 'application/json',
|
408
|
+
'Content-Range' => 'id 1..2; max=200',
|
409
|
+
'ETag' => 'second-page'},
|
410
|
+
body: MultiJson.dump([2])}
|
411
|
+
end
|
412
|
+
|
413
|
+
Excon.stub(method: :get) do |request|
|
414
|
+
Excon.stubs.shift
|
415
|
+
{status: 206, headers: {'Content-Type' => 'application/json',
|
416
|
+
'Content-Range' => 'id 0..1; max=200',
|
417
|
+
'Next-Range' => '201',
|
418
|
+
'ETag' => 'first-page'},
|
419
|
+
body: MultiJson.dump([1])}
|
420
|
+
end
|
421
|
+
|
422
|
+
schema = Heroics::Schema.new(SAMPLE_SCHEMA)
|
423
|
+
link = Heroics::Link.new('https://example.com',
|
424
|
+
schema.resource('resource').link('list'),
|
425
|
+
cache: Moneta.new(:Memory))
|
426
|
+
assert_equal([1, 2], link.run.to_a)
|
427
|
+
|
428
|
+
Excon.stub(method: :get) do |request|
|
429
|
+
assert_equal('second-page', request[:headers]['If-None-Match'])
|
430
|
+
assert_equal('201', request[:headers]['Range'])
|
431
|
+
Excon.stubs.shift
|
432
|
+
{status: 304, headers: {'Content-Type' => 'application/json'}}
|
433
|
+
end
|
434
|
+
|
435
|
+
Excon.stub(method: :get) do |request|
|
436
|
+
assert_equal('first-page', request[:headers]['If-None-Match'])
|
437
|
+
assert_equal(nil, request[:headers]['Range'])
|
438
|
+
Excon.stubs.shift
|
439
|
+
{status: 304, headers: {'Content-Type' => 'application/json'}}
|
440
|
+
end
|
441
|
+
|
442
|
+
assert_equal([1, 2], link.run.to_a)
|
443
|
+
end
|
398
444
|
end
|
data/test/naming_test.rb
CHANGED
data/test/resource_test.rb
CHANGED
data/test/schema_test.rb
CHANGED
data/test/version_test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: heroics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- geemus
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-03-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -73,14 +73,14 @@ dependencies:
|
|
73
73
|
requirements:
|
74
74
|
- - "~>"
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: 2.
|
76
|
+
version: '2.0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
81
|
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: 2.
|
83
|
+
version: '2.0'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: excon
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -202,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
202
202
|
version: '0'
|
203
203
|
requirements: []
|
204
204
|
rubyforge_project:
|
205
|
-
rubygems_version: 2.
|
205
|
+
rubygems_version: 2.5.1
|
206
206
|
signing_key:
|
207
207
|
specification_version: 4
|
208
208
|
summary: A Ruby client generator for HTTP APIs described with a JSON schema
|