gettalong-webgen 0.5.4.20080929

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 (290) hide show
  1. data/AUTHORS +5 -0
  2. data/COPYING +10 -0
  3. data/GPL +340 -0
  4. data/Rakefile +324 -0
  5. data/THANKS +17 -0
  6. data/bin/webgen +10 -0
  7. data/data/webgen/resources.yaml +3 -0
  8. data/data/webgen/webgui/controller/main.rb +129 -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 +6 -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 +61 -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 +66 -0
  117. data/doc/contentprocessor/builder.page +80 -0
  118. data/doc/contentprocessor/erb.page +56 -0
  119. data/doc/contentprocessor/erubis.page +46 -0
  120. data/doc/contentprocessor/haml.page +47 -0
  121. data/doc/contentprocessor/maruku.page +41 -0
  122. data/doc/contentprocessor/rdiscount.page +37 -0
  123. data/doc/contentprocessor/rdoc.page +36 -0
  124. data/doc/contentprocessor/redcloth.page +39 -0
  125. data/doc/contentprocessor/sass.page +31 -0
  126. data/doc/contentprocessor/tags.page +73 -0
  127. data/doc/extensions.metainfo +29 -0
  128. data/doc/extensions.page +16 -0
  129. data/doc/extensions.template +17 -0
  130. data/doc/faq.page +214 -0
  131. data/doc/getting_started.page +134 -0
  132. data/doc/index.page +65 -0
  133. data/doc/manual.page +532 -0
  134. data/doc/reference_configuration.page +646 -0
  135. data/doc/reference_metainfo.page +213 -0
  136. data/doc/sourcehandler.template +21 -0
  137. data/doc/sourcehandler/copy.page +19 -0
  138. data/doc/sourcehandler/directory.page +27 -0
  139. data/doc/sourcehandler/feed.page +82 -0
  140. data/doc/sourcehandler/metainfo.page +41 -0
  141. data/doc/sourcehandler/page.page +30 -0
  142. data/doc/sourcehandler/sitemap.page +46 -0
  143. data/doc/sourcehandler/template.page +45 -0
  144. data/doc/sourcehandler/virtual.page +49 -0
  145. data/doc/tag.template +25 -0
  146. data/doc/tag/breadcrumbtrail.page +40 -0
  147. data/doc/tag/coderay.page +49 -0
  148. data/doc/tag/date.page +31 -0
  149. data/doc/tag/executecommand.page +26 -0
  150. data/doc/tag/includefile.page +32 -0
  151. data/doc/tag/langbar.page +22 -0
  152. data/doc/tag/menu.page +92 -0
  153. data/doc/tag/metainfo.page +29 -0
  154. data/doc/tag/relocatable.page +38 -0
  155. data/doc/tag/sitemap.page +31 -0
  156. data/doc/upgrading.page +139 -0
  157. data/doc/webgen_page_format.page +128 -0
  158. data/lib/webgen/blackboard.rb +73 -0
  159. data/lib/webgen/cache.rb +85 -0
  160. data/lib/webgen/cli.rb +118 -0
  161. data/lib/webgen/cli/create_command.rb +64 -0
  162. data/lib/webgen/cli/run_command.rb +20 -0
  163. data/lib/webgen/cli/utils.rb +86 -0
  164. data/lib/webgen/cli/webgui_command.rb +49 -0
  165. data/lib/webgen/common.rb +10 -0
  166. data/lib/webgen/common/sitemap.rb +76 -0
  167. data/lib/webgen/configuration.rb +147 -0
  168. data/lib/webgen/contentprocessor.rb +96 -0
  169. data/lib/webgen/contentprocessor/blocks.rb +46 -0
  170. data/lib/webgen/contentprocessor/builder.rb +26 -0
  171. data/lib/webgen/contentprocessor/context.rb +90 -0
  172. data/lib/webgen/contentprocessor/erb.rb +24 -0
  173. data/lib/webgen/contentprocessor/erubis.rb +40 -0
  174. data/lib/webgen/contentprocessor/haml.rb +25 -0
  175. data/lib/webgen/contentprocessor/maruku.rb +18 -0
  176. data/lib/webgen/contentprocessor/rdiscount.rb +15 -0
  177. data/lib/webgen/contentprocessor/rdoc.rb +17 -0
  178. data/lib/webgen/contentprocessor/redcloth.rb +15 -0
  179. data/lib/webgen/contentprocessor/sass.rb +18 -0
  180. data/lib/webgen/contentprocessor/tags.rb +134 -0
  181. data/lib/webgen/coreext.rb +10 -0
  182. data/lib/webgen/default_config.rb +198 -0
  183. data/lib/webgen/languages.rb +578 -0
  184. data/lib/webgen/loggable.rb +23 -0
  185. data/lib/webgen/logger.rb +78 -0
  186. data/lib/webgen/node.rb +347 -0
  187. data/lib/webgen/output.rb +37 -0
  188. data/lib/webgen/output/filesystem.rb +67 -0
  189. data/lib/webgen/page.rb +133 -0
  190. data/lib/webgen/path.rb +182 -0
  191. data/lib/webgen/source.rb +24 -0
  192. data/lib/webgen/source/filesystem.rb +58 -0
  193. data/lib/webgen/source/resource.rb +42 -0
  194. data/lib/webgen/source/stacked.rb +53 -0
  195. data/lib/webgen/sourcehandler.rb +202 -0
  196. data/lib/webgen/sourcehandler/base.rb +211 -0
  197. data/lib/webgen/sourcehandler/copy.rb +41 -0
  198. data/lib/webgen/sourcehandler/directory.rb +31 -0
  199. data/lib/webgen/sourcehandler/feed.rb +121 -0
  200. data/lib/webgen/sourcehandler/fragment.rb +71 -0
  201. data/lib/webgen/sourcehandler/metainfo.rb +117 -0
  202. data/lib/webgen/sourcehandler/page.rb +77 -0
  203. data/lib/webgen/sourcehandler/sitemap.rb +60 -0
  204. data/lib/webgen/sourcehandler/template.rb +68 -0
  205. data/lib/webgen/sourcehandler/virtual.rb +75 -0
  206. data/lib/webgen/tag.rb +23 -0
  207. data/lib/webgen/tag/base.rb +162 -0
  208. data/lib/webgen/tag/breadcrumbtrail.rb +71 -0
  209. data/lib/webgen/tag/coderay.rb +32 -0
  210. data/lib/webgen/tag/date.rb +18 -0
  211. data/lib/webgen/tag/executecommand.rb +29 -0
  212. data/lib/webgen/tag/includefile.rb +42 -0
  213. data/lib/webgen/tag/langbar.rb +52 -0
  214. data/lib/webgen/tag/menu.rb +186 -0
  215. data/lib/webgen/tag/metainfo.rb +25 -0
  216. data/lib/webgen/tag/relocatable.rb +53 -0
  217. data/lib/webgen/tag/sitemap.rb +42 -0
  218. data/lib/webgen/tree.rb +80 -0
  219. data/lib/webgen/version.rb +6 -0
  220. data/lib/webgen/webgentask.rb +148 -0
  221. data/lib/webgen/website.rb +214 -0
  222. data/lib/webgen/websiteaccess.rb +29 -0
  223. data/lib/webgen/websitemanager.rb +125 -0
  224. data/man/man1/webgen.1 +67 -0
  225. data/misc/default.css +360 -0
  226. data/misc/default.template +75 -0
  227. data/misc/htmldoc.metainfo +25 -0
  228. data/misc/htmldoc.virtual +5 -0
  229. data/misc/images/arrow.gif +0 -0
  230. data/misc/images/error.gif +0 -0
  231. data/misc/images/exclamation.gif +0 -0
  232. data/misc/images/headerbg.jpg +0 -0
  233. data/misc/images/information.gif +0 -0
  234. data/misc/images/quote.gif +0 -0
  235. data/setup.rb +1585 -0
  236. data/test/helper.rb +41 -0
  237. data/test/test_blackboard.rb +58 -0
  238. data/test/test_cache.rb +57 -0
  239. data/test/test_common_sitemap.rb +56 -0
  240. data/test/test_configuration.rb +66 -0
  241. data/test/test_contentprocessor.rb +31 -0
  242. data/test/test_contentprocessor_blocks.rb +34 -0
  243. data/test/test_contentprocessor_builder.rb +19 -0
  244. data/test/test_contentprocessor_context.rb +38 -0
  245. data/test/test_contentprocessor_erb.rb +20 -0
  246. data/test/test_contentprocessor_erubis.rb +47 -0
  247. data/test/test_contentprocessor_haml.rb +20 -0
  248. data/test/test_contentprocessor_maruku.rb +27 -0
  249. data/test/test_contentprocessor_rdiscount.rb +15 -0
  250. data/test/test_contentprocessor_rdoc.rb +16 -0
  251. data/test/test_contentprocessor_redcloth.rb +12 -0
  252. data/test/test_contentprocessor_sass.rb +20 -0
  253. data/test/test_contentprocessor_tags.rb +97 -0
  254. data/test/test_languages.rb +53 -0
  255. data/test/test_loggable.rb +30 -0
  256. data/test/test_logger.rb +73 -0
  257. data/test/test_node.rb +339 -0
  258. data/test/test_output_filesystem.rb +58 -0
  259. data/test/test_page.rb +203 -0
  260. data/test/test_path.rb +131 -0
  261. data/test/test_source_filesystem.rb +59 -0
  262. data/test/test_source_resource.rb +26 -0
  263. data/test/test_source_stacked.rb +34 -0
  264. data/test/test_sourcehandler_base.rb +92 -0
  265. data/test/test_sourcehandler_copy.rb +45 -0
  266. data/test/test_sourcehandler_directory.rb +25 -0
  267. data/test/test_sourcehandler_feed.rb +74 -0
  268. data/test/test_sourcehandler_fragment.rb +67 -0
  269. data/test/test_sourcehandler_metainfo.rb +93 -0
  270. data/test/test_sourcehandler_page.rb +70 -0
  271. data/test/test_sourcehandler_sitemap.rb +47 -0
  272. data/test/test_sourcehandler_template.rb +63 -0
  273. data/test/test_sourcehandler_virtual.rb +56 -0
  274. data/test/test_tag_base.rb +82 -0
  275. data/test/test_tag_breadcrumbtrail.rb +89 -0
  276. data/test/test_tag_coderay.rb +30 -0
  277. data/test/test_tag_date.rb +16 -0
  278. data/test/test_tag_executecommand.rb +39 -0
  279. data/test/test_tag_includefile.rb +48 -0
  280. data/test/test_tag_langbar.rb +60 -0
  281. data/test/test_tag_menu.rb +195 -0
  282. data/test/test_tag_metainfo.rb +17 -0
  283. data/test/test_tag_relocatable.rb +57 -0
  284. data/test/test_tag_sitemap.rb +44 -0
  285. data/test/test_tree.rb +69 -0
  286. data/test/test_webgentask.rb +21 -0
  287. data/test/test_website.rb +96 -0
  288. data/test/test_websiteaccess.rb +23 -0
  289. data/test/test_websitemanager.rb +68 -0
  290. metadata +575 -0
@@ -0,0 +1,58 @@
1
+ require 'pathname'
2
+ require 'webgen/websiteaccess'
3
+ require 'webgen/path'
4
+
5
+ module Webgen
6
+
7
+ # This class is used to read source paths from a directory in the file system.
8
+ class Source::FileSystem
9
+
10
+ # A special Webgen::Path class for handling with file system paths.
11
+ class Path < Webgen::Path
12
+
13
+ # Create a new object with absolute path +path+ for the file system path +fs_path+.
14
+ def initialize(path, fs_path)
15
+ super(path) { File.open(fs_path, 'rb') }
16
+ @fs_path = fs_path
17
+ WebsiteAccess.website.cache[[:fs_path, @fs_path]] = File.mtime(@fs_path)
18
+ @meta_info['modified_at'] = File.mtime(@fs_path)
19
+ end
20
+
21
+ # Return +true+ if the file system path used by the object has been modified.
22
+ def changed?
23
+ data = WebsiteAccess.website.cache[[:fs_path, @fs_path]]
24
+ File.mtime(@fs_path) > data
25
+ end
26
+
27
+ end
28
+
29
+ # The root path from which paths read.
30
+ attr_reader :root
31
+
32
+ # The glob (see Dir.glob for details) that is used to specify which paths under the root path
33
+ # should be returned by #paths.
34
+ attr_reader :glob
35
+
36
+ # Create a new file system source for the root path +root+ using the provided +glob+.
37
+ def initialize(root, glob = '**/*')
38
+ if root =~ /^([a-zA-Z]:|\/)/
39
+ @root = root
40
+ else
41
+ @root = File.join(WebsiteAccess.website.directory, root)
42
+ end
43
+ @glob = glob
44
+ end
45
+
46
+ # Return all paths under #root which match #glob.
47
+ def paths
48
+ @paths ||= Dir.glob(File.join(@root, @glob), File::FNM_DOTMATCH|File::FNM_CASEFOLD).to_set.collect! do |f|
49
+ temp = Pathname.new(f.sub(/^#{Regexp.escape(@root)}\/?/, '/')).cleanpath.to_s
50
+ temp += '/' if File.directory?(f) && temp[-1] != ?/
51
+ path = Path.new(temp, f)
52
+ path
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ end
@@ -0,0 +1,42 @@
1
+ require 'webgen/websiteaccess'
2
+ require 'webgen/source'
3
+
4
+ module Webgen::Source
5
+
6
+ # This class is used to provide access to source provided by resources.
7
+ class Resource
8
+
9
+ include Webgen::WebsiteAccess
10
+
11
+ # The glob specifying the resources.
12
+ attr_reader :glob
13
+
14
+ # The glob specifying the paths that should be used from the resources.
15
+ attr_reader :paths_glob
16
+
17
+ # The prefix that should optionally be stripped from the paths.
18
+ attr_reader :strip_prefix
19
+
20
+ # Create a new resource source for the the +glob+ and use only those paths matching +paths_glob+
21
+ # while stripping +strip_prefix+ off the path.
22
+ def initialize(glob, paths_glob = nil, strip_prefix = nil)
23
+ @glob, @paths_glob, @strip_prefix = glob, paths_glob, strip_prefix
24
+ end
25
+
26
+ # Return all paths associated with the resources identified by #glob.
27
+ def paths
28
+ if !defined?(@paths)
29
+ stack = Stacked.new
30
+ website.config['resources'].select {|name, infos| File.fnmatch(@glob, name)}.sort.each do |name, infos|
31
+ stack.add([['/', constant(infos.first).new(*infos[1..-1])]])
32
+ end
33
+ @paths = stack.paths
34
+ @paths = @paths.select {|p| File.fnmatch(@paths_glob, p)} if @paths_glob
35
+ @paths.collect! {|p| p.mount_at('/', @strip_prefix)} if @strip_prefix
36
+ end
37
+ @paths
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,53 @@
1
+ module Webgen::Source
2
+
3
+ # This source class is used to stack several sources together.
4
+ #
5
+ # It serves two purposes:
6
+ #
7
+ # * First, it can be used to access more than one source. This is useful when your website
8
+ # consists of more than one source directory and you want to use all of them.
9
+ #
10
+ # * Second, sources can mounted on specific directories. For example, a folder with images that
11
+ # you don't want to copy to the website source directory can be mounted under <tt>/images</tt>
12
+ # sothat they are available nonetheless.
13
+ #
14
+ # Also be aware that when a path is returned by a source that has already be returned by a prior
15
+ # source, it is discarded and not used.
16
+ class Stacked
17
+
18
+ # Return the stack of Webgen::Source objects.
19
+ attr_reader :stack
20
+
21
+ # Create a new stack. The optional +map+ parameter can be used to provide initial mappings of
22
+ # mount points to source objects (see #add for details).
23
+ def initialize(map = {})
24
+ @stack = []
25
+ add(map)
26
+ end
27
+
28
+ # Add all mappings found in +maps+ to the stack. The parameter +maps+ should be an array of
29
+ # two-element arrays which contain an absolute directoriy (ie. starting with a slash) and a
30
+ # source object.
31
+ def add(maps)
32
+ maps.each do |mp, source|
33
+ raise "Invalid mount point specified: #{mp}" unless mp =~ /^\//
34
+ @stack << [mp, source]
35
+ end
36
+ end
37
+
38
+ # Return all paths returned by the sources in the stack. Since the stack is ordered, paths
39
+ # returned by later source objects are not used if a prior source object has returned the same
40
+ # path.
41
+ def paths
42
+ @paths = Set.new
43
+ @stack.each do |mp, source|
44
+ source.paths.each do |path|
45
+ @paths.add?(path.mount_at(mp))
46
+ end
47
+ end
48
+ @paths
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,202 @@
1
+ require 'webgen/loggable'
2
+ require 'benchmark'
3
+
4
+ module Webgen
5
+
6
+ # Namespace for all classes that handle source paths.
7
+ #
8
+ # Have a look at Webgen::SourceHandler::Base for details on how to implement a source handler
9
+ # class.
10
+ module SourceHandler
11
+
12
+ autoload :Base, 'webgen/sourcehandler/base'
13
+ autoload :Copy, 'webgen/sourcehandler/copy'
14
+ autoload :Directory, 'webgen/sourcehandler/directory'
15
+ autoload :Metainfo, 'webgen/sourcehandler/metainfo'
16
+ autoload :Template, 'webgen/sourcehandler/template'
17
+ autoload :Page, 'webgen/sourcehandler/page'
18
+ autoload :Fragment, 'webgen/sourcehandler/fragment'
19
+ autoload :Virtual, 'webgen/sourcehandler/virtual'
20
+ autoload :Feed, 'webgen/sourcehandler/feed'
21
+ autoload :Sitemap, 'webgen/sourcehandler/sitemap'
22
+
23
+ # This class is used by Website to do the actual rendering of the website. It
24
+ #
25
+ # * collects all source paths using the source classes
26
+ # * creates nodes using the source handler classes
27
+ # * writes changed nodes out using an output class
28
+ class Main
29
+
30
+ include WebsiteAccess
31
+ include Loggable
32
+
33
+ def initialize #:nodoc:
34
+ website.blackboard.add_service(:create_nodes, method(:create_nodes))
35
+ website.blackboard.add_service(:source_paths, method(:find_all_source_paths))
36
+ website.blackboard.add_listener(:node_meta_info_changed?, method(:meta_info_changed?))
37
+ end
38
+
39
+ # Render the nodes provided in the +tree+. Before the actual rendering is done, the sources
40
+ # are checked (nodes for deleted sources are deleted, nodes for new and changed sources).
41
+ def render(tree)
42
+ # Add new and changed nodes, remove nodes of deleted paths
43
+ puts "Generating tree..."
44
+ time = Benchmark.measure do
45
+ used_paths = Set.new
46
+ paths = Set.new([nil])
47
+ while paths.length > 0
48
+ used_paths += (paths = Set.new(find_all_source_paths.keys) - used_paths - clean(tree))
49
+ create_nodes_from_paths(tree, paths)
50
+ website.cache.reset_volatile_cache
51
+ end
52
+ end
53
+ puts "...done in " + ('%2.4f' % time.real) + ' seconds'
54
+
55
+ output = website.blackboard.invoke(:output_instance)
56
+
57
+ puts "Writing changed nodes..."
58
+ time = Benchmark.measure do
59
+ tree.node_access[:alcn].sort.each do |name, node|
60
+ node.dirty_meta_info = node.created = false
61
+ next if node == tree.dummy_root || !node.dirty
62
+ node.dirty = false
63
+
64
+ begin
65
+ if !node['no_output'] && (content = node.content)
66
+ puts " "*4 + name, :verbose
67
+ type = if node.is_directory?
68
+ :directory
69
+ elsif node.is_fragment?
70
+ :fragment
71
+ else
72
+ :file
73
+ end
74
+ output.write(node.path, content, type)
75
+ end
76
+ rescue
77
+ raise RuntimeError, "Error while processing <#{node.absolute_lcn}>: #{$!.message}", $!.backtrace
78
+ end
79
+ end
80
+ end
81
+ puts "...done in " + ('%2.4f' % time.real) + ' seconds'
82
+ end
83
+
84
+ #######
85
+ private
86
+ #######
87
+
88
+ # Return a hash with all source paths.
89
+ def find_all_source_paths
90
+ if !defined?(@paths)
91
+ source = Webgen::Source::Stacked.new(website.config['sources'].collect do |mp, name, *args|
92
+ [mp, constant(name).new(*args)]
93
+ end)
94
+ @paths = {}
95
+ source.paths.each do |path|
96
+ if !(website.config['sourcehandler.ignore'].any? {|pat| File.fnmatch(pat, path, File::FNM_CASEFOLD|File::FNM_DOTMATCH)})
97
+ @paths[path.path] = path
98
+ end
99
+ end
100
+ end
101
+ @paths
102
+ end
103
+
104
+ # Return only the subset of +paths+ which are handled by the source handler +name+.
105
+ def paths_for_handler(name, paths)
106
+ patterns = website.config['sourcehandler.patterns'][name]
107
+ return [] if patterns.nil?
108
+
109
+ options = (website.config['sourcehandler.casefold'] ? File::FNM_CASEFOLD : 0) |
110
+ (website.config['sourcehandler.use_hidden_files'] ? File::FNM_DOTMATCH : 0)
111
+ find_all_source_paths.values_at(*paths).select do |path|
112
+ patterns.any? {|pat| File.fnmatch(pat, path, options)}
113
+ end
114
+ end
115
+
116
+ # Use the source handlers to create nodes for the +paths+ in the +tree+.
117
+ def create_nodes_from_paths(tree, paths)
118
+ website.config['sourcehandler.invoke'].sort.each do |priority, shns|
119
+ shns.each do |shn|
120
+ sh = website.cache.instance(shn)
121
+ paths_for_handler(shn, paths).sort.each do |path|
122
+ parent_dir = path.directory.split('/').collect {|p| Path.new(p).cn}.join('/')
123
+ parent_dir += '/' if path != '/' && parent_dir == ''
124
+ create_nodes(tree, parent_dir, path, sh)
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ # Prepare everything to create nodes under the absolute lcn path +parent_path_name+ in the
131
+ # +tree from the +path+ using the +source_handler+. If a block is given, the actual creation
132
+ # of the nodes is deferred to it. After the nodes are created, it is also checked if they have
133
+ # all needed properties.
134
+ def create_nodes(tree, parent_path_name, path, source_handler) #:yields: parent, path
135
+ if !(parent = tree[parent_path_name])
136
+ raise "The specified parent path <#{parent_path_name}> does not exist"
137
+ end
138
+ path = path.dup
139
+ path.meta_info = default_meta_info(path, source_handler.class.name)
140
+ (website.cache[:sourcehandler_path_mi] ||= {})[[path.path, source_handler.class.name]] = path.meta_info.dup
141
+ website.blackboard.dispatch_msg(:before_node_created, parent, path)
142
+ *nodes = if block_given?
143
+ yield(parent, path)
144
+ else
145
+ source_handler.create_node(parent, path.dup)
146
+ end
147
+ nodes.flatten.compact.each do |node|
148
+ website.blackboard.dispatch_msg(:after_node_created, node)
149
+ end
150
+ nodes
151
+ end
152
+
153
+ # Return the default meta info for the pair of +path+ and +sh_name+.
154
+ def default_meta_info(path, sh_name)
155
+ path.meta_info.merge(website.config['sourcehandler.default_meta_info'][:all]).
156
+ merge(website.config['sourcehandler.default_meta_info'][sh_name] || {})
157
+ end
158
+
159
+ # Check if the default meta information for +node+ has changed since the last run. But don't
160
+ # take the node's path's +modified_at+ meta information into account since that changes on
161
+ # every path change.
162
+ def meta_info_changed?(node)
163
+ path = node.node_info[:src]
164
+ old_mi = website.cache[:sourcehandler_path_mi][[path, node.node_info[:processor]]]
165
+ old_mi.delete('modified_at')
166
+ new_mi = default_meta_info(@paths[path], node.node_info[:processor])
167
+ new_mi.delete('modified_at')
168
+ node.dirty_meta_info = true if !old_mi || old_mi != new_mi
169
+ end
170
+
171
+ # Clean the +tree+ by deleting nodes which have changed or which don't have an associated
172
+ # source anymore. Return all paths for which nodes need to be created.
173
+ def clean(tree)
174
+ paths_to_delete = Set.new
175
+ paths_not_to_delete = Set.new
176
+ nodes_to_be_deleted = Set.new
177
+ tree.node_access[:alcn].each do |alcn, node|
178
+ next if node == tree.dummy_root || tree[alcn].nil?
179
+
180
+ deleted = !find_all_source_paths.include?(node.node_info[:src])
181
+ if !node.created && (deleted ||
182
+ find_all_source_paths[node.node_info[:src]].changed? ||
183
+ node.changed?)
184
+ paths_not_to_delete << node.node_info[:src]
185
+ nodes_to_be_deleted << [node, deleted]
186
+ else
187
+ paths_to_delete << node.node_info[:src]
188
+ end
189
+ end
190
+
191
+ nodes_to_be_deleted.each {|node, deleted| tree.delete_node(node, deleted)}
192
+ #TODO: delete output path
193
+
194
+ # source paths that should be used
195
+ paths_to_delete - paths_not_to_delete
196
+ end
197
+
198
+ end
199
+
200
+ end
201
+
202
+ end
@@ -0,0 +1,211 @@
1
+ require 'webgen/websiteaccess'
2
+ require 'webgen/loggable'
3
+ require 'webgen/page'
4
+
5
+ module Webgen::SourceHandler
6
+
7
+ # This module should be included in every source handler as it provides the default methods for
8
+ # creating nodes.
9
+ #
10
+ # = Implementing Source Handlers
11
+ #
12
+ # A source handler is a webgen extension that processes source paths to create nodes and that
13
+ # provides the rendered content of these nodes. The nodes are later written to the output
14
+ # location. This can range from simply copying a path from the source to the output location to
15
+ # generating a whole set of nodes from one input path!
16
+ #
17
+ # The paths that are handled by a source handler are specified via path patterns (see
18
+ # below). During a webgen run the #create_node method for each source paths that matches a
19
+ # specified path pattern is called. And when it is time to write out the node, the the #content
20
+ # method is called to retrieve the rendered content.
21
+ #
22
+ # A source handler must not take any parameters on initialization and when this module is not
23
+ # mixed in, the methods #create_node and #content need to be defined. Also, a source handler does
24
+ # not need to reside under the Webgen::SourceHandler namespace but all shipped ones do.
25
+ #
26
+ # This base class provides useful default implementations of methods that are used by nearly all
27
+ # source handler class:
28
+ # * #create_node
29
+ # * #node_exists?
30
+ #
31
+ # It also provides other utility methods:
32
+ # * #page_from_path
33
+ # * #content
34
+ #
35
+ # = Nodes Created for Paths
36
+ #
37
+ # The main functions of a source handler class are to create one or more nodes for a source path
38
+ # and to provide the content of these nodes. To achieve this, certain information needs to be set
39
+ # on a node. If you use the methods provided by this base class, you don't need to set them
40
+ # explicitly because this is done by the provided methods.
41
+ #
42
+ # <tt>node_info[:processor]</tt>:: Has to be set to the class name of the source handler. This is
43
+ # used by the Node class: all unknown method calls are forwarded
44
+ # to the node processor.
45
+ # <tt>node_info[:src]</tt>:: Has to be set to the string version of the source path.
46
+ # <tt>meta_info['no_output']</tt>:: Has to be set to +true+ on nodes that are used during a
47
+ # webgen run but do not produce an output file.
48
+ #
49
+ # Additional information that is used only for processing purposes should be stored in the
50
+ # #node_info hash of a node as the #meta_info hash is reserved for real node meta information and
51
+ # should not be changed once the node is created.
52
+ #
53
+ # = Path Patterns and Invocation order
54
+ #
55
+ # Path patterns define which paths are handled by a specific source handler. These patterns are
56
+ # specified in the <tt>sourcehandler.patterns</tt> configuration hash as a mapping from the source
57
+ # handler class name to an array of path patterns. The patterns need to have a format that
58
+ # <tt>Dir.glob</tt> can handle.
59
+ #
60
+ # Specifying a path pattern does not mean that webgen uses the source handler. One also needs to
61
+ # provide an entry in the configuration value <tt>sourcehandler.invoke</tt>. This is a hash that
62
+ # maps the invocation rank (a number) to an array of source handler class names. The lower the
63
+ # invocation rank the earlier the specified source handlers are used.
64
+ #
65
+ # The default invocation ranks are:
66
+ # 1:: Early. Normally there is no need to use this rank.
67
+ # 5:: Standard. This is the rank the normal source handler should use.
68
+ # 9:: Late. This rank should be used by source handlers that operate on/use already created nodes
69
+ # and need to ensure that these nodes are available.
70
+ #
71
+ # = Default Meta Information
72
+ #
73
+ # Each source handler can define default meta information that gets automatically set on the
74
+ # source paths that are passed to the #create_node method.
75
+ #
76
+ # The default meta information is specified in the <tt>sourcehandler.default_meta_info</tt>
77
+ # configuration hash as a mapping from the source handler class name to the meta information
78
+ # hash.
79
+ #
80
+ # = Sample Source Handler Class
81
+ #
82
+ # Following is a simple source handler class example which copies paths from the source to
83
+ # the output location modifying the extension:
84
+ #
85
+ # class SimpleCopy
86
+ #
87
+ # include Webgen::SourceHandler::Base
88
+ #
89
+ # def create_node(parent, path)
90
+ # path.ext += '.copied'
91
+ # super(parent, path)
92
+ # end
93
+ #
94
+ # def content(node)
95
+ # website.blackboard.invoke(:source_paths)[node.node_info[:src]].io
96
+ # end
97
+ #
98
+ # end
99
+ #
100
+ # WebsiteAccess.website.config.sourcehandler.patterns['SimpleCopy'] = ['**/*.jpg', '**/*.png']
101
+ # WebsiteAccess.website.config.sourcehandler.invoke[5] << 'SimpleCopy'
102
+ #
103
+ module Base
104
+
105
+ # This module is used for defining all methods that can be used for creating output paths.
106
+ #
107
+ # All public methods of this module are considered to be output path creation methods and must
108
+ # have the following parameters:
109
+ # +parent+:: the parent node
110
+ # +path+:: the path for which the output name should be created
111
+ # +use_lang_part+:: controls whether the output path name has to include the language part
112
+ module OutputPathHelpers
113
+
114
+ # Default method for creating an output path for +parent+ and source +path+.
115
+ #
116
+ # The automatically set parameter +style+ (which uses the meta information +output_path_style+
117
+ # from the path's meta information hash) defines how the output name should be built (more
118
+ # information about this in the user documentation).
119
+ def standard_output_path(parent, path, use_lang_part, style = path.meta_info['output_path_style'])
120
+ result = style.collect do |part|
121
+ case part
122
+ when String then part
123
+ when :lang then use_lang_part ? path.meta_info['lang'] : ''
124
+ when :ext then path.ext.empty? ? '' : '.' + path.ext
125
+ when :parent then temp = parent; temp = temp.parent while temp.is_fragment?; temp.path
126
+ when :year, :month, :day
127
+ ctime = path.meta_info['created_at']
128
+ if !ctime.kind_of?(Time)
129
+ raise "Invalid meta info 'created_at' for #{path}, needed because of used output path style"
130
+ end
131
+ ctime.send(part).to_s.rjust(2, '0')
132
+ when Symbol then path.send(part)
133
+ when Array then part.include?(:lang) && !use_lang_part ? '' : standard_output_path(parent, path, use_lang_part, part)
134
+ else ''
135
+ end
136
+ end
137
+ result.join('')
138
+ end
139
+
140
+ end
141
+
142
+ include Webgen::Loggable
143
+ include OutputPathHelpers
144
+
145
+ # Construct the output name for the given +path+ and +parent+. First it is checked if a node
146
+ # with the constructed output name already exists. If it exists, the language part is forced to
147
+ # be in the output name and the resulting output name is returned.
148
+ def output_path(parent, path)
149
+ method = path.meta_info['output_path'] + '_output_path'
150
+ use_lang_part = if path.meta_info['lang'].nil? # unlocalized files never get a lang in the filename!
151
+ false
152
+ else
153
+ Webgen::WebsiteAccess.website.config['sourcehandler.default_lang_in_output_path'] ||
154
+ Webgen::WebsiteAccess.website.config['website.lang'] != path.meta_info['lang']
155
+ end
156
+ if OutputPathHelpers.public_instance_methods(false).include?(method)
157
+ name = send(method, parent, path, use_lang_part)
158
+ name += '/' if path.path =~ /\/$/ && name !~ /\/$/
159
+ if node_exists?(parent, path, name)
160
+ name = send(method, parent, path, (path.meta_info['lang'].nil? ? false : true))
161
+ name += '/' if path.path =~ /\/$/ && name !~ /\/$/
162
+ end
163
+ name
164
+ else
165
+ raise "Unknown method for creating output path: #{method}"
166
+ end
167
+ end
168
+
169
+ # Check if the node alcn and output path which would be created by #create_node exists. The
170
+ # +output_path+ to check for can individually be set.
171
+ def node_exists?(parent, path, output_path = self.output_path(parent, path))
172
+ parent.tree[Webgen::Node.absolute_name(parent, path.lcn, :alcn)] || (!path.meta_info['no_output'] && parent.tree[output_path, :path])
173
+ end
174
+
175
+ # Create and return a node under +parent+ from +path+ if it does not already exists. Some
176
+ # additional node information like <tt>:src</tt> and <tt>:processor</tt> is set and the meta
177
+ # information is checked for validness. The created node is yielded if a block is given.
178
+ def create_node(parent, path, output_path = self.output_path(parent, path))
179
+ return if path.meta_info['draft']
180
+ if !node_exists?(parent, path, output_path)
181
+ node = Webgen::Node.new(parent, output_path, path.cn, path.meta_info)
182
+ node['modified_at'] = Time.now unless node['modified_at'].kind_of?(Time)
183
+ node.node_info[:src] = path.path
184
+ node.node_info[:processor] = self.class.name
185
+ yield(node) if block_given?
186
+ node
187
+ else
188
+ log(:warn) { "Node already exists: output path = #{output_path} | alcn = #{Webgen::Node.absolute_name(parent, path.lcn, :alcn)}"}
189
+ end
190
+ end
191
+
192
+ # Return the content of the given +node+. This default +content+ method just returns +nil+.
193
+ def content(node)
194
+ nil
195
+ end
196
+
197
+ # Utility method for creating a Webgen::Page object from the +path+. Also updates
198
+ # <tt>path.meta_info</tt> with the meta info from the page.
199
+ def page_from_path(path)
200
+ begin
201
+ page = Webgen::Page.from_data(path.io.data, path.meta_info)
202
+ rescue Webgen::WebgenPageFormatError => e
203
+ raise "Error reading source path <#{path}>: #{e.message}"
204
+ end
205
+ path.meta_info = page.meta_info
206
+ page
207
+ end
208
+
209
+ end
210
+
211
+ end