├── Gemfile ├── Gemfile.lock ├── lib └── sinatra_static.rb ├── readme.rdoc └── sinatra-static.gemspec /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | gem 'sinatra' 3 | gem 'sinatra-advanced-routes' 4 | gem 'term-ansicolor' 5 | gem 'rack' 6 | gem 'rack-test' 7 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | backports (2.3.0) 5 | monkey-lib (0.5.4) 6 | backports 7 | rack (1.3.4) 8 | rack-protection (1.1.4) 9 | rack 10 | rack-test (0.6.1) 11 | rack (>= 1.0) 12 | sinatra (1.3.1) 13 | rack (>= 1.3.4, ~> 1.3) 14 | rack-protection (>= 1.1.2, ~> 1.1) 15 | tilt (>= 1.3.3, ~> 1.3) 16 | sinatra-advanced-routes (0.5.1) 17 | monkey-lib (~> 0.5.0) 18 | sinatra (~> 1.0) 19 | sinatra-sugar (~> 0.5.0) 20 | sinatra-sugar (0.5.1) 21 | monkey-lib (~> 0.5.0) 22 | sinatra (~> 1.0) 23 | term-ansicolor (1.0.7) 24 | tilt (1.3.3) 25 | 26 | PLATFORMS 27 | ruby 28 | 29 | DEPENDENCIES 30 | rack 31 | rack-test 32 | sinatra 33 | sinatra-advanced-routes 34 | term-ansicolor 35 | -------------------------------------------------------------------------------- /lib/sinatra_static.rb: -------------------------------------------------------------------------------- 1 | class SinatraStatic 2 | 3 | @@file_extensions = %w(css js xml json html csv) 4 | 5 | attr_accessor :app 6 | 7 | include Rack::Test::Methods 8 | 9 | require 'term/ansicolor' 10 | class ColorString < String 11 | include Term::ANSIColor 12 | end 13 | 14 | def initialize(app) 15 | @app = app 16 | end 17 | 18 | def build!(dir) 19 | handle_error_no_each_route! unless @app.respond_to?(:each_route) 20 | handle_error_dir_not_found!(dir) unless dir_exists?(dir) 21 | build_routes(dir) 22 | end 23 | 24 | private 25 | 26 | def build_routes(dir) 27 | @app.each_route do |route| 28 | next unless route.verb == 'GET' 29 | build_path(route.path, dir) 30 | end 31 | end 32 | 33 | def build_path(path, dir) 34 | ::FileUtils.mkdir_p(dir_for_path(path, dir)) 35 | ::File.open(file_for_path(path, dir), 'w+') do |f| 36 | f.write(get_path(path).body) 37 | end 38 | end 39 | 40 | def get_path(path) 41 | self.get(path).tap do |resp| 42 | handle_error_non_200!(path) unless resp.status == 200 43 | end 44 | end 45 | 46 | def file_for_path(path, dir) 47 | if path.match(/[^\/\.]+.(#{file_extensions.join("|")})$/) 48 | ::File.join(dir, path) 49 | else 50 | ::File.join(dir, path, 'index.html') 51 | end 52 | end 53 | 54 | def dir_exists?(dir) 55 | ::File.exists?(dir) && ::File.directory?(dir) 56 | end 57 | 58 | def dir_for_path(path, dir) 59 | file_for_path(path, dir).match(/(.*)\/[^\/]+$/)[1] 60 | end 61 | 62 | def file_extensions 63 | @@file_extensions 64 | end 65 | 66 | def env 67 | ENV['RACK_ENV'] 68 | end 69 | 70 | def handle_error_no_each_route! 71 | handle_error!("can't call app.each_route, did you include sinatra-advanced-routes?") 72 | end 73 | 74 | def handle_error_dir_not_found!(dir) 75 | handle_error!("can't find output directory: #{dir}") 76 | end 77 | 78 | def handle_error_non_200!(path) 79 | handle_error!("GET #{path} returned non-200 status code...") 80 | end 81 | 82 | def handle_error!(desc) 83 | puts ColorString.new("failed: #{desc}").red; exit! 84 | end 85 | 86 | end 87 | -------------------------------------------------------------------------------- /readme.rdoc: -------------------------------------------------------------------------------- 1 | = sinatra-static 2 | 3 | export your sinatra app to a directory of static files. requires "sinatra-advanced-routes". get requests and response-status 200 only (no redirects). you also have to copy the public-dir yourself (if you're using it). 4 | 5 | 6 | == usage 7 | 8 | require 'sinatra_static' 9 | 10 | builder = SinatraStatic.new(MySinatraApp) 11 | builder.build!('/Users/paul/my_static_site') 12 | 13 | 14 | = example 15 | 16 | this simple app: 17 | 18 | require 'sinatra' 19 | require "sinatra/advanced_routes" 20 | require 'sinatra_static' 21 | 22 | class MyApp::App < Sinatra::Base 23 | 24 | get '/' do 25 | "my homepage" 26 | end 27 | 28 | get '/blog' do 29 | "blog index" 30 | end 31 | 32 | get '/blog/ajax.html' do 33 | "blog index w/o layout" 34 | end 35 | 36 | %w(page1 page2 page3).each do |page| 37 | get "/blog/#{page}" do 38 | "blog page: #{page}" 39 | end 40 | end 41 | 42 | get '/dynamic.js' do 43 | "my generated javascript" 44 | end 45 | 46 | get '/data.json' do 47 | "my generated json" 48 | end 49 | 50 | end 51 | 52 | builder = SinatraStatic.new(MyApp:App) 53 | builder.build!('/Users/paul/my_static_site') 54 | 55 | 56 | will generate this output: 57 | 58 | ~/my_static_site/index.html -> "my homepage" 59 | ~/my_static_site/blog/index.html -> "blog index" 60 | ~/my_static_site/blog/ajax.html -> "blog index w/o layout" 61 | ~/my_static_site/blog/page1/index.html -> "blog page: page1" 62 | ~/my_static_site/blog/page2/index.html -> "blog page: page2" 63 | ~/my_static_site/blog/page3/index.html -> "blog page: page3" 64 | ~/my_static_site/dynamic.js -> "my generated javascript" 65 | ~/my_static_site/data.json -> "my generated json" 66 | 67 | 68 | = installation 69 | 70 | gem install sinatra-static 71 | 72 | or in your Gemfile 73 | 74 | gem 'sinatra-static', '>= 0.1.1' 75 | -------------------------------------------------------------------------------- /sinatra-static.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = "sinatra-static" 3 | s.version = "0.1.1" 4 | 5 | s.authors = ["Paul Asmuth"] 6 | s.date = "2011-10-16" 7 | s.description = "export your sinatra app to a directory of static files" 8 | s.email = "paul@paulasmuth.com" 9 | s.files = [ 10 | "Gemfile", 11 | "Gemfile.lock", 12 | "sinatra-static.gemspec", 13 | "lib/sinatra_static.rb", 14 | "readme.rdoc" 15 | ] 16 | s.homepage = "http://github.com/paulasmuth/sinatra-static" 17 | s.licenses = ["MIT"] 18 | s.require_paths = ["lib"] 19 | s.rubygems_version = "1.8.10" 20 | s.summary = "export your sinatra app to a directory of static files" 21 | 22 | if s.respond_to? :specification_version then 23 | s.specification_version = 3 24 | 25 | if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then 26 | s.add_runtime_dependency(%q, [">= 0"]) 27 | s.add_runtime_dependency(%q, [">= 0"]) 28 | s.add_runtime_dependency(%q, [">= 0"]) 29 | s.add_runtime_dependency(%q, [">= 0"]) 30 | s.add_runtime_dependency(%q, [">= 0"]) 31 | else 32 | s.add_dependency(%q, [">= 0"]) 33 | s.add_dependency(%q, [">= 0"]) 34 | s.add_dependency(%q, [">= 0"]) 35 | s.add_dependency(%q, [">= 0"]) 36 | s.add_dependency(%q, [">= 0"]) 37 | end 38 | else 39 | s.add_dependency(%q, [">= 0"]) 40 | s.add_dependency(%q, [">= 0"]) 41 | s.add_dependency(%q, [">= 0"]) 42 | s.add_dependency(%q, [">= 0"]) 43 | s.add_dependency(%q, [">= 0"]) 44 | end 45 | end 46 | 47 | --------------------------------------------------------------------------------