nanoc2 2.2.3
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.
- data/ChangeLog +3 -0
- data/LICENSE +19 -0
- data/README +75 -0
- data/Rakefile +76 -0
- data/bin/nanoc2 +26 -0
- data/lib/nanoc2.rb +73 -0
- data/lib/nanoc2/base.rb +26 -0
- data/lib/nanoc2/base/asset.rb +117 -0
- data/lib/nanoc2/base/asset_defaults.rb +21 -0
- data/lib/nanoc2/base/asset_rep.rb +282 -0
- data/lib/nanoc2/base/binary_filter.rb +44 -0
- data/lib/nanoc2/base/code.rb +41 -0
- data/lib/nanoc2/base/compiler.rb +67 -0
- data/lib/nanoc2/base/core_ext.rb +2 -0
- data/lib/nanoc2/base/core_ext/hash.rb +78 -0
- data/lib/nanoc2/base/core_ext/string.rb +8 -0
- data/lib/nanoc2/base/data_source.rb +286 -0
- data/lib/nanoc2/base/defaults.rb +30 -0
- data/lib/nanoc2/base/filter.rb +93 -0
- data/lib/nanoc2/base/layout.rb +91 -0
- data/lib/nanoc2/base/notification_center.rb +66 -0
- data/lib/nanoc2/base/page.rb +132 -0
- data/lib/nanoc2/base/page_defaults.rb +20 -0
- data/lib/nanoc2/base/page_rep.rb +324 -0
- data/lib/nanoc2/base/plugin.rb +71 -0
- data/lib/nanoc2/base/proxies.rb +5 -0
- data/lib/nanoc2/base/proxies/asset_proxy.rb +29 -0
- data/lib/nanoc2/base/proxies/asset_rep_proxy.rb +26 -0
- data/lib/nanoc2/base/proxies/layout_proxy.rb +25 -0
- data/lib/nanoc2/base/proxies/page_proxy.rb +35 -0
- data/lib/nanoc2/base/proxies/page_rep_proxy.rb +28 -0
- data/lib/nanoc2/base/proxy.rb +37 -0
- data/lib/nanoc2/base/router.rb +72 -0
- data/lib/nanoc2/base/site.rb +274 -0
- data/lib/nanoc2/base/template.rb +64 -0
- data/lib/nanoc2/binary_filters.rb +1 -0
- data/lib/nanoc2/binary_filters/image_science_thumbnail.rb +28 -0
- data/lib/nanoc2/cli.rb +9 -0
- data/lib/nanoc2/cli/base.rb +132 -0
- data/lib/nanoc2/cli/commands.rb +10 -0
- data/lib/nanoc2/cli/commands/autocompile.rb +80 -0
- data/lib/nanoc2/cli/commands/compile.rb +312 -0
- data/lib/nanoc2/cli/commands/create_layout.rb +85 -0
- data/lib/nanoc2/cli/commands/create_page.rb +85 -0
- data/lib/nanoc2/cli/commands/create_site.rb +323 -0
- data/lib/nanoc2/cli/commands/create_template.rb +76 -0
- data/lib/nanoc2/cli/commands/help.rb +69 -0
- data/lib/nanoc2/cli/commands/info.rb +125 -0
- data/lib/nanoc2/cli/commands/switch.rb +141 -0
- data/lib/nanoc2/cli/commands/update.rb +91 -0
- data/lib/nanoc2/cli/logger.rb +72 -0
- data/lib/nanoc2/data_sources.rb +2 -0
- data/lib/nanoc2/data_sources/filesystem.rb +707 -0
- data/lib/nanoc2/data_sources/filesystem_combined.rb +495 -0
- data/lib/nanoc2/extra.rb +6 -0
- data/lib/nanoc2/extra/auto_compiler.rb +285 -0
- data/lib/nanoc2/extra/context.rb +22 -0
- data/lib/nanoc2/extra/core_ext.rb +2 -0
- data/lib/nanoc2/extra/core_ext/hash.rb +54 -0
- data/lib/nanoc2/extra/core_ext/time.rb +13 -0
- data/lib/nanoc2/extra/file_proxy.rb +29 -0
- data/lib/nanoc2/extra/vcs.rb +48 -0
- data/lib/nanoc2/extra/vcses.rb +5 -0
- data/lib/nanoc2/extra/vcses/bazaar.rb +21 -0
- data/lib/nanoc2/extra/vcses/dummy.rb +20 -0
- data/lib/nanoc2/extra/vcses/git.rb +21 -0
- data/lib/nanoc2/extra/vcses/mercurial.rb +21 -0
- data/lib/nanoc2/extra/vcses/subversion.rb +21 -0
- data/lib/nanoc2/filters.rb +16 -0
- data/lib/nanoc2/filters/bluecloth.rb +13 -0
- data/lib/nanoc2/filters/erb.rb +19 -0
- data/lib/nanoc2/filters/erubis.rb +14 -0
- data/lib/nanoc2/filters/haml.rb +21 -0
- data/lib/nanoc2/filters/markaby.rb +14 -0
- data/lib/nanoc2/filters/maruku.rb +14 -0
- data/lib/nanoc2/filters/old.rb +19 -0
- data/lib/nanoc2/filters/rainpress.rb +13 -0
- data/lib/nanoc2/filters/rdiscount.rb +13 -0
- data/lib/nanoc2/filters/rdoc.rb +23 -0
- data/lib/nanoc2/filters/redcloth.rb +14 -0
- data/lib/nanoc2/filters/relativize_paths.rb +16 -0
- data/lib/nanoc2/filters/relativize_paths_in_css.rb +16 -0
- data/lib/nanoc2/filters/relativize_paths_in_html.rb +16 -0
- data/lib/nanoc2/filters/rubypants.rb +14 -0
- data/lib/nanoc2/filters/sass.rb +18 -0
- data/lib/nanoc2/helpers.rb +9 -0
- data/lib/nanoc2/helpers/blogging.rb +217 -0
- data/lib/nanoc2/helpers/capturing.rb +63 -0
- data/lib/nanoc2/helpers/filtering.rb +54 -0
- data/lib/nanoc2/helpers/html_escape.rb +25 -0
- data/lib/nanoc2/helpers/link_to.rb +113 -0
- data/lib/nanoc2/helpers/render.rb +49 -0
- data/lib/nanoc2/helpers/tagging.rb +56 -0
- data/lib/nanoc2/helpers/text.rb +38 -0
- data/lib/nanoc2/helpers/xml_sitemap.rb +63 -0
- data/lib/nanoc2/routers.rb +3 -0
- data/lib/nanoc2/routers/default.rb +54 -0
- data/lib/nanoc2/routers/no_dirs.rb +66 -0
- data/lib/nanoc2/routers/versioned.rb +79 -0
- metadata +185 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::Plugin is the superclass for all plugins, such as filters
|
4
|
+
# (Nanoc2::Filter), binary filters (Nanoc2::BinaryFilter), routers
|
5
|
+
# (Nanoc2::Router), data sources (Nanoc2::DataSource) and VCSes
|
6
|
+
# (Nanoc2::Extra::VCS). Each plugin has one or more unique identifiers, and
|
7
|
+
# several methods in this class provides functionality for finding plugins
|
8
|
+
# with given identifiers.
|
9
|
+
class Plugin
|
10
|
+
|
11
|
+
MAP = {}
|
12
|
+
|
13
|
+
class << self
|
14
|
+
|
15
|
+
# Sets or returns the identifiers for this plugin.
|
16
|
+
#
|
17
|
+
# When given a list of identifier symbols, sets the identifiers for
|
18
|
+
# this plugin. When given nothing, returns an array of identifier
|
19
|
+
# symbols for this plugin.
|
20
|
+
def identifiers(*identifiers)
|
21
|
+
# Initialize
|
22
|
+
if !instance_variables.include?('@identifiers') && !instance_variables.include?(:'@identifiers')
|
23
|
+
@identifiers = []
|
24
|
+
end
|
25
|
+
|
26
|
+
if identifiers.empty?
|
27
|
+
@identifiers
|
28
|
+
else
|
29
|
+
@identifiers = identifiers
|
30
|
+
@identifiers.each { |i| register(i, self) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Sets or returns the identifier for this plugin.
|
35
|
+
#
|
36
|
+
# When given an identifier symbols, sets the identifier for this plugin.
|
37
|
+
# When given nothing, returns the identifier for this plugin.
|
38
|
+
def identifier(identifier=nil)
|
39
|
+
# Initialize
|
40
|
+
if !instance_variables.include?('@identifiers') && !instance_variables.include?(:'@identifiers')
|
41
|
+
@identifiers = []
|
42
|
+
end
|
43
|
+
|
44
|
+
if identifier.nil?
|
45
|
+
@identifiers.first
|
46
|
+
else
|
47
|
+
@identifiers = [ identifier ]
|
48
|
+
register(identifier, self)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Registers the given class +klass+ with the given name. This will allow
|
53
|
+
# the named method to find the class.
|
54
|
+
def register(name, klass)
|
55
|
+
MAP[klass.superclass] ||= {}
|
56
|
+
MAP[klass.superclass][name.to_sym] = klass
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns the the plugin with the given name. Only subclasses of this
|
60
|
+
# class will be searched. For example, calling this method on
|
61
|
+
# Nanoc2::Filter will cause only Nanoc2::Filter subclasses to be searched.
|
62
|
+
def named(name)
|
63
|
+
MAP[self] ||= {}
|
64
|
+
MAP[self][name.to_sym]
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::AssetProxy is a proxy object for an asset (Nanoc2::Asset).
|
4
|
+
class AssetProxy < Proxy
|
5
|
+
|
6
|
+
# Requests the asset attribute with the given name. +key+ can be a string
|
7
|
+
# or a symbol, and it can contain a trailing question mark (which will be
|
8
|
+
# stripped).
|
9
|
+
def [](key)
|
10
|
+
real_key = key.to_s.sub(/\?$/, '').to_sym
|
11
|
+
|
12
|
+
if real_key == :mtime
|
13
|
+
@obj.mtime
|
14
|
+
elsif real_key == :path # backward compatibility
|
15
|
+
@obj.reps.find { |r| r.name == :default }.web_path
|
16
|
+
else
|
17
|
+
super(key)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Returns the asset representation with the given name.
|
22
|
+
def reps(name)
|
23
|
+
rep = @obj.reps.find { |r| r.name == name }
|
24
|
+
rep.nil? ? nil : rep.to_proxy
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::AssetRepProxy is a proxy object for an asset representation
|
4
|
+
# (Nanoc2::AssetRep).
|
5
|
+
class AssetRepProxy < Proxy
|
6
|
+
|
7
|
+
# Requests the asset representation attribute with the given name. +key+
|
8
|
+
# can be a string or a symbol, and it can contain a trailing question mark
|
9
|
+
# (which will be stripped).
|
10
|
+
def [](key)
|
11
|
+
real_key = key.to_s.sub(/\?$/, '').to_sym
|
12
|
+
|
13
|
+
if real_key == :name
|
14
|
+
@obj.name
|
15
|
+
elsif real_key == :path
|
16
|
+
@obj.web_path
|
17
|
+
elsif real_key == :asset
|
18
|
+
@obj.asset.to_proxy
|
19
|
+
else
|
20
|
+
super(key)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::LayoutProxy is a proxy object for a layout (Nanoc2::Layout).
|
4
|
+
class LayoutProxy < Proxy
|
5
|
+
|
6
|
+
# Requests the layout attribute with the given name. +key+ can be a string
|
7
|
+
# or a symbol, and it can contain a trailing question mark (which will be
|
8
|
+
# stripped).
|
9
|
+
def [](key)
|
10
|
+
real_key = key.to_s.sub(/\?$/, '').to_sym
|
11
|
+
|
12
|
+
if real_key == :content
|
13
|
+
@obj.content
|
14
|
+
elsif real_key == :path
|
15
|
+
@obj.path
|
16
|
+
elsif real_key == :mtime
|
17
|
+
@obj.mtime
|
18
|
+
else
|
19
|
+
super(key)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::PageProxy is a proxy object for a page (Nanoc2::Page).
|
4
|
+
class PageProxy < Proxy
|
5
|
+
|
6
|
+
# Requests the page attribute with the given name. +key+ can be a string
|
7
|
+
# or a symbol, and it can contain a trailing question mark (which will be
|
8
|
+
# stripped).
|
9
|
+
def [](key)
|
10
|
+
real_key = key.to_s.sub(/\?$/, '').to_sym
|
11
|
+
|
12
|
+
if real_key == :mtime
|
13
|
+
@obj.mtime
|
14
|
+
elsif real_key == :parent
|
15
|
+
@obj.parent.nil? ? nil : @obj.parent.to_proxy
|
16
|
+
elsif real_key == :children
|
17
|
+
@obj.children.map { |page| page.to_proxy }
|
18
|
+
elsif real_key == :content # backward compatibility
|
19
|
+
@obj.reps.find { |r| r.name == :default }.content
|
20
|
+
elsif real_key == :path # backward compatibility
|
21
|
+
@obj.reps.find { |r| r.name == :default }.web_path
|
22
|
+
else
|
23
|
+
super(key)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the page representation with the given name.
|
28
|
+
def reps(name)
|
29
|
+
rep = @obj.reps.find { |r| r.name == name }
|
30
|
+
rep.nil? ? nil : rep.to_proxy
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::PageRepProxy is a proxy object for a page representation
|
4
|
+
# (Nanoc2::PageRep).
|
5
|
+
class PageRepProxy < Proxy
|
6
|
+
|
7
|
+
# Requests the page representation attribute with the given name. +key+
|
8
|
+
# can be a string or a symbol, and it can contain a trailing question mark
|
9
|
+
# (which will be stripped).
|
10
|
+
def [](key)
|
11
|
+
real_key = key.to_s.sub(/\?$/, '').to_sym
|
12
|
+
|
13
|
+
if real_key == :name
|
14
|
+
@obj.name
|
15
|
+
elsif real_key == :content
|
16
|
+
@obj.content
|
17
|
+
elsif real_key == :path
|
18
|
+
@obj.web_path
|
19
|
+
elsif real_key == :page
|
20
|
+
@obj.page.to_proxy
|
21
|
+
else
|
22
|
+
super(key)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# Nanoc2::Proxy is used when making data available to pages and layouts.
|
4
|
+
# It provides an easy way to access data without the risk of accidentally
|
5
|
+
# calling destructive methods.
|
6
|
+
class Proxy
|
7
|
+
|
8
|
+
instance_methods.each { |m| undef_method m unless m =~ /^__/ || m.to_s == 'object_id' }
|
9
|
+
|
10
|
+
# Creates a proxy for the given object.
|
11
|
+
def initialize(obj)
|
12
|
+
@obj = obj
|
13
|
+
end
|
14
|
+
|
15
|
+
# Requests the attribute with the given name. +key+ can be a string or a
|
16
|
+
# symbol, and it can contain a trailing question mark (which will be
|
17
|
+
# stripped).
|
18
|
+
def [](key)
|
19
|
+
real_key = key.to_s.sub(/\?$/, '').to_sym
|
20
|
+
|
21
|
+
@obj.attribute_named(real_key)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Sets a given attribute. The use of setting an object's attributes is not
|
25
|
+
# recommended but may be necessary in some cases.
|
26
|
+
def []=(key, value)
|
27
|
+
@obj.attributes[key.to_sym] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
# Used for requesting attributes without accessing the proxy like a hash.
|
31
|
+
def method_missing(method, *args)
|
32
|
+
self[method]
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# A Nanoc2::Router is an abstract superclass that determines the paths of
|
4
|
+
# page and asset representations, both the path on the disk (relative to the
|
5
|
+
# site's output directory) and the path as it appears on the web site.
|
6
|
+
class Router < Plugin
|
7
|
+
|
8
|
+
# Creates a new router for the given site.
|
9
|
+
def initialize(site)
|
10
|
+
@site = site
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the routed path for the given page representation, including the
|
14
|
+
# filename and the extension. It should start with a slash, and should be
|
15
|
+
# relative to the web root (i.e. should not include any references to the
|
16
|
+
# output directory). There is no need to let this method handle custom
|
17
|
+
# paths.
|
18
|
+
#
|
19
|
+
# Subclasses must implement this method.
|
20
|
+
def path_for_page_rep(page_rep)
|
21
|
+
raise NotImplementedError.new("Nanoc2::Router subclasses must implement #path_for_page_rep.")
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns the routed path for the given asset representation, including
|
25
|
+
# the filename and the extension. It should start with a slash, and should
|
26
|
+
# be relative to the web root (i.e. should not include any references to
|
27
|
+
# the output directory). There is no need to let this method handle custom
|
28
|
+
# paths.
|
29
|
+
#
|
30
|
+
# Subclasses must implement this method.
|
31
|
+
def path_for_asset_rep(asset_rep)
|
32
|
+
raise NotImplementedError.new("Nanoc2::Router subclasses must implement #path_for_asset_rep.")
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the web path for the given page or asset representation, i.e.
|
36
|
+
# the page or asset rep's custom path or routed path with index filenames
|
37
|
+
# stripped.
|
38
|
+
def web_path_for(obj)
|
39
|
+
# Get actual path
|
40
|
+
path ||= obj.attribute_named(:custom_path)
|
41
|
+
if obj.is_a?(Nanoc2::PageRep) # Page rep
|
42
|
+
path ||= path_for_page_rep(obj)
|
43
|
+
else # Asset rep
|
44
|
+
path ||= path_for_asset_rep(obj)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Try stripping each index filename
|
48
|
+
@site.config[:index_filenames].each do |index_filename|
|
49
|
+
if path[-index_filename.length..-1] == index_filename
|
50
|
+
# Strip and stop
|
51
|
+
path = path[0..-index_filename.length-1]
|
52
|
+
break
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return possibly stripped path
|
57
|
+
path
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns the disk path for the given page or asset representation, i.e.
|
61
|
+
# the page or asset's custom path or routed path relative to the output
|
62
|
+
# directory.
|
63
|
+
def disk_path_for(obj)
|
64
|
+
@site.config[:output_dir] + (
|
65
|
+
obj.attribute_named(:custom_path) ||
|
66
|
+
(obj.is_a?(Nanoc2::PageRep) ? path_for_page_rep(obj) : path_for_asset_rep(obj))
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
module Nanoc2
|
2
|
+
|
3
|
+
# A Nanoc2::Site is the in-memory representation of a nanoc site. It holds
|
4
|
+
# references to the following site data:
|
5
|
+
#
|
6
|
+
# * +pages+ is a list of Nanoc2::Page instances representing pages
|
7
|
+
# * +assets+ is a list of Nanoc2::Asset instances representing assets
|
8
|
+
# * +page_defaults+ is a Nanoc2::PageDefaults instance representing page
|
9
|
+
# defaults
|
10
|
+
# * +asset_defaults+ is a Nanoc2::AssetDefaults instance representing asset
|
11
|
+
# defaults
|
12
|
+
# * +layouts+ is a list of Nanoc2::Layout instances representing layouts
|
13
|
+
# * +templates+ is a list of Nanoc2::Template representing templates
|
14
|
+
# * +code+ is a Nanoc2::Code instance representing custom site code
|
15
|
+
#
|
16
|
+
# In addition, each site has a +config+ hash which stores the site
|
17
|
+
# configuration. This configuration hash can have the following keys:
|
18
|
+
#
|
19
|
+
# +output_dir+:: The directory to which compiled pages and assets will be
|
20
|
+
# written. This path is relative to the current working
|
21
|
+
# directory, but can also be an absolute path.
|
22
|
+
#
|
23
|
+
# +data_source+:: The identifier of the data source that will be used for
|
24
|
+
# loading site data.
|
25
|
+
#
|
26
|
+
# +router+:: The identifier of the router that will be used for determining
|
27
|
+
# page and asset representation paths.
|
28
|
+
#
|
29
|
+
# +index_filenames+:: A list of filenames that will be stripped off full
|
30
|
+
# page and asset paths to create cleaner URLs (for
|
31
|
+
# example, '/about/' will be used instead of
|
32
|
+
# '/about/index.html'). The default value should be okay
|
33
|
+
# in most cases.
|
34
|
+
#
|
35
|
+
# A site also has several helper classes:
|
36
|
+
#
|
37
|
+
# * +router+ is a Nanoc2::Router subclass instance used for determining page
|
38
|
+
# and asset paths.
|
39
|
+
# * +data_source+ is a Nanoc2::DataSource subclass instance used for managing
|
40
|
+
# site data.
|
41
|
+
# * +compiler+ is a Nanoc2::Compiler instance that compiles page and asset
|
42
|
+
# representations.
|
43
|
+
#
|
44
|
+
# The physical representation of a Nanoc2::Site is usually a directory that
|
45
|
+
# contains a configuration file, site data, and some rake tasks. However,
|
46
|
+
# different frontends may store data differently. For example, a web-based
|
47
|
+
# frontend would probably store the configuration and the site content in a
|
48
|
+
# database, and would not have rake tasks at all.
|
49
|
+
class Site
|
50
|
+
|
51
|
+
# The default configuration for a site. A site's configuration overrides
|
52
|
+
# these options: when a Nanoc2::Site is created with a configuration that
|
53
|
+
# lacks some options, the default value will be taken from
|
54
|
+
# +DEFAULT_CONFIG+.
|
55
|
+
DEFAULT_CONFIG = {
|
56
|
+
:output_dir => 'output',
|
57
|
+
:data_source => 'filesystem',
|
58
|
+
:router => 'default',
|
59
|
+
:index_filenames => [ 'index.html' ]
|
60
|
+
}
|
61
|
+
|
62
|
+
attr_reader :config
|
63
|
+
attr_reader :compiler, :data_source, :router
|
64
|
+
attr_reader :page_defaults, :asset_defaults
|
65
|
+
attr_reader :pages, :assets, :layouts, :templates, :code
|
66
|
+
|
67
|
+
# Returns a Nanoc2::Site object for the site specified by the given
|
68
|
+
# configuration hash +config+.
|
69
|
+
#
|
70
|
+
# +config+:: A hash containing the site configuration.
|
71
|
+
def initialize(config)
|
72
|
+
# Load configuration
|
73
|
+
@config = DEFAULT_CONFIG.merge(config.clean)
|
74
|
+
|
75
|
+
# Create data source
|
76
|
+
@data_source_class = Nanoc2::DataSource.named(@config[:data_source])
|
77
|
+
raise Nanoc2::Errors::UnknownDataSourceError.new(@config[:data_source]) if @data_source_class.nil?
|
78
|
+
@data_source = @data_source_class.new(self)
|
79
|
+
|
80
|
+
# Create compiler
|
81
|
+
@compiler = Compiler.new(self)
|
82
|
+
|
83
|
+
# Load code (necessary for custom routers)
|
84
|
+
load_code
|
85
|
+
|
86
|
+
# Create router
|
87
|
+
@router_class = Nanoc2::Router.named(@config[:router])
|
88
|
+
raise Nanoc2::Errors::UnknownRouterError.new(@config[:router]) if @router_class.nil?
|
89
|
+
@router = @router_class.new(self)
|
90
|
+
|
91
|
+
# Initialize data
|
92
|
+
@page_defaults = PageDefaults.new({})
|
93
|
+
@page_defaults.site = self
|
94
|
+
@asset_defaults = AssetDefaults.new({})
|
95
|
+
@asset_defaults.site = self
|
96
|
+
@pages = []
|
97
|
+
@assets = []
|
98
|
+
@layouts = []
|
99
|
+
@templates = []
|
100
|
+
end
|
101
|
+
|
102
|
+
# Loads the site data. This will query the Nanoc2::DataSource associated
|
103
|
+
# with the site and fetch all site data. The site data is cached, so
|
104
|
+
# calling this method will not have any effect the second time, unless
|
105
|
+
# +force+ is true.
|
106
|
+
#
|
107
|
+
# +force+:: If true, will force load the site data even if it has been
|
108
|
+
# loaded before, to circumvent caching issues.
|
109
|
+
def load_data(force=false)
|
110
|
+
# Don't load data twice
|
111
|
+
@data_loaded ||= false
|
112
|
+
return if @data_loaded and !force
|
113
|
+
|
114
|
+
# Load all data
|
115
|
+
@data_source.loading do
|
116
|
+
load_code(force)
|
117
|
+
load_page_defaults
|
118
|
+
load_pages
|
119
|
+
load_asset_defaults
|
120
|
+
load_assets
|
121
|
+
load_layouts
|
122
|
+
load_templates
|
123
|
+
end
|
124
|
+
|
125
|
+
# Set loaded
|
126
|
+
@data_loaded = true
|
127
|
+
end
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
# Loads this site's code and executes it.
|
132
|
+
def load_code(force=false)
|
133
|
+
# Don't load code twice
|
134
|
+
@code_loaded ||= false
|
135
|
+
return if @code_loaded and !force
|
136
|
+
|
137
|
+
# Get code
|
138
|
+
@code = @data_source.code
|
139
|
+
|
140
|
+
# Fix code if outdated
|
141
|
+
if @code.is_a? String
|
142
|
+
warn_data_source('Code', 'code', false)
|
143
|
+
@code = Code.new(code)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Set site
|
147
|
+
@code.site = self
|
148
|
+
|
149
|
+
# Execute code
|
150
|
+
# FIXME This could be dangerous when using nanoc as a framework
|
151
|
+
# (a separate ruby process should probably be forked, and the code
|
152
|
+
# should only be loaded in this forked process)
|
153
|
+
@code.load
|
154
|
+
|
155
|
+
# Set loaded
|
156
|
+
@code_loaded = true
|
157
|
+
end
|
158
|
+
|
159
|
+
# Loads this site's page defaults.
|
160
|
+
def load_page_defaults
|
161
|
+
# Get page defaults
|
162
|
+
@page_defaults = @data_source.page_defaults
|
163
|
+
|
164
|
+
# Fix page defaults if outdated
|
165
|
+
if @page_defaults.is_a? Hash
|
166
|
+
warn_data_source('PageDefaults', 'page_defaults', false)
|
167
|
+
@page_defaults = PageDefaults.new(@page_defaults)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Set site
|
171
|
+
@page_defaults.site = self
|
172
|
+
end
|
173
|
+
|
174
|
+
# Loads this site's pages, sets up page child-parent relationships and
|
175
|
+
# builds each page's list of page representations.
|
176
|
+
def load_pages
|
177
|
+
# Get pages
|
178
|
+
@pages = @data_source.pages
|
179
|
+
|
180
|
+
# Fix pages if outdated
|
181
|
+
if @pages.any? { |p| p.is_a? Hash }
|
182
|
+
warn_data_source('Page', 'pages', true)
|
183
|
+
@pages.map! { |p| Page.new(p[:uncompiled_content], p, p[:path]) }
|
184
|
+
end
|
185
|
+
|
186
|
+
# Set site
|
187
|
+
@pages.each { |p| p.site = self }
|
188
|
+
|
189
|
+
# Setup child-parent links
|
190
|
+
@pages.each do |page|
|
191
|
+
# Get parent
|
192
|
+
parent_path = page.path.sub(/[^\/]+\/$/, '')
|
193
|
+
parent = @pages.find { |p| p.path == parent_path }
|
194
|
+
next if parent.nil? or page.path == '/'
|
195
|
+
|
196
|
+
# Link
|
197
|
+
page.parent = parent
|
198
|
+
parent.children << page
|
199
|
+
end
|
200
|
+
|
201
|
+
# Build page representations
|
202
|
+
@pages.each { |p| p.build_reps }
|
203
|
+
end
|
204
|
+
|
205
|
+
# Loads this site's asset defaults.
|
206
|
+
def load_asset_defaults
|
207
|
+
# Get page defaults
|
208
|
+
@asset_defaults = @data_source.asset_defaults
|
209
|
+
|
210
|
+
# Set site
|
211
|
+
@asset_defaults.site = self
|
212
|
+
rescue NotImplementedError
|
213
|
+
@asset_defaults = AssetDefaults.new({})
|
214
|
+
@asset_defaults.site = self
|
215
|
+
end
|
216
|
+
|
217
|
+
# Loads this site's assets and builds each asset's list of asset
|
218
|
+
# representations.
|
219
|
+
def load_assets
|
220
|
+
# Get assets
|
221
|
+
@assets = @data_source.assets
|
222
|
+
|
223
|
+
# Set site
|
224
|
+
@assets.each { |a| a.site = self }
|
225
|
+
|
226
|
+
# Build asset representations
|
227
|
+
@assets.each { |p| p.build_reps }
|
228
|
+
rescue NotImplementedError
|
229
|
+
@assets = []
|
230
|
+
end
|
231
|
+
|
232
|
+
# Loads this site's layouts.
|
233
|
+
def load_layouts
|
234
|
+
# Get layouts
|
235
|
+
@layouts = @data_source.layouts
|
236
|
+
|
237
|
+
# Fix layouts if outdated
|
238
|
+
if @layouts.any? { |l| l.is_a? Hash }
|
239
|
+
warn_data_source('Layout', 'layouts', true)
|
240
|
+
@layouts.map! { |l| Layout.new(l[:content], l, l[:path] || l[:name]) }
|
241
|
+
end
|
242
|
+
|
243
|
+
# Set site
|
244
|
+
@layouts.each { |l| l.site = self }
|
245
|
+
end
|
246
|
+
|
247
|
+
# Loads this site's templates.
|
248
|
+
def load_templates
|
249
|
+
# Get templates
|
250
|
+
@templates = @data_source.templates
|
251
|
+
|
252
|
+
# Fix templates if outdated
|
253
|
+
if @templates.any? { |t| t.is_a? Hash }
|
254
|
+
warn_data_source('Template', 'templates', true)
|
255
|
+
@templates.map! { |t| Template.new(t[:content], t[:meta].is_a?(String) ? YAML.load(t[:meta]) : t[:meta], t[:name]) }
|
256
|
+
end
|
257
|
+
|
258
|
+
# Set site
|
259
|
+
@templates.each { |t| t.site = self }
|
260
|
+
end
|
261
|
+
|
262
|
+
# Raises a warning about an outdated data source method.
|
263
|
+
def warn_data_source(class_name, method_name, is_array)
|
264
|
+
warn(
|
265
|
+
"DEPRECATION WARNING: In nanoc 2.1, DataSource##{method_name} " +
|
266
|
+
"should return #{is_array ? 'an array of' : 'a' } " +
|
267
|
+
"Nanoc2::#{class_name} object#{is_array ? 's' : ''}. Future " +
|
268
|
+
"versions will not support these outdated data sources."
|
269
|
+
)
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|