typekit-client 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +9 -5
- data/Guardfile +7 -0
- data/README.md +160 -131
- data/bin/typekit +21 -8
- data/lib/typekit/client.rb +5 -5
- data/lib/typekit/configuration/base.rb +1 -1
- data/lib/typekit/configuration/default.rb +9 -5
- data/lib/typekit/connection/dispatcher.rb +2 -2
- data/lib/typekit/connection/request.rb +5 -2
- data/lib/typekit/connection/response.rb +4 -8
- data/lib/typekit/helper.rb +22 -0
- data/lib/typekit/processing/converter/boolean.rb +11 -0
- data/lib/typekit/processing/converter/datetime.rb +11 -0
- data/lib/typekit/processing/converter/errors.rb +22 -0
- data/lib/typekit/processing/converter/record.rb +15 -0
- data/lib/typekit/processing/converter/records.rb +18 -0
- data/lib/typekit/processing/converter/unknown.rb +14 -0
- data/lib/typekit/processing/converter.rb +32 -0
- data/lib/typekit/processing/parser/json.rb +15 -0
- data/lib/typekit/processing/parser/yaml.rb +15 -0
- data/lib/typekit/processing/parser.rb +14 -0
- data/lib/typekit/processing/translator.rb +16 -0
- data/lib/typekit/processing.rb +9 -0
- data/lib/typekit/record/base.rb +30 -0
- data/lib/typekit/record/family.rb +7 -0
- data/lib/typekit/record/kit.rb +7 -0
- data/lib/typekit/record/library.rb +7 -0
- data/lib/typekit/record/variation.rb +8 -0
- data/lib/typekit/record.rb +35 -0
- data/lib/typekit/routing/{map.rb → mapper.rb} +1 -1
- data/lib/typekit/routing/node/base.rb +1 -0
- data/lib/typekit/routing.rb +1 -1
- data/lib/typekit/version.rb +1 -1
- data/lib/typekit.rb +4 -4
- data/spec/cassettes/delete_kits_xxx_ok.yml +16 -0
- data/spec/typekit/client_spec.rb +11 -3
- data/spec/typekit/configuration_spec.rb +20 -4
- data/spec/typekit/connection/dispatcher_spec.rb +4 -4
- data/spec/typekit/connection/response_spec.rb +18 -0
- data/spec/typekit/helper_spec.rb +34 -0
- data/spec/typekit/processing/converter_spec.rb +54 -0
- data/spec/typekit/processing/parser_spec.rb +23 -0
- data/spec/typekit/record/base_spec.rb +33 -0
- data/spec/typekit/record_spec.rb +48 -0
- data/spec/typekit/routing/mapper_spec.rb +177 -0
- data/spec/typekit/routing/node_spec.rb +31 -10
- data/typekit-client.gemspec +2 -1
- metadata +53 -13
- data/lib/typekit/parser/json.rb +0 -13
- data/lib/typekit/parser/yaml.rb +0 -13
- data/lib/typekit/parser.rb +0 -14
- data/lib/typekit/processor.rb +0 -38
- data/spec/typekit/processor_spec.rb +0 -34
- data/spec/typekit/routing/map_spec.rb +0 -106
data/lib/typekit/helper.rb
CHANGED
@@ -22,6 +22,28 @@ module Typekit
|
|
22
22
|
Rack::Utils.build_nested_query(prepare_parameters(parameters))
|
23
23
|
end
|
24
24
|
|
25
|
+
def self.pluralize(name)
|
26
|
+
case name
|
27
|
+
when /^.*s$/
|
28
|
+
name
|
29
|
+
when /^(?<root>.*)y$/
|
30
|
+
"#{ Regexp.last_match(:root) }ies"
|
31
|
+
else
|
32
|
+
"#{ name }s"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.singularize(name)
|
37
|
+
case name
|
38
|
+
when /^(?<root>.*)ies$/
|
39
|
+
"#{ Regexp.last_match(:root) }y"
|
40
|
+
when /^(?<root>.*)s$/
|
41
|
+
Regexp.last_match(:root)
|
42
|
+
else
|
43
|
+
name
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
25
47
|
private
|
26
48
|
|
27
49
|
def self.prepare_parameters(parameters)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Typekit
|
2
|
+
module Processing
|
3
|
+
module Converter
|
4
|
+
class Errors
|
5
|
+
ERRORS = {
|
6
|
+
400 => 'There are errors in the data provided by your application',
|
7
|
+
401 => 'Authentication is needed to access the requested endpoint',
|
8
|
+
403 => 'Your application has been rate limited',
|
9
|
+
404 => 'You are requesting a resource that does not exist',
|
10
|
+
500 => 'The servers of Typekit are unable to process the request',
|
11
|
+
503 => 'The Typekit API is offline for maintenance'
|
12
|
+
}
|
13
|
+
ERRORS.default = 'Unknown server error'
|
14
|
+
ERRORS.freeze
|
15
|
+
|
16
|
+
def process(response, errors)
|
17
|
+
raise Error, Array(errors || ERRORS[response.code]).join(', ')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Typekit
|
2
|
+
module Processing
|
3
|
+
module Converter
|
4
|
+
class Record
|
5
|
+
def initialize(name)
|
6
|
+
@klass = Typekit::Record.const_get(name.to_s.capitalize)
|
7
|
+
end
|
8
|
+
|
9
|
+
def process(response, attributes)
|
10
|
+
@klass.new(attributes)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Typekit
|
2
|
+
module Processing
|
3
|
+
module Converter
|
4
|
+
class Records
|
5
|
+
def initialize(name)
|
6
|
+
name = Helper.singularize(name.to_s).capitalize
|
7
|
+
@klass = Typekit::Record.const_get(name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def process(response, attribute_collection)
|
11
|
+
attribute_collection.map do |attributes|
|
12
|
+
@klass.new(attributes)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'converter/record'
|
2
|
+
require_relative 'converter/records'
|
3
|
+
require_relative 'converter/boolean'
|
4
|
+
require_relative 'converter/datetime'
|
5
|
+
require_relative 'converter/errors'
|
6
|
+
require_relative 'converter/unknown'
|
7
|
+
|
8
|
+
module Typekit
|
9
|
+
module Processing
|
10
|
+
module Converter
|
11
|
+
MAPPING = {
|
12
|
+
'ok' => Boolean,
|
13
|
+
'errors' => Errors,
|
14
|
+
'published' => DateTime
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
def self.build(name)
|
18
|
+
if MAPPING.key?(name)
|
19
|
+
MAPPING[name].new
|
20
|
+
elsif Typekit::Record.collection?(name)
|
21
|
+
Records.new(name)
|
22
|
+
elsif Typekit::Record.member?(name)
|
23
|
+
Record.new(name)
|
24
|
+
else
|
25
|
+
Unknown.new(name)
|
26
|
+
end
|
27
|
+
rescue NameError
|
28
|
+
raise Error, 'Unknown converter'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'parser/json'
|
2
|
+
require_relative 'parser/yaml'
|
3
|
+
|
4
|
+
module Typekit
|
5
|
+
module Processing
|
6
|
+
module Parser
|
7
|
+
def self.build(format)
|
8
|
+
self.const_get(format.to_s.upcase).new
|
9
|
+
rescue NameError
|
10
|
+
raise Error, 'Unknown format'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Typekit
|
2
|
+
module Processing
|
3
|
+
class Translator
|
4
|
+
def initialize(format:)
|
5
|
+
@parser = Parser.build(format)
|
6
|
+
end
|
7
|
+
|
8
|
+
def process(response)
|
9
|
+
data = @parser.process(response.body) rescue nil
|
10
|
+
data = { nil => nil } unless data.is_a?(Hash) && data.length == 1
|
11
|
+
name, object = *data.first
|
12
|
+
Converter.build(name).process(response, object)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Typekit
|
4
|
+
module Record
|
5
|
+
class Base
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
attr_reader :attributes
|
9
|
+
def_delegator :attributes, :to_json
|
10
|
+
|
11
|
+
def initialize(attributes = {})
|
12
|
+
@attributes = Hash[attributes.map { |k, v| [ k.to_sym, v ] }]
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(name, *arguments)
|
16
|
+
if name.to_s =~ /^(?<name>.*)=$/
|
17
|
+
name = Regexp.last_match(:name).to_sym
|
18
|
+
return super unless arguments.length == 1
|
19
|
+
return super unless @attributes.key?(name)
|
20
|
+
@attributes[name] = arguments.first
|
21
|
+
else
|
22
|
+
return super unless arguments.length.zero?
|
23
|
+
return super unless @attributes.key?(name)
|
24
|
+
@attributes[name]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_relative 'record/base'
|
2
|
+
require_relative 'record/family'
|
3
|
+
require_relative 'record/variation'
|
4
|
+
require_relative 'record/kit'
|
5
|
+
require_relative 'record/library'
|
6
|
+
|
7
|
+
module Typekit
|
8
|
+
module Record
|
9
|
+
def self.classes
|
10
|
+
@classes ||= ObjectSpace.each_object(Class).select do |klass|
|
11
|
+
klass < Base
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.collections
|
16
|
+
@collections ||= members.map(&:to_s).map do |name|
|
17
|
+
Helper.pluralize(name.to_s)
|
18
|
+
end.map(&:to_sym)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.members
|
22
|
+
@members ||= classes.map(&:to_s).map(&:downcase).map do |name|
|
23
|
+
name.sub(/^.*::/, '')
|
24
|
+
end.map(&:to_sym)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.collection?(name)
|
28
|
+
collections.include?(name.to_sym)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.member?(name)
|
32
|
+
members.include?(name.to_sym)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/typekit/routing.rb
CHANGED
data/lib/typekit/version.rb
CHANGED
data/lib/typekit.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
require_relative 'typekit/version'
|
2
|
-
require_relative 'typekit/core'
|
3
2
|
|
3
|
+
require_relative 'typekit/core'
|
4
4
|
require_relative 'typekit/helper'
|
5
5
|
require_relative 'typekit/configuration'
|
6
6
|
|
7
|
-
require_relative 'typekit/connection'
|
8
7
|
require_relative 'typekit/routing'
|
8
|
+
require_relative 'typekit/connection'
|
9
|
+
require_relative 'typekit/processing'
|
9
10
|
|
10
|
-
require_relative 'typekit/
|
11
|
-
require_relative 'typekit/processor'
|
11
|
+
require_relative 'typekit/record'
|
12
12
|
|
13
13
|
require_relative 'typekit/client'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: delete
|
5
|
+
uri: https://typekit.com/api/v1/json/kits/xxx
|
6
|
+
response:
|
7
|
+
status:
|
8
|
+
code: 200
|
9
|
+
message: OK
|
10
|
+
headers:
|
11
|
+
Status:
|
12
|
+
- 200 OK
|
13
|
+
body:
|
14
|
+
encoding: UTF-8
|
15
|
+
string: '{"ok":true}'
|
16
|
+
recorded_at: Fri, 30 May 2014 00:00:00 GMT
|
data/spec/typekit/client_spec.rb
CHANGED
@@ -9,9 +9,9 @@ describe Typekit::Client do
|
|
9
9
|
context 'when successful' do
|
10
10
|
options = { vcr: { cassette_name: 'index_kits_ok' } }
|
11
11
|
|
12
|
-
it 'returns
|
12
|
+
it 'returns Records', options do
|
13
13
|
result = subject.index(:kits)
|
14
|
-
expect(result).to
|
14
|
+
expect(result.map(&:class).uniq).to eq([ Typekit::Record::Kit ])
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -20,7 +20,7 @@ describe Typekit::Client do
|
|
20
20
|
|
21
21
|
it 'raises exceptions', options do
|
22
22
|
expect { subject.index(:kits) }.to \
|
23
|
-
raise_error(Typekit::Error, /
|
23
|
+
raise_error(Typekit::Processing::Error, /Not authorized/i)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -33,4 +33,12 @@ describe Typekit::Client do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
36
|
+
|
37
|
+
describe '#delete' do
|
38
|
+
options = { vcr: { cassette_name: 'delete_kits_xxx_ok' } }
|
39
|
+
|
40
|
+
it 'returns true', options do
|
41
|
+
expect(subject.delete(:kits, 'xxx')).to be(true)
|
42
|
+
end
|
43
|
+
end
|
36
44
|
end
|
@@ -25,10 +25,26 @@ describe Typekit::Configuration do
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
describe 'Base
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
describe 'Base' do
|
29
|
+
describe '#mapper' do
|
30
|
+
it 'returns a Mapper' do
|
31
|
+
expect(build(:default, token: 'nekot').mapper).to \
|
32
|
+
be_kind_of(Typekit::Routing::Mapper)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#dispatcher' do
|
37
|
+
it 'returns a Dispatcher' do
|
38
|
+
expect(build(:default, token: 'nekot').dispatcher).to \
|
39
|
+
be_kind_of(Typekit::Connection::Dispatcher)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#translator' do
|
44
|
+
it 'returns a Translator' do
|
45
|
+
expect(build(:default, token: 'nekot').translator).to \
|
46
|
+
be_kind_of(Typekit::Processing::Translator)
|
47
|
+
end
|
32
48
|
end
|
33
49
|
end
|
34
50
|
end
|
@@ -12,14 +12,14 @@ describe Typekit::Connection::Dispatcher do
|
|
12
12
|
double('Request', action: action, address: address, parameters: {})
|
13
13
|
end
|
14
14
|
|
15
|
-
describe '#
|
15
|
+
describe '#process' do
|
16
16
|
restful_actions.each do |action|
|
17
17
|
method = rest_http_dictionary[action]
|
18
18
|
|
19
19
|
context "when sending #{ action } Requests" do
|
20
20
|
it 'sets the token header' do
|
21
21
|
stub = stub_http_request(method, address)
|
22
|
-
response = subject.
|
22
|
+
response = subject.process(create_request(action))
|
23
23
|
expect(stub).to have_requested(method, address).
|
24
24
|
with(:headers => { 'X-Typekit-Token' => token })
|
25
25
|
end
|
@@ -27,8 +27,8 @@ describe Typekit::Connection::Dispatcher do
|
|
27
27
|
it 'returns Responses' do
|
28
28
|
stub_http_request(method, address).
|
29
29
|
to_return(code: '200', body: 'Hej!')
|
30
|
-
response = subject.
|
31
|
-
expect([ response.code, response.
|
30
|
+
response = subject.process(create_request(action))
|
31
|
+
expect([ response.code, response.body ]).to eq([ 200, 'Hej!' ])
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'typekit'
|
3
|
+
|
4
|
+
describe Typekit::Connection::Response do
|
5
|
+
let(:subject_class) { Typekit::Connection::Response }
|
6
|
+
|
7
|
+
def create(code: 200, body: '')
|
8
|
+
subject_class.new(code: code, body: body)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'is considered to be successful for HTTP OK' do
|
12
|
+
expect(create(code: 200)).to be_success
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'is considered to be successful for HTTP Found' do
|
16
|
+
expect(create(code: 302)).to be_success
|
17
|
+
end
|
18
|
+
end
|
data/spec/typekit/helper_spec.rb
CHANGED
@@ -38,6 +38,40 @@ describe Typekit::Helper do
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
describe '.pluralize' do
|
42
|
+
{
|
43
|
+
'kit' => 'kits',
|
44
|
+
'kits' => 'kits',
|
45
|
+
'family' => 'families',
|
46
|
+
'families' => 'families',
|
47
|
+
'library' => 'libraries',
|
48
|
+
'libraries' => 'libraries',
|
49
|
+
'variant' => 'variants',
|
50
|
+
'variants' => 'variants'
|
51
|
+
}.each do |k, v|
|
52
|
+
it "returns #{ v } for #{ k }" do
|
53
|
+
expect(subject_module.pluralize(k)).to eq(v)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '.singularize' do
|
59
|
+
{
|
60
|
+
'kit' => 'kit',
|
61
|
+
'kits' => 'kit',
|
62
|
+
'family' => 'family',
|
63
|
+
'families' => 'family',
|
64
|
+
'library' => 'library',
|
65
|
+
'libraries' => 'library',
|
66
|
+
'variant' => 'variant',
|
67
|
+
'variants' => 'variant'
|
68
|
+
}.each do |k, v|
|
69
|
+
it "returns #{ v } for #{ k }" do
|
70
|
+
expect(subject_module.singularize(k)).to eq(v)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
41
75
|
describe '.build_query' do
|
42
76
|
it 'handels ordinary parameters' do
|
43
77
|
queries = [
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'typekit'
|
3
|
+
|
4
|
+
describe Typekit::Processing::Converter do
|
5
|
+
def create(name)
|
6
|
+
Typekit::Processing::Converter.build(name)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:request) { double(code: 200) }
|
10
|
+
|
11
|
+
describe '.build#process' do
|
12
|
+
%w{family kit library}.each do |name|
|
13
|
+
it "maps '#{ name }' to a Record" do
|
14
|
+
result = create(name).process(request, {})
|
15
|
+
expect(result).to be_kind_of(Typekit::Record::Base)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
%w{families kits libraries}.each do |name|
|
20
|
+
it "maps '#{ name }' to an array of Records" do
|
21
|
+
result = create(name).process(request, [ {} ])
|
22
|
+
result.each { |r| expect(r).to be_kind_of(Typekit::Record::Base) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
%w{ok}.each do |name|
|
27
|
+
it "maps '#{ name }' to a boolean" do
|
28
|
+
result = create(name).process(request, true)
|
29
|
+
expect(result).to be_kind_of(::TrueClass)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
%w{published}.each do |name|
|
34
|
+
it "maps '#{ name }' to a datetime" do
|
35
|
+
result = create(name).process(request, '2010-05-20T21:15:31Z')
|
36
|
+
expect(result).to be_kind_of(::DateTime)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
[ nil, 'errors' ].each do |name|
|
41
|
+
it "raises an exception for '#{ name }'" do
|
42
|
+
expect { create(name).process(request, nil) }.to \
|
43
|
+
raise_error(Typekit::Processing::Error)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
%w{kittens puppies}.each do |name|
|
48
|
+
it "returns unknowns like '#{ name }' as they are" do
|
49
|
+
result = create(name).process(request, 42)
|
50
|
+
expect(result).to be(42)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'typekit'
|
3
|
+
|
4
|
+
describe Typekit::Processing::Parser do
|
5
|
+
let(:subject_class) { Typekit::Processing::Parser }
|
6
|
+
|
7
|
+
it 'supports JSON' do
|
8
|
+
subject = subject_class.build(:json)
|
9
|
+
result = subject.process('{ "kits": [] }')
|
10
|
+
expect(result).to eq("kits" => [])
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'supports YAML' do
|
14
|
+
subject = subject_class.build(:yaml)
|
15
|
+
result = subject.process("---\nkits: []")
|
16
|
+
expect(result).to eq("kits" => [])
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'does not support XML' do
|
20
|
+
expect { subject_class.build(:xml) }.to \
|
21
|
+
raise_error(Typekit::Processing::Error, /Unknown format/i)
|
22
|
+
end
|
23
|
+
end
|