nanoc 1.4 → 1.5

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.
@@ -0,0 +1,93 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ require 'fileutils'
4
+
5
+ def handle_exception(exception, text)
6
+ unless $quiet or exception.class == SystemExit
7
+ $stderr.puts "ERROR: Exception occured while #{text}:\n"
8
+ $stderr.puts exception
9
+ $stderr.puts exception.backtrace.join("\n")
10
+ end
11
+ exit
12
+ end
13
+
14
+ def deprecate(str)
15
+ $stderr.puts 'DEPRECATION WARNING: ' + str unless $quiet
16
+ end
17
+
18
+ class FileLogger
19
+ COLORS = {
20
+ :reset => "\e[0m",
21
+
22
+ :bold => "\e[1m",
23
+
24
+ :black => "\e[30m",
25
+ :red => "\e[31m",
26
+ :green => "\e[32m",
27
+ :yellow => "\e[33m",
28
+ :blue => "\e[34m",
29
+ :magenta => "\e[35m",
30
+ :cyan => "\e[36m",
31
+ :white => "\e[37m"
32
+ }
33
+
34
+ ACTION_COLORS = {
35
+ :create => COLORS[:bold] + COLORS[:green],
36
+ :update => COLORS[:bold] + COLORS[:yellow],
37
+ :move => COLORS[:bold] + COLORS[:blue],
38
+ :identical => COLORS[:bold]
39
+ }
40
+
41
+ attr_reader :out
42
+
43
+ def initialize(a_out = $stdout)
44
+ @out = a_out
45
+ end
46
+
47
+ def log(a_action, a_path)
48
+ @out.puts('%s%12s%s %s' % [ACTION_COLORS[a_action.to_sym], a_action, COLORS[:reset], a_path]) unless $quiet
49
+ end
50
+
51
+ private
52
+
53
+ def method_missing(a_method, *a_args)
54
+ log(a_method.to_s, a_args.first)
55
+ end
56
+ end
57
+
58
+ class FileManager
59
+ @@stack = []
60
+ @@logger = FileLogger.new
61
+
62
+ def self.create_dir(a_name)
63
+ @@stack.pushing(a_name) do
64
+ path = File.join(@@stack)
65
+ unless File.directory?(path)
66
+ FileUtils.mkdir_p(path)
67
+ @@logger.create(path)
68
+ end
69
+ yield if block_given?
70
+ end
71
+ end
72
+
73
+ def self.create_file(a_name)
74
+ path = File.join(@@stack + [ a_name ])
75
+ FileManager.create_dir(path.sub(/\/[^\/]+$/, '')) if @@stack.empty?
76
+ content = block_given? ? yield : nil
77
+ if File.exist?(path)
78
+ if block_given? and File.read(path) == content
79
+ @@logger.identical(path)
80
+ else
81
+ @@logger.update(path)
82
+ end
83
+ else
84
+ @@logger.create(path)
85
+ end
86
+ open(path, 'w') { |io| io.write(content) unless content.nil? }
87
+ end
88
+ end
89
+
90
+ def render(a_name, a_context={})
91
+ assigns = a_context.merge({ :page => @page, :pages => @pages })
92
+ File.read('layouts/' + a_name.to_s + '.erb').eruby(:assigns => assigns)
93
+ end
@@ -0,0 +1,7 @@
1
+ # Convenience function for registering filters
2
+ def register_filter(*names, &block)
3
+ names.each { |name| $nanoc_compiler.register_filter(name, &block) }
4
+ end
5
+
6
+ # Load all filters
7
+ Dir[File.join(File.dirname(__FILE__), 'filters', '*_filter.rb')].each { |f| require f }
@@ -0,0 +1,44 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+
5
+ require 'erb'
6
+ try_require 'erubis'
7
+
8
+ class ERBContext
9
+
10
+ def initialize(hash)
11
+ hash.each_pair do |key, value|
12
+ instance_variable_set('@' + key.to_s, value)
13
+ end
14
+ end
15
+
16
+ def get_binding
17
+ binding
18
+ end
19
+
20
+ end
21
+
22
+ class String
23
+
24
+ # Converts the string using eRuby
25
+ def eruby(params={})
26
+ params[:eruby_engine] == :erubis ? erubis(params) : erb(params)
27
+ end
28
+
29
+ # Converts the string using Erubis
30
+ def erubis(params={})
31
+ Erubis::Eruby.new(self).evaluate(params[:assigns] || {})
32
+ end
33
+
34
+ # Converts the string using ERB
35
+ def erb(params={})
36
+ ERB.new(self).result(ERBContext.new(params[:assigns] || {}).get_binding)
37
+ end
38
+
39
+ end
40
+
41
+ register_filter 'eruby' do |page, pages, config|
42
+ assigns = { :page => page, :pages => pages }
43
+ page.content.eruby(:assigns => assigns, :eruby_engine => config[:eruby_engine])
44
+ end
@@ -0,0 +1,24 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+
5
+ try_require 'haml'
6
+
7
+ class String
8
+
9
+ # Converts the string using Haml
10
+ def haml(params={})
11
+ options = (params[:haml_options] || {})
12
+ options[:locals] = params[:assigns] unless params[:assigns].nil?
13
+ Haml::Engine.new(self, options).to_html
14
+ rescue NameError
15
+ $stderr.puts 'ERROR: String#haml failed (Haml not installed?)' unless $quiet
16
+ exit
17
+ end
18
+
19
+ end
20
+
21
+ register_filter 'haml' do |page, pages, config|
22
+ assigns = { :page => page, :pages => pages }
23
+ page.content.haml(:assigns => assigns, :haml_options => page[:haml_options])
24
+ end
@@ -0,0 +1,51 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+
5
+ try_require 'liquid'
6
+
7
+ class String
8
+
9
+ # Converts the string using Liquid
10
+ def liquid(params={})
11
+ Liquid::Template.parse(self).render((params[:assigns] || {}).stringify_keys)
12
+ rescue NameError
13
+ $stderr.puts 'ERROR: String#liquid failed (Liquid not installed?)' unless $quiet
14
+ exit
15
+ end
16
+
17
+ end
18
+
19
+ begin
20
+ class Nanoc::LiquidRenderTag < ::Liquid::Tag
21
+ Syntax = /(['"])([^'"]+)\1/
22
+
23
+ def initialize(markup, tokens)
24
+ if markup =~ Syntax
25
+ @layout_name = $2
26
+ else
27
+ raise SyntaxError.new("Error in tag 'render' - Valid syntax: render '[layout]'")
28
+ end
29
+
30
+ super
31
+ end
32
+
33
+ def parse(tokens)
34
+ end
35
+
36
+ def render(context)
37
+ source = File.read('layouts/' + @layout_name + '.liquid')
38
+ partial = Liquid::Template.parse(source)
39
+
40
+ partial.render(context)
41
+ end
42
+ end
43
+
44
+ Liquid::Template.register_tag('render', Nanoc::LiquidRenderTag)
45
+ rescue NameError
46
+ end
47
+
48
+ register_filter 'liquid' do |page, pages, config|
49
+ assigns = { :page => page, :pages => pages }
50
+ page.content.liquid(:assigns => assigns)
51
+ end
@@ -0,0 +1,25 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+
5
+ require 'erb'
6
+
7
+ try_require 'markaby'
8
+
9
+ class String
10
+
11
+ # Converts the string using Markaby
12
+ # TODO perhaps add support for helpers
13
+ def markaby(params={})
14
+ Markaby::Builder.new((params[:assigns] || {})).instance_eval(self).to_s
15
+ rescue NameError
16
+ $stderr.puts 'ERROR: String#markaby failed (Markaby not installed?)' unless $quiet
17
+ exit
18
+ end
19
+
20
+ end
21
+
22
+ register_filter 'markaby' do |page, pages, config|
23
+ assigns = { :page => page, :pages => pages }
24
+ page.content.markaby(:assigns => assigns)
25
+ end
@@ -0,0 +1,21 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+
5
+ try_require 'bluecloth'
6
+
7
+ class String
8
+
9
+ # Converts the string to HTML using BlueCloth/Markdown.
10
+ def markdown
11
+ BlueCloth.new(self).to_html
12
+ rescue NameError
13
+ $stderr.puts 'ERROR: String#markdown failed: BlueCloth not installed' unless $quiet
14
+ exit
15
+ end
16
+
17
+ end
18
+
19
+ register_filter 'markdown', 'bluecloth' do |page, pages, config|
20
+ page.content.markdown
21
+ end
@@ -0,0 +1,19 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+
5
+ try_require 'rdoc/markup/simple_markup'
6
+ try_require 'rdoc/markup/simple_markup/to_html'
7
+
8
+ class String
9
+
10
+ # Converts the string using RDoc
11
+ def rdoc
12
+ SM::SimpleMarkup.new.convert(self, SM::ToHtml.new)
13
+ end
14
+
15
+ end
16
+
17
+ register_filter 'rdoc' do |page, pages, config|
18
+ page.content.rdoc
19
+ end
@@ -0,0 +1,18 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+
5
+ try_require 'haml'
6
+
7
+ class String
8
+
9
+ # Converts the string using Sass
10
+ def sass
11
+ Sass::Engine.new(self).render
12
+ end
13
+
14
+ end
15
+
16
+ register_filter 'sass' do |page, pages, config|
17
+ page.content.sass
18
+ end
@@ -0,0 +1,21 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+
5
+ try_require 'rubypants'
6
+
7
+ class String
8
+
9
+ # Converts the string using RubyPants/SmartyPants
10
+ def smartypants
11
+ RubyPants.new(self).to_html
12
+ rescue NameError
13
+ $stderr.puts 'ERROR: String#smartypants failed (RubyPants not installed?)' unless $quiet
14
+ exit
15
+ end
16
+
17
+ end
18
+
19
+ register_filter 'smartypants', 'rubypants' do |page, pages, config|
20
+ page.content.smartypants
21
+ end
@@ -0,0 +1,21 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+
5
+ try_require 'redcloth'
6
+
7
+ class String
8
+
9
+ # Converts the string using RedCloth/Textile
10
+ def textile
11
+ RedCloth.new(self).to_html
12
+ rescue NameError
13
+ $stderr.puts 'ERROR: String#textile failed (RedCloth not installed?)' unless $quiet
14
+ exit
15
+ end
16
+
17
+ end
18
+
19
+ register_filter 'textile', 'redcloth' do |page, pages, config|
20
+ page.content.textile
21
+ end
data/lib/nanoc/page.rb ADDED
@@ -0,0 +1,147 @@
1
+ def try_require(s) ; begin ; require s ; rescue LoadError ; end ; end
2
+
3
+ try_require 'rubygems'
4
+ try_require 'liquid'
5
+
6
+ module Nanoc
7
+
8
+ # Page drop
9
+
10
+ begin
11
+ class PageDrop < ::Liquid::Drop
12
+ def initialize(page)
13
+ @page = page
14
+ end
15
+
16
+ def before_method(name)
17
+ name == 'content' ? @page.content : @page.attributes[name.to_sym]
18
+ end
19
+ end
20
+ rescue NameError
21
+ class PageDrop
22
+ def initialize(*args)
23
+ $stderr.puts 'ERROR: Liquid not installed; cannot use Liquid in layouts.'
24
+ exit
25
+ end
26
+ end
27
+ end
28
+
29
+ # Page proxy
30
+
31
+ class PageProxy
32
+ def initialize(page, params={})
33
+ @page = page
34
+ @do_compile = (params[:compile] != false)
35
+ end
36
+
37
+ def [](key)
38
+ if key.to_sym == :content and @do_compile
39
+ @page.content
40
+ else
41
+ if key.to_s.starts_with?('_')
42
+ nil
43
+ elsif key.to_s.ends_with?('?')
44
+ @page.attributes[key.to_s[0..-2].to_sym]
45
+ else
46
+ @page.attributes[key]
47
+ end
48
+ end
49
+ end
50
+
51
+ def method_missing(method, *args)
52
+ self[method]
53
+ end
54
+ end
55
+
56
+ # Page
57
+
58
+ class Page
59
+
60
+ def initialize(hash={})
61
+ @attributes = hash
62
+ end
63
+
64
+ def attributes
65
+ @attributes
66
+ end
67
+
68
+ def content
69
+ compile
70
+ @attributes[:content]
71
+ end
72
+
73
+ # Proxy/Liquid support
74
+
75
+ def to_proxy(params={})
76
+ PageProxy.new(self, :compile => params[:compile])
77
+ end
78
+
79
+ def to_liquid
80
+ PageDrop.new(self)
81
+ end
82
+
83
+ # Compiling
84
+
85
+ def self.compile(pages)
86
+ @@compilation_stack = []
87
+ @@pages = pages
88
+
89
+ # Compile all pages
90
+ pages.each { |page| page.compile }
91
+ end
92
+
93
+ def compile
94
+ # Check for recursive call
95
+ if @@compilation_stack.include?(self)
96
+ # Print compilation stack
97
+ unless $quiet
98
+ $stderr.puts 'ERROR: Recursive call to page content.'
99
+ print_compilation_stack
100
+ end
101
+
102
+ exit
103
+ # Compile if not yet compiled
104
+ elsif @attributes[:content].nil?
105
+ @@compilation_stack.pushing(self) do
106
+ # Read page
107
+ content = File.read(@attributes[:_content_filename])
108
+
109
+ begin
110
+ # Get params
111
+ page = self.to_proxy(:compile => false)
112
+ pages = @@pages.map { |p| p.to_proxy }
113
+ config = $nanoc_compiler.config
114
+
115
+ # Filter page
116
+ @attributes[:content] = content
117
+ @attributes[:filters].each do |filter_name|
118
+ filter = $nanoc_compiler.filter_named(filter_name)
119
+ if filter.nil?
120
+ $stderr.puts 'WARNING: Unknown filter: ' + filter_name unless $quiet
121
+ else
122
+ @attributes[:content] = filter.call(page, pages, config)
123
+ end
124
+ end
125
+ rescue Exception => exception
126
+ handle_exception(exception, "compiling page '#{@attributes[:_content_filename]}'")
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ def print_compilation_stack
133
+ # Determine relevant part of compilation stack
134
+ stack_begin = @@compilation_stack.index(self)
135
+ stack_end = @@compilation_stack.size
136
+ relevant_stack_part = @@compilation_stack.last(stack_end - stack_begin)
137
+
138
+ # Print relevant part of compilation stack
139
+ $stderr.puts 'Page compilation stack:'
140
+ relevant_stack_part.each_with_index do |page, i|
141
+ $stderr.puts "#{i} #{page.attributes[:_content_filename]}"
142
+ end
143
+ end
144
+
145
+ end
146
+
147
+ end