nanoc 2.0.4 → 2.1

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 (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,64 @@
1
+ module Nanoc
2
+
3
+ # A Nanoc::Template represents a template, which can be used for creating
4
+ # new pages. Pages don't necessary have to be created using templates, but
5
+ # they can be useful for generating pages where you only have to "fill in
6
+ # the blanks".
7
+ class Template
8
+
9
+ # The Nanoc::Site this template belongs to.
10
+ attr_accessor :site
11
+
12
+ # The name of this template.
13
+ attr_reader :name
14
+
15
+ # The raw content a page created using this template will have.
16
+ attr_reader :page_content
17
+
18
+ # A hash containing the attributes a page created using this template will
19
+ # have.
20
+ attr_reader :page_attributes
21
+
22
+ # Creates a new template.
23
+ #
24
+ # +name+:: The name of this template.
25
+ #
26
+ # +page_content+:: The raw content a page created using this template will
27
+ # have.
28
+ #
29
+ # +page_attributes+:: A hash containing the attributes a page created
30
+ # using this template will have.
31
+ def initialize(page_content, page_attributes, name)
32
+ @page_content = page_content
33
+ @page_attributes = page_attributes.clean
34
+ @name = name
35
+ end
36
+
37
+ # Saves the template in the database, creating it if it doesn't exist yet
38
+ # or updating it if it already exists. Tells the site's data source to
39
+ # save the template.
40
+ def save
41
+ @site.data_source.loading do
42
+ @site.data_source.save_template(self)
43
+ end
44
+ end
45
+
46
+ # Renames the template. Tells the site's data source to rename the
47
+ # template.
48
+ def move_to(new_name)
49
+ @site.data_source.loading do
50
+ @site.data_source.move_template(self, new_name)
51
+ end
52
+ end
53
+
54
+ # Deletes the template. Tells the site's data source to delete the
55
+ # template.
56
+ def delete
57
+ @site.data_source.loading do
58
+ @site.data_source.delete_template(self)
59
+ end
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,28 @@
1
+ module Nanoc::BinaryFilters
2
+
3
+ class ImageScienceThumbnail < Nanoc::BinaryFilter
4
+
5
+ identifier :image_science_thumbnail
6
+
7
+ def run(file)
8
+ require 'image_science'
9
+
10
+ # Get temporary file path
11
+ tmp_file = Tempfile.new('filter')
12
+ tmp_path = tmp_file.path
13
+ tmp_file.close
14
+
15
+ # Create thumbnail
16
+ ImageScience.with_image(file.path) do |img|
17
+ img.thumbnail(@asset_rep.thumbnail_size || 150) do |thumbnail|
18
+ thumbnail.save(tmp_path)
19
+ end
20
+ end
21
+
22
+ # Return thumbnail file
23
+ File.open(tmp_path)
24
+ end
25
+
26
+ end
27
+
28
+ end
data/lib/nanoc/cli.rb ADDED
@@ -0,0 +1 @@
1
+ Nanoc.load('cli', '*.rb')
@@ -0,0 +1,219 @@
1
+ module Nanoc::CLI
2
+
3
+ # Nanoc::CLI::Base is the central class representing a commandline nanoc
4
+ # tool. It has a list of commands, and is linked to a specific nanoc site.
5
+ class Base
6
+
7
+ attr_reader :commands, :site
8
+
9
+ # Creates a new instance of the commandline nanoc tool.
10
+ def initialize
11
+ create_commands
12
+ end
13
+
14
+ # Parses the given commandline arguments and executes the requested
15
+ # command.
16
+ def run(args)
17
+ # Check arguments
18
+ if args.length == 0
19
+ @help_command.run([], [])
20
+ exit 1
21
+ end
22
+
23
+ # Find version or help options
24
+ if args.length == 1
25
+ # Parse arguments
26
+ begin
27
+ parsed_arguments = Nanoc::CLI::OptionParser.parse(args[0..1], global_option_definitions)
28
+ rescue Nanoc::CLI::OptionParser::IllegalOptionError => e
29
+ $stderr.puts "illegal option -- #{e}"
30
+ exit 1
31
+ end
32
+
33
+ # Handle version option
34
+ if parsed_arguments[:options].has_key?(:version)
35
+ puts "nanoc #{Nanoc::VERSION} (c) 2007-2008 Denis Defreyne."
36
+ exit 1
37
+ # Handle help option
38
+ elsif parsed_arguments[:options].has_key?(:help)
39
+ show_help
40
+ exit 1
41
+ end
42
+ end
43
+
44
+ # Find command
45
+ command = command_named(args[0])
46
+
47
+ # Get extended option definitions (with help)
48
+ extended_option_definitions = command.option_definitions + [
49
+ # --help
50
+ {
51
+ :long => 'help', :short => 'h', :argument => :forbidden,
52
+ :desc => 'show this help message and quit'
53
+ },
54
+ # --verbose
55
+ {
56
+ :long => 'verbose', :short => 'V', :argument => :forbidden,
57
+ :desc => 'enable more detailed output'
58
+ }
59
+ ]
60
+
61
+ # Parse arguments
62
+ begin
63
+ parsed_arguments = Nanoc::CLI::OptionParser.parse(args[1..-1], extended_option_definitions)
64
+ rescue Nanoc::CLI::OptionParser::IllegalOptionError => e
65
+ $stderr.puts "illegal option -- #{e}"
66
+ exit 1
67
+ rescue Nanoc::CLI::OptionParser::OptionRequiresAnArgumentError => e
68
+ $stderr.puts "option requires an argument -- #{e}"
69
+ exit 1
70
+ end
71
+
72
+ # Check help option
73
+ if parsed_arguments[:options].has_key?(:help)
74
+ show_help(command)
75
+ exit 1
76
+ end
77
+
78
+ # Check verbose option
79
+ if parsed_arguments[:options].has_key?(:verbose)
80
+ Nanoc::CLI::Logger.instance.level = :low
81
+ end
82
+
83
+ # Find and run command
84
+ command.run(parsed_arguments[:options], parsed_arguments[:arguments])
85
+ end
86
+
87
+ # Returns the command with the given name.
88
+ def command_named(name)
89
+ # Find by exact name or alias
90
+ command = @commands.find { |c| c.name == name or c.aliases.include?(name) }
91
+ return command unless command.nil?
92
+
93
+ # Find by approximation
94
+ commands = @commands.select { |c| c.name[0, name.length] == name }
95
+ if commands.length > 1
96
+ $stderr.puts "nanoc: '#{name}' is ambiguous:"
97
+ $stderr.puts " #{commands.map { |c| c.name }.join(' ') }"
98
+ exit 1
99
+ elsif commands.length == 0
100
+ $stderr.puts "nanoc: unknown command '#{name}'\n"
101
+ show_help
102
+ exit 1
103
+ else
104
+ return commands[0]
105
+ end
106
+ end
107
+
108
+ # Shows the help text for the given command, or shows the general help
109
+ # text if no command is given.
110
+ def show_help(command=nil)
111
+ if command.nil?
112
+ @help_command.run([], [])
113
+ else
114
+ @help_command.run([], [ command.name ])
115
+ end
116
+ end
117
+
118
+ # Helper function which can be called when a command is executed that
119
+ # requires a site, such as the compile command.
120
+ def require_site
121
+ if site.nil?
122
+ $stderr.puts 'The current working directory does not seem to be a ' +
123
+ 'valid/complete nanoc site directory; aborting.'
124
+ exit 1
125
+ end
126
+ end
127
+
128
+ # Gets the site (Nanoc::Site) in the current directory and loads its data.
129
+ def site
130
+ # Load site if possible
131
+ if File.file?('config.yaml') and @site.nil?
132
+ begin
133
+ @site = Nanoc::Site.new(YAML.load_file('config.yaml'))
134
+ @site.load_data
135
+ rescue Nanoc::Errors::UnknownDataSourceError => e
136
+ $stderr.puts "Unknown data source: #{e}"
137
+ exit 1
138
+ rescue Nanoc::Errors::UnknownRouterError => e
139
+ $stderr.puts "Unknown router: #{e}"
140
+ exit 1
141
+ rescue Exception => e
142
+ $stderr.puts "ERROR: An exception occured while loading this site."
143
+ $stderr.puts
144
+ $stderr.puts "If you think this is a bug in nanoc, please do report it at " +
145
+ "<http://nanoc.stoneship.org/trac/newticket> -- thanks!"
146
+ $stderr.puts
147
+ $stderr.puts 'Message:'
148
+ $stderr.puts ' ' + e.message
149
+ $stderr.puts
150
+ $stderr.puts 'Backtrace:'
151
+ $stderr.puts e.backtrace.map { |t| ' - ' + t }.join("\n")
152
+ exit 1
153
+ end
154
+ end
155
+
156
+ @site
157
+ end
158
+
159
+ # Sets the data source's VCS to the VCS with the given name. Does nothing
160
+ # when the site's data source does not support VCSes (i.e. does not
161
+ # implement #vcs=).
162
+ def set_vcs(vcs_name)
163
+ # Skip if not possible
164
+ return if vcs_name.nil?
165
+ return if site.nil? or !site.data_source.respond_to?(:vcs=)
166
+
167
+ # Find VCS
168
+ vcs_class = Nanoc::Extra::VCS.named(vcs_name.to_sym)
169
+ if vcs_class.nil?
170
+ $stderr.puts "A VCS named #{vcs_name} was not found; aborting."
171
+ exit 1
172
+ end
173
+
174
+ # Set VCS
175
+ site.data_source.vcs = vcs_class.new
176
+ end
177
+
178
+ # Returns the list of global option definitionss.
179
+ def global_option_definitions
180
+ [
181
+ {
182
+ :long => 'help', :short => 'h', :argument => :forbidden,
183
+ :desc => 'show this help message and quit'
184
+ },
185
+ {
186
+ :long => 'version', :short => 'v', :argument => :forbidden,
187
+ :desc => 'show version information and quit'
188
+ }
189
+ ]
190
+ end
191
+
192
+ protected
193
+
194
+ def create_commands
195
+ @commands = []
196
+
197
+ # Find all command classes
198
+ command_classes = []
199
+ ObjectSpace.each_object(Class) do |klass|
200
+ command_classes << klass if klass < Nanoc::CLI::Command
201
+ end
202
+
203
+ # Create commands
204
+ command_classes.each do |klass|
205
+ if klass.to_s == 'Nanoc::CLI::HelpCommand'
206
+ @help_command = HelpCommand.new
207
+ @commands << @help_command
208
+ else
209
+ @commands << klass.new
210
+ end
211
+ end
212
+
213
+ # Set base
214
+ @commands.each { |c| c.base = self }
215
+ end
216
+
217
+ end
218
+
219
+ end
@@ -0,0 +1,16 @@
1
+ module Nanoc::CLI # :nodoc:
2
+ end
3
+
4
+ # Load extensions
5
+ Nanoc.load('cli', 'ext.rb')
6
+ Nanoc.load('cli', 'option_parser.rb')
7
+
8
+ # Load logger
9
+ Nanoc.load('cli', 'logger.rb')
10
+
11
+ # Load commands
12
+ Nanoc.load('cli', 'command.rb')
13
+ Nanoc.load('cli', 'commands', '*.rb')
14
+
15
+ # Load base
16
+ Nanoc.load('cli', 'base.rb')
@@ -0,0 +1,105 @@
1
+ module Nanoc::CLI
2
+
3
+ # Nanoc::CLI::Command represents a command that can be executed on the
4
+ # commandline. It is an abstract superclass for all commands.
5
+ class Command
6
+
7
+ attr_accessor :base
8
+
9
+ # Returns a string containing the name of thi command. Subclasses must
10
+ # implement this method.
11
+ def name
12
+ raise NotImplementedError.new("Command subclasses should override #name")
13
+ end
14
+
15
+ # Returns an array of strings containing the aliases for this command.
16
+ # Subclasses must implement this method.
17
+ def aliases
18
+ raise NotImplementedError.new("Command subclasses should override #aliases")
19
+ end
20
+
21
+ # Returns a string containing this command's short description, which
22
+ # should not be longer than 50 characters. Subclasses must implement this
23
+ # method.
24
+ def short_desc
25
+ raise NotImplementedError.new("Command subclasses should override #short_desc")
26
+ end
27
+
28
+ # Returns a string containing this command's complete description, which
29
+ # should explain what this command does and how it works in detail.
30
+ # Subclasses must implement this method.
31
+ def long_desc
32
+ raise NotImplementedError.new("Command subclasses should override #long_desc")
33
+ end
34
+
35
+ # Returns a string containing this command's usage. Subclasses must
36
+ # implement this method.
37
+ def usage
38
+ raise NotImplementedError.new("Command subclasses should override #usage")
39
+ end
40
+
41
+ # Returns an array containing this command's option definitions. See the
42
+ # documentation for Nanoc::CLI::OptionParser for details on what option
43
+ # definitions look like. Subclasses may implement this method if the
44
+ # command has options.
45
+ def option_definitions
46
+ []
47
+ end
48
+
49
+ # Executes the command. Subclasses must implement this method
50
+ # (obviously... what's the point of a command that can't be run?).
51
+ #
52
+ # +options+:: A hash containing the parsed commandline options. For
53
+ # example, '--foo=bar' will be converted into { :foo => 'bar'
54
+ # }. See the Nanoc::CLI::OptionParser documentation for
55
+ # details.
56
+ #
57
+ # +arguments+:: An array of strings representing the commandline arguments
58
+ # given to this command.
59
+ def run(options, arguments)
60
+ raise NotImplementedError.new("Command subclasses should override #run")
61
+ end
62
+
63
+ # Returns the help text for this command.
64
+ def help
65
+ text = ''
66
+
67
+ # Append usage
68
+ text << usage + "\n"
69
+
70
+ # Append aliases
71
+ unless aliases.empty?
72
+ text << "\n"
73
+ text << "aliases: #{aliases.join(' ')}\n"
74
+ end
75
+
76
+ # Append short description
77
+ text << "\n"
78
+ text << short_desc + "\n"
79
+
80
+ # Append long description
81
+ text << "\n"
82
+ text << long_desc.wrap_and_indent(78, 4) + "\n"
83
+
84
+ # Append options
85
+ unless option_definitions.empty?
86
+ text << "\n"
87
+ text << "options:\n"
88
+ text << "\n"
89
+ option_definitions.sort { |x,y| x[:long] <=> y[:long] }.each do |opt_def|
90
+ text << sprintf(" -%1s --%-10s %s\n", opt_def[:short], opt_def[:long], opt_def[:desc])
91
+ end
92
+ end
93
+
94
+ # Return text
95
+ text
96
+ end
97
+
98
+ # Compares this command's name to the other given command's name.
99
+ def <=>(other)
100
+ self.name <=> other.name
101
+ end
102
+
103
+ end
104
+
105
+ end
@@ -0,0 +1,80 @@
1
+ module Nanoc::CLI
2
+
3
+ class AutocompileCommand < Command # :nodoc:
4
+
5
+ def name
6
+ 'autocompile'
7
+ end
8
+
9
+ def aliases
10
+ [ 'aco', 'autocompile_site' ]
11
+ end
12
+
13
+ def short_desc
14
+ 'start the autocompiler'
15
+ end
16
+
17
+ def long_desc
18
+ handler_names = Nanoc::Extra::AutoCompiler::HANDLER_NAMES.join(', ')
19
+
20
+ 'Start the autocompiler web server. Unless specified, the web ' +
21
+ 'server will run on port 3000 and listen on all IP addresses. ' +
22
+ 'Running the autocompiler requires \'mime/types\' and \'rack\'.' +
23
+ "\n" +
24
+ 'Available handlers are (in order of preference): ' + handler_names +
25
+ ' (default is ' + Nanoc::Extra::AutoCompiler::HANDLER_NAMES[0].to_s + ').'
26
+ end
27
+
28
+ def usage
29
+ "nanoc autocompile [options]"
30
+ end
31
+
32
+ def option_definitions
33
+ [
34
+ # --all
35
+ {
36
+ :long => 'all', :short => 'a', :argument => :forbidden,
37
+ :desc => 'compile all pages, even those that aren\'t outdated'
38
+ },
39
+ # --port
40
+ {
41
+ :long => 'port', :short => 'p', :argument => :required,
42
+ :desc => 'specify a port number for the autocompiler'
43
+ },
44
+ # --handler
45
+ {
46
+ :long => 'handler', :short => 'H', :argument => :required,
47
+ :desc => 'specify the handler to use'
48
+ }
49
+ ]
50
+ end
51
+
52
+ def run(options, arguments)
53
+ # Check arguments
54
+ if arguments.size != 0
55
+ $stderr.puts "usage: #{usage}"
56
+ exit 1
57
+ end
58
+
59
+ # Make sure we are in a nanoc site directory
60
+ @base.require_site
61
+
62
+ # Autocompile site
63
+ begin
64
+ autocompiler = Nanoc::Extra::AutoCompiler.new(@base.site, options.has_key?(:all))
65
+ autocompiler.start(
66
+ options[:port],
67
+ options[:handler]
68
+ )
69
+ rescue LoadError
70
+ $stderr.puts "'mime/types' and 'rack' are required to autocompile sites. " +
71
+ "You may want to install the 'mime-types' and 'rack' gems by " +
72
+ "running 'gem install mime-types' and 'gem install rack'."
73
+ rescue Nanoc::Extra::AutoCompiler::UnknownHandlerError
74
+ $stderr.puts "The requested handler, #{options[:handler]}, is not available."
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ end