tiny_site 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/tiny_site.rb +119 -0
- data/lib/tiny_site/version.rb +3 -0
- metadata +100 -0
data/lib/tiny_site.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'RedCloth'
|
3
|
+
require 'yaml'
|
4
|
+
require 'haml'
|
5
|
+
|
6
|
+
class TextileParts
|
7
|
+
def self.parse(tp, image_path='')
|
8
|
+
vars, *parts = tp.split(/^\+\+\+\+|\+\+\+\+$/)
|
9
|
+
|
10
|
+
vars = YAML.load(vars) || {}
|
11
|
+
parts = Hash[*parts]
|
12
|
+
parts.each{|k,v| parts[k] = textilize(v,image_path)}
|
13
|
+
|
14
|
+
return vars, parts
|
15
|
+
end
|
16
|
+
def self.textilize(string, image_path)
|
17
|
+
string.gsub!(%r{!([\w\d\-\._]+)!}){ |a| "!#{image_path}/#{$1}!" }
|
18
|
+
|
19
|
+
RedCloth.new(string).to_html
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class CachedHttpFile
|
24
|
+
def initialize(url, expires_in=3600)
|
25
|
+
@url, @expires_in = url, expires_in
|
26
|
+
end
|
27
|
+
|
28
|
+
def fetch
|
29
|
+
puts "fetching #{@url}"
|
30
|
+
@body = open(@url).read
|
31
|
+
store
|
32
|
+
return 200, @body
|
33
|
+
rescue OpenURI::HTTPError => error
|
34
|
+
puts "OpenURI::HTTPError: #{error.message}"
|
35
|
+
return error.message.to_i, nil
|
36
|
+
end
|
37
|
+
|
38
|
+
def cached?
|
39
|
+
self.class.files[@url] && self.class.files[@url][:expires_at] > Time.now
|
40
|
+
end
|
41
|
+
def cached
|
42
|
+
return 200, self.class.files[@url][:content]
|
43
|
+
end
|
44
|
+
|
45
|
+
def store
|
46
|
+
puts "storing body of #{@url}"
|
47
|
+
self.class.files[@url] = {:content => @body, :expires_at => Time.now + @expires_in}
|
48
|
+
end
|
49
|
+
|
50
|
+
def get
|
51
|
+
(cached? && cached) || fetch
|
52
|
+
end
|
53
|
+
|
54
|
+
class << self
|
55
|
+
def files
|
56
|
+
@files ||= {}
|
57
|
+
end
|
58
|
+
def get(url, expires_in=3600)
|
59
|
+
(new url, expires_in).get
|
60
|
+
end
|
61
|
+
def bust
|
62
|
+
puts 'busting cache'
|
63
|
+
@files = {}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class TinySite
|
69
|
+
def initialize(opts)
|
70
|
+
@file_path = opts[:file_path]
|
71
|
+
@image_path = opts[:image_path] || File.join(@file_path, 'images')
|
72
|
+
@cache_buster = opts[:cache_buster] || 'bust'
|
73
|
+
end
|
74
|
+
|
75
|
+
def remote_file_url_for(filename)
|
76
|
+
File.join @file_path, "#{filename}.textile"
|
77
|
+
end
|
78
|
+
|
79
|
+
def render
|
80
|
+
global_file_fetch_tread = Thread.new{
|
81
|
+
_, @global_file = CachedHttpFile.get remote_file_url_for('__global') } # get __global in background
|
82
|
+
@status, page_file = CachedHttpFile.get remote_file_url_for(@path)
|
83
|
+
_, page_file = CachedHttpFile.get remote_file_url_for(@status) if @status != 200
|
84
|
+
global_file_fetch_tread.join
|
85
|
+
|
86
|
+
global_vars, global_parts = TextileParts.parse @global_file, @image_path
|
87
|
+
page_vars, page_parts = TextileParts.parse page_file, @image_path
|
88
|
+
|
89
|
+
render_layout :global_vars => global_vars, :global_parts => global_parts,
|
90
|
+
:page_vars => page_vars, :page_parts => page_parts
|
91
|
+
end
|
92
|
+
|
93
|
+
def render_layout(params)
|
94
|
+
layout = params[:page_vars][:layout] || params[:global_vars][:layout] || 'layout'
|
95
|
+
|
96
|
+
puts "rendering layout '#{layout}'"
|
97
|
+
haml = Haml::Engine.new File.open("#{layout}.haml").read, :format => :html5
|
98
|
+
haml.render Object.new, params
|
99
|
+
end
|
100
|
+
|
101
|
+
def caching_header
|
102
|
+
return { 'Cache-Control' => 'public, max-age=3600' } unless @query_string == @cache_buster
|
103
|
+
|
104
|
+
CachedHttpFile.bust and return { 'Cache-Control' => 'no-cache' }
|
105
|
+
end
|
106
|
+
|
107
|
+
def call(env)
|
108
|
+
@path, @query_string = env['PATH_INFO'], env['QUERY_STRING']
|
109
|
+
@path = '/index' if @path == '/'
|
110
|
+
|
111
|
+
return [301, {'Location' => @path}, ''] if @path.gsub!(/\/$/,'')
|
112
|
+
|
113
|
+
body = render # render the body first to set @status
|
114
|
+
[@status, caching_header, body]
|
115
|
+
rescue => e
|
116
|
+
puts "#{e.class}: #{e.message} #{e.backtrace}"
|
117
|
+
[500, {}, 'Sorry, but something went wrong']
|
118
|
+
end
|
119
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tiny_site
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Niko Dittmann
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-02-27 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rack
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: RedCloth
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "0"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: haml
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rspec
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id004
|
60
|
+
description: A static small site engine with Heroku and DropBox in mind
|
61
|
+
email: mail+git@niko-dittmann.com
|
62
|
+
executables: []
|
63
|
+
|
64
|
+
extensions: []
|
65
|
+
|
66
|
+
extra_rdoc_files: []
|
67
|
+
|
68
|
+
files:
|
69
|
+
- lib/tiny_site/version.rb
|
70
|
+
- lib/tiny_site.rb
|
71
|
+
has_rdoc: true
|
72
|
+
homepage: http://github.com/niko/tiny_site
|
73
|
+
licenses: []
|
74
|
+
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
|
78
|
+
require_paths:
|
79
|
+
- lib
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: "0"
|
92
|
+
requirements: []
|
93
|
+
|
94
|
+
rubyforge_project: "[none]"
|
95
|
+
rubygems_version: 1.5.0
|
96
|
+
signing_key:
|
97
|
+
specification_version: 3
|
98
|
+
summary: A static small site engine with Heroku and DropBox in mind
|
99
|
+
test_files: []
|
100
|
+
|