typekit 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
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
@@ -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
@@ -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
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'httparty'
3
+
4
+ require 'typekit/base'
5
+ require 'typekit/client'
6
+ require 'typekit/variation'
7
+ require 'typekit/family'
8
+ require 'typekit/kit'
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
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestTypekit < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ 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