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