http_magic 0.1.1
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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +45 -0
- data/LICENSE +20 -0
- data/README.md +2 -0
- data/Rakefile +8 -0
- data/http_magic.gemspec +23 -0
- data/lib/http_magic.rb +4 -0
- data/lib/http_magic/api.rb +218 -0
- data/lib/http_magic/request.rb +82 -0
- data/lib/http_magic/uri.rb +74 -0
- data/test/api/get_test.rb +68 -0
- data/test/api/post_test.rb +34 -0
- data/test/fixtures/projects.json +66 -0
- data/test/request_test.rb +63 -0
- data/test/test_helper.rb +18 -0
- data/test/uri_test.rb +49 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ae2f80540b2ebc639265dd8a2b4afffa39b72f27
|
4
|
+
data.tar.gz: 38ed7512bca5927a8961ce9279e85b61521902ad
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0b9c6a898d4172ef774bc79e46a8b714d137270a0022bb3cf09f97d68b6b02e180d151b4d736bd9884b9e010cf8755b9e39c054a9ac95d82584b4f6b1fe4ae84
|
7
|
+
data.tar.gz: 53da0b3b6cdf245d2afcaefd1e0f8c3ab3a4e6522d3e344a1585cf14364a55c774d7ee4492e861bf4f4bb4c62d34b3a8c1d7dae6cc235e80ef2750329b3e9a99
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
http_magic (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
addressable (2.3.5)
|
10
|
+
coderay (1.1.0)
|
11
|
+
columnize (0.3.6)
|
12
|
+
crack (0.4.1)
|
13
|
+
safe_yaml (~> 0.9.0)
|
14
|
+
debugger (1.6.5)
|
15
|
+
columnize (>= 0.3.1)
|
16
|
+
debugger-linecache (~> 1.2.0)
|
17
|
+
debugger-ruby_core_source (~> 1.3.1)
|
18
|
+
debugger-linecache (1.2.0)
|
19
|
+
debugger-ruby_core_source (1.3.1)
|
20
|
+
method_source (0.8.2)
|
21
|
+
minitest (4.7.5)
|
22
|
+
pry (0.9.12.4)
|
23
|
+
coderay (~> 1.0)
|
24
|
+
method_source (~> 0.8)
|
25
|
+
slop (~> 3.4)
|
26
|
+
pry-debugger (0.2.2)
|
27
|
+
debugger (~> 1.3)
|
28
|
+
pry (~> 0.9.10)
|
29
|
+
rake (10.1.1)
|
30
|
+
safe_yaml (0.9.7)
|
31
|
+
slop (3.4.7)
|
32
|
+
webmock (1.16.1)
|
33
|
+
addressable (>= 2.2.7)
|
34
|
+
crack (>= 0.3.2)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
http_magic!
|
41
|
+
minitest (~> 4.7.0)
|
42
|
+
pry
|
43
|
+
pry-debugger
|
44
|
+
rake
|
45
|
+
webmock (~> 1.16.0)
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 GradesFirst
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
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, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
data/http_magic.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.name = 'http_magic'
|
4
|
+
s.version = '0.1.1'
|
5
|
+
s.licenses = ['MIT']
|
6
|
+
s.summary = 'Provides a more Object Oriented interface to RESTful apis.'
|
7
|
+
|
8
|
+
s.author = 'GradesFirst'
|
9
|
+
s.email = 'tech@gradesfirst.com'
|
10
|
+
s.homepage = 'https://github.com/Thoughtwright-LLC/httpmagic'
|
11
|
+
|
12
|
+
s.files = Dir['{lib}/**/*.rb', 'bin/*', 'LICENSE', '*.md']
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
15
|
+
|
16
|
+
s.require_paths = ['lib']
|
17
|
+
|
18
|
+
s.add_development_dependency 'rake', '~> 0'
|
19
|
+
s.add_development_dependency 'minitest', '~> 4.7'
|
20
|
+
s.add_development_dependency 'webmock', '~> 1.16'
|
21
|
+
s.add_development_dependency 'pry', '~> 0'
|
22
|
+
s.add_development_dependency 'pry-debugger', '~> 0'
|
23
|
+
end
|
data/lib/http_magic.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'http_magic/uri'
|
3
|
+
require 'http_magic/request'
|
4
|
+
|
5
|
+
module HttpMagic
|
6
|
+
# A magical class that interacts with HTTP resources with a minimal amount of
|
7
|
+
# configuration.
|
8
|
+
#
|
9
|
+
# Assuming an api where the url http://www.example.com/api/v1/foo/99 responds
|
10
|
+
# with the following.
|
11
|
+
#
|
12
|
+
# Header:
|
13
|
+
#
|
14
|
+
# Content-Type: application/json
|
15
|
+
#
|
16
|
+
# Body:
|
17
|
+
#
|
18
|
+
# {
|
19
|
+
# "name": "Foo Bar"
|
20
|
+
# }
|
21
|
+
#
|
22
|
+
# == Example
|
23
|
+
#
|
24
|
+
# class ExampleApi < HttpMagic::Api
|
25
|
+
# url 'www.example.com'
|
26
|
+
# namespace 'api/v1'
|
27
|
+
# headers({'X-AuthToken' => 'token'})
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# ExampleApi.foo[99].get['name']
|
31
|
+
# => "Foo Bar"
|
32
|
+
#
|
33
|
+
# ExampleApi.foo.create.post(name: 'New Foo')
|
34
|
+
# => { 'name' => 'New Foo' }
|
35
|
+
class Api < BasicObject
|
36
|
+
# Makes the new method private so that instances of this class and it's
|
37
|
+
# children can only be instantiated through the class method method_missing.
|
38
|
+
# This is needed to enforce the intended usage of HttpMagic where the class
|
39
|
+
# is configured to represent an http location. Once it is configured, the
|
40
|
+
# location is interacted with dynamically with chained methods that correspond
|
41
|
+
# with parts of URNs found at the location.
|
42
|
+
class << self
|
43
|
+
private :new
|
44
|
+
end
|
45
|
+
|
46
|
+
# Sets or returns the request headers for an HttpMagic based class. The
|
47
|
+
# headers will be passed along to each resource request being made.
|
48
|
+
#
|
49
|
+
# == Example
|
50
|
+
#
|
51
|
+
# class ExampleApi < HttpMagic:Api
|
52
|
+
# url 'www.example.com'
|
53
|
+
# headers({'X-AuthToken' => 'token'})
|
54
|
+
# end
|
55
|
+
def self.headers(value = :not_provided)
|
56
|
+
unless value == :not_provided
|
57
|
+
@headers = value
|
58
|
+
end
|
59
|
+
@headers
|
60
|
+
end
|
61
|
+
|
62
|
+
# Sets or returns the namespace for an HttpMagic based class. The namespace
|
63
|
+
# will be prefixed to the urn for each request made to the url.
|
64
|
+
#
|
65
|
+
# Assuming an api where each resource is namespaced with 'api/v1' and where
|
66
|
+
# the url http://www.example.com/api/v1/foo/99 responds with the following.
|
67
|
+
#
|
68
|
+
# Header:
|
69
|
+
#
|
70
|
+
# Content-Type: application/json
|
71
|
+
#
|
72
|
+
# Body:
|
73
|
+
#
|
74
|
+
# {
|
75
|
+
# "name": "Foo Bar"
|
76
|
+
# }
|
77
|
+
#
|
78
|
+
# == Example
|
79
|
+
#
|
80
|
+
# class ExampleApi < HttpMagic:Api
|
81
|
+
# url 'www.example.com'
|
82
|
+
# namespace 'api/v1'
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# ExampleApi.foo[99].get['name']
|
86
|
+
# => "Foo Bar"
|
87
|
+
#
|
88
|
+
def self.namespace(value = :not_provided)
|
89
|
+
unless value == :not_provided
|
90
|
+
@namespace = value
|
91
|
+
end
|
92
|
+
@namespace
|
93
|
+
end
|
94
|
+
|
95
|
+
# Sets or returns the uniform resource locator for the HTTP resource.
|
96
|
+
#
|
97
|
+
# == Example
|
98
|
+
#
|
99
|
+
# class ExampleApi < HttpMagic::Api
|
100
|
+
# url 'www.example.com'
|
101
|
+
# end
|
102
|
+
def self.url(value = :not_provided)
|
103
|
+
unless value == :not_provided
|
104
|
+
@url = value
|
105
|
+
end
|
106
|
+
@url
|
107
|
+
end
|
108
|
+
|
109
|
+
# Class scoped method_missing that starts the magic of creating urns
|
110
|
+
# through meta programming by instantiating an instance of the class
|
111
|
+
# and delegating the first part of the urn to that instance. This method
|
112
|
+
# is an implementation of the Factory Method design pattern.
|
113
|
+
def self.method_missing(name, *args, &block)
|
114
|
+
new(@url, @namespace, @headers).__send__(name, *args)
|
115
|
+
end
|
116
|
+
|
117
|
+
def initialize(url, namespace, headers)
|
118
|
+
@uri = Uri.new(url)
|
119
|
+
@uri.namespace = namespace
|
120
|
+
@headers = headers
|
121
|
+
end
|
122
|
+
|
123
|
+
# Resource index reference intended to allow for the use of numbers in a urn
|
124
|
+
# such as the following 'foo/99' being referenced by ExampleApi.foo[99]. It
|
125
|
+
# can also be used to allow for HttpMagic methods to be specified for a urn
|
126
|
+
# such as 'foo/get' being referenced by ExampleApi.foo[:get]. Finally, it can
|
127
|
+
# be used for urn parts that are not valid Ruby methods such as 'foo/%5B%5D'
|
128
|
+
# being referenced by ExampleApi.foo["%5B%5D"].
|
129
|
+
#
|
130
|
+
# * part - a part of a urn such that 'foo' and 'bar' would be parts of the urn
|
131
|
+
# 'foo/bar'.
|
132
|
+
#
|
133
|
+
# Returns a reference to its instance so that urn parts can be chained
|
134
|
+
# together.
|
135
|
+
def [](part)
|
136
|
+
@uri.parts << part.to_s
|
137
|
+
self
|
138
|
+
end
|
139
|
+
|
140
|
+
# Gets a resource from the URI and returns it based on its content type.
|
141
|
+
# JSON content will be parsed and returned as equivalent Ruby objects. All
|
142
|
+
# other content types will be returned as text.
|
143
|
+
#
|
144
|
+
# Assuming an api where each resource is namespaced with 'api/v1' and where
|
145
|
+
# the url http://www.example.com/api/v1/foo/99 responds with the following.
|
146
|
+
#
|
147
|
+
# Header:
|
148
|
+
#
|
149
|
+
# Content-Type: application/json
|
150
|
+
#
|
151
|
+
# Body:
|
152
|
+
#
|
153
|
+
# {
|
154
|
+
# "name": "Foo Bar"
|
155
|
+
# }
|
156
|
+
#
|
157
|
+
# == Example
|
158
|
+
#
|
159
|
+
# class ExampleApi < HttpMagic::Api
|
160
|
+
# url 'www.example.com'
|
161
|
+
# namespace 'api/v1'
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# ExampleApi.foo[99].get
|
165
|
+
# => { "name" => "Foo Bar" }
|
166
|
+
def get
|
167
|
+
request = Request.new(@uri,
|
168
|
+
headers: @headers
|
169
|
+
)
|
170
|
+
request.get
|
171
|
+
end
|
172
|
+
|
173
|
+
# POST's a resource from the URI and returns the result based on its content
|
174
|
+
# type. JSON content will be parsed and returned as equivalent Ruby objects.
|
175
|
+
# All other content types will be returned as text.
|
176
|
+
#
|
177
|
+
# Assuming an api where each resource is namespaced with 'api/v1' and where
|
178
|
+
# the url http://www.example.com/api/v1/foo/create responds with the
|
179
|
+
# following when a 'name' is sent with the request.
|
180
|
+
#
|
181
|
+
# Header:
|
182
|
+
#
|
183
|
+
# Content-Type: application/json
|
184
|
+
#
|
185
|
+
# Body:
|
186
|
+
#
|
187
|
+
# {
|
188
|
+
# "name": "New Foo"
|
189
|
+
# }
|
190
|
+
#
|
191
|
+
# == Example
|
192
|
+
#
|
193
|
+
# class ExampleApi < HttpMagic::Api
|
194
|
+
# url 'www.example.com'
|
195
|
+
# namespace 'api/v1'
|
196
|
+
# end
|
197
|
+
#
|
198
|
+
# ExampleApi.foo.create.post(name: 'New Foo')
|
199
|
+
# => { "name" => "New Foo" }
|
200
|
+
def post(data = {})
|
201
|
+
request = Request.new(@uri,
|
202
|
+
headers: @headers,
|
203
|
+
data: data,
|
204
|
+
)
|
205
|
+
request.post
|
206
|
+
end
|
207
|
+
|
208
|
+
# Instance scoped method_missing that accumulates the URN parts used in
|
209
|
+
# forming the URI. It returns a reference to the current instance so that
|
210
|
+
# method and [] based parts can be chained together to from the URN. In the
|
211
|
+
# case of ExampleApi.foo[99] the 'foo' method is accumlated as a URN part
|
212
|
+
# that will form the resulting URI.
|
213
|
+
def method_missing(part, *args, &block)
|
214
|
+
@uri.parts << part.to_s
|
215
|
+
self
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module HttpMagic
|
5
|
+
# Encapsulating class to hold all of the infrastructure to make the actual
|
6
|
+
# requests to the api. It receives at a minimum a HttpMagic::Uri object which
|
7
|
+
# manages the url building.
|
8
|
+
#
|
9
|
+
# == Example
|
10
|
+
#
|
11
|
+
# uri_object = HttpMagic::Uri.new('http://example.com')
|
12
|
+
#
|
13
|
+
# request = Request.new(uri_object)
|
14
|
+
#
|
15
|
+
# request.get
|
16
|
+
# => { 'name' => 'Foo Bar' }
|
17
|
+
class Request
|
18
|
+
def initialize(uri, options = {})
|
19
|
+
@uri = uri
|
20
|
+
@data = options[:data] || {}
|
21
|
+
@options = {
|
22
|
+
headers: options[:headers] || {}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
# Makes a GET request to the url provided by the Uri object and returns the
|
27
|
+
# resulting JSON data as a Ruby hash.
|
28
|
+
#
|
29
|
+
# == Example
|
30
|
+
#
|
31
|
+
# uri_object = HttpMagic::Uri.new('http://example.com')
|
32
|
+
#
|
33
|
+
# request = Request.new(uri_object)
|
34
|
+
#
|
35
|
+
# request.get
|
36
|
+
# => { 'name' => 'Foo Bar' }
|
37
|
+
def get
|
38
|
+
send_request :get
|
39
|
+
end
|
40
|
+
|
41
|
+
# Makes a POST request to the url provided by the Uri object and returns the
|
42
|
+
# resulting JSON data as a Ruby hash. If data was provided as an optional
|
43
|
+
# initialization parameter, then that is also POSTed.
|
44
|
+
#
|
45
|
+
# == Example
|
46
|
+
#
|
47
|
+
# uri_object = HttpMagic::Uri.new('http://example.com')
|
48
|
+
#
|
49
|
+
# request = Request.new(uri_object, data: { name: 'New Foo' })
|
50
|
+
#
|
51
|
+
# request.post
|
52
|
+
def post
|
53
|
+
if !@data.empty?
|
54
|
+
@options[:headers].merge!( 'content-type' => 'application/json' )
|
55
|
+
end
|
56
|
+
|
57
|
+
send_request :post
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def http
|
63
|
+
return @http unless @http.nil?
|
64
|
+
@http = Net::HTTP.new(@uri.domain, 443)
|
65
|
+
@http.use_ssl = true
|
66
|
+
@http
|
67
|
+
end
|
68
|
+
|
69
|
+
def send_request(method)
|
70
|
+
response = http.send_request(method, @uri.urn, @data.to_json, @options[:headers])
|
71
|
+
if response && response.is_a?(Net::HTTPSuccess)
|
72
|
+
if response.content_type == 'application/json'
|
73
|
+
JSON.parse(response.body)
|
74
|
+
else
|
75
|
+
response.body
|
76
|
+
end
|
77
|
+
else
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
|
2
|
+
module HttpMagic
|
3
|
+
# Helper class that holds the parts of the URI and provides methods to put
|
4
|
+
# them together.
|
5
|
+
#
|
6
|
+
# == Example
|
7
|
+
#
|
8
|
+
# uri = HttpMagic::Uri.new('example.com')
|
9
|
+
# uri.build
|
10
|
+
# => "https://example.com/"
|
11
|
+
#
|
12
|
+
# uri.namespace = 'api/v2'
|
13
|
+
# uri.build
|
14
|
+
# => "https://example.com/api/v2"
|
15
|
+
#
|
16
|
+
# uri.parts = ['path']
|
17
|
+
# uri.build
|
18
|
+
# => "https://example.com/api/v2/path"
|
19
|
+
#
|
20
|
+
class Uri
|
21
|
+
attr_accessor :namespace, :parts
|
22
|
+
|
23
|
+
attr_reader :domain
|
24
|
+
|
25
|
+
def initialize(domain)
|
26
|
+
@domain = domain
|
27
|
+
@parts = []
|
28
|
+
end
|
29
|
+
|
30
|
+
# Builds a full uniform resource identifier.
|
31
|
+
#
|
32
|
+
# == Example
|
33
|
+
#
|
34
|
+
# uri = HttpMagic::Uri.new('example.com')
|
35
|
+
# uri.namespace = 'api/v1'
|
36
|
+
# uri.parts = %w(foo bar)
|
37
|
+
#
|
38
|
+
# uri.urn
|
39
|
+
# => "https://example.com/api/v1/foo/bar"
|
40
|
+
def build
|
41
|
+
"#{url}#{urn}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Uniform resource locator based on @domain value.
|
45
|
+
#
|
46
|
+
# == Example
|
47
|
+
#
|
48
|
+
# uri = HttpMagic::Uri.new('example.com')
|
49
|
+
#
|
50
|
+
# uri.url
|
51
|
+
# => "https://example.com/"
|
52
|
+
#
|
53
|
+
# uri.url(false)
|
54
|
+
# => "https://example.com"
|
55
|
+
def url
|
56
|
+
"https://#{@domain}"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Uniform resource name for a resource.
|
60
|
+
#
|
61
|
+
# == Example
|
62
|
+
#
|
63
|
+
# uri = HttpMagic::Uri.new('example.com')
|
64
|
+
# uri.namespace = 'api/v1'
|
65
|
+
# uri.parts = %w(foo bar)
|
66
|
+
#
|
67
|
+
# uri.urn
|
68
|
+
# => "/api/v1/foo/bar"
|
69
|
+
def urn
|
70
|
+
resource_name = [@namespace, @parts].flatten.compact.join('/')
|
71
|
+
"/#{resource_name}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'http_magic'
|
3
|
+
|
4
|
+
class HttpMagicTest < HttpMagic::Api
|
5
|
+
end
|
6
|
+
|
7
|
+
describe 'HttpMagic#get' do
|
8
|
+
before do
|
9
|
+
@url = HttpMagicTest.url 'www.example.com'
|
10
|
+
HttpMagicTest.namespace nil
|
11
|
+
HttpMagicTest.headers nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should return the root response' do
|
15
|
+
stub_request(:get, "https://#{@url}:443").
|
16
|
+
to_return(body: 'I am root!!')
|
17
|
+
|
18
|
+
assert_equal(
|
19
|
+
'I am root!!',
|
20
|
+
HttpMagicTest.get
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should return the named resource' do
|
25
|
+
stub_request(:get, "https://#{@url}:443/bar").
|
26
|
+
to_return(body: 'A bear walked into a bar...')
|
27
|
+
|
28
|
+
assert_equal(
|
29
|
+
'A bear walked into a bar...',
|
30
|
+
HttpMagicTest.bar.get
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should return the named resource' do
|
35
|
+
stub_request(:get, "https://#{@url}:443/bar/84").
|
36
|
+
to_return(body: 'Where Everybody Knows Your Name')
|
37
|
+
|
38
|
+
assert_equal(
|
39
|
+
'Where Everybody Knows Your Name',
|
40
|
+
HttpMagicTest.bar[84].get
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should serialize JSON objects' do
|
45
|
+
stub_request(:get, "https://#{@url}:443/bar/99").
|
46
|
+
to_return(
|
47
|
+
headers: { 'Content-Type' => 'application/json' },
|
48
|
+
body: fixture_file('projects.json')
|
49
|
+
)
|
50
|
+
|
51
|
+
assert_equal(
|
52
|
+
'GradesFirst',
|
53
|
+
HttpMagicTest.bar[99].get.first['name']
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should provide specified headers' do
|
58
|
+
stub_request(:get, "https://#{@url}:443/bar/84").
|
59
|
+
with(headers: { 'X-AuthToken' => 'test_token' }).
|
60
|
+
to_return(body: 'Where Everybody Knows Your Name')
|
61
|
+
|
62
|
+
HttpMagicTest.headers({ 'X-AuthToken' => 'test_token' })
|
63
|
+
assert_equal(
|
64
|
+
'Where Everybody Knows Your Name',
|
65
|
+
HttpMagicTest.bar[84].get
|
66
|
+
)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'http_magic'
|
3
|
+
|
4
|
+
class HttpMagicTest < HttpMagic::Api
|
5
|
+
end
|
6
|
+
|
7
|
+
describe 'HttpMagic#post' do
|
8
|
+
before do
|
9
|
+
@url = HttpMagicTest.url 'www.example.com'
|
10
|
+
HttpMagicTest.namespace nil
|
11
|
+
HttpMagicTest.headers nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should send POST request' do
|
15
|
+
stub_post = stub_request(:post, "https://#{@url}")
|
16
|
+
|
17
|
+
HttpMagicTest.post
|
18
|
+
assert_requested stub_post
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should send data with POST request' do
|
22
|
+
expected_data = {
|
23
|
+
apple: 'sauce',
|
24
|
+
banana: 'bread'
|
25
|
+
}
|
26
|
+
stub_post = stub_request(:post, "https://#{@url}/foo").with(
|
27
|
+
body: expected_data
|
28
|
+
)
|
29
|
+
|
30
|
+
HttpMagicTest.foo.post(expected_data)
|
31
|
+
|
32
|
+
assert_requested stub_post
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"atom_enabled": false,
|
4
|
+
"version": 91975,
|
5
|
+
"name": "GradesFirst",
|
6
|
+
"velocity_averaged_over": 3,
|
7
|
+
"kind": "project",
|
8
|
+
"created_at": "2009-03-13T21:43:45Z",
|
9
|
+
"has_google_domain": false,
|
10
|
+
"point_scale_is_custom": false,
|
11
|
+
"current_iteration_number": 123,
|
12
|
+
"start_date": "2012-11-12",
|
13
|
+
"number_of_done_iterations_to_show": 4,
|
14
|
+
"updated_at": "2013-11-21T05:39:11Z",
|
15
|
+
"enable_incoming_emails": true,
|
16
|
+
"initial_velocity": 10,
|
17
|
+
"enable_following": true,
|
18
|
+
"account_id": 277647,
|
19
|
+
"start_time": "2009-03-16T05:00:00Z",
|
20
|
+
"enable_tasks": true,
|
21
|
+
"enable_planned_mode": true,
|
22
|
+
"week_start_day": "Monday",
|
23
|
+
"iteration_length": 2,
|
24
|
+
"time_zone": {
|
25
|
+
"kind": "time_zone",
|
26
|
+
"olson_name": "America/Chicago",
|
27
|
+
"offset": "-06:00"
|
28
|
+
},
|
29
|
+
"id": 10688,
|
30
|
+
"bugs_and_chores_are_estimatable": true,
|
31
|
+
"public": false,
|
32
|
+
"point_scale": "0,1,2,3,5,8"
|
33
|
+
},
|
34
|
+
{
|
35
|
+
"atom_enabled": false,
|
36
|
+
"version": 91975,
|
37
|
+
"name": "Technical",
|
38
|
+
"velocity_averaged_over": 3,
|
39
|
+
"kind": "project",
|
40
|
+
"created_at": "2009-03-13T21:43:45Z",
|
41
|
+
"has_google_domain": false,
|
42
|
+
"point_scale_is_custom": false,
|
43
|
+
"current_iteration_number": 123,
|
44
|
+
"start_date": "2012-11-12",
|
45
|
+
"number_of_done_iterations_to_show": 4,
|
46
|
+
"updated_at": "2013-11-21T05:39:11Z",
|
47
|
+
"enable_incoming_emails": true,
|
48
|
+
"initial_velocity": 10,
|
49
|
+
"enable_following": true,
|
50
|
+
"account_id": 277647,
|
51
|
+
"start_time": "2009-03-16T05:00:00Z",
|
52
|
+
"enable_tasks": true,
|
53
|
+
"enable_planned_mode": true,
|
54
|
+
"week_start_day": "Monday",
|
55
|
+
"iteration_length": 2,
|
56
|
+
"time_zone": {
|
57
|
+
"kind": "time_zone",
|
58
|
+
"olson_name": "America/Chicago",
|
59
|
+
"offset": "-06:00"
|
60
|
+
},
|
61
|
+
"id": 10687,
|
62
|
+
"bugs_and_chores_are_estimatable": true,
|
63
|
+
"public": false,
|
64
|
+
"point_scale": "0,1,2,3,5,8"
|
65
|
+
}
|
66
|
+
]
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'http_magic/uri'
|
3
|
+
require 'http_magic/request'
|
4
|
+
|
5
|
+
describe 'HttpMagic::Request' do
|
6
|
+
before do
|
7
|
+
@domain = 'example.com'
|
8
|
+
@uri = HttpMagic::Uri.new(@domain)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should make a request' do
|
12
|
+
stub_request = stub_request(
|
13
|
+
:get,
|
14
|
+
"https://#{@domain}/api/v2/path/to/something"
|
15
|
+
)
|
16
|
+
|
17
|
+
@uri.namespace = 'api/v2'
|
18
|
+
@uri.parts = ['path', 'to', 'something']
|
19
|
+
request = HttpMagic::Request.new(@uri)
|
20
|
+
request.get
|
21
|
+
|
22
|
+
assert_requested stub_request
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return content on request' do
|
26
|
+
content = 'This is SPARTA!'
|
27
|
+
stub_request(:get, "https://#{@domain}").
|
28
|
+
to_return(body: content)
|
29
|
+
|
30
|
+
request = HttpMagic::Request.new(@uri)
|
31
|
+
|
32
|
+
assert_equal content, request.get
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should be able to post data as hash' do
|
36
|
+
expected_data = {
|
37
|
+
apple: 'crispy',
|
38
|
+
banana: 'soft'
|
39
|
+
}
|
40
|
+
stub_request = stub_request(:post, "https://#{@domain}").with(
|
41
|
+
body: expected_data.to_json,
|
42
|
+
headers: { 'content-type' => 'application/json' }
|
43
|
+
)
|
44
|
+
|
45
|
+
request = HttpMagic::Request.new(@uri, data: expected_data)
|
46
|
+
request.post
|
47
|
+
|
48
|
+
assert_requested stub_request
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should set correct headers' do
|
52
|
+
stub_request = stub_request(:get, "https://#{@domain}").
|
53
|
+
with(headers: { 'X-AuthToken' => 'test_token' })
|
54
|
+
|
55
|
+
request = HttpMagic::Request.new(
|
56
|
+
@uri,
|
57
|
+
headers: { 'X-AuthToken' => 'test_token' }
|
58
|
+
)
|
59
|
+
request.get
|
60
|
+
|
61
|
+
assert_requested stub_request
|
62
|
+
end
|
63
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
gem 'minitest' if RUBY_VERSION > '1.9'
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'webmock/minitest'
|
7
|
+
require 'pry'
|
8
|
+
|
9
|
+
# Retreive the contents of fixture files to be used in tests. It is easier
|
10
|
+
# to view, modify and visualize text used in tests when it is stored in files.
|
11
|
+
# Also, it is much easier to reuse that text.
|
12
|
+
def fixture_file(file_name)
|
13
|
+
File.open(fixture_file_path(file_name), 'rb').read
|
14
|
+
end
|
15
|
+
|
16
|
+
def fixture_file_path(file_name)
|
17
|
+
File.join(File.dirname(__FILE__), 'fixtures', file_name)
|
18
|
+
end
|
data/test/uri_test.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'http_magic/uri'
|
3
|
+
|
4
|
+
describe 'HttpMagic::Uri' do
|
5
|
+
before do
|
6
|
+
@domain = 'example.com'
|
7
|
+
@uri = uri = HttpMagic::Uri.new(@domain)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'must have a domain param' do
|
11
|
+
assert_raises ArgumentError do
|
12
|
+
HttpMagic::Uri.new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should return the domain' do
|
17
|
+
assert_equal @domain, @uri.domain
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'can build a simple uri' do
|
21
|
+
assert_equal "https://#{@domain}/", @uri.build
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should have url' do
|
25
|
+
assert_equal "https://#{@domain}", @uri.url
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should create urn with parts' do
|
29
|
+
@uri.parts = ['path', 'to', 'something']
|
30
|
+
assert_equal '/path/to/something', @uri.urn
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should create urn with namespace' do
|
34
|
+
@uri.namespace = 'api/v2'
|
35
|
+
assert_equal '/api/v2', @uri.urn
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should create urn with namespace and parts combined' do
|
39
|
+
@uri.parts = ['path', 'to', 'something']
|
40
|
+
@uri.namespace = 'api/v2'
|
41
|
+
assert_equal '/api/v2/path/to/something', @uri.urn
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should create the full uri with urn included' do
|
45
|
+
@uri.parts = ['path', 'to', 'something']
|
46
|
+
@uri.namespace = 'api/v2'
|
47
|
+
assert_equal "https://#{@domain}/api/v2/path/to/something", @uri.build
|
48
|
+
end
|
49
|
+
end
|
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: http_magic
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- GradesFirst
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: webmock
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.16'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.16'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry-debugger
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description:
|
84
|
+
email: tech@gradesfirst.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- .gitignore
|
90
|
+
- Gemfile
|
91
|
+
- Gemfile.lock
|
92
|
+
- LICENSE
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- http_magic.gemspec
|
96
|
+
- lib/http_magic.rb
|
97
|
+
- lib/http_magic/api.rb
|
98
|
+
- lib/http_magic/request.rb
|
99
|
+
- lib/http_magic/uri.rb
|
100
|
+
- test/api/get_test.rb
|
101
|
+
- test/api/post_test.rb
|
102
|
+
- test/fixtures/projects.json
|
103
|
+
- test/request_test.rb
|
104
|
+
- test/test_helper.rb
|
105
|
+
- test/uri_test.rb
|
106
|
+
homepage: https://github.com/Thoughtwright-LLC/httpmagic
|
107
|
+
licenses:
|
108
|
+
- MIT
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.2.1
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: Provides a more Object Oriented interface to RESTful apis.
|
130
|
+
test_files: []
|