typekitable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.ruby-version +1 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +38 -0
- data/Rakefile +13 -0
- data/bin/typekitable +6 -0
- data/features/authentication.feature +13 -0
- data/features/kits.feature +22 -0
- data/features/step_definitions/kit_steps.rb +5 -0
- data/features/support/env.rb +15 -0
- data/lib/typekitable.rb +11 -0
- data/lib/typekitable/authenticator.rb +22 -0
- data/lib/typekitable/commander.rb +51 -0
- data/lib/typekitable/request.rb +66 -0
- data/lib/typekitable/request_fetcher.rb +72 -0
- data/lib/typekitable/response_formatter.rb +120 -0
- data/lib/typekitable/tokenizer.rb +23 -0
- data/lib/typekitable/version.rb +3 -0
- data/spec/fixtures/vcr_cassettes/add_kit.yml +63 -0
- data/spec/fixtures/vcr_cassettes/add_kit_maximum_error.yml +61 -0
- data/spec/fixtures/vcr_cassettes/add_kit_unauthorized_error.yml +61 -0
- data/spec/fixtures/vcr_cassettes/kits.yml +61 -0
- data/spec/fixtures/vcr_cassettes/kits_error.yml +59 -0
- data/spec/fixtures/vcr_cassettes/libraries.yml +61 -0
- data/spec/lib/typekitable/commander_spec.rb +17 -0
- data/spec/lib/typekitable/request_fetcher_spec.rb +67 -0
- data/spec/lib/typekitable/request_spec.rb +151 -0
- data/spec/lib/typekitable/response_formatter_spec.rb +199 -0
- data/spec/lib/typekitable/tokenizer_spec.rb +48 -0
- data/spec/spec_helper.rb +23 -0
- data/typekitable.gemspec +24 -0
- metadata +149 -0
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Typekitable
|
4
|
+
describe Request do
|
5
|
+
let(:path) { "kits" }
|
6
|
+
let(:verb) { "GET" }
|
7
|
+
let(:parameters) { {} }
|
8
|
+
let(:token) { "5e4ce50b7c5b996b2fb5e65ee4a6b870b9bd3297" }
|
9
|
+
|
10
|
+
subject { described_class.new(path, verb, parameters) }
|
11
|
+
|
12
|
+
context ".new" do
|
13
|
+
it "stores the path" do
|
14
|
+
expect(subject.verb).to eq(verb)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "stores the verb" do
|
18
|
+
expect(subject.path).to eq(path)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "stores the parameters" do
|
22
|
+
expect(subject.parameters).to eq(parameters)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context ".token" do
|
27
|
+
it "returns the token" do
|
28
|
+
expect(Tokenizer).to receive(:get_token).and_return(token)
|
29
|
+
|
30
|
+
subject.token
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context ".response" do
|
35
|
+
context "get kit list" do
|
36
|
+
context "successful response" do
|
37
|
+
it "returns the request response with access to the code, message, and body" do
|
38
|
+
VCR.use_cassette 'kits' do
|
39
|
+
allow(subject).to receive(:token).and_return(token)
|
40
|
+
@response = subject.response
|
41
|
+
end
|
42
|
+
|
43
|
+
expected_code = "200"
|
44
|
+
expected_message = "OK"
|
45
|
+
expected_body = "{\"kits\":[{\"id\":\"yuw0tqs\",\"link\":\"/api/v1/json/kits/yuw0tqs\"}]}"
|
46
|
+
expect(@response.body).to eq(expected_body)
|
47
|
+
expect(@response.code).to eq(expected_code)
|
48
|
+
expect(@response.message).to eq(expected_message)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "unsuccessful response" do
|
53
|
+
let(:token) { "143250b7c5b996b2fb5e65ee4a6b870b9bd3297" }
|
54
|
+
|
55
|
+
it "returns the request response with access to the code, message, and body" do
|
56
|
+
|
57
|
+
VCR.use_cassette 'kits_error' do
|
58
|
+
allow(subject).to receive(:token).and_return(token)
|
59
|
+
@response = subject.response
|
60
|
+
end
|
61
|
+
|
62
|
+
expected_code = "401"
|
63
|
+
expected_message = "Unauthorized"
|
64
|
+
expected_body = "{\"errors\":[\"Not authorized\"]}"
|
65
|
+
expect(@response.body).to eq(expected_body)
|
66
|
+
expect(@response.code).to eq(expected_code)
|
67
|
+
expect(@response.message).to eq(expected_message)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "get libraries list" do
|
73
|
+
let(:path) { "libraries" }
|
74
|
+
let(:verb) { "GET" }
|
75
|
+
context "successful response" do
|
76
|
+
it "returns the request response with access to the code, message, and body" do
|
77
|
+
VCR.use_cassette 'libraries' do
|
78
|
+
allow(subject).to receive(:token).and_return(token)
|
79
|
+
@response = subject.response
|
80
|
+
end
|
81
|
+
|
82
|
+
expected_code = "200"
|
83
|
+
expected_message = "OK"
|
84
|
+
expected_body = "{\"libraries\":[{\"id\":\"trial\",\"link\":\"/api/v1/json/libraries/trial\",\"name\":\"Trial Library\"},{\"id\":\"personal\",\"link\":\"/api/v1/json/libraries/personal\",\"name\":\"Personal Library\"},{\"id\":\"full\",\"link\":\"/api/v1/json/libraries/full\",\"name\":\"Full Library\"}]}"
|
85
|
+
expect(@response.body).to eq(expected_body)
|
86
|
+
expect(@response.code).to eq(expected_code)
|
87
|
+
expect(@response.message).to eq(expected_message)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "post new kit" do
|
93
|
+
let(:path) { "kits" }
|
94
|
+
let(:verb) { "POST" }
|
95
|
+
let(:parameters) { {:name => "A new kit", :domains => "http://persazula.com"} }
|
96
|
+
|
97
|
+
context "successful response" do
|
98
|
+
it "returns the request response with access to the code, message, and body" do
|
99
|
+
VCR.use_cassette 'add_kit' do
|
100
|
+
allow(subject).to receive(:token).and_return(token)
|
101
|
+
@response = subject.response
|
102
|
+
end
|
103
|
+
|
104
|
+
expected_code = "200"
|
105
|
+
expected_message = "OK"
|
106
|
+
expected_body = "{\"kit\":{\"id\":\"fla3cfh\",\"name\":\"A new kit\",\"analytics\":false,\"domains\":[\"persazula.com\"],\"families\":[]}}"
|
107
|
+
expect(@response.body).to eq(expected_body)
|
108
|
+
expect(@response.code).to eq(expected_code)
|
109
|
+
expect(@response.message).to eq(expected_message)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context "unauthorized response" do
|
114
|
+
let(:token) { "143250b7c5b996b2fb5e65ee4a6b870b9bd3297" }
|
115
|
+
|
116
|
+
it "returns the request response with access to the code, message, and body" do
|
117
|
+
|
118
|
+
VCR.use_cassette 'add_kit_unauthorized_error' do
|
119
|
+
allow(subject).to receive(:token).and_return(token)
|
120
|
+
@response = subject.response
|
121
|
+
end
|
122
|
+
|
123
|
+
expected_code = "401"
|
124
|
+
expected_message = "Unauthorized"
|
125
|
+
expected_body = "{\"errors\":[\"Not authorized\"]}"
|
126
|
+
expect(@response.body).to eq(expected_body)
|
127
|
+
expect(@response.code).to eq(expected_code)
|
128
|
+
expect(@response.message).to eq(expected_message)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "maximum kits response" do
|
133
|
+
it "returns the request response with access to the code, message, and body" do
|
134
|
+
|
135
|
+
VCR.use_cassette 'add_kit_maximum_error' do
|
136
|
+
allow(subject).to receive(:token).and_return(token)
|
137
|
+
@response = subject.response
|
138
|
+
end
|
139
|
+
|
140
|
+
expected_code = "400"
|
141
|
+
expected_message = "Bad Request"
|
142
|
+
expected_body = "{\"errors\":[\"You have reached the maximum number of kits\"]}"
|
143
|
+
expect(@response.body).to eq(expected_body)
|
144
|
+
expect(@response.code).to eq(expected_code)
|
145
|
+
expect(@response.message).to eq(expected_message)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Typekitable
|
4
|
+
describe ResponseFormatter do
|
5
|
+
|
6
|
+
let(:success_response) do
|
7
|
+
double(
|
8
|
+
:response,
|
9
|
+
:code => "200",
|
10
|
+
:message => "OK",
|
11
|
+
:body => "{\"kits\":[{\"id\":\"yuw0tqs\",\"link\":\"/api/v1/json/kits/yuw0tqs\"}]}"
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:successful_response_with_long_body) do
|
16
|
+
double(
|
17
|
+
:response,
|
18
|
+
:code => "200",
|
19
|
+
:message => "OK",
|
20
|
+
:body => "{\"libraries\":[{\"id\":\"trial\",\"link\":\"/api/v1/json/libraries/trial\",\"name\":\"Trial Library\"},{\"id\":\"personal\",\"link\":\"/api/v1/json/libraries/personal\",\"name\":\"Personal Library\"},{\"id\":\"full\",\"link\":\"/api/v1/json/libraries/full\",\"name\":\"Full Library\"}]}"
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:singular_resource_response) do
|
25
|
+
double(
|
26
|
+
:response,
|
27
|
+
:code => "200",
|
28
|
+
:message => "OK",
|
29
|
+
:body => "{\"kit\":{\"id\":\"fla3cfh\",\"name\":\"A new kit\",\"analytics\":false,\"domains\":[\"persazula.com\"],\"families\":[]}}"
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:short_response) do
|
34
|
+
double(
|
35
|
+
:response,
|
36
|
+
:code => "200",
|
37
|
+
:message => "OK",
|
38
|
+
:body => "{\"published\":\"2015-04-26T23:35:33Z\"}"
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
let(:empty_response) do
|
43
|
+
double(
|
44
|
+
:response,
|
45
|
+
:code => "200",
|
46
|
+
:message => "OK",
|
47
|
+
:body => "{\"kits\":[{}]}"
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
let(:error_response) do
|
52
|
+
double(
|
53
|
+
:response,
|
54
|
+
:code => "401",
|
55
|
+
:message => "Unauthorized",
|
56
|
+
:body => "{\"errors\":[\"Not authorized\"]}"
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
context ".error" do
|
61
|
+
context "with successful response code" do
|
62
|
+
subject { described_class.new(success_response) }
|
63
|
+
|
64
|
+
it "returns false" do
|
65
|
+
expect(subject.error?).to be_falsey
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with unsuccessful response code" do
|
70
|
+
subject { described_class.new(error_response) }
|
71
|
+
|
72
|
+
it "returns false" do
|
73
|
+
expect(subject.error?).to be_truthy
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context ".parsed_body" do
|
79
|
+
context "success response" do
|
80
|
+
subject { described_class.new(success_response) }
|
81
|
+
|
82
|
+
it "formats the body to a usable hash structure" do
|
83
|
+
expect(subject.parsed_body).to eq({:kits => [{:id =>"yuw0tqs", :link =>"/api/v1/json/kits/yuw0tqs"}]})
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "error response" do
|
88
|
+
subject { described_class.new(error_response) }
|
89
|
+
|
90
|
+
it "formats the body to a usable hash structure" do
|
91
|
+
expect(subject.parsed_body).to eq({:errors => ["Not authorized"]})
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context ".table_headers" do
|
97
|
+
subject { described_class.new(successful_response_with_long_body) }
|
98
|
+
|
99
|
+
it "formats the table headers for a collection" do
|
100
|
+
expected_headers = [:id, :link, :name]
|
101
|
+
|
102
|
+
expect(subject.table_headers).to eq(expected_headers)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "formats the table headers for a singular resource" do
|
106
|
+
singular_resource_subject = described_class.new(singular_resource_response)
|
107
|
+
expected_headers = [:id, :name, :analytics, :domains, :families]
|
108
|
+
|
109
|
+
expect(singular_resource_subject.table_headers).to eq(expected_headers)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "formats the table header for a short message" do
|
113
|
+
expected_header = [:published]
|
114
|
+
|
115
|
+
expect(described_class.new(short_response).table_headers).to eq(expected_header)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "formats the table headers for an empty response" do
|
119
|
+
response = described_class.new(empty_response)
|
120
|
+
expected_headers = []
|
121
|
+
|
122
|
+
expect(response.table_headers).to eq(expected_headers)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "formats the table header if an error response is detected" do
|
126
|
+
error_subject = described_class.new(error_response)
|
127
|
+
|
128
|
+
expect(error_subject.table_headers).to eq(["401"])
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context ".table_body" do
|
133
|
+
subject { described_class.new(successful_response_with_long_body) }
|
134
|
+
|
135
|
+
it "formats the table body for a collection" do
|
136
|
+
expected_body = [
|
137
|
+
{
|
138
|
+
:id => "trial",
|
139
|
+
:link => "/api/v1/json/libraries/trial",
|
140
|
+
:name=> "Trial Library"
|
141
|
+
},
|
142
|
+
{
|
143
|
+
:id => "personal",
|
144
|
+
:link => "/api/v1/json/libraries/personal",
|
145
|
+
:name => "Personal Library"
|
146
|
+
},
|
147
|
+
{
|
148
|
+
:id => "full",
|
149
|
+
:link => "/api/v1/json/libraries/full",
|
150
|
+
:name => "Full Library"
|
151
|
+
}
|
152
|
+
]
|
153
|
+
expect(subject.table_body).to eq(expected_body)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "formats the table body for errors" do
|
157
|
+
error_subject = described_class.new(error_response)
|
158
|
+
|
159
|
+
expect(error_subject.table_body).to eq([{"401"=>"Not authorized"}])
|
160
|
+
end
|
161
|
+
|
162
|
+
it "formats the table body for a singular resource" do
|
163
|
+
singular_resource_subject = described_class.new(singular_resource_response)
|
164
|
+
|
165
|
+
expected_body = [
|
166
|
+
{
|
167
|
+
:id => "fla3cfh",
|
168
|
+
:name => "A new kit",
|
169
|
+
:analytics => false,
|
170
|
+
:domains => ["persazula.com"],
|
171
|
+
:families => []
|
172
|
+
}
|
173
|
+
]
|
174
|
+
|
175
|
+
expect(singular_resource_subject.table_body).to eq(expected_body)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "formats the table body for a short message" do
|
179
|
+
expected_body = [{:published => "2015-04-26T23:35:33Z"}]
|
180
|
+
|
181
|
+
expect(described_class.new(short_response).table_body).to eq(expected_body)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "formats the table body when no data is received" do
|
185
|
+
response = described_class.new(empty_response)
|
186
|
+
|
187
|
+
expect(response.table_body).to eq([{}])
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context ".data_heading" do
|
192
|
+
subject { described_class.new(successful_response_with_long_body) }
|
193
|
+
|
194
|
+
it "formats the data heading for display" do
|
195
|
+
expect(subject.data_heading).to eq("Libraries")
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Typekitable
|
4
|
+
describe Tokenizer do
|
5
|
+
subject { described_class }
|
6
|
+
let(:token_store) { double(:file) }
|
7
|
+
let(:example_token) { "4d6141e7c82cb30affebcc392abc2ce3ab0ea4c1" }
|
8
|
+
|
9
|
+
context "#store" do
|
10
|
+
it "stores a given API token" do
|
11
|
+
expect(File).to receive(:open).with(Tokenizer::TOKEN_STORE, 'w').and_yield(token_store)
|
12
|
+
expect(token_store).to receive(:write).with(example_token)
|
13
|
+
|
14
|
+
subject.store(example_token)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "#has_token?" do
|
19
|
+
it "returns true when a token file exists" do
|
20
|
+
expect(File).to receive(:exist?).with(Tokenizer::TOKEN_STORE).and_return(true)
|
21
|
+
|
22
|
+
expect(subject.has_token?).to be_truthy
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns false when a token file does not exist" do
|
26
|
+
expect(File).to receive(:exist?).with(Tokenizer::TOKEN_STORE).and_return(false)
|
27
|
+
|
28
|
+
expect(subject.has_token?).to be_falsey
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "#get_token" do
|
33
|
+
it "returns the token when one exists" do
|
34
|
+
allow(subject).to receive(:has_token?).and_return(true)
|
35
|
+
expect(File).to receive(:open).with(Tokenizer::TOKEN_STORE, 'r').and_yield(token_store)
|
36
|
+
expect(token_store).to receive(:gets).and_return(example_token)
|
37
|
+
|
38
|
+
expect(subject.get_token).to eq(example_token)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns nil when the token does not exist" do
|
42
|
+
allow(subject).to receive(:has_token?).and_return(false)
|
43
|
+
|
44
|
+
expect(subject.get_token).to be_nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'typekitable'
|
2
|
+
require 'vcr'
|
3
|
+
require 'webmock/rspec'
|
4
|
+
|
5
|
+
VCR.configure do |c|
|
6
|
+
c.cassette_library_dir = './spec/fixtures/vcr_cassettes'
|
7
|
+
c.hook_into :webmock
|
8
|
+
end
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
def capture(stream)
|
12
|
+
begin
|
13
|
+
stream = stream.to_s
|
14
|
+
eval "$#{stream} = StringIO.new"
|
15
|
+
yield
|
16
|
+
result = eval("$#{stream}").string
|
17
|
+
ensure
|
18
|
+
eval("$#{stream} = #{stream.upcase}")
|
19
|
+
end
|
20
|
+
|
21
|
+
result
|
22
|
+
end
|
23
|
+
end
|
data/typekitable.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'typekitable/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "typekitable"
|
8
|
+
spec.version = Typekitable::VERSION
|
9
|
+
spec.authors = ["Persa Zula"]
|
10
|
+
spec.email = ["persa@persazula.com"]
|
11
|
+
spec.summary = %q{A CLI for interacting with your Typekit kits. No need to form your own requests!}
|
12
|
+
spec.homepage = "http://github.com/pzula/typekitable"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "thor", "0.19.1"
|
21
|
+
spec.add_dependency "formatador", "0.2.5"
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
end
|