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,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