nanoc 1.6.2 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
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