typekit 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +20 -0
- data/README.md +165 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/lib/typekit/base.rb +15 -0
- data/lib/typekit/client.rb +119 -0
- data/lib/typekit/family.rb +37 -0
- data/lib/typekit/kit.rb +147 -0
- data/lib/typekit/variation.rb +43 -0
- data/lib/typekit.rb +8 -0
- data/test/helper.rb +18 -0
- data/test/test_typekit.rb +7 -0
- metadata +129 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "shoulda", ">= 0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.5.2"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.5.2)
|
6
|
+
bundler (~> 1.0.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
rake (0.8.7)
|
10
|
+
rcov (0.9.9)
|
11
|
+
shoulda (2.11.3)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
bundler (~> 1.0.0)
|
18
|
+
jeweler (~> 1.5.2)
|
19
|
+
rcov
|
20
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Corey Ward
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
Typekit API Client
|
2
|
+
==================
|
3
|
+
|
4
|
+
This is a Ruby client for the [Typekit API](http://typekit.com/docs/api). **It is still in development**. Feel free to help out,
|
5
|
+
or just watch the project and check it out when it gets closer to completion. Any tips/pointers are much appreciated.
|
6
|
+
|
7
|
+
You can get in touch with me at `corey.atx.at.gmail.com`.
|
8
|
+
|
9
|
+
Example
|
10
|
+
-------
|
11
|
+
|
12
|
+
A quick example of how to use the client.
|
13
|
+
|
14
|
+
# Add FF Meta Web Pro to a Kit with Normal and Bold weights
|
15
|
+
typekit = Typekit::Client.new(token)
|
16
|
+
kit = typekit.kit('abcdef')
|
17
|
+
kit.add_family(typekit.family_by_name('FF Meta Web Pro').id, :variations => ['n4', 'n7'])
|
18
|
+
kit.publish
|
19
|
+
|
20
|
+
# Change the name of a kit and add a domain
|
21
|
+
kit.name = 'Example'
|
22
|
+
kit.domains << 'localhost'
|
23
|
+
kit.save
|
24
|
+
|
25
|
+
# Get the web address to Droid Sans
|
26
|
+
typekit.family_by_slug('droid-sans').web_link
|
27
|
+
|
28
|
+
Usage
|
29
|
+
-----
|
30
|
+
|
31
|
+
You'll need a Typekit account and a Typekit API token to use the Typekit API. You can generate a new token
|
32
|
+
[here](https://typekit.com/account/tokens). You should also familiarize yourself with the
|
33
|
+
[terminology](http://typekit.com/docs/api/terminology) that the Typekit API uses and the way [changes are published](http://typekit.com/docs/api/kits).
|
34
|
+
|
35
|
+
There are two ways you can work with the Typekit API client: directly through the class variables, or via an
|
36
|
+
instance of the `Typekit::Client` object. Either way, beware that the token you provide will be assigned to
|
37
|
+
a class variable (ie. it'll be shared across instances of Typekit::Client). This is due to the way HTTParty works.
|
38
|
+
|
39
|
+
### Getting Started
|
40
|
+
|
41
|
+
# Getting down to business...
|
42
|
+
typekit = Typekit::Client.new(token)
|
43
|
+
|
44
|
+
# Get a list of kits in your account
|
45
|
+
kits = typekit.kits #=> [<Typekit::Kit @id='abcdef'>, <Typekit::Kit @id='ghijkl', ...]
|
46
|
+
|
47
|
+
# Get detailed information for a kit by ID
|
48
|
+
typekit.kit('abcdef')
|
49
|
+
#=> <Typekit::Kit @id='abcdef', @name='Test', @analytics=false, @badge=false, @domains=['localhost'], @families=[...]>
|
50
|
+
|
51
|
+
### Using the API without an instance of Typekit::Client
|
52
|
+
|
53
|
+
# If you prefer using the class methods directly, the following is identical to the above methods...
|
54
|
+
Typekit::Client.set_token(token)
|
55
|
+
Typekit::Kit.all #=> [<Typekit::Kit @id='abcdef'>, <Typekit::Kit @id='ghijkl', ...]
|
56
|
+
Typekit::Kit.find('abcdef') #=> <Typekit::Kit @id='abcdef', @name="Test", ...>
|
57
|
+
|
58
|
+
### Lazy Loaded Detailed Attributes
|
59
|
+
|
60
|
+
Detailed information for kits gets loaded lazily when you use `Typekit::Kit.all`. This allows us to create instances
|
61
|
+
of `Typekit::Kit` without the full set of attributes and without requiring you to manually load that data.
|
62
|
+
|
63
|
+
kits = typekits.all #=> [...]
|
64
|
+
kits.first #=> <Typekit::Kit @id='abcdef'>
|
65
|
+
kits.first.name #=> "Test"
|
66
|
+
kits.first #=> <Typekit::Kit @id='abcdef', @name='Test', @analytics=false, @badge=false, @domains=['localhost'], @families=[]>
|
67
|
+
|
68
|
+
### Updating a Kit
|
69
|
+
|
70
|
+
You can make changes to a Kit by altering the attributes and calling `save`:
|
71
|
+
|
72
|
+
kit = typekit.kit('abcdef')
|
73
|
+
kit.name = 'Derezzed'
|
74
|
+
kit.domains << 'localhost'
|
75
|
+
kit.save
|
76
|
+
|
77
|
+
#### Publishing Manually
|
78
|
+
|
79
|
+
When you call `Typekit::Kit#save`, the kit is also published. If you don't want this to happen, pass `false` as the only argument. You can also manually publish a Kit after making changes.
|
80
|
+
|
81
|
+
kit.name = 'Fashion Nugget'
|
82
|
+
kit.save(false)
|
83
|
+
# ... later in your application, possibly even in another request
|
84
|
+
kit = Typekit::Client.kit('abcdef')
|
85
|
+
kit.publish #=> Finally, changes are published to the Typekit CDN
|
86
|
+
|
87
|
+
### Getting Font Family Information
|
88
|
+
|
89
|
+
The Typekit API also allows you to find detailed information about any Family in their library, including all available
|
90
|
+
validations, CSS font names, etc. **If you are not familiar with the terminology Typekit uses throughout their API, you
|
91
|
+
really should [give it a read](http://typekit.com/docs/api/terminology) before continuing.**
|
92
|
+
|
93
|
+
# Get a family by ID
|
94
|
+
family = typekit.family('brwr')
|
95
|
+
|
96
|
+
# Get a family by slug
|
97
|
+
family = typekit.family_by_slug('ff-meta-web-pro')
|
98
|
+
|
99
|
+
# Get a family by name (gets converted to a slug automatically)
|
100
|
+
family = typekit.family_by_name('FF Meta Web Pro')
|
101
|
+
|
102
|
+
# List variations available for a given family
|
103
|
+
family.variations #=> [<Typekit::Variation ...>, <Typekit::Variation ...>, ...]
|
104
|
+
|
105
|
+
# Get a particular variation (details lazy-loaded)
|
106
|
+
variation = typekit.family('brwr').variation('n4') #=> <Typekit::Variation @id="brwr:n4", @name="FF Meta Web Pro Normal">
|
107
|
+
|
108
|
+
# View details about a variation
|
109
|
+
variation.font_weight #=> "400"
|
110
|
+
variation.to_fvd #=> "n4"
|
111
|
+
variation #=> <Typekit::Variation @id="brwr:n4", @name="FF Meta Web Pro Normal", @font_weight="400", ...>
|
112
|
+
|
113
|
+
**Note**: Variations, like Kits, have detailed information loaded lazily. If you would like to load data for a Variation
|
114
|
+
without accessing an individual attribute you can simply call `Typekit::Variation#fetch`.
|
115
|
+
|
116
|
+
### Adding a Family to a Kit
|
117
|
+
|
118
|
+
You can add Families to a kit by specifying the Family ID (which can be found through the `Typekit::Family` methods) and
|
119
|
+
which you want to have included in the Kit. These methods *make changes to the "working" copy* of your Kit. In order for them
|
120
|
+
to take effect, **you must publish your Kit after adding/updating/removing Families**.
|
121
|
+
|
122
|
+
# Add a new Family with the full character subset
|
123
|
+
kit = typekit.kit('abcdef')
|
124
|
+
kit.add_family('brwr', :variations => ['n4'], :subset => 'all')
|
125
|
+
|
126
|
+
# Changing a Family that is already a part of a Kit
|
127
|
+
kit.update_family('brwr') do |f|
|
128
|
+
f['subset'] = 'default'
|
129
|
+
f['variations'] << 'i7'
|
130
|
+
end
|
131
|
+
|
132
|
+
# Removing a Variation from a Family in your a Kit
|
133
|
+
kit.update_family('brwr') do |f|
|
134
|
+
f['variations'].delete_if { |v| v == 'n4' }
|
135
|
+
end
|
136
|
+
|
137
|
+
# Remove a Family from a Kit
|
138
|
+
kit.delete_family('brwr')
|
139
|
+
|
140
|
+
# Publishing your changes
|
141
|
+
kit.publish
|
142
|
+
|
143
|
+
**Important Note**: Families and Variations that are a part of Kits are passed around as Hashes, not instances of `Typekit::Family` or
|
144
|
+
`Typekit::Variation`, which are used solely browse the available Families and their details.
|
145
|
+
|
146
|
+
Documentation
|
147
|
+
-------------
|
148
|
+
|
149
|
+
Full documentation for the latest version can be found at [RubyDoc](http://rubydoc.info/github/coreyward/typekit).
|
150
|
+
|
151
|
+
Contributing
|
152
|
+
------------
|
153
|
+
|
154
|
+
* Fork the project
|
155
|
+
* Start a feature/bugfix branch
|
156
|
+
* Add [yard](http://yardoc.org/)-compatible documentation for your changes, where relevant. Follow the existing styles.
|
157
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
158
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
159
|
+
|
160
|
+
Copyright
|
161
|
+
---------
|
162
|
+
|
163
|
+
Copyright (c) 2011 Corey Ward. Licensed under the "MIT" license. See LICENSE.txt for
|
164
|
+
further details.
|
165
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "typekit"
|
16
|
+
gem.homepage = "http://github.com/coreyward/typekit"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %{Ruby library for accessing the Typekit REST API.}
|
19
|
+
gem.description = %{Ruby library for accessing the Typekit REST API.}
|
20
|
+
gem.email = "corey.atx@gmail.com"
|
21
|
+
gem.authors = ["Corey Ward"]
|
22
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
23
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
25
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
26
|
+
gem.add_dependency 'httparty', '~> 0.7.3'
|
27
|
+
end
|
28
|
+
Jeweler::RubygemsDotOrgTasks.new
|
29
|
+
|
30
|
+
require 'rake/testtask'
|
31
|
+
Rake::TestTask.new(:test) do |test|
|
32
|
+
test.libs << 'lib' << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
|
37
|
+
require 'rcov/rcovtask'
|
38
|
+
Rcov::RcovTask.new do |test|
|
39
|
+
test.libs << 'test'
|
40
|
+
test.pattern = 'test/**/test_*.rb'
|
41
|
+
test.verbose = true
|
42
|
+
end
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "typekit #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.0
|
data/lib/typekit/base.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Typekit
|
2
|
+
# Contains mass assignment functionality for building objects out of hashes.
|
3
|
+
# @abstract
|
4
|
+
module MassAssignment
|
5
|
+
def initialize(attributes = {})
|
6
|
+
mass_assign(attributes)
|
7
|
+
end
|
8
|
+
|
9
|
+
def mass_assign(attributes)
|
10
|
+
attributes.each do |attribute, value|
|
11
|
+
respond_to?(:"#{attribute}=") && send(:"#{attribute}=", value)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Typekit
|
2
|
+
class Client
|
3
|
+
include HTTParty
|
4
|
+
base_uri 'https://typekit.com/api/v1/json'
|
5
|
+
|
6
|
+
# @param token [String] Your Typekit API token
|
7
|
+
def initialize(token)
|
8
|
+
set_token token
|
9
|
+
end
|
10
|
+
|
11
|
+
# Rather than making laborious calls to `Typekit::Client.kits` you can create an instance
|
12
|
+
# of the {Typekit::Client} and call methods on it. Instance methods will be defined for
|
13
|
+
# class methods on their first utilization.
|
14
|
+
# @example
|
15
|
+
# typekit = Typekit::Client.new('your token here')
|
16
|
+
# typekit.kits #=> [...]
|
17
|
+
def method_missing(method, *args, &block)
|
18
|
+
super unless self.class.respond_to? method
|
19
|
+
self.class.class_eval do
|
20
|
+
define_method method do |*args, &block|
|
21
|
+
self.class.send(method, *args, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
self.class.send(method, *args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
# Handle responses from HTTParty calls to the Typekit API with
|
29
|
+
# some generic response interpretation and manipulation.
|
30
|
+
# @todo Add individual errors for various HTTP Status codes
|
31
|
+
def handle_response(response)
|
32
|
+
status = response.headers['status'].to_i
|
33
|
+
|
34
|
+
case status
|
35
|
+
when 404 then raise ResourceDoesNotExistError, response
|
36
|
+
when 400..499 then raise APIError, response
|
37
|
+
when 500..599 then raise ServiceError, response
|
38
|
+
end
|
39
|
+
|
40
|
+
response.values.first if response.values.any?
|
41
|
+
end
|
42
|
+
private :handle_response
|
43
|
+
|
44
|
+
# Handle all HTTParty responses with some error handling so that our
|
45
|
+
# individual methods don't have to worry about it at all (although they)
|
46
|
+
# can (and should where relevant) rescue from errors when they are able to.
|
47
|
+
[:get, :head, :post, :put, :delete].each do |http_verb|
|
48
|
+
define_method http_verb do |*args|
|
49
|
+
handle_response super(*args)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Set the Typekit API token to be used for subsequent calls.
|
54
|
+
# @note This is set to a class variable, so all instances of Typekit::Client
|
55
|
+
# will use the same API token. This is due to the way HTTParty works.
|
56
|
+
# @param token [String] Your Typekit API token
|
57
|
+
# @todo Work around the class variable limitation of HTTParty to allow use of
|
58
|
+
# the API with multiple tokens.
|
59
|
+
def set_token(token)
|
60
|
+
headers 'X-Typekit-Token' => token
|
61
|
+
end
|
62
|
+
|
63
|
+
# List kits available for this account
|
64
|
+
# @see Typekit::Kit.all
|
65
|
+
def kits
|
66
|
+
Kit.all
|
67
|
+
end
|
68
|
+
|
69
|
+
# Retrieve a specific kit
|
70
|
+
# @see Typekit::Kit.find
|
71
|
+
def kit(id)
|
72
|
+
Kit.find id
|
73
|
+
end
|
74
|
+
|
75
|
+
# Create a new kit
|
76
|
+
# @see Typekit::Kit.create
|
77
|
+
def create_kit(params)
|
78
|
+
Kit.create(params)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Retrieve a specific Family
|
82
|
+
# @see Typekit::Family.find
|
83
|
+
# @param id [String] The Typekit Family id (e.g. 'brwr' or 'gkmg')
|
84
|
+
def family(id)
|
85
|
+
Family.find(id)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Retrieve a Family by Typekit slug
|
89
|
+
# @see Typekit::Family.find_by_slug
|
90
|
+
# @param slug [String] The Typekit Family slug for the font family (e.g. 'ff-meta-web-pro' or 'droid-sans')
|
91
|
+
def family_by_slug(slug)
|
92
|
+
Family.find_by_slug(slug)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Retrieve a Family by font family name
|
96
|
+
# @see Typekit::Family.find_by_name
|
97
|
+
# @param name [String] The name of the font family without variation (e.g. 'FF Meta Web Pro' or 'Droid Sans')
|
98
|
+
def family_by_name(name)
|
99
|
+
Family.find_by_name(name)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# @todo Put this somewhere better than Typekit::Client
|
104
|
+
class APIError < ArgumentError
|
105
|
+
attr_reader :response
|
106
|
+
|
107
|
+
def initialize(response)
|
108
|
+
@response = response
|
109
|
+
end
|
110
|
+
|
111
|
+
def to_s
|
112
|
+
@response['errors'].first if @response['errors'].any?
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class ResourceDoesNotExistError < APIError; end
|
117
|
+
class ServiceError < APIError; end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Typekit
|
2
|
+
class Family
|
3
|
+
include MassAssignment
|
4
|
+
attr_accessor :id, :name, :slug, :web_link, :description, :foundry, :variations, :libraries
|
5
|
+
# Typekit::Family.new isn't expected usage
|
6
|
+
private :initialize
|
7
|
+
|
8
|
+
# Find a variation in this Family by the Font Variation Description
|
9
|
+
# @param id [String] Family/Font variation ID/Description (e.g. n4 or i7)
|
10
|
+
def variation(id)
|
11
|
+
variations.select { |v| v.id.split(':').last == id }.first
|
12
|
+
end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# Retrieve a specific Family
|
16
|
+
# @param id [String] The Typekit Family id (e.g. 'brwr' or 'gkmg')
|
17
|
+
def find(id)
|
18
|
+
family = Family.new Client.get("/families/#{id}")
|
19
|
+
family.variations.map! { |v| Variation.send(:new, v) }
|
20
|
+
family
|
21
|
+
end
|
22
|
+
|
23
|
+
# Retrieve a Family by Typekit slug
|
24
|
+
# @param slug [String] The Typekit Family slug for the font family (e.g. 'ff-meta-web-pro' or 'droid-sans')
|
25
|
+
# @todo Add error handling
|
26
|
+
def find_by_slug(slug)
|
27
|
+
find(Client.get("/families/#{slug}")['id'])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Retrieve a Family by font family name
|
31
|
+
# @param name [String] The name of the font family without variation (e.g. 'FF Meta Web Pro' or 'Droid Sans')
|
32
|
+
def find_by_name(name)
|
33
|
+
find_by_slug name.downcase.gsub(/[^a-z]+/, '-')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/typekit/kit.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
module Typekit
|
2
|
+
# @todo Get information for a specific family in the kit (/kits/:kit/families/:family)
|
3
|
+
class Kit
|
4
|
+
include MassAssignment
|
5
|
+
|
6
|
+
# Detailed information about a kit. Lazy loaded when accessed unless
|
7
|
+
# the data already exists.
|
8
|
+
# @see Kit#fetch
|
9
|
+
attr_accessor :name, :domains, :families, :analytics, :badge
|
10
|
+
|
11
|
+
# Typekit-defined kit id
|
12
|
+
attr_accessor :id
|
13
|
+
protected :id=
|
14
|
+
|
15
|
+
# Typekit::Kit.new isn't expected usage
|
16
|
+
private :initialize
|
17
|
+
|
18
|
+
# @todo Allow users to change defaults easily
|
19
|
+
@@defaults = { :analytics => false, :badge => false }
|
20
|
+
|
21
|
+
class << self
|
22
|
+
# Find a kit by id (*not* by name)
|
23
|
+
# @param id [String] Typekit Kit ID (can be found via {Kit.all})
|
24
|
+
def find(id)
|
25
|
+
kit = Kit.new(:id => id)
|
26
|
+
kit.reload
|
27
|
+
kit
|
28
|
+
end
|
29
|
+
|
30
|
+
# Get a list of all of the kits available for this Typekit account
|
31
|
+
# @todo Support pagination
|
32
|
+
def all
|
33
|
+
Client.get('/kits').inject([]) do |kits, attributes|
|
34
|
+
kits << Kit.new(attributes)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Create a new kit
|
39
|
+
# @param params [Hash] Attributes for the newly create kit
|
40
|
+
# @option params [String] :name Required: The name of the kit
|
41
|
+
# @option params [Array] :domains Required: An array of the domains that this kit will be used on
|
42
|
+
# @option params [Boolean] :analytics (false) Allow Typekit to collect kit-usage data via Google Analytics
|
43
|
+
# @option params [Boolean] :badge (false) Show the Typekit colophon badge on websites using this kit
|
44
|
+
def create(params)
|
45
|
+
params = @@defaults.merge(params)
|
46
|
+
response = Client.post("/kits", :query => params)
|
47
|
+
Kit.new(response)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def lazy_load(*attributes)
|
52
|
+
attributes.each do |attribute|
|
53
|
+
define_method :"#{attribute}" do
|
54
|
+
instance_variable_defined?("@#{attribute}") ? instance_variable_get("@#{attribute}") : fetch(attribute)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Lazy load extended information only when it's accessed
|
61
|
+
lazy_load :name, :analytics, :badge, :domains, :families
|
62
|
+
|
63
|
+
# Get detailed information about this kit from Typekit
|
64
|
+
# @note This is called lazily when you access any non-loaded attribute
|
65
|
+
# and doesn't need to be called manually unless you want to reload the
|
66
|
+
# data. This means we can return an array of Kit objects for {Kit.all}
|
67
|
+
# without making N+1 requests to the API.
|
68
|
+
# @param attribute [Symbol] Optionally return a single attribute after data is loaded
|
69
|
+
# @return Returns @attribute if attribute argument is specified; otherwise returns self
|
70
|
+
def fetch(attribute = nil)
|
71
|
+
mass_assign Client.get("/kits/#{@id}")
|
72
|
+
attribute ? instance_variable_get("@#{attribute}") : self
|
73
|
+
end
|
74
|
+
alias :reload :fetch
|
75
|
+
|
76
|
+
# Save kit attributes like name and domains. This does *not* alter the families
|
77
|
+
# added to the kit.
|
78
|
+
# @param publish_after_save [Boolean] Commit changes saved to the published kit. See {#publish}.
|
79
|
+
# @return [Boolean] Status of the operation (including the publishing, if it is called)
|
80
|
+
def save(publish_after_save = true)
|
81
|
+
attributes = [:name, :analytics, :badge, :domains].inject({}) { |attributes, x| attributes[x] = instance_variable_get("@#{x}"); attributes }
|
82
|
+
result = mass_assign Client.post("/kits/#{@id}", :query => attributes)
|
83
|
+
published = publish if publish_after_save
|
84
|
+
|
85
|
+
# For the parenthesized statement, true && true or false && false are acceptable.
|
86
|
+
# but xor does the exact opposite, so we negate it.
|
87
|
+
result && !(publish_after_save ^ published)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Typekit maintains the changes you have made to a Kit in a "working" state
|
91
|
+
# until you specify that it is ready to be published. After the state has been
|
92
|
+
# changed to "published" your kit will be queued to be pushed out to their CDN
|
93
|
+
# and served to new requests. This can take up to 5 minutes when they are under
|
94
|
+
# heavy load.
|
95
|
+
# @return [Time] The date & time that the kit was last published
|
96
|
+
def publish
|
97
|
+
Client.post("/kits/#{@id}/publish")
|
98
|
+
end
|
99
|
+
|
100
|
+
# Delete a kit from Typekit
|
101
|
+
# @note Typekit does not have this functionality in their API at this time. When they do,
|
102
|
+
# the `raise` call in this method can be removed, along with this warning.
|
103
|
+
# @raise An error, always, telling you this doesn't work.
|
104
|
+
def delete
|
105
|
+
raise "The Typekit API does not support deleting a kit at this time."
|
106
|
+
Client.delete("/kits/#{@id}")
|
107
|
+
end
|
108
|
+
alias :destroy :delete
|
109
|
+
|
110
|
+
# Add a family to this kit (does not publish changes)
|
111
|
+
# @param id [String] Typekit Font Family id (e.g. 'brwr')
|
112
|
+
# @param params [Hash] Attributes for the family to be added
|
113
|
+
# @option params [Array] :variations ([]) Font Variation Descriptions ('n4', 'i7', etc.) for the variations to be included
|
114
|
+
# @option params [String] :subset ('default') Character subset to be served ('all' or 'default')
|
115
|
+
# @return [Boolean] True on success; error raised on failure
|
116
|
+
def add_family(id, params = {})
|
117
|
+
params = { :variations => [], :subset => 'default' }.merge(params)
|
118
|
+
!!Client.post("/kits/#{@id}/families/#{id}", :query => params)
|
119
|
+
end
|
120
|
+
|
121
|
+
# Update a family on this kit (does not publish changes)
|
122
|
+
# @param id [String] Typekit Font Family id (e.g. 'brwr')
|
123
|
+
# @param [Block] A block manipulating the family attributes
|
124
|
+
# @yieldparam [Hash] family The existing definition for this family
|
125
|
+
# @example Updating a font family
|
126
|
+
# Typekit::Kit.update_family('abcdef') do |family|
|
127
|
+
# family['subset'] = 'all'
|
128
|
+
# family['variations'] << 'i3'
|
129
|
+
# end
|
130
|
+
# @return [Boolean] True on success; error raised on failure
|
131
|
+
def update_family(id)
|
132
|
+
raise 'Block required' unless block_given?
|
133
|
+
family = Client.get("/kits/#{@id}/families/#{id}")
|
134
|
+
yield family
|
135
|
+
family.keep_if { |k,v| %w{variations subset}.include? k }
|
136
|
+
!!Client.post("/kits/#{@id}/families/#{id}", :query => family)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Delete a family from this kit (does not publish changes)
|
140
|
+
# @param id [String] Typekit Font Family id (e.g. 'brwr')
|
141
|
+
# @return [Boolean] True on success; error raised on failure
|
142
|
+
def delete_family(id)
|
143
|
+
!!Client.delete("/kits/#{@id}/families/#{id}")
|
144
|
+
end
|
145
|
+
alias :remove_family :delete_family
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Typekit
|
2
|
+
# @todo Move lazy loading into a module
|
3
|
+
class Variation
|
4
|
+
include MassAssignment
|
5
|
+
attr_accessor :id, :name, :font_style, :font_variant, :font_weight, :foundry, :libraries, :postscript_name
|
6
|
+
|
7
|
+
# Typekit::Variation.new isn't expected usage
|
8
|
+
private :initialize
|
9
|
+
|
10
|
+
class << self
|
11
|
+
private
|
12
|
+
def lazy_load(*attributes)
|
13
|
+
attributes.each do |attribute|
|
14
|
+
define_method :"#{attribute}" do
|
15
|
+
instance_variable_defined?("@#{attribute}") ? instance_variable_get("@#{attribute}") : fetch(attribute)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
lazy_load :font_style, :font_variant, :font_weight, :foundry, :libraries, :postscript_name
|
22
|
+
|
23
|
+
# Get detailed information about this Family Variation from Typekit
|
24
|
+
# @note This is called lazily when you access any non-loaded attribute
|
25
|
+
# and doesn't need to be called manually unless you want to reload the
|
26
|
+
# data. This means we can return an array of Variation objects for {Family#variations}
|
27
|
+
# without making N+1 requests to the API.
|
28
|
+
# @param attribute [Symbol] Optionally return a single attribute after data is loaded
|
29
|
+
# @return Returns @attribute if attribute argument is specified; otherwise returns self
|
30
|
+
def fetch(attribute)
|
31
|
+
family_id, variation_id = @id.split(':')
|
32
|
+
mass_assign Client.get("/families/#{family_id}/#{variation_id}")
|
33
|
+
attribute ? instance_variable_get("@#{attribute}") : self
|
34
|
+
end
|
35
|
+
alias :reload :fetch
|
36
|
+
|
37
|
+
# Convert the variation name to the Font Variation Description for adding it to a Kit
|
38
|
+
# @return [String] Font Variation ID (e.g. 'n4' or 'i7')
|
39
|
+
def to_fvd
|
40
|
+
name.split(':').last
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/typekit.rb
ADDED
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'typekit'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: typekit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.2.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Corey Ward
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-02-12 00:00:00 -06:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: shoulda
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :development
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 1.0.0
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: jeweler
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.5.2
|
46
|
+
type: :development
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rcov
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: httparty
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ~>
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 0.7.3
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: *id005
|
71
|
+
description: Ruby library for accessing the Typekit REST API.
|
72
|
+
email: corey.atx@gmail.com
|
73
|
+
executables: []
|
74
|
+
|
75
|
+
extensions: []
|
76
|
+
|
77
|
+
extra_rdoc_files:
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
files:
|
81
|
+
- .document
|
82
|
+
- Gemfile
|
83
|
+
- Gemfile.lock
|
84
|
+
- LICENSE.txt
|
85
|
+
- README.md
|
86
|
+
- Rakefile
|
87
|
+
- VERSION
|
88
|
+
- lib/typekit.rb
|
89
|
+
- lib/typekit/base.rb
|
90
|
+
- lib/typekit/client.rb
|
91
|
+
- lib/typekit/family.rb
|
92
|
+
- lib/typekit/kit.rb
|
93
|
+
- lib/typekit/variation.rb
|
94
|
+
- test/helper.rb
|
95
|
+
- test/test_typekit.rb
|
96
|
+
has_rdoc: true
|
97
|
+
homepage: http://github.com/coreyward/typekit
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 1490713961465430856
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
version: "0"
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: "0"
|
120
|
+
requirements: []
|
121
|
+
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 1.5.2
|
124
|
+
signing_key:
|
125
|
+
specification_version: 3
|
126
|
+
summary: Ruby library for accessing the Typekit REST API.
|
127
|
+
test_files:
|
128
|
+
- test/helper.rb
|
129
|
+
- test/test_typekit.rb
|