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