nanoc 3.2.4 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. data/.gemtest +0 -0
  2. data/ChangeLog +3 -0
  3. data/Gemfile +32 -0
  4. data/LICENSE +19 -0
  5. data/NEWS.md +470 -0
  6. data/README.md +114 -0
  7. data/Rakefile +14 -0
  8. data/bin/nanoc +7 -27
  9. data/bin/nanoc3 +3 -0
  10. data/doc/yardoc_templates/default/layout/html/footer.erb +10 -0
  11. data/lib/nanoc.rb +41 -0
  12. data/lib/nanoc/base.rb +49 -0
  13. data/lib/nanoc/base/compilation/checksum_store.rb +57 -0
  14. data/lib/nanoc/base/compilation/compiled_content_cache.rb +62 -0
  15. data/lib/nanoc/base/compilation/compiler.rb +458 -0
  16. data/lib/nanoc/base/compilation/compiler_dsl.rb +214 -0
  17. data/lib/nanoc/base/compilation/dependency_tracker.rb +200 -0
  18. data/lib/nanoc/base/compilation/filter.rb +165 -0
  19. data/lib/nanoc/base/compilation/item_rep_proxy.rb +103 -0
  20. data/lib/nanoc/base/compilation/item_rep_recorder_proxy.rb +102 -0
  21. data/lib/nanoc/base/compilation/outdatedness_checker.rb +223 -0
  22. data/lib/nanoc/base/compilation/outdatedness_reasons.rb +46 -0
  23. data/lib/nanoc/base/compilation/rule.rb +73 -0
  24. data/lib/nanoc/base/compilation/rule_context.rb +84 -0
  25. data/lib/nanoc/base/compilation/rule_memory_calculator.rb +40 -0
  26. data/lib/nanoc/base/compilation/rule_memory_store.rb +53 -0
  27. data/lib/nanoc/base/compilation/rules_collection.rb +243 -0
  28. data/lib/nanoc/base/context.rb +47 -0
  29. data/lib/nanoc/base/core_ext.rb +6 -0
  30. data/lib/nanoc/base/core_ext/array.rb +62 -0
  31. data/lib/nanoc/base/core_ext/hash.rb +63 -0
  32. data/lib/nanoc/base/core_ext/pathname.rb +26 -0
  33. data/lib/nanoc/base/core_ext/string.rb +46 -0
  34. data/lib/nanoc/base/directed_graph.rb +275 -0
  35. data/lib/nanoc/base/errors.rb +211 -0
  36. data/lib/nanoc/base/memoization.rb +67 -0
  37. data/lib/nanoc/base/notification_center.rb +84 -0
  38. data/lib/nanoc/base/ordered_hash.rb +200 -0
  39. data/lib/nanoc/base/plugin_registry.rb +181 -0
  40. data/lib/nanoc/base/result_data/item_rep.rb +492 -0
  41. data/lib/nanoc/base/source_data/code_snippet.rb +58 -0
  42. data/lib/nanoc/base/source_data/configuration.rb +24 -0
  43. data/lib/nanoc/base/source_data/data_source.rb +234 -0
  44. data/lib/nanoc/base/source_data/item.rb +301 -0
  45. data/lib/nanoc/base/source_data/layout.rb +130 -0
  46. data/lib/nanoc/base/source_data/site.rb +361 -0
  47. data/lib/nanoc/base/store.rb +135 -0
  48. data/lib/nanoc/cli.rb +137 -0
  49. data/lib/nanoc/cli/command_runner.rb +104 -0
  50. data/lib/nanoc/cli/commands/autocompile.rb +58 -0
  51. data/lib/nanoc/cli/commands/compile.rb +297 -0
  52. data/lib/nanoc/cli/commands/create_item.rb +60 -0
  53. data/lib/nanoc/cli/commands/create_layout.rb +73 -0
  54. data/lib/nanoc/cli/commands/create_site.rb +411 -0
  55. data/lib/nanoc/cli/commands/debug.rb +117 -0
  56. data/lib/nanoc/cli/commands/deploy.rb +79 -0
  57. data/lib/nanoc/cli/commands/info.rb +98 -0
  58. data/lib/nanoc/cli/commands/nanoc.rb +38 -0
  59. data/lib/nanoc/cli/commands/prune.rb +50 -0
  60. data/lib/nanoc/cli/commands/update.rb +70 -0
  61. data/lib/nanoc/cli/commands/view.rb +82 -0
  62. data/lib/nanoc/cli/commands/watch.rb +124 -0
  63. data/lib/nanoc/cli/error_handler.rb +199 -0
  64. data/lib/nanoc/cli/logger.rb +92 -0
  65. data/lib/nanoc/data_sources.rb +29 -0
  66. data/lib/nanoc/data_sources/deprecated/delicious.rb +42 -0
  67. data/lib/nanoc/data_sources/deprecated/last_fm.rb +87 -0
  68. data/lib/nanoc/data_sources/deprecated/twitter.rb +38 -0
  69. data/lib/nanoc/data_sources/filesystem.rb +299 -0
  70. data/lib/nanoc/data_sources/filesystem_unified.rb +121 -0
  71. data/lib/nanoc/data_sources/filesystem_verbose.rb +91 -0
  72. data/lib/nanoc/extra.rb +24 -0
  73. data/lib/nanoc/extra/auto_compiler.rb +103 -0
  74. data/lib/nanoc/extra/chick.rb +125 -0
  75. data/lib/nanoc/extra/core_ext.rb +6 -0
  76. data/lib/nanoc/extra/core_ext/enumerable.rb +33 -0
  77. data/lib/nanoc/extra/core_ext/pathname.rb +30 -0
  78. data/lib/nanoc/extra/core_ext/time.rb +19 -0
  79. data/lib/nanoc/extra/deployer.rb +47 -0
  80. data/lib/nanoc/extra/deployers.rb +15 -0
  81. data/lib/nanoc/extra/deployers/fog.rb +98 -0
  82. data/lib/nanoc/extra/deployers/rsync.rb +70 -0
  83. data/lib/nanoc/extra/file_proxy.rb +40 -0
  84. data/lib/nanoc/extra/pruner.rb +86 -0
  85. data/lib/nanoc/extra/validators.rb +12 -0
  86. data/lib/nanoc/extra/validators/links.rb +268 -0
  87. data/lib/nanoc/extra/validators/w3c.rb +95 -0
  88. data/lib/nanoc/extra/vcs.rb +66 -0
  89. data/lib/nanoc/extra/vcses.rb +17 -0
  90. data/lib/nanoc/extra/vcses/bazaar.rb +25 -0
  91. data/lib/nanoc/extra/vcses/dummy.rb +24 -0
  92. data/lib/nanoc/extra/vcses/git.rb +25 -0
  93. data/lib/nanoc/extra/vcses/mercurial.rb +25 -0
  94. data/lib/nanoc/extra/vcses/subversion.rb +25 -0
  95. data/lib/nanoc/filters.rb +59 -0
  96. data/lib/nanoc/filters/asciidoc.rb +38 -0
  97. data/lib/nanoc/filters/bluecloth.rb +19 -0
  98. data/lib/nanoc/filters/coderay.rb +21 -0
  99. data/lib/nanoc/filters/coffeescript.rb +20 -0
  100. data/lib/nanoc/filters/colorize_syntax.rb +298 -0
  101. data/lib/nanoc/filters/erb.rb +38 -0
  102. data/lib/nanoc/filters/erubis.rb +34 -0
  103. data/lib/nanoc/filters/haml.rb +27 -0
  104. data/lib/nanoc/filters/kramdown.rb +20 -0
  105. data/lib/nanoc/filters/less.rb +53 -0
  106. data/lib/nanoc/filters/markaby.rb +20 -0
  107. data/lib/nanoc/filters/maruku.rb +20 -0
  108. data/lib/nanoc/filters/mustache.rb +24 -0
  109. data/lib/nanoc/filters/rainpress.rb +19 -0
  110. data/lib/nanoc/filters/rdiscount.rb +22 -0
  111. data/lib/nanoc/filters/rdoc.rb +33 -0
  112. data/lib/nanoc/filters/redcarpet.rb +62 -0
  113. data/lib/nanoc/filters/redcloth.rb +47 -0
  114. data/lib/nanoc/filters/relativize_paths.rb +94 -0
  115. data/lib/nanoc/filters/rubypants.rb +20 -0
  116. data/lib/nanoc/filters/sass.rb +74 -0
  117. data/lib/nanoc/filters/slim.rb +25 -0
  118. data/lib/nanoc/filters/typogruby.rb +23 -0
  119. data/lib/nanoc/filters/uglify_js.rb +42 -0
  120. data/lib/nanoc/filters/xsl.rb +46 -0
  121. data/lib/nanoc/filters/yui_compressor.rb +23 -0
  122. data/lib/nanoc/helpers.rb +16 -0
  123. data/lib/nanoc/helpers/blogging.rb +319 -0
  124. data/lib/nanoc/helpers/breadcrumbs.rb +40 -0
  125. data/lib/nanoc/helpers/capturing.rb +138 -0
  126. data/lib/nanoc/helpers/filtering.rb +50 -0
  127. data/lib/nanoc/helpers/html_escape.rb +55 -0
  128. data/lib/nanoc/helpers/link_to.rb +151 -0
  129. data/lib/nanoc/helpers/rendering.rb +140 -0
  130. data/lib/nanoc/helpers/tagging.rb +71 -0
  131. data/lib/nanoc/helpers/text.rb +44 -0
  132. data/lib/nanoc/helpers/xml_sitemap.rb +76 -0
  133. data/lib/nanoc/tasks.rb +10 -0
  134. data/lib/nanoc/tasks/clean.rake +16 -0
  135. data/lib/nanoc/tasks/clean.rb +29 -0
  136. data/lib/nanoc/tasks/deploy/rsync.rake +16 -0
  137. data/lib/nanoc/tasks/validate.rake +92 -0
  138. data/nanoc.gemspec +49 -0
  139. data/tasks/doc.rake +16 -0
  140. data/tasks/test.rake +46 -0
  141. data/test/base/core_ext/array_spec.rb +73 -0
  142. data/test/base/core_ext/hash_spec.rb +98 -0
  143. data/test/base/core_ext/pathname_spec.rb +27 -0
  144. data/test/base/core_ext/string_spec.rb +37 -0
  145. data/test/base/test_checksum_store.rb +35 -0
  146. data/test/base/test_code_snippet.rb +31 -0
  147. data/test/base/test_compiler.rb +403 -0
  148. data/test/base/test_compiler_dsl.rb +161 -0
  149. data/test/base/test_context.rb +31 -0
  150. data/test/base/test_data_source.rb +46 -0
  151. data/test/base/test_dependency_tracker.rb +262 -0
  152. data/test/base/test_directed_graph.rb +288 -0
  153. data/test/base/test_filter.rb +83 -0
  154. data/test/base/test_item.rb +179 -0
  155. data/test/base/test_item_rep.rb +579 -0
  156. data/test/base/test_layout.rb +59 -0
  157. data/test/base/test_memoization.rb +90 -0
  158. data/test/base/test_notification_center.rb +34 -0
  159. data/test/base/test_outdatedness_checker.rb +394 -0
  160. data/test/base/test_plugin.rb +30 -0
  161. data/test/base/test_rule.rb +19 -0
  162. data/test/base/test_rule_context.rb +65 -0
  163. data/test/base/test_site.rb +190 -0
  164. data/test/cli/commands/test_compile.rb +33 -0
  165. data/test/cli/commands/test_create_item.rb +14 -0
  166. data/test/cli/commands/test_create_layout.rb +28 -0
  167. data/test/cli/commands/test_create_site.rb +24 -0
  168. data/test/cli/commands/test_deploy.rb +74 -0
  169. data/test/cli/commands/test_help.rb +12 -0
  170. data/test/cli/commands/test_info.rb +11 -0
  171. data/test/cli/commands/test_prune.rb +98 -0
  172. data/test/cli/commands/test_update.rb +10 -0
  173. data/test/cli/test_cli.rb +102 -0
  174. data/test/cli/test_error_handler.rb +29 -0
  175. data/test/cli/test_logger.rb +10 -0
  176. data/test/data_sources/test_filesystem.rb +433 -0
  177. data/test/data_sources/test_filesystem_unified.rb +536 -0
  178. data/test/data_sources/test_filesystem_verbose.rb +357 -0
  179. data/test/extra/core_ext/test_enumerable.rb +30 -0
  180. data/test/extra/core_ext/test_pathname.rb +17 -0
  181. data/test/extra/core_ext/test_time.rb +15 -0
  182. data/test/extra/deployers/test_fog.rb +67 -0
  183. data/test/extra/deployers/test_rsync.rb +100 -0
  184. data/test/extra/test_auto_compiler.rb +417 -0
  185. data/test/extra/test_file_proxy.rb +19 -0
  186. data/test/extra/test_vcs.rb +22 -0
  187. data/test/extra/validators/test_links.rb +62 -0
  188. data/test/extra/validators/test_w3c.rb +47 -0
  189. data/test/filters/test_asciidoc.rb +22 -0
  190. data/test/filters/test_bluecloth.rb +18 -0
  191. data/test/filters/test_coderay.rb +44 -0
  192. data/test/filters/test_coffeescript.rb +18 -0
  193. data/test/filters/test_colorize_syntax.rb +379 -0
  194. data/test/filters/test_erb.rb +105 -0
  195. data/test/filters/test_erubis.rb +78 -0
  196. data/test/filters/test_haml.rb +96 -0
  197. data/test/filters/test_kramdown.rb +18 -0
  198. data/test/filters/test_less.rb +113 -0
  199. data/test/filters/test_markaby.rb +24 -0
  200. data/test/filters/test_maruku.rb +18 -0
  201. data/test/filters/test_mustache.rb +25 -0
  202. data/test/filters/test_rainpress.rb +29 -0
  203. data/test/filters/test_rdiscount.rb +31 -0
  204. data/test/filters/test_rdoc.rb +18 -0
  205. data/test/filters/test_redcarpet.rb +73 -0
  206. data/test/filters/test_redcloth.rb +33 -0
  207. data/test/filters/test_relativize_paths.rb +533 -0
  208. data/test/filters/test_rubypants.rb +18 -0
  209. data/test/filters/test_sass.rb +229 -0
  210. data/test/filters/test_slim.rb +35 -0
  211. data/test/filters/test_typogruby.rb +21 -0
  212. data/test/filters/test_uglify_js.rb +30 -0
  213. data/test/filters/test_xsl.rb +105 -0
  214. data/test/filters/test_yui_compressor.rb +44 -0
  215. data/test/gem_loader.rb +11 -0
  216. data/test/helper.rb +207 -0
  217. data/test/helpers/test_blogging.rb +754 -0
  218. data/test/helpers/test_breadcrumbs.rb +81 -0
  219. data/test/helpers/test_capturing.rb +41 -0
  220. data/test/helpers/test_filtering.rb +106 -0
  221. data/test/helpers/test_html_escape.rb +32 -0
  222. data/test/helpers/test_link_to.rb +249 -0
  223. data/test/helpers/test_rendering.rb +89 -0
  224. data/test/helpers/test_tagging.rb +87 -0
  225. data/test/helpers/test_text.rb +24 -0
  226. data/test/helpers/test_xml_sitemap.rb +103 -0
  227. data/test/tasks/test_clean.rb +67 -0
  228. metadata +327 -15
  229. data/bin/nanoc-select +0 -86
  230. data/lib/nanoc-select.rb +0 -11
@@ -0,0 +1,12 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc::Extra
4
+
5
+ module Validators
6
+
7
+ autoload 'W3C', 'nanoc/extra/validators/w3c'
8
+ autoload 'Links', 'nanoc/extra/validators/links'
9
+
10
+ end
11
+
12
+ end
@@ -0,0 +1,268 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc::Extra::Validators
4
+
5
+ # A validator that verifies that all links (`<a href="…">…</a>`) point to a
6
+ # location that exists.
7
+ class Links
8
+
9
+ # @param [String] dir The directory that will be searched for HTML files
10
+ # to validate
11
+ #
12
+ # @param [Array<String>] index_filenames An array of index filenames that
13
+ # will be appended to URLs by web servers if a directory is requested
14
+ # instead of a file
15
+ #
16
+ # @option params [Boolean] :internal (false) True if internal links should
17
+ # be checked; false if they should not
18
+ #
19
+ # @option params [Boolean] :external (false) True if external links should
20
+ # be checked; false if they should not
21
+ def initialize(dir, index_filenames, params={})
22
+ @dir = dir
23
+ @index_filenames = index_filenames
24
+ @include_internal = params.has_key?(:internal) && params[:internal]
25
+ @include_external = params.has_key?(:external) && params[:external]
26
+ end
27
+
28
+ # Starts the validator. The results will be printed to stdout.
29
+ #
30
+ # @return [void]
31
+ def run
32
+ require 'nokogiri'
33
+
34
+ @delegate = self
35
+ links = all_broken_hrefs
36
+ if links.empty?
37
+ puts "No broken links found!"
38
+ else
39
+ links.each_pair do |href, origins|
40
+ puts "Broken link: #{href} -- referenced from:"
41
+ origins.each do |origin|
42
+ puts " #{origin}"
43
+ end
44
+ puts
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ # Enumerates all key-value pairs of a given hash in a thread-safe way.
52
+ #
53
+ # @api private
54
+ class ThreadsafeHashEnumerator
55
+
56
+ # Creates a new enumerator for the given hash.
57
+ #
58
+ # @param [Hash] hash The hash for which the enumerator should return
59
+ # key-value pairs
60
+ def initialize(hash)
61
+ @hash = hash
62
+ @unprocessed_keys = @hash.keys.dup
63
+ @mutex = Mutex.new
64
+ end
65
+
66
+ # Returns the next key-value pair in the hash.
67
+ #
68
+ # @return [Array] An array containing the key and the corresponding
69
+ # value of teh next key-value pair
70
+ def next_pair
71
+ @mutex.synchronize do
72
+ key = @unprocessed_keys.shift
73
+ return (key ? [ key, @hash[key] ] : nil)
74
+ end
75
+ end
76
+
77
+ end
78
+
79
+ def all_broken_hrefs
80
+ broken_hrefs = {}
81
+
82
+ internal_hrefs = {}
83
+ external_hrefs = {}
84
+
85
+ # Split into internal and external hrefs
86
+ all_hrefs_per_filename.each_pair do |filename, hrefs|
87
+ hrefs.each do |href|
88
+ if is_external_href?(href)
89
+ external_hrefs[href] ||= []
90
+ external_hrefs[href] << filename
91
+ else
92
+ internal_hrefs[href] ||= []
93
+ internal_hrefs[href] << filename
94
+ end
95
+ end
96
+ end
97
+
98
+ # Validate hrefs
99
+ validate_internal_hrefs(internal_hrefs, broken_hrefs) if @include_internal
100
+ validate_external_hrefs(external_hrefs, broken_hrefs) if @include_external
101
+
102
+ # Done
103
+ broken_hrefs
104
+ end
105
+
106
+ def all_files
107
+ Dir[@dir + '/**/*.html']
108
+ end
109
+
110
+ def all_hrefs_per_filename
111
+ hrefs = {}
112
+ all_files.each do |filename|
113
+ hrefs[filename] ||= all_hrefs_in_file(filename)
114
+ end
115
+ hrefs
116
+ end
117
+
118
+ def all_hrefs_in_file(filename)
119
+ doc = Nokogiri::HTML(::File.read(filename))
120
+ doc.css('a').map { |l| l[:href] }.compact
121
+ end
122
+
123
+ def is_external_href?(href)
124
+ !!(href =~ %r{^[a-z\-]+:})
125
+ end
126
+
127
+ def is_valid_internal_href?(href, origin)
128
+ # Skip hrefs that point to self
129
+ # FIXME this is ugly and won’t always be correct
130
+ return true if href == '.'
131
+
132
+ # Remove target
133
+ path = href.sub(/#.*$/, '')
134
+ return true if path.empty?
135
+
136
+ # Make absolute
137
+ if path[0, 1] == '/'
138
+ path = @dir + path
139
+ else
140
+ path = ::File.expand_path(path, ::File.dirname(origin))
141
+ end
142
+
143
+ # Check whether file exists
144
+ return true if File.file?(path)
145
+
146
+ # Check whether directory with index file exists
147
+ return true if File.directory?(path) && @index_filenames.any? { |fn| File.file?(File.join(path, fn)) }
148
+
149
+ # Nope :(
150
+ return false
151
+ end
152
+
153
+ def is_valid_external_href?(href)
154
+ require 'net/http'
155
+ require 'uri'
156
+
157
+ # Parse
158
+ uri = nil
159
+ begin
160
+ uri = URI.parse(href)
161
+ rescue URI::InvalidURIError
162
+ @delegate && @delegate.send(:external_href_validated, href, false)
163
+ return false
164
+ end
165
+
166
+ # Skip non-HTTP URLs
167
+ return true if uri.scheme !~ /^https?$/
168
+
169
+ # Get status
170
+ status = fetch_http_status_for(uri)
171
+ is_valid = !!(status && status >= 200 && status <= 299)
172
+
173
+ # Notify
174
+ @delegate && @delegate.send(:external_href_validated, href, is_valid)
175
+
176
+ # Done
177
+ is_valid
178
+ end
179
+
180
+ def validate_internal_hrefs(hrefs, broken_hrefs)
181
+ hrefs.each_pair do |href, filenames|
182
+ filenames.each do |filename|
183
+ if !is_valid_internal_href?(href, filename)
184
+ broken_hrefs[href] = filenames
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ def validate_external_hrefs(hrefs, broken_hrefs)
191
+ @mutex = Mutex.new
192
+
193
+ enum = ThreadsafeHashEnumerator.new(hrefs)
194
+
195
+ threads = []
196
+ 10.times do
197
+ threads << Thread.new do
198
+ loop do
199
+ # Get next pair
200
+ pair = enum.next_pair
201
+ break if pair.nil?
202
+ href, filenames = pair[0], pair[1]
203
+
204
+ # Validate
205
+ if !is_valid_external_href?(href)
206
+ @mutex.synchronize do
207
+ broken_hrefs[href] = filenames
208
+ end
209
+ end
210
+ end
211
+ end
212
+ end
213
+ threads.each { |t| t.join }
214
+ end
215
+
216
+ def fetch_http_status_for(url, params={})
217
+ 5.times do |i|
218
+ begin
219
+ res = nil
220
+ Timeout::timeout(10) do
221
+ res = request_url_once(url)
222
+ end
223
+
224
+ if res.code =~ /^3..$/
225
+ url = URI.parse(res['location'])
226
+ return nil if i == 5
227
+ else
228
+ return res.code.to_i
229
+ end
230
+ rescue
231
+ return nil
232
+ end
233
+ end
234
+ end
235
+
236
+ def request_url_once(url)
237
+ require 'net/https'
238
+
239
+ path = (url.path.nil? || url.path.empty? ? '/' : url.path)
240
+ req = Net::HTTP::Head.new(path)
241
+ http=Net::HTTP.new(url.host, url.port)
242
+ if url.instance_of? URI::HTTPS
243
+ http.use_ssl = true
244
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
245
+ end
246
+ res = http.request(req)
247
+ end
248
+
249
+ def external_href_validated(href, is_valid)
250
+ texts = {
251
+ true => 'ok',
252
+ false => ' ERROR '
253
+ }
254
+
255
+ colors = {
256
+ true => "\e[32m",
257
+ false => "\e[41m\e[37m",
258
+ :off => "\033[0m"
259
+ }
260
+
261
+ @mutex.synchronize do
262
+ puts href + ': ' + colors[is_valid] + texts[is_valid] + colors[:off]
263
+ end
264
+ end
265
+
266
+ end
267
+
268
+ end
@@ -0,0 +1,95 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc::Extra::Validators
4
+
5
+ # A validator that uses the W3C web service to validate HTML and CSS files.
6
+ class W3C
7
+
8
+ # @param [String] dir The directory that will be searched for HTML and/or
9
+ # CSS files to validate
10
+ #
11
+ # @param [Array<Symbol>] types A list of types to check. Allowed types are
12
+ # `:html` and `:css`.
13
+ def initialize(dir, types)
14
+ @dir = dir
15
+ @types = types
16
+ end
17
+
18
+ # Starts the validator. The results will be printed to stdout.
19
+ #
20
+ # @return [void]
21
+ def run
22
+ # Load validator
23
+ require 'w3c_validators'
24
+
25
+ # Find all files
26
+ filenames = []
27
+ extensions = types_to_extensions(@types)
28
+ extensions.each { |extension| filenames.concat(Dir[@dir + '/**/*.' + extension]) }
29
+
30
+ # Validate each file
31
+ filenames.each do |filename|
32
+ validation_started(filename)
33
+
34
+ extension = File.extname(filename)[1..-1]
35
+ results = validator_for(extension).validate_file(filename)
36
+
37
+ validation_ended(filename, results.errors)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # Returns all extensions for the given types
44
+ def types_to_extensions(types)
45
+ extensions = []
46
+ types.each { |type| extensions.concat(type_to_extensions(type)) }
47
+ extensions
48
+ end
49
+
50
+ # Returns all extensions for the given type
51
+ def type_to_extensions(type)
52
+ case type
53
+ when :html
54
+ [ 'html', 'htm' ]
55
+ when :css
56
+ [ 'css' ]
57
+ else
58
+ raise RuntimeError, "unknown type: #{type}"
59
+ end
60
+ end
61
+
62
+ # Returns the validator class for the given extension
63
+ def validator_class_for(extension)
64
+ case extension
65
+ when 'html', 'htm'
66
+ ::W3CValidators::MarkupValidator
67
+ when 'css'
68
+ ::W3CValidators::CSSValidator
69
+ else
70
+ raise RuntimeError, "unknown extension: #{extension}"
71
+ end
72
+ end
73
+
74
+ # Returns the validator for the given extension
75
+ def validator_for(extension)
76
+ @validators ||= {}
77
+ @validators[extension] ||= validator_class_for(extension).new
78
+ end
79
+
80
+ def validation_started(file)
81
+ $stdout.print "Validating #{file}... "
82
+ $stdout.flush
83
+ end
84
+
85
+ def validation_ended(file, errors)
86
+ $stdout.puts(errors.empty? ? "valid" : "INVALID")
87
+
88
+ errors.each do |err|
89
+ puts " #{err}"
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc::Extra
4
+
5
+ # A very simple representation of a version control system (VCS) that
6
+ # abstracts the add, remove and move operations. It does not commit. This
7
+ # class is primarily used by data sources that store data as flat files on
8
+ # the disk.
9
+ #
10
+ # @abstract Subclass and override {#add}, {#remove} and {#move} to implement
11
+ # a custom VCS.
12
+ class VCS
13
+
14
+ extend Nanoc::PluginRegistry::PluginMethods
15
+
16
+ # Adds the file with the given filename to the working copy.
17
+ #
18
+ # @param [String] filename The name of the file to add
19
+ #
20
+ # @return [void]
21
+ #
22
+ # @abstract
23
+ def add(filename)
24
+ not_implemented('add')
25
+ end
26
+
27
+ # Removes the file with the given filename from the working copy. When
28
+ # this method is executed, the file should no longer be present on the
29
+ # disk.
30
+ #
31
+ # @param [String] filename The name of the file to remove
32
+ #
33
+ # @return [void]
34
+ #
35
+ # @abstract
36
+ def remove(filename)
37
+ not_implemented('remove')
38
+ end
39
+
40
+ # Moves the file with the given filename to a new location. When this
41
+ # method is executed, the original file should no longer be present on the
42
+ # disk.
43
+ #
44
+ # @param [String] src The old filename
45
+ #
46
+ # @param [String] dst The new filename
47
+ #
48
+ # @return [void]
49
+ #
50
+ # @abstract
51
+ def move(src, dst)
52
+ not_implemented('move')
53
+ end
54
+
55
+ private
56
+
57
+ def not_implemented(name)
58
+ raise NotImplementedError.new(
59
+ "#{self.class} does not override ##{name}, which is required for " +
60
+ "this data source to be used."
61
+ )
62
+ end
63
+
64
+ end
65
+
66
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc::Extra::VCSes
4
+
5
+ autoload 'Bazaar', 'nanoc/extra/vcses/bazaar'
6
+ autoload 'Dummy', 'nanoc/extra/vcses/dummy'
7
+ autoload 'Git', 'nanoc/extra/vcses/git'
8
+ autoload 'Mercurial', 'nanoc/extra/vcses/mercurial'
9
+ autoload 'Subversion', 'nanoc/extra/vcses/subversion'
10
+
11
+ Nanoc::Extra::VCS.register '::Nanoc::Extra::VCSes::Bazaar', :bazaar, :bzr
12
+ Nanoc::Extra::VCS.register '::Nanoc::Extra::VCSes::Dummy', :dummy
13
+ Nanoc::Extra::VCS.register '::Nanoc::Extra::VCSes::Git', :git
14
+ Nanoc::Extra::VCS.register '::Nanoc::Extra::VCSes::Mercurial', :mercurial, :hg
15
+ Nanoc::Extra::VCS.register '::Nanoc::Extra::VCSes::Subversion', :subversion, :svn
16
+
17
+ end