webgen 0.3.0

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 (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