webgen 0.5.7 → 0.5.8
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +870 -0
- data/Rakefile +37 -36
- data/VERSION +1 -1
- data/data/webgen/resources.yaml +2 -2
- data/data/webgen/webgui/app.rb +11 -0
- data/data/webgen/webgui/controller/main.rb +30 -26
- data/data/webgen/webgui/{view/page.xhtml → layout/default.xhtml} +8 -8
- data/data/webgen/webgui/start.rb +9 -0
- data/data/webgen/webgui/view/create_website.xhtml +6 -14
- data/data/webgen/webgui/view/manage_website.xhtml +2 -2
- data/data/webgen/website_bundles/default/README +6 -0
- data/data/webgen/website_bundles/default/src/index.page +15 -0
- data/data/webgen/{website_styles → website_bundles/style}/1024px/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/1024px/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/1024px/src/default.template +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/1024px/src/images/background.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas00/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/default.template +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/images/bg.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/images/front.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/images/menubg.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/images/menubg2.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas01/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/default.template +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/images/bg.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/images/front.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/print.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas03/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/default.template +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/bodybg.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/contbg.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/footerbg.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/gradient1.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/gradient2.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/default.template +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/blinkarrow.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/bodybg.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/contentbg.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/entrybg.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/flash.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/flash2.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/globe.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/globebottom.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/linkarrow.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/menuhover.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas05/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas05/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas05/src/default.template +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas05/src/images/bodybg.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas05/src/images/front.png +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/default.css +6 -4
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/default.template +2 -2
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/bodybg.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/boxbg.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/greypx.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/header.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/innerbg.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/leaves.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/tabs.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas07/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/browserfix.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/default.template +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/images/bodybg.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/images/sidebarbg.gif +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas08/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas08/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas08/src/default.template +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/default.template +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-black.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-green.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-orange.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-purple.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-red.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/footerbg.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-black.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-green.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-orange.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-purple.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-red.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover.jpg +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/simple/README +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/simple/src/default.css +0 -0
- data/data/webgen/{website_styles → website_bundles/style}/simple/src/default.template +0 -0
- data/data/webgen/website_skeleton/README +1 -1
- data/data/webgen/website_skeleton/config.yaml +5 -4
- data/doc/contentprocessor/blocks.page +43 -10
- data/doc/contentprocessor/builder.page +1 -1
- data/doc/contentprocessor/erb.page +12 -11
- data/doc/contentprocessor/redcloth.page +3 -1
- data/doc/extensions.page +3 -3
- data/doc/faq.page +13 -10
- data/doc/getting_started.page +12 -15
- data/doc/index.page +7 -1
- data/doc/manual.page +78 -27
- data/doc/reference_configuration.page +166 -3
- data/doc/reference_website_styles.page +28 -0
- data/doc/source/filesystem.page +39 -0
- data/doc/source/tararchive.page +40 -0
- data/doc/tag/tikz.page +2 -1
- data/doc/webgen_page_format.page +13 -12
- data/doc/website_styles.metainfo +8 -0
- data/lib/webgen/blackboard.rb +2 -2
- data/lib/webgen/cache.rb +4 -4
- data/lib/webgen/cli.rb +29 -16
- data/lib/webgen/cli/apply_command.rb +66 -0
- data/lib/webgen/cli/create_command.rb +22 -16
- data/lib/webgen/cli/utils.rb +23 -0
- data/lib/webgen/cli/webgui_command.rb +31 -16
- data/lib/webgen/configuration.rb +8 -6
- data/lib/webgen/contentprocessor.rb +4 -5
- data/lib/webgen/contentprocessor/blocks.rb +2 -0
- data/lib/webgen/contentprocessor/builder.rb +6 -3
- data/lib/webgen/contentprocessor/erb.rb +6 -3
- data/lib/webgen/contentprocessor/erubis.rb +7 -6
- data/lib/webgen/contentprocessor/haml.rb +6 -3
- data/lib/webgen/contentprocessor/rdoc.rb +0 -1
- data/lib/webgen/contentprocessor/redcloth.rb +3 -1
- data/lib/webgen/context.rb +73 -0
- data/lib/webgen/context/nodes.rb +36 -0
- data/lib/webgen/coreext.rb +3 -2
- data/lib/webgen/default_config.rb +3 -1
- data/lib/webgen/deprecated.rb +53 -0
- data/lib/webgen/node.rb +24 -19
- data/lib/webgen/output.rb +50 -7
- data/lib/webgen/page.rb +45 -36
- data/lib/webgen/path.rb +1 -1
- data/lib/webgen/source.rb +32 -4
- data/lib/webgen/source/resource.rb +3 -3
- data/lib/webgen/source/stacked.rb +1 -1
- data/lib/webgen/source/tararchive.rb +73 -0
- data/lib/webgen/sourcehandler.rb +4 -4
- data/lib/webgen/sourcehandler/base.rb +36 -24
- data/lib/webgen/sourcehandler/copy.rb +1 -1
- data/lib/webgen/sourcehandler/feed.rb +2 -2
- data/lib/webgen/sourcehandler/fragment.rb +1 -1
- data/lib/webgen/sourcehandler/metainfo.rb +15 -6
- data/lib/webgen/sourcehandler/page.rb +9 -5
- data/lib/webgen/sourcehandler/virtual.rb +44 -7
- data/lib/webgen/tag/base.rb +19 -13
- data/lib/webgen/tag/link.rb +1 -0
- data/lib/webgen/version.rb +1 -1
- data/lib/webgen/webgentask.rb +15 -13
- data/lib/webgen/website.rb +42 -11
- data/lib/webgen/websiteaccess.rb +1 -1
- data/lib/webgen/websitemanager.rb +61 -66
- data/man/man1/webgen.1 +4 -0
- data/misc/default.css +13 -0
- data/misc/default.template +1 -1
- data/misc/htmldoc.metainfo +2 -1
- data/misc/style.page +33 -0
- data/test/test_cli.rb +1 -7
- data/test/test_common_sitemap.rb +2 -2
- data/test/test_contentprocessor_blocks.rb +14 -1
- data/test/test_contentprocessor_builder.rb +3 -1
- data/test/test_contentprocessor_erb.rb +3 -2
- data/test/test_contentprocessor_erubis.rb +3 -3
- data/test/test_contentprocessor_fragments.rb +3 -3
- data/test/test_contentprocessor_haml.rb +3 -2
- data/test/test_contentprocessor_maruku.rb +3 -3
- data/test/test_contentprocessor_rdiscount.rb +1 -1
- data/test/test_contentprocessor_rdoc.rb +1 -1
- data/test/test_contentprocessor_redcloth.rb +9 -2
- data/test/test_contentprocessor_sass.rb +1 -1
- data/test/test_contentprocessor_tags.rb +1 -1
- data/test/{test_contentprocessor_context.rb → test_context.rb} +9 -7
- data/test/test_node.rb +27 -21
- data/test/test_page.rb +4 -4
- data/test/test_source_tararchive.rb +65 -0
- data/test/test_sourcehandler_fragment.rb +1 -1
- data/test/test_sourcehandler_memory.rb +6 -6
- data/test/test_sourcehandler_metainfo.rb +34 -13
- data/test/test_sourcehandler_page.rb +8 -0
- data/test/test_sourcehandler_virtual.rb +51 -12
- data/test/test_tag_breadcrumbtrail.rb +4 -4
- data/test/test_tag_coderay.rb +1 -1
- data/test/test_tag_date.rb +1 -1
- data/test/test_tag_executecommand.rb +1 -1
- data/test/test_tag_includefile.rb +3 -3
- data/test/test_tag_langbar.rb +6 -6
- data/test/test_tag_link.rb +8 -2
- data/test/test_tag_menu.rb +9 -9
- data/test/test_tag_metainfo.rb +1 -1
- data/test/test_tag_relocatable.rb +1 -1
- data/test/test_tag_sitemap.rb +1 -1
- data/test/test_tag_tikz.rb +2 -2
- data/test/test_website.rb +17 -0
- data/test/test_websitemanager.rb +16 -21
- metadata +146 -187
- data/data/webgen/website_templates/default/README +0 -6
- data/data/webgen/website_templates/default/src/index.page +0 -8
- data/data/webgen/website_templates/project/README +0 -5
- data/data/webgen/website_templates/project/src/about.page +0 -12
- data/data/webgen/website_templates/project/src/download.page +0 -15
- data/data/webgen/website_templates/project/src/features.page +0 -8
- data/data/webgen/website_templates/project/src/index.page +0 -9
- data/data/webgen/website_templates/project/src/screenshots.page +0 -18
- data/lib/webgen/contentprocessor/context.rb +0 -89
data/lib/webgen/node.rb
CHANGED
@@ -10,6 +10,13 @@ require 'pathname'
|
|
10
10
|
module Webgen
|
11
11
|
|
12
12
|
# Represents a file, a directory or a fragment. A node always belongs to a Tree.
|
13
|
+
#
|
14
|
+
# All needed meta and processing information is associated with a Node. The meta information is
|
15
|
+
# available throught the #[] and #meta_info accessors, the processing information through the
|
16
|
+
# #node_info accessor.
|
17
|
+
#
|
18
|
+
# Although node information should be changed by code, it is not advised to change meta
|
19
|
+
# information values in code since this may lead to unwanted behaviour!
|
13
20
|
class Node
|
14
21
|
|
15
22
|
include WebsiteAccess
|
@@ -50,18 +57,18 @@ module Webgen
|
|
50
57
|
|
51
58
|
# Create a new Node instance.
|
52
59
|
#
|
53
|
-
# +parent+ (immutable)
|
60
|
+
# [+parent+ (immutable)]
|
54
61
|
# The parent node under which this nodes should be created.
|
55
|
-
# +path+ (immutable)
|
62
|
+
# [+path+ (immutable)]
|
56
63
|
# The full output path for this node. If this node is a directory, the path must have a
|
57
64
|
# trailing slash (<tt>dir/</tt>). If it is a fragment, the hash sign must be the first
|
58
65
|
# character of the path (<tt>#fragment</tt>). This can also be an absolute path like
|
59
66
|
# <tt>http://myhost.com/</tt>.
|
60
|
-
# +cn+ (immutable)
|
67
|
+
# [+cn+ (immutable)]
|
61
68
|
# The canonical name for this node. Needs to be of the form <tt>basename.ext</tt> or
|
62
69
|
# <tt>basename</tt> where +basename+ does not contain any dots. Also, the +basename+ must not
|
63
70
|
# include a language part!
|
64
|
-
# +meta_info
|
71
|
+
# [+meta_info+]
|
65
72
|
# A hash with meta information for the new node.
|
66
73
|
#
|
67
74
|
# The language of a node is taken from the meta information +lang+ and the entry is deleted from
|
@@ -121,13 +128,13 @@ module Webgen
|
|
121
128
|
|
122
129
|
# Check if the node is flagged with one of the following:
|
123
130
|
#
|
124
|
-
# :created
|
125
|
-
# :reinit
|
126
|
-
# :dirty
|
131
|
+
# [:created] Has the node been created or has it been read from the cache?
|
132
|
+
# [:reinit] Does the node need to be reinitialized?
|
133
|
+
# [:dirty] Set by other objects to +true+ if they think the object has changed since the last
|
127
134
|
# run. Must not be set to +false+ once it is +true+!
|
128
|
-
# :dirty_meta_info
|
135
|
+
# [:dirty_meta_info] Set by other objects to +true+ if the meta information of the node has
|
129
136
|
# changed since the last run. Must not be set to +false+ once it is +true+!
|
130
|
-
def flagged(key)
|
137
|
+
def flagged?(key)
|
131
138
|
@flags.include?(key)
|
132
139
|
end
|
133
140
|
|
@@ -154,10 +161,11 @@ module Webgen
|
|
154
161
|
def changed?
|
155
162
|
if_not_checked(:node) do
|
156
163
|
flag(:dirty) if meta_info_changed? ||
|
157
|
-
node_info[:used_nodes].any? {|n| n != @absolute_lcn && (!tree[n] || tree[n].changed?)}
|
158
|
-
|
164
|
+
node_info[:used_nodes].any? {|n| n != @absolute_lcn && (!tree[n] || tree[n].changed?)} ||
|
165
|
+
node_info[:used_meta_info_nodes].any? {|n| n != @absolute_lcn && (!tree[n] || tree[n].meta_info_changed?)}
|
166
|
+
website.blackboard.dispatch_msg(:node_changed?, self) unless flagged?(:dirty)
|
159
167
|
end
|
160
|
-
flagged(:dirty)
|
168
|
+
flagged?(:dirty)
|
161
169
|
end
|
162
170
|
|
163
171
|
# Return +true+ if the meta information of the node has changed.
|
@@ -168,12 +176,9 @@ module Webgen
|
|
168
176
|
# dirty.
|
169
177
|
def meta_info_changed?
|
170
178
|
if_not_checked(:meta_info) do
|
171
|
-
|
172
|
-
n != @absolute_lcn && (!tree[n] || tree[n].meta_info_changed?)
|
173
|
-
end
|
174
|
-
website.blackboard.dispatch_msg(:node_meta_info_changed?, self) unless flagged(:dirty_meta_info)
|
179
|
+
website.blackboard.dispatch_msg(:node_meta_info_changed?, self) unless flagged?(:dirty_meta_info)
|
175
180
|
end
|
176
|
-
flagged(:dirty_meta_info)
|
181
|
+
flagged?(:dirty_meta_info)
|
177
182
|
end
|
178
183
|
|
179
184
|
# Return an informative representation of the node.
|
@@ -199,7 +204,7 @@ module Webgen
|
|
199
204
|
end
|
200
205
|
|
201
206
|
# Construct the absolute (localized) canonical name by using the +parent+ node and +name+ (which
|
202
|
-
# can be a cn or an lcn). The +type+ can be either
|
207
|
+
# can be a cn or an lcn). The +type+ can be either <tt>:alcn</tt> or <tt>:acn</tt>.
|
203
208
|
def self.absolute_name(parent, name, type)
|
204
209
|
if parent.kind_of?(Tree)
|
205
210
|
''
|
@@ -326,7 +331,7 @@ module Webgen
|
|
326
331
|
#
|
327
332
|
# If the special value <tt>:lang</tt> is present in the attributes, it will be used as parameter
|
328
333
|
# to the <tt>node.routing_node</tt> call for getting the linked-to node instead of this node's
|
329
|
-
# +lang+ attribute. Note
|
334
|
+
# +lang+ attribute. *Note*: this is only useful when linking to a directory.
|
330
335
|
def link_to(node, attr = {})
|
331
336
|
attr = node['link_attrs'].merge(attr) if node['link_attrs'].kind_of?(Hash)
|
332
337
|
rnode = node.routing_node(attr[:lang] || @lang)
|
data/lib/webgen/output.rb
CHANGED
@@ -4,22 +4,65 @@ module Webgen
|
|
4
4
|
|
5
5
|
# Namespace for all classes that know how to write out node content.
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# == Implementing an output class
|
8
8
|
#
|
9
9
|
# Output classes know how to write rendered node data to an output location.
|
10
10
|
#
|
11
11
|
# An output class must respond to three methods
|
12
12
|
#
|
13
|
-
# <tt>exists?(path)</tt
|
13
|
+
# [<tt>exists?(path)</tt>]
|
14
14
|
# Return +true+ if the output path exists.
|
15
|
-
# <tt>delete(path)</tt
|
15
|
+
# [<tt>delete(path)</tt>]
|
16
16
|
# Delete the given output path.
|
17
|
-
# <tt>write(path, data, type)</tt
|
18
|
-
# Write the data to the given output path
|
19
|
-
#
|
20
|
-
# <tt>
|
17
|
+
# [<tt>write(path, data, type)</tt>]
|
18
|
+
# Write the +data+ to the given output +path+. The parameter +data+ is either a String with the
|
19
|
+
# content or a Webgen::Path::SourceIO object. The parameter +type+ specifies the type of the to
|
20
|
+
# be written path: <tt>:file</tt> or <tt>:directory</tt>.
|
21
|
+
# [<tt>read(path)</tt>]
|
21
22
|
# Return the content of the given path if it exists or raise an error otherwise.
|
22
23
|
#
|
24
|
+
# It seems a bit odd that an output instance has to implement reading functionality. However,
|
25
|
+
# consider the case where you want webgen to render a website programmatically and *use* the
|
26
|
+
# output. In this case you need a way to get to content of the written files! This functionality
|
27
|
+
# is used, for example, in the webgui.
|
28
|
+
#
|
29
|
+
# == Sample Output Class
|
30
|
+
#
|
31
|
+
# Following is a simple but actually used (by the webgui) output class which stores the written
|
32
|
+
# nodes in a hash in memory:
|
33
|
+
#
|
34
|
+
# class MemoryOutput
|
35
|
+
# include Webgen::WebsiteAccess
|
36
|
+
#
|
37
|
+
# attr_reader :data
|
38
|
+
#
|
39
|
+
# def initialize
|
40
|
+
# @data = {}
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# def exists?(path)
|
44
|
+
# @data.has_key?(path)
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# def delete(path)
|
48
|
+
# @data.delete(path)
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# def write(path, io, type = :file)
|
52
|
+
# @data[path] = [(io.kind_of?(String) ? io : io.data), type]
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# def read(path)
|
56
|
+
# path = File.join('/', path)
|
57
|
+
# raise "No such file #{path}" unless @data[path] && @data[path].last == :file
|
58
|
+
# @data[path].first
|
59
|
+
# end
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# WebsiteAccess.website.config.output(['MemoryOutput'])
|
63
|
+
#
|
64
|
+
# The last line is used to tell webgen to use this new output class instead of the default one.
|
65
|
+
#
|
23
66
|
module Output
|
24
67
|
|
25
68
|
autoload :FileSystem, 'webgen/output/filesystem'
|
data/lib/webgen/page.rb
CHANGED
@@ -4,52 +4,61 @@ require 'yaml'
|
|
4
4
|
|
5
5
|
module Webgen
|
6
6
|
|
7
|
-
# A
|
8
|
-
class
|
7
|
+
# A Page object wraps a meta information hash and an array of Block objects. It is normally
|
8
|
+
# generated from a file or string in Webgen Page Format using the provided class methods.
|
9
|
+
class Page
|
9
10
|
|
10
|
-
# The
|
11
|
-
|
11
|
+
# A single block within a Page object. The content of the block can be rendered using the #render method.
|
12
|
+
class Block
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
# The name of the block.
|
15
|
+
attr_reader :name
|
15
16
|
|
16
|
-
|
17
|
-
|
17
|
+
# The content of the block.
|
18
|
+
attr_reader :content
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
@name, @content, @options = name, content, options
|
22
|
-
end
|
20
|
+
# The options set specifically for this block.
|
21
|
+
attr_reader :options
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
# Returns the given context with the rendered content.
|
28
|
-
def render(context)
|
29
|
-
context[:content] = @content.dup
|
30
|
-
context[:block] = self
|
31
|
-
@options['pipeline'].to_s.split(/,/).each do |processor|
|
32
|
-
raise "No such content processor available: #{processor}" unless context[:processors].has_key?(processor)
|
33
|
-
context[:processors][processor].call(context)
|
23
|
+
# Create a new block with the name +name+ and the given +content+ and +options+.
|
24
|
+
def initialize(name, content, options)
|
25
|
+
@name, @content, @options = name, content, options
|
34
26
|
end
|
35
|
-
context
|
36
|
-
end
|
37
27
|
|
38
|
-
|
28
|
+
# Render the block using the provided context object.
|
29
|
+
#
|
30
|
+
# The context object needs to respond to <tt>#[]</tt> and <tt>#[]=</tt> (e.g. a Hash is a valid
|
31
|
+
# context object) and the key <tt>:processors</tt> needs to contain a Hash which maps processor
|
32
|
+
# names to processor objects that respond to <tt>#call</tt>.
|
33
|
+
#
|
34
|
+
# Uses the content processors specified in the +pipeline+ key of the +options+ attribute to do
|
35
|
+
# the actual rendering.
|
36
|
+
#
|
37
|
+
# Returns the given context with the rendered content.
|
38
|
+
def render(context)
|
39
|
+
context[:content] = @content.dup
|
40
|
+
context[:block] = self
|
41
|
+
@options['pipeline'].to_s.split(/,/).each do |processor|
|
42
|
+
raise "No such content processor available: #{processor}" unless context[:processors].has_key?(processor)
|
43
|
+
context[:processors][processor].call(context)
|
44
|
+
end
|
45
|
+
context
|
46
|
+
end
|
39
47
|
|
48
|
+
end
|
40
49
|
|
41
|
-
# Raised during parsing of data in Webgen Page Format if the data is invalid.
|
42
|
-
class WebgenPageFormatError < RuntimeError; end
|
43
50
|
|
44
|
-
|
45
|
-
|
46
|
-
|
51
|
+
# Raised during parsing of data in Webgen Page Format if the data is invalid.
|
52
|
+
class FormatError < RuntimeError; end
|
53
|
+
|
47
54
|
|
55
|
+
# :stopdoc:
|
48
56
|
RE_META_INFO_START = /\A---\s*(?:\n|\r|\r\n)/m
|
49
57
|
RE_META_INFO = /\A---\s*(?:\n|\r|\r\n).*?(?:\n|\r|\r\n)(?=---.*?(?:\n|\r|\r\n)|\Z)/m
|
50
58
|
RE_BLOCKS_OPTIONS = /^--- *?(?: *((?:\w+:[^\s]* *)*))?$|^$/
|
51
59
|
RE_BLOCKS_START = /^--- .*?$|^--- *$/
|
52
60
|
RE_BLOCKS = /(?:(#{RE_BLOCKS_START})|\A)(.*?)(?:(?=#{RE_BLOCKS_START})|\Z)/m
|
61
|
+
# :startdoc:
|
53
62
|
|
54
63
|
class << self
|
55
64
|
|
@@ -81,17 +90,17 @@ module Webgen
|
|
81
90
|
# original +data+ is used for checking the validness of the meta information block.
|
82
91
|
def parse_meta_info(mi_data, data)
|
83
92
|
if mi_data.nil? && data =~ RE_META_INFO_START
|
84
|
-
raise
|
93
|
+
raise FormatError, 'Found start line for meta information block but no valid meta information block'
|
85
94
|
elsif mi_data.nil?
|
86
95
|
{}
|
87
96
|
else
|
88
97
|
begin
|
89
98
|
meta_info = YAML::load(mi_data.to_s)
|
90
99
|
unless meta_info.kind_of?(Hash)
|
91
|
-
raise
|
100
|
+
raise FormatError, "Invalid structure of meta information block: expected YAML hash but found #{meta_info.class}"
|
92
101
|
end
|
93
102
|
rescue ArgumentError => e
|
94
|
-
raise
|
103
|
+
raise FormatError, e.message
|
95
104
|
end
|
96
105
|
meta_info
|
97
106
|
end
|
@@ -101,20 +110,20 @@ module Webgen
|
|
101
110
|
# which is used for setting the block names and options.
|
102
111
|
def parse_blocks(data, meta_info)
|
103
112
|
scanned = data.scan(RE_BLOCKS)
|
104
|
-
raise(
|
113
|
+
raise(FormatError, 'No content blocks specified') if scanned.length == 0
|
105
114
|
|
106
115
|
blocks = {}
|
107
116
|
scanned.each_with_index do |block_data, index|
|
108
117
|
options, content = *block_data
|
109
118
|
md = RE_BLOCKS_OPTIONS.match(options.to_s)
|
110
|
-
raise(
|
119
|
+
raise(FormatError, "Found invalid blocks starting line for block #{index+1}: #{options}") if content =~ /\A---/ || md.nil?
|
111
120
|
options = Hash[*md[1].to_s.scan(/(\w+):([^\s]*)/).map {|k,v| [k, (v == '' ? nil : YAML::load(v))]}.flatten]
|
112
121
|
options = (meta_info['blocks']['default'] || {} rescue {}).
|
113
122
|
merge((meta_info['blocks'][index+1] || {} rescue {})).
|
114
123
|
merge(options)
|
115
124
|
|
116
125
|
name = options.delete('name') || (index == 0 ? 'content' : 'block' + (index + 1).to_s)
|
117
|
-
raise(
|
126
|
+
raise(FormatError, "Previously used name '#{name}' also used for block #{index+1}") if blocks.has_key?(name)
|
118
127
|
content ||= ''
|
119
128
|
content.gsub!(/^(\\+)(---.*?)$/) {|m| "\\" * ($1.length / 2) + $2}
|
120
129
|
content.strip!
|
data/lib/webgen/path.rb
CHANGED
data/lib/webgen/source.rb
CHANGED
@@ -4,15 +4,42 @@ module Webgen
|
|
4
4
|
|
5
5
|
# Namespace for all classes that provide source paths.
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# == Implementing a source class
|
8
8
|
#
|
9
9
|
# Source classes provide access to the source paths on which the source handlers act.
|
10
10
|
#
|
11
11
|
# A source class only needs to respond to the method +paths+ which needs to return a set of paths
|
12
12
|
# for the source. The returned paths must respond to the method <tt>changed?</tt> (has to return
|
13
|
-
# +true+ if the paths has changed since the last webgen run)
|
14
|
-
#
|
15
|
-
# on each path object.
|
13
|
+
# +true+ if the paths has changed since the last webgen run). The default implementation in the
|
14
|
+
# Path class just returns +true+. One can either derive a specialized path class or define
|
15
|
+
# singleton methods on each path object.
|
16
|
+
#
|
17
|
+
# == Sample Source Class
|
18
|
+
#
|
19
|
+
# Following is a simple source class which has stored the paths and their contents in a hash:
|
20
|
+
#
|
21
|
+
# require 'stringio'
|
22
|
+
#
|
23
|
+
# class MemorySource
|
24
|
+
#
|
25
|
+
# CONTENT = {
|
26
|
+
# '/directory/' => nil,
|
27
|
+
# '/directory/file.page' => "This is the content of the file"
|
28
|
+
# }
|
29
|
+
#
|
30
|
+
# def paths
|
31
|
+
# CONTENT.collect do |path, content|
|
32
|
+
# Webgen::Path.new(path) { StringIO.new(content.to_s) }
|
33
|
+
# end.to_set
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# You can use this source class in your website (after placing the code in, for example,
|
39
|
+
# <tt>ext/init.rb</tt>) by updating the <tt>sources</tt> configuration option (the following code
|
40
|
+
# has to be placed after the definition of the +MemorySource+ class):
|
41
|
+
#
|
42
|
+
# WebsiteAccess.website.config['sources'] << ['/', MemorySource]
|
16
43
|
#
|
17
44
|
module Source
|
18
45
|
|
@@ -20,6 +47,7 @@ module Webgen
|
|
20
47
|
autoload :FileSystem, 'webgen/source/filesystem'
|
21
48
|
autoload :Stacked, 'webgen/source/stacked'
|
22
49
|
autoload :Resource, 'webgen/source/resource'
|
50
|
+
autoload :TarArchive, 'webgen/source/tararchive'
|
23
51
|
|
24
52
|
end
|
25
53
|
|
@@ -5,15 +5,15 @@ require 'webgen/source'
|
|
5
5
|
|
6
6
|
module Webgen::Source
|
7
7
|
|
8
|
-
# This class is used to provide access to
|
8
|
+
# This class is used to provide access to sources provided by resources.
|
9
9
|
class Resource
|
10
10
|
|
11
11
|
include Webgen::WebsiteAccess
|
12
12
|
|
13
|
-
# The glob specifying the resources.
|
13
|
+
# The glob (see File.fnmatch) specifying the resources.
|
14
14
|
attr_reader :glob
|
15
15
|
|
16
|
-
# The glob specifying the paths that should be used from the resources.
|
16
|
+
# The glob (see File.fnmatch) specifying the paths that should be used from the resources.
|
17
17
|
attr_reader :paths_glob
|
18
18
|
|
19
19
|
# The prefix that should optionally be stripped from the paths.
|
@@ -9,7 +9,7 @@ module Webgen::Source
|
|
9
9
|
# * First, it can be used to access more than one source. This is useful when your website
|
10
10
|
# consists of more than one source directory and you want to use all of them.
|
11
11
|
#
|
12
|
-
# * Second, sources can mounted on specific directories. For example, a folder with images that
|
12
|
+
# * Second, sources can be mounted on specific directories. For example, a folder with images that
|
13
13
|
# you don't want to copy to the website source directory can be mounted under <tt>/images</tt>
|
14
14
|
# sothat they are available nonetheless.
|
15
15
|
#
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
require 'webgen/websiteaccess'
|
5
|
+
require 'webgen/path'
|
6
|
+
require 'open-uri'
|
7
|
+
require 'zlib'
|
8
|
+
require 'archive/tar/minitar'
|
9
|
+
|
10
|
+
module Webgen
|
11
|
+
|
12
|
+
# This class is used to read source paths from a (gzipped) tar archive. The archive can be remote
|
13
|
+
# (http(s) or ftp) or local.
|
14
|
+
#
|
15
|
+
# For example, the following are all valid URIs:
|
16
|
+
# http://example.com/directory/file.tgz
|
17
|
+
# /home/test/my.tar.gz
|
18
|
+
# ftp://ftp.example.com/archives/archive.tar
|
19
|
+
#
|
20
|
+
class Source::TarArchive
|
21
|
+
|
22
|
+
# A special Webgen::Path class for handling paths from a tar archive.
|
23
|
+
class Path < Webgen::Path
|
24
|
+
|
25
|
+
# Create a new tar archive path object for the entry +entry+.
|
26
|
+
def initialize(path, data, mtime, uri)
|
27
|
+
super(path) { StringIO.new(data.to_s) }
|
28
|
+
@uri = uri
|
29
|
+
@mtime = mtime
|
30
|
+
WebsiteAccess.website.cache[[:tararchive_path, @uri, path]] = @mtime if WebsiteAccess.website
|
31
|
+
@meta_info['modified_at'] = @mtime
|
32
|
+
end
|
33
|
+
|
34
|
+
# Return +true+ if the tar archive path used by the object has been modified.
|
35
|
+
def changed?
|
36
|
+
!WebsiteAccess.website || @mtime > WebsiteAccess.website.cache[[:tararchive_path, @uri, path]]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# The URI of the tar archive.
|
42
|
+
attr_reader :uri
|
43
|
+
|
44
|
+
# The glob (see File.fnmatch for details) that is used to specify which paths in the archive should
|
45
|
+
# be returned by #paths.
|
46
|
+
attr_reader :glob
|
47
|
+
|
48
|
+
# Create a new tar archive source for the URI string +uri+.
|
49
|
+
def initialize(uri, glob = '**/*')
|
50
|
+
@uri = uri
|
51
|
+
@glob = glob
|
52
|
+
end
|
53
|
+
|
54
|
+
# Return all paths in the tar archive available at #uri.
|
55
|
+
def paths
|
56
|
+
if !defined?(@paths)
|
57
|
+
stream = open(@uri)
|
58
|
+
stream = Zlib::GzipReader.new(stream) if @uri =~ /(\.tar\.gz|\.tgz)$/
|
59
|
+
Archive::Tar::Minitar::Input.open(stream) do |input|
|
60
|
+
@paths = input.collect do |entry|
|
61
|
+
path = entry.full_name
|
62
|
+
next unless File.fnmatch(@glob, path, File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME)
|
63
|
+
path += '/' if entry.directory? && path[-1] != ?/
|
64
|
+
Path.new(path, entry.read, Time.at(entry.mtime), @uri)
|
65
|
+
end.compact.to_set
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@paths
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|