webby 0.9.3-x86-mswin32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (229) hide show
  1. data/History.txt +206 -0
  2. data/Manifest.txt +228 -0
  3. data/README.txt +92 -0
  4. data/Rakefile +49 -0
  5. data/bin/webby +41 -0
  6. data/bin/webby-gen +41 -0
  7. data/examples/blog/Sitefile +7 -0
  8. data/examples/blog/tasks/blog.rake +72 -0
  9. data/examples/blog/templates/atom_feed.erb +40 -0
  10. data/examples/blog/templates/blog/month.erb +22 -0
  11. data/examples/blog/templates/blog/post.erb +16 -0
  12. data/examples/blog/templates/blog/year.erb +22 -0
  13. data/examples/presentation/Sitefile +10 -0
  14. data/examples/presentation/content/css/uv/twilight.css +137 -0
  15. data/examples/presentation/content/presentation/_sample_code.txt +10 -0
  16. data/examples/presentation/content/presentation/index.txt +63 -0
  17. data/examples/presentation/content/presentation/s5/blank.gif +0 -0
  18. data/examples/presentation/content/presentation/s5/bodybg.gif +0 -0
  19. data/examples/presentation/content/presentation/s5/framing.css +23 -0
  20. data/examples/presentation/content/presentation/s5/iepngfix.htc +42 -0
  21. data/examples/presentation/content/presentation/s5/opera.css +7 -0
  22. data/examples/presentation/content/presentation/s5/outline.css +15 -0
  23. data/examples/presentation/content/presentation/s5/pretty.css +86 -0
  24. data/examples/presentation/content/presentation/s5/print.css +25 -0
  25. data/examples/presentation/content/presentation/s5/s5-core.css +9 -0
  26. data/examples/presentation/content/presentation/s5/slides.css +3 -0
  27. data/examples/presentation/content/presentation/s5/slides.js +553 -0
  28. data/examples/presentation/layouts/presentation.txt +43 -0
  29. data/examples/presentation/templates/_code_partial.erb +13 -0
  30. data/examples/presentation/templates/presentation.erb +40 -0
  31. data/examples/tumblog/Sitefile +9 -0
  32. data/examples/tumblog/content/css/tumblog.css +308 -0
  33. data/examples/tumblog/content/images/tumblog/permalink.gif +0 -0
  34. data/examples/tumblog/content/images/tumblog/rss.gif +0 -0
  35. data/examples/tumblog/content/tumblog/200806/the-noble-chicken/index.txt +12 -0
  36. data/examples/tumblog/content/tumblog/200807/historical-perspectives-on-the-classic-chicken-joke/index.txt +12 -0
  37. data/examples/tumblog/content/tumblog/200807/mad-city-chickens/index.txt +10 -0
  38. data/examples/tumblog/content/tumblog/200807/the-wisdom-of-the-dutch/index.txt +11 -0
  39. data/examples/tumblog/content/tumblog/200807/up-a-tree/index.txt +13 -0
  40. data/examples/tumblog/content/tumblog/index.txt +37 -0
  41. data/examples/tumblog/content/tumblog/rss.txt +37 -0
  42. data/examples/tumblog/layouts/tumblog/default.txt +44 -0
  43. data/examples/tumblog/layouts/tumblog/post.txt +15 -0
  44. data/examples/tumblog/lib/tumblog_helper.rb +32 -0
  45. data/examples/tumblog/tasks/tumblog.rake +30 -0
  46. data/examples/tumblog/templates/atom_feed.erb +40 -0
  47. data/examples/tumblog/templates/tumblog/conversation.erb +12 -0
  48. data/examples/tumblog/templates/tumblog/link.erb +10 -0
  49. data/examples/tumblog/templates/tumblog/photo.erb +13 -0
  50. data/examples/tumblog/templates/tumblog/post.erb +12 -0
  51. data/examples/tumblog/templates/tumblog/quote.erb +11 -0
  52. data/examples/webby/Sitefile +19 -0
  53. data/examples/webby/content/communicate/index.txt +28 -0
  54. data/examples/webby/content/css/background.gif +0 -0
  55. data/examples/webby/content/css/blueprint/print.css +76 -0
  56. data/examples/webby/content/css/blueprint/screen.css +696 -0
  57. data/examples/webby/content/css/coderay.css +96 -0
  58. data/examples/webby/content/css/site.css +196 -0
  59. data/examples/webby/content/css/uv/twilight.css +137 -0
  60. data/examples/webby/content/index.txt +37 -0
  61. data/examples/webby/content/learn/index.txt +28 -0
  62. data/examples/webby/content/reference/index.txt +204 -0
  63. data/examples/webby/content/release-notes/index.txt +21 -0
  64. data/examples/webby/content/release-notes/rel-0-9-0/index.txt +74 -0
  65. data/examples/webby/content/release-notes/rel-0-9-1/index.txt +93 -0
  66. data/examples/webby/content/release-notes/rel-0-9-2/index.txt +14 -0
  67. data/examples/webby/content/release-notes/rel-0-9-3/index.txt +49 -0
  68. data/examples/webby/content/robots.txt +6 -0
  69. data/examples/webby/content/script/jquery.corner.js +152 -0
  70. data/examples/webby/content/script/jquery.js +31 -0
  71. data/examples/webby/content/sitemap.txt +31 -0
  72. data/examples/webby/content/tips_and_tricks/index.txt +97 -0
  73. data/examples/webby/content/tutorial/index.txt +135 -0
  74. data/examples/webby/content/user-manual/index.txt +419 -0
  75. data/examples/webby/layouts/default.txt +49 -0
  76. data/examples/webby/templates/page.erb +10 -0
  77. data/examples/website/Sitefile +7 -0
  78. data/examples/website/content/css/blueprint/License.txt +21 -0
  79. data/examples/website/content/css/blueprint/Readme.txt +100 -0
  80. data/examples/website/content/css/blueprint/compressed/print.css +76 -0
  81. data/examples/website/content/css/blueprint/compressed/screen.css +696 -0
  82. data/examples/website/content/css/blueprint/lib/forms.css +45 -0
  83. data/examples/website/content/css/blueprint/lib/grid.css +193 -0
  84. data/examples/website/content/css/blueprint/lib/grid.png +0 -0
  85. data/examples/website/content/css/blueprint/lib/ie.css +30 -0
  86. data/examples/website/content/css/blueprint/lib/reset.css +39 -0
  87. data/examples/website/content/css/blueprint/lib/typography.css +116 -0
  88. data/examples/website/content/css/blueprint/plugins/buttons/Readme +31 -0
  89. data/examples/website/content/css/blueprint/plugins/buttons/buttons.css +97 -0
  90. data/examples/website/content/css/blueprint/plugins/buttons/icons/cross.png +0 -0
  91. data/examples/website/content/css/blueprint/plugins/buttons/icons/key.png +0 -0
  92. data/examples/website/content/css/blueprint/plugins/buttons/icons/tick.png +0 -0
  93. data/examples/website/content/css/blueprint/plugins/css-classes/Readme +14 -0
  94. data/examples/website/content/css/blueprint/plugins/css-classes/css-classes.css +24 -0
  95. data/examples/website/content/css/blueprint/plugins/fancy-type/Readme +22 -0
  96. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type-compressed.css +5 -0
  97. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type.css +74 -0
  98. data/examples/website/content/css/blueprint/print.css +68 -0
  99. data/examples/website/content/css/blueprint/screen.css +22 -0
  100. data/examples/website/content/css/coderay.css +111 -0
  101. data/examples/website/content/css/site.css +67 -0
  102. data/examples/website/content/index.txt +19 -0
  103. data/examples/website/layouts/default.txt +58 -0
  104. data/examples/website/lib/breadcrumbs.rb +28 -0
  105. data/examples/website/templates/_partial.erb +10 -0
  106. data/examples/website/templates/page.erb +18 -0
  107. data/lib/webby.rb +221 -0
  108. data/lib/webby/apps.rb +12 -0
  109. data/lib/webby/apps/generator.rb +276 -0
  110. data/lib/webby/apps/main.rb +255 -0
  111. data/lib/webby/auto_builder.rb +157 -0
  112. data/lib/webby/builder.rb +180 -0
  113. data/lib/webby/core_ext/enumerable.rb +11 -0
  114. data/lib/webby/core_ext/hash.rb +28 -0
  115. data/lib/webby/core_ext/kernel.rb +26 -0
  116. data/lib/webby/core_ext/string.rb +163 -0
  117. data/lib/webby/core_ext/time.rb +9 -0
  118. data/lib/webby/filters.rb +83 -0
  119. data/lib/webby/filters/basepath.rb +97 -0
  120. data/lib/webby/filters/erb.rb +9 -0
  121. data/lib/webby/filters/haml.rb +18 -0
  122. data/lib/webby/filters/markdown.rb +16 -0
  123. data/lib/webby/filters/outline.rb +309 -0
  124. data/lib/webby/filters/sass.rb +17 -0
  125. data/lib/webby/filters/slides.rb +56 -0
  126. data/lib/webby/filters/textile.rb +16 -0
  127. data/lib/webby/filters/tidy.rb +76 -0
  128. data/lib/webby/filters/wiki_words.rb +14 -0
  129. data/lib/webby/helpers.rb +30 -0
  130. data/lib/webby/helpers/capture_helper.rb +141 -0
  131. data/lib/webby/helpers/coderay_helper.rb +69 -0
  132. data/lib/webby/helpers/graphviz_helper.rb +136 -0
  133. data/lib/webby/helpers/tag_helper.rb +65 -0
  134. data/lib/webby/helpers/tex_img_helper.rb +133 -0
  135. data/lib/webby/helpers/ultraviolet_helper.rb +63 -0
  136. data/lib/webby/helpers/url_helper.rb +241 -0
  137. data/lib/webby/journal.rb +126 -0
  138. data/lib/webby/link_validator.rb +152 -0
  139. data/lib/webby/renderer.rb +386 -0
  140. data/lib/webby/resources.rb +136 -0
  141. data/lib/webby/resources/db.rb +251 -0
  142. data/lib/webby/resources/layout.rb +54 -0
  143. data/lib/webby/resources/meta_file.rb +211 -0
  144. data/lib/webby/resources/page.rb +81 -0
  145. data/lib/webby/resources/partial.rb +85 -0
  146. data/lib/webby/resources/resource.rb +201 -0
  147. data/lib/webby/resources/static.rb +36 -0
  148. data/lib/webby/stelan/mktemp.rb +135 -0
  149. data/lib/webby/stelan/paginator.rb +165 -0
  150. data/lib/webby/stelan/spawner.rb +339 -0
  151. data/lib/webby/tasks/build.rake +27 -0
  152. data/lib/webby/tasks/create.rake +22 -0
  153. data/lib/webby/tasks/deploy.rake +22 -0
  154. data/lib/webby/tasks/growl.rake +16 -0
  155. data/lib/webby/tasks/validate.rake +19 -0
  156. data/spec/core_ext/hash_spec.rb +47 -0
  157. data/spec/core_ext/string_spec.rb +110 -0
  158. data/spec/core_ext/time_spec.rb +19 -0
  159. data/spec/data/hooligans/bad_meta_data_1.txt +34 -0
  160. data/spec/data/hooligans/bad_meta_data_2.txt +34 -0
  161. data/spec/data/outline/basic.out +81 -0
  162. data/spec/data/outline/basic.txt +25 -0
  163. data/spec/data/outline/no_clobber.out +86 -0
  164. data/spec/data/outline/numbering.out +81 -0
  165. data/spec/data/outline/numbering_only.out +21 -0
  166. data/spec/data/outline/toc_range_1.out +66 -0
  167. data/spec/data/outline/toc_range_2.out +55 -0
  168. data/spec/data/outline/toc_style.out +81 -0
  169. data/spec/data/site/Sitefile +9 -0
  170. data/spec/data/site/content/_partial.txt +10 -0
  171. data/spec/data/site/content/css/coderay.css +111 -0
  172. data/spec/data/site/content/css/site.css +67 -0
  173. data/spec/data/site/content/css/tumblog.css +308 -0
  174. data/spec/data/site/content/images/tumblog/permalink.gif +0 -0
  175. data/spec/data/site/content/images/tumblog/rss.gif +0 -0
  176. data/spec/data/site/content/index.txt +19 -0
  177. data/spec/data/site/content/photos.txt +21 -0
  178. data/spec/data/site/content/tumblog/200806/the-noble-chicken/index.txt +12 -0
  179. data/spec/data/site/content/tumblog/200807/historical-perspectives-on-the-classic-chicken-joke/index.txt +12 -0
  180. data/spec/data/site/content/tumblog/200807/mad-city-chickens/index.txt +10 -0
  181. data/spec/data/site/content/tumblog/200807/the-wisdom-of-the-dutch/index.txt +11 -0
  182. data/spec/data/site/content/tumblog/200807/up-a-tree/index.txt +13 -0
  183. data/spec/data/site/content/tumblog/index.txt +37 -0
  184. data/spec/data/site/content/tumblog/rss.txt +37 -0
  185. data/spec/data/site/layouts/default.txt +58 -0
  186. data/spec/data/site/layouts/tumblog/default.txt +44 -0
  187. data/spec/data/site/layouts/tumblog/post.txt +15 -0
  188. data/spec/data/site/lib/breadcrumbs.rb +28 -0
  189. data/spec/data/site/lib/tumblog_helper.rb +32 -0
  190. data/spec/data/site/tasks/tumblog.rake +30 -0
  191. data/spec/data/site/templates/_partial.erb +10 -0
  192. data/spec/data/site/templates/atom_feed.erb +40 -0
  193. data/spec/data/site/templates/page.erb +18 -0
  194. data/spec/data/site/templates/presentation.erb +40 -0
  195. data/spec/data/site/templates/tumblog/conversation.erb +12 -0
  196. data/spec/data/site/templates/tumblog/link.erb +10 -0
  197. data/spec/data/site/templates/tumblog/photo.erb +13 -0
  198. data/spec/data/site/templates/tumblog/post.erb +12 -0
  199. data/spec/data/site/templates/tumblog/quote.erb +11 -0
  200. data/spec/spec.opts +1 -0
  201. data/spec/spec_helper.rb +51 -0
  202. data/spec/webby/apps/generator_spec.rb +116 -0
  203. data/spec/webby/apps/main_spec.rb +88 -0
  204. data/spec/webby/filters/basepath_spec.rb +167 -0
  205. data/spec/webby/filters/outline_spec.rb +92 -0
  206. data/spec/webby/filters/textile_spec.rb +20 -0
  207. data/spec/webby/helpers/capture_helper_spec.rb +56 -0
  208. data/spec/webby/renderer_spec.rb +139 -0
  209. data/spec/webby/resources/db_spec.rb +250 -0
  210. data/spec/webby/resources/layout_spec.rb +83 -0
  211. data/spec/webby/resources/meta_file_spec.rb +171 -0
  212. data/spec/webby/resources/page_spec.rb +111 -0
  213. data/spec/webby/resources/partial_spec.rb +58 -0
  214. data/spec/webby/resources/resource_spec.rb +219 -0
  215. data/spec/webby/resources/static_spec.rb +49 -0
  216. data/spec/webby/resources_spec.rb +69 -0
  217. data/tasks/ann.rake +81 -0
  218. data/tasks/bones.rake +21 -0
  219. data/tasks/gem.rake +187 -0
  220. data/tasks/git.rake +41 -0
  221. data/tasks/manifest.rake +48 -0
  222. data/tasks/notes.rake +28 -0
  223. data/tasks/post_load.rake +39 -0
  224. data/tasks/rdoc.rake +51 -0
  225. data/tasks/rubyforge.rake +55 -0
  226. data/tasks/setup.rb +268 -0
  227. data/tasks/spec.rake +55 -0
  228. data/tasks/website.rake +38 -0
  229. metadata +365 -0
@@ -0,0 +1,255 @@
1
+ require 'optparse'
2
+ require 'rake'
3
+
4
+ module Webby::Apps
5
+
6
+ class Main
7
+
8
+ # Create a new instance of Main, and run the +webby+ application given the
9
+ # command line _args_.
10
+ #
11
+ def self.run( args )
12
+ self.new.run args
13
+ end
14
+
15
+ attr_reader :cmd_line_options
16
+
17
+ # Create a new Main webby object for building websites.
18
+ #
19
+ def initialize
20
+ @stdout = $stdout
21
+ @cmd_line_options = {}
22
+ end
23
+
24
+ # Runs the main webby application. The command line arguments are passed
25
+ # in to this method as an array of strings. The command line arguments are
26
+ # parsed to figure out which rake task to invoke.
27
+ #
28
+ def run( args )
29
+ args = args.dup
30
+
31
+ parse args
32
+ init args
33
+ rake
34
+ end
35
+
36
+ # Parse the command line _args_ for options and commands to invoke.
37
+ #
38
+ def parse( args )
39
+ opts = OptionParser.new
40
+ opts.banner = 'Usage: webby [options] target [target args]'
41
+
42
+ opts.separator ''
43
+
44
+ desired_opts = %[--describe --prereqs --tasks --trace]
45
+ app.standard_rake_options.each do |options|
46
+ next unless desired_opts.include?(options.first)
47
+ opts.on(*options)
48
+ end
49
+
50
+ opts.separator ''
51
+ opts.separator 'autobuild options:'
52
+
53
+ opts.on('--web-server', 'Start a local web server') {
54
+ cmd_line_options[:use_web_server] = true
55
+ }
56
+ opts.on('--no-web-server', 'Do not start a local web server') {
57
+ cmd_line_options[:use_web_server] = false
58
+ }
59
+
60
+ opts.separator ''
61
+ opts.separator 'common options:'
62
+
63
+ opts.on_tail( '-h', '--help', 'show this message' ) do
64
+ @stdout.puts opts
65
+ exit
66
+ end
67
+ opts.on_tail( '--version', 'show version' ) do
68
+ @stdout.puts "Webby #{::Webby::VERSION}"
69
+ exit
70
+ end
71
+
72
+ opts.parse! args
73
+
74
+ ARGV.replace Array(args.shift)
75
+ args.delete_if do |arg|
76
+ if %r/^[A-Z_]+=/ =~ arg
77
+ ARGV << arg
78
+ next true
79
+ end
80
+ false
81
+ end
82
+
83
+ args
84
+ end
85
+
86
+ # Initialize the Rake application object and load the core rake tasks, the
87
+ # site specific rake tasks, and the site specific ruby code. Any extra
88
+ # command line arguments are converted into a page name and directory that
89
+ # might get created (depending upon the task invoked).
90
+ #
91
+ def init( args )
92
+ # Make sure we're in a folder with a Sitefile
93
+ options = app.standard_rake_options
94
+ [['--rakefile', 'Sitefile'],
95
+ ['--no-search', nil],
96
+ ['--silent', nil]].each {|opt, value| options.assoc(opt).last.call(value)}
97
+
98
+ unless app.have_rakefile
99
+ raise RuntimeError, "Sitefile not found"
100
+ end
101
+
102
+ import_default_tasks
103
+ import_website_tasks
104
+ require_lib_files
105
+ capture_command_line_args(args)
106
+ args
107
+ end
108
+
109
+ # Execute the rake command.
110
+ #
111
+ def rake
112
+ app.init 'webby'
113
+ app.load_rakefile
114
+ load_command_line_options
115
+ app.top_level
116
+ end
117
+
118
+ # Return the Rake application object.
119
+ #
120
+ def app
121
+ Rake.application
122
+ end
123
+
124
+ # Returns the options hash from the Rake application object.
125
+ #
126
+ def options
127
+ app.options
128
+ end
129
+
130
+ # Search for the "Sitefile" starting in the current directory and working
131
+ # upwards through the filesystem until the root of the filesystem is
132
+ # reached. If a "Sitefile" is not found, a RuntimeError is raised.
133
+ #
134
+ def find_sitefile
135
+ here = Dir.pwd
136
+ while ! app.have_rakefile
137
+ Dir.chdir("..")
138
+ if Dir.pwd == here || options.nosearch
139
+ fail "No Sitefile found"
140
+ end
141
+ here = Dir.pwd
142
+ end
143
+ end
144
+
145
+ def import_default_tasks
146
+ Dir.glob(::Webby.libpath(%w[webby tasks *.rake])).sort.each {|fn| import fn}
147
+ end
148
+
149
+ def import_website_tasks
150
+ Dir.glob(::File.join(%w[tasks *.rake])).sort.each {|fn| import fn}
151
+ end
152
+
153
+ def require_lib_files
154
+ Dir.glob(::File.join(%w[lib ** *.rb])).sort.each {|fn| require fn}
155
+ end
156
+
157
+ def capture_command_line_args(args)
158
+ args = OpenStruct.new(:raw => args)
159
+
160
+ if args.raw.size > 1
161
+ ::Webby.deprecated "multiple arguments used for page title",
162
+ "please quote the page title"
163
+ end
164
+
165
+ dashed = args.raw.join('-').downcase
166
+ spaced = args.raw.join(' ')
167
+ dir = ::File.dirname(dashed)
168
+
169
+ args.dir = ('.' == dir ? '' : dir)
170
+ args.slug = ::Webby::Resources.basename(dashed).to_url
171
+ args.title = ::Webby::Resources.basename(spaced).titlecase
172
+
173
+ # page should be dir/slug without leading /
174
+ args.page = ::File.join(args.dir, args.slug).gsub(/^\//, '')
175
+
176
+ ext = ::File.extname(dashed)
177
+ args.page << ext unless ext.empty?
178
+
179
+ ::Webby.site.args = args
180
+ Object.const_set(:SITE, Webby.site)
181
+ args
182
+ end
183
+
184
+ # Load options from the command line into the ::Webby.site struct
185
+ #
186
+ def load_command_line_options
187
+ cmd_line_options.each do |key, value|
188
+ ::Webby.site.__send__("#{key}=", value)
189
+ end
190
+ end
191
+
192
+ end # class Main
193
+ end # module Webby::Apps
194
+
195
+ # :stopdoc:
196
+ # Monkey patches so that rake displays the correct application name in the
197
+ # help messages.
198
+ #
199
+ class Rake::Application
200
+ def display_prerequisites
201
+ tasks.each do |t|
202
+ puts "#{name} #{t.name}"
203
+ t.prerequisites.each { |pre| puts " #{pre}" }
204
+ end
205
+ end
206
+
207
+ def display_tasks_and_comments
208
+ displayable_tasks = tasks.select { |t|
209
+ t.comment && t.name =~ options.show_task_pattern
210
+ }
211
+ if options.full_description
212
+ displayable_tasks.each do |t|
213
+ puts "#{name} #{t.name_with_args}"
214
+ t.full_comment.split("\n").each do |line|
215
+ puts " #{line}"
216
+ end
217
+ puts
218
+ end
219
+ else
220
+ width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
221
+ max_column = truncate_output? ? terminal_width - name.size - width - 7 : nil
222
+ displayable_tasks.each do |t|
223
+ printf "#{name} %-#{width}s # %s\n",
224
+ t.name_with_args, max_column ? truncate(t.comment, max_column) : t.comment
225
+ end
226
+ end
227
+ end
228
+
229
+ # Provide standard execption handling for the given block.
230
+ def standard_exception_handling
231
+ begin
232
+ yield
233
+ rescue SystemExit => ex
234
+ # Exit silently with current status
235
+ exit(ex.status)
236
+ rescue SystemExit, OptionParser::InvalidOption => ex
237
+ # Exit silently
238
+ exit(1)
239
+ rescue Exception => ex
240
+ # Exit with error message
241
+ $stderr.puts "#{name} aborted!"
242
+ $stderr.puts ex.message
243
+ if options.trace
244
+ $stderr.puts ex.backtrace.join("\n")
245
+ else
246
+ $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
247
+ $stderr.puts "(See full trace by running task with --trace)"
248
+ end
249
+ exit(1)
250
+ end
251
+ end
252
+ end # class Rake::Application
253
+ # :startdoc:
254
+
255
+ # EOF
@@ -0,0 +1,157 @@
1
+ require 'directory_watcher'
2
+ require 'launchy'
3
+ require 'webrick'
4
+
5
+ module Webby
6
+
7
+ # The AutoBuilder class is used to monitor the content and layouts folders
8
+ # and to compile the resource files only when they are modified. If a
9
+ # layout is modified, then all resources that depend upon the layout are
10
+ # compiled.
11
+ #
12
+ class AutoBuilder
13
+
14
+ # TODO: hit Ctrl-C once to rebuild everything, and hit it twice to stop the autobuild loop
15
+
16
+ # call-seq:
17
+ # AutoBuilder.run
18
+ #
19
+ # Creates a new AutoBuilder and sets it running. This method will only
20
+ # return when the user presses Ctrl-C.
21
+ #
22
+ def self.run
23
+ self.new.run
24
+ end
25
+
26
+ attr_reader :logger
27
+
28
+ # call-seq:
29
+ # AutoBuilder.new
30
+ #
31
+ # Create a new AutoBuilder class.
32
+ #
33
+ def initialize
34
+ @logger = Logging::Logger[self]
35
+
36
+ @builder = Builder.new
37
+ @builder.load_files
38
+
39
+ @watcher = DirectoryWatcher.new '.', :interval => 2
40
+ @watcher.add_observer self
41
+
42
+ glob = []
43
+ glob << File.join(::Webby.site.layout_dir, '**', '*')
44
+ glob << File.join(::Webby.site.content_dir, '**', '*')
45
+ @watcher.glob = glob
46
+
47
+ @web_server = ::Webby.site.use_web_server ? WebServer.new : nil
48
+ end
49
+
50
+ # call-seq:
51
+ # update( *events )
52
+ #
53
+ # The update method is called by the DirectoryWatcher when files have been
54
+ # modified, added, or deleted. An array of events is passed to his method,
55
+ # and each event contains the event type and the path to the file.
56
+ #
57
+ def update( *events )
58
+ ary = events.find_all {|evt| evt.type != :removed}
59
+ return if ary.empty?
60
+
61
+ ary.each do |evt|
62
+ logger.debug "changed #{evt.path}"
63
+ next unless test ?f, evt.path
64
+ next if evt.path =~ ::Webby.exclude
65
+ Resources.new evt.path
66
+ end
67
+
68
+ logger.info 'running the build'
69
+ @builder.run :load_files => false, :verbose => false
70
+ rescue => err
71
+ logger.error err
72
+ end
73
+
74
+ # call-seq:
75
+ # run
76
+ #
77
+ # Starts the DirectoryWatcher running and waits till the user presses
78
+ # Ctrl-C to stop the watcher thread.
79
+ #
80
+ def run
81
+ logger.info 'starting autobuild (Ctrl-C to stop)'
82
+
83
+ Signal.trap('INT') {
84
+ @watcher.stop
85
+ @web_server.stop if @web_server
86
+ }
87
+
88
+ @watcher.start
89
+ if @web_server
90
+ @web_server.start
91
+ sleep 0.25
92
+ Launchy.open("http://localhost:#{::Webby.site.heel_port}")
93
+ end
94
+
95
+ @watcher.join
96
+ @web_server.join if @web_server
97
+ end
98
+
99
+ # Wrapper class around the webrick web server.
100
+ #
101
+ class WebServer
102
+
103
+ # Create a new webrick server configured to serve pages from the output
104
+ # directory. Output will be directed to /dev/null.
105
+ #
106
+ def initialize
107
+ logger = WEBrick::Log.new(Kernel::DEV_NULL, WEBrick::Log::DEBUG)
108
+ access_log = [[ logger, WEBrick::AccessLog::COMBINED_LOG_FORMAT ]]
109
+
110
+ @thread = nil
111
+ @running = false
112
+ @server = WEBrick::HTTPServer.new(
113
+ :BindAddress => 'localhost',
114
+ :Port => ::Webby.site.heel_port,
115
+ :DocumentRoot => ::Webby.site.output_dir,
116
+ :FancyIndexing => true,
117
+ :Logger => logger,
118
+ :AccessLog => access_log
119
+ )
120
+ end
121
+
122
+ # Returns +true+ if the server is running.
123
+ #
124
+ def running?
125
+ @running
126
+ end
127
+
128
+ # Start the webrick server running in a separate thread (so we don't
129
+ # block forever).
130
+ #
131
+ def start
132
+ return if running?
133
+ @running = true
134
+ @thread = Thread.new {@server.start}
135
+ end
136
+
137
+ # Stop the webrick server.
138
+ #
139
+ def stop
140
+ return if not running?
141
+ @running = false
142
+ @server.shutdown
143
+ end
144
+
145
+ # Join on the webserver thread.
146
+ #
147
+ def join
148
+ return if not running?
149
+ @thread.join
150
+ end
151
+
152
+ end # class WebServer
153
+
154
+ end # class AutoBuilder
155
+ end # module Webby
156
+
157
+ # EOF
@@ -0,0 +1,180 @@
1
+ require 'find'
2
+ require 'fileutils'
3
+ require 'erb'
4
+
5
+ module Webby
6
+
7
+ # The Builder class performs the work of scanning the content folder,
8
+ # creating Resource objects, and converting / copying the contents to the
9
+ # output folder as needed.
10
+ #
11
+ class Builder
12
+
13
+ class << self
14
+
15
+ # call-seq:
16
+ # Builder.run( :rebuild => false )
17
+ #
18
+ # Create a new instance of the Builder class and invoke the run method.
19
+ # If the <code>:rebuild</code> option is given as +true+, then all pages
20
+ # will be recreated / copied.
21
+ #
22
+ def run( opts = {} )
23
+ self.new.run opts
24
+ end
25
+
26
+ # call-seq:
27
+ # Builder.create( page, :from => template, :locals => {} )
28
+ #
29
+ # This mehod is used to create a new _page_ in the content folder based
30
+ # on the specified template. _page_ is the relative path to the new page
31
+ # from the <code>content/</code> folder. The _template_ is the name of
32
+ # the template to use from the <code>templates/</code> folder.
33
+ #
34
+ def create( page, opts = {} )
35
+ tmpl = opts[:from]
36
+ raise Error, "template not given" unless tmpl
37
+
38
+ name = ::Webby::Resources.basename(page)
39
+ ext = ::Webby::Resources.extname(page)
40
+ dir = ::File.dirname(page)
41
+ dir = '' if dir == '.'
42
+
43
+ if tmpl.pathmap('%n') =~ %r/^_/
44
+ page = ::File.join(::Webby.site.content_dir, dir, '_'+name)
45
+ page << '.' << (ext.empty? ? 'txt' : ext)
46
+ elsif ::Webby.site.create_mode == 'directory' and name != 'index'
47
+ page = ::File.join(::Webby.site.content_dir, dir, name, 'index')
48
+ page << '.' << (ext.empty? ? 'txt' : ext)
49
+ else
50
+ page = ::File.join(::Webby.site.content_dir, page)
51
+ page << '.txt' if ext.empty?
52
+ end
53
+ raise Error, "#{page} already exists" if test ?e, page
54
+
55
+ Logging::Logger[self].info "creating #{page}"
56
+ FileUtils.mkdir_p ::File.dirname(page)
57
+
58
+ context = scope
59
+ opts[:locals].each do |k,v|
60
+ Thread.current[:value] = v
61
+ definition = "#{k} = Thread.current[:value]"
62
+ eval(definition, context)
63
+ end if opts.has_key?(:locals)
64
+
65
+ str = ERB.new(::File.read(tmpl), nil, '-').result(context)
66
+ ::File.open(page, 'w') {|fd| fd.write str}
67
+
68
+ page
69
+ end
70
+
71
+ # call-seq:
72
+ # Builder.new_page_info => [page, title, directory]
73
+ #
74
+ def new_page_info
75
+ args = Webby.site.args
76
+
77
+ if args.raw.empty?
78
+ task_name = Rake.application.top_level_tasks.first
79
+ raise "Usage: webby #{task_name} path"
80
+ end
81
+
82
+ [args.page, args.title, args.dir]
83
+ end
84
+
85
+ private
86
+
87
+ # Returns the binding in the scope of the Builder class object.
88
+ #
89
+ def scope() binding end
90
+
91
+ end # class << self
92
+
93
+ # call-seq:
94
+ # Builder.new
95
+ #
96
+ # Creates a new Builder object for creating pages from the content and
97
+ # layout directories.
98
+ #
99
+ def initialize
100
+ @logger = Logging::Logger[self]
101
+ end
102
+
103
+ # call-seq:
104
+ # run( :rebuild => false, :load_files => true )
105
+ #
106
+ # Runs the Webby builder by loading in the layout files from the
107
+ # <code>layouts/</code> folder and the content from the
108
+ # <code>contents/</code> folder. Content is analyzed, and those that need
109
+ # to be copied or compiled (filtered using ERB, Texttile, Markdown, etc.)
110
+ # are handled. The results are placed in the <code>output/</code> folder.
111
+ #
112
+ # If the <code>:rebuild</code> flag is set to +true+, then all content is
113
+ # copied and/or compiled to the output folder.
114
+ #
115
+ # A content file can mark itself as dirty by setting the +dirty+ flag to
116
+ # +true+ in the meta-data of the file. This will cause the contenet to
117
+ # always be compiled when the builder is run. Conversely, setting the
118
+ # dirty flag to +false+ will cause the content to never be compiled or
119
+ # copied to the output folder.
120
+ #
121
+ # A content file needs to be built if the age of the file is less then the
122
+ # age of the output product -- i.e. the content file has been modified
123
+ # more recently than the output file.
124
+ #
125
+ def run( opts = {} )
126
+ opts[:load_files] = true unless opts.has_key?(:load_files)
127
+ verbose = opts.getopt(:verbose, true)
128
+
129
+ unless test(?d, output_dir)
130
+ journal.create output_dir
131
+ FileUtils.mkdir output_dir
132
+ end
133
+
134
+ load_files if opts[:load_files]
135
+
136
+ Resources.pages.each do |page|
137
+ unless page.dirty? or opts[:rebuild]
138
+ journal.identical(page.destination) if verbose
139
+ next
140
+ end
141
+
142
+ # copy the resource to the output directory if it is static
143
+ if page.instance_of? Resources::Static
144
+ FileUtils.mkdir_p ::File.dirname(page.destination)
145
+ journal.create_or_update(page)
146
+ FileUtils.cp page.path, page.destination
147
+ FileUtils.chmod 0644, page.destination
148
+
149
+ # otherwise, layout the resource and write the results to
150
+ # the output directory
151
+ else Renderer.write(page) end
152
+ end
153
+
154
+ # touch the cairn so we know when the website was last generated
155
+ FileUtils.touch ::Webby.cairn
156
+
157
+ nil
158
+ end
159
+
160
+ # Scan the <code>layouts/</code> folder and the <code>content/</code>
161
+ # folder and create a new Resource object for each file found there.
162
+ #
163
+ def load_files
164
+ ::Find.find(layout_dir, content_dir) do |path|
165
+ next unless test ?f, path
166
+ next if path =~ ::Webby.exclude
167
+ Resources.new path
168
+ end
169
+ end
170
+
171
+ %w(output_dir layout_dir content_dir).each do |key|
172
+ self.class_eval <<-CODE
173
+ def #{key}( ) ::Webby.site.#{key} end
174
+ CODE
175
+ end
176
+
177
+ end # class Builder
178
+ end # module Webby
179
+
180
+ # EOF