nanoc 2.0.4 → 2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. data/ChangeLog +31 -1
  2. data/LICENSE +1 -1
  3. data/README +63 -3
  4. data/Rakefile +59 -12
  5. data/bin/nanoc +7 -199
  6. data/lib/nanoc.rb +83 -12
  7. data/lib/nanoc/base/asset.rb +113 -0
  8. data/lib/nanoc/base/asset_defaults.rb +21 -0
  9. data/lib/nanoc/base/asset_rep.rb +277 -0
  10. data/lib/nanoc/base/binary_filter.rb +44 -0
  11. data/lib/nanoc/base/code.rb +41 -0
  12. data/lib/nanoc/base/compiler.rb +46 -34
  13. data/lib/nanoc/base/core_ext/hash.rb +51 -7
  14. data/lib/nanoc/base/core_ext/string.rb +8 -0
  15. data/lib/nanoc/base/data_source.rb +253 -20
  16. data/lib/nanoc/base/defaults.rb +30 -0
  17. data/lib/nanoc/base/enhancements.rb +9 -84
  18. data/lib/nanoc/base/filter.rb +109 -6
  19. data/lib/nanoc/base/layout.rb +91 -0
  20. data/lib/nanoc/base/notification_center.rb +66 -0
  21. data/lib/nanoc/base/page.rb +94 -126
  22. data/lib/nanoc/base/page_defaults.rb +20 -0
  23. data/lib/nanoc/base/page_rep.rb +318 -0
  24. data/lib/nanoc/base/plugin.rb +57 -9
  25. data/lib/nanoc/base/proxies/asset_proxy.rb +29 -0
  26. data/lib/nanoc/base/proxies/asset_rep_proxy.rb +26 -0
  27. data/lib/nanoc/base/proxies/layout_proxy.rb +25 -0
  28. data/lib/nanoc/base/proxies/page_proxy.rb +35 -0
  29. data/lib/nanoc/base/proxies/page_rep_proxy.rb +28 -0
  30. data/lib/nanoc/base/proxy.rb +37 -0
  31. data/lib/nanoc/base/router.rb +72 -0
  32. data/lib/nanoc/base/site.rb +219 -88
  33. data/lib/nanoc/base/template.rb +64 -0
  34. data/lib/nanoc/binary_filters/image_science_thumbnail.rb +28 -0
  35. data/lib/nanoc/cli.rb +1 -0
  36. data/lib/nanoc/cli/base.rb +219 -0
  37. data/lib/nanoc/cli/cli.rb +16 -0
  38. data/lib/nanoc/cli/command.rb +105 -0
  39. data/lib/nanoc/cli/commands/autocompile.rb +80 -0
  40. data/lib/nanoc/cli/commands/compile.rb +273 -0
  41. data/lib/nanoc/cli/commands/create_layout.rb +85 -0
  42. data/lib/nanoc/cli/commands/create_page.rb +85 -0
  43. data/lib/nanoc/cli/commands/create_site.rb +327 -0
  44. data/lib/nanoc/cli/commands/create_template.rb +76 -0
  45. data/lib/nanoc/cli/commands/help.rb +69 -0
  46. data/lib/nanoc/cli/commands/info.rb +114 -0
  47. data/lib/nanoc/cli/commands/switch.rb +141 -0
  48. data/lib/nanoc/cli/commands/update.rb +91 -0
  49. data/lib/nanoc/cli/ext.rb +37 -0
  50. data/lib/nanoc/cli/logger.rb +66 -0
  51. data/lib/nanoc/cli/option_parser.rb +168 -0
  52. data/lib/nanoc/data_sources/filesystem.rb +645 -224
  53. data/lib/nanoc/data_sources/filesystem_combined.rb +495 -0
  54. data/lib/nanoc/extra/auto_compiler.rb +265 -0
  55. data/lib/nanoc/extra/context.rb +22 -0
  56. data/lib/nanoc/extra/core_ext/hash.rb +54 -0
  57. data/lib/nanoc/extra/core_ext/time.rb +13 -0
  58. data/lib/nanoc/extra/file_proxy.rb +29 -0
  59. data/lib/nanoc/extra/vcs.rb +48 -0
  60. data/lib/nanoc/extra/vcses/bazaar.rb +21 -0
  61. data/lib/nanoc/extra/vcses/dummy.rb +20 -0
  62. data/lib/nanoc/extra/vcses/git.rb +21 -0
  63. data/lib/nanoc/extra/vcses/mercurial.rb +21 -0
  64. data/lib/nanoc/extra/vcses/subversion.rb +21 -0
  65. data/lib/nanoc/filters/bluecloth.rb +13 -0
  66. data/lib/nanoc/filters/erb.rb +6 -22
  67. data/lib/nanoc/filters/erubis.rb +14 -0
  68. data/lib/nanoc/filters/haml.rb +7 -23
  69. data/lib/nanoc/filters/markaby.rb +5 -5
  70. data/lib/nanoc/filters/maruku.rb +14 -0
  71. data/lib/nanoc/filters/old.rb +19 -0
  72. data/lib/nanoc/filters/rdiscount.rb +13 -0
  73. data/lib/nanoc/filters/rdoc.rb +5 -4
  74. data/lib/nanoc/filters/redcloth.rb +14 -0
  75. data/lib/nanoc/filters/rubypants.rb +14 -0
  76. data/lib/nanoc/filters/sass.rb +13 -0
  77. data/lib/nanoc/helpers/blogging.rb +170 -0
  78. data/lib/nanoc/helpers/capturing.rb +59 -0
  79. data/lib/nanoc/helpers/html_escape.rb +23 -0
  80. data/lib/nanoc/helpers/link_to.rb +69 -0
  81. data/lib/nanoc/helpers/render.rb +47 -0
  82. data/lib/nanoc/helpers/tagging.rb +52 -0
  83. data/lib/nanoc/helpers/xml_sitemap.rb +58 -0
  84. data/lib/nanoc/routers/default.rb +54 -0
  85. data/lib/nanoc/routers/no_dirs.rb +66 -0
  86. data/lib/nanoc/routers/versioned.rb +79 -0
  87. metadata +112 -22
  88. data/lib/nanoc/base/auto_compiler.rb +0 -132
  89. data/lib/nanoc/base/layout_processor.rb +0 -33
  90. data/lib/nanoc/base/page_proxy.rb +0 -31
  91. data/lib/nanoc/base/plugin_manager.rb +0 -33
  92. data/lib/nanoc/data_sources/database.rb +0 -259
  93. data/lib/nanoc/data_sources/trivial.rb +0 -145
  94. data/lib/nanoc/filters/markdown.rb +0 -13
  95. data/lib/nanoc/filters/smartypants.rb +0 -13
  96. data/lib/nanoc/filters/textile.rb +0 -13
  97. data/lib/nanoc/layout_processors/erb.rb +0 -35
  98. data/lib/nanoc/layout_processors/haml.rb +0 -38
  99. data/lib/nanoc/layout_processors/markaby.rb +0 -16
@@ -0,0 +1,30 @@
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,89 +1,14 @@
1
- # Get requirements
2
- begin ; require 'rubygems' ; rescue LoadError ; end
3
- require 'yaml'
4
- require 'fileutils'
5
-
6
- # Logging (level can be :off, :high, :low)
7
- $log_level = :high
8
- def log(log_level, s, io=$stdout)
9
- io.puts s if ($log_level == :low or $log_level == log_level) and $log_level != :off
1
+ # Convenience function for printing warnings
2
+ def warn(s, pre='WARNING')
3
+ $stderr.puts "#{pre}: #{s}"
10
4
  end
11
5
 
12
- # Convenience function for printing errors
13
- def error(s, pre='ERROR')
14
- log(:high, pre + ': ' + s, $stderr)
15
- exit(1)
16
- end
6
+ ############################# OLD AND DEPRECATED #############################
17
7
 
18
- # Convenience function for requiring libraries
19
- def nanoc_require(x, message="'#{x}' is required to compile this site.")
8
+ def nanoc_require(x)
9
+ warn(
10
+ "'nanoc_require' is deprecated and will be removed in a future version. Please use 'require' instead.",
11
+ 'DEPRECATION WARNING'
12
+ )
20
13
  require x
21
- rescue LoadError
22
- error(message)
23
- end
24
-
25
- # Rendering sub-layouts
26
- def render(name, other_assigns={})
27
- layout = @site.layouts.find { |l| l[:name] == name }
28
- layout_processor_class = Nanoc::PluginManager.layout_processor_for_extension(layout[:extension])
29
- layout_processor = layout_processor_class.new(@page, @pages, @site.config, @site, other_assigns)
30
- layout_processor.run(layout[:content])
31
- end
32
-
33
- # Convenience function for cd'ing in and out of a directory
34
- def in_dir(path)
35
- FileUtils.cd(File.join(path))
36
- yield
37
- ensure
38
- FileUtils.cd(File.join(path.map { |n| '..' }))
39
- end
40
-
41
- class FileManager
42
-
43
- ACTION_COLORS = {
44
- :create => "\e[1m" + "\e[32m", # bold + green
45
- :update => "\e[1m" + "\e[33m", # bold + yellow
46
- :identical => "\e[1m" # bold
47
- }
48
-
49
- def self.file_log(log_level, action, path)
50
- log(log_level, '%s%12s%s %s' % [ACTION_COLORS[action.to_sym], action, "\e[0m", path])
51
- end
52
-
53
- def self.create_dir(name)
54
- # Check whether directory exists
55
- return if File.exist?(name)
56
-
57
- # Create dir
58
- FileUtils.mkdir_p(name)
59
- log(:create, name)
60
- end
61
-
62
- def self.create_file(path)
63
- # Create parent directory if necessary
64
- if path =~ /\//
65
- parent_path = path.sub(/\/[^\/]+$/, '')
66
- FileManager.create_dir(parent_path)
67
- end
68
-
69
- # Get contents
70
- content_old = File.exist?(path) ? File.read(path) : nil
71
- content_new = yield
72
- content_new = content_new.force_encoding(content_old.encoding) if content_old and String.method_defined?(:force_encoding)
73
- modified = (content_old != content_new)
74
-
75
- # Log
76
- if File.exist?(path)
77
- file_log(*(modified ? [ :high, :update, path ] : [ :low, :identical, path ]))
78
- else
79
- file_log(:high, :create, path)
80
- end
81
-
82
- # Write
83
- open(path, 'w') { |io| io.write(content_new) }
84
-
85
- # Report back
86
- modified
87
- end
88
-
89
14
  end
@@ -1,16 +1,119 @@
1
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.
2
7
  class Filter < Plugin
3
8
 
4
- def initialize(page, pages, config, site)
5
- @page = page
6
- @pages = pages
7
- @config = config
8
- @site = site
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
9
49
  end
10
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.
11
56
  def run(content)
12
- error 'Filter#run must be overridden'
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
+ class << self
78
+
79
+ # Deprecated
80
+ def extensions(*extensions) # :nodoc:
81
+ # Initialize
82
+ @extensions = [] unless instance_variables.include?('@extensions')
83
+
84
+ if extensions.empty?
85
+ @extensions
86
+ else
87
+ @extensions = extensions
88
+ @extensions.each { |e| register_extension(e, self) }
89
+ end
90
+ end
91
+
92
+ # Deprecated
93
+ def extension(extension=nil) # :nodoc:
94
+ # Initialize
95
+ @extensions = [] unless instance_variables.include?('@extensions')
96
+
97
+ if extension.nil?
98
+ @extensions.first
99
+ else
100
+ @extensions = [ extension ]
101
+ register_extension(extension, self)
102
+ end
103
+ end
104
+
105
+ # Deprecated
106
+ def register_extension(extension, klass)
107
+ EXTENSIONS_MAP[extension] = klass
108
+ end
109
+
110
+ # Deprecated
111
+ def with_extension(extension)
112
+ EXTENSIONS_MAP[extension]
113
+ end
114
+
13
115
  end
14
116
 
15
117
  end
118
+
16
119
  end
@@ -0,0 +1,91 @@
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
+ if attribute_named(:extension).nil?
59
+ Nanoc::Filter.named(attribute_named(:filter))
60
+ else
61
+ Nanoc::Filter.with_extension(attribute_named(:extension))
62
+ end
63
+ end
64
+
65
+ # Saves the layout in the database, creating it if it doesn't exist yet or
66
+ # updating it if it already exists. Tells the site's data source to save
67
+ # the layout.
68
+ def save
69
+ @site.data_source.loading do
70
+ @site.data_source.save_layout(self)
71
+ end
72
+ end
73
+
74
+ # Moves the layout to a new path. Tells the site's data source to move the
75
+ # layout.
76
+ def move_to(new_path)
77
+ @site.data_source.loading do
78
+ @site.data_source.move_layout(self, new_path)
79
+ end
80
+ end
81
+
82
+ # Deletes the layout. Tells the site's data source to delete the layout.
83
+ def delete
84
+ @site.data_source.loading do
85
+ @site.data_source.delete_layout(self)
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,66 @@
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,160 +1,128 @@
1
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.
2
9
  class Page
3
10
 
4
- PAGE_DEFAULTS = {
11
+ # Default values for pages.
12
+ DEFAULTS = {
5
13
  :custom_path => nil,
6
14
  :extension => 'html',
7
15
  :filename => 'index',
8
16
  :filters_pre => [],
9
17
  :filters_post => [],
10
- :haml_options => {},
11
- :is_draft => false,
12
18
  :layout => 'default',
13
- :path => nil,
14
19
  :skip_output => false
15
20
  }
16
21
 
17
- attr_reader :attributes
18
- attr_accessor :parent, :children
19
-
20
- def initialize(hash, site)
21
- @site = site
22
- @compiler = site.compiler
23
-
24
- @attributes = hash
25
- @content = { :pre => attribute_named(:uncompiled_content), :post => nil }
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
26
67
 
27
- @parent = nil
28
- @children = []
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
29
82
 
30
- @filtered_pre = false
31
- @layouted = false
32
- @filtered_post = false
33
- @written = false
83
+ # Build reps
84
+ @reps = []
85
+ reps.each_pair do |name, attrs|
86
+ @reps << PageRep.new(self, attrs, name)
87
+ end
34
88
  end
35
89
 
36
- # Proxy support
37
-
90
+ # Returns a proxy (Nanoc::PageProxy) for this page.
38
91
  def to_proxy
39
92
  @proxy ||= PageProxy.new(self)
40
93
  end
41
94
 
42
- # Accessors, kind of
43
-
44
- def modified? ; @modified ; end
45
-
95
+ # Returns the attribute with the given name.
46
96
  def attribute_named(name)
47
- return @attributes[name] if @attributes.has_key?(name)
48
- return @site.page_defaults[name] if @site.page_defaults.has_key?(name)
49
- return PAGE_DEFAULTS[name]
50
- end
51
-
52
- def content
53
- compile(false) unless @filtered_pre
54
- @content[:pre]
55
- end
56
-
57
- def layouted_content
58
- compile(true)
59
- @content[:post]
60
- end
61
-
62
- def skip_output?
63
- attribute_named(:skip_output)
64
- end
65
-
66
- def path
67
- attribute_named(:custom_path) || attribute_named(:path)
68
- end
69
-
70
- def path_on_filesystem
71
- if attribute_named(:custom_path).nil?
72
- @site.config[:output_dir] + attribute_named(:path) +
73
- attribute_named(:filename) + '.' + attribute_named(:extension)
74
- else
75
- @site.config[:output_dir] + attribute_named(:custom_path)
76
- end
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]
77
100
  end
78
101
 
79
- # Compiling
80
-
81
- def compile(full=true)
82
- @modified = false
83
-
84
- # Check for recursive call
85
- if @compiler.stack.include?(self)
86
- log(:high, "\n" + 'ERROR: Recursive call to page content. Page filter stack:', $stderr)
87
- log(:high, " - #{self.attribute_named(:path)}", $stderr)
88
- @compiler.stack.each_with_index do |page, i|
89
- log(:high, " - #{page.attribute_named(:path)}", $stderr)
90
- end
91
- exit(1)
92
- end
93
-
94
- @compiler.stack.push(self)
95
-
96
- # Filter pre
97
- unless @filtered_pre
98
- filter(:pre)
99
- @filtered_pre = true
100
- end
101
-
102
- # Layout
103
- if !@layouted and full
104
- layout
105
- @layouted = true
106
- end
107
-
108
- # Filter post
109
- if !@filtered_post and full
110
- filter(:post)
111
- @filtered_post = true
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)
112
108
  end
113
-
114
- # Write
115
- if !@written and full
116
- @modified = FileManager.create_file(self.path_on_filesystem) { @content[:post] } unless skip_output?
117
- @written = true
118
- end
119
-
120
- @compiler.stack.pop
121
109
  end
122
110
 
123
- def filter(stage)
124
- # Get filters
125
- error 'The `filters` property is no longer supported; please use `filters_pre` instead.' unless attribute_named(:filters).nil?
126
- filters = attribute_named(stage == :pre ? :filters_pre : :filters_post)
127
-
128
- filters.each do |filter_name|
129
- # Create filter
130
- filter_class = PluginManager.filter_named(filter_name)
131
- error "Unknown filter: '#{filter_name}'" if filter_class.nil?
132
- filter = filter_class.new(self.to_proxy, @site.pages.map { |p| p.to_proxy }, @site.config, @site)
133
-
134
- # Run filter
135
- @content[stage] = filter.run(@content[stage])
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)
136
116
  end
137
117
  end
138
118
 
139
- def layout
140
- # Don't layout if not necessary
141
- if attribute_named(:layout).nil?
142
- @content[:post] = @content[:pre]
143
- return
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)
144
123
  end
145
-
146
- # Find layout
147
- layout = @site.layouts.find { |l| l[:name] == attribute_named(:layout) }
148
- error 'Unknown layout: ' + attribute_named(:layout) if layout.nil?
149
-
150
- # Find layout processor
151
- layout_processor_class = PluginManager.layout_processor_for_extension(layout[:extension])
152
- error "Unknown layout processor: '#{layout[:extension]}'" if layout_processor_class.nil?
153
- layout_processor = layout_processor_class.new(self.to_proxy, @site.pages.map { |p| p.to_proxy }, @site.config, @site)
154
-
155
- # Layout
156
- @content[:post] = layout_processor.run(layout[:content])
157
124
  end
158
125
 
159
126
  end
127
+
160
128
  end