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,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'webgen/websiteaccess'
4
+
5
+ module Webgen
6
+
7
+ # This module should be included in all classes that need a logging facility.
8
+ module Loggable
9
+
10
+ # Log the result of the +block+ using the log level +log_level+.
11
+ def log(sev_level, &block)
12
+ source = (self.kind_of?(Class) ? self.name : self.class.name) + '#' + caller[0][%r"`.*"][1..-2]
13
+ if WebsiteAccess.website && WebsiteAccess.website.logger && (!WebsiteAccess.website.config['logger.mask'] || source =~ WebsiteAccess.website.config['logger.mask'])
14
+ WebsiteAccess.website.logger.send(sev_level, source, &block)
15
+ end
16
+ end
17
+
18
+ # Shortcut for writing a line to the normal log output.
19
+ def puts(*args)
20
+ (args.last == :verbose ? log(:verbose) { args[0..-2].join } : log(:stdout) { args.join })
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,97 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'stringio'
4
+ require 'logger'
5
+
6
+ module Webgen
7
+
8
+ # The class used by a Website to do the logging and the normal output.
9
+ class Logger
10
+
11
+ # Specifies whether log output should be synchronous with normal output.
12
+ attr_reader :sync
13
+
14
+ # Normal output verbosity (:normal, :verbose, :quiet).
15
+ attr_accessor :verbosity
16
+
17
+ # Create a new Logger object which uses +outdev+ as output device. If +sync+ is set to +true+,
18
+ # log messages are interspersed with normal output.
19
+ def initialize(outdev=$stdout, sync=false)
20
+ @sync = sync
21
+ @outdev = outdev
22
+ @logger = (@sync ? ::Logger.new(@outdev) : ::Logger.new(@logio = StringIO.new))
23
+ @logger.formatter = Proc.new do |severity, timestamp, progname, msg|
24
+ if self.level == ::Logger::DEBUG
25
+ "%5s -- %s: %s\n" % [severity, progname, msg ]
26
+ else
27
+ "%5s -- %s\n" % [severity, msg]
28
+ end
29
+ end
30
+ self.level = ::Logger::WARN
31
+ self.verbosity = :normal
32
+ @marks = []
33
+ end
34
+
35
+ # Returns the output of the logger when #sync is +false+. Otherwise an empty string is returned.
36
+ def log_output
37
+ if @sync
38
+ ''
39
+ else
40
+ out = @logio.string.dup
41
+ @marks.reverse.each_with_index do |mark, index|
42
+ out.insert(mark, " INFO -- Log messages for run #{@marks.length - index} are following\n")
43
+ end if out.length > 0
44
+ out
45
+ end
46
+ end
47
+
48
+ # Only used when #sync is +false: Mark the location in the log stream where a new update/write
49
+ # run begins.
50
+ def mark_new_cycle
51
+ if !@sync
52
+ @marks << @logio.string.length
53
+ end
54
+ end
55
+
56
+ # The severity threshold level.
57
+ def level
58
+ @logger.level
59
+ end
60
+
61
+ # Set the severity threshold to +value+ which can be one of the stdlib Logger severity levels.
62
+ def level=(value)
63
+ @logger.level = value
64
+ end
65
+
66
+ # Log a message of +sev_level+ from +source+. The mandatory block has to return the message.
67
+ def log(sev_level, source='', &block)
68
+ if sev_level == :stdout
69
+ @outdev.write(block.call + "\n") if @verbosity == :normal || @verbosity == :verbose
70
+ elsif sev_level == :verbose
71
+ @outdev.write(block.call + "\n") if @verbosity == :verbose
72
+ else
73
+ @logger.send(sev_level, source, &block)
74
+ end
75
+ end
76
+
77
+ # Utiltity method for logging an error message.
78
+ def error(source='', &block); log(:error, source, &block); end
79
+
80
+ # Utiltity method for logging a warning message.
81
+ def warn(source='', &block); log(:warn, source, &block); end
82
+
83
+ # Utiltity method for logging an informational message.
84
+ def info(source='', &block); log(:info, source, &block); end
85
+
86
+ # Utiltity method for logging a debug message.
87
+ def debug(source='', &block); log(:debug, source, &block); end
88
+
89
+ # Utiltity method for writing a normal output message.
90
+ def stdout(source='', &block); log(:stdout, source, &block); end
91
+
92
+ # Utiltity method for writing a verbose output message.
93
+ def verbose(source='', &block); log(:verbose, source, &block); end
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,391 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'webgen/websiteaccess'
4
+ require 'webgen/loggable'
5
+ require 'webgen/path'
6
+ require 'uri'
7
+ require 'set'
8
+ require 'pathname'
9
+
10
+ module Webgen
11
+
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!
20
+ class Node
21
+
22
+ include WebsiteAccess
23
+ include Loggable
24
+
25
+ # The parent node.
26
+ attr_reader :parent
27
+
28
+ # The children of this node.
29
+ attr_reader :children
30
+
31
+ # The full output path of this node.
32
+ attr_reader :path
33
+
34
+ # The tree to which this node belongs.
35
+ attr_reader :tree
36
+
37
+ # The canonical name of this node.
38
+ attr_reader :cn
39
+
40
+ # The absolute canonical name of this node.
41
+ attr_reader :absolute_cn
42
+
43
+ # The localized canonical name of this node.
44
+ attr_reader :lcn
45
+
46
+ # The absolute localized canonical name of this node.
47
+ attr_reader :absolute_lcn
48
+
49
+ # The level of the node. The level specifies how deep the node is in the hierarchy.
50
+ attr_reader :level
51
+
52
+ # The language of this node.
53
+ attr_reader :lang
54
+
55
+ # Meta information associated with the node.
56
+ attr_reader :meta_info
57
+
58
+ # Create a new Node instance.
59
+ #
60
+ # [+parent+ (immutable)]
61
+ # The parent node under which this nodes should be created.
62
+ # [+path+ (immutable)]
63
+ # The full output path for this node. If this node is a directory, the path must have a
64
+ # trailing slash (<tt>dir/</tt>). If it is a fragment, the hash sign must be the first
65
+ # character of the path (<tt>#fragment</tt>). This can also be an absolute path like
66
+ # <tt>http://myhost.com/</tt>.
67
+ # [+cn+ (immutable)]
68
+ # The canonical name for this node. Needs to be of the form <tt>basename.ext</tt> or
69
+ # <tt>basename</tt> where +basename+ does not contain any dots. Also, the +basename+ must not
70
+ # include a language part!
71
+ # [+meta_info+]
72
+ # A hash with meta information for the new node.
73
+ #
74
+ # The language of a node is taken from the meta information +lang+ and the entry is deleted from
75
+ # the meta information hash. The language cannot be changed afterwards! If no +lang+ key is
76
+ # found, the node is language neutral.
77
+ def initialize(parent, path, cn, meta_info = {})
78
+ @parent = parent
79
+ @cn = cn.chomp('/').freeze
80
+ @children = []
81
+ reinit(path, meta_info)
82
+ init_rest
83
+ end
84
+
85
+ # Re-initializes an already initialized node and resets it to its pristine state.
86
+ def reinit(path, meta_info = {})
87
+ old_path = @path if defined?(@path)
88
+ @path = path.freeze
89
+ @lang = Webgen::LanguageManager.language_for_code(meta_info.delete('lang'))
90
+ @lang = nil unless is_file?
91
+ @meta_info = meta_info
92
+ @flags = Set.new([:dirty, :created])
93
+ if defined?(@tree)
94
+ @tree.node_access[:path].delete(old_path) if old_path
95
+ @tree.register_path(self)
96
+ self.node_info.clear
97
+ self.node_info[:used_nodes] = Set.new
98
+ self.node_info[:used_meta_info_nodes] = Set.new
99
+ end
100
+ end
101
+
102
+ # Return the meta information item for +key+.
103
+ def [](key)
104
+ @meta_info[key]
105
+ end
106
+
107
+ # Assign +value+ to the meta information item for +key+.
108
+ def []=(key, value)
109
+ @meta_info[key] = value
110
+ end
111
+
112
+ # Return the node information hash which contains information for processing the node.
113
+ def node_info
114
+ tree.node_info[@absolute_lcn] ||= {}
115
+ end
116
+
117
+ # Check if the node is a directory.
118
+ def is_directory?; @path[-1] == ?/; end
119
+
120
+ # Check if the node is a file.
121
+ def is_file?; !is_directory? && !is_fragment?; end
122
+
123
+ # Check if the node is a fragment.
124
+ def is_fragment?; @cn[0] == ?# end
125
+
126
+ # Check if the node is the root node.
127
+ def is_root?; self == tree.root; end
128
+
129
+ # Check if the node is flagged with one of the following:
130
+ #
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
134
+ # run. Must not be set to +false+ once it is +true+!
135
+ # [:dirty_meta_info] Set by other objects to +true+ if the meta information of the node has
136
+ # changed since the last run. Must not be set to +false+ once it is +true+!
137
+ def flagged(key)
138
+ @flags.include?(key)
139
+ end
140
+
141
+ # Flag the node with the +keys+ and dispatch the message <tt>:node_flagged</tt> with +self+ and
142
+ # +keys+ as arguments. See #flagged for valid keys.
143
+ def flag(*keys)
144
+ @flags += keys
145
+ website.blackboard.dispatch_msg(:node_flagged, self, keys)
146
+ end
147
+
148
+ # Remove the flags +keys+ from the node and dispatch the message <tt>:node_unflagged</tt> with
149
+ # +self+ and +keys+ as arguments.
150
+ def unflag(*keys)
151
+ @flags.subtract(keys)
152
+ website.blackboard.dispatch_msg(:node_unflagged, self, keys)
153
+ end
154
+
155
+ # Return +true+ if the node has changed since the last webgen run. If it has changed, +dirty+ is
156
+ # set to +true+.
157
+ #
158
+ # Sends the message <tt>:node_changed?</tt> with +self+ as argument unless the node is already
159
+ # dirty. A listener to this message should set the flag <tt>:dirty</tt> on the passed node if he
160
+ # thinks it is dirty.
161
+ def changed?
162
+ if_not_checked(:node) do
163
+ flag(:dirty) if meta_info_changed? ||
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)
167
+ end
168
+ flagged(:dirty)
169
+ end
170
+
171
+ # Return +true+ if the meta information of the node has changed.
172
+ #
173
+ # Sends the message <tt>:node_meta_info_changed?</tt> with +self+ as argument unless the meta
174
+ # information of the node is already dirty. A listener to this message should set the flag
175
+ # <tt>:dirt_meta_info</tt> on the passed node if he thinks that the node's meta information is
176
+ # dirty.
177
+ def meta_info_changed?
178
+ if_not_checked(:meta_info) do
179
+ website.blackboard.dispatch_msg(:node_meta_info_changed?, self) unless flagged(:dirty_meta_info)
180
+ end
181
+ flagged(:dirty_meta_info)
182
+ end
183
+
184
+ # Return an informative representation of the node.
185
+ def inspect
186
+ "<##{self.class.name}: alcn=#{@absolute_lcn}>"
187
+ end
188
+
189
+ # Return +true+ if the alcn matches the pattern. See File.fnmatch for useable patterns.
190
+ def =~(pattern)
191
+ File.fnmatch(pattern, @absolute_lcn, File::FNM_DOTMATCH|File::FNM_CASEFOLD|File::FNM_PATHNAME)
192
+ end
193
+
194
+ # Sort nodes by using the meta info +sort_info+ (or +title+ if +sort_info+ is not set) of both
195
+ # involved nodes.
196
+ def <=>(other)
197
+ self_so = (@meta_info['sort_info'] && @meta_info['sort_info'].to_s) || @meta_info['title'] || ''
198
+ other_so = (other['sort_info'] && other['sort_info'].to_s) || other['title'] || ''
199
+ if self_so !~ /\D/ && other_so !~ /\D/
200
+ self_so = self_so.to_i
201
+ other_so = other_so.to_i
202
+ end
203
+ self_so <=> other_so
204
+ end
205
+
206
+ # Construct the absolute (localized) canonical name by using the +parent+ node and +name+ (which
207
+ # can be a cn or an lcn). The +type+ can be either <tt>:alcn</tt> or <tt>:acn</tt>.
208
+ def self.absolute_name(parent, name, type)
209
+ if parent.kind_of?(Tree)
210
+ ''
211
+ else
212
+ parent = parent.parent while parent.is_fragment? # Handle fragment nodes specially in case they are nested
213
+ parent_name = (type == :alcn ? parent.absolute_lcn : parent.absolute_cn)
214
+ parent_name + (parent_name !~ /\/$/ && (parent.is_directory? || parent == parent.tree.dummy_root) ? '/' : '') + name
215
+ end
216
+ end
217
+
218
+ # Construct an internal URL for the given +name+ which can be a acn/alcn/path.
219
+ def self.url(name)
220
+ url = URI::parse(name)
221
+ url = URI::parse('webgen://webgen.localhost/') + url unless url.absolute?
222
+ url
223
+ end
224
+
225
+
226
+ # Check if the this node is in the subtree which is spanned by +node+. The check is performed
227
+ # using only the +parent+ information of the involved nodes, NOT the actual path/alcn values!
228
+ def in_subtree_of?(node)
229
+ temp = self
230
+ temp = temp.parent while temp != tree.dummy_root && temp != node
231
+ temp != tree.dummy_root
232
+ end
233
+
234
+ # Return the node with the same canonical name but in language +lang+ or, if no such node
235
+ # exists, an unlocalized version of the node. If no such node is found either, +nil+ is
236
+ # returned.
237
+ def in_lang(lang)
238
+ avail = @tree.node_access[:acn][@absolute_cn]
239
+ avail.find do |n|
240
+ n = n.parent while n.is_fragment?
241
+ n.lang == lang
242
+ end || avail.find do |n|
243
+ n = n.parent while n.is_fragment?
244
+ n.lang.nil?
245
+ end
246
+ end
247
+
248
+ # Return the node representing the given +path+ which can be an acn/alcn. The path can be
249
+ # absolute (i.e. starting with a slash) or relative to the current node. If no node exists for
250
+ # the given path or if the path is invalid, +nil+ is returned.
251
+ #
252
+ # If the +path+ is an alcn and a node is found, it is returned. If the +path+ is an acn, the
253
+ # correct localized node according to +lang+ is returned or if no such node exists but an
254
+ # unlocalized version does, the unlocalized node is returned.
255
+ def resolve(path, lang = nil)
256
+ url = self.class.url(self.is_directory? ? File.join(@absolute_lcn, '/') : @absolute_lcn) + path
257
+
258
+ path = url.path + (url.fragment.nil? ? '' : '#' + url.fragment)
259
+ path.chomp!('/') unless path == '/'
260
+ return nil if path =~ /^\/\.\./
261
+
262
+ node = @tree[path, :alcn]
263
+ if node && node.absolute_cn != path
264
+ node
265
+ else
266
+ (node = @tree[path, :acn]) && node.in_lang(lang)
267
+ end
268
+ end
269
+
270
+ # Return the relative path to the given path +other+. The parameter +other+ can be a Node or a
271
+ # String.
272
+ def route_to(other)
273
+ my_url = self.class.url(@path)
274
+ other_url = if other.kind_of?(Node)
275
+ self.class.url(other.routing_node(@lang).path)
276
+ elsif other.kind_of?(String)
277
+ my_url + other
278
+ else
279
+ raise ArgumentError, "improper class for argument"
280
+ end
281
+
282
+ # resolve any '.' and '..' paths in the target url
283
+ if other_url.path =~ /\/\.\.?\// && other_url.scheme == 'webgen'
284
+ other_url.path = Pathname.new(other_url.path).cleanpath.to_s
285
+ end
286
+ route = my_url.route_to(other_url).to_s
287
+ (route == '' ? File.basename(self.path) : route)
288
+ end
289
+
290
+ # Return the routing node in language +lang+ which is the node that is used when routing to this
291
+ # node. The returned node can differ from the node itself in case of a directory where the
292
+ # routing node is the directory index node. If +show_warning+ is +true+ and this node is a
293
+ # directory node, then a warning is logged if no associated index file is found.
294
+ def routing_node(lang, log_warning = true)
295
+ if !is_directory?
296
+ self
297
+ else
298
+ key = [absolute_lcn, :index_node, lang]
299
+ vcache = website.cache.volatile
300
+ return vcache[key] if vcache.has_key?(key)
301
+
302
+ index_path = self.meta_info['index_path']
303
+ if index_path.nil?
304
+ vcache[key] = self
305
+ else
306
+ index_node = resolve(index_path, lang)
307
+ if index_node
308
+ vcache[key] = index_node
309
+ log(:info) { "Directory index path for <#{absolute_lcn}> => <#{index_node.absolute_lcn}>" }
310
+ elsif log_warning
311
+ vcache[key] = self
312
+ log(:warn) { "No directory index path found for directory <#{absolute_lcn}>" }
313
+ end
314
+ end
315
+ vcache[key] || self
316
+ end
317
+ end
318
+
319
+ # Return a HTML link from this node to the +node+ or, if this node and +node+ are the same and
320
+ # the parameter <tt>website.link_to_current_page</tt> is +false+, a +span+ element with the link
321
+ # text.
322
+ #
323
+ # You can optionally specify additional attributes for the HTML element in the +attr+ Hash.
324
+ # Also, the meta information +link_attrs+ of the given +node+ is used, if available, to set
325
+ # attributes. However, the +attr+ parameter takes precedence over the +link_attrs+ meta
326
+ # information. Be aware that all key-value pairs with Symbol keys are removed before the
327
+ # attributes are written. Therefore you always need to specify general attributes with Strings!
328
+ #
329
+ # If the special value <tt>:link_text</tt> is present in the attributes, it will be used as the
330
+ # link text; otherwise the title of the +node+ will be used.
331
+ #
332
+ # If the special value <tt>:lang</tt> is present in the attributes, it will be used as parameter
333
+ # to the <tt>node.routing_node</tt> call for getting the linked-to node instead of this node's
334
+ # +lang+ attribute. *Note*: this is only useful when linking to a directory.
335
+ def link_to(node, attr = {})
336
+ attr = node['link_attrs'].merge(attr) if node['link_attrs'].kind_of?(Hash)
337
+ rnode = node.routing_node(attr[:lang] || @lang)
338
+ link_text = attr[:link_text] || (rnode != node && rnode['routed_title']) || node['title']
339
+ attr.delete_if {|k,v| k.kind_of?(Symbol)}
340
+
341
+ use_link = (rnode != self || website.config['website.link_to_current_page'])
342
+ attr['href'] = self.route_to(rnode) if use_link
343
+ attrs = attr.collect {|name,value| "#{name.to_s}=\"#{value}\"" }.sort.unshift('').join(' ')
344
+ (use_link ? "<a#{attrs}>#{link_text}</a>" : "<span#{attrs}>#{link_text}</span>")
345
+ end
346
+
347
+ #######
348
+ private
349
+ #######
350
+
351
+ # Do the rest of the initialization.
352
+ def init_rest
353
+ @lcn = Path.lcn(@cn, @lang)
354
+ @absolute_cn = self.class.absolute_name(@parent, @cn, :acn)
355
+ @absolute_lcn = self.class.absolute_name(@parent, @lcn, :alcn)
356
+
357
+ @level = -1
358
+ @tree = @parent
359
+ (@level += 1; @tree = @tree.parent) while !@tree.kind_of?(Tree)
360
+
361
+ @tree.register_node(self)
362
+ @parent.children << self unless @parent == @tree
363
+
364
+ self.node_info[:used_nodes] = Set.new
365
+ self.node_info[:used_meta_info_nodes] = Set.new
366
+ end
367
+
368
+ # Only run the code in the block if this node has not already been checked. Different checks are
369
+ # supported by setting a different +type+ value.
370
+ def if_not_checked(type)
371
+ array = (website.cache.volatile[:node_change_checking] ||= {})[type] ||= []
372
+ if !array.include?(self)
373
+ array << self
374
+ yield
375
+ array.delete(self)
376
+ end
377
+ end
378
+
379
+ # Delegate missing methods to a processor. The current node is placed into the argument array as
380
+ # the first argument before the method +name+ is invoked on the processor.
381
+ def method_missing(name, *args, &block)
382
+ if node_info[:processor]
383
+ website.cache.instance(node_info[:processor]).send(name, *([self] + args), &block)
384
+ else
385
+ super
386
+ end
387
+ end
388
+
389
+ end
390
+
391
+ end