typekit-client 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +5 -3
  3. data/.travis.yml +4 -0
  4. data/.yardopts +6 -0
  5. data/CHANGELOG.md +12 -0
  6. data/Guardfile +21 -3
  7. data/README.md +253 -248
  8. data/bin/typekit-client +16 -16
  9. data/bin/typekit-publisher +6 -5
  10. data/lib/typekit.rb +6 -2
  11. data/lib/typekit/client.rb +66 -24
  12. data/lib/typekit/collection.rb +6 -11
  13. data/lib/typekit/collection/base.rb +40 -0
  14. data/lib/typekit/collection/serialization.rb +17 -0
  15. data/lib/typekit/converter.rb +26 -0
  16. data/lib/typekit/converter/boolean.rb +12 -0
  17. data/lib/typekit/converter/collection.rb +13 -0
  18. data/lib/typekit/converter/datetime.rb +12 -0
  19. data/lib/typekit/converter/element.rb +13 -0
  20. data/lib/typekit/converter/errors.rb +12 -0
  21. data/lib/typekit/converter/unknown.rb +13 -0
  22. data/lib/typekit/core.rb +8 -10
  23. data/lib/typekit/element.rb +27 -0
  24. data/lib/typekit/element/association.rb +63 -0
  25. data/lib/typekit/element/base.rb +61 -0
  26. data/lib/typekit/element/persistence.rb +61 -0
  27. data/lib/typekit/element/query.rb +25 -0
  28. data/lib/typekit/element/serialization.rb +17 -0
  29. data/lib/typekit/error.rb +23 -0
  30. data/lib/typekit/helper.rb +59 -10
  31. data/lib/typekit/record.rb +18 -22
  32. data/lib/typekit/record/family.rb +24 -1
  33. data/lib/typekit/record/kit.rb +29 -1
  34. data/lib/typekit/record/library.rb +4 -1
  35. data/lib/typekit/record/variation.rb +13 -1
  36. data/lib/typekit/version.rb +1 -1
  37. data/spec/feature/create_kit_spec.rb +52 -0
  38. data/spec/feature/delete_kit_spec.rb +33 -0
  39. data/spec/feature/index_kits_spec.rb +55 -0
  40. data/spec/feature/publish_kit_spec.rb +15 -0
  41. data/spec/feature/show_family_spec.rb +75 -0
  42. data/spec/feature/show_kit_spec.rb +56 -0
  43. data/spec/feature/show_library_spec.rb +29 -0
  44. data/spec/feature/show_variation_spec.rb +18 -0
  45. data/spec/feature/update_kit_spec.rb +88 -0
  46. data/spec/fixture/cassette/create_kits_bad.yml +16 -0
  47. data/spec/fixture/cassette/create_kits_ok.yml +16 -0
  48. data/spec/fixture/cassette/delete_kits_xxx_not_found.yml +13 -0
  49. data/spec/{cassettes → fixture/cassette}/delete_kits_xxx_ok.yml +0 -3
  50. data/spec/fixture/cassette/index_kits_show_kit_xxx_ok.yml +25 -0
  51. data/spec/{cassettes → fixture/cassette}/index_kits_unauthorized.yml +0 -3
  52. data/spec/{cassettes → fixture/cassette}/show_families_xxx_found.yml +0 -3
  53. data/spec/{cassettes → fixture/cassette}/show_families_xxx_ok.yml +0 -3
  54. data/spec/{cassettes → fixture/cassette}/show_families_xxx_yyy_ok.yml +0 -3
  55. data/spec/fixture/cassette/show_families_yyy_update_kits_xxx_families_ok.yml +35 -0
  56. data/spec/fixture/cassette/show_kits_xxx_families_yyy_show_family_yyy_ok.yml +45 -0
  57. data/spec/fixture/cassette/show_kits_xxx_not_found.yml +13 -0
  58. data/spec/fixture/cassette/show_kits_xxx_show_family_yyy_ok.yml +46 -0
  59. data/spec/{cassettes → fixture/cassette}/show_libraries_xxx_ok.yml +0 -3
  60. data/spec/fixture/cassette/update_kits_xxx_empty_families_ok.yml +16 -0
  61. data/spec/fixture/cassette/update_kits_xxx_families_ok.yml +18 -0
  62. data/spec/fixture/cassette/update_kits_xxx_families_variations_ok.yml +18 -0
  63. data/spec/fixture/cassette/update_kits_xxx_name_ok.yml +17 -0
  64. data/spec/fixture/cassette/update_kits_xxx_publish_ok.yml +16 -0
  65. data/spec/fixture/record/article.rb +11 -0
  66. data/spec/fixture/record/section.rb +10 -0
  67. data/spec/lib/typekit/collection_spec.rb +22 -0
  68. data/spec/{typekit/processing → lib/typekit}/converter_spec.rb +13 -13
  69. data/spec/lib/typekit/element/association_spec.rb +96 -0
  70. data/spec/lib/typekit/element/base_spec.rb +70 -0
  71. data/spec/lib/typekit/element/persistence_spec.rb +97 -0
  72. data/spec/lib/typekit/element/serialization_spec.rb +28 -0
  73. data/spec/lib/typekit/element_spec.rb +58 -0
  74. data/spec/{typekit → lib/typekit}/helper_spec.rb +6 -8
  75. data/spec/lib/typekit/record_spec.rb +57 -0
  76. data/spec/spec_helper.rb +10 -3
  77. data/spec/support/common_helper.rb +5 -0
  78. data/spec/support/record_helper.rb +38 -0
  79. data/typekit-client.gemspec +11 -4
  80. metadata +164 -58
  81. data/lib/typekit/processing.rb +0 -8
  82. data/lib/typekit/processing/converter.rb +0 -28
  83. data/lib/typekit/processing/converter/boolean.rb +0 -14
  84. data/lib/typekit/processing/converter/collection.rb +0 -18
  85. data/lib/typekit/processing/converter/datetime.rb +0 -14
  86. data/lib/typekit/processing/converter/errors.rb +0 -24
  87. data/lib/typekit/processing/converter/record.rb +0 -16
  88. data/lib/typekit/processing/converter/unknown.rb +0 -15
  89. data/lib/typekit/processing/translator.rb +0 -13
  90. data/lib/typekit/record/base.rb +0 -52
  91. data/spec/cassettes/index_kits_ok.yml +0 -16
  92. data/spec/cassettes/show_kits_xxx_families_yyy_ok.yml +0 -16
  93. data/spec/cassettes/show_kits_xxx_ok.yml +0 -17
  94. data/spec/features/client/delete_kit_spec.rb +0 -13
  95. data/spec/features/client/index_kits_spec.rb +0 -25
  96. data/spec/features/client/show_family_spec.rb +0 -47
  97. data/spec/features/client/show_kit_spec.rb +0 -18
  98. data/spec/features/client/show_library_spec.rb +0 -18
  99. data/spec/features/client/show_variation_spec.rb +0 -22
  100. data/spec/support/resource_helper.rb +0 -34
  101. data/spec/typekit/record/base_spec.rb +0 -85
  102. data/spec/typekit/record_spec.rb +0 -80
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
 
5
6
  require 'typekit'
6
7
  require 'readline'
@@ -11,42 +12,41 @@ class Controller
11
12
  ACTIONS = %w{index show create update delete}
12
13
  KEYWORDS = %w{families kits libraries published publish}
13
14
 
14
- def initialize(**options)
15
- @client = Typekit::Client.new(**options)
15
+ def initialize(options)
16
+ @client = Typekit::Client.new(options)
16
17
  end
17
18
 
18
19
  def process(command)
19
20
  action, path, parameters = parse(command)
20
- print @client.perform(action, path, parameters)
21
+ print @client.process(action, path, parameters)
21
22
  rescue Exception => e
22
23
  puts e
23
24
  end
24
25
 
25
26
  def help
26
27
  puts <<-HELP
27
- Usage: <action> <resource> [parameters]
28
+ Usage: <action> <endpoint> [parameters]
28
29
 
29
30
  <action> index, show, create, update, or delete
30
- <resource> a list separated by whitespaces
31
+ <endpoint> a list separated by whitespaces
31
32
  [parameters] a JSON-encoded hash (optional)
32
33
 
33
34
  Examples:
34
35
  index kits
35
- show kits bas4cfe families vcsm
36
- show families vcsm i9
37
- show libraries trial { "page": 10, "per_page": 5 }
38
- create kits { "name": "Megakit", "domains": "localhost" }
39
- update kits bas4cfe { "name": "Ultrakit" }
36
+ create kits { "name": "Megakit", domains: ["localhost"] }
37
+ show kits bas4cfe
38
+ update kits bas4cfe { families: [{ "id": "vybr" }] }
39
+ update kits bas4cfe publish
40
40
  delete kits bas4cfe
41
+ show families vybr i4
42
+ show libraries trial { "page": 10, "per_page": 5 }
41
43
  HELP
42
44
  end
43
45
 
44
46
  protected
45
47
 
46
48
  def print(output)
47
- puts JSON.pretty_generate(output)
48
- rescue JSON::GeneratorError
49
- puts output.to_s # neither hash nor array
49
+ puts JSON.pretty_generate(output, quirks_mode: true)
50
50
  end
51
51
 
52
52
  def parse(command)
@@ -59,7 +59,7 @@ HELP
59
59
  raise 'Invalid action name' unless ACTIONS.include?(action)
60
60
  raise 'Missing resource name' if path.empty?
61
61
 
62
- [ action, path, parameters ]
62
+ [action, path, parameters]
63
63
  end
64
64
 
65
65
  def extract_parameters!(command)
@@ -132,7 +132,7 @@ puts %{Type 'help' for help and 'exit' to exit.}
132
132
 
133
133
  COMMANDS = Controller::ACTIONS + Controller::KEYWORDS + %w{help exit}
134
134
  Readline.completion_proc = proc do |input|
135
- COMMANDS.grep(/^#{ Regexp.escape(input) }/)
135
+ COMMANDS.grep(/^#{Regexp.escape(input)}/)
136
136
  end
137
137
 
138
138
  loop do
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
3
+ lib = File.expand_path('../../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
 
5
6
  require 'typekit'
6
7
  require 'readline'
@@ -59,9 +60,9 @@ kits = process(:index, :kits)
59
60
 
60
61
  puts 'Which kit would you like to publish?'
61
62
  kits.each_with_index do |kit, i|
62
- puts "%4d. %s" % [ i + 1, kit.id ]
63
+ puts "%4d. %s" % [i + 1, kit.id]
63
64
  end
64
- puts "%4d. all" % [ kits.length + 1 ]
65
+ puts "%4d. all" % [kits.length + 1]
65
66
 
66
67
  k = Readline.readline('> ')
67
68
  if k.nil? || k.empty?
@@ -76,10 +77,10 @@ if k < 1 || k > kits.length + 1
76
77
  exit
77
78
  end
78
79
 
79
- range = k == kits.length + 1 ? 0...kits.length : [ k - 1 ]
80
+ range = k == kits.length + 1 ? 0...kits.length : [k - 1]
80
81
 
81
82
  range.each do |i|
82
- print "Publishing #{ kits[i].id }..."
83
+ print "Publishing #{kits[i].id}..."
83
84
  process(:update, :kits, kits[i].id, :publish)
84
85
  puts ' Done.'
85
86
  end
@@ -2,12 +2,16 @@ require 'forwardable'
2
2
  require 'apitizer'
3
3
 
4
4
  require_relative 'typekit/core'
5
+ require_relative 'typekit/error'
5
6
  require_relative 'typekit/helper'
6
7
 
7
- require_relative 'typekit/processing'
8
+ require_relative 'typekit/converter'
8
9
 
10
+ require_relative 'typekit/client'
11
+
12
+ require_relative 'typekit/element'
9
13
  require_relative 'typekit/collection'
14
+
10
15
  require_relative 'typekit/record'
11
- require_relative 'typekit/client'
12
16
 
13
17
  require_relative 'typekit/version'
@@ -1,40 +1,82 @@
1
1
  module Typekit
2
- class Client
3
- extend Forwardable
2
+ module Client
3
+ def self.new(options)
4
+ raise Error, 'Token is missing' unless options.key?(:token)
4
5
 
5
- def_delegator :translator, :process, :translate
6
+ client = Module.new
7
+ client.extend(InstanceMethods)
8
+ client.configure(Typekit.defaults.merge(options))
6
9
 
7
- def initialize(**options)
8
- @options = Typekit.defaults.merge(options)
9
- raise Error, 'Token is missing' unless @options.key?(:token)
10
+ client
10
11
  end
11
12
 
12
- [ :process, :index, :show, :create, :update, :delete ].each do |method|
13
- define_method(method) do |*arguments|
14
- translate(engine.send(method, *arguments))
13
+ module InstanceMethods
14
+ [:process, :index, :show, :create, :update, :delete].each do |method|
15
+ define_method(method) do |*arguments|
16
+ translate(engine.send(method, *arguments))
17
+ end
15
18
  end
16
- end
17
- alias_method :perform, :process
18
19
 
19
- private
20
+ def configure(options)
21
+ self.options = options
22
+ end
20
23
 
21
- def engine
22
- @engine ||= build_engine
23
- end
24
+ private
25
+
26
+ attr_accessor :options
27
+
28
+ def engine
29
+ @engine ||= build_engine
30
+ end
31
+
32
+ def build_engine
33
+ engine_options = options.merge(dictionary: Typekit.dictionary,
34
+ headers: Typekit.headers.call(options[:token]))
35
+
36
+ version = options[:version]
37
+ format = options[:format]
38
+
39
+ Apitizer::Base.new(engine_options) do
40
+ instance_exec(version, format, &Typekit.schema)
41
+ end
42
+ end
24
43
 
25
- def translator
26
- @translator ||= Processing::Translator.new
44
+ def translate(result)
45
+ unless result.is_a?(Hash) && result.length == 1
46
+ raise ServerError.new(result.code)
47
+ end
48
+ name, object = *result.first
49
+ converter(name).process(result, object)
50
+ end
51
+
52
+ def const_missing(name)
53
+ record_class(name)
54
+ end
55
+
56
+ def converter(name)
57
+ (@converters ||= {})[name] ||= Converter.build(name, self)
58
+ end
59
+
60
+ def record_class(name)
61
+ (@record_classes ||= {})[name] ||= Record.build(name, self)
62
+ end
27
63
  end
28
64
 
29
- def build_engine
30
- version = @options[:version]
31
- format = @options[:format]
65
+ module Proxy
66
+ attr_reader :client, :token
67
+
68
+ def connect(object = nil, token = Helper.tokenize(self.class))
69
+ self.client = object.respond_to?(:client) ? object.client : object
70
+ self.token = token
71
+ end
72
+
73
+ private
32
74
 
33
- options = @options.merge(dictionary: Typekit.dictionary,
34
- headers: Typekit.headers.call(@options[:token]))
75
+ attr_writer :client, :token
35
76
 
36
- Apitizer::Base.new(**options) do
37
- instance_exec(version, format, &Typekit.schema)
77
+ def process(action, *arguments)
78
+ raise Error, 'Client is not specified' if client.nil?
79
+ client.process(action, token, *arguments)
38
80
  end
39
81
  end
40
82
  end
@@ -1,15 +1,10 @@
1
- module Typekit
2
- class Collection
3
- extend Forwardable
4
-
5
- def_delegator :@records, :to_json
6
- def_delegators :@records, :each, :map, :[], :size, :length
1
+ require_relative 'collection/serialization'
2
+ require_relative 'collection/base'
7
3
 
8
- def initialize(name, collection_attributes = nil)
9
- @klass = Record.classify(name)
10
- @records = collection_attributes.map do |attributes|
11
- @klass.new(attributes)
12
- end
4
+ module Typekit
5
+ module Collection
6
+ def self.build(name, *arguments)
7
+ Base.new(name, *arguments)
13
8
  end
14
9
  end
15
10
  end
@@ -0,0 +1,40 @@
1
+ module Typekit
2
+ module Collection
3
+ class Base
4
+ extend Forwardable
5
+ include Enumerable
6
+
7
+ include Client::Proxy
8
+
9
+ include Serialization
10
+
11
+ def_delegators :elements, :to_ary, :to_a, :to_json,
12
+ :[], :each, :size, :length, :empty?, :delete
13
+ def_delegator :klass, :feature?
14
+
15
+ def initialize(name, *arguments)
16
+ objects = Helper.extract_array!(arguments)
17
+
18
+ @elements = []
19
+ @klass = Element.classify(name)
20
+ connect(arguments.first, name)
21
+
22
+ objects.each { |object| push(object) }
23
+ end
24
+
25
+ def push(object)
26
+ if object.is_a?(klass)
27
+ object.connect(self)
28
+ elements << object
29
+ else
30
+ elements << klass.new(self, object)
31
+ end
32
+ end
33
+ alias_method :<<, :push
34
+
35
+ private
36
+
37
+ attr_reader :elements, :klass
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ module Typekit
2
+ module Collection
3
+ module Serialization
4
+ def serialize
5
+ result = nil
6
+
7
+ if klass.feature?(:serialization)
8
+ result = elements.map(&:serialize)
9
+ # FIXME: A nasty hack to empty collections.
10
+ result = '' if result.empty?
11
+ end
12
+
13
+ result
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'converter/element'
2
+ require_relative 'converter/collection'
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 Converter
10
+ MAPPING = {
11
+ :element => Element,
12
+ :collection => Collection,
13
+
14
+ 'ok' => Boolean,
15
+ 'errors' => Errors,
16
+ 'published' => DateTime,
17
+
18
+ nil => Errors
19
+ }
20
+ MAPPING.default = Unknown
21
+
22
+ def self.build(name, *arguments)
23
+ MAPPING[Record.identify(name) || name].new(name, *arguments)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ module Typekit
2
+ module Converter
3
+ class Boolean
4
+ def initialize(*)
5
+ end
6
+
7
+ def process(result, object)
8
+ object # already boolean
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Typekit
2
+ module Converter
3
+ class Collection
4
+ def initialize(*arguments)
5
+ @arguments = arguments
6
+ end
7
+
8
+ def process(result, collection_attributes)
9
+ Typekit::Collection.build(*@arguments, collection_attributes)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Typekit
2
+ module Converter
3
+ class DateTime
4
+ def initialize(*)
5
+ end
6
+
7
+ def process(result, object)
8
+ ::DateTime.parse(object)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Typekit
2
+ module Converter
3
+ class Element
4
+ def initialize(*arguments)
5
+ @arguments = arguments
6
+ end
7
+
8
+ def process(result, attributes)
9
+ Typekit::Element.build(*@arguments, attributes)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Typekit
2
+ module Converter
3
+ class Errors
4
+ def initialize(*)
5
+ end
6
+
7
+ def process(result, errors)
8
+ raise ServerError.new(result.code, Array(errors).join(', '))
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module Typekit
2
+ module Converter
3
+ class Unknown
4
+ def initialize(name, *)
5
+ @name = name
6
+ end
7
+
8
+ def process(result, object)
9
+ { @name => object }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,25 +1,23 @@
1
1
  module Typekit
2
- Error = Class.new(StandardError)
3
-
4
2
  @defaults = { version: 1, format: :json }
5
3
 
6
4
  @schema = Proc.new do |version, format|
7
- address "https://typekit.com/api/v#{ version }/#{ format }"
8
-
9
- resources :families, only: :show do
10
- show ':variation', on: :member
11
- end
5
+ address "https://typekit.com/api/v#{version}/#{format}"
12
6
 
13
7
  resources :kits do
14
- resources :families, only: [ :show, :update, :delete ]
8
+ resources :families, only: [:show, :update, :delete]
15
9
  show :published, on: :member
16
10
  update :publish, on: :member
17
11
  end
18
12
 
19
- resources :libraries, only: [ :index, :show ]
13
+ resources :families, only: :show do
14
+ show ':variation', on: :member
15
+ end
16
+
17
+ resources :libraries, only: [:index, :show]
20
18
  end
21
19
 
22
- @dictionary = { :update => :post } # not PUT
20
+ @dictionary = { :update => :post } # not PATCH
23
21
 
24
22
  @headers = Proc.new do |token|
25
23
  { 'X-Typekit-Token' => token }