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,103 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Represents an item representation, but provides an interface that is
6
+ # easier to use when writing compilation and routing rules. It is also
7
+ # responsible for fetching the necessary information from the compiler, such
8
+ # as assigns.
9
+ #
10
+ # The API provided by item representation proxies allows layout identifiers
11
+ # to be given as literals instead of as references to {Nanoc::Layout}.
12
+ class ItemRepProxy
13
+
14
+ extend Forwardable
15
+
16
+ def_delegators :@item_rep, :item, :name, :binary, :binary?, :compiled_content, :has_snapshot?, :raw_path, :path
17
+ def_delegator :@item_rep, :snapshot
18
+
19
+ # @param [Nanoc::ItemRep] item_rep The item representation that this
20
+ # proxy should behave like
21
+ #
22
+ # @param [Nanoc::Compiler] compiler The compiler that will provide the
23
+ # necessary compilation-related functionality.
24
+ def initialize(item_rep, compiler)
25
+ @item_rep = item_rep
26
+ @compiler = compiler
27
+ end
28
+
29
+ # Runs the item content through the given filter with the given arguments.
30
+ # This method will replace the content of the `:last` snapshot with the
31
+ # filtered content of the last snapshot.
32
+ #
33
+ # This method is supposed to be called only in a compilation rule block
34
+ # (see {Nanoc::CompilerDSL#compile}).
35
+ #
36
+ # @see Nanoc::ItemRep#filter
37
+ #
38
+ # @param [Symbol] filter_name The name of the filter to run the item
39
+ # representations' content through
40
+ #
41
+ # @param [Hash] filter_args The filter arguments that should be passed to
42
+ # the filter's #run method
43
+ #
44
+ # @return [void]
45
+ def filter(name, args={})
46
+ set_assigns
47
+ @item_rep.filter(name, args)
48
+ end
49
+
50
+ # Lays out the item using the given layout. This method will replace the
51
+ # content of the `:last` snapshot with the laid out content of the last
52
+ # snapshot.
53
+ #
54
+ # This method is supposed to be called only in a compilation rule block
55
+ # (see {Nanoc::CompilerDSL#compile}).
56
+ #
57
+ # @see Nanoc::ItemRep#layout
58
+ #
59
+ # @param [String] layout_identifier The identifier of the layout to use
60
+ #
61
+ # @return [void]
62
+ def layout(layout_identifier, extra_filter_args={})
63
+ set_assigns
64
+
65
+ layout = layout_with_identifier(layout_identifier)
66
+ filter_name, filter_args = @compiler.rules_collection.filter_for_layout(layout)
67
+ filter_args = filter_args.merge(extra_filter_args)
68
+
69
+ @item_rep.layout(layout, filter_name, filter_args)
70
+ end
71
+
72
+ # Returns true because this item is already a proxy, and therefore doesn’t
73
+ # need to be wrapped anymore.
74
+ #
75
+ # @api private
76
+ #
77
+ # @return [true]
78
+ #
79
+ # @see Nanoc::ItemRep#is_proxy?
80
+ # @see Nanoc::ItemRepRecorderProxy#is_proxy?
81
+ def is_proxy?
82
+ true
83
+ end
84
+
85
+ private
86
+
87
+ def set_assigns
88
+ @item_rep.assigns = @compiler.assigns_for(@item_rep)
89
+ end
90
+
91
+ def layouts
92
+ @compiler.site.layouts
93
+ end
94
+
95
+ def layout_with_identifier(layout_identifier)
96
+ layout ||= layouts.find { |l| l.identifier == layout_identifier.cleaned_identifier }
97
+ raise Nanoc::Errors::UnknownLayout.new(layout_identifier) if layout.nil?
98
+ layout
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -0,0 +1,102 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Represents a fake iem representation that does not actually perform any
6
+ # actual filtering, layouting or snapshotting, but instead keeps track of
7
+ # what would happen if a real item representation would have been used
8
+ # instead. It therefore “records” the actions that happens upon it.
9
+ #
10
+ # The list of recorded actions is used during compilation to determine
11
+ # whether an item representation needs to be recompiled: if the list of
12
+ # actions is different from the list of actions from the previous
13
+ # compilation run, the item needs to be recompiled; if it is the same, it
14
+ # may not need to be recompiled.
15
+ #
16
+ # @api private
17
+ class ItemRepRecorderProxy
18
+
19
+ extend Forwardable
20
+
21
+ def_delegators :@item_rep, :item, :name, :binary, :binary?, :compiled_content, :has_snapshot?, :raw_path, :path, :assigns, :assigns=
22
+
23
+ # @example The compilation rule and the corresponding rule memory
24
+ #
25
+ # # rule
26
+ # compile '/foo/' do
27
+ # filter :erb
28
+ # filter :myfilter, :arg1 => 'stuff'
29
+ # layout 'meh'
30
+ # end
31
+ #
32
+ # # memory
33
+ # [
34
+ # [ :filter, :erb, {} ],
35
+ # [ :filter, :myfilter, { :arg1 => 'stuff' } ],
36
+ # [ :layout, 'meh' ]
37
+ # ]
38
+ #
39
+ # @return [Array] The list of recorded actions (“rule memory”)
40
+ attr_reader :rule_memory
41
+
42
+ # @param [Nanoc::ItemRep] item_rep The item representation that this
43
+ # proxy should behave like
44
+ def initialize(item_rep)
45
+ @item_rep = item_rep
46
+ @rule_memory = []
47
+ end
48
+
49
+ # @return [void]
50
+ #
51
+ # @see Nanoc::ItemRepProxy#filter, Nanoc::ItemRep#filter
52
+ def filter(name, args={})
53
+ @rule_memory << [ :filter, name, args ]
54
+ end
55
+
56
+ # @return [void]
57
+ #
58
+ # @see Nanoc::ItemRepProxy#layout, Nanoc::ItemRep#layout
59
+ def layout(layout_identifier, extra_filter_args=nil)
60
+ if extra_filter_args
61
+ @rule_memory << [ :layout, layout_identifier, extra_filter_args ]
62
+ else
63
+ @rule_memory << [ :layout, layout_identifier ]
64
+ end
65
+ end
66
+
67
+ # @return [void]
68
+ #
69
+ # @see Nanoc::ItemRep#snapshot
70
+ def snapshot(snapshot_name, params={})
71
+ @rule_memory << [ :snapshot, snapshot_name, params ]
72
+
73
+ # Count
74
+ existing = Set.new
75
+ names = @rule_memory.select { |r| r[0] == :snapshot }.map { |r| r[2] }
76
+ names.each do |n|
77
+ if existing.include?(n)
78
+ raise Nanoc::Errors::CannotCreateMultipleSnapshotsWithSameName.new(@item_rep, snapshot_name)
79
+ end
80
+ existing << n
81
+ end
82
+ end
83
+
84
+ # @return [{}]
85
+ def content
86
+ {}
87
+ end
88
+
89
+ # Returns true because this item is already a proxy, and therefore doesn’t
90
+ # need to be wrapped anymore.
91
+ #
92
+ # @return [true]
93
+ #
94
+ # @see Nanoc::ItemRep#is_proxy?
95
+ # @see Nanoc::ItemRepProxy#is_proxy?
96
+ def is_proxy?
97
+ true
98
+ end
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,223 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Responsible for determining whether an item or a layout is outdated.
6
+ #
7
+ # @api private
8
+ class OutdatednessChecker
9
+
10
+ extend Nanoc::Memoization
11
+
12
+ # @option params [Nanoc::Site] :site (nil) The site this outdatedness
13
+ # checker belongs to.
14
+ #
15
+ # @option params [Nanoc::ChecksumStore] :checksum_store (nil) The
16
+ # checksum store where checksums of items, layouts, … are stored.
17
+ #
18
+ # @option params [Nanoc::DependencyTracker] :dependency_tracker (nil) The
19
+ # dependency tracker for the given site.
20
+ def initialize(params={})
21
+ @site = params[:site] or raise ArgumentError,
22
+ 'Nanoc::OutdatednessChecker#initialize needs a :site parameter'
23
+ @checksum_store = params[:checksum_store] or raise ArgumentError,
24
+ 'Nanoc::OutdatednessChecker#initialize needs a :checksum_store parameter'
25
+ @dependency_tracker = params[:dependency_tracker] or raise ArgumentError,
26
+ 'Nanoc::OutdatednessChecker#initialize needs a :dependency_tracker parameter'
27
+
28
+ @basic_outdatedness_reasons = {}
29
+ @outdatedness_reasons = {}
30
+ @objects_outdated_due_to_dependencies = {}
31
+ end
32
+
33
+ # Checks whether the given object is outdated and therefore needs to be
34
+ # recompiled.
35
+ #
36
+ # @param [Nanoc::Item, Nanoc::ItemRep, Nanoc::Layout] obj The object
37
+ # whose outdatedness should be checked.
38
+ #
39
+ # @return [Boolean] true if the object is outdated, false otherwise
40
+ def outdated?(obj)
41
+ !outdatedness_reason_for(obj).nil?
42
+ end
43
+
44
+ # Calculates the reason why the given object is outdated.
45
+ #
46
+ # @param [Nanoc::Item, Nanoc::ItemRep, Nanoc::Layout] obj The object
47
+ # whose outdatedness reason should be calculated.
48
+ #
49
+ # @return [Nanoc::OutdatednessReasons::Generic, nil] The reason why the
50
+ # given object is outdated, or nil if the object is not outdated.
51
+ def outdatedness_reason_for(obj)
52
+ reason = basic_outdatedness_reason_for(obj)
53
+ if reason.nil? && outdated_due_to_dependencies?(obj)
54
+ reason = Nanoc::OutdatednessReasons::DependenciesOutdated
55
+ end
56
+ reason
57
+ end
58
+ memoize :outdatedness_reason_for
59
+
60
+ private
61
+
62
+ # Checks whether the given object is outdated and therefore needs to be
63
+ # recompiled. This method does not take dependencies into account; use
64
+ # {#outdated?} if you want to include dependencies in the outdatedness
65
+ # check.
66
+ #
67
+ # @param [Nanoc::Item, Nanoc::ItemRep, Nanoc::Layout] obj The object
68
+ # whose outdatedness should be checked.
69
+ #
70
+ # @return [Boolean] true if the object is outdated, false otherwise
71
+ def basic_outdated?(obj)
72
+ !basic_outdatedness_reason_for(obj).nil?
73
+ end
74
+
75
+ # Calculates the reason why the given object is outdated. This method does
76
+ # not take dependencies into account; use {#outdatedness_reason_for?} if
77
+ # you want to include dependencies in the outdatedness check.
78
+ #
79
+ # @param [Nanoc::Item, Nanoc::ItemRep, Nanoc::Layout] obj The object
80
+ # whose outdatedness reason should be calculated.
81
+ #
82
+ # @return [Nanoc::OutdatednessReasons::Generic, nil] The reason why the
83
+ # given object is outdated, or nil if the object is not outdated.
84
+ def basic_outdatedness_reason_for(obj)
85
+ case obj.type
86
+ when :item_rep
87
+ # Outdated if rules outdated
88
+ return Nanoc::OutdatednessReasons::RulesModified if
89
+ rule_memory_differs_for(obj)
90
+
91
+ # Outdated if checksums are missing or different
92
+ return Nanoc::OutdatednessReasons::NotEnoughData if !checksums_available?(obj.item)
93
+ return Nanoc::OutdatednessReasons::SourceModified if !checksums_identical?(obj.item)
94
+
95
+ # Outdated if compiled file doesn't exist (yet)
96
+ return Nanoc::OutdatednessReasons::NotWritten if obj.raw_path && !File.file?(obj.raw_path)
97
+
98
+ # Outdated if code snippets outdated
99
+ return Nanoc::OutdatednessReasons::CodeSnippetsModified if site.code_snippets.any? do |cs|
100
+ object_modified?(cs)
101
+ end
102
+
103
+ # Outdated if configuration outdated
104
+ return Nanoc::OutdatednessReasons::ConfigurationModified if object_modified?(site.config)
105
+
106
+ # Not outdated
107
+ return nil
108
+ when :item
109
+ obj.reps.find { |rep| basic_outdatedness_reason_for(rep) }
110
+ when :layout
111
+ # Outdated if rules outdated
112
+ return Nanoc::OutdatednessReasons::RulesModified if
113
+ rule_memory_differs_for(obj)
114
+
115
+ # Outdated if checksums are missing or different
116
+ return Nanoc::OutdatednessReasons::NotEnoughData if !checksums_available?(obj)
117
+ return Nanoc::OutdatednessReasons::SourceModified if !checksums_identical?(obj)
118
+
119
+ # Not outdated
120
+ return nil
121
+ else
122
+ raise RuntimeError, "do not know how to check outdatedness of #{obj.inspect}"
123
+ end
124
+ end
125
+ memoize :basic_outdatedness_reason_for
126
+
127
+ # Checks whether the given object is outdated due to dependencies.
128
+ #
129
+ # @param [Nanoc::Item, Nanoc::ItemRep, Nanoc::Layout] obj The object
130
+ # whose outdatedness should be checked.
131
+ #
132
+ # @param [Set] processed The collection of items that has been visited
133
+ # during this outdatedness check. This is used to prevent checks for
134
+ # items that (indirectly) depend on their own from looping
135
+ # indefinitely. It should not be necessary to pass this a custom value.
136
+ #
137
+ # @return [Boolean] true if the object is outdated, false otherwise
138
+ def outdated_due_to_dependencies?(obj, processed=Set.new)
139
+ # Convert from rep to item if necessary
140
+ obj = obj.item if obj.type == :item_rep
141
+
142
+ # Get from cache
143
+ if @objects_outdated_due_to_dependencies.has_key?(obj)
144
+ return @objects_outdated_due_to_dependencies[obj]
145
+ end
146
+
147
+ # Check processed
148
+ # Don’t return true; the false will be or’ed into a true if there
149
+ # really is a dependency that is causing outdatedness.
150
+ return false if processed.include?(obj)
151
+
152
+ # Calculate
153
+ is_outdated = dependency_tracker.objects_causing_outdatedness_of(obj).any? do |other|
154
+ other.nil? || basic_outdated?(other) || outdated_due_to_dependencies?(other, processed.merge([obj]))
155
+ end
156
+
157
+ # Cache
158
+ @objects_outdated_due_to_dependencies[obj] = is_outdated
159
+
160
+ # Done
161
+ is_outdated
162
+ end
163
+
164
+ # @param [Nanoc::ItemRep, Nanoc::Layout] obj The layout or item
165
+ # representation to check the rule memory for
166
+ #
167
+ # @return [Boolean] true if the rule memory for the given item
168
+ # represenation has changed, false otherwise
169
+ def rule_memory_differs_for(obj)
170
+ rules_collection.rule_memory_differs_for(obj)
171
+ end
172
+ memoize :rule_memory_differs_for
173
+
174
+ # @param obj
175
+ #
176
+ # @return [Boolean] false if either the new or the old checksum for the
177
+ # given object is not available, true if both checksums are available
178
+ def checksums_available?(obj)
179
+ !!checksum_store[obj] && obj.checksum
180
+ end
181
+ memoize :checksums_available?
182
+
183
+ # @param obj
184
+ #
185
+ # @return [Boolean] false if the old and new checksums for the given
186
+ # object differ, true if they are identical
187
+ def checksums_identical?(obj)
188
+ checksum_store[obj] == obj.checksum
189
+ end
190
+ memoize :checksums_identical?
191
+
192
+ # @param obj
193
+ #
194
+ # @return [Boolean] true if the old and new checksums for the given object
195
+ # are available and identical, false otherwise
196
+ def object_modified?(obj)
197
+ !checksums_available?(obj) || !checksums_identical?(obj)
198
+ end
199
+ memoize :object_modified?
200
+
201
+ # @return [Nanoc::ChecksumStore] The checksum store
202
+ def checksum_store
203
+ @checksum_store
204
+ end
205
+
206
+ # @return [Nanoc::RulesCollection] The rules collection
207
+ def rules_collection
208
+ site.compiler.rules_collection
209
+ end
210
+
211
+ # @return [Nanoc::DependencyTracker] The dependency tracker
212
+ def dependency_tracker
213
+ @dependency_tracker
214
+ end
215
+
216
+ # @return [Nanoc::Site] The site
217
+ def site
218
+ @site
219
+ end
220
+
221
+ end
222
+
223
+ end
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ module Nanoc
4
+
5
+ # Module that contains all outdatedness reasons.
6
+ module OutdatednessReasons
7
+
8
+ # A generic outdatedness reason. An outdatedness reason is basically a
9
+ # descriptive message that explains why a given object is outdated.
10
+ class Generic
11
+
12
+ # @return [String] A descriptive message for this outdatedness reason
13
+ attr_reader :message
14
+
15
+ # @param [String] message The descriptive message for this outdatedness
16
+ # reason
17
+ def initialize(message)
18
+ @message = message
19
+ end
20
+
21
+ end
22
+
23
+ CodeSnippetsModified = Generic.new(
24
+ 'The code snippets have been modified since the last time the site was compiled.')
25
+
26
+ ConfigurationModified = Generic.new(
27
+ 'The site configuration has been modified since the last time the site was compiled.')
28
+
29
+ DependenciesOutdated = Generic.new(
30
+ 'This item uses content or attributes that have changed since the last time the site was compiled.')
31
+
32
+ NotEnoughData = Generic.new(
33
+ 'Not enough data is present to correctly determine whether the item is outdated.')
34
+
35
+ NotWritten = Generic.new(
36
+ 'This item representation has not yet been written to the output directory (but it does have a path).')
37
+
38
+ RulesModified = Generic.new(
39
+ 'The rules file has been modified since the last time the site was compiled.')
40
+
41
+ SourceModified = Generic.new(
42
+ 'The source file of this item has been modified since the last time the site was compiled.')
43
+
44
+ end
45
+
46
+ end