chain 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +106 -0
- data/Rakefile +1 -0
- data/chain.gemspec +28 -0
- data/lib/chain.rb +9 -0
- data/lib/chain/middleware/hashie_mash_response.rb +14 -0
- data/lib/chain/url.rb +87 -0
- data/lib/chain/version.rb +3 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/url_spec.rb +165 -0
- metadata +142 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 96a912a49313f8b3e5f4f384c4b85e421c7950fb
|
4
|
+
data.tar.gz: 95bf5be6688445559aa4d5afa0144e9d7ce1f2a8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0bf5415f4bd29a8d98a1a31e2077f76d3ff3959dfeeafdd826ef1df002d7e7e9d99cadeeaa2bc095038bc80d0e2b27b1735b5ceb732b4fb83b9f0b88b3df74c6
|
7
|
+
data.tar.gz: f6f9e422551146b173d85f60383b8e1bea9a298b7ad84c7ddbf564f478a31987c60337ed7d98a1414aebacd1beec362577938a3059b5f5f593bee07b84b2f01c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Stefan Novak
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# Chain #
|
2
|
+
|
3
|
+
*Abusing `method_missing` since 2013*™
|
4
|
+
|
5
|
+
### What in the Sam Hill is Chain? ###
|
6
|
+
|
7
|
+
Chain is a simple library that makes it (too) easy to interface with a (non)-RESTful web API. Inspired by [Her](https://github.com/remiprev/her/), I needed a way to create something that mimics an ORM to communicate with a non-RESTful API. Chain uses [Faraday](https://github.com/lostisland/faraday) as the client library to manage requests to API endpoints. As a result, you have full control of how the request and response are parsed out and mapped to an object in Ruby!
|
8
|
+
|
9
|
+
### How does it work? ###
|
10
|
+
|
11
|
+
Simply instantiate the `Url` class and then chain together a series of methods that represent the URL path. Finish off the chain with a bang to kick off the request. For example:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
>> require 'chain'
|
15
|
+
|
16
|
+
>> site = Chain::Url("http://www.site.com")
|
17
|
+
|
18
|
+
>> item = site.items[1].group!
|
19
|
+
=> #Hashie::Mash of JSON from http://www.site.com/items/1/group
|
20
|
+
|
21
|
+
>> item.name
|
22
|
+
=> "..."
|
23
|
+
```
|
24
|
+
|
25
|
+
This opens up all sorts of clever ways to iterate through an endpoint:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
# Send a GET request to http://www.site.com/items
|
29
|
+
items = site.items!
|
30
|
+
|
31
|
+
# Assuming that /items returns a JSON object containing a list of items in the `data` attribute...
|
32
|
+
items.data.each do |item|
|
33
|
+
|
34
|
+
# ...iterate through and print out the `name` attribute for http://www.site.com/items/#
|
35
|
+
puts items[item.id]!.name
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
### Query Parameters ###
|
40
|
+
|
41
|
+
You can specify query parameters via the `[]`, `_fetch`, or `_<insert your favorite http verb here>`. For example:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
# Submit a GET request to http://www.site.com/users?name=Mark Corrigan
|
45
|
+
|
46
|
+
>> user = site.users[name: 'Mark Corrigan']
|
47
|
+
>> user = site[:users, name: 'Mark Corrigan']
|
48
|
+
>> user = site.users._fetch(name: 'Mark Corrigan`)
|
49
|
+
```
|
50
|
+
|
51
|
+
### Other HTTP actions ###
|
52
|
+
|
53
|
+
By default, the `!`, `[]`, and `_fetch` methods on a `Url` object will map to a GET request. You can also use `_put`, `_post`, `_head`, `_delete`, etc.
|
54
|
+
|
55
|
+
To submit a request with a payload, send a request with the `_body` parameter:
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
# Send a POST request to http://www.site.com/users with URL-encoded parameters in the payload
|
59
|
+
>> user = site.users._post(_body: {name: 'Mark Corrigan'})
|
60
|
+
```
|
61
|
+
|
62
|
+
You can also manually specify the HTTP verb via `_method` and headers via `_headers`:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
>> user = site.users._fetch(_method: :post, _body: {name: 'Mark Corrigan'})
|
66
|
+
>> site.users._fetch(_method: :post, _headers: {"Accept" => "text/plain"})
|
67
|
+
```
|
68
|
+
|
69
|
+
### Configuring the Middleware ###
|
70
|
+
|
71
|
+
By default, Chain will assume that the response is JSON and will render that object inside of a [Hashie::Mash](https://github.com/intridea/hashie) object. If you want to implement your own request/response middleware, simply pass in a block to configure the Faraday connection:
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
site = Chain.Url("http://www.site.com") do |connection|
|
75
|
+
connection.use Faraday::Request::UrlEncoded
|
76
|
+
connection.use MyResponseMiddleWare
|
77
|
+
connection.use Faraday::Adapter::NetHttp
|
78
|
+
end
|
79
|
+
```
|
80
|
+
|
81
|
+
Writing your own middleware is fairly easy. Chain uses something along the lines of:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
class HashieMashResponse < Faraday::Response::Middleware
|
85
|
+
def on_complete(env)
|
86
|
+
body = JSON.parse(env[:body])
|
87
|
+
headers = env[:response_headers]
|
88
|
+
env[:body] = Hashie::Mash.new(body).tap do |item|
|
89
|
+
item._headers = Hashie::Mash.new(headers)
|
90
|
+
item._status = env[:status]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
### Bring on the caveats! ###
|
97
|
+
|
98
|
+
1. You cannot follow the bracket notation by a bang, such as: `site.person["Mark Corrgian"]!`. Use `site.person["Mark Corrgian"]._fetch`.
|
99
|
+
|
100
|
+
2. You cannot pass in a block to the bracket method, such as: `site.person["Mark Corrgian"]{|req| p req['url']}`. Use the `_fetch` method as described above.
|
101
|
+
|
102
|
+
3. For any urls that end with an extension, you will need to use the bracket notation. For example, site.users.json would render http://www.site.com/users/json.
|
103
|
+
|
104
|
+
4. Any portions of the url path that contain characters not supported by Ruby, you will need to use the bracket notation. This includes path segments that start with numerics, such as http://www.site.com/users/0. (It cannot be rendered as `site.users.0`, but rather `site.users[0]`.)
|
105
|
+
|
106
|
+
5. You will not be able to access URL sub-paths that have names similar to methods on standard objects in Ruby. For example, site.users[1].methods (http://www.site.com/users/1/methods) will return you a list of methods on the Chain::Url object. Use bracket notation!
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/chain.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'chain/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "chain"
|
8
|
+
spec.version = Chain::VERSION
|
9
|
+
spec.authors = ["Stefan Novak"]
|
10
|
+
spec.email = ["stefan.louis.novak@gmail.com"]
|
11
|
+
spec.description = %q{Access API endpoints via method chaining in Ruby.}
|
12
|
+
spec.summary = %q{Access API endpoints via method chaining in Ruby.}
|
13
|
+
spec.homepage = "https://github.com/slnovak/chain"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
24
|
+
spec.add_development_dependency "webmock", "~> 1.15.2"
|
25
|
+
|
26
|
+
spec.add_dependency "faraday", "~> 0.8.8"
|
27
|
+
spec.add_dependency "hashie", "~> 2.0.5"
|
28
|
+
end
|
data/lib/chain.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Chain
|
2
|
+
module Middleware
|
3
|
+
class HashieMashResponse < Faraday::Response::Middleware
|
4
|
+
def on_complete(env)
|
5
|
+
body = JSON.parse(env[:body].to_s.encode('UTF-8', {:invalid => :replace, :undef => :replace, :replace => '?'}))
|
6
|
+
headers = env[:response_headers]
|
7
|
+
env[:body] = Hashie::Mash.new(body).tap do |item|
|
8
|
+
item._headers = Hashie::Mash.new(headers)
|
9
|
+
item._status = env[:status]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/chain/url.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
module Chain
|
2
|
+
class Url
|
3
|
+
attr_accessor :connection, :default_parameters
|
4
|
+
|
5
|
+
def initialize(url, base_url=nil, params={}, &block)
|
6
|
+
@url = url
|
7
|
+
|
8
|
+
# Shift method arguments
|
9
|
+
if base_url.is_a? Hash
|
10
|
+
base_url, params = nil, base_url
|
11
|
+
end
|
12
|
+
|
13
|
+
@base_url = base_url
|
14
|
+
|
15
|
+
@default_parameters = params.delete(:_default_parameters)
|
16
|
+
|
17
|
+
if base_url.nil?
|
18
|
+
# If no base_url is given, then this is a 'base' instance of a Url. If a block is given,
|
19
|
+
# yield our connection object to the block so that the base instance can have its own
|
20
|
+
# Faraday configuration
|
21
|
+
@connection = Faraday.new(url: @url) do |connection|
|
22
|
+
if block_given?
|
23
|
+
yield connection
|
24
|
+
else
|
25
|
+
connection.use Faraday::Request::UrlEncoded
|
26
|
+
connection.use Middleware::HashieMashResponse
|
27
|
+
connection.use Faraday::Adapter::NetHttp
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else
|
31
|
+
# If this is a new instance with a base_url (from method_missing, let's say), then we're
|
32
|
+
# going to yield a request object to the block so a user can configure it.
|
33
|
+
if block_given?
|
34
|
+
_fetch(params, &block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(method_name, path=nil, params={}, &block)
|
40
|
+
|
41
|
+
# If this is a bang method, prepare to run a _fetch.
|
42
|
+
is_bang_method = method_name.to_s.chars.last == "!"
|
43
|
+
method_name = method_name[0...-1] if is_bang_method
|
44
|
+
|
45
|
+
# If a subsequent path is given as an argument, then expand out the path appropriately.
|
46
|
+
# For example, we might have base.api.items("My item", f: 'json'){|request| ...}. This
|
47
|
+
# should call into #{base}/api/items/My%20Item?f=json
|
48
|
+
combined_path = [method_name, path].compact.join("/")
|
49
|
+
|
50
|
+
url = URI.join("#{@url}/", combined_path)
|
51
|
+
|
52
|
+
self.class.new(url, @base_url || self, params, &block).tap do |request|
|
53
|
+
return request._fetch(params, &block) if is_bang_method || !params.empty?
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def [](path=nil, params={})
|
58
|
+
if path.is_a? Hash
|
59
|
+
path, params = nil, path.merge(params)
|
60
|
+
end
|
61
|
+
|
62
|
+
url = [@url, path].compact.join("/")
|
63
|
+
method_missing(url, nil, **params)
|
64
|
+
end
|
65
|
+
|
66
|
+
def _fetch(params={}, &block)
|
67
|
+
http_method = params.delete(:_method) || :get
|
68
|
+
body = params.delete(:_body)
|
69
|
+
headers = params.delete(:_headers)
|
70
|
+
|
71
|
+
@base_url.connection.run_request(http_method, @url, body, headers){|request|
|
72
|
+
request.params.update(params) if params
|
73
|
+
request.params.update(@base_url.default_parameters) if @base_url.default_parameters
|
74
|
+
yield request if block_given?
|
75
|
+
}.body
|
76
|
+
end
|
77
|
+
|
78
|
+
%w[get head delete post put patch].each do |verb|
|
79
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
80
|
+
def _#{verb}(params={}, &block)
|
81
|
+
params.merge!(_method: :#{verb})
|
82
|
+
_fetch(params, &block)
|
83
|
+
end
|
84
|
+
RUBY
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/url_spec.rb
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chain::Url do
|
4
|
+
|
5
|
+
context 'with HashieMashMiddleware' do
|
6
|
+
|
7
|
+
subject do
|
8
|
+
described_class.new('http://test.com')
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'response payloads' do
|
12
|
+
|
13
|
+
before :each do
|
14
|
+
body = {data: true}.to_json
|
15
|
+
|
16
|
+
stub_request(:get, 'http://test.com/item').
|
17
|
+
to_return(status: 200, body: body)
|
18
|
+
end
|
19
|
+
|
20
|
+
after :each do
|
21
|
+
a_request(:get, 'http://test.com/item').
|
22
|
+
should have_been_made
|
23
|
+
|
24
|
+
expect(@item.data).to eq(true)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should return a response payload using the bang method' do
|
28
|
+
@item = subject.item!
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should return a response payload using the _fetch method' do
|
32
|
+
@item = subject.item._fetch
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should parse a request url using the bracket method' do
|
36
|
+
@item = subject['item']._fetch
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'http verbs' do
|
41
|
+
|
42
|
+
[:get, :put, :post, :delete, :head, :patch].each do |verb|
|
43
|
+
it "should make valid request using the _#{verb} syntax" do
|
44
|
+
body = {data: true}.to_json
|
45
|
+
|
46
|
+
stub_request(verb, 'http://test.com/item').
|
47
|
+
to_return(status: 200, body: body)
|
48
|
+
|
49
|
+
subject.item.send("_#{verb}")
|
50
|
+
|
51
|
+
a_request(verb, 'http://test.com/item').
|
52
|
+
should have_been_made
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'request parsing' do
|
58
|
+
|
59
|
+
before :each do
|
60
|
+
body = {data: true}.to_json
|
61
|
+
|
62
|
+
stub_request(:get, 'http://test.com/item').
|
63
|
+
to_return(status: 200, body: body)
|
64
|
+
|
65
|
+
stub_request(:get, 'http://test.com/a/b/c/d/e/f/g').
|
66
|
+
to_return(status: 200, body: body)
|
67
|
+
|
68
|
+
stub_request(:get, 'http://test.com/item').
|
69
|
+
with(query: {foo: 'bar'}).
|
70
|
+
to_return(status: 200, body: body)
|
71
|
+
|
72
|
+
stub_request(:post, 'http://test.com/item').
|
73
|
+
to_return(status: 200, body: body)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should parse chained methods as a nested url path' do
|
77
|
+
subject.a.b.c.d.e.f.g!
|
78
|
+
|
79
|
+
a_request(:get, 'http://test.com/a/b/c/d/e/f/g').
|
80
|
+
should have_been_made
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should take keyword arguments from bracket notion and expend them out as parameters' do
|
84
|
+
subject.item[foo: 'bar']._fetch
|
85
|
+
|
86
|
+
a_request(:get, 'http://test.com/item').
|
87
|
+
with(query: hash_including({'foo' => 'bar'})).
|
88
|
+
should have_been_made
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should parse the _method parameter as the HTTP request type' do
|
92
|
+
subject.item[_method: :post]._fetch
|
93
|
+
|
94
|
+
a_request(:post, 'http://test.com/item').
|
95
|
+
should have_been_made
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should parse the _body parameter as the HTTP request type' do
|
99
|
+
subject.item[_method: :post, _body: 'foo=bar']._fetch
|
100
|
+
|
101
|
+
a_request(:post, 'http://test.com/item').
|
102
|
+
with(body: 'foo=bar').
|
103
|
+
should have_been_made
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should parse the _headers parameter as the HTTP request headers' do
|
107
|
+
subject.item[:_headers => {'Content-Length' => '3'}]._fetch
|
108
|
+
|
109
|
+
a_request(:get, 'http://test.com/item').
|
110
|
+
with(headers: {'Content-Length' => '3'}).
|
111
|
+
should have_been_made
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe 'modifying Faraday requests' do
|
116
|
+
|
117
|
+
before :each do
|
118
|
+
body = {data: true}.to_json
|
119
|
+
|
120
|
+
stub_request(:get, 'http://test.com/item').
|
121
|
+
with(query: {foo: 'bar'}).
|
122
|
+
to_return(status: 200, body: body)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should be able to modify the request object as a request is made' do
|
126
|
+
subject.item do |request|
|
127
|
+
request.params['foo'] = 'bar'
|
128
|
+
end
|
129
|
+
|
130
|
+
a_request(:get, 'http://test.com/item').
|
131
|
+
with(query: hash_including({'foo' => 'bar'})).
|
132
|
+
should have_been_made
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'with HashieMashMiddleware and default parameters' do
|
138
|
+
|
139
|
+
subject do
|
140
|
+
described_class.new('http://test.com', _default_parameters: {foo: 'bar'})
|
141
|
+
end
|
142
|
+
|
143
|
+
describe 'request parsing' do
|
144
|
+
|
145
|
+
before :each do
|
146
|
+
body = {data: true}.to_json
|
147
|
+
|
148
|
+
stub_request(:get, 'http://test.com/item').
|
149
|
+
with(query: {foo: 'bar'}).
|
150
|
+
to_return(status: 200, body: body)
|
151
|
+
|
152
|
+
stub_request(:post, 'http://test.com/item').
|
153
|
+
to_return(status: 200, body: body)
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should parse out a url with default_parameters specified by the base url instance' do
|
157
|
+
subject.item!
|
158
|
+
|
159
|
+
a_request(:get, 'http://test.com/item').
|
160
|
+
with(query: hash_including({'foo' => 'bar'})).
|
161
|
+
should have_been_made
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chain
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stefan Novak
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.14.1
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.14.1
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: webmock
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.15.2
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.15.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: faraday
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.8.8
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.8.8
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: hashie
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 2.0.5
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 2.0.5
|
97
|
+
description: Access API endpoints via method chaining in Ruby.
|
98
|
+
email:
|
99
|
+
- stefan.louis.novak@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- .gitignore
|
105
|
+
- Gemfile
|
106
|
+
- LICENSE.txt
|
107
|
+
- README.md
|
108
|
+
- Rakefile
|
109
|
+
- chain.gemspec
|
110
|
+
- lib/chain.rb
|
111
|
+
- lib/chain/middleware/hashie_mash_response.rb
|
112
|
+
- lib/chain/url.rb
|
113
|
+
- lib/chain/version.rb
|
114
|
+
- spec/spec_helper.rb
|
115
|
+
- spec/url_spec.rb
|
116
|
+
homepage: https://github.com/slnovak/chain
|
117
|
+
licenses:
|
118
|
+
- MIT
|
119
|
+
metadata: {}
|
120
|
+
post_install_message:
|
121
|
+
rdoc_options: []
|
122
|
+
require_paths:
|
123
|
+
- lib
|
124
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
requirements:
|
126
|
+
- - '>='
|
127
|
+
- !ruby/object:Gem::Version
|
128
|
+
version: '0'
|
129
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
requirements: []
|
135
|
+
rubyforge_project:
|
136
|
+
rubygems_version: 2.0.7
|
137
|
+
signing_key:
|
138
|
+
specification_version: 4
|
139
|
+
summary: Access API endpoints via method chaining in Ruby.
|
140
|
+
test_files:
|
141
|
+
- spec/spec_helper.rb
|
142
|
+
- spec/url_spec.rb
|