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,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