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,25 @@
1
+ module Nanoc
2
+
3
+ # Nanoc::LayoutProxy is a proxy object for a layout (Nanoc::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 Nanoc
2
+
3
+ # Nanoc::PageProxy is a proxy object for a page (Nanoc::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 Nanoc
2
+
3
+ # Nanoc::PageRepProxy is a proxy object for a page representation
4
+ # (Nanoc::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 Nanoc
2
+
3
+ # Nanoc::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 =~ /^__/ }
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 Nanoc
2
+
3
+ # A Nanoc::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("Nanoc::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("Nanoc::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?(Nanoc::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?(Nanoc::PageRep) ? path_for_page_rep(obj) : path_for_asset_rep(obj))
67
+ )
68
+ end
69
+
70
+ end
71
+
72
+ end
@@ -1,51 +1,191 @@
1
1
  module Nanoc
2
+
3
+ # A Nanoc::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 Nanoc::Page instances representing pages
7
+ # * +assets+ is a list of Nanoc::Asset instances representing assets
8
+ # * +page_defaults+ is a Nanoc::PageDefaults instance representing page
9
+ # defaults
10
+ # * +asset_defaults+ is a Nanoc::AssetDefaults instance representing asset
11
+ # defaults
12
+ # * +layouts+ is a list of Nanoc::Layout instances representing layouts
13
+ # * +templates+ is a list of Nanoc::Template representing templates
14
+ # * +code+ is a Nanoc::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 Nanoc::Router subclass instance used for determining page
38
+ # and asset paths.
39
+ # * +data_source+ is a Nanoc::DataSource subclass instance used for managing
40
+ # site data.
41
+ # * +compiler+ is a Nanoc::Compiler instance that compiles page and asset
42
+ # representations.
43
+ #
44
+ # The physical representation of a Nanoc::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.
2
49
  class Site
3
50
 
51
+ # The default configuration for a site. A site's configuration overrides
52
+ # these options: when a Nanoc::Site is created with a configuration that
53
+ # lacks some options, the default value will be taken from
54
+ # +DEFAULT_CONFIG+.
4
55
  DEFAULT_CONFIG = {
5
- :output_dir => 'output',
6
- :eruby_engine => 'erb',
7
- :data_source => 'filesystem'
56
+ :output_dir => 'output',
57
+ :data_source => 'filesystem',
58
+ :router => 'default',
59
+ :index_filenames => [ 'index.html' ]
8
60
  }
9
61
 
10
62
  attr_reader :config
11
- attr_reader :compiler, :data_source
12
- attr_reader :code, :pages, :page_defaults, :layouts, :templates
13
-
14
- # Creating a Site object
15
-
16
- def self.from_cwd
17
- File.file?('config.yaml') ? new : nil
18
- end
19
-
20
- def initialize
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 Nanoc::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)
21
72
  # Load configuration
22
- @config = DEFAULT_CONFIG.merge((YAML.load_file('config.yaml') || {}).clean)
73
+ @config = DEFAULT_CONFIG.merge(config.clean)
23
74
 
24
75
  # Create data source
25
- @data_source_class = PluginManager.data_source_named(@config[:data_source])
26
- error "Unrecognised data source: #{@config[:data_source]}" if @data_source_class.nil?
76
+ @data_source_class = Nanoc::DataSource.named(@config[:data_source])
77
+ raise Nanoc::Errors::UnknownDataSourceError.new(@config[:data_source]) if @data_source_class.nil?
27
78
  @data_source = @data_source_class.new(self)
28
79
 
29
80
  # Create compiler
30
- @compiler = Compiler.new(self)
31
- @autocompiler = AutoCompiler.new(self)
32
-
33
- # Set not loaded
34
- @data_loaded = false
81
+ @compiler = Compiler.new(self)
82
+
83
+ # Load code (necessary for custom routers)
84
+ load_code
85
+
86
+ # Create router
87
+ @router_class = Nanoc::Router.named(@config[:router])
88
+ raise Nanoc::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 = []
35
100
  end
36
101
 
102
+ # Loads the site data. This will query the Nanoc::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.
37
109
  def load_data(force=false)
110
+ # Don't load data twice
111
+ @data_loaded ||= false
38
112
  return if @data_loaded and !force
39
113
 
40
- # Load data
114
+ # Load all data
41
115
  @data_source.loading do
42
- @code = @data_source.code
43
- @pages = @data_source.pages.map { |p| Page.new(p, self) }
44
- @page_defaults = @data_source.page_defaults
45
- @layouts = @data_source.layouts
46
- @templates = @data_source.templates
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]) }
47
184
  end
48
185
 
186
+ # Set site
187
+ @pages.each { |p| p.site = self }
188
+
49
189
  # Setup child-parent links
50
190
  @pages.each do |page|
51
191
  # Get parent
@@ -58,84 +198,75 @@ module Nanoc
58
198
  parent.children << page
59
199
  end
60
200
 
61
- # Set loaded
62
- @data_loaded = true
63
- end
64
-
65
- # Creating a new site on disk
66
-
67
- def self.create(sitename)
68
- # Check whether site exists
69
- error "A site named '#{sitename}' already exists." if File.exist?(sitename)
70
-
71
- FileUtils.mkdir_p sitename
72
- in_dir([sitename]) do
73
- # Create output
74
- FileManager.create_dir 'output'
75
-
76
- # Create config
77
- FileManager.create_file 'config.yaml' do
78
- "output_dir: \"output\"\n" +
79
- "data_source: \"filesystem\"\n"
80
- end
81
-
82
- # Create rakefile
83
- FileManager.create_file 'Rakefile' do
84
- "Dir['tasks/**/*.rake'].sort.each { |rakefile| load rakefile }\n" +
85
- "\n" +
86
- "task :default do\n" +
87
- " puts 'This is an example rake task.'\n" +
88
- "end\n"
89
- end
90
-
91
- # Create tasks
92
- FileManager.create_file 'tasks/default.rake' do
93
- "task :example do\n" +
94
- " puts 'This is an example rake task in tasks/default.rake.'\n" +
95
- "end\n"
96
- end
97
-
98
- # Setup site
99
- Site.from_cwd.setup
100
- end
201
+ # Build page representations
202
+ @pages.each { |p| p.build_reps }
101
203
  end
102
204
 
103
- # Compiling
205
+ # Loads this site's asset defaults.
206
+ def load_asset_defaults
207
+ # Get page defaults
208
+ @asset_defaults = @data_source.asset_defaults
104
209
 
105
- def compile
106
- @compiler.run
210
+ # Set site
211
+ @asset_defaults.site = self
212
+ rescue NotImplementedError
213
+ @asset_defaults = AssetDefaults.new({})
214
+ @asset_defaults.site = self
107
215
  end
108
216
 
109
- def autocompile(port)
110
- @autocompiler.start(port)
111
- end
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
112
222
 
113
- # Creating
223
+ # Set site
224
+ @assets.each { |a| a.site = self }
114
225
 
115
- def setup
116
- @data_source.loading { @data_source.setup }
226
+ # Build asset representations
227
+ @assets.each { |p| p.build_reps }
228
+ rescue NotImplementedError
229
+ @assets = []
117
230
  end
118
231
 
119
- def create_page(name, template_name='default')
120
- load_data
232
+ # Loads this site's layouts.
233
+ def load_layouts
234
+ # Get layouts
235
+ @layouts = @data_source.layouts
121
236
 
122
- template = @templates.find { |t| t[:name] == template_name }
123
- error "A template named '#{template_name}' was not found; aborting." if template.nil?
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
124
242
 
125
- @data_source.loading { @data_source.create_page(name, template) }
243
+ # Set site
244
+ @layouts.each { |l| l.site = self }
126
245
  end
127
246
 
128
- def create_template(name)
129
- load_data
247
+ # Loads this site's templates.
248
+ def load_templates
249
+ # Get templates
250
+ @templates = @data_source.templates
130
251
 
131
- @data_source.loading {@data_source.create_template(name) }
132
- end
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
133
257
 
134
- def create_layout(name)
135
- load_data
258
+ # Set site
259
+ @templates.each { |t| t.site = self }
260
+ end
136
261
 
137
- @data_source.loading { @data_source.create_layout(name) }
262
+ # Raises a warning about an outdated data source method.
263
+ def warn_data_source(class_name, method_name, is_array)
264
+ warn(
265
+ "In nanoc 2.1, DataSource##{method_name} should return #{is_array ? 'an array of' : 'a' } Nanoc::#{class_name} object#{is_array ? 's' : ''}. Future versions will not support these outdated data sources.",
266
+ 'DEPRECATION WARNING'
267
+ )
138
268
  end
139
269
 
140
270
  end
271
+
141
272
  end