thewoolleyman-webgen 0.5.8.20090419

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 (309) hide show
  1. data/AUTHORS +8 -0
  2. data/COPYING +10 -0
  3. data/GPL +340 -0
  4. data/Rakefile +334 -0
  5. data/THANKS +18 -0
  6. data/bin/webgen +12 -0
  7. data/data/webgen/resources.yaml +3 -0
  8. data/data/webgen/webgui/controller/main.rb +135 -0
  9. data/data/webgen/webgui/overrides/win32console.rb +0 -0
  10. data/data/webgen/webgui/public/css/jquery.autocomplete.css +50 -0
  11. data/data/webgen/webgui/public/css/ramaze_error.css +90 -0
  12. data/data/webgen/webgui/public/css/style.css +55 -0
  13. data/data/webgen/webgui/public/img/headerbg.jpg +0 -0
  14. data/data/webgen/webgui/public/img/webgen_logo.png +0 -0
  15. data/data/webgen/webgui/public/js/jquery.autocomplete.js +15 -0
  16. data/data/webgen/webgui/public/js/jquery.js +32 -0
  17. data/data/webgen/webgui/view/create_website.xhtml +22 -0
  18. data/data/webgen/webgui/view/error.xhtml +64 -0
  19. data/data/webgen/webgui/view/index.xhtml +22 -0
  20. data/data/webgen/webgui/view/manage_website.xhtml +18 -0
  21. data/data/webgen/webgui/view/page.xhtml +40 -0
  22. data/data/webgen/website_skeleton/README +10 -0
  23. data/data/webgen/website_skeleton/Rakefile +40 -0
  24. data/data/webgen/website_skeleton/config.yaml +17 -0
  25. data/data/webgen/website_skeleton/ext/init.rb +10 -0
  26. data/data/webgen/website_styles/1024px/README +13 -0
  27. data/data/webgen/website_styles/1024px/src/default.css +188 -0
  28. data/data/webgen/website_styles/1024px/src/default.template +60 -0
  29. data/data/webgen/website_styles/1024px/src/images/background.gif +0 -0
  30. data/data/webgen/website_styles/andreas00/README +13 -0
  31. data/data/webgen/website_styles/andreas00/src/default.css +290 -0
  32. data/data/webgen/website_styles/andreas00/src/default.template +60 -0
  33. data/data/webgen/website_styles/andreas00/src/images/bg.gif +0 -0
  34. data/data/webgen/website_styles/andreas00/src/images/front.jpg +0 -0
  35. data/data/webgen/website_styles/andreas00/src/images/menubg.gif +0 -0
  36. data/data/webgen/website_styles/andreas00/src/images/menubg2.gif +0 -0
  37. data/data/webgen/website_styles/andreas01/README +14 -0
  38. data/data/webgen/website_styles/andreas01/src/default.css +310 -0
  39. data/data/webgen/website_styles/andreas01/src/default.template +62 -0
  40. data/data/webgen/website_styles/andreas01/src/images/bg.gif +0 -0
  41. data/data/webgen/website_styles/andreas01/src/images/front.jpg +0 -0
  42. data/data/webgen/website_styles/andreas01/src/print.css +35 -0
  43. data/data/webgen/website_styles/andreas03/README +14 -0
  44. data/data/webgen/website_styles/andreas03/src/default.css +223 -0
  45. data/data/webgen/website_styles/andreas03/src/default.template +58 -0
  46. data/data/webgen/website_styles/andreas03/src/images/bodybg.png +0 -0
  47. data/data/webgen/website_styles/andreas03/src/images/contbg.png +0 -0
  48. data/data/webgen/website_styles/andreas03/src/images/footerbg.png +0 -0
  49. data/data/webgen/website_styles/andreas03/src/images/gradient1.png +0 -0
  50. data/data/webgen/website_styles/andreas03/src/images/gradient2.png +0 -0
  51. data/data/webgen/website_styles/andreas04/README +15 -0
  52. data/data/webgen/website_styles/andreas04/src/default.css +290 -0
  53. data/data/webgen/website_styles/andreas04/src/default.template +81 -0
  54. data/data/webgen/website_styles/andreas04/src/images/blinkarrow.gif +0 -0
  55. data/data/webgen/website_styles/andreas04/src/images/bodybg.png +0 -0
  56. data/data/webgen/website_styles/andreas04/src/images/contentbg.png +0 -0
  57. data/data/webgen/website_styles/andreas04/src/images/entrybg.png +0 -0
  58. data/data/webgen/website_styles/andreas04/src/images/flash.gif +0 -0
  59. data/data/webgen/website_styles/andreas04/src/images/flash2.gif +0 -0
  60. data/data/webgen/website_styles/andreas04/src/images/globe.gif +0 -0
  61. data/data/webgen/website_styles/andreas04/src/images/globebottom.gif +0 -0
  62. data/data/webgen/website_styles/andreas04/src/images/linkarrow.gif +0 -0
  63. data/data/webgen/website_styles/andreas04/src/images/menuhover.png +0 -0
  64. data/data/webgen/website_styles/andreas05/README +14 -0
  65. data/data/webgen/website_styles/andreas05/src/default.css +33 -0
  66. data/data/webgen/website_styles/andreas05/src/default.template +40 -0
  67. data/data/webgen/website_styles/andreas05/src/images/bodybg.gif +0 -0
  68. data/data/webgen/website_styles/andreas05/src/images/front.png +0 -0
  69. data/data/webgen/website_styles/andreas06/README +14 -0
  70. data/data/webgen/website_styles/andreas06/src/default.css +354 -0
  71. data/data/webgen/website_styles/andreas06/src/default.template +70 -0
  72. data/data/webgen/website_styles/andreas06/src/images/bodybg.gif +0 -0
  73. data/data/webgen/website_styles/andreas06/src/images/boxbg.gif +0 -0
  74. data/data/webgen/website_styles/andreas06/src/images/greypx.gif +0 -0
  75. data/data/webgen/website_styles/andreas06/src/images/header.jpg +0 -0
  76. data/data/webgen/website_styles/andreas06/src/images/innerbg.gif +0 -0
  77. data/data/webgen/website_styles/andreas06/src/images/leaves.jpg +0 -0
  78. data/data/webgen/website_styles/andreas06/src/images/tabs.gif +0 -0
  79. data/data/webgen/website_styles/andreas07/README +15 -0
  80. data/data/webgen/website_styles/andreas07/src/browserfix.css +7 -0
  81. data/data/webgen/website_styles/andreas07/src/default.css +92 -0
  82. data/data/webgen/website_styles/andreas07/src/default.template +42 -0
  83. data/data/webgen/website_styles/andreas07/src/images/bodybg.gif +0 -0
  84. data/data/webgen/website_styles/andreas07/src/images/sidebarbg.gif +0 -0
  85. data/data/webgen/website_styles/andreas08/README +14 -0
  86. data/data/webgen/website_styles/andreas08/src/default.css +224 -0
  87. data/data/webgen/website_styles/andreas08/src/default.template +51 -0
  88. data/data/webgen/website_styles/andreas09/README +14 -0
  89. data/data/webgen/website_styles/andreas09/src/default.css +308 -0
  90. data/data/webgen/website_styles/andreas09/src/default.template +68 -0
  91. data/data/webgen/website_styles/andreas09/src/images/bodybg-black.jpg +0 -0
  92. data/data/webgen/website_styles/andreas09/src/images/bodybg-green.jpg +0 -0
  93. data/data/webgen/website_styles/andreas09/src/images/bodybg-orange.jpg +0 -0
  94. data/data/webgen/website_styles/andreas09/src/images/bodybg-purple.jpg +0 -0
  95. data/data/webgen/website_styles/andreas09/src/images/bodybg-red.jpg +0 -0
  96. data/data/webgen/website_styles/andreas09/src/images/bodybg.jpg +0 -0
  97. data/data/webgen/website_styles/andreas09/src/images/footerbg.jpg +0 -0
  98. data/data/webgen/website_styles/andreas09/src/images/menuhover-black.jpg +0 -0
  99. data/data/webgen/website_styles/andreas09/src/images/menuhover-green.jpg +0 -0
  100. data/data/webgen/website_styles/andreas09/src/images/menuhover-orange.jpg +0 -0
  101. data/data/webgen/website_styles/andreas09/src/images/menuhover-purple.jpg +0 -0
  102. data/data/webgen/website_styles/andreas09/src/images/menuhover-red.jpg +0 -0
  103. data/data/webgen/website_styles/andreas09/src/images/menuhover.jpg +0 -0
  104. data/data/webgen/website_styles/simple/README +6 -0
  105. data/data/webgen/website_styles/simple/src/default.css +84 -0
  106. data/data/webgen/website_styles/simple/src/default.template +36 -0
  107. data/data/webgen/website_templates/default/README +6 -0
  108. data/data/webgen/website_templates/default/src/index.page +8 -0
  109. data/data/webgen/website_templates/project/README +5 -0
  110. data/data/webgen/website_templates/project/src/about.page +12 -0
  111. data/data/webgen/website_templates/project/src/download.page +15 -0
  112. data/data/webgen/website_templates/project/src/features.page +8 -0
  113. data/data/webgen/website_templates/project/src/index.page +9 -0
  114. data/data/webgen/website_templates/project/src/screenshots.page +18 -0
  115. data/doc/contentprocessor.template +11 -0
  116. data/doc/contentprocessor/blocks.page +129 -0
  117. data/doc/contentprocessor/builder.page +80 -0
  118. data/doc/contentprocessor/erb.page +59 -0
  119. data/doc/contentprocessor/erubis.page +46 -0
  120. data/doc/contentprocessor/fragments.page +25 -0
  121. data/doc/contentprocessor/haml.page +47 -0
  122. data/doc/contentprocessor/maruku.page +41 -0
  123. data/doc/contentprocessor/rdiscount.page +37 -0
  124. data/doc/contentprocessor/rdoc.page +36 -0
  125. data/doc/contentprocessor/redcloth.page +39 -0
  126. data/doc/contentprocessor/sass.page +31 -0
  127. data/doc/contentprocessor/tags.page +73 -0
  128. data/doc/extensions.metainfo +29 -0
  129. data/doc/extensions.page +16 -0
  130. data/doc/extensions.template +17 -0
  131. data/doc/faq.page +219 -0
  132. data/doc/getting_started.page +135 -0
  133. data/doc/index.page +65 -0
  134. data/doc/manual.page +589 -0
  135. data/doc/reference_configuration.page +959 -0
  136. data/doc/reference_metainfo.page +222 -0
  137. data/doc/source/filesystem.page +39 -0
  138. data/doc/source/tararchive.page +40 -0
  139. data/doc/sourcehandler.template +21 -0
  140. data/doc/sourcehandler/copy.page +19 -0
  141. data/doc/sourcehandler/directory.page +27 -0
  142. data/doc/sourcehandler/feed.page +105 -0
  143. data/doc/sourcehandler/metainfo.page +41 -0
  144. data/doc/sourcehandler/page.page +14 -0
  145. data/doc/sourcehandler/sitemap.page +46 -0
  146. data/doc/sourcehandler/template.page +45 -0
  147. data/doc/sourcehandler/virtual.page +49 -0
  148. data/doc/tag.template +25 -0
  149. data/doc/tag/breadcrumbtrail.page +40 -0
  150. data/doc/tag/coderay.page +49 -0
  151. data/doc/tag/date.page +31 -0
  152. data/doc/tag/executecommand.page +26 -0
  153. data/doc/tag/includefile.page +32 -0
  154. data/doc/tag/langbar.page +44 -0
  155. data/doc/tag/link.page +44 -0
  156. data/doc/tag/menu.page +106 -0
  157. data/doc/tag/metainfo.page +29 -0
  158. data/doc/tag/relocatable.page +38 -0
  159. data/doc/tag/sitemap.page +31 -0
  160. data/doc/tag/tikz.page +158 -0
  161. data/doc/upgrading.page +139 -0
  162. data/doc/webgen_page_format.page +129 -0
  163. data/lib/webgen/blackboard.rb +78 -0
  164. data/lib/webgen/cache.rb +87 -0
  165. data/lib/webgen/cli.rb +124 -0
  166. data/lib/webgen/cli/apply_command.rb +64 -0
  167. data/lib/webgen/cli/create_command.rb +66 -0
  168. data/lib/webgen/cli/run_command.rb +22 -0
  169. data/lib/webgen/cli/utils.rb +88 -0
  170. data/lib/webgen/cli/webgui_command.rb +72 -0
  171. data/lib/webgen/common.rb +21 -0
  172. data/lib/webgen/common/sitemap.rb +83 -0
  173. data/lib/webgen/configuration.rb +153 -0
  174. data/lib/webgen/contentprocessor.rb +99 -0
  175. data/lib/webgen/contentprocessor/blocks.rb +60 -0
  176. data/lib/webgen/contentprocessor/builder.rb +30 -0
  177. data/lib/webgen/contentprocessor/context.rb +89 -0
  178. data/lib/webgen/contentprocessor/erb.rb +28 -0
  179. data/lib/webgen/contentprocessor/erubis.rb +40 -0
  180. data/lib/webgen/contentprocessor/fragments.rb +25 -0
  181. data/lib/webgen/contentprocessor/haml.rb +30 -0
  182. data/lib/webgen/contentprocessor/maruku.rb +20 -0
  183. data/lib/webgen/contentprocessor/rdiscount.rb +17 -0
  184. data/lib/webgen/contentprocessor/rdoc.rb +19 -0
  185. data/lib/webgen/contentprocessor/redcloth.rb +17 -0
  186. data/lib/webgen/contentprocessor/sass.rb +20 -0
  187. data/lib/webgen/contentprocessor/tags.rb +136 -0
  188. data/lib/webgen/coreext.rb +13 -0
  189. data/lib/webgen/default_config.rb +215 -0
  190. data/lib/webgen/languages.rb +589 -0
  191. data/lib/webgen/loggable.rb +25 -0
  192. data/lib/webgen/logger.rb +97 -0
  193. data/lib/webgen/node.rb +391 -0
  194. data/lib/webgen/output.rb +82 -0
  195. data/lib/webgen/output/filesystem.rb +69 -0
  196. data/lib/webgen/page.rb +153 -0
  197. data/lib/webgen/path.rb +194 -0
  198. data/lib/webgen/source.rb +54 -0
  199. data/lib/webgen/source/filesystem.rb +61 -0
  200. data/lib/webgen/source/resource.rb +44 -0
  201. data/lib/webgen/source/stacked.rb +55 -0
  202. data/lib/webgen/source/tararchive.rb +73 -0
  203. data/lib/webgen/sourcehandler.rb +226 -0
  204. data/lib/webgen/sourcehandler/base.rb +248 -0
  205. data/lib/webgen/sourcehandler/copy.rb +43 -0
  206. data/lib/webgen/sourcehandler/directory.rb +36 -0
  207. data/lib/webgen/sourcehandler/feed.rb +117 -0
  208. data/lib/webgen/sourcehandler/fragment.rb +68 -0
  209. data/lib/webgen/sourcehandler/memory.rb +43 -0
  210. data/lib/webgen/sourcehandler/metainfo.rb +128 -0
  211. data/lib/webgen/sourcehandler/page.rb +59 -0
  212. data/lib/webgen/sourcehandler/sitemap.rb +60 -0
  213. data/lib/webgen/sourcehandler/template.rb +66 -0
  214. data/lib/webgen/sourcehandler/virtual.rb +110 -0
  215. data/lib/webgen/tag.rb +27 -0
  216. data/lib/webgen/tag/base.rb +170 -0
  217. data/lib/webgen/tag/breadcrumbtrail.rb +70 -0
  218. data/lib/webgen/tag/coderay.rb +31 -0
  219. data/lib/webgen/tag/date.rb +18 -0
  220. data/lib/webgen/tag/executecommand.rb +30 -0
  221. data/lib/webgen/tag/includefile.rb +42 -0
  222. data/lib/webgen/tag/langbar.rb +52 -0
  223. data/lib/webgen/tag/link.rb +26 -0
  224. data/lib/webgen/tag/menu.rb +207 -0
  225. data/lib/webgen/tag/metainfo.rb +25 -0
  226. data/lib/webgen/tag/relocatable.rb +54 -0
  227. data/lib/webgen/tag/sitemap.rb +41 -0
  228. data/lib/webgen/tag/tikz.rb +119 -0
  229. data/lib/webgen/tree.rb +90 -0
  230. data/lib/webgen/version.rb +8 -0
  231. data/lib/webgen/webgentask.rb +152 -0
  232. data/lib/webgen/website.rb +342 -0
  233. data/lib/webgen/websiteaccess.rb +31 -0
  234. data/lib/webgen/websitemanager.rb +127 -0
  235. data/man/man1/webgen.1 +73 -0
  236. data/misc/default.css +384 -0
  237. data/misc/default.template +75 -0
  238. data/misc/htmldoc.metainfo +25 -0
  239. data/misc/htmldoc.virtual +5 -0
  240. data/misc/images/arrow.gif +0 -0
  241. data/misc/images/error.png +0 -0
  242. data/misc/images/headerbg.jpg +0 -0
  243. data/misc/images/important.png +0 -0
  244. data/misc/images/information.png +0 -0
  245. data/misc/images/quote.gif +0 -0
  246. data/misc/images/warning.png +0 -0
  247. data/setup.rb +1585 -0
  248. data/test/helper.rb +45 -0
  249. data/test/test_blackboard.rb +60 -0
  250. data/test/test_cache.rb +59 -0
  251. data/test/test_cli.rb +21 -0
  252. data/test/test_common.rb +18 -0
  253. data/test/test_common_sitemap.rb +58 -0
  254. data/test/test_configuration.rb +68 -0
  255. data/test/test_contentprocessor.rb +33 -0
  256. data/test/test_contentprocessor_blocks.rb +68 -0
  257. data/test/test_contentprocessor_builder.rb +23 -0
  258. data/test/test_contentprocessor_context.rb +40 -0
  259. data/test/test_contentprocessor_erb.rb +23 -0
  260. data/test/test_contentprocessor_erubis.rb +49 -0
  261. data/test/test_contentprocessor_fragments.rb +42 -0
  262. data/test/test_contentprocessor_haml.rb +23 -0
  263. data/test/test_contentprocessor_maruku.rb +29 -0
  264. data/test/test_contentprocessor_rdiscount.rb +17 -0
  265. data/test/test_contentprocessor_rdoc.rb +18 -0
  266. data/test/test_contentprocessor_redcloth.rb +15 -0
  267. data/test/test_contentprocessor_sass.rb +22 -0
  268. data/test/test_contentprocessor_tags.rb +99 -0
  269. data/test/test_languages.rb +67 -0
  270. data/test/test_loggable.rb +32 -0
  271. data/test/test_logger.rb +94 -0
  272. data/test/test_node.rb +367 -0
  273. data/test/test_output_filesystem.rb +60 -0
  274. data/test/test_page.rb +214 -0
  275. data/test/test_path.rb +165 -0
  276. data/test/test_source_filesystem.rb +76 -0
  277. data/test/test_source_resource.rb +28 -0
  278. data/test/test_source_stacked.rb +36 -0
  279. data/test/test_source_tararchive.rb +65 -0
  280. data/test/test_sourcehandler_base.rb +123 -0
  281. data/test/test_sourcehandler_copy.rb +47 -0
  282. data/test/test_sourcehandler_directory.rb +42 -0
  283. data/test/test_sourcehandler_feed.rb +77 -0
  284. data/test/test_sourcehandler_fragment.rb +69 -0
  285. data/test/test_sourcehandler_memory.rb +44 -0
  286. data/test/test_sourcehandler_metainfo.rb +118 -0
  287. data/test/test_sourcehandler_page.rb +65 -0
  288. data/test/test_sourcehandler_sitemap.rb +49 -0
  289. data/test/test_sourcehandler_template.rb +65 -0
  290. data/test/test_sourcehandler_virtual.rb +87 -0
  291. data/test/test_tag_base.rb +85 -0
  292. data/test/test_tag_breadcrumbtrail.rb +91 -0
  293. data/test/test_tag_coderay.rb +32 -0
  294. data/test/test_tag_date.rb +18 -0
  295. data/test/test_tag_executecommand.rb +41 -0
  296. data/test/test_tag_includefile.rb +50 -0
  297. data/test/test_tag_langbar.rb +72 -0
  298. data/test/test_tag_link.rb +69 -0
  299. data/test/test_tag_menu.rb +207 -0
  300. data/test/test_tag_metainfo.rb +19 -0
  301. data/test/test_tag_relocatable.rb +59 -0
  302. data/test/test_tag_sitemap.rb +47 -0
  303. data/test/test_tag_tikz.rb +69 -0
  304. data/test/test_tree.rb +70 -0
  305. data/test/test_webgentask.rb +23 -0
  306. data/test/test_website.rb +98 -0
  307. data/test/test_websiteaccess.rb +25 -0
  308. data/test/test_websitemanager.rb +70 -0
  309. metadata +613 -0
@@ -0,0 +1,82 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ module Webgen
4
+
5
+ # Namespace for all classes that know how to write out node content.
6
+ #
7
+ # == Implementing an output class
8
+ #
9
+ # Output classes know how to write rendered node data to an output location.
10
+ #
11
+ # An output class must respond to three methods
12
+ #
13
+ # [<tt>exists?(path)</tt>]
14
+ # Return +true+ if the output path exists.
15
+ # [<tt>delete(path)</tt>]
16
+ # Delete the given output path.
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>]
22
+ # Return the content of the given path if it exists or raise an error otherwise.
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
+ #
66
+ module Output
67
+
68
+ autoload :FileSystem, 'webgen/output/filesystem'
69
+
70
+ # Returns an instance of the configured output class.
71
+ def self.instance
72
+ classes = (WebsiteAccess.website.cache.volatile[:classes] ||= {})
73
+ unless classes.has_key?(:output_instance)
74
+ klass, *args = WebsiteAccess.website.config['output']
75
+ classes[:output_instance] = Object.constant(klass).new(*args)
76
+ end
77
+ classes[:output_instance]
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,69 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'fileutils'
4
+
5
+ module Webgen::Output
6
+
7
+ # This class uses the file systems as output device. On initialization a +root+ path is set and
8
+ # all other operations are taken relative to this root path.
9
+ class FileSystem
10
+
11
+ include Webgen::WebsiteAccess
12
+
13
+ # The root path, ie. the path to which the root node gets rendered.
14
+ attr_reader :root
15
+
16
+ # Create a new object with the given +root+ path. If +root+ is not absolute, it is taken
17
+ # relative to the website directory.
18
+ def initialize(root)
19
+ #TODO: copied from source/filesystem.rb
20
+ if root =~ /^([a-zA-Z]:|\/)/
21
+ @root = root
22
+ else
23
+ @root = File.join(website.directory, root)
24
+ end
25
+ end
26
+
27
+ # Return +true+ if the given path exists.
28
+ def exists?(path)
29
+ File.exists?(File.join(@root, path))
30
+ end
31
+
32
+ # Delete the given +path+
33
+ def delete(path)
34
+ dest = File.join(@root, path)
35
+ if File.directory?(dest)
36
+ FileUtils.rm_rf(dest)
37
+ else
38
+ FileUtils.rm(dest)
39
+ end
40
+ end
41
+
42
+ # Write the +data+ to the given +path+. The +type+ parameter specifies the type of the path to
43
+ # be created which can either be <tt>:file</tt> or <tt>:directory</tt>.
44
+ def write(path, data, type = :file)
45
+ dest = File.join(@root, path)
46
+ FileUtils.makedirs(File.dirname(dest))
47
+ if type == :directory
48
+ FileUtils.makedirs(dest)
49
+ elsif type == :file
50
+ if data.kind_of?(String)
51
+ File.open(dest, 'wb') {|f| f.write(data) }
52
+ else
53
+ data.stream do |source|
54
+ File.open(dest, 'wb') {|f| FileUtils.copy_stream(source, f) }
55
+ end
56
+ end
57
+ else
58
+ raise "Unsupported path type '#{type}' for #{path}"
59
+ end
60
+ end
61
+
62
+ # Return the content of the given +path+.
63
+ def read(path)
64
+ File.open(File.join(@root, path), 'rb') {|f| f.read}
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -0,0 +1,153 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'yaml'
4
+
5
+ module Webgen
6
+
7
+ # A single block within a Page object. The content of the block can be rendered using the #render method.
8
+ class Block
9
+
10
+ # The name of the block.
11
+ attr_reader :name
12
+
13
+ # The content of the block.
14
+ attr_reader :content
15
+
16
+ # The options set specifically for this block.
17
+ attr_reader :options
18
+
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
23
+
24
+ # Render the block using the provided context object.
25
+ #
26
+ # The context object needs to respond to <tt>#[]</tt> and <tt>#[]=</tt> (e.g. a Hash is a valid
27
+ # context object) and the key <tt>:processors</tt> needs to contain a Hash which maps processor
28
+ # names to processor objects that respond to <tt>#call</tt>.
29
+ #
30
+ # Uses the content processors specified in the +pipeline+ key of the +options+ attribute to do
31
+ # the actual rendering.
32
+ #
33
+ # Returns the given context with the rendered content.
34
+ def render(context)
35
+ context[:content] = @content.dup
36
+ context[:block] = self
37
+ @options['pipeline'].to_s.split(/,/).each do |processor|
38
+ raise "No such content processor available: #{processor}" unless context[:processors].has_key?(processor)
39
+ context[:processors][processor].call(context)
40
+ end
41
+ context
42
+ end
43
+
44
+ end
45
+
46
+
47
+ # Raised during parsing of data in Webgen Page Format if the data is invalid.
48
+ class WebgenPageFormatError < RuntimeError; end
49
+
50
+ # A Page object wraps a meta information hash and an array of Block objects. It is normally
51
+ # generated from a file or string in Webgen Page Format using the provided class methods.
52
+ class Page
53
+
54
+ # :stopdoc:
55
+ RE_META_INFO_START = /\A---\s*(?:\n|\r|\r\n)/m
56
+ RE_META_INFO = /\A---\s*(?:\n|\r|\r\n).*?(?:\n|\r|\r\n)(?=---.*?(?:\n|\r|\r\n)|\Z)/m
57
+ RE_BLOCKS_OPTIONS = /^--- *?(?: *((?:\w+:[^\s]* *)*))?$|^$/
58
+ RE_BLOCKS_START = /^--- .*?$|^--- *$/
59
+ RE_BLOCKS = /(?:(#{RE_BLOCKS_START})|\A)(.*?)(?:(?=#{RE_BLOCKS_START})|\Z)/m
60
+ # :startdoc:
61
+
62
+ class << self
63
+
64
+ # Parse the given string +data+ in Webgen Page Format and initialize a new Page object with
65
+ # the information. The +meta_info+ parameter can be used to provide default meta information.
66
+ def from_data(data, meta_info = {})
67
+ md = /(#{RE_META_INFO})?(.*)/m.match(normalize_eol(data))
68
+ meta_info = meta_info.merge(parse_meta_info(md[1], data))
69
+ blocks = parse_blocks(md[2] || '', meta_info)
70
+ new(meta_info, blocks)
71
+ end
72
+
73
+ # Parse the given string +data+ in Webgen Page Format and return the found meta information.
74
+ def meta_info_from_data(data)
75
+ md = /(#{RE_META_INFO})?/m.match(normalize_eol(data))
76
+ parse_meta_info(md[1], data)
77
+ end
78
+
79
+ #######
80
+ private
81
+ #######
82
+
83
+ # Normalize the end-of-line encodings to Unix style.
84
+ def normalize_eol(data)
85
+ data.gsub(/\r\n?/, "\n")
86
+ end
87
+
88
+ # Parse the meta info string in +mi_data+ and return the hash with the meta information. The
89
+ # original +data+ is used for checking the validness of the meta information block.
90
+ def parse_meta_info(mi_data, data)
91
+ if mi_data.nil? && data =~ RE_META_INFO_START
92
+ raise WebgenPageFormatError, 'Found start line for meta information block but no valid meta information block'
93
+ elsif mi_data.nil?
94
+ {}
95
+ else
96
+ begin
97
+ meta_info = YAML::load(mi_data.to_s)
98
+ unless meta_info.kind_of?(Hash)
99
+ raise WebgenPageFormatError, "Invalid structure of meta information block: expected YAML hash but found #{meta_info.class}"
100
+ end
101
+ rescue ArgumentError => e
102
+ raise WebgenPageFormatError, e.message
103
+ end
104
+ meta_info
105
+ end
106
+ end
107
+
108
+ # Parse all blocks in +data+ and return them. Meta information can be provided in +meta_info+
109
+ # which is used for setting the block names and options.
110
+ def parse_blocks(data, meta_info)
111
+ scanned = data.scan(RE_BLOCKS)
112
+ raise(WebgenPageFormatError, 'No content blocks specified') if scanned.length == 0
113
+
114
+ blocks = {}
115
+ scanned.each_with_index do |block_data, index|
116
+ options, content = *block_data
117
+ md = RE_BLOCKS_OPTIONS.match(options.to_s)
118
+ raise(WebgenPageFormatError, "Found invalid blocks starting line for block #{index+1}: #{options}") if content =~ /\A---/ || md.nil?
119
+ options = Hash[*md[1].to_s.scan(/(\w+):([^\s]*)/).map {|k,v| [k, (v == '' ? nil : YAML::load(v))]}.flatten]
120
+ options = (meta_info['blocks']['default'] || {} rescue {}).
121
+ merge((meta_info['blocks'][index+1] || {} rescue {})).
122
+ merge(options)
123
+
124
+ name = options.delete('name') || (index == 0 ? 'content' : 'block' + (index + 1).to_s)
125
+ raise(WebgenPageFormatError, "Previously used name '#{name}' also used for block #{index+1}") if blocks.has_key?(name)
126
+ content ||= ''
127
+ content.gsub!(/^(\\+)(---.*?)$/) {|m| "\\" * ($1.length / 2) + $2}
128
+ content.strip!
129
+ blocks[name] = blocks[index+1] = Block.new(name, content, options)
130
+ end
131
+ meta_info.delete('blocks')
132
+ blocks
133
+ end
134
+
135
+ end
136
+
137
+
138
+ # The contents of the meta information block.
139
+ attr_reader :meta_info
140
+
141
+ # The hash of blocks for the page.
142
+ attr_reader :blocks
143
+
144
+ # Create a new Page object with the meta information provided in +meta_info+ and the given
145
+ # +blocks+.
146
+ def initialize(meta_info = {}, blocks = {})
147
+ @meta_info = meta_info
148
+ @blocks = blocks
149
+ end
150
+
151
+ end
152
+
153
+ end
@@ -0,0 +1,194 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'webgen/languages'
4
+
5
+ module Webgen
6
+
7
+ # A path object provides information about a specific path as well as methods for accessing its
8
+ # content.
9
+ #
10
+ # A webgen source class needs to derive a specialized path class from this class and implement an
11
+ # approriate #changed? method that returns +true+ if the path's content has changed since the last
12
+ # webgen run.
13
+ class Path
14
+
15
+ # Helper class for easy access to the content of a path.
16
+ class SourceIO
17
+
18
+ # Create a new SourceIO object. A block has to be specified that returns an IO object.
19
+ def initialize(&block)
20
+ @block = block
21
+ raise ArgumentError, 'Need to provide a block which returns an IO object' if @block.nil?
22
+ end
23
+
24
+ # Provide direct access to the wrapped IO object.
25
+ def stream
26
+ io = @block.call
27
+ yield(io)
28
+ ensure
29
+ io.close
30
+ end
31
+
32
+ # Return the content of the wrapped IO object as string.
33
+ def data
34
+ stream {|io| io.read}
35
+ end
36
+
37
+ end
38
+
39
+
40
+ # Return +true+ if the given +path+ matches the given +pattern+ (trailing slashes of directories
41
+ # are not respected). For information on which patterns are supported, have a look at the
42
+ # documentation of File.fnmatch.
43
+ def self.match(path, pattern)
44
+ path = path.to_s.chomp('/') unless path == '/'
45
+ pattern = pattern.to_s.chomp('/') unless pattern == '/'
46
+ File.fnmatch(pattern, path, File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME)
47
+ end
48
+
49
+
50
+ include Comparable
51
+
52
+ # The full path.
53
+ attr_accessor :path
54
+
55
+ # The source path that lead to the creation of this path.
56
+ attr_accessor :source_path
57
+
58
+ # The basename part of the path.
59
+ attr_accessor :basename
60
+
61
+ # The directory part of the path.
62
+ attr_accessor :directory
63
+
64
+ # The canonical name without the extension.
65
+ attr_accessor :cnbase
66
+
67
+ # The extension.
68
+ attr_accessor :ext
69
+
70
+ # Extracted meta information for the path.
71
+ attr_accessor :meta_info
72
+
73
+ # Create a new Path object for +path+. The optional +source_path+ parameter specifies the path
74
+ # that lead to the creation of this path. The optional block needs to return an IO object for
75
+ # the content of the path.
76
+ def initialize(path, source_path = path, &ioblock)
77
+ @meta_info = {}
78
+ @io = block_given? ? SourceIO.new(&ioblock) : nil
79
+ @source_path = source_path
80
+ analyse(path)
81
+ end
82
+
83
+ # Mount this path at the mount point +mp+ optionally stripping +prefix+ from the path and return
84
+ # the new path object.
85
+ def mount_at(mp, prefix = nil)
86
+ temp = dup
87
+ temp.path = temp.path.sub(/^#{Regexp.escape(prefix.chomp("/"))}/, '') if prefix #"
88
+ reanalyse = (@path == '/' || temp.path == '/')
89
+ temp.path = File.join(mp, temp.path)
90
+ temp.source_path = temp.path if @path == @source_path
91
+ if reanalyse
92
+ temp.send(:analyse, temp.path)
93
+ else
94
+ temp.directory = File.join(File.dirname(temp.path), '/')
95
+ end
96
+ temp
97
+ end
98
+
99
+ # Has the content of this path changed since the last webgen run? This default implementation
100
+ # always returns +true+, a specialized sub class needs to override this behaviour!
101
+ def changed?
102
+ true
103
+ end
104
+
105
+ # Duplicate the path object.
106
+ def dup
107
+ temp = super
108
+ temp.meta_info = @meta_info.dup
109
+ temp
110
+ end
111
+
112
+ # The SourceIO object associated with the path.
113
+ def io
114
+ if @io
115
+ @io
116
+ else
117
+ raise "No IO object defined for the path #{self}"
118
+ end
119
+ end
120
+
121
+ # The canonical name created from the filename (created from cnbase and extension).
122
+ def cn
123
+ @cnbase + (@ext.length > 0 ? '.' + @ext : '')
124
+ end
125
+
126
+ # Utility method for creating the lcn from +cn+ and the language +lang+.
127
+ def self.lcn(cn, lang)
128
+ if lang.nil?
129
+ cn
130
+ else
131
+ cn.split('.').insert(1, lang.to_s).join('.')
132
+ end
133
+ end
134
+
135
+ # The localized canonical name created from the filename.
136
+ def lcn
137
+ self.class.lcn(cn, @meta_info['lang'])
138
+ end
139
+
140
+ # Compare this object to another Path or a String.
141
+ def ==(other)
142
+ if other.kind_of?(Path)
143
+ other.path == @path
144
+ elsif other.kind_of?(String)
145
+ other == @path
146
+ else
147
+ false
148
+ end
149
+ end
150
+ alias_method(:eql?, :==)
151
+
152
+ # Implemented sothat a Path looks like a String when used as key in a hash.
153
+ def <=>(other)
154
+ @path <=> other.to_str
155
+ end
156
+
157
+ # Implemented sothat a Path looks like a String when used as key in a hash.
158
+ def hash
159
+ @path.hash
160
+ end
161
+
162
+ def to_s #:nodoc:
163
+ @path.dup
164
+ end
165
+ alias_method :to_str, :to_s
166
+
167
+ def inspect #:nodoc:
168
+ "#<Path: #{@path}>"
169
+ end
170
+
171
+ #######
172
+ private
173
+ #######
174
+
175
+ FILENAME_RE = /^(?:(\d+)\.)?([^.]*?)(?:\.(\w\w\w?)(?=.))?(?:\.(.*))?$/
176
+
177
+ # Analyse the +path+ and fill the object with the extracted information.
178
+ def analyse(path)
179
+ @path = path
180
+ @basename = File.basename(path)
181
+ @directory = File.join(File.dirname(path), '/')
182
+ matchData = FILENAME_RE.match(@basename)
183
+
184
+ @meta_info['sort_info'] = (matchData[1].nil? ? nil : matchData[1].to_i)
185
+ @cnbase = matchData[2]
186
+ @meta_info['lang'] = Webgen::LanguageManager.language_for_code(matchData[3])
187
+ @ext = (@meta_info['lang'].nil? && !matchData[3].nil? ? matchData[3].to_s + '.' : '') + matchData[4].to_s
188
+
189
+ @meta_info['title'] = @cnbase.tr('_-', ' ').capitalize
190
+ end
191
+
192
+ end
193
+
194
+ end