async-rest 0.10.0 → 0.12.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/async/rest.rb +2 -0
- data/lib/async/rest/error.rb +20 -1
- data/lib/async/rest/representation.rb +41 -7
- data/lib/async/rest/resource.rb +8 -7
- data/lib/async/rest/version.rb +3 -1
- data/lib/async/rest/wrapper/form.rb +65 -0
- data/lib/async/rest/wrapper/generic.rb +22 -0
- data/lib/async/rest/wrapper/json.rb +6 -13
- data/lib/async/rest/wrapper/url_encoded.rb +6 -12
- metadata +22 -30
- data/.editorconfig +0 -6
- data/.gitignore +0 -12
- data/.rspec +0 -3
- data/.travis.yml +0 -19
- data/Gemfile +0 -8
- data/README.md +0 -106
- data/Rakefile +0 -6
- data/async-rest.gemspec +0 -28
- data/examples/slack/clean.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc914b22fd6a8a19da71676f835e23a606b8c9e6ebd981f25b17b9452422a791
|
4
|
+
data.tar.gz: d639c6647805c99501b9849ee4ebdc3a1650279b93b5053f00af513cb75c2e6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2fe066c918388cd94e92ba167f0910fd189991abb14565172946f74f9d8af3f24f66c18cef586a0b41a87d19c036af08da227404954f5619c313b1273fe64025
|
7
|
+
data.tar.gz: fe5226f20eb31178830ff77f37df8d03c0d3f66c0edc098ed700fcf7f394fee9ba4452cca6190e21c153390915227df23d7e29017e506f9c18f7e19000be33f5
|
data/lib/async/rest.rb
CHANGED
data/lib/async/rest/error.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -23,7 +25,24 @@ module Async
|
|
23
25
|
class Error < StandardError
|
24
26
|
end
|
25
27
|
|
26
|
-
class
|
28
|
+
class RequestError < Error
|
29
|
+
end
|
30
|
+
|
31
|
+
class UnsupportedError < Error
|
32
|
+
end
|
33
|
+
|
34
|
+
class ResponseError < Error
|
35
|
+
def initialize(response)
|
36
|
+
super(response.read)
|
37
|
+
|
38
|
+
@response = response
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
"#{@response}: #{super}"
|
43
|
+
end
|
44
|
+
|
45
|
+
attr :response
|
27
46
|
end
|
28
47
|
end
|
29
48
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -28,15 +30,35 @@ module Async
|
|
28
30
|
#
|
29
31
|
# A representation consists of data, metadata describing the data, and, on occasion, metadata to describe the metadata (usually for the purpose of verifying message integrity). Metadata is in the form of name-value pairs, where the name corresponds to a standard that defines the value's structure and semantics. Response messages may include both representation metadata and resource metadata: information about the resource that is not specific to the supplied representation.
|
30
32
|
class Representation
|
31
|
-
def self.
|
32
|
-
|
33
|
+
def self.[] wrapper
|
34
|
+
klass = Class.new(self)
|
35
|
+
|
36
|
+
klass.const_set(:WRAPPER, wrapper)
|
37
|
+
|
38
|
+
return klass
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.for(*arguments, **options)
|
42
|
+
representation = self.new(Resource.for(*arguments), **options)
|
43
|
+
|
44
|
+
return representation unless block_given?
|
45
|
+
|
46
|
+
Async do
|
47
|
+
begin
|
48
|
+
yield representation
|
49
|
+
ensure
|
50
|
+
representation.close
|
51
|
+
end
|
52
|
+
end
|
33
53
|
end
|
34
54
|
|
55
|
+
WRAPPER = Wrapper::JSON
|
56
|
+
|
35
57
|
# @param resource [Resource] the RESTful resource that this representation is of.
|
36
58
|
# @param metadata [Hash | HTTP::Headers] the metadata associated wtih teh representation.
|
37
59
|
# @param value [Object] the value of the representation.
|
38
60
|
# @param wrapper [#prepare_request, #process_response] the wrapper for encoding/decoding the request/response body.
|
39
|
-
def initialize(resource, metadata: {}, value: nil, wrapper:
|
61
|
+
def initialize(resource, metadata: {}, value: nil, wrapper: self.class::WRAPPER.new)
|
40
62
|
@resource = resource
|
41
63
|
@wrapper = wrapper
|
42
64
|
|
@@ -44,8 +66,12 @@ module Async
|
|
44
66
|
@value = value
|
45
67
|
end
|
46
68
|
|
47
|
-
def with(klass =
|
48
|
-
klass
|
69
|
+
def with(klass = nil, **options)
|
70
|
+
if klass
|
71
|
+
klass.new(@resource.with(**options), wrapper: klass::WRAPPER.new)
|
72
|
+
else
|
73
|
+
self.new(@resource.with(**options), wrapper: @wrapper)
|
74
|
+
end
|
49
75
|
end
|
50
76
|
|
51
77
|
def [] **parameters
|
@@ -63,6 +89,7 @@ module Async
|
|
63
89
|
@resource.prepare_request(verb, payload, &@wrapper.method(:prepare_request))
|
64
90
|
end
|
65
91
|
|
92
|
+
# If an exception propagates out of this method, the response will be closed.
|
66
93
|
def process_response(request, response)
|
67
94
|
@wrapper.process_response(request, response)
|
68
95
|
end
|
@@ -75,7 +102,14 @@ module Async
|
|
75
102
|
|
76
103
|
response = @resource.call(request)
|
77
104
|
|
78
|
-
|
105
|
+
# If we exit this block because of an exception, we close the response. This ensures we don't have any dangling connections.
|
106
|
+
begin
|
107
|
+
return process_response(request, response)
|
108
|
+
rescue
|
109
|
+
response.close
|
110
|
+
|
111
|
+
raise
|
112
|
+
end
|
79
113
|
end
|
80
114
|
end
|
81
115
|
|
@@ -88,7 +122,7 @@ module Async
|
|
88
122
|
@metadata = response.headers
|
89
123
|
@value = response.read
|
90
124
|
else
|
91
|
-
|
125
|
+
raise ResponseError, response
|
92
126
|
end
|
93
127
|
end
|
94
128
|
|
data/lib/async/rest/resource.rb
CHANGED
@@ -39,13 +39,14 @@ module Async
|
|
39
39
|
@headers = headers
|
40
40
|
end
|
41
41
|
|
42
|
+
# @param endpoint [Async::HTTP::Endpoint] used to connect to the remote system and specify the base path.
|
42
43
|
def self.connect(endpoint)
|
43
44
|
reference = ::Protocol::HTTP::Reference.parse(endpoint.path)
|
44
45
|
|
45
46
|
return ::Protocol::HTTP::AcceptEncoding.new(HTTP::Client.new(endpoint)), reference
|
46
47
|
end
|
47
48
|
|
48
|
-
def self.for(endpoint, *
|
49
|
+
def self.for(endpoint, *arguments)
|
49
50
|
# TODO This behaviour is deprecated and will probably be removed.
|
50
51
|
if endpoint.is_a? String
|
51
52
|
endpoint = HTTP::Endpoint.parse(endpoint)
|
@@ -53,11 +54,11 @@ module Async
|
|
53
54
|
|
54
55
|
client, reference = connect(endpoint)
|
55
56
|
|
56
|
-
resource = self.new(client, reference, *
|
57
|
+
resource = self.new(client, reference, *arguments)
|
57
58
|
|
58
59
|
return resource unless block_given?
|
59
60
|
|
60
|
-
Async
|
61
|
+
Async do
|
61
62
|
begin
|
62
63
|
yield resource
|
63
64
|
ensure
|
@@ -69,14 +70,14 @@ module Async
|
|
69
70
|
attr :reference
|
70
71
|
attr :headers
|
71
72
|
|
72
|
-
def self.with(parent, *
|
73
|
+
def self.with(parent, *arguments, headers: {}, **options)
|
73
74
|
reference = parent.reference.with(**options)
|
74
75
|
|
75
|
-
self.new(*
|
76
|
+
self.new(*arguments, parent.delegate, reference, parent.headers.merge(headers))
|
76
77
|
end
|
77
78
|
|
78
|
-
def with(*
|
79
|
-
self.class.with(self, *
|
79
|
+
def with(*arguments, **options)
|
80
|
+
self.class.with(self, *arguments, **options)
|
80
81
|
end
|
81
82
|
|
82
83
|
def get(klass = Representation, **parameters)
|
data/lib/async/rest/version.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -20,6 +22,6 @@
|
|
20
22
|
|
21
23
|
module Async
|
22
24
|
module REST
|
23
|
-
VERSION = "0.
|
25
|
+
VERSION = "0.12.3"
|
24
26
|
end
|
25
27
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
10
|
+
# furnished to do so, subject to the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be included in
|
13
|
+
# all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
# THE SOFTWARE.
|
22
|
+
|
23
|
+
require_relative 'json'
|
24
|
+
require_relative 'url_encoded'
|
25
|
+
|
26
|
+
module Async
|
27
|
+
module REST
|
28
|
+
module Wrapper
|
29
|
+
class Form < Generic
|
30
|
+
DEFAULT_CONTENT_TYPES = {
|
31
|
+
JSON::APPLICATION_JSON => JSON::Parser,
|
32
|
+
URLEncoded::APPLICATION_FORM_URLENCODED => URLEncoded::Parser,
|
33
|
+
}
|
34
|
+
|
35
|
+
def initialize(content_types = DEFAULT_CONTENT_TYPES)
|
36
|
+
@content_types = content_types
|
37
|
+
end
|
38
|
+
|
39
|
+
def prepare_request(payload, headers)
|
40
|
+
@content_types.each_key do |key|
|
41
|
+
headers.add('accept', key)
|
42
|
+
end
|
43
|
+
|
44
|
+
if payload
|
45
|
+
headers['content-type'] = URLEncoded::APPLICATION_FORM_URLENCODED
|
46
|
+
|
47
|
+
::Protocol::HTTP::Body::Buffered.new([
|
48
|
+
::Protocol::HTTP::URL.encode(payload)
|
49
|
+
])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def parser_for(response)
|
54
|
+
if content_type = response.headers['content-type']
|
55
|
+
if parser = @content_types[content_type]
|
56
|
+
return parser
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
return super
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -32,8 +34,28 @@ module Async
|
|
32
34
|
# @param response [Protocol::HTTP::Response] the response that was received.
|
33
35
|
# @return [Object] some application specific representation of the response.
|
34
36
|
def process_response(request, response)
|
37
|
+
wrap_response(response)
|
38
|
+
end
|
39
|
+
|
40
|
+
def parser_for(response)
|
41
|
+
# It's not always clear why this error is being thrown.
|
42
|
+
return Unsupported
|
43
|
+
end
|
44
|
+
|
45
|
+
# Wrap the response body in the given klass.
|
46
|
+
def wrap_response(response)
|
47
|
+
if body = response.body
|
48
|
+
response.body = parser_for(response).new(body)
|
49
|
+
end
|
50
|
+
|
35
51
|
return response
|
36
52
|
end
|
53
|
+
|
54
|
+
class Unsupported < HTTP::Body::Wrapper
|
55
|
+
def join
|
56
|
+
raise UnsupportedError, super
|
57
|
+
end
|
58
|
+
end
|
37
59
|
end
|
38
60
|
end
|
39
61
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -38,7 +40,7 @@ module Async
|
|
38
40
|
|
39
41
|
attr :content_type
|
40
42
|
|
41
|
-
def split(*
|
43
|
+
def split(*arguments)
|
42
44
|
@content_type.split
|
43
45
|
end
|
44
46
|
|
@@ -48,7 +50,6 @@ module Async
|
|
48
50
|
if payload
|
49
51
|
headers['content-type'] = @content_type
|
50
52
|
|
51
|
-
# TODO dump incrementally to IO?
|
52
53
|
HTTP::Body::Buffered.new([
|
53
54
|
::JSON.dump(payload)
|
54
55
|
])
|
@@ -61,22 +62,14 @@ module Async
|
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
|
-
def
|
65
|
-
if body = response.body
|
66
|
-
response.body = Parser.new(body)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def process_response(request, response)
|
65
|
+
def parser_for(response)
|
71
66
|
if content_type = response.headers['content-type']
|
72
67
|
if content_type.start_with? @content_type
|
73
|
-
|
74
|
-
else
|
75
|
-
raise Error, "Unknown content type: #{content_type}!"
|
68
|
+
return Parser
|
76
69
|
end
|
77
70
|
end
|
78
71
|
|
79
|
-
return
|
72
|
+
return super
|
80
73
|
end
|
81
74
|
end
|
82
75
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Copyright, 2018, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
4
|
#
|
3
5
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -37,7 +39,7 @@ module Async
|
|
37
39
|
|
38
40
|
attr :content_type
|
39
41
|
|
40
|
-
def split(*
|
42
|
+
def split(*arguments)
|
41
43
|
@content_type.split
|
42
44
|
end
|
43
45
|
|
@@ -59,22 +61,14 @@ module Async
|
|
59
61
|
end
|
60
62
|
end
|
61
63
|
|
62
|
-
def
|
63
|
-
if body = response.body
|
64
|
-
response.body = Parser.new(body)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def process_response(request, response)
|
64
|
+
def parser_for(response)
|
69
65
|
if content_type = response.headers['content-type']
|
70
66
|
if content_type.start_with? @content_type
|
71
|
-
|
72
|
-
else
|
73
|
-
raise Error, "Unknown content type: #{content_type}!"
|
67
|
+
return Parser
|
74
68
|
end
|
75
69
|
end
|
76
70
|
|
77
|
-
return
|
71
|
+
return super
|
78
72
|
end
|
79
73
|
end
|
80
74
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-rest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: async-http
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: covered
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
@@ -81,61 +81,53 @@ dependencies:
|
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: rake
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rspec
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '3.6'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '
|
111
|
-
description:
|
110
|
+
version: '3.6'
|
111
|
+
description:
|
112
112
|
email:
|
113
|
-
- samuel.williams@oriontransfer.co.nz
|
114
113
|
executables: []
|
115
114
|
extensions: []
|
116
115
|
extra_rdoc_files: []
|
117
116
|
files:
|
118
|
-
- ".editorconfig"
|
119
|
-
- ".gitignore"
|
120
|
-
- ".rspec"
|
121
|
-
- ".travis.yml"
|
122
|
-
- Gemfile
|
123
|
-
- README.md
|
124
|
-
- Rakefile
|
125
|
-
- async-rest.gemspec
|
126
|
-
- examples/slack/clean.rb
|
127
117
|
- lib/async/rest.rb
|
128
118
|
- lib/async/rest/error.rb
|
129
119
|
- lib/async/rest/representation.rb
|
130
120
|
- lib/async/rest/resource.rb
|
131
121
|
- lib/async/rest/version.rb
|
122
|
+
- lib/async/rest/wrapper/form.rb
|
132
123
|
- lib/async/rest/wrapper/generic.rb
|
133
124
|
- lib/async/rest/wrapper/json.rb
|
134
125
|
- lib/async/rest/wrapper/url_encoded.rb
|
135
126
|
homepage: https://github.com/socketry/async-rest
|
136
|
-
licenses:
|
127
|
+
licenses:
|
128
|
+
- MIT
|
137
129
|
metadata: {}
|
138
|
-
post_install_message:
|
130
|
+
post_install_message:
|
139
131
|
rdoc_options: []
|
140
132
|
require_paths:
|
141
133
|
- lib
|
@@ -150,8 +142,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
150
142
|
- !ruby/object:Gem::Version
|
151
143
|
version: '0'
|
152
144
|
requirements: []
|
153
|
-
rubygems_version: 3.0.
|
154
|
-
signing_key:
|
145
|
+
rubygems_version: 3.3.0.dev
|
146
|
+
signing_key:
|
155
147
|
specification_version: 4
|
156
148
|
summary: A library for RESTful clients (and hopefully servers).
|
157
149
|
test_files: []
|
data/.editorconfig
DELETED
data/.gitignore
DELETED
data/.rspec
DELETED
data/.travis.yml
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
dist: xenial
|
3
|
-
cache: bundler
|
4
|
-
|
5
|
-
matrix:
|
6
|
-
include:
|
7
|
-
- rvm: 2.4
|
8
|
-
- rvm: 2.5
|
9
|
-
- rvm: 2.6
|
10
|
-
- rvm: jruby-head
|
11
|
-
env: JRUBY_OPTS="--debug -X+O"
|
12
|
-
- rvm: truffleruby
|
13
|
-
- rvm: ruby-head
|
14
|
-
- rvm: rbx-3
|
15
|
-
allow_failures:
|
16
|
-
- rvm: ruby-head
|
17
|
-
- rvm: jruby-head
|
18
|
-
- rvm: rbx-3
|
19
|
-
- rvm: truffleruby
|
data/Gemfile
DELETED
data/README.md
DELETED
@@ -1,106 +0,0 @@
|
|
1
|
-
# Async::REST
|
2
|
-
|
3
|
-
Roy Thomas Fielding's thesis [Architectural Styles and the Design of Network-based Software Architectures](https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm) describes [Representational State Transfer](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm) which comprises several core concepts:
|
4
|
-
|
5
|
-
- `Resource`: A conceptual mapping to one or more entities.
|
6
|
-
- `Representation`: An instance of a resource at a given point in time.
|
7
|
-
|
8
|
-
This gem models these abstractions as closely and practically as possible and serves as a basis for building asynchronous web clients.
|
9
|
-
|
10
|
-
[![Build Status](https://secure.travis-ci.org/socketry/async-rest.svg)](http://travis-ci.org/socketry/async-rest)
|
11
|
-
[![Code Climate](https://codeclimate.com/github/socketry/async-rest.svg)](https://codeclimate.com/github/socketry/async-rest)
|
12
|
-
[![Coverage Status](https://coveralls.io/repos/socketry/async-rest/badge.svg)](https://coveralls.io/r/socketry/async-rest)
|
13
|
-
|
14
|
-
[async]: https://github.com/socketry/async
|
15
|
-
[async-io]: https://github.com/socketry/async-io
|
16
|
-
[falcon]: https://github.com/socketry/falcon
|
17
|
-
|
18
|
-
## Installation
|
19
|
-
|
20
|
-
Add this line to your application's Gemfile:
|
21
|
-
|
22
|
-
```ruby
|
23
|
-
gem 'async-rest'
|
24
|
-
```
|
25
|
-
|
26
|
-
And then execute:
|
27
|
-
|
28
|
-
$ bundle
|
29
|
-
|
30
|
-
Or install it yourself as:
|
31
|
-
|
32
|
-
$ gem install async-rest
|
33
|
-
|
34
|
-
## Usage
|
35
|
-
|
36
|
-
Generally speaking, you want to create a representation class for each endpoint. This class is responsible for negotiating content type and processing the response, and traversing related endpoints.
|
37
|
-
|
38
|
-
### DNS over HTTP
|
39
|
-
|
40
|
-
This simple example shows how to use a custom representation to access DNS over HTTP.
|
41
|
-
|
42
|
-
```ruby
|
43
|
-
require 'async/http/server'
|
44
|
-
require 'async/http/endpoint'
|
45
|
-
|
46
|
-
require 'async/rest/resource'
|
47
|
-
require 'async/rest/representation'
|
48
|
-
|
49
|
-
module DNS
|
50
|
-
class Query < Async::REST::Representation
|
51
|
-
def initialize(*args)
|
52
|
-
# This is the old/weird content-type used by Google's DNS resolver. It's obsolete.
|
53
|
-
super(*args, wrapper: Async::REST::Wrapper::JSON.new("application/x-javascript"))
|
54
|
-
end
|
55
|
-
|
56
|
-
def question
|
57
|
-
value[:Question]
|
58
|
-
end
|
59
|
-
|
60
|
-
def answer
|
61
|
-
value[:Answer]
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
URL = 'https://dns.google.com/resolve'
|
67
|
-
Async::REST::Resource.for(URL) do |resource|
|
68
|
-
# Specify the representation class as the first argument (client side negotiation):
|
69
|
-
query = resource.get(DNS::Query, name: 'example.com', type: 'AAAA')
|
70
|
-
|
71
|
-
pp query.metadata
|
72
|
-
pp query.value
|
73
|
-
end
|
74
|
-
```
|
75
|
-
|
76
|
-
## Contributing
|
77
|
-
|
78
|
-
1. Fork it
|
79
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
80
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
81
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
82
|
-
5. Create new Pull Request
|
83
|
-
|
84
|
-
## License
|
85
|
-
|
86
|
-
Released under the MIT license.
|
87
|
-
|
88
|
-
Copyright, 2015, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
89
|
-
|
90
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
91
|
-
of this software and associated documentation files (the "Software"), to deal
|
92
|
-
in the Software without restriction, including without limitation the rights
|
93
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
94
|
-
copies of the Software, and to permit persons to whom the Software is
|
95
|
-
furnished to do so, subject to the following conditions:
|
96
|
-
|
97
|
-
The above copyright notice and this permission notice shall be included in
|
98
|
-
all copies or substantial portions of the Software.
|
99
|
-
|
100
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
101
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
102
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
103
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
104
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
105
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
106
|
-
THE SOFTWARE.
|
data/Rakefile
DELETED
data/async-rest.gemspec
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
require_relative 'lib/async/rest/version'
|
3
|
-
|
4
|
-
Gem::Specification.new do |spec|
|
5
|
-
spec.name = "async-rest"
|
6
|
-
spec.version = Async::REST::VERSION
|
7
|
-
spec.authors = ["Samuel Williams"]
|
8
|
-
spec.email = ["samuel.williams@oriontransfer.co.nz"]
|
9
|
-
|
10
|
-
spec.summary = "A library for RESTful clients (and hopefully servers)."
|
11
|
-
spec.homepage = "https://github.com/socketry/async-rest"
|
12
|
-
|
13
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
14
|
-
f.match(%r{^(test|spec|features)/})
|
15
|
-
end
|
16
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
-
spec.require_paths = ["lib"]
|
18
|
-
|
19
|
-
spec.add_dependency "async-http", "~> 0.42"
|
20
|
-
spec.add_dependency "protocol-http", "~> 0.7"
|
21
|
-
|
22
|
-
spec.add_development_dependency "async-rspec", "~> 1.1"
|
23
|
-
|
24
|
-
spec.add_development_dependency "covered"
|
25
|
-
spec.add_development_dependency "bundler"
|
26
|
-
spec.add_development_dependency "rspec", "~> 3.6"
|
27
|
-
spec.add_development_dependency "rake"
|
28
|
-
end
|
data/examples/slack/clean.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'pry'
|
4
|
-
require 'set'
|
5
|
-
|
6
|
-
def rate_limited?(response)
|
7
|
-
pp response
|
8
|
-
|
9
|
-
response[:error] == "ratelimited"
|
10
|
-
end
|
11
|
-
|
12
|
-
require 'async/rest'
|
13
|
-
|
14
|
-
URL = "https://slack.com/api"
|
15
|
-
TOKEN = "xoxp-your-api-token"
|
16
|
-
|
17
|
-
Async::REST::Resource.for(URL) do |resource|
|
18
|
-
authenticated = resource.with(parameters: {token: TOKEN})
|
19
|
-
delete = authenticated.with(path: "chat.delete")
|
20
|
-
|
21
|
-
page = 1
|
22
|
-
while true
|
23
|
-
search = authenticated.with(path: "search.messages", parameters: {page: page, count: 100, query: "from:@username before:2019-02-15"})
|
24
|
-
representation = search.get
|
25
|
-
|
26
|
-
messages = representation.value[:messages]
|
27
|
-
matches = messages[:matches]
|
28
|
-
|
29
|
-
puts "Found #{matches.size} messages on page #{page} out of #{messages[:total]}..."
|
30
|
-
|
31
|
-
break if matches.empty?
|
32
|
-
|
33
|
-
matches.each do |message|
|
34
|
-
text = message[:text]
|
35
|
-
channel_id = message[:channel][:id]
|
36
|
-
channel_name = message[:channel][:name]
|
37
|
-
timestamp = message[:ts]
|
38
|
-
|
39
|
-
pp [timestamp, channel_name, text]
|
40
|
-
|
41
|
-
message_delete = Async::REST::Representation.new(
|
42
|
-
delete.with(parameters: {channel: channel_id, ts: timestamp})
|
43
|
-
)
|
44
|
-
|
45
|
-
response = message_delete.post
|
46
|
-
if rate_limited?(response.read)
|
47
|
-
puts "Rate limiting..."
|
48
|
-
Async::Task.current.sleep 10
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
page += 1
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
puts "Done"
|