typekitable 0.1.0
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 +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
|