nanoc 2.0.4 → 2.1

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