webgen 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/COPYING +340 -0
  2. data/ChangeLog +2172 -0
  3. data/README +16 -0
  4. data/Rakefile +283 -0
  5. data/TODO +133 -0
  6. data/VERSION +1 -0
  7. data/bin/webgen +5 -0
  8. data/doc/extension.config +55 -0
  9. data/doc/src/default.css +129 -0
  10. data/doc/src/default.template +45 -0
  11. data/doc/src/design.gallery +18 -0
  12. data/doc/src/designs/default.png +0 -0
  13. data/doc/src/designs/nostyle.png +0 -0
  14. data/doc/src/designs/old.png +0 -0
  15. data/doc/src/documentation/extloader.page +20 -0
  16. data/doc/src/documentation/filehandler/backing.page +16 -0
  17. data/doc/src/documentation/filehandler/copy.page +12 -0
  18. data/doc/src/documentation/filehandler/directory.page +15 -0
  19. data/doc/src/documentation/filehandler/index.page +13 -0
  20. data/doc/src/documentation/filehandler/page.page +122 -0
  21. data/doc/src/documentation/filehandler/picturegallery.page +25 -0
  22. data/doc/src/documentation/filehandler/template.page +21 -0
  23. data/doc/src/documentation/index.page +47 -0
  24. data/doc/src/documentation/tags/date.page +19 -0
  25. data/doc/src/documentation/tags/executecommand.page +19 -0
  26. data/doc/src/documentation/tags/includefile.page +15 -0
  27. data/doc/src/documentation/tags/index.page +39 -0
  28. data/doc/src/documentation/tags/lang.de.page +6 -0
  29. data/doc/src/documentation/tags/lang.page +27 -0
  30. data/doc/src/documentation/tags/menu.de.page +11 -0
  31. data/doc/src/documentation/tags/menu.page +30 -0
  32. data/doc/src/documentation/tags/meta.page +20 -0
  33. data/doc/src/documentation/tags/multilang.de.page +4 -0
  34. data/doc/src/documentation/tags/multilang.fr.page +4 -0
  35. data/doc/src/documentation/tags/multilang.page +4 -0
  36. data/doc/src/documentation/tags/navbar.page +19 -0
  37. data/doc/src/documentation/tags/relocatable.page +16 -0
  38. data/doc/src/documentation/tags/wikilink.page +18 -0
  39. data/doc/src/download.page +42 -0
  40. data/doc/src/features.page +14 -0
  41. data/doc/src/index.page +48 -0
  42. data/doc/src/logo.png +0 -0
  43. data/doc/src/meta.info +22 -0
  44. data/install.rb +19 -0
  45. data/lib/util/composite.rb +101 -0
  46. data/lib/util/listener.rb +105 -0
  47. data/lib/webgen/configuration.rb +216 -0
  48. data/lib/webgen/logging.rb +73 -0
  49. data/lib/webgen/node.rb +147 -0
  50. data/lib/webgen/plugins/extloader.rb +88 -0
  51. data/lib/webgen/plugins/filehandler/backing.rb +200 -0
  52. data/lib/webgen/plugins/filehandler/directory.rb +96 -0
  53. data/lib/webgen/plugins/filehandler/filecopy.rb +59 -0
  54. data/lib/webgen/plugins/filehandler/filehandler.rb +209 -0
  55. data/lib/webgen/plugins/filehandler/pagehandler/html.rb +43 -0
  56. data/lib/webgen/plugins/filehandler/pagehandler/markdown.rb +53 -0
  57. data/lib/webgen/plugins/filehandler/pagehandler/page.rb +205 -0
  58. data/lib/webgen/plugins/filehandler/pagehandler/rdoc.rb +50 -0
  59. data/lib/webgen/plugins/filehandler/pagehandler/textile.rb +52 -0
  60. data/lib/webgen/plugins/filehandler/picturegallery.rb +194 -0
  61. data/lib/webgen/plugins/filehandler/template.rb +98 -0
  62. data/lib/webgen/plugins/tags/date.rb +46 -0
  63. data/lib/webgen/plugins/tags/executecommand.rb +53 -0
  64. data/lib/webgen/plugins/tags/includefile.rb +60 -0
  65. data/lib/webgen/plugins/tags/lang.rb +50 -0
  66. data/lib/webgen/plugins/tags/menu.rb +198 -0
  67. data/lib/webgen/plugins/tags/meta.rb +54 -0
  68. data/lib/webgen/plugins/tags/navbar.rb +62 -0
  69. data/lib/webgen/plugins/tags/relocatable.rb +58 -0
  70. data/lib/webgen/plugins/tags/tags.rb +247 -0
  71. data/lib/webgen/plugins/tags/wikilink.rb +58 -0
  72. data/lib/webgen/plugins/treewalker.rb +81 -0
  73. data/lib/webgen/webgen.rb +155 -0
  74. data/setup.rb +1331 -0
  75. data/testsite/config.yaml +7 -0
  76. data/testsite/src/bluecloth.page +102 -0
  77. data/testsite/src/default.css +146 -0
  78. data/testsite/src/default.template +33 -0
  79. data/testsite/src/home.en.page +22 -0
  80. data/testsite/src/home.page +22 -0
  81. data/testsite/src/images/bghack.png +0 -0
  82. data/testsite/src/images/o.png +0 -0
  83. data/testsite/src/images/smagacor.png +0 -0
  84. data/testsite/src/images/tictactoe.png +0 -0
  85. data/testsite/src/images/x.png +0 -0
  86. data/testsite/src/index.page +21 -0
  87. data/testsite/src/meta.info +15 -0
  88. data/testsite/src/news.page +20 -0
  89. data/testsite/src/news_are_so-cool.de.page +19 -0
  90. data/testsite/src/noindex/noindex.page +20 -0
  91. data/testsite/src/pictures/index.page +20 -0
  92. data/testsite/src/projects.de.page +11 -0
  93. data/testsite/src/projects.es.page +11 -0
  94. data/testsite/src/projects.page +17 -0
  95. data/testsite/src/projects/00.index.de.page +10 -0
  96. data/testsite/src/projects/01.project2.page +20 -0
  97. data/testsite/src/projects/02.project1.page +20 -0
  98. data/testsite/src/projects/05.project3.page +22 -0
  99. data/testsite/src/projects/index.page +20 -0
  100. data/testsite/src/projects/subproj/index.page +22 -0
  101. data/testsite/src/projects/subproj/project3.page +21 -0
  102. data/testsite/src/rdoc.page +12 -0
  103. data/testsite/src/redcloth.page +106 -0
  104. data/testsite/src/test.gallery +5 -0
  105. metadata +155 -0
data/install.rb ADDED
@@ -0,0 +1,19 @@
1
+
2
+ require 'rpa/install'
3
+
4
+ class Install_webgen < RPA::Install::FullInstaller
5
+ name 'webgen'
6
+ version '0.3.0-1'
7
+ classification Application
8
+ build do
9
+ installdocs %w[COPYING ChangeLog TODO]
10
+ installdocs 'docs'
11
+ installrdoc %w[README] + Dir['lib/**/*.rb']
12
+ installdata
13
+ end
14
+ description <<-EOF
15
+ Webgen is a templated based static website generator.
16
+
17
+ Webgen is a web page generator implemented in Ruby. It is used to generate static web pages from templates and page description files.
18
+ EOF
19
+ end
@@ -0,0 +1,101 @@
1
+ #
2
+ #--
3
+ #
4
+ # $Id: composite.rb 203 2005-02-21 18:42:04Z thomas $
5
+ #
6
+ # webgen: template based static website generator
7
+ # Copyright (C) 2004 Thomas Leitner
8
+ #
9
+ # This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10
+ # General Public License as published by the Free Software Foundation; either version 2 of the
11
+ # License, or (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14
+ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License along with this program; if not,
18
+ # write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ #++
21
+ #
22
+
23
+
24
+ # Module Composite
25
+ #
26
+ # Implementation of the Composite pattern.
27
+ #
28
+ # Usage example:
29
+ #
30
+ # class Test
31
+ # include Composite
32
+ # end
33
+ #
34
+ # t = Test.new
35
+ # t.add_child("Hello")
36
+ # t.add_child("Lester")
37
+ # t.each do |child| print child end
38
+ #
39
+
40
+
41
+ module Composite
42
+
43
+ include Enumerable
44
+
45
+
46
+ # Returns the array of children
47
+ def children
48
+ @children = [] unless defined? @children
49
+ @children
50
+ end
51
+
52
+
53
+ # Adds all objects in the array
54
+ def add_children( array )
55
+ if array.kind_of? Array
56
+ @children = [] unless defined? @children
57
+ @children.concat array
58
+ else
59
+ raise ArgumentError, "Parameter must be array"
60
+ end
61
+ end
62
+
63
+
64
+ # Deletes all children
65
+ def del_children
66
+ @children = []
67
+ end
68
+
69
+
70
+ # Adds the child
71
+ def add_child( child )
72
+ @children = [] unless defined? @children
73
+ @children.push child unless @children.include? child
74
+ end
75
+
76
+
77
+ # Depending on the type of argument one of these actions is taken
78
+ #
79
+ # [+Numeric+] the child at the specified position is deleted
80
+ # [+else+] the specified child is deleted
81
+ def del_child( child )
82
+ if child.kind_of? Numeric
83
+ @children.delete_at child if defined? @children
84
+ else
85
+ @children.delete child if defined? @children
86
+ end
87
+ end
88
+
89
+
90
+ # Iterates over all childrenldren
91
+ def each # :yields: child
92
+ children.each do |child| yield child end if defined? @children
93
+ end
94
+
95
+
96
+ # Checks if there are any children
97
+ def has_children?
98
+ defined?( @children ) && children.length > 0
99
+ end
100
+
101
+ end
@@ -0,0 +1,105 @@
1
+ #
2
+ #--
3
+ #
4
+ # $Id: listener.rb 203 2005-02-21 18:42:04Z thomas $
5
+ #
6
+ # webgen: template based static website generator
7
+ # Copyright (C) 2004 Thomas Leitner
8
+ #
9
+ # This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10
+ # General Public License as published by the Free Software Foundation; either version 2 of the
11
+ # License, or (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14
+ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License along with this program; if not,
18
+ # write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ #++
21
+ #
22
+
23
+ # Module Listener
24
+ #
25
+ # Implementation of the listener pattern. The including class defines messages to which other
26
+ # classes can listen.
27
+ #
28
+ # Usage example:
29
+ #
30
+ # class Test
31
+ # include Listener
32
+ #
33
+ # def initialize
34
+ # add_msg_name :test
35
+ # end
36
+ #
37
+ # def invoke( *param )
38
+ # dispatch_msg( :test, *param )
39
+ # end
40
+ #
41
+ # end
42
+ #
43
+ # t = Test.new
44
+ # t.add_msg_listener( :test ) do |*param|
45
+ # print param.inspect
46
+ # end
47
+ # t.invoke 'hello'
48
+ # t.invoke 'lester', ['tsd', 4, 'test']
49
+ #
50
+ module Listener
51
+
52
+
53
+ # Adds a new message listener for the object. The message +msgName+
54
+ # will be dispatched to either the given +callableObject+ (has to respond
55
+ # to +call+) or the given block. If both are specified the +callableObject+
56
+ # is used.
57
+ def add_msg_listener( msgName, callableObject = nil, &block )
58
+ return unless defined?( @msgNames ) && @msgNames.has_key?( msgName )
59
+
60
+ if !callableObject.nil?
61
+ raise NoMethodError, "listener needs to respond to 'call'" unless callableObject.respond_to? :call
62
+ @msgNames[msgName].push callableObject
63
+ elsif !block.nil?
64
+ @msgNames[msgName].push block
65
+ else
66
+ raise "you have to provide a callback object or a block"
67
+ end
68
+ end
69
+
70
+
71
+ # Removes the given object from the dispatcher queue of the message +msgName+.
72
+ def del_msg_listener( msgName, object )
73
+ @msgNames[msgName].delete object if defined? @msgNames
74
+ end
75
+
76
+
77
+ #######
78
+ private
79
+ #######
80
+
81
+
82
+ # Adds a new message target called +msgName+
83
+ def add_msg_name( msgName )
84
+ @msgNames = {} unless defined? @msgNames
85
+ @msgNames[msgName] = [] unless @msgNames.has_key? msgName
86
+ end
87
+
88
+
89
+ # Deletes the message target +msgName+.
90
+ def del_msg_name( msgName )
91
+ @msgNames.delete msgName if defined? @msgNames
92
+ end
93
+
94
+
95
+ # Dispatches the message +msgName+ to all listeners for this message,
96
+ # providing the given arguments
97
+ def dispatch_msg( msgName, *args )
98
+ if defined? @msgNames and @msgNames.has_key? msgName
99
+ @msgNames[msgName].each do |obj|
100
+ obj.call( *args )
101
+ end
102
+ end
103
+ end
104
+
105
+ end
@@ -0,0 +1,216 @@
1
+ #
2
+ #--
3
+ #
4
+ # $Id: configuration.rb 203 2005-02-21 18:42:04Z thomas $
5
+ #
6
+ # webgen: template based static website generator
7
+ # Copyright (C) 2004 Thomas Leitner
8
+ #
9
+ # This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10
+ # General Public License as published by the Free Software Foundation; either version 2 of the
11
+ # License, or (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14
+ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License along with this program; if not,
18
+ # write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ #++
21
+ #
22
+
23
+ require 'yaml'
24
+ require 'ostruct'
25
+ require 'find'
26
+ require 'tsort'
27
+ require 'webgen/node'
28
+ require 'webgen/logging'
29
+
30
+ # Helper class for calculating plugin dependencies.
31
+ class Dependency < Hash
32
+ include TSort
33
+
34
+ alias tsort_each_node each_key
35
+ def tsort_each_child(node, &block)
36
+ fetch(node).each(&block)
37
+ end
38
+ end
39
+
40
+
41
+ module Webgen
42
+
43
+ VERSION = [0, 3, 0]
44
+ SUMMARY = "Webgen is a templated based static website generator."
45
+ DESCRIPTION = "Webgen is a web page generator implemented in Ruby. " \
46
+ "It is used to generate static web pages from templates and page " \
47
+ "description files."
48
+
49
+ # Base class for all plugins.
50
+ class Plugin
51
+
52
+ # Holds the plugin data from each and every plugin.
53
+ @@config = {}
54
+
55
+ def self.inherited( klass )
56
+ (@@config[klass.name] = OpenStruct.new).klass = klass
57
+ @@config[klass.name].plugin = klass.name.split( /::/ ).last
58
+ end
59
+
60
+ ['extension', 'summary', 'description'].each do |name|
61
+ self.module_eval "def self.#{name}( obj ); @@config[self.name].#{name} = obj; end"
62
+ end
63
+
64
+ # Return plugin data
65
+ def self.config
66
+ @@config
67
+ end
68
+
69
+ # Add a dependency to the plugin. Dependencies are instantiated before the plugin gets
70
+ # instantiated.
71
+ def self.depends_on( *dep )
72
+ dep.each {|d| (@@config[self.name].dependencies ||= []) << d}
73
+ end
74
+
75
+ # Shortcut for getting the plugin with the name +name+.
76
+ def self.[]( name )
77
+ pair = @@config.find {|k,v| v.plugin == name }
78
+ self.logger.warn { "Could not retrieve plugin '#{name}' as such a plugin does not exist!" } if pair.nil?
79
+ pair[1].obj unless pair.nil?
80
+ end
81
+
82
+ # Add a parameter for the current class. Has to be used by subclasses to define their parameters!
83
+ #
84
+ # Arguments:
85
+ # +name+:: the name of the parameter
86
+ # +default+:: the default value of the parameter
87
+ # +description+:: a small description of the parameter
88
+ def self.add_param( name, default, description )
89
+ self.logger.debug { "Adding parameter '#{name}' for plugin class '#{self.name}'" }
90
+ data = OpenStruct.new( :name => name, :value => default, :default => default, :description => description )
91
+ (@@config[self.name].params ||= {})[name] = data
92
+ end
93
+
94
+ # Set parameter +name+ for +plugin+ to +value+.
95
+ def self.set_param( plugin, name, value )
96
+ found = catch( :found ) do
97
+ item = @@config.find {|k,v| v.plugin == plugin }[1]
98
+ item.klass.ancestor_classes.each do |k|
99
+ item = @@config[k.name]
100
+ if !item.nil? && !item.params.nil? && item.params.has_key?( name )
101
+ item.params[name].value = value
102
+ logger.debug { "Setting parameter '#{name}' for plugin '#{plugin}' to #{value.inspect}" }
103
+ throw :found, true
104
+ end
105
+ end
106
+ end
107
+ logger.error { "Cannot set undefined parameter '#{name}' for plugin '#{plugin}'" } unless found
108
+ end
109
+
110
+ # Return parameter +name+.
111
+ def []( name )
112
+ self.class.ancestor_classes.each do |klass|
113
+ data = @@config[klass.name]
114
+ return data.params[name].value unless data.params.nil? || data.params[name].nil?
115
+ end
116
+ logger.error { "Referencing invalid configuration value '#{name}' in class #{self.class.name}" }
117
+ return nil
118
+ end
119
+
120
+ # Set parameter +name+.
121
+ def []=( name, value )
122
+ self.class.set_param( @@config[self.class.name].plugin, name, value )
123
+ end
124
+ alias get_param []
125
+
126
+ # Checks if the plugin has a parameter +name+.
127
+ def has_param?( name )
128
+ self.class.ancestor_classes.any? do |klass|
129
+ !@@config[klass.name].params.nil? && @@config[klass.name].params.has_key?( name )
130
+ end
131
+ end
132
+
133
+ #######
134
+ private
135
+ #######
136
+
137
+ # Return the ancestor classes for the object's class which are sub classes from Plugin.
138
+ def self.ancestor_classes
139
+ self.ancestors.delete_if {|c| c.instance_of?( Module ) }[0..-3]
140
+ end
141
+
142
+ end
143
+
144
+
145
+ # Responsible for loading the other plugin files and holds the basic configuration options.
146
+ class Configuration < Plugin
147
+
148
+ summary "Responsible for loading the configuration data"
149
+
150
+ add_param 'srcDirectory', 'src', 'The directory from which the source files are read.'
151
+ add_param 'outDirectory', 'output', 'The directory to which the output files are written.'
152
+ add_param 'verbosityLevel', 2, 'The level of verbosity for the output of messages on the standard output.'
153
+ add_param 'lang', 'en', 'The default language.'
154
+ add_param 'configfile', 'config.yaml', 'The file from which extra configuration data is taken.'
155
+ add_param 'logfile', 'webgen.log', 'The name of the log file if the log should be written to a file.'
156
+
157
+ # Does all the initialisation stuff
158
+ def init_all( data )
159
+ data.each {|k,v| Plugin['Configuration'][k] = v}
160
+ logger.level = get_param( 'verbosityLevel' )
161
+
162
+ load_plugins( File.dirname( __FILE__) + '/plugins', File.dirname( __FILE__).sub(/webgen$/, '') )
163
+ parse_config_file
164
+
165
+ data.each {|k,v| Plugin['Configuration'][k] = v}
166
+ logger.level = get_param( 'verbosityLevel' )
167
+ init_plugins
168
+ Plugin['ExtensionLoader'].parse_config_file
169
+ end
170
+
171
+ # Parse config file and load the configuration values.
172
+ def parse_config_file
173
+ if File.exists?( get_param( 'configfile' ) )
174
+ @pluginData = YAML::load( File.new( get_param( 'configfile' ) ) )
175
+ @pluginData.each {|plugin, params| params.each {|name,value| Plugin.set_param( plugin, name, value ) } }
176
+ else
177
+ logger.info { "Config file <#{get_param( 'configfile' )}> does not exist, not extra configuration data read." }
178
+ end
179
+ end
180
+
181
+ # Load all plugins in the given +path+. Before +require+ is actually called the path is
182
+ # trimmed: if +trimpath+ matches the beginning of the string, +trimpath+ is deleted from it.
183
+ def load_plugins( path, trimpath )
184
+ Find.find( path ) do |file|
185
+ Find.prune unless File.directory?( file ) || (/.rb$/ =~ file)
186
+ self.logger.debug { "Loading plugin file <#{file}>..." }
187
+ require file.gsub(/^#{trimpath}/, '') if File.file?( file )
188
+ end
189
+ end
190
+
191
+ # Instantiate the plugins in the correct order, except the classes which have a constant
192
+ # +VIRTUAL+.
193
+ def init_plugins
194
+ dep = Dependency.new
195
+ Plugin.config.each {|k,data| dep[data.plugin] = data.dependencies || []}
196
+ self.logger.debug { "Dependencies: #{dep.inspect}" }
197
+ dep.tsort.each do |plugin|
198
+ data = Plugin.config.find {|k,v| v.plugin == plugin }[1]
199
+ self.logger.debug { "Creating plugin of class #{data.klass.name}" }
200
+ data.obj ||= data.klass.new unless data.klass.const_defined?( 'VIRTUAL' )
201
+ end
202
+ end
203
+
204
+ # Set the log device to the logfile.
205
+ def set_log_dev_to_logfile
206
+ logger.set_log_dev( File.open( get_param( 'logfile' ), 'a' ) )
207
+ end
208
+
209
+ end
210
+
211
+ # Initialize single configuration instance
212
+ Plugin.config[Configuration.name].obj = Configuration.new
213
+
214
+ end
215
+
216
+
@@ -0,0 +1,73 @@
1
+ #
2
+ #--
3
+ #
4
+ # $Id: logging.rb 203 2005-02-21 18:42:04Z thomas $
5
+ #
6
+ # webgen: template based static website generator
7
+ # Copyright (C) 2004 Thomas Leitner
8
+ #
9
+ # This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10
+ # General Public License as published by the Free Software Foundation; either version 2 of the
11
+ # License, or (at your option) any later version.
12
+ #
13
+ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
14
+ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU General Public License along with this program; if not,
18
+ # write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
+ #
20
+ #++
21
+ #
22
+
23
+ require 'logger'
24
+
25
+ module Webgen
26
+
27
+ class Logger < ::Logger
28
+
29
+ def initialize( dev )
30
+ super( dev )
31
+ self.datetime_format = "%Y-%m-%d %H:%M:%S"
32
+ self.level = Logger::ERROR
33
+ end
34
+
35
+ def set_log_dev( dev )
36
+ @logdev = LogDevice.new( dev )
37
+ end
38
+
39
+ def format_message( severity, timestamp, msg, progname )
40
+ "%s %5s -- %s: %s\n" % [timestamp, severity, progname, msg ]
41
+ end
42
+
43
+ def warn( progname = nil, &block )
44
+ super
45
+ self.debug { "Call stack for last warning: #{caller[3..-1].join("\n")}" }
46
+ end
47
+
48
+ def error( progname = nil, &block )
49
+ super
50
+ self.debug { "Call stack for last error: #{caller[3..-1].join("\n")}" }
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ class Object
58
+
59
+ LOGGER = Webgen::Logger.new( STDERR )
60
+
61
+ def logger
62
+ LOGGER
63
+ end
64
+
65
+ end
66
+
67
+ class Module
68
+
69
+ def self.logger
70
+ Object::LOGGER
71
+ end
72
+
73
+ end