webgen 0.5.7 → 0.5.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (207) hide show
  1. data/ChangeLog +870 -0
  2. data/Rakefile +37 -36
  3. data/VERSION +1 -1
  4. data/data/webgen/resources.yaml +2 -2
  5. data/data/webgen/webgui/app.rb +11 -0
  6. data/data/webgen/webgui/controller/main.rb +30 -26
  7. data/data/webgen/webgui/{view/page.xhtml → layout/default.xhtml} +8 -8
  8. data/data/webgen/webgui/start.rb +9 -0
  9. data/data/webgen/webgui/view/create_website.xhtml +6 -14
  10. data/data/webgen/webgui/view/manage_website.xhtml +2 -2
  11. data/data/webgen/website_bundles/default/README +6 -0
  12. data/data/webgen/website_bundles/default/src/index.page +15 -0
  13. data/data/webgen/{website_styles → website_bundles/style}/1024px/README +0 -0
  14. data/data/webgen/{website_styles → website_bundles/style}/1024px/src/default.css +0 -0
  15. data/data/webgen/{website_styles → website_bundles/style}/1024px/src/default.template +0 -0
  16. data/data/webgen/{website_styles → website_bundles/style}/1024px/src/images/background.gif +0 -0
  17. data/data/webgen/{website_styles → website_bundles/style}/andreas00/README +0 -0
  18. data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/default.css +0 -0
  19. data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/default.template +0 -0
  20. data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/images/bg.gif +0 -0
  21. data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/images/front.jpg +0 -0
  22. data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/images/menubg.gif +0 -0
  23. data/data/webgen/{website_styles → website_bundles/style}/andreas00/src/images/menubg2.gif +0 -0
  24. data/data/webgen/{website_styles → website_bundles/style}/andreas01/README +0 -0
  25. data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/default.css +0 -0
  26. data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/default.template +0 -0
  27. data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/images/bg.gif +0 -0
  28. data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/images/front.jpg +0 -0
  29. data/data/webgen/{website_styles → website_bundles/style}/andreas01/src/print.css +0 -0
  30. data/data/webgen/{website_styles → website_bundles/style}/andreas03/README +0 -0
  31. data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/default.css +0 -0
  32. data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/default.template +0 -0
  33. data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/bodybg.png +0 -0
  34. data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/contbg.png +0 -0
  35. data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/footerbg.png +0 -0
  36. data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/gradient1.png +0 -0
  37. data/data/webgen/{website_styles → website_bundles/style}/andreas03/src/images/gradient2.png +0 -0
  38. data/data/webgen/{website_styles → website_bundles/style}/andreas04/README +0 -0
  39. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/default.css +0 -0
  40. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/default.template +0 -0
  41. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/blinkarrow.gif +0 -0
  42. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/bodybg.png +0 -0
  43. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/contentbg.png +0 -0
  44. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/entrybg.png +0 -0
  45. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/flash.gif +0 -0
  46. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/flash2.gif +0 -0
  47. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/globe.gif +0 -0
  48. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/globebottom.gif +0 -0
  49. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/linkarrow.gif +0 -0
  50. data/data/webgen/{website_styles → website_bundles/style}/andreas04/src/images/menuhover.png +0 -0
  51. data/data/webgen/{website_styles → website_bundles/style}/andreas05/README +0 -0
  52. data/data/webgen/{website_styles → website_bundles/style}/andreas05/src/default.css +0 -0
  53. data/data/webgen/{website_styles → website_bundles/style}/andreas05/src/default.template +0 -0
  54. data/data/webgen/{website_styles → website_bundles/style}/andreas05/src/images/bodybg.gif +0 -0
  55. data/data/webgen/{website_styles → website_bundles/style}/andreas05/src/images/front.png +0 -0
  56. data/data/webgen/{website_styles → website_bundles/style}/andreas06/README +0 -0
  57. data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/default.css +6 -4
  58. data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/default.template +2 -2
  59. data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/bodybg.gif +0 -0
  60. data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/boxbg.gif +0 -0
  61. data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/greypx.gif +0 -0
  62. data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/header.jpg +0 -0
  63. data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/innerbg.gif +0 -0
  64. data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/leaves.jpg +0 -0
  65. data/data/webgen/{website_styles → website_bundles/style}/andreas06/src/images/tabs.gif +0 -0
  66. data/data/webgen/{website_styles → website_bundles/style}/andreas07/README +0 -0
  67. data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/browserfix.css +0 -0
  68. data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/default.css +0 -0
  69. data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/default.template +0 -0
  70. data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/images/bodybg.gif +0 -0
  71. data/data/webgen/{website_styles → website_bundles/style}/andreas07/src/images/sidebarbg.gif +0 -0
  72. data/data/webgen/{website_styles → website_bundles/style}/andreas08/README +0 -0
  73. data/data/webgen/{website_styles → website_bundles/style}/andreas08/src/default.css +0 -0
  74. data/data/webgen/{website_styles → website_bundles/style}/andreas08/src/default.template +0 -0
  75. data/data/webgen/{website_styles → website_bundles/style}/andreas09/README +0 -0
  76. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/default.css +0 -0
  77. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/default.template +0 -0
  78. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-black.jpg +0 -0
  79. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-green.jpg +0 -0
  80. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-orange.jpg +0 -0
  81. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-purple.jpg +0 -0
  82. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg-red.jpg +0 -0
  83. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/bodybg.jpg +0 -0
  84. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/footerbg.jpg +0 -0
  85. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-black.jpg +0 -0
  86. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-green.jpg +0 -0
  87. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-orange.jpg +0 -0
  88. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-purple.jpg +0 -0
  89. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover-red.jpg +0 -0
  90. data/data/webgen/{website_styles → website_bundles/style}/andreas09/src/images/menuhover.jpg +0 -0
  91. data/data/webgen/{website_styles → website_bundles/style}/simple/README +0 -0
  92. data/data/webgen/{website_styles → website_bundles/style}/simple/src/default.css +0 -0
  93. data/data/webgen/{website_styles → website_bundles/style}/simple/src/default.template +0 -0
  94. data/data/webgen/website_skeleton/README +1 -1
  95. data/data/webgen/website_skeleton/config.yaml +5 -4
  96. data/doc/contentprocessor/blocks.page +43 -10
  97. data/doc/contentprocessor/builder.page +1 -1
  98. data/doc/contentprocessor/erb.page +12 -11
  99. data/doc/contentprocessor/redcloth.page +3 -1
  100. data/doc/extensions.page +3 -3
  101. data/doc/faq.page +13 -10
  102. data/doc/getting_started.page +12 -15
  103. data/doc/index.page +7 -1
  104. data/doc/manual.page +78 -27
  105. data/doc/reference_configuration.page +166 -3
  106. data/doc/reference_website_styles.page +28 -0
  107. data/doc/source/filesystem.page +39 -0
  108. data/doc/source/tararchive.page +40 -0
  109. data/doc/tag/tikz.page +2 -1
  110. data/doc/webgen_page_format.page +13 -12
  111. data/doc/website_styles.metainfo +8 -0
  112. data/lib/webgen/blackboard.rb +2 -2
  113. data/lib/webgen/cache.rb +4 -4
  114. data/lib/webgen/cli.rb +29 -16
  115. data/lib/webgen/cli/apply_command.rb +66 -0
  116. data/lib/webgen/cli/create_command.rb +22 -16
  117. data/lib/webgen/cli/utils.rb +23 -0
  118. data/lib/webgen/cli/webgui_command.rb +31 -16
  119. data/lib/webgen/configuration.rb +8 -6
  120. data/lib/webgen/contentprocessor.rb +4 -5
  121. data/lib/webgen/contentprocessor/blocks.rb +2 -0
  122. data/lib/webgen/contentprocessor/builder.rb +6 -3
  123. data/lib/webgen/contentprocessor/erb.rb +6 -3
  124. data/lib/webgen/contentprocessor/erubis.rb +7 -6
  125. data/lib/webgen/contentprocessor/haml.rb +6 -3
  126. data/lib/webgen/contentprocessor/rdoc.rb +0 -1
  127. data/lib/webgen/contentprocessor/redcloth.rb +3 -1
  128. data/lib/webgen/context.rb +73 -0
  129. data/lib/webgen/context/nodes.rb +36 -0
  130. data/lib/webgen/coreext.rb +3 -2
  131. data/lib/webgen/default_config.rb +3 -1
  132. data/lib/webgen/deprecated.rb +53 -0
  133. data/lib/webgen/node.rb +24 -19
  134. data/lib/webgen/output.rb +50 -7
  135. data/lib/webgen/page.rb +45 -36
  136. data/lib/webgen/path.rb +1 -1
  137. data/lib/webgen/source.rb +32 -4
  138. data/lib/webgen/source/resource.rb +3 -3
  139. data/lib/webgen/source/stacked.rb +1 -1
  140. data/lib/webgen/source/tararchive.rb +73 -0
  141. data/lib/webgen/sourcehandler.rb +4 -4
  142. data/lib/webgen/sourcehandler/base.rb +36 -24
  143. data/lib/webgen/sourcehandler/copy.rb +1 -1
  144. data/lib/webgen/sourcehandler/feed.rb +2 -2
  145. data/lib/webgen/sourcehandler/fragment.rb +1 -1
  146. data/lib/webgen/sourcehandler/metainfo.rb +15 -6
  147. data/lib/webgen/sourcehandler/page.rb +9 -5
  148. data/lib/webgen/sourcehandler/virtual.rb +44 -7
  149. data/lib/webgen/tag/base.rb +19 -13
  150. data/lib/webgen/tag/link.rb +1 -0
  151. data/lib/webgen/version.rb +1 -1
  152. data/lib/webgen/webgentask.rb +15 -13
  153. data/lib/webgen/website.rb +42 -11
  154. data/lib/webgen/websiteaccess.rb +1 -1
  155. data/lib/webgen/websitemanager.rb +61 -66
  156. data/man/man1/webgen.1 +4 -0
  157. data/misc/default.css +13 -0
  158. data/misc/default.template +1 -1
  159. data/misc/htmldoc.metainfo +2 -1
  160. data/misc/style.page +33 -0
  161. data/test/test_cli.rb +1 -7
  162. data/test/test_common_sitemap.rb +2 -2
  163. data/test/test_contentprocessor_blocks.rb +14 -1
  164. data/test/test_contentprocessor_builder.rb +3 -1
  165. data/test/test_contentprocessor_erb.rb +3 -2
  166. data/test/test_contentprocessor_erubis.rb +3 -3
  167. data/test/test_contentprocessor_fragments.rb +3 -3
  168. data/test/test_contentprocessor_haml.rb +3 -2
  169. data/test/test_contentprocessor_maruku.rb +3 -3
  170. data/test/test_contentprocessor_rdiscount.rb +1 -1
  171. data/test/test_contentprocessor_rdoc.rb +1 -1
  172. data/test/test_contentprocessor_redcloth.rb +9 -2
  173. data/test/test_contentprocessor_sass.rb +1 -1
  174. data/test/test_contentprocessor_tags.rb +1 -1
  175. data/test/{test_contentprocessor_context.rb → test_context.rb} +9 -7
  176. data/test/test_node.rb +27 -21
  177. data/test/test_page.rb +4 -4
  178. data/test/test_source_tararchive.rb +65 -0
  179. data/test/test_sourcehandler_fragment.rb +1 -1
  180. data/test/test_sourcehandler_memory.rb +6 -6
  181. data/test/test_sourcehandler_metainfo.rb +34 -13
  182. data/test/test_sourcehandler_page.rb +8 -0
  183. data/test/test_sourcehandler_virtual.rb +51 -12
  184. data/test/test_tag_breadcrumbtrail.rb +4 -4
  185. data/test/test_tag_coderay.rb +1 -1
  186. data/test/test_tag_date.rb +1 -1
  187. data/test/test_tag_executecommand.rb +1 -1
  188. data/test/test_tag_includefile.rb +3 -3
  189. data/test/test_tag_langbar.rb +6 -6
  190. data/test/test_tag_link.rb +8 -2
  191. data/test/test_tag_menu.rb +9 -9
  192. data/test/test_tag_metainfo.rb +1 -1
  193. data/test/test_tag_relocatable.rb +1 -1
  194. data/test/test_tag_sitemap.rb +1 -1
  195. data/test/test_tag_tikz.rb +2 -2
  196. data/test/test_website.rb +17 -0
  197. data/test/test_websitemanager.rb +16 -21
  198. metadata +146 -187
  199. data/data/webgen/website_templates/default/README +0 -6
  200. data/data/webgen/website_templates/default/src/index.page +0 -8
  201. data/data/webgen/website_templates/project/README +0 -5
  202. data/data/webgen/website_templates/project/src/about.page +0 -12
  203. data/data/webgen/website_templates/project/src/download.page +0 -15
  204. data/data/webgen/website_templates/project/src/features.page +0 -8
  205. data/data/webgen/website_templates/project/src/index.page +0 -9
  206. data/data/webgen/website_templates/project/src/screenshots.page +0 -18
  207. data/lib/webgen/contentprocessor/context.rb +0 -89
@@ -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:: Has the node been created or has it been read from the cache?
125
- # :reinit:: Does the node need to be reinitialized?
126
- # :dirty:: Set by other objects to +true+ if they think the object has changed since the last
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:: Set by other objects to +true+ if the meta information of the node has
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
- website.blackboard.dispatch_msg(:node_changed?, self) unless flagged(:dirty)
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
- flag(:dirty_meta_info) if node_info[:used_meta_info_nodes].any? do |n|
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 +:alcn+ or +:acn+.
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: this is only useful when linking to a directory.
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)
@@ -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
- # = Implementing an output class
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. The parameter +type+ specifies the type of the
19
- # to be written path: <tt>:file</tt> or <tt>:directory</tt>.
20
- # <tt>read(path)</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'
@@ -4,52 +4,61 @@ require 'yaml'
4
4
 
5
5
  module Webgen
6
6
 
7
- # A single block within a Page object. The content of the block can be rendered using the #render method.
8
- class Block
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 name of the block.
11
- attr_reader :name
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
- # The content of the block.
14
- attr_reader :content
14
+ # The name of the block.
15
+ attr_reader :name
15
16
 
16
- # The options set specifically for this block.
17
- attr_reader :options
17
+ # The content of the block.
18
+ attr_reader :content
18
19
 
19
- # Create a new block with the name +name+ and the given +content+ and +options+.
20
- def initialize(name, content, options)
21
- @name, @content, @options = name, content, options
22
- end
20
+ # The options set specifically for this block.
21
+ attr_reader :options
23
22
 
24
- # Render the block using the provided context object. Uses the content processors specified in
25
- # the +pipeline+ key of the +options+ attribute to do the actual rendering.
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
- end
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
- # A Page object wraps a meta information hash and an array of Block objects. It is normally
45
- # generated from a file or string in Webgen Page Format using the provided class methods.
46
- class Page
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 WebgenPageFormatError, 'Found start line for meta information block but no valid meta information block'
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 WebgenPageFormatError, "Invalid structure of meta information block: expected YAML hash but found #{meta_info.class}"
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 WebgenPageFormatError, e.message
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(WebgenPageFormatError, 'No content blocks specified') if scanned.length == 0
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(WebgenPageFormatError, "Found invalid blocks starting line for block #{index+1}: #{options}") if content =~ /\A---/ || md.nil?
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(WebgenPageFormatError, "Previously used name '#{name}' also used for block #{index+1}") if blocks.has_key?(name)
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!
@@ -109,7 +109,7 @@ module Webgen
109
109
  temp
110
110
  end
111
111
 
112
- # The IO object associated with the path.
112
+ # The SourceIO object associated with the path.
113
113
  def io
114
114
  if @io
115
115
  @io
@@ -4,15 +4,42 @@ module Webgen
4
4
 
5
5
  # Namespace for all classes that provide source paths.
6
6
  #
7
- # = Implementing a source class
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) which is not implemented in the
14
- # default Path class. One can either derive a specialized path class or define singleton methods
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 source provided by resources.
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