nanoc 1.6.2 → 2.0

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 (51) hide show
  1. data/ChangeLog +27 -0
  2. data/Rakefile +34 -27
  3. data/bin/nanoc +153 -49
  4. data/lib/nanoc.rb +15 -33
  5. data/lib/nanoc/base/auto_compiler.rb +124 -0
  6. data/lib/nanoc/base/compiler.rb +55 -0
  7. data/lib/nanoc/base/core_ext/hash.rb +34 -0
  8. data/lib/nanoc/base/data_source.rb +53 -0
  9. data/lib/nanoc/base/enhancements.rb +89 -0
  10. data/lib/nanoc/base/filter.rb +16 -0
  11. data/lib/nanoc/base/layout_processor.rb +33 -0
  12. data/lib/nanoc/base/page.rb +155 -0
  13. data/lib/nanoc/base/page_proxy.rb +31 -0
  14. data/lib/nanoc/base/plugin.rb +19 -0
  15. data/lib/nanoc/base/plugin_manager.rb +33 -0
  16. data/lib/nanoc/base/site.rb +143 -0
  17. data/lib/nanoc/data_sources/database.rb +259 -0
  18. data/lib/nanoc/data_sources/filesystem.rb +308 -0
  19. data/lib/nanoc/data_sources/trivial.rb +145 -0
  20. data/lib/nanoc/filters/erb.rb +34 -0
  21. data/lib/nanoc/filters/haml.rb +16 -0
  22. data/lib/nanoc/filters/markaby.rb +15 -0
  23. data/lib/nanoc/filters/markdown.rb +13 -0
  24. data/lib/nanoc/filters/rdoc.rb +14 -0
  25. data/lib/nanoc/filters/smartypants.rb +13 -0
  26. data/lib/nanoc/filters/textile.rb +13 -0
  27. data/lib/nanoc/layout_processors/erb.rb +35 -0
  28. data/lib/nanoc/layout_processors/haml.rb +18 -0
  29. data/lib/nanoc/layout_processors/markaby.rb +16 -0
  30. metadata +37 -30
  31. data/lib/nanoc/compiler.rb +0 -145
  32. data/lib/nanoc/core_ext.rb +0 -1
  33. data/lib/nanoc/core_ext/array.rb +0 -17
  34. data/lib/nanoc/core_ext/hash.rb +0 -43
  35. data/lib/nanoc/core_ext/string.rb +0 -13
  36. data/lib/nanoc/core_ext/yaml.rb +0 -10
  37. data/lib/nanoc/creator.rb +0 -180
  38. data/lib/nanoc/enhancements.rb +0 -101
  39. data/lib/nanoc/filters.rb +0 -7
  40. data/lib/nanoc/filters/eruby_filter.rb +0 -39
  41. data/lib/nanoc/filters/haml_filter.rb +0 -18
  42. data/lib/nanoc/filters/liquid_filter.rb +0 -47
  43. data/lib/nanoc/filters/markaby_filter.rb +0 -15
  44. data/lib/nanoc/filters/markdown_filter.rb +0 -13
  45. data/lib/nanoc/filters/rdoc_filter.rb +0 -15
  46. data/lib/nanoc/filters/sass_filter.rb +0 -13
  47. data/lib/nanoc/filters/smartypants_filter.rb +0 -13
  48. data/lib/nanoc/filters/textile_filter.rb +0 -13
  49. data/lib/nanoc/page.rb +0 -171
  50. data/lib/nanoc/page_drop.rb +0 -18
  51. data/lib/nanoc/page_proxy.rb +0 -30
@@ -0,0 +1,19 @@
1
+ module Nanoc
2
+ class Plugin
3
+
4
+ class << self
5
+ attr_accessor :_identifiers
6
+ end
7
+
8
+ def self.identifiers(*identifiers)
9
+ self._identifiers = [] unless instance_variable_defined?(:@_identifiers)
10
+ identifiers.empty? ? self._identifiers || [] : self._identifiers = (self._identifiers || []) + identifiers
11
+ end
12
+
13
+ def self.identifier(identifier=nil)
14
+ self._identifiers = [] unless instance_variable_defined?(:@_identifiers)
15
+ identifier.nil? ? self.identifiers.first : self.identifiers(identifier)
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ module Nanoc
2
+ class PluginManager
3
+
4
+ @@data_sources = {}
5
+ @@filters = {}
6
+ @@layout_processors = {}
7
+
8
+ def self.subclasses_of(superclass)
9
+ subclasses = []
10
+ ObjectSpace.each_object(Class) { |subclass| subclasses << subclass if subclass < superclass }
11
+ subclasses
12
+ end
13
+
14
+ def self.data_source_named(name)
15
+ @@data_sources[name.to_sym] ||= subclasses_of(DataSource).find do |klass|
16
+ klass.identifiers.include?(name.to_sym)
17
+ end
18
+ end
19
+
20
+ def self.filter_named(name)
21
+ @@filters[name.to_sym] ||= subclasses_of(Filter).find do |klass|
22
+ klass.identifiers.include?(name.to_sym)
23
+ end
24
+ end
25
+
26
+ def self.layout_processor_for_extension(ext)
27
+ @@filters[ext.to_sym] ||= subclasses_of(LayoutProcessor).find do |klass|
28
+ klass.extensions.include?(ext)
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,143 @@
1
+ module Nanoc
2
+ class Site
3
+
4
+ DEFAULT_CONFIG = {
5
+ :output_dir => 'output',
6
+ :eruby_engine => 'erb',
7
+ :data_source => 'filesystem'
8
+ }
9
+
10
+ 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
21
+ # Load configuration
22
+ @config = DEFAULT_CONFIG.merge((YAML.load_file('config.yaml') || {}).clean)
23
+
24
+ # 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?
27
+ @data_source = @data_source_class.new(self)
28
+
29
+ # Create compiler
30
+ @compiler = Compiler.new(self)
31
+ @autocompiler = AutoCompiler.new(self)
32
+
33
+ # Set not loaded
34
+ @data_loaded = false
35
+ end
36
+
37
+ def load_data(force=false)
38
+ return if @data_loaded and !force
39
+
40
+ # Load data
41
+ @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
47
+ end
48
+
49
+ # Setup child-parent links
50
+ @pages.each do |page|
51
+ # Skip pages without parent
52
+ next if page.path == '/'
53
+
54
+ # Get parent
55
+ parent_path = page.path.sub(/[^\/]+\/$/, '')
56
+ parent = @pages.find { |p| p.path == parent_path }
57
+
58
+ # Link
59
+ page.parent = parent
60
+ parent.children << page
61
+ end
62
+
63
+ # Set loaded
64
+ @data_loaded = true
65
+ end
66
+
67
+ # Creating a new site on disk
68
+
69
+ def self.create(sitename)
70
+ # Check whether site exists
71
+ error "A site named '#{sitename}' already exists." if File.exist?(sitename)
72
+
73
+ FileUtils.mkdir_p sitename
74
+ in_dir([sitename]) do
75
+ # Create output
76
+ FileManager.create_dir 'output'
77
+
78
+ # Create config
79
+ FileManager.create_file 'config.yaml' do
80
+ "output_dir: \"output\"\n" +
81
+ "data_source: \"filesystem\"\n"
82
+ end
83
+
84
+ # Create rakefile
85
+ FileManager.create_file 'Rakefile' do
86
+ "Dir['tasks/**/*.rake'].sort.each { |rakefile| load rakefile }\n" +
87
+ "\n" +
88
+ "task :default do\n" +
89
+ " puts 'This is an example rake task.'\n" +
90
+ "end\n"
91
+ end
92
+
93
+ # Create tasks
94
+ FileManager.create_file 'tasks/default.rake' do
95
+ "task :example do\n" +
96
+ " puts 'This is an example rake task in tasks/default.rake.'\n" +
97
+ "end\n"
98
+ end
99
+
100
+ # Setup site
101
+ Site.from_cwd.setup
102
+ end
103
+ end
104
+
105
+ # Compiling
106
+
107
+ def compile
108
+ @compiler.run
109
+ end
110
+
111
+ def autocompile(port)
112
+ @autocompiler.start(port)
113
+ end
114
+
115
+ # Creating
116
+
117
+ def setup
118
+ @data_source.loading { @data_source.setup }
119
+ end
120
+
121
+ def create_page(name, template_name='default')
122
+ load_data
123
+
124
+ template = @templates.find { |t| t[:name] == template_name }
125
+ error "A template named '#{template_name}' was not found; aborting." if template.nil?
126
+
127
+ @data_source.loading { @data_source.create_page(name, template) }
128
+ end
129
+
130
+ def create_template(name)
131
+ load_data
132
+
133
+ @data_source.loading {@data_source.create_template(name) }
134
+ end
135
+
136
+ def create_layout(name)
137
+ load_data
138
+
139
+ @data_source.loading { @data_source.create_layout(name) }
140
+ end
141
+
142
+ end
143
+ end
@@ -0,0 +1,259 @@
1
+ begin ; require 'active_record' ; rescue LoadError ; end
2
+
3
+ module Nanoc::DataSource::Database
4
+
5
+ ########## Helper classes ##########
6
+
7
+ begin
8
+
9
+ class DatabasePage < ActiveRecord::Base
10
+ set_table_name 'pages'
11
+ end
12
+
13
+ class DatabasePageDefault < ActiveRecord::Base
14
+ set_table_name 'page_defaults'
15
+ end
16
+
17
+ class DatabaseTemplate < ActiveRecord::Base
18
+ set_table_name 'templates'
19
+ end
20
+
21
+ class DatabaseLayout < ActiveRecord::Base
22
+ set_table_name 'layouts'
23
+ end
24
+
25
+ class DatabaseCodePiece < ActiveRecord::Base
26
+ set_table_name 'code_pieces'
27
+ end
28
+
29
+ rescue NameError
30
+ end
31
+
32
+ class DatabaseDataSource < Nanoc::DataSource
33
+
34
+ ########## Attributes ##########
35
+
36
+ identifier :database
37
+
38
+ ########## Preparation ##########
39
+
40
+ def up
41
+ nanoc_require 'active_record'
42
+
43
+ # Connect to the database
44
+ ActiveRecord::Base.establish_connection(@site.config[:database])
45
+ end
46
+
47
+ def down
48
+ # Disconnect from the database
49
+ ActiveRecord::Base.remove_connection
50
+ end
51
+
52
+ def setup
53
+ # Create tables
54
+ schema = ActiveRecord::Schema
55
+ schema.verbose = false
56
+ schema.define do
57
+
58
+ create_table :pages, :force => true do |t|
59
+ t.column :content, :text
60
+ t.column :path, :string
61
+ t.column :meta, :text
62
+ end
63
+
64
+ create_table :page_defaults, :force => true do |t|
65
+ t.column :meta, :text
66
+ end
67
+
68
+ create_table :layouts, :force => true do |t|
69
+ t.column :name, :string
70
+ t.column :content, :text
71
+ t.column :extension, :string
72
+ end
73
+
74
+ create_table :templates, :force => true do |t|
75
+ t.column :content, :text
76
+ t.column :name, :string
77
+ t.column :meta, :text
78
+ end
79
+
80
+ create_table :code_pieces, :force => true do |t|
81
+ t.column :name, :string
82
+ t.column :code, :text
83
+ end
84
+
85
+ end
86
+
87
+ # Create first page
88
+ DatabasePage.create(
89
+ :path => '/',
90
+ :content => "I'm a brand new root page. Please edit me!\n",
91
+ :meta => "# Built-in\n" +
92
+ "\n" +
93
+ "# Custom\n" +
94
+ "title: \"A New Root Page\"\n"
95
+ )
96
+
97
+ # Create page defaults
98
+ DatabasePageDefault.create(
99
+ :meta => "# Built-in\n" +
100
+ "custom_path: none\n" +
101
+ "extension: \"html\"\n" +
102
+ "filename: \"index\"\n" +
103
+ "filters_post: []\n" +
104
+ "filters_pre: []\n" +
105
+ "is_draft: false\n" +
106
+ "layout: \"default\"\n" +
107
+ "skip_output: false\n" +
108
+ "\n" +
109
+ "# Custom\n"
110
+ )
111
+
112
+ # Create default layout
113
+ DatabaseLayout.create(
114
+ :name => 'default',
115
+ :content => "<html>\n" +
116
+ " <head>\n" +
117
+ " <title><%= @page.title %></title>\n" +
118
+ " </head>\n" +
119
+ " <body>\n" +
120
+ "<%= @page.content %>\n" +
121
+ " </body>\n" +
122
+ "</html>",
123
+ :extension => '.erb'
124
+ )
125
+
126
+ # Create default template
127
+ DatabaseTemplate.create(
128
+ :name => 'default',
129
+ :content => 'Hi, I\'m a new page!',
130
+ :meta => "# Built-in\n" +
131
+ "\n" +
132
+ "# Custom\n" +
133
+ "title: \"A New Page\"\n"
134
+ )
135
+
136
+ # Create default code piece
137
+ DatabaseCodePiece.create(
138
+ :name => 'default',
139
+ :code => "def html_escape(str)\n" +
140
+ " str.gsub('&', '&amp;').str('<', '&lt;').str('>', '&gt;').str('\"', '&quot;')\n" +
141
+ "end\n" +
142
+ "alias h html_escape\n"
143
+ )
144
+
145
+ log(:high, "Set up database schema.")
146
+ end
147
+
148
+ ########## Loading data ##########
149
+
150
+ def pages
151
+ # Create Pages for each database object
152
+ DatabasePage.find(:all).inject([]) do |pages, page|
153
+ # Read metadata
154
+ hash = (YAML.load(page.meta || '') || {}).clean
155
+
156
+ if hash[:is_draft]
157
+ # Skip drafts
158
+ pages
159
+ else
160
+ # Get extra info
161
+ extras = { :path => page.path, :uncompiled_content => page.content }
162
+
163
+ # Add to list of pages
164
+ pages + [ hash.merge(extras) ]
165
+ end
166
+ end
167
+ end
168
+
169
+ def page_defaults
170
+ YAML.load(DatabasePageDefault.find(:first).meta) || {}
171
+ end
172
+
173
+ def layouts
174
+ DatabaseLayout.find(:all).map do |layout|
175
+ {
176
+ :name => layout.name,
177
+ :content => layout.content,
178
+ :extension => layout.extension
179
+ }
180
+ end
181
+ end
182
+
183
+ def templates
184
+ DatabaseTemplate.find(:all).map do |template|
185
+ {
186
+ :name => template.name,
187
+ :content => template.content,
188
+ :meta => template.meta
189
+ }
190
+ end
191
+ end
192
+
193
+ def code
194
+ DatabaseCodePiece.find(:all).map { |p| p.code }.join("\n")
195
+ end
196
+
197
+ ########## Creating data ##########
198
+
199
+ def create_page(path, template)
200
+ # Make sure path does not start or end with a slash
201
+ sanitized_path = ('/' + path + '/').gsub(/^\/+|\/+$/, '/')
202
+
203
+ # Make sure the page doesn't exist yet
204
+ unless DatabasePage.find_all_by_path(sanitized_path).empty?
205
+ error "A page named '#{sanitized_path}' already exists."
206
+ end
207
+
208
+ # Create page
209
+ DatabasePage.create(
210
+ :path => sanitized_path,
211
+ :content => "I'm a brand new page. Please edit me!\n",
212
+ :meta => "# Built-in\n\n# Custom\ntitle: A New Page\n"
213
+ )
214
+
215
+ log(:high, "Created page '#{sanitized_path}'.")
216
+ end
217
+
218
+ def create_layout(name)
219
+ # Make sure the layout doesn't exist yet
220
+ unless DatabaseLayout.find_all_by_name(name).empty?
221
+ error "A layout named '#{name}' already exists."
222
+ end
223
+
224
+ # Create layout
225
+ DatabaseLayout.create(
226
+ :name => name,
227
+ :content => "<html>\n" +
228
+ " <head>\n" +
229
+ " <title><%= @page.title %></title>\n" +
230
+ " </head>\n" +
231
+ " <body>\n" +
232
+ "<%= @page.content %>\n" +
233
+ " </body>\n" +
234
+ "</html>",
235
+ :extension => '.erb'
236
+ )
237
+
238
+ log(:high, "Created layout '#{name}'.")
239
+ end
240
+
241
+ def create_template(name)
242
+ # Make sure the layout doesn't exist yet
243
+ unless DatabaseTemplate.find_all_by_name(name).empty?
244
+ error "A template named '#{name}' already exists."
245
+ end
246
+
247
+ # Create template
248
+ DatabaseTemplate.create(
249
+ :name => name,
250
+ :content => "Hi, I'm a brand new page!\n",
251
+ :meta => "# Built-in\n\n# Custom\ntitle: A New Page\n"
252
+ )
253
+
254
+ log(:high,"Created template '#{name}'.")
255
+ end
256
+
257
+ end
258
+
259
+ end