TwP-webby 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. data/History.txt +176 -0
  2. data/Manifest.txt +173 -0
  3. data/README.txt +92 -0
  4. data/Rakefile +50 -0
  5. data/bin/webby +8 -0
  6. data/bin/webby-gen +8 -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 +1 -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/rel-0-9-0/index.txt +73 -0
  64. data/examples/webby/content/robots.txt +6 -0
  65. data/examples/webby/content/script/jquery.corner.js +152 -0
  66. data/examples/webby/content/script/jquery.js +31 -0
  67. data/examples/webby/content/sitemap.txt +31 -0
  68. data/examples/webby/content/tips_and_tricks/index.txt +96 -0
  69. data/examples/webby/content/tutorial/index.txt +131 -0
  70. data/examples/webby/content/user-manual/index.txt +419 -0
  71. data/examples/webby/layouts/default.txt +49 -0
  72. data/examples/webby/templates/page.erb +10 -0
  73. data/examples/website/Sitefile +7 -0
  74. data/examples/website/content/css/blueprint/License.txt +21 -0
  75. data/examples/website/content/css/blueprint/Readme.txt +100 -0
  76. data/examples/website/content/css/blueprint/compressed/print.css +76 -0
  77. data/examples/website/content/css/blueprint/compressed/screen.css +696 -0
  78. data/examples/website/content/css/blueprint/lib/forms.css +45 -0
  79. data/examples/website/content/css/blueprint/lib/grid.css +193 -0
  80. data/examples/website/content/css/blueprint/lib/grid.png +0 -0
  81. data/examples/website/content/css/blueprint/lib/ie.css +30 -0
  82. data/examples/website/content/css/blueprint/lib/reset.css +39 -0
  83. data/examples/website/content/css/blueprint/lib/typography.css +116 -0
  84. data/examples/website/content/css/blueprint/plugins/buttons/Readme +31 -0
  85. data/examples/website/content/css/blueprint/plugins/buttons/buttons.css +97 -0
  86. data/examples/website/content/css/blueprint/plugins/buttons/icons/cross.png +0 -0
  87. data/examples/website/content/css/blueprint/plugins/buttons/icons/key.png +0 -0
  88. data/examples/website/content/css/blueprint/plugins/buttons/icons/tick.png +0 -0
  89. data/examples/website/content/css/blueprint/plugins/css-classes/Readme +14 -0
  90. data/examples/website/content/css/blueprint/plugins/css-classes/css-classes.css +24 -0
  91. data/examples/website/content/css/blueprint/plugins/fancy-type/Readme +22 -0
  92. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type-compressed.css +5 -0
  93. data/examples/website/content/css/blueprint/plugins/fancy-type/fancy-type.css +74 -0
  94. data/examples/website/content/css/blueprint/print.css +68 -0
  95. data/examples/website/content/css/blueprint/screen.css +22 -0
  96. data/examples/website/content/css/coderay.css +111 -0
  97. data/examples/website/content/css/site.css +67 -0
  98. data/examples/website/content/index.txt +19 -0
  99. data/examples/website/layouts/default.txt +58 -0
  100. data/examples/website/lib/breadcrumbs.rb +28 -0
  101. data/examples/website/templates/_partial.erb +10 -0
  102. data/examples/website/templates/page.erb +18 -0
  103. data/examples/website/templates/presentation.erb +40 -0
  104. data/lib/webby/apps/generator.rb +283 -0
  105. data/lib/webby/apps/main.rb +221 -0
  106. data/lib/webby/apps.rb +12 -0
  107. data/lib/webby/auto_builder.rb +83 -0
  108. data/lib/webby/builder.rb +183 -0
  109. data/lib/webby/core_ext/enumerable.rb +11 -0
  110. data/lib/webby/core_ext/hash.rb +28 -0
  111. data/lib/webby/core_ext/kernel.rb +21 -0
  112. data/lib/webby/core_ext/string.rb +163 -0
  113. data/lib/webby/core_ext/time.rb +9 -0
  114. data/lib/webby/filters/basepath.rb +97 -0
  115. data/lib/webby/filters/erb.rb +9 -0
  116. data/lib/webby/filters/haml.rb +18 -0
  117. data/lib/webby/filters/markdown.rb +16 -0
  118. data/lib/webby/filters/outline.rb +309 -0
  119. data/lib/webby/filters/sass.rb +17 -0
  120. data/lib/webby/filters/slides.rb +56 -0
  121. data/lib/webby/filters/textile.rb +16 -0
  122. data/lib/webby/filters/tidy.rb +76 -0
  123. data/lib/webby/filters.rb +91 -0
  124. data/lib/webby/helpers/capture_helper.rb +141 -0
  125. data/lib/webby/helpers/coderay_helper.rb +69 -0
  126. data/lib/webby/helpers/graphviz_helper.rb +136 -0
  127. data/lib/webby/helpers/tag_helper.rb +65 -0
  128. data/lib/webby/helpers/tex_img_helper.rb +133 -0
  129. data/lib/webby/helpers/ultraviolet_helper.rb +63 -0
  130. data/lib/webby/helpers/url_helper.rb +235 -0
  131. data/lib/webby/helpers.rb +30 -0
  132. data/lib/webby/link_validator.rb +152 -0
  133. data/lib/webby/renderer.rb +379 -0
  134. data/lib/webby/resources/db.rb +251 -0
  135. data/lib/webby/resources/file.rb +221 -0
  136. data/lib/webby/resources/layout.rb +63 -0
  137. data/lib/webby/resources/page.rb +118 -0
  138. data/lib/webby/resources/partial.rb +79 -0
  139. data/lib/webby/resources/resource.rb +160 -0
  140. data/lib/webby/resources/static.rb +52 -0
  141. data/lib/webby/resources.rb +96 -0
  142. data/lib/webby/stelan/mktemp.rb +135 -0
  143. data/lib/webby/stelan/paginator.rb +150 -0
  144. data/lib/webby/stelan/spawner.rb +339 -0
  145. data/lib/webby/tasks/build.rake +27 -0
  146. data/lib/webby/tasks/create.rake +22 -0
  147. data/lib/webby/tasks/deploy.rake +22 -0
  148. data/lib/webby/tasks/growl.rake +15 -0
  149. data/lib/webby/tasks/heel.rake +28 -0
  150. data/lib/webby/tasks/validate.rake +19 -0
  151. data/lib/webby.rb +227 -0
  152. data/spec/core_ext/hash_spec.rb +47 -0
  153. data/spec/core_ext/string_spec.rb +110 -0
  154. data/spec/core_ext/time_spec.rb +19 -0
  155. data/spec/spec.opts +1 -0
  156. data/spec/spec_helper.rb +14 -0
  157. data/spec/webby/apps/generator_spec.rb +111 -0
  158. data/spec/webby/apps/main_spec.rb +75 -0
  159. data/spec/webby/helpers/capture_helper_spec.rb +56 -0
  160. data/spec/webby/resources/file_spec.rb +104 -0
  161. data/spec/webby/resources_spec.rb +17 -0
  162. data/tasks/ann.rake +81 -0
  163. data/tasks/bones.rake +21 -0
  164. data/tasks/gem.rake +126 -0
  165. data/tasks/git.rake +41 -0
  166. data/tasks/manifest.rake +49 -0
  167. data/tasks/notes.rake +28 -0
  168. data/tasks/post_load.rake +39 -0
  169. data/tasks/rdoc.rake +51 -0
  170. data/tasks/rubyforge.rake +57 -0
  171. data/tasks/setup.rb +268 -0
  172. data/tasks/spec.rake +55 -0
  173. data/tasks/website.rake +38 -0
  174. metadata +289 -0
@@ -0,0 +1,309 @@
1
+ require 'hpricot'
2
+
3
+ module Webby
4
+ module Filters
5
+
6
+ # The Outline filter is used to insert outline numbering into HTML heading
7
+ # tags (h1, h2, h3, etc.) and to generate a table of contents based on the
8
+ # heading tags. The table of contents is inserted into the page at the
9
+ # location of the <toc /> tag. If there is no <toc /> tag, then a table of
10
+ # contents will not be created but outline numbering will still take place.
11
+ #
12
+ # If a table of contents is desired without outline number being inserted
13
+ # into the heading tags, this can be specified in the attibutes of the
14
+ # <toc /> tag itself.
15
+ #
16
+ # <toc numbering="off" />
17
+ #
18
+ # This will generate a table of contents, but not insert outline numbering
19
+ # into the heading tags.
20
+ #
21
+ # The Outline filter will only work on valid HTML or XHTML pages. Therefore
22
+ # it should be used after any markup langauge filters (textile, markdown,
23
+ # etc.).
24
+ #
25
+ # The following attributes can be specified in the <toc /> tag itself to
26
+ # control how outline numbering is performed by the filter. The attributes
27
+ # can be used in combination with one another.
28
+ #
29
+ # === numbering
30
+ #
31
+ # If set to "off", this will prevent numbers from being inserted into the
32
+ # page. The default is "on".
33
+ #
34
+ # <toc numbering="off" />
35
+ #
36
+ # === numbering_start
37
+ #
38
+ # This is the number to start with when inserting outline numbers into a
39
+ # page. The default is 1.
40
+ #
41
+ # <toc numbering_start="3" />
42
+ #
43
+ # === toc_style
44
+ #
45
+ # The style of the Table of Contents list to generated. This will be
46
+ # either "ol" for an ordered list or "ul" for an unordered list. The
47
+ # default is an ordered list.
48
+ #
49
+ # <toc toc_style="ul" />
50
+ #
51
+ # === toc_range
52
+ #
53
+ # This limits the numbering to only a subset of the HTML heading tags. The
54
+ # defaul is to number all the heading tags.
55
+ #
56
+ # <toc toc_range="h1-h3" />
57
+ #
58
+ # In this example, only the heading tags h1, h2, and h3 will be numbered
59
+ # and included in the table of contents listing.
60
+ #
61
+ # ==== Example
62
+ #
63
+ # Generate a table of contents using an unordered list, starting with the
64
+ # number 2, and only numbering heading levels 2, 3, and 4.
65
+ #
66
+ # <toc numbering_start="2" toc_style="ul" toc_range="h2-h4" />
67
+ #
68
+ class Outline
69
+ include ERB::Util
70
+
71
+ # call-seq:
72
+ # Outline.new( html )
73
+ #
74
+ # Creates a new outline filter that will operate on the given
75
+ # _html_ string.
76
+ #
77
+ def initialize( str )
78
+ @str = str
79
+
80
+ @cur_level, @base_level, @cur_depth = nil
81
+ @level = [0] * 6
82
+ @h_rgxp = %r/^h(\d)$/o
83
+
84
+ @numbering = true
85
+ @numbering_start = 1
86
+
87
+ @toc = []
88
+ @toc_style = 'ol'
89
+ @toc_range = 'h1-h6'
90
+ @list_opening = nil
91
+ end
92
+
93
+ # call-seq:
94
+ # filter => html
95
+ #
96
+ # Process the original html document passed to the filter when it was
97
+ # created. The document will be scanned for heading tags (h1, h2, etc.)
98
+ # and outline numbering and id attributes will be inserted. A table of
99
+ # contents will also be created and inserted into the page if a <toc />
100
+ # tag is found.
101
+ #
102
+ # For example, if there is a heading tag
103
+ #
104
+ # <h3>Get Fuzzy</h3>
105
+ #
106
+ # somewhere in a page about comic strips, the tag might be altered as such
107
+ #
108
+ # <h3 id="h2_2_1"><span class="heading-num">2.2.1</span>Get Fuzzy</h3>
109
+ #
110
+ # The id attribute is used to generate a linke from the table of contents
111
+ # to this particular heading tag. The original text of the tag is used in
112
+ # the table of contents -- "Get Fuzzy" in this example.
113
+ #
114
+ def filter
115
+ doc = Hpricot.XML(@str)
116
+
117
+ # extract directives from the "toc" tag
118
+ toc_elem = doc.search('toc').first
119
+
120
+ unless toc_elem.nil?
121
+ @numbering = toc_elem['numbering'] !~ %r/off/i
122
+ @numbering_start = Integer(toc_elem['numbering_start']) if toc_elem.has_attribute? 'numbering_start'
123
+ @toc_style = toc_elem['toc_style'] if toc_elem.has_attribute? 'toc_style'
124
+ @toc_range = toc_elem['toc_range'] if toc_elem.has_attribute? 'toc_range'
125
+ end
126
+
127
+ unless %w[ul ol].include? @toc_style
128
+ raise ArgumentError, "unknown ToC list type '#{@toc_style}'"
129
+ end
130
+
131
+ m = %r/h(\d)\s*-\s*h(\d)/i.match @toc_range
132
+ @toc_range = Integer(m[1])..Integer(m[2])
133
+ @list_opening = build_list_opening(toc_elem)
134
+
135
+ headers = @toc_range.map {|x| "h#{x}"}
136
+ doc.traverse_element(*headers) do |elem|
137
+ text, id = heading_info(elem)
138
+ add_to_toc(text, id) if @toc_range.include? current_level
139
+ end
140
+
141
+ toc_elem.swap(toc) unless toc_elem.nil?
142
+ doc.to_html
143
+ end
144
+
145
+
146
+ private
147
+
148
+ def build_list_opening( elem )
149
+ lo = "<#{@toc_style}"
150
+ unless elem.nil?
151
+ %w[class style id].each do |atr|
152
+ next unless elem.has_attribute? atr
153
+ lo << " %s=\"%s\"" % [atr, elem[atr]]
154
+ end
155
+ end
156
+ if @toc_style == 'ol' and @numbering_start != 1
157
+ lo << " start=\"#{@numbering_start}\""
158
+ end
159
+ lo << ">"
160
+ end
161
+
162
+ # Returns information for the given heading element. The information is
163
+ # returned as a two element array: [text, id].
164
+ #
165
+ # This method will also insert outline numbering and an id attribute. The
166
+ # outline numbering can be disabled, but the id attribute must be present
167
+ # for TOC generation.
168
+ #
169
+ def heading_info( elem )
170
+ m = @h_rgxp.match(elem.name)
171
+ level = Integer(m[1])
172
+
173
+ self.current_level = level
174
+ text = elem.inner_text
175
+
176
+ lbl = label
177
+ if numbering?
178
+ elem.children.first.before {tag!(:span, lbl, :class => 'heading-num')}
179
+ end
180
+ elem['id'] = "h#{lbl.tr('.','_')}" if elem['id'].nil?
181
+
182
+ return [text, elem['id']]
183
+ end
184
+
185
+ # Set the current heading level. This will set the label and depth as
186
+ # well. An error will be raised if the _level_ is less than the base
187
+ # heading level.
188
+ #
189
+ # The base heading level will be set to the _level_ if it has not already
190
+ # been set. Therefore, the first heading tag encountered defines the base
191
+ # heading level.
192
+ #
193
+ def current_level=( level )
194
+ if @base_level.nil?
195
+ @base_level = @cur_level = level
196
+ @level[@base_level-1] = @numbering_start-1
197
+ end
198
+
199
+ if level < @base_level
200
+ raise ::Webby::Error, "heading tags are not in order, cannot outline"
201
+ end
202
+
203
+ if level == @cur_level
204
+ @level[level-1] += 1
205
+ elsif level > @cur_level
206
+ @cur_level.upto(level-1) {|ii| @level[ii] += 1}
207
+ else
208
+ @cur_level.downto(level+1) {|ii| @level[ii-1] = 0}
209
+ @level[level-1] += 1
210
+ end
211
+
212
+ @cur_level = level
213
+ end
214
+
215
+ # Returns the current heading level number.
216
+ #
217
+ def current_level
218
+ @cur_level
219
+ end
220
+
221
+ # Return the label string for the current heading level.
222
+ #
223
+ def label
224
+ rv = @level.dup
225
+ rv.delete(0)
226
+ rv.join('.')
227
+ end
228
+
229
+ # Return the nesting depth of the current heading level with respect to the
230
+ # base heading level. This is a one-based number.
231
+ #
232
+ def depth
233
+ @cur_level - @base_level + 1
234
+ end
235
+
236
+ # Add the given text and id reference to the table of contents.
237
+ #
238
+ def add_to_toc( text, id )
239
+ a = "<a href=\"##{id}\">#{h(text)}</a>"
240
+ @toc << [depth, a]
241
+ end
242
+
243
+ # Returns the table of contents as a collection of nested ordered lists.
244
+ # This is fully formatted HTML.
245
+ #
246
+ def toc
247
+ ary = []
248
+
249
+ lopen = "<#@toc_style>"
250
+ lclose = "</#@toc_style>"
251
+ prev_depth = open = 0
252
+
253
+ @toc.each do |a|
254
+ cur = a.first
255
+
256
+ # close out the previous list item if we're at the same level
257
+ if cur == prev_depth
258
+ ary << "</li>"
259
+
260
+ # if we are increasing the level, then start a new list
261
+ elsif cur > prev_depth
262
+ ary << if ary.empty? then @list_opening else lopen end
263
+ open += 1
264
+
265
+ # we are decreasing the level; close out tags but ensure we don't
266
+ # close out all the tags (leave one open)
267
+ else
268
+ (prev_depth - cur).times {
269
+ ary << "</li>" << lclose
270
+ open -= 1
271
+ break if open <= 0
272
+ }
273
+ if open > 0
274
+ ary << "</li>"
275
+ else
276
+ ary << lopen
277
+ open += 1
278
+ end
279
+ end
280
+
281
+ # add the current element
282
+ ary << "<li>" << a.last
283
+ prev_depth = cur
284
+ end
285
+
286
+ # close out the remaingling tags
287
+ ary << "</li>" << lclose
288
+ ary.join("\n")
289
+ end
290
+
291
+ # Returns +true+ if outline numbering should be inserted into the heading
292
+ # tags. Returns +false+ otherwise.
293
+ #
294
+ def numbering?
295
+ @numbering
296
+ end
297
+ end # class Outline
298
+
299
+ # Generate a outline numbering and/or a table of contents in the input HTML
300
+ # text.
301
+ #
302
+ register :outline do |input|
303
+ Outline.new(input).filter
304
+ end
305
+
306
+ end # module Filters
307
+ end # module Webby
308
+
309
+ # EOF
@@ -0,0 +1,17 @@
1
+
2
+ # Render text via the Sass library (part of Haml)
3
+ if try_require('sass', 'haml')
4
+
5
+ Webby::Filters.register :sass do |input, cursor|
6
+ opts = ::Webby.site.sass_options.merge(cursor.page.sass_options || {})
7
+ Sass::Engine.new(input, opts).render
8
+ end
9
+
10
+ # Otherwise raise an error if the user tries to use sass
11
+ else
12
+ Webby::Filters.register :sass do |input, cursor|
13
+ raise Webby::Error, "'haml' must be installed to use the sass filter"
14
+ end
15
+ end
16
+
17
+ # EOF
@@ -0,0 +1,56 @@
1
+ module Webby
2
+ module Filters
3
+
4
+ # The Slides filter is used to generate an S5 presentation from HTML input
5
+ # text. The input HTML is scanned for <h1> tags and slide divs are inserted
6
+ # before each <h1> tag found.
7
+ #
8
+ # When the HTML is rendered into the presentation layout, the result is an
9
+ # S5 presentation -- provided that the layout includes the appropriate S5
10
+ # javascript and CSS files.
11
+ #
12
+ class Slides
13
+
14
+ START_SLIDE = %{<div class="slide">#$/}
15
+ END_SLIDE = %{</div>#$/#$/}
16
+
17
+ # call-seq:
18
+ # Slides.new( html )
19
+ #
20
+ # Creates a new slides filter that will operate on the given
21
+ # _html_ string.
22
+ #
23
+ def initialize( str )
24
+ @str = str
25
+ @open = false
26
+ end
27
+
28
+ # call-seq:
29
+ # filter => html
30
+ #
31
+ # Process the original html document passed to the filter when it was
32
+ # created. The document will be scanned for H1 heading tags and slide
33
+ # divs will be inserted into the page before each H1 tag that is found.
34
+ #
35
+ def filter
36
+ result = []
37
+
38
+ @str.split(%r/\<h1\>/i).each do |slide|
39
+ next if slide.strip.empty?
40
+ result << START_SLIDE << '<h1>' << slide << END_SLIDE
41
+ end
42
+
43
+ result.join
44
+ end
45
+ end # class Slides
46
+
47
+ # Insert slide divs into the input HTML text.
48
+ #
49
+ register :slides do |input|
50
+ Slides.new(input).filter
51
+ end
52
+
53
+ end # module Filters
54
+ end # module Webby
55
+
56
+ # EOF
@@ -0,0 +1,16 @@
1
+
2
+ # If RedCloth is installed, then configure the textile filter
3
+ if try_require('redcloth', 'RedCloth')
4
+
5
+ Webby::Filters.register :textile do |input|
6
+ RedCloth.new(input, %w(no_span_caps)).to_html
7
+ end
8
+
9
+ # Otherwise raise an error if the user tries to use textile
10
+ else
11
+ Webby::Filters.register :textile do |input|
12
+ raise Webby::Error, "'RedCloth' must be installed to use the textile filter"
13
+ end
14
+ end
15
+
16
+ # EOF
@@ -0,0 +1,76 @@
1
+ require 'fileutils'
2
+ require 'tempfile'
3
+
4
+ module Webby
5
+ module Filters
6
+
7
+ # The Tidy filter is used to process HTML (or XHTML) through the _tidy_
8
+ # program and outpu nicely formatted and correct HTML (or XHTML).
9
+ #
10
+ # Options can be passed to the _tidy_ program via the
11
+ # <code>Webby.site</code> struct. Setting the +tidy_options+ to the string
12
+ # of desired options will do the trick.
13
+ #
14
+ # From a project's Rakefile, include the following line (or one that's more
15
+ # to your liking):
16
+ #
17
+ # SITE.tidy_options = "-indent -wrap 80 -utf8"
18
+ #
19
+ class Tidy
20
+
21
+ # call-seq:
22
+ # Tidy.new( html )
23
+ #
24
+ # Create a new filter that will process the given _html_ through the tidy
25
+ # program.
26
+ #
27
+ def initialize( str )
28
+ @log = ::Logging::Logger[self]
29
+ @str = str
30
+
31
+ # create a temporary file for holding any error messages
32
+ # from the tidy program
33
+ @err = Tempfile.new('tidy_err')
34
+ @err.close
35
+ end
36
+
37
+ # call-seq:
38
+ # process => formatted html
39
+ #
40
+ # Process the original HTML text string passed to the filter when it was
41
+ # created and output Tidy formatted HTML or XHTML.
42
+ #
43
+ def process
44
+ cmd = "tidy %s -q -f #{@err.path}" % ::Webby.site.tidy_options
45
+ out = IO.popen(cmd, 'r+') do |tidy|
46
+ tidy.write @str
47
+ tidy.close_write
48
+ tidy.read
49
+ end
50
+
51
+ if File.size(@err.path) != 0
52
+ @log.warn File.read(@err.path).strip
53
+ end
54
+
55
+ return out
56
+ end
57
+
58
+ end # class Tidy
59
+
60
+ # Render html into html/xhtml via the Tidy program
61
+ if cmd_available? %w[tidy -v]
62
+ register :tidy do |input|
63
+ Filters::Tidy.new(input).process
64
+ end
65
+
66
+ # Otherwise raise an error if the user tries to use tidy
67
+ else
68
+ register :tidy do |input|
69
+ raise Webby::Error, "'tidy' must be installed to use the tidy filter"
70
+ end
71
+ end
72
+
73
+ end # module Filters
74
+ end # module Webby
75
+
76
+ # EOF
@@ -0,0 +1,91 @@
1
+ module Webby
2
+ module Filters
3
+
4
+ class << self
5
+
6
+ # Register a handler for a filter
7
+ def register( filter, &block )
8
+ handlers[filter.to_s] = block
9
+ end
10
+
11
+ # Process input through filters
12
+ def process( renderer, page, input )
13
+ # Start a new cursor for this page
14
+ Cursor.new(renderer, page).start_for(input)
15
+ end
16
+
17
+ # Access a filter handler
18
+ def []( name )
19
+ handlers[name]
20
+ end
21
+
22
+ #######
23
+ private
24
+ #######
25
+
26
+ # The registered filter handlers
27
+ def handlers
28
+ @handlers ||= {}
29
+ end
30
+
31
+ # Instances of this class handle processing a set of filters
32
+ # for a given renderer and page.
33
+ # Note: The instance is passed as the second argument to filters
34
+ # that require two parameters and can be used to access
35
+ # information on the renderer, page, or filters being
36
+ # processed.
37
+ class Cursor
38
+
39
+ attr_reader :renderer, :page, :filters
40
+ def initialize(renderer, page)
41
+ @renderer, @page = renderer, page
42
+ @filters = Array(page.filter)
43
+ @log = Logging::Logger[Webby::Renderer]
44
+ @processed = 0
45
+ @prev_cursor = nil
46
+ end
47
+
48
+ def start_for(input)
49
+ @prev_cursor = @renderer.instance_variable_get(:@_cursor)
50
+ @renderer.instance_variable_set(:@_cursor, self)
51
+ filters.inject(input) do |result, filter|
52
+ handler = Filters[filter]
53
+ raise ::Webby::Error, "unknown filter: #{filter.inspect}" if handler.nil?
54
+
55
+ args = [result, self][0, handler.arity]
56
+ handle(filter, handler, *args)
57
+ end
58
+ ensure
59
+ @renderer.instance_variable_set(:@_cursor, @prev_cursor)
60
+ end
61
+
62
+ # The list of filters yet to be processed
63
+ def remaining_filters
64
+ filters[@processed..-1]
65
+ end
66
+
67
+ # The name of the current filter
68
+ def current_filter
69
+ filters[@processed]
70
+ end
71
+
72
+ #######
73
+ private
74
+ #######
75
+
76
+ # Process arguments through a single filter
77
+ def handle(filter, handler, *args)
78
+ result = handler.call(*args)
79
+ @processed += 1
80
+ result
81
+ end
82
+
83
+ end # class Cursor
84
+ end # class << self
85
+
86
+ end # module Filters
87
+ end # module Webby
88
+
89
+ Webby.require_all_libs_relative_to(__FILE__)
90
+
91
+ # EOF
@@ -0,0 +1,141 @@
1
+
2
+ module Webby::Helpers
3
+
4
+ # Based on code from Rails and Merb.
5
+ #
6
+ module CaptureHelper
7
+
8
+ # Called in pages and partials to store up content for later use. Takes a
9
+ # string and/or a block. First, the string is evaluated, and then the
10
+ # block is captured using the capture() helper provided by the template
11
+ # languages. The two are concatenated together.
12
+ #
13
+ # Content is retrieved by calling the method without a string or a block.
14
+ #
15
+ # ==== Parameters
16
+ # obj<Object>:: The key in the conetnt_for hash.
17
+ # string<String>:: Textual content. Defaults to nil.
18
+ # &block:: A block to be evaluated and concatenated to string.
19
+ #
20
+ # ==== Returns
21
+ # Any content associated with the key (or nil).
22
+ #
23
+ # ==== Example
24
+ # content_for(:foo, "Foo")
25
+ # content_for(:foo) #=> "Foo"
26
+ # content_for(:foo, "Bar")
27
+ # content_for(:foo) #=> "FooBar"
28
+ #
29
+ def content_for( obj, string = nil, &block )
30
+ return @_content_for[obj] unless string || block_given?
31
+
32
+ cur = @_content_for[obj].to_s
33
+ new = string.to_s + (block_given? ? capture_erb(&block) : "")
34
+ @_content_for[obj] = cur + new
35
+ end
36
+
37
+ # Returns true if there is content for the given key. Otherwise returns
38
+ # false.
39
+ #
40
+ # ==== Parameters
41
+ # obj<Object>:: The key in the conetnt_for hash.
42
+ #
43
+ # ==== Example
44
+ # content_for(:foo, "Foo")
45
+ # content_for?(:foo) #=> true
46
+ # content_for?(:bar) #=> false
47
+ #
48
+ def content_for?( obj )
49
+ @_content_for.key?(obj)
50
+ end
51
+
52
+ # Deletes any content associated with the given object in the content_for
53
+ # hash.
54
+ #
55
+ # ==== Parameters
56
+ # obj<Object>:: The key in the conetnt_for hash.
57
+ #
58
+ # ==== Returns
59
+ # Any content associated with the key (or nil).
60
+ #
61
+ # ==== Example
62
+ # content_for(:foo, "Foo")
63
+ # content_for?(:foo) #=> true
64
+ # delete_content_for(:foo)
65
+ # content_for?(:foo) #=> false
66
+ #
67
+ def delete_content_for( obj )
68
+ @_content_for.delete(obj)
69
+ end
70
+
71
+ # This method is used to capture content from an ERB filter evaluation. It
72
+ # is useful to helpers that need to process chunks of data during ERB filter
73
+ # processing.
74
+ #
75
+ # ==== Parameters
76
+ # *args:: Arguments to pass to the block.
77
+ # &block:: The ERB block to call.
78
+ #
79
+ # ==== Returns
80
+ # String:: The output of the block.
81
+ #
82
+ # ==== Examples
83
+ # Capture being used in an ERB page:
84
+ #
85
+ # <% @foo = capture_erb do %>
86
+ # <p>Some Foo content!</p>
87
+ # <% end %>
88
+ #
89
+ def capture_erb( *args, &block )
90
+ # get the buffer from the block's binding
91
+ buffer = _erb_buffer(block.binding) rescue nil
92
+
93
+ # If there is no buffer, just call the block and get the contents
94
+ if buffer.nil?
95
+ block.call(*args)
96
+ # If there is a buffer, execute the block, then extract its contents
97
+ else
98
+ pos = buffer.length
99
+ block.call(*args)
100
+
101
+ # extract the block
102
+ data = buffer[pos..-1]
103
+
104
+ # replace it in the original with empty string
105
+ buffer[pos..-1] = ""
106
+
107
+ data
108
+ end
109
+ end
110
+
111
+ # This method is used to concatenate content into the ERB output buffer.
112
+ # It is usefule to helpers that need to insert transformed text back into
113
+ # the ERB output buffer.
114
+ #
115
+ # ==== Parameters
116
+ # string<String>:: The string to insert into the ERB output.
117
+ # the_binding<Binding>:: The binding to pass to the buffer.
118
+ #
119
+ def concat_erb( string, the_binding )
120
+ _erb_buffer(the_binding) << string
121
+ end
122
+
123
+ # Provides direct acccess to the ERB buffer in the conext of the binding.
124
+ #
125
+ # ==== Parameters
126
+ # the_binding<Binding>:: The binding to pass to the buffer.
127
+ #
128
+ # ==== Returns
129
+ # The current ERB output buffer.
130
+ #
131
+ def _erb_buffer( the_binding )
132
+ eval("_erbout", the_binding, __FILE__, __LINE__)
133
+ end
134
+
135
+ end # module CaptureHelper
136
+
137
+ register(CaptureHelper)
138
+
139
+ end # module Webby::Helpers
140
+
141
+ # EOF