webby 0.8.4 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (165) hide show
  1. data/History.txt +19 -0
  2. data/Manifest.txt +104 -91
  3. data/README.txt +27 -45
  4. data/Rakefile +4 -5
  5. data/bin/webby +2 -1
  6. data/bin/webby-gen +8 -0
  7. data/{data/Rakefile → examples/blog/Sitefile} +0 -2
  8. data/examples/{webby → blog}/tasks/blog.rake +5 -4
  9. data/{data → examples/blog}/templates/atom_feed.erb +10 -11
  10. data/{data → examples/blog}/templates/blog/month.erb +1 -1
  11. data/{data → examples/blog}/templates/blog/post.erb +1 -0
  12. data/{data → examples/blog}/templates/blog/year.erb +1 -1
  13. data/examples/presentation/{Rakefile → Sitefile} +0 -4
  14. data/examples/presentation/content/{_sample_code.txt → presentation/_sample_code.txt} +0 -0
  15. data/examples/presentation/content/{index.txt → presentation/index.txt} +0 -0
  16. data/{data/content → examples/presentation/content/presentation}/s5/blank.gif +0 -0
  17. data/{data/content → examples/presentation/content/presentation}/s5/bodybg.gif +0 -0
  18. data/{data/content → examples/presentation/content/presentation}/s5/framing.css +0 -0
  19. data/{data/content → examples/presentation/content/presentation}/s5/iepngfix.htc +0 -0
  20. data/{data/content → examples/presentation/content/presentation}/s5/opera.css +0 -0
  21. data/{data/content → examples/presentation/content/presentation}/s5/outline.css +0 -0
  22. data/{data/content → examples/presentation/content/presentation}/s5/pretty.css +0 -0
  23. data/{data/content → examples/presentation/content/presentation}/s5/print.css +0 -0
  24. data/{data/content → examples/presentation/content/presentation}/s5/s5-core.css +0 -0
  25. data/{data/content → examples/presentation/content/presentation}/s5/slides.css +0 -0
  26. data/{data/content → examples/presentation/content/presentation}/s5/slides.js +0 -0
  27. data/examples/presentation/layouts/{presentation.rhtml → presentation.txt} +3 -3
  28. data/examples/presentation/templates/{_partial.erb → _code_partial.erb} +0 -0
  29. data/examples/tumblog/Sitefile +9 -0
  30. data/examples/tumblog/content/css/tumblog.css +308 -0
  31. data/examples/tumblog/content/images/tumblog/permalink.gif +0 -0
  32. data/examples/tumblog/content/images/tumblog/rss.gif +0 -0
  33. data/examples/tumblog/content/tumblog/200806/the-noble-chicken/index.txt +12 -0
  34. data/examples/tumblog/content/tumblog/200807/historical-perspectives-on-the-classic-chicken-joke/index.txt +12 -0
  35. data/examples/tumblog/content/tumblog/200807/mad-city-chickens/index.txt +10 -0
  36. data/examples/tumblog/content/tumblog/200807/the-wisdom-of-the-dutch/index.txt +11 -0
  37. data/examples/tumblog/content/tumblog/200807/up-a-tree/index.txt +13 -0
  38. data/examples/tumblog/content/tumblog/index.txt +37 -0
  39. data/examples/tumblog/content/tumblog/rss.txt +37 -0
  40. data/examples/tumblog/layouts/tumblog/default.txt +44 -0
  41. data/examples/tumblog/layouts/tumblog/post.txt +15 -0
  42. data/examples/tumblog/lib/tumblog_helper.rb +32 -0
  43. data/examples/tumblog/tasks/tumblog.rake +30 -0
  44. data/examples/tumblog/templates/atom_feed.erb +40 -0
  45. data/examples/tumblog/templates/tumblog/conversation.erb +12 -0
  46. data/examples/tumblog/templates/tumblog/link.erb +10 -0
  47. data/examples/tumblog/templates/tumblog/photo.erb +13 -0
  48. data/examples/tumblog/templates/tumblog/post.erb +12 -0
  49. data/examples/tumblog/templates/tumblog/quote.erb +11 -0
  50. data/examples/webby/{Rakefile → Sitefile} +2 -2
  51. data/examples/webby/content/communicate/index.txt +28 -0
  52. data/examples/webby/content/css/background.gif +0 -0
  53. data/examples/webby/content/css/site.css +52 -20
  54. data/examples/webby/content/index.txt +7 -8
  55. data/examples/webby/content/learn/index.txt +28 -0
  56. data/examples/webby/content/reference/index.txt +3 -1
  57. data/examples/webby/content/release-notes/rel-0-9-0/index.txt +73 -0
  58. data/examples/webby/content/sitemap.txt +31 -0
  59. data/examples/webby/content/tips_and_tricks/index.txt +1 -1
  60. data/examples/webby/content/tutorial/index.txt +17 -17
  61. data/examples/webby/content/{manual → user-manual}/index.txt +53 -50
  62. data/examples/webby/layouts/{default.rhtml → default.txt} +8 -15
  63. data/examples/webby/templates/page.erb +1 -1
  64. data/examples/website/Sitefile +7 -0
  65. data/{data → examples/website}/content/css/blueprint/License.txt +0 -0
  66. data/{data → examples/website}/content/css/blueprint/Readme.txt +0 -0
  67. data/{data → examples/website}/content/css/blueprint/compressed/print.css +0 -0
  68. data/{data → examples/website}/content/css/blueprint/compressed/screen.css +0 -0
  69. data/{data → examples/website}/content/css/blueprint/lib/forms.css +0 -0
  70. data/{data → examples/website}/content/css/blueprint/lib/grid.css +0 -0
  71. data/{data → examples/website}/content/css/blueprint/lib/grid.png +0 -0
  72. data/{data → examples/website}/content/css/blueprint/lib/ie.css +0 -0
  73. data/{data → examples/website}/content/css/blueprint/lib/reset.css +0 -0
  74. data/{data → examples/website}/content/css/blueprint/lib/typography.css +0 -0
  75. data/{data → examples/website}/content/css/blueprint/plugins/buttons/Readme +0 -0
  76. data/{data → examples/website}/content/css/blueprint/plugins/buttons/buttons.css +0 -0
  77. data/{data → examples/website}/content/css/blueprint/plugins/buttons/icons/cross.png +0 -0
  78. data/{data → examples/website}/content/css/blueprint/plugins/buttons/icons/key.png +0 -0
  79. data/{data → examples/website}/content/css/blueprint/plugins/buttons/icons/tick.png +0 -0
  80. data/{data → examples/website}/content/css/blueprint/plugins/css-classes/Readme +0 -0
  81. data/{data → examples/website}/content/css/blueprint/plugins/css-classes/css-classes.css +0 -0
  82. data/{data → examples/website}/content/css/blueprint/plugins/fancy-type/Readme +0 -0
  83. data/{data → examples/website}/content/css/blueprint/plugins/fancy-type/fancy-type-compressed.css +0 -0
  84. data/{data → examples/website}/content/css/blueprint/plugins/fancy-type/fancy-type.css +0 -0
  85. data/{data → examples/website}/content/css/blueprint/print.css +0 -0
  86. data/{data → examples/website}/content/css/blueprint/screen.css +0 -0
  87. data/{data → examples/website}/content/css/coderay.css +0 -0
  88. data/{data → examples/website}/content/css/site.css +0 -0
  89. data/{data → examples/website}/content/index.txt +2 -1
  90. data/{data/layouts/default.rhtml → examples/website/layouts/default.txt} +1 -1
  91. data/{data → examples/website}/lib/breadcrumbs.rb +0 -0
  92. data/{data → examples/website}/templates/_partial.erb +0 -0
  93. data/{data → examples/website}/templates/page.erb +0 -0
  94. data/{data → examples/website}/templates/presentation.erb +0 -0
  95. data/lib/webby/apps/generator.rb +283 -0
  96. data/lib/webby/apps/main.rb +221 -0
  97. data/lib/webby/apps.rb +12 -0
  98. data/lib/webby/builder.rb +8 -10
  99. data/lib/webby/core_ext/enumerable.rb +11 -0
  100. data/lib/webby/{utils.rb → core_ext/hash.rb} +2 -26
  101. data/lib/webby/core_ext/kernel.rb +21 -0
  102. data/lib/webby/core_ext/string.rb +163 -0
  103. data/lib/webby/core_ext/time.rb +9 -0
  104. data/lib/webby/filters/haml.rb +13 -5
  105. data/lib/webby/filters/markdown.rb +12 -4
  106. data/lib/webby/filters/outline.rb +3 -2
  107. data/lib/webby/filters/sass.rb +12 -4
  108. data/lib/webby/filters/textile.rb +12 -4
  109. data/lib/webby/filters/tidy.rb +10 -8
  110. data/lib/webby/filters.rb +2 -0
  111. data/lib/webby/helpers/graphviz_helper.rb +1 -2
  112. data/lib/webby/helpers/tex_img_helper.rb +6 -10
  113. data/lib/webby/renderer.rb +5 -3
  114. data/lib/webby/resources/layout.rb +1 -1
  115. data/lib/webby/resources/page.rb +1 -1
  116. data/lib/webby/resources/resource.rb +13 -3
  117. data/lib/webby/resources.rb +16 -0
  118. data/{data → lib/webby}/tasks/build.rake +0 -0
  119. data/{examples/presentation → lib/webby}/tasks/create.rake +1 -1
  120. data/{data → lib/webby}/tasks/deploy.rake +0 -0
  121. data/{examples → lib}/webby/tasks/growl.rake +4 -1
  122. data/{data → lib/webby}/tasks/heel.rake +0 -0
  123. data/{data → lib/webby}/tasks/validate.rake +0 -0
  124. data/lib/webby.rb +11 -5
  125. data/spec/core_ext/hash_spec.rb +47 -0
  126. data/spec/core_ext/string_spec.rb +110 -0
  127. data/spec/core_ext/time_spec.rb +19 -0
  128. data/spec/webby/apps/generator_spec.rb +111 -0
  129. data/spec/webby/apps/main_spec.rb +75 -0
  130. data/spec/webby/helpers/capture_helper_spec.rb +1 -1
  131. data/spec/webby/resources_spec.rb +17 -0
  132. data/tasks/gem.rake +10 -2
  133. data/tasks/git.rake +41 -0
  134. data/tasks/rubyforge.rake +2 -2
  135. data/tasks/website.rake +38 -38
  136. metadata +125 -98
  137. data/data/tasks/blog.rake +0 -71
  138. data/data/tasks/create.rake +0 -22
  139. data/data/tasks/growl.rake +0 -12
  140. data/data/tasks/setup.rb +0 -17
  141. data/examples/presentation/content/s5/blank.gif +0 -0
  142. data/examples/presentation/content/s5/bodybg.gif +0 -0
  143. data/examples/presentation/content/s5/framing.css +0 -23
  144. data/examples/presentation/content/s5/iepngfix.htc +0 -42
  145. data/examples/presentation/content/s5/opera.css +0 -7
  146. data/examples/presentation/content/s5/outline.css +0 -15
  147. data/examples/presentation/content/s5/pretty.css +0 -86
  148. data/examples/presentation/content/s5/print.css +0 -1
  149. data/examples/presentation/content/s5/s5-core.css +0 -9
  150. data/examples/presentation/content/s5/slides.css +0 -3
  151. data/examples/presentation/content/s5/slides.js +0 -553
  152. data/examples/presentation/tasks/blog.rake +0 -71
  153. data/examples/presentation/tasks/build.rake +0 -27
  154. data/examples/presentation/tasks/deploy.rake +0 -22
  155. data/examples/presentation/tasks/growl.rake +0 -12
  156. data/examples/presentation/tasks/heel.rake +0 -28
  157. data/examples/presentation/tasks/setup.rb +0 -17
  158. data/examples/presentation/tasks/validate.rake +0 -19
  159. data/examples/webby/tasks/build.rake +0 -27
  160. data/examples/webby/tasks/create.rake +0 -22
  161. data/examples/webby/tasks/deploy.rake +0 -22
  162. data/examples/webby/tasks/heel.rake +0 -28
  163. data/examples/webby/tasks/setup.rb +0 -17
  164. data/examples/webby/tasks/validate.rake +0 -19
  165. data/lib/webby/main.rb +0 -227
@@ -0,0 +1,221 @@
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
+ # Create a new Main webby object for building websites.
16
+ #
17
+ def initialize
18
+ @stdout = $stdout
19
+ end
20
+
21
+ # Runs the main webby application. The command line arguments are passed
22
+ # in to this method as an array of strings. The command line arguments are
23
+ # parsed to figure out which rake task to invoke.
24
+ #
25
+ def run( args )
26
+ args = args.dup
27
+
28
+ parse args
29
+ init args
30
+ rake
31
+ end
32
+
33
+ # Parse the command line _args_ for options and commands to invoke.
34
+ #
35
+ def parse( args )
36
+ opts = OptionParser.new
37
+ opts.banner = 'Usage: webby [options] target [target args]'
38
+
39
+ opts.separator ''
40
+ opts.on('-D', '--describe [PATTERN]', 'describe the tasks (matching optional PATTERN), then exit') {|pattern| app.do_option('--describe', pattern)}
41
+ opts.on('-P', '--prereqs', 'display the tasks and dependencies, then exit') {app.do_option('--prereqs', nil)}
42
+ opts.on('-T', '--tasks [PATTERN]', 'display the tasks (matching optional PATTERN) with descriptions, then exit') {|pattern| app.do_option('--tasks', pattern)}
43
+ opts.on('-t', '--trace', 'turn on invoke/execute tracing, enable full backtrace') {app.do_option('--trace', nil)}
44
+
45
+ opts.separator ''
46
+ opts.separator 'common options:'
47
+
48
+ opts.on_tail( '-h', '--help', 'show this message' ) do
49
+ @stdout.puts opts
50
+ exit
51
+ end
52
+ opts.on_tail( '--version', 'show version' ) do
53
+ @stdout.puts "Webby #{::Webby::VERSION}"
54
+ exit
55
+ end
56
+
57
+ opts.parse! args
58
+
59
+ ARGV.replace Array(args.shift)
60
+ args.delete_if do |arg|
61
+ if %r/^[A-Z_]+=/ =~ arg
62
+ ARGV << arg
63
+ next true
64
+ end
65
+ false
66
+ end
67
+
68
+ args
69
+ end
70
+
71
+ # Initialize the Rake application object and load the core rake tasks, the
72
+ # site specific rake tasks, and the site specific ruby code. Any extra
73
+ # command line arguments are converted into a page name and directory that
74
+ # might get created (depending upon the task invoked).
75
+ #
76
+ def init( args )
77
+ # Make sure we're in a folder with a Sitefile
78
+ app.do_option('--rakefile', 'Sitefile')
79
+ app.do_option('--nosearch', nil)
80
+ app.do_option('--silent', nil)
81
+
82
+ unless app.have_rakefile
83
+ raise RuntimeError, "Sitefile not found"
84
+ end
85
+
86
+ import_default_tasks
87
+ import_website_tasks
88
+ require_lib_files
89
+ capture_command_line_args(args)
90
+ args
91
+ end
92
+
93
+ # Execute the rake command.
94
+ #
95
+ def rake
96
+ app.init 'webby'
97
+ app.load_rakefile
98
+ app.top_level
99
+ end
100
+
101
+ # Return the Rake application object.
102
+ #
103
+ def app
104
+ Rake.application
105
+ end
106
+
107
+ # Search for the "Sitefile" starting in the current directory and working
108
+ # upwards through the filesystem until the root of the filesystem is
109
+ # reached. If a "Sitefile" is not found, a RuntimeError is raised.
110
+ #
111
+ def find_sitefile
112
+ here = Dir.pwd
113
+ while ! app.have_rakefile
114
+ Dir.chdir("..")
115
+ if Dir.pwd == here || options.nosearch
116
+ fail "No Sitefile found"
117
+ end
118
+ here = Dir.pwd
119
+ end
120
+ end
121
+
122
+ def import_default_tasks
123
+ Dir.glob(::Webby.libpath(%w[webby tasks *.rake])).sort.each {|fn| import fn}
124
+ end
125
+
126
+ def import_website_tasks
127
+ Dir.glob(::File.join(%w[tasks *.rake])).sort.each {|fn| import fn}
128
+ end
129
+
130
+ def require_lib_files
131
+ Dir.glob(::File.join(%w[lib ** *.rb])).sort.each {|fn| require fn}
132
+ end
133
+
134
+ def capture_command_line_args(args)
135
+ args = OpenStruct.new(:raw => args)
136
+
137
+ if args.raw.size > 1
138
+ ::Webby.deprecated "multiple arguments used for page title",
139
+ "please quote the page title"
140
+ end
141
+
142
+ dashed = args.raw.join('-').downcase
143
+ spaced = args.raw.join(' ')
144
+ dir = ::File.dirname(dashed)
145
+
146
+ args.dir = ('.' == dir ? '' : dir)
147
+ args.slug = ::Webby::Resources::File.basename(dashed).to_url
148
+ args.title = ::Webby::Resources::File.basename(spaced).titlecase
149
+
150
+ # page should be dir/slug without leading /
151
+ args.page = ::File.join(args.dir, args.slug).gsub(/^\//, '')
152
+
153
+ ::Webby.site.args = args
154
+ Object.const_set(:SITE, Webby.site)
155
+ args
156
+ end
157
+
158
+ end # class Main
159
+ end # module Webby::Apps
160
+
161
+ # :stopdoc:
162
+ # Monkey patches so that rake displays the correct application name in the
163
+ # help messages.
164
+ #
165
+ class Rake::Application
166
+ def display_prerequisites
167
+ tasks.each do |t|
168
+ puts "#{name} #{t.name}"
169
+ t.prerequisites.each { |pre| puts " #{pre}" }
170
+ end
171
+ end
172
+
173
+ def display_tasks_and_comments
174
+ displayable_tasks = tasks.select { |t|
175
+ t.comment && t.name =~ options.show_task_pattern
176
+ }
177
+ if options.full_description
178
+ displayable_tasks.each do |t|
179
+ puts "#{name} #{t.name_with_args}"
180
+ t.full_comment.split("\n").each do |line|
181
+ puts " #{line}"
182
+ end
183
+ puts
184
+ end
185
+ else
186
+ width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
187
+ max_column = 80 - name.size - width - 7
188
+ displayable_tasks.each do |t|
189
+ printf "#{name} %-#{width}s # %s\n",
190
+ t.name_with_args, truncate(t.comment, max_column)
191
+ end
192
+ end
193
+ end
194
+
195
+ # Provide standard execption handling for the given block.
196
+ def standard_exception_handling
197
+ begin
198
+ yield
199
+ rescue SystemExit => ex
200
+ # Exit silently with current status
201
+ exit(ex.status)
202
+ rescue SystemExit, GetoptLong::InvalidOption => ex
203
+ # Exit silently
204
+ exit(1)
205
+ rescue Exception => ex
206
+ # Exit with error message
207
+ $stderr.puts "webby aborted!"
208
+ $stderr.puts ex.message
209
+ if options.trace
210
+ $stderr.puts ex.backtrace.join("\n")
211
+ else
212
+ $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
213
+ $stderr.puts "(See full trace by running task with --trace)"
214
+ end
215
+ exit(1)
216
+ end
217
+ end
218
+ end # class Rake::Application
219
+ # :startdoc:
220
+
221
+ # EOF
data/lib/webby/apps.rb ADDED
@@ -0,0 +1,12 @@
1
+
2
+ module Webby::Apps
3
+
4
+ class << self
5
+ def author() 'Tim Pease'; end
6
+ end
7
+
8
+ end # module Webby::Apps
9
+
10
+ Webby.require_all_libs_relative_to(__FILE__)
11
+
12
+ # EOF
data/lib/webby/builder.rb CHANGED
@@ -69,19 +69,17 @@ class Builder
69
69
  end
70
70
 
71
71
  # call-seq:
72
- # Builder.new_page_info( task ) => [page, title, directory]
72
+ # Builder.new_page_info => [page, title, directory]
73
73
  #
74
- def new_page_info( task )
75
- return @new_page_info if defined? @new_page_info
74
+ def new_page_info
75
+ args = Webby.site.args
76
76
 
77
- raise "Usage: rake #{ARGV.first} path" unless ARGV.length > 1
78
- page = task.application.top_level_tasks.slice!(1..-1).join('-')
79
- title = ::Webby::Resources::File.basename(page).
80
- split('-').map {|w| w.capitalize}.join(' ')
81
- dir = ::File.dirname(page)
82
- dir = '' if dir == '.'
77
+ if args.raw.empty?
78
+ task_name = Rake.application.top_level_tasks.first
79
+ raise "Usage: webby #{task_name} path"
80
+ end
83
81
 
84
- @new_page_info = [page, title, dir]
82
+ [args.page, args.title, args.dir]
85
83
  end
86
84
 
87
85
 
@@ -0,0 +1,11 @@
1
+
2
+ module Enumerable
3
+
4
+ def injecting( initial )
5
+ inject(initial) do |memo, obj|
6
+ yield(memo, obj); memo
7
+ end
8
+ end
9
+ end # module Enumerable
10
+
11
+ # EOF
@@ -1,13 +1,6 @@
1
- # :stopdoc:
2
- module Enumerable
3
- def injecting( initial )
4
- inject(initial) do |memo, obj|
5
- yield(memo, obj); memo
6
- end
7
- end
8
- end
9
1
 
10
2
  class Hash
3
+
11
4
  def sanitize!
12
5
  h = self.injecting({}) do |h, (k, v)|
13
6
  h[k] = case v
@@ -30,23 +23,6 @@ class Hash
30
23
  self.each {|k,v| h[k.to_sym] = v}
31
24
  return h
32
25
  end
33
- end
34
-
35
- class String
36
- def underscore
37
- self.
38
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
39
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
40
- tr(" -", "__").
41
- downcase
42
- end
43
- end
44
-
45
- class Time
46
- def to_y
47
- self.to_yaml.slice(4..-1).strip
48
- end
49
- end
50
- # :startdoc:
26
+ end # class Hash
51
27
 
52
28
  # EOF
@@ -0,0 +1,21 @@
1
+
2
+ module Kernel
3
+
4
+ # :stopdoc:
5
+ WINDOWS = %r/djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM
6
+ DEV_NULL = WINDOWS ? 'NUL:' : '/dev/null'
7
+ # :startdoc:
8
+
9
+ def cmd_available?( *args )
10
+ io = [STDOUT.dup, STDERR.dup]
11
+ STDOUT.reopen DEV_NULL
12
+ STDERR.reopen DEV_NULL
13
+ system(*(args.flatten))
14
+ ensure
15
+ STDOUT.reopen io.first
16
+ STDERR.reopen io.last
17
+ $stdout, $stderr = STDOUT, STDERR
18
+ end
19
+ end # module Kernel
20
+
21
+ # EOF
@@ -0,0 +1,163 @@
1
+
2
+ class String
3
+
4
+ def self.small_words
5
+ @small_words ||= %w(a an and as at but by en for if in of on or the to v[.]? via vs[.]?)
6
+ end
7
+
8
+ def /( path )
9
+ ::File.join(self, path)
10
+ end
11
+
12
+ def titlecase
13
+ swrgxp = self.class.small_words.join('|')
14
+
15
+ parts = self.split( %r/( [:.;?!][ ] | (?:[ ]|^)["“] )/x )
16
+ parts.each do |part|
17
+ part.gsub!(%r/\b[[:alpha:]][[:lower:].'’]*\b/) do |s|
18
+ s =~ %r/\w+\.\w+/ ? s : s.capitalize
19
+ end
20
+
21
+ # Lowercase the small words
22
+ part.gsub!(%r/\b(#{swrgxp})\b/i) {|w| w.downcase}
23
+
24
+ # If the first word is a small word, then capitalize it
25
+ part.gsub!(%r/\A([[:punct:]]*)(#{swrgxp})\b/) {$1 + $2.capitalize}
26
+
27
+ # If the last word is a small word, then capitalize it
28
+ part.gsub!(%r/\b(#{swrgxp})([^\w\s]*)\z/) {$1.capitalize + $2}
29
+ end
30
+
31
+ str = parts.join
32
+
33
+ # Special cases:
34
+ str.gsub!(/ V(s?)\. /, ' v\1. ') # "v." and "vs."
35
+ str.gsub!(/(['’])S\b/, '\1s') # 'S (otherwise you get "the SEC'S decision")
36
+ str.gsub!(/\b(AT&T|Q&A)\b/i) { |w| w.upcase } # "AT&T" and "Q&A", which get tripped up.
37
+
38
+ str
39
+ end
40
+
41
+ # Borrowed from the excellent StringEx library: git://github.com/rsl/stringex.git
42
+
43
+ # Create a URI-friendly representation of the string.
44
+ def to_url
45
+ remove_formatting.downcase.replace_whitespace("-").collapse("-")
46
+ end
47
+
48
+ # Performs multiple text manipulations. Essentially a shortcut for typing them all. View source
49
+ # below to see which methods are run.
50
+ def remove_formatting
51
+ strip_html_tags.convert_accented_entities.convert_misc_entities.convert_misc_characters.collapse
52
+ end
53
+
54
+ # Removes HTML tags from text. This code is simplified from Tobias Luettke's regular expression
55
+ # in Typo[http://typosphere.org].
56
+ def strip_html_tags(leave_whitespace = false)
57
+ name = /[\w:_-]+/
58
+ value = /([A-Za-z0-9]+|('[^']*?'|"[^"]*?"))/
59
+ attr = /(#{name}(\s*=\s*#{value})?)/
60
+ rx = /<[!\/?\[]?(#{name}|--)(\s+(#{attr}(\s+#{attr})*))?\s*([!\/?\]]+|--)?>/
61
+ (leave_whitespace) ? gsub(rx, "").strip : gsub(rx, "").gsub(/\s+/, " ").strip
62
+ end
63
+
64
+ # Converts HTML entities into the respective non-accented letters. Examples:
65
+ #
66
+ # "&aacute;".convert_accented_entities # => "a"
67
+ # "&ccedil;".convert_accented_entities # => "c"
68
+ # "&egrave;".convert_accented_entities # => "e"
69
+ # "&icirc;".convert_accented_entities # => "i"
70
+ # "&oslash;".convert_accented_entities # => "o"
71
+ # "&uuml;".convert_accented_entities # => "u"
72
+ #
73
+ # Note: This does not do any conversion of Unicode/Ascii accented-characters. For that
74
+ # functionality please use <tt>to_ascii</tt>.
75
+ def convert_accented_entities
76
+ gsub(/&([A-Za-z])(grave|acute|circ|tilde|uml|ring|cedil|slash);/, '\1')
77
+ end
78
+
79
+ # Converts HTML entities (taken from common Textile/RedCloth formattings) into plain text formats.
80
+ #
81
+ # Note: This isn't an attempt at complete conversion of HTML entities, just those most likely
82
+ # to be generated by Textile.
83
+ def convert_misc_entities
84
+ dummy = dup
85
+ {
86
+ "#822[01]" => "\"",
87
+ "#821[67]" => "'",
88
+ "#8230" => "...",
89
+ "#8211" => "-",
90
+ "#8212" => "--",
91
+ "#215" => "x",
92
+ "gt" => ">",
93
+ "lt" => "<",
94
+ "(#8482|trade)" => "(tm)",
95
+ "(#174|reg)" => "(r)",
96
+ "(#169|copy)" => "(c)",
97
+ "(#38|amp)" => "and",
98
+ "nbsp" => " ",
99
+ "(#162|cent)" => " cent",
100
+ "(#163|pound)" => " pound",
101
+ "(#188|frac14)" => "one fourth",
102
+ "(#189|frac12)" => "half",
103
+ "(#190|frac34)" => "three fourths",
104
+ "(#176|deg)" => " degrees"
105
+ }.each do |textiled, normal|
106
+ dummy.gsub!(/&#{textiled};/, normal)
107
+ end
108
+ dummy.gsub(/&[^;]+;/, "")
109
+ end
110
+
111
+ # Converts various common plaintext characters to a more URI-friendly representation.
112
+ # Examples:
113
+ #
114
+ # "foo & bar".convert_misc_characters # => "foo and bar"
115
+ # "Chanel #9".convert_misc_characters # => "Chanel number nine"
116
+ # "user@host".convert_misc_characters # => "user at host"
117
+ # "google.com".convert_misc_characters # => "google dot com"
118
+ # "$10".convert_misc_characters # => "10 dollars"
119
+ # "*69".convert_misc_characters # => "star 69"
120
+ # "100%".convert_misc_characters # => "100 percent"
121
+ # "windows/mac/linux".convert_misc_characters # => "windows slash mac slash linux"
122
+ #
123
+ # Note: Because this method will convert any & symbols to the string "and",
124
+ # you should run any methods which convert HTML entities (convert_html_entities and convert_misc_entities)
125
+ # before running this method.
126
+ def convert_misc_characters
127
+ dummy = dup.gsub(/\.{3,}/, " dot dot dot ") # Catch ellipses before single dot rule!
128
+ {
129
+ /\s*&\s*/ => "and",
130
+ /\s*#/ => "number",
131
+ /\s*@\s*/ => "at",
132
+ /(\S|^)\.(\S)/ => '\1 dot \2',
133
+ /(\s|^)\$(\d*)(\s|$)/ => '\2 dollars',
134
+ /\s*\*\s*/ => "star",
135
+ /\s*%\s*/ => "percent",
136
+ /\s*(\\|\/)\s*/ => "slash",
137
+ }.each do |found, replaced|
138
+ replaced = " #{replaced} " unless replaced =~ /\\1/
139
+ dummy.gsub!(found, replaced)
140
+ end
141
+ dummy = dummy.gsub(/(^|\w)'(\w|$)/, '\1\2').gsub(/[\.,:;()\[\]\/\?!\^'"_]/, " ")
142
+ end
143
+
144
+ # Replace runs of whitespace in string. Defaults to a single space but any replacement
145
+ # string may be specified as an argument. Examples:
146
+ #
147
+ # "Foo bar".replace_whitespace # => "Foo bar"
148
+ # "Foo bar".replace_whitespace("-") # => "Foo-bar"
149
+ def replace_whitespace(replace = " ")
150
+ gsub(/\s+/, replace)
151
+ end
152
+
153
+ # Removes specified character from the beginning and/or end of the string and then performs
154
+ # <tt>String#squeeze(character)</tt>, condensing runs of the character within the string.
155
+ #
156
+ # Note: This method has been superceded by ActiveSupport's squish method.
157
+ def collapse(character = " ")
158
+ sub(/^#{character}*/, "").sub(/#{character}*$/, "").squeeze(character)
159
+ end
160
+
161
+ end # class String
162
+
163
+ # EOF
@@ -0,0 +1,9 @@
1
+
2
+ class Time
3
+
4
+ def to_y
5
+ self.to_yaml.slice(4..-1).strip
6
+ end
7
+ end # class Time
8
+
9
+ # EOF
@@ -1,10 +1,18 @@
1
- try_require 'haml'
2
1
 
3
2
  # Render text via the Haml library
4
- Webby::Filters.register :haml do |input, cursor|
5
- opts = ::Webby.site.haml_options.merge(cursor.page.haml_options || {})
6
- b = cursor.renderer.get_binding
7
- Haml::Engine.new(input, opts).to_html(b)
3
+ if try_require('haml', 'haml')
4
+
5
+ Webby::Filters.register :haml do |input, cursor|
6
+ opts = ::Webby.site.haml_options.merge(cursor.page.haml_options || {})
7
+ b = cursor.renderer.get_binding
8
+ Haml::Engine.new(input, opts).to_html(b)
9
+ end
10
+
11
+ # Otherwise raise an error if the user tries to use haml
12
+ else
13
+ Webby::Filters.register :haml do |input, cursor|
14
+ raise Webby::Error, "'haml' must be installed to use the haml filter"
15
+ end
8
16
  end
9
17
 
10
18
  # EOF
@@ -1,8 +1,16 @@
1
- try_require 'bluecloth'
2
1
 
3
- # Render text via markdown using the BlueCloth library.
4
- Webby::Filters.register :markdown do |input|
5
- BlueCloth.new(input).to_html
2
+ # Render text via markdown using the RDiscount library.
3
+ if try_require('rdiscount', 'rdiscount')
4
+
5
+ Webby::Filters.register :markdown do |input|
6
+ RDiscount.new(input).to_html
7
+ end
8
+
9
+ # Otherwise raise an error if the user tries to use markdown
10
+ else
11
+ Webby::Filters.register :markdown do |input|
12
+ raise Webby::Error, "'rdiscount' must be installed to use the markdown filter"
13
+ end
6
14
  end
7
15
 
8
16
  # EOF
@@ -112,7 +112,7 @@ class Outline
112
112
  # the table of contents -- "Get Fuzzy" in this example.
113
113
  #
114
114
  def filter
115
- doc = Hpricot(@str)
115
+ doc = Hpricot.XML(@str)
116
116
 
117
117
  # extract directives from the "toc" tag
118
118
  toc_elem = doc.search('toc').first
@@ -132,7 +132,8 @@ class Outline
132
132
  @toc_range = Integer(m[1])..Integer(m[2])
133
133
  @list_opening = build_list_opening(toc_elem)
134
134
 
135
- doc.traverse_element(*%w[h1 h2 h3 h4 h5 h6]) do |elem|
135
+ headers = @toc_range.map {|x| "h#{x}"}
136
+ doc.traverse_element(*headers) do |elem|
136
137
  text, id = heading_info(elem)
137
138
  add_to_toc(text, id) if @toc_range.include? current_level
138
139
  end
@@ -1,9 +1,17 @@
1
- try_require 'sass'
2
1
 
3
2
  # Render text via the Sass library (part of Haml)
4
- Webby::Filters.register :sass do |input, cursor|
5
- opts = ::Webby.site.sass_options.merge(cursor.page.sass_options || {})
6
- Sass::Engine.new(input, opts).render
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
7
15
  end
8
16
 
9
17
  # EOF
@@ -1,8 +1,16 @@
1
- try_require 'redcloth'
2
1
 
3
- # Render text via textile using the RedCloth library.
4
- Webby::Filters.register :textile do |input|
5
- RedCloth.new(input, %w(no_span_caps)).to_html
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
6
14
  end
7
15
 
8
16
  # EOF
@@ -41,11 +41,6 @@ class Tidy
41
41
  # created and output Tidy formatted HTML or XHTML.
42
42
  #
43
43
  def process
44
- %x[tidy -v 2>&1]
45
- unless 0 == $?.exitstatus
46
- raise NameError, "'tidy' not found on the path"
47
- end
48
-
49
44
  cmd = "tidy %s -q -f #{@err.path}" % ::Webby.site.tidy_options
50
45
  out = IO.popen(cmd, 'r+') do |tidy|
51
46
  tidy.write @str
@@ -63,9 +58,16 @@ class Tidy
63
58
  end # class Tidy
64
59
 
65
60
  # Render html into html/xhtml via the Tidy program
66
- #
67
- register :tidy do |input|
68
- Filters::Tidy.new(input).process
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
69
71
  end
70
72
 
71
73
  end # module Filters
data/lib/webby/filters.rb CHANGED
@@ -50,6 +50,8 @@ module Filters
50
50
  @renderer.instance_variable_set(:@_cursor, self)
51
51
  filters.inject(input) do |result, filter|
52
52
  handler = Filters[filter]
53
+ raise ::Webby::Error, "unknown filter: #{filter.inspect}" if handler.nil?
54
+
53
55
  args = [result, self][0, handler.arity]
54
56
  handle(filter, handler, *args)
55
57
  end
@@ -127,8 +127,7 @@ module GraphvizHelper
127
127
  end
128
128
  end # module GraphvizHelper
129
129
 
130
- %x[dot -V 2>&1]
131
- if 0 == $?.exitstatus
130
+ if cmd_available? %w[dot -V]
132
131
  register(GraphvizHelper)
133
132
  end
134
133