nanoc 3.2.4 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
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,114 @@
1
+ # nanoc 3
2
+
3
+ nanoc is a simple but very flexible static site generator written in Ruby.
4
+ It operates on local files, and therefore does not run on the server. nanoc
5
+ “compiles” the local source files into HTML (usually), by evaluating eRuby,
6
+ Markdown, etc.
7
+
8
+ Note: This documentation looks best with Yardoc, not RDoc.
9
+
10
+ ## Resources
11
+
12
+ The [nanoc web site](http://nanoc.stoneship.org) contains a few useful
13
+ resources to help you get started with nanoc. If you need further assistance,
14
+ the following places will help you out:
15
+
16
+ * The [discussion group](http://groups.google.com/group/nanoc)
17
+ * The [IRC channel](irc://chat.freenode.net/#nanoc)
18
+
19
+ ## Source Code Documentation
20
+
21
+ The source code is located in `lib/nanoc` and is structured in a few
22
+ directories:
23
+
24
+ * `base` contains the bare essentials necessary for nanoc to function
25
+ * `source_data` contains raw, uncompiled content that will be compiled
26
+ * `result_data` contains the compiled content
27
+ * `compilation` contains the compilation functionality
28
+ * `cli` contains the commandline interface
29
+ * `data_sources` contains the standard data sources ({Nanoc::DataSource}
30
+ subclasses), such as the filesystem data source
31
+ * `extra` contains stuff that is not needed by nanoc itself, but which may
32
+ be used by helpers, data sources, filters or VCSes.
33
+ * `filters` contains the standard filters ({Nanoc::Filter} subclasses)
34
+ such as ERB, Markdown, Haml, …
35
+ * `helpers` contains helpers, which provide functionality some sites
36
+ may find useful, such as the blogging and tagging helpers
37
+ * `tasks` contains rake tasks that perform a variety of functions such as
38
+ validating HTML and CSS, uploading compiled files, …
39
+
40
+ The namespaces (modules) are organised like this:
41
+
42
+ * {Nanoc} is the namespace for everything nanoc-related (obviously). The
43
+ classes in `lib/nanoc/base` are part of this module (not `Nanoc::Base`)
44
+ * {Nanoc::CLI} containing everything related to the commandline tool.
45
+ * {Nanoc::DataSources} contains the data sources
46
+ * {Nanoc::Helpers} contains the helpers
47
+ * {Nanoc::Extra} contains useful stuff not needed by nanoc itself
48
+ * {Nanoc::Filters} contains the (textual) filters
49
+
50
+ The central class in nanoc is {Nanoc::Site}, so you should start there if
51
+ you want to explore nanoc from a technical perspective.
52
+
53
+ ## Dependencies
54
+
55
+ nanoc has few dependencies. It is possible to use nanoc programmatically
56
+ without any dependencies at all, but if you want to use nanoc in a proper way,
57
+ you’ll likely need some dependencies:
58
+
59
+ * The **commandline frontend** depends on `cri`.
60
+ * The **autocompiler** depends on `mime-types` and `rack`.
61
+ * Filters and helpers likely have dependencies on their own too.
62
+
63
+ If you’re developing for nanoc, such as writing custom filters or helpers, you
64
+ may be interested in the development dependencies:
65
+
66
+ * For **documentation generation** you’ll need `yard`.
67
+ * For **packaging** you’ll need `rubygems` (1.3 or newer).
68
+ * For **testing** you’ll need `mocha` and `minitest`.
69
+
70
+ ## Contributors
71
+
72
+ (In alphabetical order)
73
+
74
+ * Ben Armston
75
+ * Colin Barrett
76
+ * Bil Bas
77
+ * Dmitry Bilunov
78
+ * Fabian Buch
79
+ * Devon Luke Buchanan
80
+ * Stefan Bühler
81
+ * Dan Callahan
82
+ * Brian Candler
83
+ * Jack Chu
84
+ * Michal Cichra
85
+ * Zaiste de Grengolada
86
+ * Vincent Driessen
87
+ * Chris Eppstein
88
+ * Jeff Forcier
89
+ * Riley Goodside
90
+ * Felix Hanley
91
+ * Justin Hileman
92
+ * Starr Horne
93
+ * Tuomas Kareinen
94
+ * Matt Keveney
95
+ * Kevin Lynagh
96
+ * Nikhil Marathe
97
+ * Daniel Mendler
98
+ * Ale Muñoz
99
+ * Nicky Peeters
100
+ * Christian Plessl
101
+ * Šime Ramov
102
+ * Xavier Shay
103
+ * Arnau Siches
104
+ * “Soryu”
105
+ * Eric Sunshine
106
+ * Dennis Sutch
107
+ * Matthias Vallentin
108
+ * Ruben Verborgh
109
+ * Scott Vokes
110
+ * Toon Willems
111
+
112
+ ## Contact
113
+
114
+ You can reach me at <denis.defreyne@stoneship.org>.
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ # Set up env
4
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/lib'))
5
+ require './test/gem_loader.rb'
6
+
7
+ # Load nanoc
8
+ require 'nanoc'
9
+
10
+ # Load tasks
11
+ Dir.glob('tasks/**/*.rake').each { |r| Rake.application.add_import r }
12
+
13
+ # Set default task
14
+ task :default => :test
data/bin/nanoc CHANGED
@@ -1,32 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
3
 
4
- # Find version
5
- version_file_path = File.join(ENV['APPDATA'] || ENV['HOME'], '.nanoc-select-version')
6
- if !File.exist?(version_file_path)
7
- version = 3
8
- else
9
- version = File.read(version_file_path).to_i
10
- end
4
+ # Add lib to load path
5
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
11
6
 
12
- # Determine nanoc executable name
13
- VERSION_MAP = {
14
- 2 => 'nanoc2',
15
- 3 => 'nanoc3'
16
- }
17
- name = VERSION_MAP[version]
18
- if name.nil?
19
- $stderr.puts "Unsupported nanoc version number: #{version}. Supported versions: #{VERSION_MAP.keys.join(', ')}."
20
- exit 1
21
- end
7
+ # Load nanoc
8
+ require 'nanoc'
9
+ require 'nanoc/cli'
22
10
 
23
- # Run nanoc
24
- begin
25
- exec name, *ARGV
26
- rescue Errno::ENOENT
27
- $stderr.puts "Could not execute #{name}, which is your selected nanoc version. Make sure that #{name} is installed and that it is in your $PATH."
28
- $stderr.puts
29
- $stderr.puts "* To install #{name}, run `gem install #{name}`."
30
- $stderr.puts "* To select a different version of nanoc, run `nanoc-select`."
31
- exit 1
32
- end
11
+ # Run base
12
+ Nanoc::CLI.run(ARGV)
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ exec File.dirname(__FILE__) + '/nanoc', *ARGV
@@ -0,0 +1,10 @@
1
+ <%= superb %>
2
+ <script type="text/javascript">
3
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
4
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
5
+ </script>
6
+ <script type="text/javascript">
7
+ try {
8
+ var pageTracker = _gat._getTracker("UA-15639968-1");
9
+ pageTracker._trackPageview();
10
+ } catch(err) {}</script>
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # The current nanoc version.
6
+ VERSION = '3.3.0'
7
+
8
+ # @return [String] A string containing information about this nanoc version
9
+ # and its environment (Ruby engine and version, Rubygems version if any).
10
+ def self.version_information
11
+ gem_info = defined?(Gem) ? "with RubyGems #{Gem::VERSION}" : "without RubyGems"
12
+ engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
13
+ res = ''
14
+ res << "nanoc #{Nanoc::VERSION} © 2007-2012 Denis Defreyne.\n".make_compatible_with_env
15
+ res << "Running #{engine} #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) on #{RUBY_PLATFORM} #{gem_info}.\n"
16
+ res
17
+ end
18
+
19
+ end
20
+
21
+ Nanoc3 = Nanoc
22
+
23
+ # Load general requirements
24
+ require 'digest'
25
+ require 'enumerator'
26
+ require 'fileutils'
27
+ require 'forwardable'
28
+ require 'pathname'
29
+ require 'pstore'
30
+ require 'set'
31
+ require 'tempfile'
32
+ require 'thread'
33
+ require 'time'
34
+ require 'yaml'
35
+
36
+ # Load nanoc
37
+ require 'nanoc/base'
38
+ require 'nanoc/extra'
39
+ require 'nanoc/data_sources'
40
+ require 'nanoc/filters'
41
+ require 'nanoc/helpers'
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ require 'nanoc/base/core_ext'
6
+ require 'nanoc/base/ordered_hash'
7
+
8
+ # Load helper classes
9
+ autoload 'Context', 'nanoc/base/context'
10
+ autoload 'DirectedGraph', 'nanoc/base/directed_graph'
11
+ autoload 'Errors', 'nanoc/base/errors'
12
+ autoload 'Memoization', 'nanoc/base/memoization'
13
+ autoload 'NotificationCenter', 'nanoc/base/notification_center'
14
+ autoload 'PluginRegistry', 'nanoc/base/plugin_registry'
15
+ autoload 'Store', 'nanoc/base/store'
16
+
17
+ # Load source data classes
18
+ autoload 'CodeSnippet', 'nanoc/base/source_data/code_snippet'
19
+ autoload 'Configuration', 'nanoc/base/source_data/configuration'
20
+ autoload 'DataSource', 'nanoc/base/source_data/data_source'
21
+ autoload 'Item', 'nanoc/base/source_data/item'
22
+ autoload 'Layout', 'nanoc/base/source_data/layout'
23
+ autoload 'Site', 'nanoc/base/source_data/site'
24
+
25
+ # Load result data classes
26
+ autoload 'ItemRep', 'nanoc/base/result_data/item_rep'
27
+
28
+ # Load compilation classes
29
+ autoload 'ChecksumStore', 'nanoc/base/compilation/checksum_store'
30
+ autoload 'CompiledContentCache', 'nanoc/base/compilation/compiled_content_cache'
31
+ autoload 'Compiler', 'nanoc/base/compilation/compiler'
32
+ autoload 'CompilerDSL', 'nanoc/base/compilation/compiler_dsl'
33
+ autoload 'DependencyTracker', 'nanoc/base/compilation/dependency_tracker'
34
+ autoload 'Filter', 'nanoc/base/compilation/filter'
35
+ autoload 'ItemRepProxy', 'nanoc/base/compilation/item_rep_proxy'
36
+ autoload 'ItemRepRecorderProxy', 'nanoc/base/compilation/item_rep_recorder_proxy'
37
+ autoload 'OutdatednessChecker', 'nanoc/base/compilation/outdatedness_checker'
38
+ autoload 'OutdatednessReasons', 'nanoc/base/compilation/outdatedness_reasons'
39
+ autoload 'Rule', 'nanoc/base/compilation/rule'
40
+ autoload 'RuleContext', 'nanoc/base/compilation/rule_context'
41
+ autoload 'RuleMemoryCalculator', 'nanoc/base/compilation/rule_memory_calculator'
42
+ autoload 'RuleMemoryStore', 'nanoc/base/compilation/rule_memory_store'
43
+ autoload 'RulesCollection', 'nanoc/base/compilation/rules_collection'
44
+
45
+ # Deprecated; use PluginRepository instead
46
+ # TODO [in nanoc 4.0] remove me
47
+ autoload 'Plugin', 'nanoc/base/plugin_registry'
48
+
49
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Stores checksums for objects in order to be able to detect whether a file
6
+ # has changed since the last site compilation.
7
+ #
8
+ # @api private
9
+ class ChecksumStore < ::Nanoc::Store
10
+
11
+ # @option params [Nanoc::Site] site The site where this checksum store
12
+ # belongs to
13
+ def initialize(params={})
14
+ super('tmp/checksums', 1)
15
+
16
+ @site = params[:site] if params.has_key?(:site)
17
+
18
+ @checksums = {}
19
+ end
20
+
21
+ # Returns the old checksum for the given object. This makes sense for
22
+ # items, layouts and code snippets.
23
+ #
24
+ # @param [#reference] obj The object for which to fetch the checksum
25
+ #
26
+ # @return [String] The checksum for the given object
27
+ def [](obj)
28
+ @checksums[obj.reference]
29
+ end
30
+
31
+ # Sets the checksum for the given object.
32
+ #
33
+ # @param [#reference] obj The object for which to set the checksum
34
+ #
35
+ # @param [String] checksum The checksum
36
+ def []=(obj, checksum)
37
+ @checksums[obj.reference] = checksum
38
+ end
39
+
40
+ # @see Nanoc::Store#unload
41
+ def unload
42
+ @checksums = {}
43
+ end
44
+
45
+ protected
46
+
47
+ def data
48
+ @checksums
49
+ end
50
+
51
+ def data=(new_data)
52
+ @checksums = new_data
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Represents a cache than can be used to store already compiled content,
6
+ # to prevent it from being needlessly recompiled.
7
+ #
8
+ # @api private
9
+ class CompiledContentCache < ::Nanoc::Store
10
+
11
+ def initialize
12
+ super('tmp/compiled_content', 1)
13
+
14
+ @cache = {}
15
+ end
16
+
17
+ # Returns the cached compiled content for the given item
18
+ # representation. This cached compiled content is a hash where the keys
19
+ # are the snapshot names and the values the compiled content at the
20
+ # given snapshot.
21
+ #
22
+ # @param [Nanoc::ItemRep] rep The item rep to fetch the content for
23
+ #
24
+ # @return [Hash<Symbol,String>] A hash containing the cached compiled
25
+ # content for the given item representation
26
+ def [](rep)
27
+ item_cache = @cache[rep.item.identifier] || {}
28
+ item_cache[rep.name]
29
+ end
30
+
31
+ # Sets the compiled content for the given representation.
32
+ #
33
+ # @param [Nanoc::ItemRep] rep The item representation for which to set
34
+ # the compiled content
35
+ #
36
+ # @param [Hash<Symbol,String>] content A hash containing the compiled
37
+ # content of the given representation
38
+ #
39
+ # @return [void]
40
+ def []=(rep, content)
41
+ @cache[rep.item.identifier] ||= {}
42
+ @cache[rep.item.identifier][rep.name] = content
43
+ end
44
+
45
+ # @see Nanoc::Store#unload
46
+ def unload
47
+ @cache = {}
48
+ end
49
+
50
+ protected
51
+
52
+ def data
53
+ @cache
54
+ end
55
+
56
+ def data=(new_data)
57
+ @cache = new_data
58
+ end
59
+
60
+ end
61
+
62
+ end
@@ -0,0 +1,458 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Responsible for compiling a site’s item representations.
6
+ #
7
+ # The compilation process makes use of notifications (see
8
+ # {Nanoc::NotificationCenter}) to track dependencies between items,
9
+ # layouts, etc. The following notifications are used:
10
+ #
11
+ # * `compilation_started` — indicates that the compiler has started
12
+ # compiling this item representation. Has one argument: the item
13
+ # representation itself. Only one item can be compiled at a given moment;
14
+ # therefore, it is not possible to get two consecutive
15
+ # `compilation_started` notifications without also getting a
16
+ # `compilation_ended` notification in between them.
17
+ #
18
+ # * `compilation_ended` — indicates that the compiler has finished compiling
19
+ # this item representation (either successfully or with failure). Has one
20
+ # argument: the item representation itself.
21
+ #
22
+ # * `visit_started` — indicates that the compiler requires content or
23
+ # attributes from the item representation that will be visited. Has one
24
+ # argument: the visited item identifier. This notification is used to
25
+ # track dependencies of items on other items; a `visit_started` event
26
+ # followed by another `visit_started` event indicates that the item
27
+ # corresponding to the former event will depend on the item from the
28
+ # latter event.
29
+ #
30
+ # * `visit_ended` — indicates that the compiler has finished visiting the
31
+ # item representation and that the requested attributes or content have
32
+ # been fetched (either successfully or with failure)
33
+ #
34
+ # * `processing_started` — indicates that the compiler has started
35
+ # processing the specified object, which can be an item representation
36
+ # (when it is compiled) or a layout (when it is used to lay out an item
37
+ # representation or when it is used as a partial)
38
+ #
39
+ # * `processing_ended` — indicates that the compiler has finished processing
40
+ # the specified object.
41
+ class Compiler
42
+
43
+ extend Nanoc::Memoization
44
+
45
+ # @group Accessors
46
+
47
+ # @return [Nanoc::Site] The site this compiler belongs to
48
+ attr_reader :site
49
+
50
+ # The compilation stack. When the compiler begins compiling a rep or a
51
+ # layout, it will be placed on the stack; when it is done compiling the
52
+ # rep or layout, it will be removed from the stack.
53
+ #
54
+ # @return [Array] The compilation stack
55
+ attr_reader :stack
56
+
57
+ # @group Public instance methods
58
+
59
+ # Creates a new compiler fo the given site
60
+ #
61
+ # @param [Nanoc::Site] site The site this compiler belongs to
62
+ def initialize(site)
63
+ @site = site
64
+
65
+ @stack = []
66
+ end
67
+
68
+ # Compiles the site and writes out the compiled item representations.
69
+ #
70
+ # Previous versions of nanoc (< 3.2) allowed passing items to compile, and
71
+ # had a “force” option to make the compiler recompile all pages, even
72
+ # when not outdated. These arguments and options are, as of nanoc 3.2, no
73
+ # longer used, and will simply be ignored when passed to {#run}.
74
+ #
75
+ # @overload run
76
+ # @return [void]
77
+ def run(*args)
78
+ # Create output directory if necessary
79
+ FileUtils.mkdir_p(@site.config[:output_dir])
80
+
81
+ # Compile reps
82
+ load
83
+ @site.freeze
84
+ dependency_tracker.start
85
+ compile_reps(reps)
86
+ dependency_tracker.stop
87
+ store
88
+ ensure
89
+ # Cleanup
90
+ FileUtils.rm_rf(Nanoc::Filter::TMP_BINARY_ITEMS_DIR)
91
+ end
92
+
93
+ # @group Private instance methods
94
+
95
+ # @return [Nanoc::RulesCollection] The collection of rules to be used
96
+ # for compiling this site
97
+ def rules_collection
98
+ Nanoc::RulesCollection.new(self)
99
+ end
100
+ memoize :rules_collection
101
+
102
+ # Load the helper data that is used for compiling the site.
103
+ #
104
+ # @api private
105
+ #
106
+ # @return [void]
107
+ def load
108
+ return if @loaded || @loading
109
+ @loading = true
110
+
111
+ # Load site if necessary
112
+ site.load
113
+
114
+ # Preprocess
115
+ rules_collection.load
116
+ preprocess
117
+ site.setup_child_parent_links
118
+ build_reps
119
+ route_reps
120
+
121
+ # Load auxiliary stores
122
+ stores.each { |s| s.load }
123
+
124
+ # Determine which reps need to be recompiled
125
+ forget_dependencies_if_outdated(items)
126
+
127
+ @loaded = true
128
+ rescue => e
129
+ unload
130
+ raise e
131
+ ensure
132
+ @loading = false
133
+ end
134
+
135
+ # Undoes the effects of {#load}. Used when {#load} raises an exception.
136
+ #
137
+ # @api private
138
+ #
139
+ # @return [void]
140
+ def unload
141
+ return if @unloading
142
+ @unloading = true
143
+
144
+ stores.each { |s| s.unload }
145
+
146
+ @stack = []
147
+
148
+ items.each { |item| item.reps.clear }
149
+ site.teardown_child_parent_links
150
+ rules_collection.unload
151
+
152
+ site.unload
153
+
154
+ @loaded = false
155
+ @unloading = false
156
+ end
157
+
158
+ # Store the modified helper data used for compiling the site.
159
+ #
160
+ # @api private
161
+ #
162
+ # @return [void]
163
+ def store
164
+ # Calculate rule memory
165
+ (reps + layouts).each do |obj|
166
+ rule_memory_store[obj] = rule_memory_calculator[obj]
167
+ end
168
+
169
+ # Calculate checksums
170
+ self.objects.each do |obj|
171
+ checksum_store[obj] = obj.checksum
172
+ end
173
+
174
+ # Store
175
+ stores.each { |s| s.store }
176
+ end
177
+
178
+ # Returns the dependency tracker for this site, creating it first if it
179
+ # does not yet exist.
180
+ #
181
+ # @api private
182
+ #
183
+ # @return [Nanoc::DependencyTracker] The dependency tracker for this site
184
+ def dependency_tracker
185
+ dt = Nanoc::DependencyTracker.new(@site.items + @site.layouts)
186
+ dt.compiler = self
187
+ dt
188
+ end
189
+ memoize :dependency_tracker
190
+
191
+ # Runs the preprocessor.
192
+ #
193
+ # @api private
194
+ def preprocess
195
+ return if rules_collection.preprocessor.nil?
196
+ preprocessor_context.instance_eval(&rules_collection.preprocessor)
197
+ end
198
+
199
+ # Returns all objects managed by the site (items, layouts, code snippets,
200
+ # site configuration and the rules).
201
+ #
202
+ # @api private
203
+ def objects
204
+ site.items + site.layouts + site.code_snippets +
205
+ [ site.config, rules_collection ]
206
+ end
207
+
208
+ # Creates the representations of all items as defined by the compilation
209
+ # rules.
210
+ #
211
+ # @api private
212
+ def build_reps
213
+ items.each do |item|
214
+ # Find matching rules
215
+ matching_rules = rules_collection.item_compilation_rules_for(item)
216
+ raise Nanoc::Errors::NoMatchingCompilationRuleFound.new(item) if matching_rules.empty?
217
+
218
+ # Create reps
219
+ rep_names = matching_rules.map { |r| r.rep_name }.uniq
220
+ rep_names.each do |rep_name|
221
+ item.reps << ItemRep.new(item, rep_name)
222
+ end
223
+ end
224
+ end
225
+
226
+ # Determines the paths of all item representations.
227
+ #
228
+ # @api private
229
+ def route_reps
230
+ reps.each do |rep|
231
+ # Find matching rules
232
+ rules = rules_collection.routing_rules_for(rep)
233
+ raise Nanoc::Errors::NoMatchingRoutingRuleFound.new(rep) if rules[:last].nil?
234
+
235
+ rules.each_pair do |snapshot, rule|
236
+ # Get basic path by applying matching rule
237
+ basic_path = rule.apply_to(rep, :compiler => self)
238
+ next if basic_path.nil?
239
+ if basic_path !~ %r{^/}
240
+ raise RuntimeError, "The path returned for the #{rep.inspect} item representation, “#{basic_path}”, does not start with a slash. Please ensure that all routing rules return a path that starts with a slash.".make_compatible_with_env
241
+ end
242
+
243
+ # Get raw path by prepending output directory
244
+ rep.raw_paths[snapshot] = @site.config[:output_dir] + basic_path
245
+
246
+ # Get normal path by stripping index filename
247
+ rep.paths[snapshot] = basic_path
248
+ @site.config[:index_filenames].each do |index_filename|
249
+ if rep.paths[snapshot][-index_filename.length..-1] == index_filename
250
+ # Strip and stop
251
+ rep.paths[snapshot] = rep.paths[snapshot][0..-index_filename.length-1]
252
+ break
253
+ end
254
+ end
255
+ end
256
+ end
257
+ end
258
+
259
+ # @param [Nanoc::ItemRep] rep The item representation for which the
260
+ # assigns should be fetched
261
+ #
262
+ # @return [Hash] The assigns that should be used in the next filter/layout
263
+ # operation
264
+ #
265
+ # @api private
266
+ def assigns_for(rep)
267
+ if rep.binary?
268
+ content_or_filename_assigns = { :filename => rep.temporary_filenames[:last] }
269
+ else
270
+ content_or_filename_assigns = { :content => rep.content[:last] }
271
+ end
272
+
273
+ content_or_filename_assigns.merge({
274
+ :item => rep.item,
275
+ :item_rep => rep,
276
+ :items => site.items,
277
+ :layouts => site.layouts,
278
+ :config => site.config,
279
+ :site => site
280
+ })
281
+ end
282
+
283
+ # @return [Nanoc::OutdatednessChecker] The outdatedness checker
284
+ def outdatedness_checker
285
+ Nanoc::OutdatednessChecker.new(
286
+ :site => @site,
287
+ :checksum_store => checksum_store,
288
+ :dependency_tracker => dependency_tracker)
289
+ end
290
+ memoize :outdatedness_checker
291
+
292
+ private
293
+
294
+ # @return [Array<Nanoc::Item>] The site’s items
295
+ def items
296
+ @site.items
297
+ end
298
+ memoize :items
299
+
300
+ # @return [Array<Nanoc::ItemRep>] The site’s item representations
301
+ def reps
302
+ items.map { |i| i.reps }.flatten
303
+ end
304
+ memoize :reps
305
+
306
+ # @return [Array<Nanoc::Layout>] The site’s layouts
307
+ def layouts
308
+ @site.layouts
309
+ end
310
+ memoize :layouts
311
+
312
+ # Compiles the given representations.
313
+ #
314
+ # @param [Array] reps The item representations to compile.
315
+ #
316
+ # @return [void]
317
+ def compile_reps(reps)
318
+ content_dependency_graph = Nanoc::DirectedGraph.new(reps)
319
+
320
+ # Listen to processing start/stop
321
+ Nanoc::NotificationCenter.on(:processing_started, self) { |obj| @stack.push(obj) }
322
+ Nanoc::NotificationCenter.on(:processing_ended, self) { |obj| @stack.pop }
323
+
324
+ # Attempt to compile all active reps
325
+ loop do
326
+ # Find rep to compile
327
+ break if content_dependency_graph.roots.empty?
328
+ rep = content_dependency_graph.roots.each { |e| break e }
329
+ @stack = []
330
+
331
+ begin
332
+ compile_rep(rep)
333
+ content_dependency_graph.delete_vertex(rep)
334
+ rescue Nanoc::Errors::UnmetDependency => e
335
+ content_dependency_graph.add_edge(e.rep, rep)
336
+ unless content_dependency_graph.vertices.include?(e.rep)
337
+ content_dependency_graph.add_vertex(e.rep)
338
+ end
339
+ end
340
+ end
341
+
342
+ # Check whether everything was compiled
343
+ if !content_dependency_graph.vertices.empty?
344
+ raise Nanoc::Errors::RecursiveCompilation.new(content_dependency_graph.vertices)
345
+ end
346
+ ensure
347
+ Nanoc::NotificationCenter.remove(:processing_started, self)
348
+ Nanoc::NotificationCenter.remove(:processing_ended, self)
349
+ end
350
+
351
+ # Compiles the given item representation.
352
+ #
353
+ # This method should not be called directly; please use
354
+ # {Nanoc::Compiler#run} instead, and pass this item representation's item
355
+ # as its first argument.
356
+ #
357
+ # @param [Nanoc::ItemRep] rep The rep that is to be compiled
358
+ #
359
+ # @return [void]
360
+ def compile_rep(rep)
361
+ Nanoc::NotificationCenter.post(:compilation_started, rep)
362
+ Nanoc::NotificationCenter.post(:processing_started, rep)
363
+ Nanoc::NotificationCenter.post(:visit_started, rep.item)
364
+
365
+ # Calculate rule memory if we haven’t yet done do
366
+ rules_collection.new_rule_memory_for_rep(rep)
367
+
368
+ # Assign snapshots
369
+ rep.snapshots = rules_collection.snapshots_for(rep)
370
+
371
+ if !outdatedness_checker.outdated?(rep) && compiled_content_cache[rep]
372
+ # Reuse content
373
+ Nanoc::NotificationCenter.post(:cached_content_used, rep)
374
+ rep.content = compiled_content_cache[rep]
375
+ else
376
+ # Recalculate content
377
+ rep.snapshot(:raw)
378
+ rep.snapshot(:pre, :final => false)
379
+ rules_collection.compilation_rule_for(rep).apply_to(rep, :compiler => self)
380
+ rep.snapshot(:post) if rep.has_snapshot?(:post)
381
+ rep.snapshot(:last)
382
+ end
383
+
384
+ rep.compiled = true
385
+ compiled_content_cache[rep] = rep.content
386
+ rescue => e
387
+ rep.forget_progress
388
+ Nanoc::NotificationCenter.post(:compilation_failed, rep, e)
389
+ raise e
390
+ ensure
391
+ Nanoc::NotificationCenter.post(:visit_ended, rep.item)
392
+ Nanoc::NotificationCenter.post(:processing_ended, rep)
393
+ Nanoc::NotificationCenter.post(:compilation_ended, rep)
394
+ end
395
+
396
+ # Clears the list of dependencies for items that will be recompiled.
397
+ #
398
+ # @param [Array<Nanoc::Item>] items The list of items for which to forget
399
+ # the dependencies
400
+ #
401
+ # @return [void]
402
+ def forget_dependencies_if_outdated(items)
403
+ items.each do |i|
404
+ if i.reps.any? { |r| outdatedness_checker.outdated?(r) }
405
+ dependency_tracker.forget_dependencies_for(i)
406
+ end
407
+ end
408
+ end
409
+
410
+ # Returns a preprocessor context, creating one if none exists yet.
411
+ def preprocessor_context
412
+ Nanoc::Context.new({
413
+ :site => @site,
414
+ :config => @site.config,
415
+ :items => @site.items,
416
+ :layouts => @site.layouts
417
+ })
418
+ end
419
+ memoize :preprocessor_context
420
+
421
+ # @return [CompiledContentCache] The compiled content cache
422
+ def compiled_content_cache
423
+ Nanoc::CompiledContentCache.new
424
+ end
425
+ memoize :compiled_content_cache
426
+
427
+ # @return [ChecksumStore] The checksum store
428
+ def checksum_store
429
+ Nanoc::ChecksumStore.new(:site => @site)
430
+ end
431
+ memoize :checksum_store
432
+
433
+ # @return [RuleMemoryStore] The rule memory store
434
+ def rule_memory_store
435
+ Nanoc::RuleMemoryStore.new(:site => @site)
436
+ end
437
+ memoize :rule_memory_store
438
+
439
+ # @return [RuleMemoryCalculator] The rule memory calculator
440
+ def rule_memory_calculator
441
+ Nanoc::RuleMemoryCalculator.new(:rules_collection => rules_collection)
442
+ end
443
+ memoize :rule_memory_calculator
444
+
445
+ # Returns all stores that can load/store data that can be used for
446
+ # compilation.
447
+ def stores
448
+ [
449
+ checksum_store,
450
+ compiled_content_cache,
451
+ dependency_tracker,
452
+ rule_memory_store
453
+ ]
454
+ end
455
+
456
+ end
457
+
458
+ end