nanoc 2.2.2 → 3.0.0a1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/bin/nanoc +29 -11
  2. data/bin/nanoc-select +85 -0
  3. metadata +27 -161
  4. data/ChangeLog +0 -3
  5. data/LICENSE +0 -19
  6. data/README +0 -75
  7. data/Rakefile +0 -76
  8. data/lib/nanoc.rb +0 -73
  9. data/lib/nanoc/base.rb +0 -26
  10. data/lib/nanoc/base/asset.rb +0 -117
  11. data/lib/nanoc/base/asset_defaults.rb +0 -21
  12. data/lib/nanoc/base/asset_rep.rb +0 -282
  13. data/lib/nanoc/base/binary_filter.rb +0 -44
  14. data/lib/nanoc/base/code.rb +0 -41
  15. data/lib/nanoc/base/compiler.rb +0 -67
  16. data/lib/nanoc/base/core_ext.rb +0 -2
  17. data/lib/nanoc/base/core_ext/hash.rb +0 -78
  18. data/lib/nanoc/base/core_ext/string.rb +0 -8
  19. data/lib/nanoc/base/data_source.rb +0 -286
  20. data/lib/nanoc/base/defaults.rb +0 -30
  21. data/lib/nanoc/base/filter.rb +0 -93
  22. data/lib/nanoc/base/layout.rb +0 -91
  23. data/lib/nanoc/base/notification_center.rb +0 -66
  24. data/lib/nanoc/base/page.rb +0 -132
  25. data/lib/nanoc/base/page_defaults.rb +0 -20
  26. data/lib/nanoc/base/page_rep.rb +0 -324
  27. data/lib/nanoc/base/plugin.rb +0 -71
  28. data/lib/nanoc/base/proxies.rb +0 -5
  29. data/lib/nanoc/base/proxies/asset_proxy.rb +0 -29
  30. data/lib/nanoc/base/proxies/asset_rep_proxy.rb +0 -26
  31. data/lib/nanoc/base/proxies/layout_proxy.rb +0 -25
  32. data/lib/nanoc/base/proxies/page_proxy.rb +0 -35
  33. data/lib/nanoc/base/proxies/page_rep_proxy.rb +0 -28
  34. data/lib/nanoc/base/proxy.rb +0 -37
  35. data/lib/nanoc/base/router.rb +0 -72
  36. data/lib/nanoc/base/site.rb +0 -274
  37. data/lib/nanoc/base/template.rb +0 -64
  38. data/lib/nanoc/binary_filters.rb +0 -1
  39. data/lib/nanoc/binary_filters/image_science_thumbnail.rb +0 -28
  40. data/lib/nanoc/cli.rb +0 -9
  41. data/lib/nanoc/cli/base.rb +0 -132
  42. data/lib/nanoc/cli/commands.rb +0 -10
  43. data/lib/nanoc/cli/commands/autocompile.rb +0 -80
  44. data/lib/nanoc/cli/commands/compile.rb +0 -311
  45. data/lib/nanoc/cli/commands/create_layout.rb +0 -85
  46. data/lib/nanoc/cli/commands/create_page.rb +0 -85
  47. data/lib/nanoc/cli/commands/create_site.rb +0 -323
  48. data/lib/nanoc/cli/commands/create_template.rb +0 -76
  49. data/lib/nanoc/cli/commands/help.rb +0 -69
  50. data/lib/nanoc/cli/commands/info.rb +0 -125
  51. data/lib/nanoc/cli/commands/switch.rb +0 -141
  52. data/lib/nanoc/cli/commands/update.rb +0 -91
  53. data/lib/nanoc/cli/logger.rb +0 -72
  54. data/lib/nanoc/data_sources.rb +0 -2
  55. data/lib/nanoc/data_sources/filesystem.rb +0 -707
  56. data/lib/nanoc/data_sources/filesystem_combined.rb +0 -495
  57. data/lib/nanoc/extra.rb +0 -6
  58. data/lib/nanoc/extra/auto_compiler.rb +0 -285
  59. data/lib/nanoc/extra/context.rb +0 -22
  60. data/lib/nanoc/extra/core_ext.rb +0 -2
  61. data/lib/nanoc/extra/core_ext/hash.rb +0 -54
  62. data/lib/nanoc/extra/core_ext/time.rb +0 -13
  63. data/lib/nanoc/extra/file_proxy.rb +0 -29
  64. data/lib/nanoc/extra/vcs.rb +0 -48
  65. data/lib/nanoc/extra/vcses.rb +0 -5
  66. data/lib/nanoc/extra/vcses/bazaar.rb +0 -21
  67. data/lib/nanoc/extra/vcses/dummy.rb +0 -20
  68. data/lib/nanoc/extra/vcses/git.rb +0 -21
  69. data/lib/nanoc/extra/vcses/mercurial.rb +0 -21
  70. data/lib/nanoc/extra/vcses/subversion.rb +0 -21
  71. data/lib/nanoc/filters.rb +0 -16
  72. data/lib/nanoc/filters/bluecloth.rb +0 -13
  73. data/lib/nanoc/filters/erb.rb +0 -19
  74. data/lib/nanoc/filters/erubis.rb +0 -14
  75. data/lib/nanoc/filters/haml.rb +0 -21
  76. data/lib/nanoc/filters/markaby.rb +0 -14
  77. data/lib/nanoc/filters/maruku.rb +0 -14
  78. data/lib/nanoc/filters/old.rb +0 -19
  79. data/lib/nanoc/filters/rainpress.rb +0 -13
  80. data/lib/nanoc/filters/rdiscount.rb +0 -13
  81. data/lib/nanoc/filters/rdoc.rb +0 -23
  82. data/lib/nanoc/filters/redcloth.rb +0 -14
  83. data/lib/nanoc/filters/relativize_paths.rb +0 -16
  84. data/lib/nanoc/filters/relativize_paths_in_css.rb +0 -16
  85. data/lib/nanoc/filters/relativize_paths_in_html.rb +0 -16
  86. data/lib/nanoc/filters/rubypants.rb +0 -14
  87. data/lib/nanoc/filters/sass.rb +0 -18
  88. data/lib/nanoc/helpers.rb +0 -9
  89. data/lib/nanoc/helpers/blogging.rb +0 -217
  90. data/lib/nanoc/helpers/capturing.rb +0 -63
  91. data/lib/nanoc/helpers/filtering.rb +0 -54
  92. data/lib/nanoc/helpers/html_escape.rb +0 -25
  93. data/lib/nanoc/helpers/link_to.rb +0 -113
  94. data/lib/nanoc/helpers/render.rb +0 -49
  95. data/lib/nanoc/helpers/tagging.rb +0 -56
  96. data/lib/nanoc/helpers/text.rb +0 -38
  97. data/lib/nanoc/helpers/xml_sitemap.rb +0 -63
  98. data/lib/nanoc/routers.rb +0 -3
  99. data/lib/nanoc/routers/default.rb +0 -54
  100. data/lib/nanoc/routers/no_dirs.rb +0 -66
  101. data/lib/nanoc/routers/versioned.rb +0 -79
  102. data/vendor/cri/ChangeLog +0 -0
  103. data/vendor/cri/LICENSE +0 -19
  104. data/vendor/cri/NEWS +0 -0
  105. data/vendor/cri/README +0 -4
  106. data/vendor/cri/Rakefile +0 -25
  107. data/vendor/cri/lib/cri.rb +0 -12
  108. data/vendor/cri/lib/cri/base.rb +0 -153
  109. data/vendor/cri/lib/cri/command.rb +0 -104
  110. data/vendor/cri/lib/cri/core_ext.rb +0 -8
  111. data/vendor/cri/lib/cri/core_ext/string.rb +0 -41
  112. data/vendor/cri/lib/cri/option_parser.rb +0 -186
  113. data/vendor/cri/test/test_base.rb +0 -6
  114. data/vendor/cri/test/test_command.rb +0 -6
  115. data/vendor/cri/test/test_core_ext.rb +0 -21
  116. data/vendor/cri/test/test_option_parser.rb +0 -279
@@ -1,30 +0,0 @@
1
- module Nanoc
2
-
3
- # Nanoc::Defaults represent the default attributes for a given set of
4
- # objects in the site. It is basically a hash with an optional modification
5
- # time.
6
- class Defaults
7
-
8
- # Th site where this set of defaults belongs to.
9
- attr_accessor :site
10
-
11
- # A hash containing the default attributes.
12
- attr_reader :attributes
13
-
14
- # The time when this set of defaults was last modified.
15
- attr_reader :mtime
16
-
17
- # Creates a new set of defaults.
18
- #
19
- # +attributes+:: The hash containing the metadata that individual objects
20
- # will override.
21
- #
22
- # +mtime+:: The time when the defaults were last modified (optional).
23
- def initialize(attributes, mtime=nil)
24
- @attributes = attributes.clean
25
- @mtime = mtime
26
- end
27
-
28
- end
29
-
30
- end
@@ -1,93 +0,0 @@
1
- module Nanoc
2
-
3
- # Nanoc::Filter is responsible for filtering pages and textual assets
4
- # (binary assets are filtered using Nanoc::BinaryFilter). It is the
5
- # (abstract) superclass for all textual filters. Subclasses should override
6
- # the +run+ method.
7
- class Filter < Plugin
8
-
9
- # Deprecated
10
- EXTENSIONS_MAP = {}
11
-
12
- # Creates a new filter for the given object (page or asset) and site.
13
- #
14
- # +kind+:: The kind of object that is passed. Can be either +:page+ or
15
- # +:asset+.
16
- #
17
- # +obj_rep+:: A proxy for the page or asset representation (Nanoc::PageRep
18
- # or Nanoc::AssetRep) that should be compiled by this filter.
19
- #
20
- # +obj+:: A proxy for the page or asset's page (Nanoc::Page or
21
- # Nanoc::Asset).
22
- #
23
- # +site+:: The site (Nanoc::Site) this filter belongs to.
24
- #
25
- # +other_assigns+:: A hash containing other variables that should be made
26
- # available during filtering.
27
- def initialize(obj_rep, other_assigns={})
28
- # Determine kind
29
- @kind = obj_rep.is_a?(Nanoc::PageRep) ? :page : :asset
30
-
31
- # Set object
32
- @obj_rep = obj_rep
33
- @obj = (@kind == :page ? @obj_rep.page : @obj_rep.asset)
34
-
35
- # Set page/asset and page/asset reps
36
- if @kind == :page
37
- @page = @obj
38
- @page_rep = @obj_rep
39
- else
40
- @asset = @obj
41
- @asset_rep = @obj_rep
42
- end
43
-
44
- # Set site
45
- @site = @obj.site
46
-
47
- # Set other assigns
48
- @other_assigns = other_assigns
49
- end
50
-
51
- # Runs the filter. This method returns the filtered content.
52
- #
53
- # +content+:: The unprocessed content that should be filtered.
54
- #
55
- # Subclasses must implement this method.
56
- def run(content)
57
- raise NotImplementedError.new("Nanoc::Filter subclasses must implement #run")
58
- end
59
-
60
- # Returns a hash with data that should be available.
61
- def assigns
62
- @assigns ||= @other_assigns.merge({
63
- :_obj_rep => @obj_rep,
64
- :_obj => @obj,
65
- :page_rep => @kind == :page ? @page_rep.to_proxy : nil,
66
- :page => @kind == :page ? @page.to_proxy : nil,
67
- :asset_rep => @kind == :asset ? @asset_rep.to_proxy : nil,
68
- :asset => @kind == :asset ? @asset.to_proxy : nil,
69
- :pages => @site.pages.map { |obj| obj.to_proxy },
70
- :assets => @site.assets.map { |obj| obj.to_proxy },
71
- :layouts => @site.layouts.map { |obj| obj.to_proxy },
72
- :config => @site.config,
73
- :site => @site
74
- })
75
- end
76
-
77
- # Returns the filename associated with the item that is being filtered.
78
- # The returned filename is in the format "page <path> (rep <name>)".
79
- def filename
80
- if assigns[:layout]
81
- "layout #{assigns[:layout].path}"
82
- elsif assigns[:page]
83
- "page #{assigns[:_obj].path} (rep #{assigns[:_obj_rep].name})"
84
- elsif assigns[:asset]
85
- "asset #{assigns[:_obj].path} (rep #{assigns[:_obj_rep].name})"
86
- else
87
- '?'
88
- end
89
- end
90
-
91
- end
92
-
93
- end
@@ -1,91 +0,0 @@
1
- module Nanoc
2
-
3
- # A Nanoc::Layout represents a layout in a nanoc site. It has content,
4
- # attributes (for determining which filter to use for laying out a page), a
5
- # path (because layouts are organised hierarchically), and a modification
6
- # time (to speed up compilation).
7
- class Layout
8
-
9
- # Default values for layouts.
10
- DEFAULTS = {
11
- :filter => 'erb'
12
- }
13
-
14
- # The Nanoc::Site this layout belongs to.
15
- attr_accessor :site
16
-
17
- # The raw content of this layout.
18
- attr_reader :content
19
-
20
- # A hash containing this layout's attributes.
21
- attr_reader :attributes
22
-
23
- # This layout's path, starting and ending with a slash.
24
- attr_reader :path
25
-
26
- # The time when this layout was last modified.
27
- attr_reader :mtime
28
-
29
- # Creates a new layout.
30
- #
31
- # +content+:: The raw content of this layout.
32
- #
33
- # +attributes+:: A hash containing this layout's attributes.
34
- #
35
- # +path+:: This layout's path, starting and ending with a slash.
36
- #
37
- # +mtime+:: The time when this layout was last modified.
38
- def initialize(content, attributes, path, mtime=nil)
39
- @content = content
40
- @attributes = attributes.clean
41
- @path = path.cleaned_path
42
- @mtime = mtime
43
- end
44
-
45
- # Returns a proxy (Nanoc::LayoutProxy) for this layout.
46
- def to_proxy
47
- @proxy ||= LayoutProxy.new(self)
48
- end
49
-
50
- # Returns the attribute with the given name.
51
- def attribute_named(name)
52
- return @attributes[name] if @attributes.has_key?(name)
53
- return DEFAULTS[name]
54
- end
55
-
56
- # Returns the filter class needed for this layout.
57
- def filter_class
58
- Nanoc::Filter.named(attribute_named(:filter))
59
- end
60
-
61
- # Saves the layout in the database, creating it if it doesn't exist yet or
62
- # updating it if it already exists. Tells the site's data source to save
63
- # the layout.
64
- def save
65
- @site.data_source.loading do
66
- @site.data_source.save_layout(self)
67
- end
68
- end
69
-
70
- # Moves the layout to a new path. Tells the site's data source to move the
71
- # layout.
72
- def move_to(new_path)
73
- @site.data_source.loading do
74
- @site.data_source.move_layout(self, new_path)
75
- end
76
- end
77
-
78
- # Deletes the layout. Tells the site's data source to delete the layout.
79
- def delete
80
- @site.data_source.loading do
81
- @site.data_source.delete_layout(self)
82
- end
83
- end
84
-
85
- def inspect
86
- "<#{self.class} path=#{self.path}>"
87
- end
88
-
89
- end
90
-
91
- end
@@ -1,66 +0,0 @@
1
- module Nanoc
2
-
3
- # Nanoc::NotificationCenter provides a way to send notifications between
4
- # objects. It allows blocks associated with a certain notification name to
5
- # be registered; these blocks will be called when the notification with the
6
- # given name is posted.
7
- #
8
- # It is a slightly different implementation of the Observer pattern; the
9
- # table of subscribers is not stored in the observable object itself, but in
10
- # the notification center.
11
- class NotificationCenter
12
-
13
- class << self
14
-
15
- # Adds the given block to the list of blocks that should be called when
16
- # the notification with the given name is received.
17
- #
18
- # +name+:: The name of the notification that will be posted.
19
- #
20
- # +id+:: An identifier for the block. This is only used to be able to
21
- # remove the block (using the remove method) later. Defaults to
22
- # nil.
23
- def on(name, id=nil, &block)
24
- initialize_if_necessary(name)
25
-
26
- # Add observer
27
- @notifications[name] << { :id => id, :block => block }
28
- end
29
-
30
- # Posts a notification with the given name. All arguments wil be passed
31
- # to the blocks handling the notification.
32
- def post(name, *args)
33
- initialize_if_necessary(name)
34
-
35
- # Notify all observers
36
- @notifications[name].each do |observer|
37
- observer[:block].call(*args)
38
- end
39
- end
40
-
41
- # Removes the block with the given identifier from the list of blocks
42
- # that should be called when the notification with the given name is
43
- # posted.
44
- #
45
- # +name+:: The name of the notification that will be posted.
46
- #
47
- # +id+:: The identifier of the block that should be removed.
48
- def remove(name, id)
49
- initialize_if_necessary(name)
50
-
51
- # Remove relevant observers
52
- @notifications[name].reject! { |i| i[:id] == id }
53
- end
54
-
55
- private
56
-
57
- def initialize_if_necessary(name)
58
- @notifications ||= {} # name => observers dictionary
59
- @notifications[name] ||= [] # list of observers
60
- end
61
-
62
- end
63
-
64
- end
65
-
66
- end
@@ -1,132 +0,0 @@
1
- module Nanoc
2
-
3
- # A Nanoc::Page represents a page in a nanoc site. It has content and
4
- # attributes, as well as a path. It can also store the modification time to
5
- # speed up compilation.
6
- #
7
- # Each page has a list of page representations or reps (Nanoc::PageRep);
8
- # compiling a page actually compiles all of its representations.
9
- class Page
10
-
11
- # Default values for pages.
12
- DEFAULTS = {
13
- :custom_path => nil,
14
- :extension => 'html',
15
- :filename => 'index',
16
- :filters_pre => [],
17
- :filters_post => [],
18
- :layout => 'default',
19
- :skip_output => false
20
- }
21
-
22
- # The Nanoc::Site this page belongs to.
23
- attr_accessor :site
24
-
25
- # The parent page of this page. This can be nil even for non-root pages.
26
- attr_accessor :parent
27
-
28
- # The child pages of this page.
29
- attr_accessor :children
30
-
31
- # This page's raw, uncompiled content.
32
- attr_reader :content
33
-
34
- # A hash containing this page's attributes.
35
- attr_accessor :attributes
36
-
37
- # This page's path.
38
- attr_reader :path
39
-
40
- # The time when this page was last modified.
41
- attr_reader :mtime
42
-
43
- # This page's list of page representations.
44
- attr_reader :reps
45
-
46
- # Creates a new page.
47
- #
48
- # +content+:: This page's unprocessed content.
49
- #
50
- # +attributes+:: A hash containing this page's attributes.
51
- #
52
- # +path+:: This page's path.
53
- #
54
- # +mtime+:: The time when this page was last modified.
55
- def initialize(content, attributes, path, mtime=nil)
56
- # Set primary attributes
57
- @attributes = attributes.clean
58
- @content = content
59
- @path = path.cleaned_path
60
- @mtime = mtime
61
-
62
- # Start disconnected
63
- @parent = nil
64
- @children = []
65
- @reps = []
66
- end
67
-
68
- # Builds the individual page representations (Nanoc::PageRep) for this
69
- # page.
70
- def build_reps
71
- # Get list of rep names
72
- rep_names_default = (@site.page_defaults.attributes[:reps] || {}).keys
73
- rep_names_this = (@attributes[:reps] || {}).keys + [ :default ]
74
- rep_names = rep_names_default | rep_names_this
75
-
76
- # Get list of reps
77
- reps = rep_names.inject({}) do |memo, rep_name|
78
- rep = (@attributes[:reps] || {})[rep_name]
79
- is_bad = (@attributes[:reps] || {}).has_key?(rep_name) && rep.nil?
80
- is_bad ? memo : memo.merge(rep_name => rep || {})
81
- end
82
-
83
- # Build reps
84
- @reps = []
85
- reps.each_pair do |name, attrs|
86
- @reps << PageRep.new(self, attrs, name)
87
- end
88
- end
89
-
90
- # Returns a proxy (Nanoc::PageProxy) for this page.
91
- def to_proxy
92
- @proxy ||= PageProxy.new(self)
93
- end
94
-
95
- # Returns the attribute with the given name.
96
- def attribute_named(name)
97
- return @attributes[name] if @attributes.has_key?(name)
98
- return @site.page_defaults.attributes[name] if @site.page_defaults.attributes.has_key?(name)
99
- return DEFAULTS[name]
100
- end
101
-
102
- # Saves the page in the database, creating it if it doesn't exist yet or
103
- # updating it if it already exists. Tells the site's data source to save
104
- # the page.
105
- def save
106
- @site.data_source.loading do
107
- @site.data_source.save_page(self)
108
- end
109
- end
110
-
111
- # Moves the page to a new path. Tells the site's data source to move the
112
- # page.
113
- def move_to(new_path)
114
- @site.data_source.loading do
115
- @site.data_source.move_page(self, new_path)
116
- end
117
- end
118
-
119
- # Deletes the page. Tells the site's data source to delete the page.
120
- def delete
121
- @site.data_source.loading do
122
- @site.data_source.delete_page(self)
123
- end
124
- end
125
-
126
- def inspect
127
- "<#{self.class} path=#{self.path}>"
128
- end
129
-
130
- end
131
-
132
- end
@@ -1,20 +0,0 @@
1
- module Nanoc
2
-
3
- # Nanoc::PageDefaults represent the default attributes for all pages in the
4
- # site. If a specific page attribute is requested, but not found, then the
5
- # page defaults will be queried for this attribute. (If the attribute
6
- # doesn't even exist in the page defaults, hardcoded defaults will be used.)
7
- class PageDefaults < Defaults
8
-
9
- # Saves the page defaults in the database, creating it if it doesn't exist
10
- # yet or updating it if it already exists. Tells the site's data source to
11
- # save the page defaults.
12
- def save
13
- @site.data_source.loading do
14
- @site.data_source.save_page_defaults(self)
15
- end
16
- end
17
-
18
- end
19
-
20
- end
@@ -1,324 +0,0 @@
1
- module Nanoc
2
-
3
- # A Nanoc::PageRep is a single representation (rep) of a page (Nanoc::Page).
4
- # A page can have multiple representations. A representation has its own
5
- # attributes and its own output file. A single page can therefore have
6
- # multiple output files, each run through a different set of filters with a
7
- # different layout.
8
- #
9
- # A page representation is observable. The following events will be
10
- # notified:
11
- #
12
- # * :compilation_started
13
- # * :compilation_ended
14
- # * :filtering_started
15
- # * :filtering_ended
16
- #
17
- # The compilation-related events have one parameters (the page
18
- # representation); the filtering-related events have two (the page
19
- # representation, and a symbol containing the filter class name).
20
- class PageRep
21
-
22
- # The page (Nanoc::Page) to which this representation belongs.
23
- attr_reader :page
24
-
25
- # A hash containing this page representation's attributes.
26
- attr_accessor :attributes
27
-
28
- # This page representation's unique name.
29
- attr_reader :name
30
-
31
- # Creates a new page representation for the given page and with the given
32
- # attributes.
33
- #
34
- # +page+:: The page (Nanoc::Page) to which the new representation will
35
- # belong.
36
- #
37
- # +attributes+:: A hash containing the new page representation's
38
- # attributes. This hash must have been run through
39
- # Hash#clean before using it here.
40
- #
41
- # +name+:: The unique name for the new page representation.
42
- def initialize(page, attributes, name)
43
- # Set primary attributes
44
- @page = page
45
- @attributes = attributes
46
- @name = name
47
-
48
- # Get page content from page
49
- @content = { :pre => nil, :post => nil }
50
-
51
- # Reset flags
52
- @compiled = false
53
- @modified = false
54
- @created = false
55
- end
56
-
57
- # Returns a proxy (Nanoc::PageRepProxy) for this page representation.
58
- def to_proxy
59
- @proxy ||= PageRepProxy.new(self)
60
- end
61
-
62
- # Returns true if this page rep's output file was created during the last
63
- # compilation session, or false if the output file did already exist.
64
- def created?
65
- @created
66
- end
67
-
68
- # Returns true if this page rep's output file was modified during the last
69
- # compilation session, or false if the output file wasn't changed.
70
- def modified?
71
- @modified
72
- end
73
-
74
- # Returns true if this page rep has been compiled, false otherwise.
75
- def compiled?
76
- @compiled
77
- end
78
-
79
- # Returns true if this page rep's output file is outdated and must be
80
- # regenerated, false otherwise.
81
- def outdated?
82
- # Outdated if we don't know
83
- return true if @page.mtime.nil?
84
-
85
- # Outdated if compiled file doesn't exist
86
- return true if !File.file?(disk_path)
87
-
88
- # Get compiled mtime
89
- compiled_mtime = File.stat(disk_path).mtime
90
-
91
- # Outdated if file too old
92
- return true if @page.mtime > compiled_mtime
93
-
94
- # Outdated if layouts outdated
95
- return true if @page.site.layouts.any? do |l|
96
- l.mtime.nil? or l.mtime > compiled_mtime
97
- end
98
-
99
- # Outdated if page defaults outdated
100
- return true if @page.site.page_defaults.mtime.nil?
101
- return true if @page.site.page_defaults.mtime > compiled_mtime
102
-
103
- # Outdated if code outdated
104
- return true if @page.site.code.mtime.nil?
105
- return true if @page.site.code.mtime > compiled_mtime
106
-
107
- return false
108
- end
109
-
110
- # Returns the path to the output file, including the path to the output
111
- # directory specified in the site configuration, and including the
112
- # filename and extension.
113
- def disk_path
114
- @disk_path ||= @page.site.router.disk_path_for(self)
115
- end
116
-
117
- # Returns the path to the output file as it would be used in a web
118
- # browser: starting with a slash (representing the web root), and only
119
- # including the filename and extension if they cannot be ignored (i.e.
120
- # they are not in the site configuration's list of index files).
121
- def web_path
122
- @web_path ||= @page.site.router.web_path_for(self)
123
- end
124
-
125
- # Returns the attribute with the given name. This method will look in
126
- # several places for the requested attribute:
127
- #
128
- # 1. This page representation's attributes;
129
- # 2. The attributes of this page representation's page;
130
- # 3. The page defaults' representation corresponding to this page
131
- # representation;
132
- # 4. The page defaults in general;
133
- # 5. The hardcoded page defaults, if everything else fails.
134
- def attribute_named(name)
135
- # Check in here
136
- return @attributes[name] if @attributes.has_key?(name)
137
-
138
- # Check in page
139
- return @page.attributes[name] if @page.attributes.has_key?(name)
140
-
141
- # Check in page defaults' page rep
142
- page_default_reps = @page.site.page_defaults.attributes[:reps] || {}
143
- page_default_rep = page_default_reps[@name] || {}
144
- return page_default_rep[name] if page_default_rep.has_key?(name)
145
-
146
- # Check in site defaults (global)
147
- page_defaults_attrs = @page.site.page_defaults.attributes
148
- return page_defaults_attrs[name] if page_defaults_attrs.has_key?(name)
149
-
150
- # Check in hardcoded defaults
151
- return Nanoc::Page::DEFAULTS[name]
152
- end
153
-
154
- # Returns the page representation content at the given stage.
155
- #
156
- # +stage+:: The stage at which the content should be fetched. Can be
157
- # either +:pre+ or +:post+. To get the raw, uncompiled content,
158
- # use Nanoc::Page#content.
159
- def content(stage=:pre)
160
- compile(stage == :post, true, false)
161
-
162
- @content[stage]
163
- end
164
-
165
- # Returns the layout used for this page representation.
166
- def layout
167
- # Check whether layout is present
168
- return nil if attribute_named(:layout).nil?
169
-
170
- # Find layout
171
- @layout ||= @page.site.layouts.find { |l| l.path == attribute_named(:layout).cleaned_path }
172
- raise Nanoc::Errors::UnknownLayoutError.new(attribute_named(:layout)) if @layout.nil?
173
-
174
- @layout
175
- end
176
-
177
- # Compiles the page representation and writes the result to the disk. This
178
- # method should not be called directly; please use Nanoc::Compiler#run
179
- # instead, and pass this page representation's page as its first argument.
180
- #
181
- # The page representation will only be compiled if it wasn't compiled
182
- # before yet. To force recompilation of the page rep, forgetting any
183
- # progress, set +from_scratch+ to true.
184
- #
185
- # +also_layout+:: true if the page rep should also be laid out and
186
- # post-filtered, false if the page rep should only be
187
- # pre-filtered.
188
- #
189
- # +even_when_not_outdated+:: true if the page rep should be compiled even
190
- # if it is not outdated, false if not.
191
- #
192
- # +from_scratch+:: true if all compilation stages (pre-filter, layout,
193
- # post-filter) should be performed again even if they
194
- # have already been performed, false otherwise.
195
- def compile(also_layout, even_when_not_outdated, from_scratch)
196
- # Don't compile if already compiled
197
- return if @content[also_layout ? :post : :pre] and !from_scratch
198
-
199
- # Skip unless outdated
200
- unless outdated? or even_when_not_outdated
201
- if also_layout
202
- Nanoc::NotificationCenter.post(:compilation_started, self)
203
- Nanoc::NotificationCenter.post(:compilation_ended, self)
204
- end
205
- return
206
- end
207
-
208
- # Reset flags
209
- @compiled = false
210
- @modified = false
211
- @created = false
212
-
213
- # Forget progress if requested
214
- @content = { :pre => nil, :post => nil } if from_scratch
215
-
216
- # Check for recursive call
217
- if @page.site.compiler.stack.include?(self)
218
- @page.site.compiler.stack.push(self)
219
- raise Nanoc::Errors::RecursiveCompilationError.new
220
- end
221
-
222
- # Start
223
- @page.site.compiler.stack.push(self)
224
- Nanoc::NotificationCenter.post(:compilation_started, self) if also_layout
225
-
226
- # Pre-filter if necesary
227
- if @content[:pre].nil?
228
- do_filter(:pre)
229
- end
230
-
231
- # Post-filter if necessary
232
- if @content[:post].nil? and also_layout
233
- do_layout
234
- do_filter(:post)
235
-
236
- # Update status
237
- @compiled = true
238
- unless attribute_named(:skip_output)
239
- @created = !File.file?(self.disk_path)
240
- @modified = @created ? true : File.read(self.disk_path) != @content[:post]
241
- end
242
-
243
- # Write if necessary
244
- write unless attribute_named(:skip_output)
245
- end
246
-
247
- # Stop
248
- Nanoc::NotificationCenter.post(:compilation_ended, self) if also_layout
249
- @page.site.compiler.stack.pop
250
- end
251
-
252
- private
253
-
254
- # Runs the content through the filters in the given stage.
255
- def do_filter(stage)
256
- # Get content if necessary
257
- content = (stage == :pre ? @page.content : @content[:post])
258
-
259
- # Get filters
260
- check_for_outdated_filters
261
- filters = attribute_named(stage == :pre ? :filters_pre : :filters_post)
262
-
263
- # Run each filter
264
- filters.each do |filter_name|
265
- # Create filter
266
- klass = Nanoc::Filter.named(filter_name)
267
- raise Nanoc::Errors::UnknownFilterError.new(filter_name) if klass.nil?
268
- filter = klass.new(self)
269
-
270
- # Run filter
271
- Nanoc::NotificationCenter.post(:filtering_started, self, klass.identifier)
272
- content = filter.run(content)
273
- # FIXME hacky
274
- content.force_encoding('utf-8') if content.respond_to?(:'force_encoding')
275
- Nanoc::NotificationCenter.post(:filtering_ended, self, klass.identifier)
276
- end
277
-
278
- # Set content
279
- @content[stage] = content
280
- end
281
-
282
- # Runs the content through this rep's layout.
283
- def do_layout
284
- # Don't layout if not necessary
285
- if attribute_named(:layout).nil?
286
- @content[:post] = @content[:pre]
287
- return
288
- end
289
-
290
- # Create filter
291
- klass = layout.filter_class
292
- raise Nanoc::Errors::CannotDetermineFilterError.new(layout.path) if klass.nil?
293
- filter = klass.new(self, :layout => layout.to_proxy)
294
-
295
- # Layout
296
- Nanoc::NotificationCenter.post(:filtering_started, self, klass.identifier)
297
- @content[:post] = filter.run(layout.content)
298
- Nanoc::NotificationCenter.post(:filtering_ended, self, klass.identifier)
299
- end
300
-
301
- # Writes the compiled content to the disk.
302
- def write
303
- # TODO add ruby 1.9 support
304
- FileUtils.mkdir_p(File.dirname(self.disk_path))
305
- File.open(self.disk_path, 'w') { |io| io.write(@content[:post]) }
306
- end
307
-
308
- # Raises an error when the outdated 'filters' attribute is used.
309
- def check_for_outdated_filters
310
- unless attribute_named(:filters).nil?
311
- raise Nanoc::Errors::NoLongerSupportedError.new(
312
- 'The `filters` property is no longer supported; please use ' +
313
- '`filters_pre` instead.'
314
- )
315
- end
316
- end
317
-
318
- def inspect
319
- "<#{self.class} name=#{self.name} page.path=#{self.page.path}>"
320
- end
321
-
322
- end
323
-
324
- end