stackd 0.0.1 → 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 +9 -4
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +1 -1
- data/LICENSE +24 -0
- data/README.md +184 -0
- data/bin/bundler +16 -0
- data/bin/console +14 -0
- data/bin/htmldiff +16 -0
- data/bin/ldiff +16 -0
- data/bin/rake +16 -0
- data/bin/rdoc +16 -0
- data/bin/restclient +16 -0
- data/bin/ri +16 -0
- data/bin/rspec +16 -0
- data/bin/safe_yaml +16 -0
- data/bin/setup +7 -0
- data/bin/stackd +16 -0
- data/lib/stackd.rb +27 -2
- data/lib/stackd/auth_request.rb +138 -0
- data/lib/stackd/client.rb +29 -0
- data/lib/stackd/concerns/require_attr.rb +20 -0
- data/lib/stackd/concerns/tattr_accessor.rb +51 -0
- data/lib/stackd/config.rb +23 -0
- data/lib/stackd/error.rb +27 -0
- data/lib/stackd/server_error.rb +4 -0
- data/lib/stackd/token.rb +103 -0
- data/lib/stackd/util/http.rb +135 -0
- data/lib/stackd/util/portal.rb +14 -0
- data/lib/stackd/version.rb +1 -1
- data/stackd.gemspec +28 -15
- metadata +141 -17
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 712a5a41ba1e4378a6f294d4ab7f4bd42dfa60df
|
|
4
|
+
data.tar.gz: 262301250ceb765546dd1120f259540e064ed25b
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 0c670d327edea7dc4d9fd30337b370094abe354e5f571f0b9f201d49bfeefef479508bfbd09c305f24646a597bef4e3b96fb0440abd21b99f97a1aee072c2ad4
|
|
7
|
+
data.tar.gz: 22e64533ead572f8c16a2c2c190492cf4772eab612b47fdc6dafd8fe6defde8f0b881fa74960b7d50b602a1b3bc5ca320c2184cf0565066f00be21ccb50ea304
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
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 NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <http://unlicense.org>
|
data/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Stackd Ruby Client
|
|
2
|
+
|
|
3
|
+
[](https://codeship.com/projects/77196)
|
|
4
|
+
|
|
5
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/stackd`. To experiment with that code, run `bin/console` for an interactive prompt.
|
|
6
|
+
|
|
7
|
+
TODO: Delete this and the text above, and describe your gem
|
|
8
|
+
|
|
9
|
+
### Installation
|
|
10
|
+
|
|
11
|
+
Add this line to your application's Gemfile:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
gem 'stackd'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
And then execute:
|
|
18
|
+
|
|
19
|
+
$ bundle
|
|
20
|
+
|
|
21
|
+
Or install it yourself as:
|
|
22
|
+
|
|
23
|
+
$ gem install stackd
|
|
24
|
+
|
|
25
|
+
### Usage
|
|
26
|
+
|
|
27
|
+
###### Creating a client
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
$stackd = Stackd::Client.new id: 'YOUR_CLIENT_ID',
|
|
31
|
+
secret: 'YOUR_CLIENT_SECRET'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
###### Getting an app token
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
app_token = $stackd.auth_requests.client scope: 'a,b,c'
|
|
38
|
+
# => <Stackd::Token app_id: "YOUR_CLIENT_ID",
|
|
39
|
+
# scope: "a,b,c",
|
|
40
|
+
# access_token: "e1979b29529ac",
|
|
41
|
+
# expires_in: 3600>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
###### Getting a user token
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
class MyController
|
|
48
|
+
def authorize
|
|
49
|
+
auth_request = $stackd.auth_requests.new redirect_uri: 'YOUR_CALLBACK_URL',
|
|
50
|
+
scope: 'a,b,c'
|
|
51
|
+
|
|
52
|
+
session[:auth_state] = auth_request.state
|
|
53
|
+
|
|
54
|
+
redirect_to auth_request.url
|
|
55
|
+
# stackd.com/authorize?client_id=...&state=...&redirect_uri=...&scope=...
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def callback
|
|
59
|
+
auth_request = $stackd.auth_requests.new state: session[:state]
|
|
60
|
+
|
|
61
|
+
user_token = auth_request.callback code: params[:code],
|
|
62
|
+
state: params[:state]
|
|
63
|
+
# => <Stackd::Token user_id: "09545bce-3c31-4593-99bd-1dfe8b98df93",
|
|
64
|
+
# scope: "a,b",
|
|
65
|
+
# access_token: "e1979b29529ac",
|
|
66
|
+
# refresh_token: "ca92592b9791e",
|
|
67
|
+
# expires_in: 3600>
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
###### Refreshing a user token
|
|
73
|
+
|
|
74
|
+
```ruby
|
|
75
|
+
refreshed_user_token = $stackd.auth_requests.refresh user_token
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
###### Persisting tokens (example)
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
rails generate model TokenData \
|
|
82
|
+
user_id:string \
|
|
83
|
+
scope:string \
|
|
84
|
+
access_token:string \
|
|
85
|
+
refresh_token:string \
|
|
86
|
+
expires_in:integer
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
Stackd::Token.on_grant do |token|
|
|
91
|
+
TokenData.create! user_id: token.user_id,
|
|
92
|
+
scope: token.scope,
|
|
93
|
+
access_token: token.access_token,
|
|
94
|
+
refresh_token: token.refresh_token,
|
|
95
|
+
expires_in: token.expires_in
|
|
96
|
+
end
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
class TokenData
|
|
101
|
+
def self.fresh_token_by criteria
|
|
102
|
+
# ...
|
|
103
|
+
token = $stackd.tokens.new user_id: user_id,
|
|
104
|
+
scope: scope,
|
|
105
|
+
access_token: access_token,
|
|
106
|
+
refresh_token: refresh_token,
|
|
107
|
+
expires_in: expires_in,
|
|
108
|
+
token_type: 'bearer'
|
|
109
|
+
|
|
110
|
+
if expired?
|
|
111
|
+
$stackd.auth_requests.refresh token
|
|
112
|
+
else
|
|
113
|
+
token
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def expired?
|
|
118
|
+
Time.now > created_at + expires_in.seconds
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
###### Making requests
|
|
124
|
+
|
|
125
|
+
https://stackd.com/docs
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
token.post :rappers, name: 'Marshall Mathers'
|
|
129
|
+
# POST /rappers
|
|
130
|
+
# {"name": "Marshall Mathers"}
|
|
131
|
+
# => { ... }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
token.patch :rappers, ':id', name: 'EMIN3M'
|
|
136
|
+
# PATCH /rappers/:id
|
|
137
|
+
# {"name": "EMIN3M"}
|
|
138
|
+
# => { ... }
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
token.get :rapper, ':id'
|
|
143
|
+
# GET /rappers/:id
|
|
144
|
+
# => { ... }
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
token.get :rappers, q: 'Slim Shady'
|
|
149
|
+
# GET /rappers?q=Slim%20Shady
|
|
150
|
+
# => { rappers: [ ... ], ... }
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
```ruby
|
|
154
|
+
token.get '/any/url'
|
|
155
|
+
# GET /any/url
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Application errors (4xx)**
|
|
159
|
+
|
|
160
|
+
Will throw a `Stackd::Error`:
|
|
161
|
+
|
|
162
|
+
```ruby
|
|
163
|
+
# <Stackd::Error error="error_code"
|
|
164
|
+
# error_description="Something went wrong."
|
|
165
|
+
# error_uri="https://stackd.com/docs/errors#error_code">
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Server errors (5xx)**
|
|
169
|
+
|
|
170
|
+
Will throw a `Stackd::ServerError`.
|
|
171
|
+
|
|
172
|
+
### Development
|
|
173
|
+
|
|
174
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment. Run `bundle exec stackd` to use the code located in this directory, ignoring other installed copies of this gem.
|
|
175
|
+
|
|
176
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
177
|
+
|
|
178
|
+
### Contributing
|
|
179
|
+
|
|
180
|
+
1. Fork it ( https://github.com/stackd/stackd-ruby/fork )
|
|
181
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
182
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
183
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
184
|
+
5. Create a new Pull Request
|
data/bin/bundler
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'bundler' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('bundler', 'bundler')
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "stackd"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start
|
data/bin/htmldiff
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'htmldiff' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('diff-lcs', 'htmldiff')
|
data/bin/ldiff
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'ldiff' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('diff-lcs', 'ldiff')
|
data/bin/rake
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'rake' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('rake', 'rake')
|
data/bin/rdoc
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'rdoc' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('rdoc', 'rdoc')
|
data/bin/restclient
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'restclient' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('rest-client', 'restclient')
|
data/bin/ri
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'ri' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('rdoc', 'ri')
|
data/bin/rspec
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'rspec' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('rspec-core', 'rspec')
|
data/bin/safe_yaml
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'safe_yaml' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('safe_yaml', 'safe_yaml')
|
data/bin/setup
ADDED
data/bin/stackd
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# This file was generated by Bundler.
|
|
4
|
+
#
|
|
5
|
+
# The application 'stackd' is installed as part of a gem, and
|
|
6
|
+
# this file is here to facilitate running it.
|
|
7
|
+
#
|
|
8
|
+
|
|
9
|
+
require 'pathname'
|
|
10
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
|
|
11
|
+
Pathname.new(__FILE__).realpath)
|
|
12
|
+
|
|
13
|
+
require 'rubygems'
|
|
14
|
+
require 'bundler/setup'
|
|
15
|
+
|
|
16
|
+
load Gem.bin_path('stackd', 'stackd')
|
data/lib/stackd.rb
CHANGED
|
@@ -1,4 +1,29 @@
|
|
|
1
|
-
require "stackd/version"
|
|
2
|
-
|
|
3
1
|
module Stackd
|
|
2
|
+
autoload :Version, 'stackd/version'
|
|
3
|
+
autoload :Config, 'stackd/config'
|
|
4
|
+
autoload :Client, 'stackd/client'
|
|
5
|
+
autoload :AuthRequest, 'stackd/auth_request'
|
|
6
|
+
autoload :Token, 'stackd/token'
|
|
7
|
+
autoload :Error, 'stackd/error'
|
|
8
|
+
autoload :ServerError, 'stackd/server_error'
|
|
9
|
+
|
|
10
|
+
module Util
|
|
11
|
+
autoload :Portal, 'stackd/util/portal'
|
|
12
|
+
autoload :HTTP, 'stackd/util/http'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module Concerns
|
|
16
|
+
autoload :TattrAccessor, 'stackd/concerns/tattr_accessor'
|
|
17
|
+
autoload :RequireAttr, 'stackd/concerns/require_attr'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
def config
|
|
22
|
+
@config ||= Stackd::Config.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def configure
|
|
26
|
+
yield config
|
|
27
|
+
end
|
|
28
|
+
end
|
|
4
29
|
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
require 'active_support/core_ext/hash/keys'
|
|
3
|
+
require 'unirest'
|
|
4
|
+
|
|
5
|
+
module Stackd
|
|
6
|
+
class AuthRequest
|
|
7
|
+
include Concerns::TattrAccessor
|
|
8
|
+
include Concerns::RequireAttr
|
|
9
|
+
|
|
10
|
+
tattr_accessor client: Client,
|
|
11
|
+
state: String,
|
|
12
|
+
redirect_uri: String
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def password client, params
|
|
16
|
+
if params[:username].nil?
|
|
17
|
+
raise ArgumentError.new "username is required"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
if params[:password].nil?
|
|
21
|
+
raise ArgumentError.new "password is required"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
request_token client, grant_type: 'password',
|
|
25
|
+
username: params[:username],
|
|
26
|
+
password: params[:password],
|
|
27
|
+
scope: params[:scope]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def client client, params = {}
|
|
31
|
+
request_token client, grant_type: 'client_credentials',
|
|
32
|
+
scope: params[:scope]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def refresh client, token, params = {}
|
|
36
|
+
if token.nil?
|
|
37
|
+
raise ArgumentError.new "Token is required"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if token.refresh_token.nil?
|
|
41
|
+
raise ArgumentError.new "Token must have refresh_token"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
request_token client, grant_type: 'refresh_token',
|
|
45
|
+
refresh_token: token.refresh_token,
|
|
46
|
+
scope: params[:scope]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def request_token client, params = {}
|
|
52
|
+
if params[:grant_type].nil?
|
|
53
|
+
raise ArgumentError.new "grant_type not provided"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
res = Unirest.post "#{Stackd.config.api_url}/token", {
|
|
57
|
+
auth: {
|
|
58
|
+
user: client.id,
|
|
59
|
+
password: client.secret
|
|
60
|
+
},
|
|
61
|
+
headers: {'Content-Type' => 'application/x-www-form-urlencoded'},
|
|
62
|
+
parameters: params.reject { |k,v| v.nil? }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if res.code == 200
|
|
66
|
+
token = client.tokens.new res.body.symbolize_keys
|
|
67
|
+
|
|
68
|
+
on_grant_callbacks = \
|
|
69
|
+
Stackd::Token.instance_variable_get :@_on_grant_callbacks
|
|
70
|
+
on_grant_callbacks.each {|c| c.(token) }
|
|
71
|
+
|
|
72
|
+
token
|
|
73
|
+
else
|
|
74
|
+
raise Error.new res.body.symbolize_keys
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def initialize client, attrs = {}
|
|
80
|
+
if client.nil?
|
|
81
|
+
raise ArgumentError.new "client not provided"
|
|
82
|
+
else
|
|
83
|
+
self.client = client
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
attrs.each do |key, val|
|
|
87
|
+
public_send :"#{key}=", val
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
if state.nil?
|
|
91
|
+
self.state = SecureRandom.urlsafe_base64 9
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def url params = {}
|
|
96
|
+
uri = auth_url
|
|
97
|
+
|
|
98
|
+
uri.query_values = {
|
|
99
|
+
response_type: 'code',
|
|
100
|
+
client_id: client.id,
|
|
101
|
+
state: state,
|
|
102
|
+
redirect_uri: params[:redirect_uri],
|
|
103
|
+
scope: params[:scope]
|
|
104
|
+
}.reject { |k,v| v.nil? }
|
|
105
|
+
|
|
106
|
+
uri.to_s
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def callback params
|
|
110
|
+
unless params[:code] || params[:error]
|
|
111
|
+
raise ArgumentError.new 'no code or error'
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
if params[:state] != state
|
|
115
|
+
raise StateMismatchError.new "#{params[:state]} != #{state}"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
if params[:error]
|
|
119
|
+
raise Error.new params
|
|
120
|
+
else
|
|
121
|
+
self.class.send :request_token, client, {
|
|
122
|
+
grant_type: 'authorization_code',
|
|
123
|
+
code: params[:code],
|
|
124
|
+
redirect_uri: redirect_uri
|
|
125
|
+
}
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
private
|
|
130
|
+
|
|
131
|
+
def auth_url
|
|
132
|
+
Addressable::URI.parse Stackd.config.auth_url
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
class StateMismatchError < StandardError
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Stackd
|
|
2
|
+
class Client
|
|
3
|
+
include Concerns::TattrAccessor
|
|
4
|
+
include Concerns::RequireAttr
|
|
5
|
+
|
|
6
|
+
tattr_accessor id: String,
|
|
7
|
+
secret: String
|
|
8
|
+
|
|
9
|
+
def initialize attrs
|
|
10
|
+
attrs.each do |attr, val|
|
|
11
|
+
public_send :"#{attr}=", val
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
begin
|
|
15
|
+
require_attr! :id, :secret
|
|
16
|
+
rescue Concerns::RequireAttr::AttrNotSetError => e
|
|
17
|
+
raise ArgumentError.new e.message
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def auth_requests
|
|
22
|
+
@auth_requests ||= Util::Portal.new self, AuthRequest
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def tokens
|
|
26
|
+
@tokens ||= Util::Portal.new self, Token
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
|
|
3
|
+
module Stackd
|
|
4
|
+
module Concerns
|
|
5
|
+
module RequireAttr
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
def require_attr! *attrs
|
|
9
|
+
attrs.each do |key|
|
|
10
|
+
if public_send(key).nil?
|
|
11
|
+
raise AttrNotSetError.new "#{key} not set"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class AttrNotSetError < StandardError
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
|
|
3
|
+
module Stackd
|
|
4
|
+
module Concerns
|
|
5
|
+
module TattrAccessor
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
@_tattrs = {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class_methods do
|
|
13
|
+
def tattr_accessor tattrs
|
|
14
|
+
tattrs.each do |tattr, type|
|
|
15
|
+
attr_reader tattr
|
|
16
|
+
|
|
17
|
+
@_tattrs[tattr] = type
|
|
18
|
+
|
|
19
|
+
define_method :"#{tattr}=" do |value|
|
|
20
|
+
unless value.nil? || self.class.tattr_type_match?(tattr, value)
|
|
21
|
+
tattr_type = self.class.tattr_type tattr
|
|
22
|
+
raise TypeMismatchError.new [
|
|
23
|
+
"tattr: #{tattr}",
|
|
24
|
+
"tattr_type: #{tattr_type}",
|
|
25
|
+
"value: #{value.inspect}"
|
|
26
|
+
].join ', '
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
instance_variable_set :"@#{tattr}", value
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def tattr_type_match? tattr, value
|
|
35
|
+
value.is_a? tattr_type(tattr)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def tattr_type tattr
|
|
39
|
+
@_tattrs[tattr]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def tattr? key
|
|
44
|
+
self.class.instance_variable_get(:@_tattrs).has_key? key
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class TypeMismatchError < StandardError
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Stackd
|
|
2
|
+
class Config
|
|
3
|
+
include Concerns::TattrAccessor
|
|
4
|
+
|
|
5
|
+
tattr_accessor auth_url: String,
|
|
6
|
+
token_url: String,
|
|
7
|
+
api_url: String
|
|
8
|
+
|
|
9
|
+
def initialize attrs = {}
|
|
10
|
+
attrs.each do |key, val|
|
|
11
|
+
public_send :"#{key}=", val
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def auth_url
|
|
16
|
+
@auth_url || "https://stackd.com/authorize"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def api_url
|
|
20
|
+
@api_url || "https://api.stackd.com"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/stackd/error.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Stackd
|
|
2
|
+
class Error < StandardError
|
|
3
|
+
include Concerns::TattrAccessor
|
|
4
|
+
include Concerns::RequireAttr
|
|
5
|
+
|
|
6
|
+
tattr_accessor error: String,
|
|
7
|
+
error_description: String,
|
|
8
|
+
error_uri: String,
|
|
9
|
+
error_params: Hash
|
|
10
|
+
|
|
11
|
+
def initialize attrs
|
|
12
|
+
attrs.each do |key, val|
|
|
13
|
+
public_send :"#{key}=", val if tattr? key
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
begin
|
|
17
|
+
require_attr! :error
|
|
18
|
+
rescue Concerns::RequireAttr::AttrNotSetError => e
|
|
19
|
+
raise ArgumentError.new e.message
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def message
|
|
24
|
+
error_description
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/stackd/token.rb
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require 'active_support/core_ext/object/to_query'
|
|
2
|
+
|
|
3
|
+
module Stackd
|
|
4
|
+
class Token
|
|
5
|
+
include Concerns::TattrAccessor
|
|
6
|
+
include Concerns::RequireAttr
|
|
7
|
+
|
|
8
|
+
@_on_grant_callbacks = []
|
|
9
|
+
|
|
10
|
+
tattr_accessor client: Client,
|
|
11
|
+
access_token: String,
|
|
12
|
+
token_type: String,
|
|
13
|
+
expires_in: Integer,
|
|
14
|
+
refresh_token: String,
|
|
15
|
+
scope: String,
|
|
16
|
+
service_id: String,
|
|
17
|
+
user_id: String
|
|
18
|
+
|
|
19
|
+
def self.on_grant &block
|
|
20
|
+
@_on_grant_callbacks.push block
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def initialize client, attrs = {}
|
|
24
|
+
self.client = client
|
|
25
|
+
|
|
26
|
+
attrs.each do |key, val|
|
|
27
|
+
public_send :"#{key}=", val if tattr? key
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
begin
|
|
31
|
+
require_attr! :client, :access_token, :token_type
|
|
32
|
+
rescue Concerns::RequireAttr::AttrNotSetError => e
|
|
33
|
+
raise ArgumentError.new e.message
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def get *args
|
|
38
|
+
Util::HTTP.get self, get_url(*args)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def post *args
|
|
42
|
+
url_args = reject_body_arg *args
|
|
43
|
+
body_arg = get_body_arg *args
|
|
44
|
+
content_type = content_type_for body_arg
|
|
45
|
+
|
|
46
|
+
Util::HTTP.post self, get_url(*url_args), body_arg, content_type
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def put *args
|
|
50
|
+
url_args = reject_body_arg *args
|
|
51
|
+
body_arg = get_body_arg *args
|
|
52
|
+
content_type = content_type_for body_arg
|
|
53
|
+
|
|
54
|
+
Util::HTTP.put self, get_url(*url_args), body_arg, content_type
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def patch *args
|
|
58
|
+
url_args = reject_body_arg *args
|
|
59
|
+
body_arg = get_body_arg *args
|
|
60
|
+
content_type = content_type_for body_arg
|
|
61
|
+
|
|
62
|
+
Util::HTTP.patch self, get_url(*url_args), body_arg, content_type
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def delete *args
|
|
66
|
+
url_args = reject_body_arg *args
|
|
67
|
+
body_arg = get_body_arg *args
|
|
68
|
+
content_type = content_type_for body_arg
|
|
69
|
+
|
|
70
|
+
Util::HTTP.delete self, get_url(*url_args), body_arg, content_type
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def get_url *args
|
|
76
|
+
args.inject Stackd.config.api_url do |url, part|
|
|
77
|
+
if part.is_a? Hash
|
|
78
|
+
"#{url}?#{part.to_query}"
|
|
79
|
+
else part = part.to_s
|
|
80
|
+
if part.index(Stackd.config.api_url) == 0
|
|
81
|
+
part
|
|
82
|
+
elsif part.index('/') == 0
|
|
83
|
+
"#{url}#{part}"
|
|
84
|
+
else
|
|
85
|
+
"#{url}/#{part}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def reject_body_arg *args
|
|
92
|
+
args.reject {|a| a.is_a? Hash }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def get_body_arg *args
|
|
96
|
+
args.last if args.last.is_a? Hash
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def content_type_for body_arg
|
|
100
|
+
:json unless body_arg.nil?
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'uri'
|
|
3
|
+
require 'unirest'
|
|
4
|
+
require 'active_support/core_ext/hash/keys'
|
|
5
|
+
|
|
6
|
+
module Stackd
|
|
7
|
+
module Util
|
|
8
|
+
module HTTP
|
|
9
|
+
def self.get credentials, url
|
|
10
|
+
request_without_body :get, credentials, url
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.post credentials, url, body, content_type
|
|
14
|
+
request_with_body :post, credentials, url, body, content_type
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.put credentials, url, body, content_type
|
|
18
|
+
request_with_body :put, credentials, url, body, content_type
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.patch credentials, url, body, content_type
|
|
22
|
+
request_with_body :patch, credentials, url, body, content_type
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.delete credentials, url
|
|
26
|
+
request_without_body :delete, credentials, url
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def self.request_without_body method, credentials, url
|
|
32
|
+
validate_params! credentials, url
|
|
33
|
+
|
|
34
|
+
basic_auth = basic_auth_for credentials
|
|
35
|
+
headers = headers_for credentials
|
|
36
|
+
|
|
37
|
+
res = Unirest.public_send method, url, headers: headers,
|
|
38
|
+
auth: basic_auth
|
|
39
|
+
|
|
40
|
+
process_response res
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.request_with_body method, credentials, url, body, content_type
|
|
44
|
+
validate_params! credentials, url, body, content_type
|
|
45
|
+
|
|
46
|
+
basic_auth = basic_auth_for credentials
|
|
47
|
+
headers = headers_for credentials, content_type
|
|
48
|
+
parameters = parameters_for body, content_type
|
|
49
|
+
|
|
50
|
+
res = Unirest.public_send method, url, headers: headers,
|
|
51
|
+
auth: basic_auth,
|
|
52
|
+
parameters: parameters
|
|
53
|
+
|
|
54
|
+
process_response res
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.validate_params! credentials, url, body = nil, content_type = nil
|
|
58
|
+
unless creds_are_valid? credentials
|
|
59
|
+
raise ArgumentError.new \
|
|
60
|
+
"credentials must be a Stackd::Token, Hash with :user + " + \
|
|
61
|
+
":password, credentials: #{credentials.inspect}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
unless url.is_a? String
|
|
65
|
+
raise ArgumentError.new "url must be String. url: #{url.inspect}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
unless body.nil? || body.is_a?(Hash)
|
|
69
|
+
raise ArgumentError.new \
|
|
70
|
+
"body must be a Hash or nil. body: #{body.inspect}"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
unless content_type.nil? || [:json, :form].include?(content_type)
|
|
74
|
+
raise ArgumentError.new \
|
|
75
|
+
"content_type must be :json, :form, or nil. " + \
|
|
76
|
+
"content_type: #{content_type.inspect}"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def self.creds_are_valid? credentials
|
|
81
|
+
credentials.nil? || \
|
|
82
|
+
credentials.is_a?(Client) || \
|
|
83
|
+
credentials.is_a?(Token) || \
|
|
84
|
+
(credentials.is_a?(Hash) && \
|
|
85
|
+
credentials[:user].is_a?(String) && \
|
|
86
|
+
credentials[:password].is_a?(String))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def self.basic_auth_for credentials
|
|
90
|
+
if credentials.is_a? Hash
|
|
91
|
+
credentials
|
|
92
|
+
elsif credentials.is_a? Client
|
|
93
|
+
{ user: credentials.id, password: credentials.secret }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.headers_for credentials, content_type = nil
|
|
98
|
+
headers = {}
|
|
99
|
+
|
|
100
|
+
if credentials.is_a? Token
|
|
101
|
+
headers.merge!(
|
|
102
|
+
{ 'Authorization' => "Bearer #{credentials.access_token}" })
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
unless content_type.nil?
|
|
106
|
+
content_type_value = content_type == :json \
|
|
107
|
+
? 'application/json' \
|
|
108
|
+
: 'application/x-www-form-urlencoded'
|
|
109
|
+
|
|
110
|
+
headers.merge!({ 'Content-Type' => content_type_value })
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
headers
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def self.parameters_for body, content_type
|
|
117
|
+
if content_type == :json
|
|
118
|
+
JSON.generate body
|
|
119
|
+
else
|
|
120
|
+
body
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def self.process_response res
|
|
125
|
+
if res.code >= 500
|
|
126
|
+
raise ServerError.new res.body.deep_symbolize_keys
|
|
127
|
+
elsif res.code >= 400
|
|
128
|
+
raise Error.new res.body.deep_symbolize_keys
|
|
129
|
+
else
|
|
130
|
+
res.body.deep_symbolize_keys
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
data/lib/stackd/version.rb
CHANGED
data/stackd.gemspec
CHANGED
|
@@ -1,18 +1,31 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'stackd/version'
|
|
4
5
|
|
|
5
|
-
Gem::Specification.new do |
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
s.homepage = "https://stackd.com/"
|
|
11
|
-
s.summary = %q{Stackd gem}
|
|
12
|
-
s.description = %q{Stackd gem}
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "stackd"
|
|
8
|
+
spec.version = Stackd::VERSION
|
|
9
|
+
spec.authors = ["Stephen Ausman"]
|
|
10
|
+
spec.email = ["stephen@stackd.com"]
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
spec.summary = "Stackd Ruby client"
|
|
13
|
+
spec.description = "https://stackd.com"
|
|
14
|
+
spec.homepage = "https://github.com/stackd/stackd-ruby"
|
|
15
|
+
spec.license = "Unlicense"
|
|
16
|
+
|
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f|
|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
|
19
|
+
}
|
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
21
|
+
spec.require_paths = ["lib"]
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.8"
|
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
|
26
|
+
spec.add_development_dependency "webmock", "~> 1.21"
|
|
27
|
+
|
|
28
|
+
spec.add_dependency "unirest", "~> 1.1"
|
|
29
|
+
spec.add_dependency "addressable", "~> 2.3"
|
|
30
|
+
spec.add_dependency "activesupport", "~> 4.2"
|
|
18
31
|
end
|
metadata
CHANGED
|
@@ -1,50 +1,174 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stackd
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
5
|
-
prerelease:
|
|
4
|
+
version: 0.1.1
|
|
6
5
|
platform: ruby
|
|
7
6
|
authors:
|
|
8
|
-
-
|
|
7
|
+
- Stephen Ausman
|
|
9
8
|
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date:
|
|
13
|
-
dependencies:
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
date: 2015-12-21 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.8'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.8'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.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: '3.2'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.2'
|
|
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.21'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.21'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: unirest
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '1.1'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '1.1'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: addressable
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '2.3'
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '2.3'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: activesupport
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '4.2'
|
|
104
|
+
type: :runtime
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '4.2'
|
|
111
|
+
description: https://stackd.com
|
|
112
|
+
email:
|
|
113
|
+
- stephen@stackd.com
|
|
16
114
|
executables: []
|
|
17
115
|
extensions: []
|
|
18
116
|
extra_rdoc_files: []
|
|
19
117
|
files:
|
|
20
|
-
- .gitignore
|
|
118
|
+
- ".gitignore"
|
|
119
|
+
- ".rspec"
|
|
120
|
+
- ".travis.yml"
|
|
21
121
|
- Gemfile
|
|
122
|
+
- LICENSE
|
|
123
|
+
- README.md
|
|
22
124
|
- Rakefile
|
|
125
|
+
- bin/bundler
|
|
126
|
+
- bin/console
|
|
127
|
+
- bin/htmldiff
|
|
128
|
+
- bin/ldiff
|
|
129
|
+
- bin/rake
|
|
130
|
+
- bin/rdoc
|
|
131
|
+
- bin/restclient
|
|
132
|
+
- bin/ri
|
|
133
|
+
- bin/rspec
|
|
134
|
+
- bin/safe_yaml
|
|
135
|
+
- bin/setup
|
|
136
|
+
- bin/stackd
|
|
23
137
|
- lib/stackd.rb
|
|
138
|
+
- lib/stackd/auth_request.rb
|
|
139
|
+
- lib/stackd/client.rb
|
|
140
|
+
- lib/stackd/concerns/require_attr.rb
|
|
141
|
+
- lib/stackd/concerns/tattr_accessor.rb
|
|
142
|
+
- lib/stackd/config.rb
|
|
143
|
+
- lib/stackd/error.rb
|
|
144
|
+
- lib/stackd/server_error.rb
|
|
145
|
+
- lib/stackd/token.rb
|
|
146
|
+
- lib/stackd/util/http.rb
|
|
147
|
+
- lib/stackd/util/portal.rb
|
|
24
148
|
- lib/stackd/version.rb
|
|
25
149
|
- stackd.gemspec
|
|
26
|
-
homepage: https://
|
|
27
|
-
licenses:
|
|
150
|
+
homepage: https://github.com/stackd/stackd-ruby
|
|
151
|
+
licenses:
|
|
152
|
+
- Unlicense
|
|
153
|
+
metadata: {}
|
|
28
154
|
post_install_message:
|
|
29
155
|
rdoc_options: []
|
|
30
156
|
require_paths:
|
|
31
157
|
- lib
|
|
32
158
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
33
|
-
none: false
|
|
34
159
|
requirements:
|
|
35
|
-
- -
|
|
160
|
+
- - ">="
|
|
36
161
|
- !ruby/object:Gem::Version
|
|
37
162
|
version: '0'
|
|
38
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
39
|
-
none: false
|
|
40
164
|
requirements:
|
|
41
|
-
- -
|
|
165
|
+
- - ">="
|
|
42
166
|
- !ruby/object:Gem::Version
|
|
43
167
|
version: '0'
|
|
44
168
|
requirements: []
|
|
45
169
|
rubyforge_project:
|
|
46
|
-
rubygems_version:
|
|
170
|
+
rubygems_version: 2.4.5.1
|
|
47
171
|
signing_key:
|
|
48
|
-
specification_version:
|
|
49
|
-
summary: Stackd
|
|
172
|
+
specification_version: 4
|
|
173
|
+
summary: Stackd Ruby client
|
|
50
174
|
test_files: []
|