Permalink
Browse files

Initial import

  • Loading branch information...
0 parents commit 7410f54f6ec4f4735e1ef9b0e8b7ab2c2c195b26 @colszowka committed Mar 27, 2011
@@ -0,0 +1,4 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in rack-fontserve.gemspec
+gemspec
@@ -0,0 +1,11 @@
+require 'bundler'
+Bundler::GemHelper.install_tasks
+
+require 'rake/testtask'
+Rake::TestTask.new(:test) do |test|
+ test.libs << 'lib' << 'test'
+ test.pattern = 'test/**/test_*.rb'
+ test.verbose = true
+end
+
+task :default => :test
@@ -0,0 +1,61 @@
+require 'sinatra/base'
+
+module Rack
+ class Fontserve < Sinatra::Base
+ class InvalidFontError < StandardError; end;
+ class InvalidFormatError < StandardError; end;
+ autoload :Font, 'rack-fontserve/font'
+
+ CONTENT_TYPES = {'ttf' => 'font/truetype',
+ 'otf' => 'font/opentype',
+ 'woff' => 'font/woff',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'svg' => 'image/svg+xml',
+ 'css' => 'text/css;charset=utf-8'}
+
+ set :max_age, 365 * 24 * 60 * 60
+ set :views, ::File.join(::File.dirname(__FILE__), 'rack-fontserve/views')
+
+ not_found do
+ [404, '']
+ end
+
+ error(InvalidFontError) { not_found }
+ error(InvalidFormatError) { not_found }
+
+ helpers do
+ def set_content_type(format)
+ headers['Content-Type'] = CONTENT_TYPES[format.to_s]
+ end
+
+ def set_cache
+ headers 'Cache-Control' => "public, max-age=#{Rack::Fontserve.max_age}",
+ 'Expires' => (Time.now + Rack::Fontserve.max_age).httpdate,
+ 'Access-Control-Allow-Origin' => '*'
+ end
+
+ def format?(f)
+ @font.formats.include?(f.to_s)
+ end
+ end
+
+ get '/demo' do
+ erb :demo
+ end
+
+ get '/:font_name.css' do
+ @font = Font.new(params[:font_name])
+ set_content_type :css
+ set_cache
+ erb :stylesheet
+ end
+
+ get '/:font_name.:format' do
+ @font = Font.new(params[:font_name])
+ @data = open(@font.format_path(params[:format]))
+ set_content_type(params[:format])
+ set_cache
+ @data.read
+ end
+ end
+end
@@ -0,0 +1,38 @@
+class Rack::Fontserve::Font
+ attr_reader :name
+
+ def self.all
+ Dir[File.join(Rack::Fontserve.fonts_path.to_s, '*')].map do |path|
+ begin
+ new(File.basename(path))
+ rescue Rack::Fontserve::InvalidFontError
+ nil
+ end
+ end.compact
+ end
+
+ def initialize(name)
+ @name = File.basename(name) # Ensure we remove any path sections that might get burned into here
+ raise Rack::Fontserve::InvalidFontError unless valid?
+ end
+
+ def path
+ @path ||= File.join(Rack::Fontserve.fonts_path, name)
+ end
+
+ def formats
+ @formats ||= Dir[File.join(path, "#{name}.{otf,svg,ttf,woff,eot}")].map {|file| File.extname(file)[1..-1] }.sort
+ end
+
+ def format_path(format)
+ raise Rack::Fontserve::InvalidFormatError unless formats.include?(format)
+ File.join(path, "#{name}.#{format}")
+ end
+
+ private
+
+ def valid?
+ formats.count > 0
+ end
+
+end
@@ -0,0 +1,5 @@
+# Define it as a plain constant instead of Bundler best-practice of
+# Rack::Fontserve::VERSION since Fontserve is a class that inherits from Sinatra::Base
+# and we'd be getting Superclass mismatch errors here since Sinatra is
+# unavailable when evaluating this file standalone, i.e. in Rakefile
+FONTSERVE_VERSION = '0.0.1'
@@ -0,0 +1,33 @@
+<html>
+<head>
+ <title>rack-fontserve demo</title>
+<% Font.all.each do |font| %>
+ <link rel="stylesheet" src="/<%= font.name %>.css?nocache=<%= rand(500000000) * rand(5000)/(rand(2000)+3)+5 %>"/>
+<% end %>
+ <style type="text/css">
+ body {
+ text-align: center;
+ font-size: 180%;
+ background: #ddd;
+ padding-top: 35px;
+ font-family: Helvetica, "Helvetica Neue", Arial, sans-serif;
+ }
+ h1,h2,h3 {
+ text-shadow: white 1px 1px 1px;
+ }
+
+ <% Font.all.each do |font| %>
+ .<%= font.name %> { font-family: '<%= font.name %>', Helvetica, Arial, sans-serif; }
+ <% end %>
+
+ </style>
+</head>
+<body>
+ <h1>rack-fontserve</h1>
+ <% Font.all.each do |font| %>
+ <h2 class="<%= font.name %>"><%= font.name %></h2>
+ <div class="<%= font.name %>">The quick brown fox jumps over the lazy dog (possibly)</div>
+ <% end %>
+</body>
+</html>
+
@@ -0,0 +1,13 @@
+@font-face {
+ font-family: '<%= @font.name %>';
+ <% if format?('eot') %>src: url('<%= url("#{@font.name}.eot") %>');<% end %>
+ src: local('☺'),
+ <% if format?('eot') %>url('<%= url("#{@font.name}.eot?iefix") %>') format('eot'), <% end %>
+ <% if format?('woff') %>url('<%= url("#{@font.name}.woff") %>') format('woff'), <% end %>
+ <% if format?('ttf') %>url('<%= url("#{@font.name}.ttf") %>') format('truetype'), <% end %>
+ <% if format?('otf') %>url('<%= url("#{@font.name}.otf") %>') format('opentype'), <% end %>
+ <% if format?('svg') %>url('<%= url("#{@font.name}.svg#webfont") %>') format('svg'), <% end %>
+ local('☺');
+ font-weight: normal;
+ font-style: normal;
+}
@@ -0,0 +1,26 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "rack-fontserve/version"
+
+Gem::Specification.new do |s|
+ s.name = "rack-fontserve"
+ s.version = FONTSERVE_VERSION
+ s.platform = Gem::Platform::RUBY
+ s.authors = ["Christoph Olszowka"]
+ s.email = ["christoph (at) olszowka de"]
+ s.homepage = "https://github.com/colszowka/rack-fontserve"
+ s.summary = %q{Sinatra app for serving web fonts easily with proper caching and access-control headers}
+ s.description = %q{Sinatra app for serving web fonts easily with proper caching and access-control headers}
+
+ s.rubyforge_project = "rack-fontserve"
+
+ s.add_dependency 'sinatra', "~> 1.2.1"
+
+ s.add_development_dependency 'rack-test', "~> 0.5.7"
+ s.add_development_dependency 'shoulda', "~> 2.11.3"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+end
@@ -0,0 +1 @@
+foo
No changes.
No changes.
No changes.
No changes.
No changes.
No changes.
@@ -0,0 +1,90 @@
+ENV['RACK_ENV'] = 'test'
+require 'rubygems'
+require 'bundler/setup'
+require 'rack-fontserve'
+
+require 'test/unit'
+require 'shoulda'
+require 'rack/test'
+
+Rack::Fontserve.set :fonts_path, File.join(File.dirname(__FILE__), 'fixtures/fonts')
+
+class Test::Unit::TestCase
+ include Rack::Test::Methods
+
+ def app
+ Rack::Fontserve
+ end
+
+ # Shortcut for making requests
+ def self.request(http_method, path)
+ raise ArgumentError, "Must be get, post, put or delete" unless %w(get post put delete).include?(http_method)
+
+ context "#{http_method} '#{path}'" do
+ setup { self.send(http_method, path) }
+ yield
+ end
+ end
+
+ def self.get(path, &blk)
+ request('get', path, &blk)
+ end
+
+ def self.post(path, &blk)
+ request('post', path, &blk)
+ end
+
+ def self.should_respond_with(status)
+ should("respond with #{status}") { assert_equal status, last_response.status }
+ end
+
+ def self.should_set_content_type_for(format)
+ formats = {'ttf' => 'font/truetype',
+ 'otf' => 'font/opentype',
+ 'woff' => 'font/woff',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'svg' => 'image/svg+xml',
+ 'css' => 'text/css'
+ }
+ should_set_header 'Content-Type', formats[format.to_s]
+ end
+
+ def self.should_set_header(name, value)
+ should "set header '#{name}' to '#{value}'" do
+ assert_equal value, last_response.headers[name]
+ end
+ end
+
+ def self.should_set_caching
+ should_set_header 'Cache-Control', 'public, max-age=31536000'
+
+ should "have set 'Expires' to '#{(Time.now + Rack::Fontserve.max_age).httpdate}'" do
+ assert_equal((Time.now + Rack::Fontserve.max_age).httpdate, last_response.headers['Expires'])
+ end
+
+ should "have set 'Access-Control-Allow-Origin' to '*'" do
+ assert_equal '*', last_response.headers['Access-Control-Allow-Origin']
+ end
+ end
+
+ def self.should_not_set_caching
+ should "not have set 'Cache-Control' header" do
+ assert_nil last_response.headers['Cache-Control']
+ end
+
+ should "not have set 'Expires' header" do
+ assert_nil last_response.headers['Expires']
+ end
+
+ should "not have set 'Access-Control-Allow-Originl' header" do
+ assert_nil last_response.headers['Access-Control-Allow-Origin']
+ end
+ end
+
+ def self.should_have_rendered_css(filename)
+ should "have rendered the body as expected in fixtures/#{filename}.css" do
+ puts last_response.body
+ assert_equal File.read(File.join(File.dirname(__FILE__), 'fixtures', "#{filename}.css")), last_response.body
+ end
+ end
+end
@@ -0,0 +1,55 @@
+require 'helper'
+
+class FontTest < Test::Unit::TestCase
+ should "have a fonts path set" do
+ assert Rack::Fontserve.fonts_path =~ /fixtures\/fonts$/
+ end
+
+ context "Rack::Fontserve::Font.all" do
+ setup { @all = Rack::Fontserve::Font.all }
+ should("return 3 fonts") { assert_equal 3, @all.count }
+ should("have font 'SampleFont'") { assert @all.map(&:name).include?('SampleFont') }
+ should("have font 'AnotherFont'") { assert @all.map(&:name).include?('AnotherFont') }
+ should("have font 'SimpleFont'") { assert @all.map(&:name).include?('SimpleFont') }
+ end
+
+ context "the font 'AnotherFont'" do
+ setup { @font = Rack::Fontserve::Font.new('AnotherFont') }
+ should("have 4 formats") { assert_equal 4, @font.formats.count }
+ should("have formats otf, svg, ttf, woff") { assert_equal %w(otf svg ttf woff), @font.formats }
+
+ should "return fonts_path/AnotherFont/AnotherFont.otf for format_path('otf')" do
+ assert_equal File.join(Rack::Fontserve.fonts_path, 'AnotherFont/AnotherFont.otf'), @font.format_path('otf')
+ end
+
+ should "Rack::Fontserve::InvalidFontError for format_path('eot')" do
+ assert_raise Rack::Fontserve::InvalidFormatError do
+ @font.format_path('eot')
+ end
+ end
+ end
+
+ should "raise Rack::Fontserve::InvalidFontError when trying to load 'InvalidFont'" do
+ assert_raise Rack::Fontserve::InvalidFontError do
+ Rack::Fontserve::Font.new('InvalidFont')
+ end
+ end
+
+ should "raise Rack::Fontserve::InvalidFontError when trying to load 'MissingFont'" do
+ assert_raise Rack::Fontserve::InvalidFontError do
+ Rack::Fontserve::Font.new('MissingFont')
+ end
+ end
+
+ should "raise Rack::Fontserve::InvalidFontError when trying to load 'UnexistingFont'" do
+ assert_raise Rack::Fontserve::InvalidFontError do
+ Rack::Fontserve::Font.new('UnexistingFont')
+ end
+ end
+
+ should "raise Rack::Fontserve::InvalidFontError when trying to load 'FileFont'" do
+ assert_raise Rack::Fontserve::InvalidFontError do
+ Rack::Fontserve::Font.new('FileFont')
+ end
+ end
+end
Oops, something went wrong.

0 comments on commit 7410f54

Please sign in to comment.