sitepack 0.6

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.
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