webby 0.7.4 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/History.txt +19 -0
  2. data/Manifest.txt +19 -6
  3. data/README.txt +21 -5
  4. data/Rakefile +2 -3
  5. data/data/Rakefile +1 -1
  6. data/data/lib/breadcrumbs.rb +28 -0
  7. data/data/tasks/create.rake +0 -1
  8. data/data/tasks/deploy.rake +0 -1
  9. data/data/tasks/growl.rake +0 -1
  10. data/data/tasks/heel.rake +2 -3
  11. data/data/tasks/setup.rb +0 -1
  12. data/data/templates/_partial.erb +10 -0
  13. data/data/templates/atom_feed.erb +34 -0
  14. data/examples/webby/content/manual/index.txt +11 -13
  15. data/examples/webby/content/tutorial/index.txt +1 -1
  16. data/examples/webby/tasks/heel.rake +2 -2
  17. data/examples/webby/tasks/setup.rb +6 -1
  18. data/lib/webby.rb +50 -23
  19. data/lib/webby/auto_builder.rb +4 -2
  20. data/lib/webby/builder.rb +6 -5
  21. data/lib/webby/filters.rb +6 -7
  22. data/lib/webby/filters/outline.rb +4 -2
  23. data/lib/webby/filters/tidy.rb +4 -2
  24. data/lib/webby/helpers.rb +32 -0
  25. data/lib/webby/helpers/coderay_helper.rb +78 -0
  26. data/lib/webby/helpers/graphviz_helper.rb +158 -0
  27. data/lib/webby/helpers/tag_helper.rb +9 -4
  28. data/lib/webby/helpers/tex_img_helper.rb +181 -0
  29. data/lib/webby/helpers/url_helper.rb +12 -11
  30. data/lib/webby/renderer.rb +97 -18
  31. data/lib/webby/resources.rb +82 -0
  32. data/lib/webby/{pages_db.rb → resources/db.rb} +63 -33
  33. data/lib/webby/{file.rb → resources/file.rb} +27 -24
  34. data/lib/webby/resources/layout.rb +65 -0
  35. data/lib/webby/resources/page.rb +109 -0
  36. data/lib/webby/resources/partial.rb +81 -0
  37. data/lib/webby/resources/resource.rb +145 -0
  38. data/lib/webby/resources/static.rb +54 -0
  39. data/lib/webby/stelan/mktemp.rb +137 -0
  40. data/lib/webby/stelan/spawner.rb +5 -1
  41. data/lib/webby/utils.rb +3 -1
  42. data/lib/webby/webby_task.rb +43 -24
  43. data/spec/spec_helper.rb +12 -1
  44. data/spec/webby/{file_spec.rb → resources/file_spec.rb} +21 -22
  45. data/tasks/ann.rake +76 -0
  46. data/tasks/annotations.rake +6 -14
  47. data/tasks/bones.rake +40 -0
  48. data/tasks/doc.rake +1 -2
  49. data/tasks/gem.rake +29 -2
  50. data/tasks/manifest.rake +15 -21
  51. data/tasks/post_load.rake +22 -8
  52. data/tasks/setup.rb +53 -15
  53. data/tasks/spec.rake +13 -0
  54. metadata +22 -9
  55. data/lib/webby/filters/coderay.rb +0 -98
  56. data/lib/webby/filters/graphviz.rb +0 -189
  57. data/lib/webby/resource.rb +0 -293
@@ -0,0 +1,181 @@
1
+ # $Id: tex_img_helper.rb 181 2008-02-29 05:09:49Z tim_pease $
2
+
3
+ require Webby.libpath(*%w[webby stelan mktemp])
4
+ require 'fileutils'
5
+ require 'tempfile'
6
+
7
+ module Webby::Helpers
8
+ module TexImgHelper
9
+
10
+ # :stopdoc:
11
+ class Error < StandardError; end
12
+ # :startdoc:
13
+
14
+ # The +tex2img+ method converts a a section of mathematical TeX script
15
+ # into an image and embeds the resulting image into the page. The TeX
16
+ # engine must be installed on your system along with the ImageMagick
17
+ # +convert+ program.
18
+ #
19
+ # Options can be passed to the TeX engine via attributes in the
20
+ # +tex2img+ method.
21
+ #
22
+ # <% tex2img( "wave_eq", :path => "images", :alt => "wave equation" ) do -%>
23
+ # $\psi_{tot}(x,-t_0,r) = \frac{1}{(2\pi)^2} \int\!\!\!\int
24
+ # \tilde\Psi_{tot}\left(k_x,\frac{c}{2}\sqrt{k_x^2 + k_r^2},r=0\right)$
25
+ # <% end -%>
26
+ #
27
+ # The supported TeX options are the following:
28
+ #
29
+ # :path : where generated images will be stored
30
+ # [default is "/"]
31
+ # :type : the type of image to generate (png, jpeg, gif)
32
+ # [default is png]
33
+ # :bg : the background color of the image (color name,
34
+ # TeX color spec, or #aabbcc) [default is white]
35
+ # :fg : the foreground color of the image (color name,
36
+ # TeX color spec, or #aabbcc) [default is black]
37
+ # :resolution : the desired resolution in dpi (HxV)
38
+ # [default is 150x150]
39
+ # :antialias : if false, disables anti-aliasing in the resulting image
40
+ # [default is true]
41
+ #
42
+ # the following options are passed as-is to the generated <img /> tag
43
+ # :style : CSS styles to apply to the <img />
44
+ # :class : CSS class to apply to the <img />
45
+ # :id : HTML identifier
46
+ # :alt : alternate text for the <img />
47
+ #
48
+ def tex2img( *args, &block )
49
+ opts = args.last.instance_of?(Hash) ? args.pop : {}
50
+ name = args.first
51
+ raise 'TeX graphics must have a name' if name.nil?
52
+
53
+ buffer = eval('_erbout', block.binding)
54
+ pos = buffer.length
55
+ block.call(*args)
56
+
57
+ text = buffer[pos..-1].strip
58
+ if text.empty?
59
+ buffer[pos..-1] = ''
60
+ return
61
+ end
62
+
63
+ # create a temporary file for holding any error messages
64
+ # from the graphviz program
65
+ err = Tempfile.new('graphviz_err')
66
+ err.close
67
+
68
+ path = opts.getopt(:path)
69
+ type = opts.getopt(:type, 'png')
70
+ bg = opts.getopt(:bg, 'white')
71
+ fg = opts.getopt(:fg, 'black')
72
+ res = opts.getopt(:resolution, '150x150')
73
+ aa = opts.getopt(:antialias, true)
74
+
75
+ # fix the color escaping
76
+ fg = TexImgHelper.tex_color(fg)
77
+ bg = TexImgHelper.tex_color(bg)
78
+
79
+ # generate the image filename based on the path, graph name, and type
80
+ # of image to generate
81
+ image_fn = path.nil? ? name.dup : ::File.join(path, name)
82
+ image_fn = ::File.join('', image_fn) << '.' << type
83
+
84
+ # generate the image using convert -- but first ensure that the
85
+ # path exists
86
+ out_dir = ::Webby.site.output_dir
87
+ out_file = ::File.join('..', out_dir, image_fn)
88
+ FileUtils.mkpath(::File.join(out_dir, path)) unless path.nil?
89
+
90
+ tex = <<-TEX
91
+ \\documentclass[12pt]{article}
92
+ \\usepackage[usenames,dvipsnames]{color}
93
+ \\usepackage[dvips]{graphicx}
94
+ \\pagestyle{empty}
95
+ \\pagecolor#{bg}
96
+ \\begin{document}
97
+ {\\color#{fg}
98
+ #{text}
99
+ }\\end{document}
100
+ TEX
101
+ tex.gsub!(%r/\n\s+/, "\n").strip!
102
+
103
+ # make a temporarty directory to store all the TeX files
104
+ pwd = Dir.pwd
105
+ tmpdir = ::Webby::MkTemp.mktempdir('tex2img_XXXXXX')
106
+
107
+ begin
108
+ Dir.chdir(tmpdir)
109
+ File.open('out.tex', 'w') {|fd| fd.puts tex}
110
+ dev_null = test(?e, "/dev/null") ? "/dev/null" : "NUL:"
111
+
112
+ %x[latex -interaction=batchmode out.tex &> #{dev_null}]
113
+ %x[dvips -o out.eps -E out.dvi &> #{dev_null}]
114
+ %x[convert +adjoin #{aa ? '-antialias' : '+antialias'} -density #{res} out.eps #{out_file} &> #{dev_null}]
115
+ ensure
116
+ Dir.chdir(pwd)
117
+ FileUtils.rm_rf(tmpdir) if test(?e, tmpdir)
118
+ end
119
+
120
+ # generate the HTML img tag to insert back into the document
121
+ out = "<img src=\"#{image_fn}\""
122
+ %w[class style id alt].each do |atr|
123
+ val = opts.getopt(atr)
124
+ next if val.nil?
125
+ out << " %s=\"%s\"" % [atr, val]
126
+ end
127
+ out << " />\n"
128
+
129
+ if @_cursor.remaining_filters.include? 'textile'
130
+ out.insert 0, "<notextile>\n"
131
+ out << "\n</notextile>"
132
+ end
133
+
134
+ buffer[pos..-1] = out
135
+ return
136
+ ensure
137
+ end
138
+
139
+ # call-seq:
140
+ # TexImgHelper.tex_color( string ) => string
141
+ #
142
+ # Taken the given color _string_ and convert it to a TeX color spec. The
143
+ # input string can be either a RGB Hex value, a TeX color spec, or a color
144
+ # name.
145
+ #
146
+ # tex_color( '#666666' ) #=> [rgb]{0.4,0.4,0.4}
147
+ # tex_color( 'Tan' ) #=> {Tan}
148
+ # tex_color( '[rgb]{1,0,0}' ) #=> [rgb]{1,0,0}
149
+ #
150
+ # This is an example of an invalid Hex RGB color -- they must contain six
151
+ # hexidecimal characters to be valid.
152
+ #
153
+ # tex_color( '#333' ) #=> {#333}
154
+ #
155
+ def self.tex_color( color )
156
+ case color
157
+ when %r/^#([A-Fa-f0-9]{6})/o
158
+ hex = $1
159
+ rgb = []
160
+ hex.scan(%r/../) {|n| rgb << Float(n.to_i(16))/255.0}
161
+ "[rgb]{#{rgb.join(',')}}"
162
+ when %r/^[\{\[]/o
163
+ "{#{color}}"
164
+ else
165
+ color
166
+ end
167
+ end
168
+
169
+ end # module TexImgHelper
170
+
171
+ %x[latex --version 2>&1]
172
+ if 0 == $?.exitstatus
173
+ %x[convert --version 2>&1]
174
+ if 0 == $?.exitstatus
175
+ register(TexImgHelper)
176
+ end
177
+ end
178
+
179
+ end # module Webby::Helpers
180
+
181
+ # EOF
@@ -1,7 +1,6 @@
1
- # $Id: url_helper.rb 147 2008-02-14 20:14:04Z tim_pease $
1
+ # $Id: url_helper.rb 175 2008-02-28 15:49:11Z tim_pease $
2
2
 
3
- module Webby
4
- module Helpers #:nodoc:
3
+ module Webby::Helpers
5
4
 
6
5
  #
7
6
  #
@@ -38,9 +37,9 @@ module UrlHelper
38
37
  obj = args.first
39
38
 
40
39
  anchor = opts.delete(:anchor)
41
- escape = opts.has_key?(:escape) ? opts.delte(:escape) : true
40
+ escape = opts.has_key?(:escape) ? opts.delete(:escape) : true
42
41
 
43
- url = Webby::Resource === obj ? obj.url : obj.to_s
42
+ url = Webby::Resources::Resource === obj ? obj.url : obj.to_s
44
43
  url = escape_once(url) if escape
45
44
  url << "#" << anchor if anchor
46
45
 
@@ -55,8 +54,8 @@ module UrlHelper
55
54
  # method for final URL creation; see the url_for method for
56
55
  # documentation on those options.
57
56
  #
58
- # The PagesDB#find method is used to locate the page; see the find method
59
- # for the available options.
57
+ # The Resources::DB#find method is used to locate the page; see the find
58
+ # method for the available options.
60
59
  #
61
60
  # ==== Examples
62
61
  #
@@ -97,7 +96,7 @@ module UrlHelper
97
96
  attrs = opts.delete(:attrs)
98
97
 
99
98
  url = case url
100
- when String, Webby::Resource
99
+ when String, Webby::Resources::Resource
101
100
  self.url_for(url, opts)
102
101
  when :back
103
102
  'javascript:history.back()'
@@ -211,7 +210,7 @@ module UrlHelper
211
210
  link_opts = opts.delete(:url) || {}
212
211
  link_opts[:attrs] = opts.delete(:attrs)
213
212
 
214
- if Webby::Resource === name
213
+ if Webby::Resources::Resource === name
215
214
  p, name = name, nil
216
215
  elsif opts.empty? && name
217
216
  p = @pages.find(Webby.site.find_by.to_sym => name)
@@ -227,7 +226,9 @@ module UrlHelper
227
226
  end
228
227
 
229
228
  end # module UrlHelper
230
- end # module Helpers
231
- end # module Webby
229
+
230
+ register(UrlHelper)
231
+
232
+ end # module Webby::Helpers
232
233
 
233
234
  # EOF
@@ -1,10 +1,10 @@
1
- # $Id: renderer.rb 112 2008-01-26 05:31:48Z tim_pease $
1
+ # $Id: renderer.rb 173 2008-02-27 02:58:43Z tim_pease $
2
+
3
+ # Equivalent to a header guard in C/C++
4
+ # Used to prevent the spec helper from being loaded more than once
5
+ unless defined? ::Webby::Renderer
2
6
 
3
7
  require 'erb'
4
- try_require 'bluecloth'
5
- try_require 'redcloth'
6
- try_require 'haml'
7
- try_require 'sass'
8
8
 
9
9
  module Webby
10
10
 
@@ -22,10 +22,11 @@ module Webby
22
22
  #
23
23
  class Renderer
24
24
  include ERB::Util
25
- include Webby::Helpers::TagHelper
26
- include Webby::Helpers::UrlHelper
27
25
 
28
- class Error < StandardError; end # :nodoc:
26
+ # :stopdoc:
27
+ class Error < StandardError; end
28
+ @@stack = []
29
+ # :startdoc:
29
30
 
30
31
  # call-seq:
31
32
  # Renderer.write( page )
@@ -41,7 +42,7 @@ class Renderer
41
42
  ::File.open(page.destination, 'w') do |fd|
42
43
  fd.write renderer.layout_page
43
44
  end
44
- break unless renderer.__send__(:next_page)
45
+ break unless renderer.__send__(:_next_page)
45
46
  }
46
47
  end
47
48
 
@@ -53,14 +54,16 @@ class Renderer
53
54
  # render the filtered page into the desired layout.
54
55
  #
55
56
  def initialize( page )
56
- unless page.is_page?
57
+ unless page.instance_of? Resources::Page
57
58
  raise ArgumentError,
58
59
  "only page resources can be rendered '#{page.path}'"
59
60
  end
60
61
 
61
62
  @page = page
62
- @pages = Resource.pages
63
+ @pages = Resources.pages
64
+ @partials = Resources.partials
63
65
  @content = nil
66
+ @config = ::Webby.site
64
67
 
65
68
  @log = Logging::Logger[self]
66
69
  end
@@ -74,20 +77,29 @@ class Renderer
74
77
  # page's meta-data.
75
78
  #
76
79
  def layout_page
77
- layouts = Resource.layouts
80
+ layouts = Resources.layouts
78
81
  obj = @page
79
82
  str = @page.render(self)
80
83
 
84
+ @@stack << @page.path
81
85
  loop do
82
86
  lyt = layouts.find :filename => obj.layout
83
87
  break if lyt.nil?
84
88
 
85
- @content, str = str, ::Webby::File.read(lyt.path)
86
- str = Filters.process(self, lyt, str)
89
+ @content, str = str, ::Webby::Resources::File.read(lyt.path)
90
+ str = _track_rendering(lyt.path) {
91
+ Filters.process(self, lyt, str)
92
+ }
87
93
  @content, obj = nil, lyt
88
94
  end
89
95
 
96
+ @@stack.pop if @page.path == @@stack.last
97
+ raise Error, "rendering stack corrupted" unless @@stack.empty?
98
+
90
99
  str
100
+ rescue => err
101
+ @log.error "while rendering page '#{@page.path}'"
102
+ @log.error err
91
103
  end
92
104
 
93
105
  # call-seq:
@@ -97,7 +109,42 @@ class Renderer
97
109
  # determined from the page's meta-data.
98
110
  #
99
111
  def render_page
100
- Filters.process(self, @page, ::Webby::File.read(@page.path))
112
+ _track_rendering(@page.path) {
113
+ Filters.process(self, @page, ::Webby::Resources::File.read(@page.path))
114
+ }
115
+ end
116
+
117
+ # call-seq:
118
+ # render_partial( partial ) => string
119
+ #
120
+ # Render the given _partial_ into the current page. The _partial_ can
121
+ # either be the name of the partial to render or a Partial object.
122
+ #
123
+ # In the former case, the partial is found by first looking in the
124
+ # directory of the current for a partial of the same name. Failing that,
125
+ # the search is expanded to include all directories in the site. The first
126
+ # partial with a matching name is returned.
127
+ #
128
+ # In the latter case, Partial objects can be found by using the +find+
129
+ # method of the <tt>@partials</tt> database hash. Please refer to
130
+ # Webby::Resources::DB#find method for more information.
131
+ #
132
+ def render_partial( part, opts = {} )
133
+ part = case part
134
+ when String
135
+ fn = '_' + part
136
+ p = Resources.partials.find(
137
+ :filename => fn, :in_directory => @page.dir ) rescue nil
138
+ p ||= Resources.partials.find(:filename => fn)
139
+ raise Error, "could not find partial '#{part}'" if p.nil?
140
+ p
141
+ when ::Webby::Resources::Partial
142
+ part
143
+ else raise Error, "expecting a partial or a partial name" end
144
+
145
+ _track_rendering(part.path) {
146
+ Filters.process(self, part, ::Webby::Resources::File.read(part.path))
147
+ }
101
148
  end
102
149
 
103
150
  # call-seq:
@@ -119,7 +166,7 @@ class Renderer
119
166
  items[offset,per_page]
120
167
  end.first
121
168
 
122
- @pager.each &block
169
+ @pager.each(&block)
123
170
  end
124
171
 
125
172
  # call-seq:
@@ -135,13 +182,13 @@ class Renderer
135
182
  private
136
183
 
137
184
  # call-seq:
138
- # next_page => true or false
185
+ # _next_page => true or false
139
186
  #
140
187
  # Returns +true+ if there is a next page to render. Returns +false+ if
141
188
  # there is no next page or if pagination has not been configured for the
142
189
  # current page.
143
190
  #
144
- def next_page
191
+ def _next_page
145
192
  return false unless defined? @pager and @pager
146
193
 
147
194
  # go to the next page; break out if there is no next page
@@ -155,7 +202,39 @@ class Renderer
155
202
  true
156
203
  end
157
204
 
205
+ # call-seq:
206
+ # _track_rendering( path ) {block}
207
+ #
208
+ # Keep track of the page rendering for the given _path_. The _block_ is
209
+ # where the the page will be rendered.
210
+ #
211
+ # This method keeps a stack of the current pages being rendeered. It looks
212
+ # for duplicates in the stack -- an indication of a rendering loop. When a
213
+ # rendering loop is detected, an error is raised.
214
+ #
215
+ # This method returns whatever is returned from the _block_.
216
+ #
217
+ def _track_rendering( path )
218
+ loop_error = @@stack.include? path
219
+ @@stack << path
220
+
221
+ if loop_error
222
+ msg = "rendering loop detected for '#{path}'\n"
223
+ msg << " current rendering stack\n\t"
224
+ msg << @@stack.join("\n\t")
225
+ raise Error, msg
226
+ end
227
+
228
+ yield
229
+ ensure
230
+ @@stack.pop if path == @@stack.last
231
+ end
232
+
158
233
  end # class Renderer
159
234
  end # module Webby
160
235
 
236
+ Webby.require_all_libs_relative_to(__FILE__, 'stelan')
237
+
238
+ end # unless defined?
239
+
161
240
  # EOF
@@ -0,0 +1,82 @@
1
+ # $Id: resources.rb 167 2008-02-24 00:59:54Z tim_pease $
2
+
3
+ module Webby::Resources
4
+
5
+ class << self
6
+ # Returns the pages hash object.
7
+ #
8
+ def pages
9
+ @pages ||= ::Webby::Resources::DB.new
10
+ end
11
+
12
+ # Returns the layouts hash object.
13
+ #
14
+ def layouts
15
+ @layouts ||= ::Webby::Resources::DB.new
16
+ end
17
+
18
+ # Returns the partials hash object.
19
+ #
20
+ def partials
21
+ @partials ||= ::Webby::Resources::DB.new
22
+ end
23
+
24
+ # Clear the contents of the +layouts+, +pages+ and +partials+ hash
25
+ # objects.
26
+ #
27
+ def clear
28
+ self.pages.clear
29
+ self.layouts.clear
30
+ self.partials.clear
31
+ end
32
+
33
+ # call-seq:
34
+ # Resources.new( filename )
35
+ #
36
+ #
37
+ def new( fn )
38
+ # normalize the path
39
+ fn = self.path(fn)
40
+
41
+ # see if we are dealing with a layout
42
+ if %r/\A#{::Webby.site.layout_dir}\//o =~ fn
43
+ r = ::Webby::Resources::Layout.new(fn)
44
+ self.layouts << r
45
+ return r
46
+ end
47
+
48
+ # see if we are dealing with a partial
49
+ filename = ::Webby::Resources::File.basename(fn)
50
+ if %r/\A_/o =~ filename
51
+ r = ::Webby::Resources::Partial.new(fn)
52
+ self.partials << r
53
+ return r
54
+ end
55
+
56
+ # see if we are dealing with a static resource
57
+ meta = ::Webby::Resources::File.meta_data(fn)
58
+ if meta.nil?
59
+ r = ::Webby::Resources::Static.new(fn)
60
+ self.pages << r
61
+ return r
62
+ end
63
+
64
+ # this is a renderable page
65
+ r = ::Webby::Resources::Page.new(fn)
66
+ self.pages << r
67
+ return r
68
+ end
69
+
70
+ # Returns a normalized path for the given filename.
71
+ #
72
+ def path( filename )
73
+ filename.sub(%r/\A(?:\.\/|\/)/o, '').freeze
74
+ end
75
+
76
+ end # class << self
77
+
78
+ end # module Webby::Resources
79
+
80
+ Webby.require_all_libs_relative_to(__FILE__)
81
+
82
+ # EOF