sitepack 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/README +9 -0
  2. data/lib/sitepack.rb +189 -0
  3. data/test.rb +75 -0
  4. metadata +85 -0
data/README ADDED
@@ -0,0 +1,9 @@
1
+ Sinatra Static Pages
2
+ --------------------
3
+
4
+ Sinatra makes websites easy, but when it's time to deploy running ruby can be a pain.
5
+
6
+ ContentPack makes it easy. Just export your sinatra application as static html and upload to any webserver - Done!
7
+
8
+ All the power of ruby, but really how many times are you changing that content and why can't you traverse your content store
9
+ before deploying. Do you really have so many pages you need a database for every request?
@@ -0,0 +1,189 @@
1
+ require 'stringio'
2
+ require 'pathname'
3
+
4
+ require 'hpricot'
5
+ require 'redcloth'
6
+ require 'erubis'
7
+
8
+ module SitePack
9
+ RackDefaultEnv = {
10
+ 'REQUEST_METHOD' => 'GET',
11
+ 'SCRIPT_NAME' => 'app.rb',
12
+ 'SERVER_NAME' => 'localhost',
13
+ 'SERVER_PORT' => 9999,
14
+ 'rack.url_scheme' => 'http',
15
+ 'rack.version' => [1,1],
16
+ 'rack.input' => StringIO.new,
17
+ 'rack.errors' => StringIO.new,
18
+ 'rack.run_once' => true,
19
+ 'rack.multiprocess' => false,
20
+ 'rack.multithread' => false
21
+ }.freeze
22
+
23
+ #
24
+ # Generate a static site using sinatra
25
+ #
26
+ # Given a content root folder, Builder will auto generate a site.
27
+ #
28
+ # builder = SitePack::Builder.new(MyAppKlass, 'mydomain.com', './site/')
29
+ #
30
+ # # walk all .xml files in the './content/' directory
31
+ # # calling builder.save with the computed path will
32
+ # # write out a rendered .html file into the ./site/ directory at the path
33
+ # # ./content/#{path}.html
34
+ #
35
+ # builder.content('./content/') do|path|
36
+ # builder.save(path)
37
+ # end
38
+ #
39
+ class Builder
40
+
41
+ def initialize(appklass, domain, sitedir)
42
+ @appklass = appklass
43
+ @domain = domain
44
+ @sitedir = sitedir
45
+ end
46
+
47
+ #
48
+ # yield each sub path of each content file within the content directory
49
+ # or return an array of all paths
50
+ #
51
+ def content(dir)
52
+ @content_dir = dir
53
+ dir_path = Pathname.new(File.expand_path(dir))
54
+ paths = Dir["#{dir}/**/**.xml"].map{|p| Pathname.new(File.expand_path(p)).relative_path_from(dir_path) }
55
+ paths.each {|p| yield p } if block_given?
56
+ @content_dir = nil
57
+ paths
58
+ end
59
+
60
+ #
61
+ # save a given path into the site output directory
62
+ #
63
+ def save(path)
64
+ doc = Hpricot.XML(File.read(File.expand_path(File.join(@content_dir, path))))
65
+ ext = doc.at(:page)['extension'] || 'html'
66
+
67
+ output_path = path.sub(/\.xml$/,".#{ext}")
68
+ file = "#{@sitedir}/#{output_path}"
69
+ url = "http://#{@domain}/#{output_path}"
70
+ env = RackDefaultEnv.dup
71
+ uri = URI.parse(url)
72
+ env['PATH_INFO'] = uri.path
73
+ env['QUERY_STRING'] = uri.query || ''
74
+ req = Rack::Request.new(env) #Rack::MockRequest.env_for(url, env)
75
+ status, headers, body = @appklass.call(req.env)
76
+ res = Rack::MockResponse.new(status, headers, body, req.env["rack.errors"].flush)
77
+
78
+ case status
79
+ when 200
80
+ puts "render: #{url} as #{file}"
81
+ FileUtils.mkdir_p(File.dirname(file)) unless File.exist?(File.dirname(file))
82
+ File.open(file,'wb') { |f| f << res.body }
83
+ return file
84
+ else
85
+ raise "error #{status} status code: #{status} when requesting: #{url}\n#{res.body}"
86
+ end
87
+ nil
88
+ end
89
+ end
90
+
91
+ #
92
+ # enable content by including this module in your sinatra application
93
+ #
94
+ # class MyApp < Sinatra::Application
95
+ # include SitePack::Content
96
+ # set :content_path, 'content'
97
+ # set :public, 'public'
98
+ #
99
+ # get '/:page.html' do
100
+ # erb site_content(options.content_path, params)
101
+ # end
102
+ # end
103
+ #
104
+ # sample page content format:
105
+ #
106
+ # <?xml version="1.0"?>
107
+ # <page>
108
+ # <title>Title Content</title>
109
+ # <body template="special" filter="redcloth">
110
+ # h1. Foo Bar
111
+ #
112
+ # A *simple* paragraph with
113
+ # a line break, some _emphasis_ and a "link":http://redcloth.org
114
+ #
115
+ # * an item
116
+ # * and another
117
+ #
118
+ # # one
119
+ # # two
120
+ #
121
+ # </body>
122
+ # </page>
123
+ #
124
+ # template = by default is page, e.g. views/page.erb
125
+ # filter = by default is redcloth, but can be html -> in which case use <![CDATA[ html ]]>
126
+ #
127
+ module Config
128
+ def site_pack_config(yaml_file)
129
+ config = YAML.load_file(yaml_file)
130
+ @vars = config['vars']
131
+ @filter = config['filter'] || 'redcloth'
132
+ @verbose = config['verbose']
133
+ puts "Site Pack!\nVars:#{@vars.inspect}\nFilter(default):#{@filter.inspect}" if @verbose
134
+ end
135
+ def _site_pack_get_opt(opt)
136
+ instance_variable_get("@#{opt}".to_sym)
137
+ end
138
+ end
139
+ module Content
140
+
141
+
142
+ def site_content(content_path, params)
143
+ if params[:splat].nil?
144
+ file_path = "#{content_path}/index.xml"
145
+ else
146
+ file_path = "#{content_path}/#{params[:splat].join('/')}.xml"
147
+ end
148
+ halt 404, "page not found: #{file_path.inspect}" unless File.exists?(file_path)
149
+ doc = Hpricot.XML(File.read(file_path))
150
+ @title = doc.at(:title) ? doc.at(:title).inner_html : nil
151
+ body = doc.at(:body)
152
+ if body
153
+ template = body[:template] || 'page'
154
+ @body = content_processor(body)
155
+ else
156
+ halt 500, "Missing body tag!"
157
+ end
158
+ vars = self.class._site_pack_get_opt('vars')
159
+ if vars and vars.respond_to?(:each)
160
+ vars.each do|var|
161
+ node = doc.at(var.to_sym)
162
+ instance_variable_set("@#{var}".to_sym, content_processor(node)) if node
163
+ end
164
+ end
165
+ sidebar = doc.at(:sidebar)
166
+ @sidebar = content_processor(sidebar) if sidebar
167
+
168
+ template.to_sym
169
+ end
170
+
171
+ def content_processor(node)
172
+ filter = node[:filter] || self.class._site_pack_get_opt('filter')
173
+ puts "Render(#{node.name.inspect}) with #{filter.inspect}" if self.class._site_pack_get_opt('verbose')
174
+ output = case filter
175
+ when 'redcloth'
176
+ RedCloth.new(node.inner_html).to_html
177
+ when 'html'
178
+ node.inner_html
179
+ when 'erubis'
180
+ Erubis::Eruby.new(node.inner_html).result(binding())
181
+ else
182
+ halt 500, "Unsupported filter: #{filter} when rendering #{file_path}"
183
+ end
184
+ output
185
+ end
186
+
187
+ end
188
+
189
+ end
data/test.rb ADDED
@@ -0,0 +1,75 @@
1
+
2
+ require 'app'
3
+ require 'test/unit'
4
+ require 'rack/test'
5
+
6
+ class TestApp < Test::Unit::TestCase
7
+ include Rack::Test::Methods
8
+
9
+ def app
10
+ App
11
+ end
12
+
13
+ def test_index_redirect
14
+ get '/'
15
+ assert_equal 302, last_response.status
16
+ end
17
+
18
+ def test_404
19
+ get '/foobar.html'
20
+ assert_equal 404, last_response.status
21
+ assert_match /That page is missing/, last_response.body
22
+ end
23
+
24
+ def test_500
25
+ get '/badcontent.html'
26
+ assert_equal 500, last_response.status
27
+ assert_match /Missing body tag/, last_response.body
28
+ end
29
+
30
+ def test_200
31
+ get '/index.html'
32
+ assert_equal 200, last_response.status
33
+ assert_match /Home Page/, last_response.body
34
+ end
35
+
36
+ def test_html
37
+ get '/html.html'
38
+ assert_equal 200, last_response.status
39
+ assert_match /<h1>we have html tags<\/h1>/, last_response.body
40
+ end
41
+
42
+ def test_erubis
43
+ get '/erubis.html'
44
+ assert_equal 200, last_response.status
45
+ assert_match /Yes this is erubis/, last_response.body
46
+ end
47
+
48
+ def test_package
49
+ system("mv content/badcontent.xml .")
50
+ system("rake package")
51
+ assert File.exist?("site/index.html")
52
+ assert File.exist?("site/page2.html")
53
+ assert File.exist?("site/services/foo.html")
54
+ assert File.exist?("site/404.html")
55
+ assert File.exist?("site/altfile_extension.php")
56
+ ensure
57
+ system("mv badcontent.xml content/badcontent.xml")
58
+ end
59
+
60
+ def test_alt_extensions
61
+ get '/altfile_extension.php'
62
+ assert_equal 200, last_response.status
63
+ assert_match /<\? echo 'hello' \?>/, last_response.body # /
64
+ end
65
+
66
+ def test_extravars
67
+ get '/extravars.html'
68
+ assert_equal 200, last_response.status
69
+
70
+ assert_match(/footer/,last_response.body)
71
+ assert_match(/sidebar/,last_response.body)
72
+ assert_match(/head/,last_response.body)
73
+ end
74
+
75
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sitepack
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.6"
5
+ platform: ruby
6
+ authors:
7
+ - Todd A. Fisher
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-03-02 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hpricot
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: RedCloth
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: erubis
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ description: Sinatra Static Pages
46
+ email: todd.fisher@gmail.com
47
+ executables: []
48
+
49
+ extensions: []
50
+
51
+ extra_rdoc_files: []
52
+
53
+ files:
54
+ - README
55
+ - lib/sitepack.rb
56
+ has_rdoc: true
57
+ homepage:
58
+ licenses: []
59
+
60
+ post_install_message:
61
+ rdoc_options: []
62
+
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ version:
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.3.5
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: Sinatra Static Pages
84
+ test_files:
85
+ - test.rb