nanoc3 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +3 -0
- data/LICENSE +19 -0
- data/NEWS.rdoc +262 -0
- data/README.rdoc +80 -0
- data/Rakefile +11 -0
- data/bin/nanoc3 +16 -0
- data/lib/nanoc3/base/code_snippet.rb +42 -0
- data/lib/nanoc3/base/compiler.rb +225 -0
- data/lib/nanoc3/base/compiler_dsl.rb +110 -0
- data/lib/nanoc3/base/core_ext/array.rb +21 -0
- data/lib/nanoc3/base/core_ext/hash.rb +23 -0
- data/lib/nanoc3/base/core_ext/string.rb +14 -0
- data/lib/nanoc3/base/core_ext.rb +5 -0
- data/lib/nanoc3/base/data_source.rb +197 -0
- data/lib/nanoc3/base/dependency_tracker.rb +291 -0
- data/lib/nanoc3/base/errors.rb +95 -0
- data/lib/nanoc3/base/filter.rb +60 -0
- data/lib/nanoc3/base/item.rb +87 -0
- data/lib/nanoc3/base/item_rep.rb +236 -0
- data/lib/nanoc3/base/layout.rb +53 -0
- data/lib/nanoc3/base/notification_center.rb +68 -0
- data/lib/nanoc3/base/plugin.rb +88 -0
- data/lib/nanoc3/base/preprocessor_context.rb +37 -0
- data/lib/nanoc3/base/rule.rb +37 -0
- data/lib/nanoc3/base/rule_context.rb +68 -0
- data/lib/nanoc3/base/site.rb +334 -0
- data/lib/nanoc3/base.rb +25 -0
- data/lib/nanoc3/cli/base.rb +151 -0
- data/lib/nanoc3/cli/commands/autocompile.rb +89 -0
- data/lib/nanoc3/cli/commands/compile.rb +279 -0
- data/lib/nanoc3/cli/commands/create_item.rb +79 -0
- data/lib/nanoc3/cli/commands/create_layout.rb +94 -0
- data/lib/nanoc3/cli/commands/create_site.rb +320 -0
- data/lib/nanoc3/cli/commands/help.rb +71 -0
- data/lib/nanoc3/cli/commands/info.rb +114 -0
- data/lib/nanoc3/cli/commands/update.rb +96 -0
- data/lib/nanoc3/cli/commands.rb +13 -0
- data/lib/nanoc3/cli/logger.rb +73 -0
- data/lib/nanoc3/cli.rb +16 -0
- data/lib/nanoc3/data_sources/delicious.rb +66 -0
- data/lib/nanoc3/data_sources/filesystem.rb +231 -0
- data/lib/nanoc3/data_sources/filesystem_combined.rb +202 -0
- data/lib/nanoc3/data_sources/filesystem_common.rb +22 -0
- data/lib/nanoc3/data_sources/filesystem_compact.rb +232 -0
- data/lib/nanoc3/data_sources/last_fm.rb +103 -0
- data/lib/nanoc3/data_sources/twitter.rb +53 -0
- data/lib/nanoc3/data_sources.rb +20 -0
- data/lib/nanoc3/extra/auto_compiler.rb +97 -0
- data/lib/nanoc3/extra/chick.rb +119 -0
- data/lib/nanoc3/extra/context.rb +24 -0
- data/lib/nanoc3/extra/core_ext/time.rb +19 -0
- data/lib/nanoc3/extra/core_ext.rb +3 -0
- data/lib/nanoc3/extra/deployers/rsync.rb +64 -0
- data/lib/nanoc3/extra/deployers.rb +12 -0
- data/lib/nanoc3/extra/file_proxy.rb +31 -0
- data/lib/nanoc3/extra/validators/links.rb +0 -0
- data/lib/nanoc3/extra/validators/w3c.rb +71 -0
- data/lib/nanoc3/extra/validators.rb +12 -0
- data/lib/nanoc3/extra/vcs.rb +65 -0
- data/lib/nanoc3/extra/vcses/bazaar.rb +21 -0
- data/lib/nanoc3/extra/vcses/dummy.rb +20 -0
- data/lib/nanoc3/extra/vcses/git.rb +21 -0
- data/lib/nanoc3/extra/vcses/mercurial.rb +21 -0
- data/lib/nanoc3/extra/vcses/subversion.rb +21 -0
- data/lib/nanoc3/extra/vcses.rb +17 -0
- data/lib/nanoc3/extra.rb +16 -0
- data/lib/nanoc3/filters/bluecloth.rb +13 -0
- data/lib/nanoc3/filters/coderay.rb +17 -0
- data/lib/nanoc3/filters/erb.rb +19 -0
- data/lib/nanoc3/filters/erubis.rb +17 -0
- data/lib/nanoc3/filters/haml.rb +20 -0
- data/lib/nanoc3/filters/less.rb +13 -0
- data/lib/nanoc3/filters/markaby.rb +14 -0
- data/lib/nanoc3/filters/maruku.rb +14 -0
- data/lib/nanoc3/filters/rainpress.rb +13 -0
- data/lib/nanoc3/filters/rdiscount.rb +13 -0
- data/lib/nanoc3/filters/rdoc.rb +23 -0
- data/lib/nanoc3/filters/redcloth.rb +14 -0
- data/lib/nanoc3/filters/relativize_paths.rb +32 -0
- data/lib/nanoc3/filters/rubypants.rb +14 -0
- data/lib/nanoc3/filters/sass.rb +17 -0
- data/lib/nanoc3/filters.rb +37 -0
- data/lib/nanoc3/helpers/blogging.rb +226 -0
- data/lib/nanoc3/helpers/breadcrumbs.rb +25 -0
- data/lib/nanoc3/helpers/capturing.rb +71 -0
- data/lib/nanoc3/helpers/filtering.rb +46 -0
- data/lib/nanoc3/helpers/html_escape.rb +22 -0
- data/lib/nanoc3/helpers/link_to.rb +120 -0
- data/lib/nanoc3/helpers/rendering.rb +76 -0
- data/lib/nanoc3/helpers/tagging.rb +58 -0
- data/lib/nanoc3/helpers/text.rb +40 -0
- data/lib/nanoc3/helpers/xml_sitemap.rb +69 -0
- data/lib/nanoc3/helpers.rb +16 -0
- data/lib/nanoc3/package.rb +106 -0
- data/lib/nanoc3/tasks/clean.rake +16 -0
- data/lib/nanoc3/tasks/clean.rb +33 -0
- data/lib/nanoc3/tasks/deploy/rsync.rake +11 -0
- data/lib/nanoc3/tasks/validate.rake +35 -0
- data/lib/nanoc3/tasks.rb +9 -0
- data/lib/nanoc3.rb +19 -0
- data/vendor/cri/ChangeLog +0 -0
- data/vendor/cri/LICENSE +19 -0
- data/vendor/cri/NEWS +0 -0
- data/vendor/cri/README +4 -0
- data/vendor/cri/Rakefile +25 -0
- data/vendor/cri/lib/cri/base.rb +153 -0
- data/vendor/cri/lib/cri/command.rb +105 -0
- data/vendor/cri/lib/cri/core_ext/string.rb +41 -0
- data/vendor/cri/lib/cri/core_ext.rb +8 -0
- data/vendor/cri/lib/cri/option_parser.rb +186 -0
- data/vendor/cri/lib/cri.rb +12 -0
- data/vendor/cri/test/test_base.rb +6 -0
- data/vendor/cri/test/test_command.rb +6 -0
- data/vendor/cri/test/test_core_ext.rb +21 -0
- data/vendor/cri/test/test_option_parser.rb +279 -0
- metadata +225 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::Helpers
|
4
|
+
|
5
|
+
# Nanoc3::Helpers::Text contains several useful text-related helper functions.
|
6
|
+
module Text
|
7
|
+
|
8
|
+
# Returns an excerpt for the given string. HTML tags are ignored, so if
|
9
|
+
# you don't want them to turn up, they should be stripped from the string
|
10
|
+
# before passing it to the excerpt function.
|
11
|
+
#
|
12
|
+
# +params+ is a hash where the following keys can be set:
|
13
|
+
#
|
14
|
+
# +length+:: The maximum number of characters this excerpt can contain,
|
15
|
+
# including the omission. Defaults to 25.
|
16
|
+
#
|
17
|
+
# +omission+:: The string to append to the excerpt when the excerpt is
|
18
|
+
# shorter than the original string. Defaults to '...' (but in
|
19
|
+
# HTML, you may want to use something more fancy, like
|
20
|
+
# '…').
|
21
|
+
def excerptize(string, params={})
|
22
|
+
# Initialize params
|
23
|
+
params[:length] ||= 25
|
24
|
+
params[:omission] ||= '...'
|
25
|
+
|
26
|
+
# Get excerpt
|
27
|
+
length = params[:length] - params[:omission].length
|
28
|
+
length = 0 if length < 0
|
29
|
+
(string.length > params[:length] ? string[0...length] + params[:omission] : string)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Strips all HTML tags out of the given string.
|
33
|
+
def strip_html(string)
|
34
|
+
# FIXME will need something more sophisticated than this, because it sucks
|
35
|
+
string.gsub(/<[^>]*(>+|\s*\z)/m, '').strip
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::Helpers
|
4
|
+
|
5
|
+
# Nanoc3::Helpers::XMLSitemap contains functionality for building XML
|
6
|
+
# sitemaps that will be crawled by search engines. See the Sitemaps protocol
|
7
|
+
# web site, http://www.sitemaps.org, for details.
|
8
|
+
#
|
9
|
+
# To activate this helper, +include+ it, like this:
|
10
|
+
#
|
11
|
+
# include Nanoc3::Helpers::XMLSitemap
|
12
|
+
module XMLSitemap
|
13
|
+
|
14
|
+
# Returns the XML sitemap as a string.
|
15
|
+
#
|
16
|
+
# The following attributes can optionally be set on items to change the
|
17
|
+
# behaviour of the sitemap:
|
18
|
+
#
|
19
|
+
# * 'changefreq', containing the estimated change frequency as defined by
|
20
|
+
# the Sitemaps protocol.
|
21
|
+
#
|
22
|
+
# * 'priority', containing the item's priority, ranging from 0.0 to 1.0,
|
23
|
+
# as defined by the Sitemaps protocol.
|
24
|
+
#
|
25
|
+
# The sitemap will also include dates on which the items were updated.
|
26
|
+
# These are generated automatically; the way this happens depends on the
|
27
|
+
# used data source (the filesystem data source checks the file mtimes, for
|
28
|
+
# instance).
|
29
|
+
#
|
30
|
+
# The site configuration will need to have the following attributes:
|
31
|
+
#
|
32
|
+
# * 'base_url', containing the URL to the site, without trailing slash.
|
33
|
+
# For example, if the site is at "http://example.com/", the base_url
|
34
|
+
# would be "http://example.com".
|
35
|
+
def xml_sitemap
|
36
|
+
require 'builder'
|
37
|
+
|
38
|
+
# Create builder
|
39
|
+
buffer = ''
|
40
|
+
xml = Builder::XmlMarkup.new(:target => buffer, :indent => 2)
|
41
|
+
|
42
|
+
# Check for required attributes
|
43
|
+
if @site.config[:base_url].nil?
|
44
|
+
raise RuntimeError.new("The Nanoc3::Helpers::XMLSitemap helper requires the site configuration to specify the base URL for the site.")
|
45
|
+
end
|
46
|
+
|
47
|
+
# Build sitemap
|
48
|
+
xml.instruct!
|
49
|
+
xml.urlset(:xmlns => 'http://www.google.com/schemas/sitemap/0.84') do
|
50
|
+
# Add item
|
51
|
+
@items.reject { |i| i[:is_hidden] }.each do |item|
|
52
|
+
item.reps.reject { |r| r.raw_path.nil? }.each do |rep|
|
53
|
+
xml.url do
|
54
|
+
xml.loc @site.config[:base_url] + rep.path
|
55
|
+
xml.lastmod item.mtime.to_iso8601_date unless item.mtime.nil?
|
56
|
+
xml.changefreq item[:changefreq] unless item[:changefreq].nil?
|
57
|
+
xml.priority item[:priority] unless item[:priority].nil?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Return sitemap
|
64
|
+
buffer
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::Helpers
|
4
|
+
|
5
|
+
autoload 'Blogging', 'nanoc3/helpers/blogging'
|
6
|
+
autoload 'Breadcrumbs', 'nanoc3/helpers/breadcrumbs'
|
7
|
+
autoload 'Capturing', 'nanoc3/helpers/capturing'
|
8
|
+
autoload 'Filtering', 'nanoc3/helpers/filtering'
|
9
|
+
autoload 'HTMLEscape', 'nanoc3/helpers/html_escape'
|
10
|
+
autoload 'LinkTo', 'nanoc3/helpers/link_to'
|
11
|
+
autoload 'Rendering', 'nanoc3/helpers/rendering'
|
12
|
+
autoload 'Tagging', 'nanoc3/helpers/tagging'
|
13
|
+
autoload 'Text', 'nanoc3/helpers/text'
|
14
|
+
autoload 'XMLSitemap', 'nanoc3/helpers/xml_sitemap'
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
module Nanoc3
|
6
|
+
|
7
|
+
# Nanoc3::Package is a singleton that contains metadata about the nanoc
|
8
|
+
# project, which is used for packaging releases.
|
9
|
+
class Package
|
10
|
+
|
11
|
+
include Singleton
|
12
|
+
|
13
|
+
# The name of the application.
|
14
|
+
def name
|
15
|
+
'nanoc3'
|
16
|
+
end
|
17
|
+
|
18
|
+
# The files to include in the package. This is also the list of files that
|
19
|
+
# will be included in the documentation (with the exception of the files
|
20
|
+
# in undocumented_files).
|
21
|
+
def files
|
22
|
+
@files ||= (%w( ChangeLog LICENSE NEWS.rdoc Rakefile README.rdoc ) +
|
23
|
+
Dir['bin/**/*'] +
|
24
|
+
Dir['lib/**/*'] +
|
25
|
+
Dir['vendor/**/*']).reject { |f| File.directory?(f) }
|
26
|
+
end
|
27
|
+
|
28
|
+
# The files that are included in the documentation by default.
|
29
|
+
def files_documented_by_default
|
30
|
+
Dir['lib/**/*'].reject { |f| File.directory?(f) }
|
31
|
+
end
|
32
|
+
|
33
|
+
# The files that should not be included in the documentation.
|
34
|
+
def files_not_in_documentation
|
35
|
+
Dir['lib/**/*.rake'] +
|
36
|
+
Dir['vendor/**/*'].reject { |f| File.directory?(f) }
|
37
|
+
end
|
38
|
+
|
39
|
+
# The files that should be included in the documentation.
|
40
|
+
def files_in_documentation
|
41
|
+
files - files_not_in_documentation
|
42
|
+
end
|
43
|
+
|
44
|
+
# The files that are not documented by RDoc by default, but should still
|
45
|
+
# be included in the documentation.
|
46
|
+
def extra_rdoc_files
|
47
|
+
files_in_documentation - files_documented_by_default
|
48
|
+
end
|
49
|
+
|
50
|
+
# The name of the file that should be used as entry point for the
|
51
|
+
# documentation.
|
52
|
+
def main_documentation_file
|
53
|
+
'README.rdoc'
|
54
|
+
end
|
55
|
+
|
56
|
+
# The Gem::Specification used for packaging.
|
57
|
+
def gem_spec
|
58
|
+
@gem_spec ||= Gem::Specification.new do |s|
|
59
|
+
s.name = self.name
|
60
|
+
s.version = Nanoc3::VERSION
|
61
|
+
s.platform = Gem::Platform::RUBY
|
62
|
+
s.summary = 'a tool that runs on your local computer ' +
|
63
|
+
'and compiles Markdown, Textile, Haml, ' +
|
64
|
+
'... documents into static web pages'
|
65
|
+
s.description = s.summary
|
66
|
+
s.homepage = 'http://nanoc.stoneship.org/'
|
67
|
+
s.rubyforge_project = 'nanoc3'
|
68
|
+
|
69
|
+
s.author = 'Denis Defreyne'
|
70
|
+
s.email = 'denis.defreyne@stoneship.org'
|
71
|
+
|
72
|
+
s.post_install_message = <<EOS
|
73
|
+
------------------------------------------------------------------------------
|
74
|
+
Thanks for installing nanoc 3.0! Here are some resources to help you get started:
|
75
|
+
|
76
|
+
* The tutorial at <http://nanoc.stoneship.org/help/tutorial/>
|
77
|
+
* The manual at <http://nanoc.stoneship.org/help/manual/>
|
78
|
+
* The discussion group at <http://groups.google.com/group/nanoc>
|
79
|
+
|
80
|
+
Because nanoc 3.0 has a lot of new features, be sure to check out the nanoc blog at <http://nanoc.stoneship.org/blog/> for details about this release.
|
81
|
+
|
82
|
+
Enjoy!
|
83
|
+
------------------------------------------------------------------------------
|
84
|
+
EOS
|
85
|
+
|
86
|
+
s.required_ruby_version = '>= 1.8.5'
|
87
|
+
|
88
|
+
s.has_rdoc = true
|
89
|
+
s.extra_rdoc_files = self.extra_rdoc_files
|
90
|
+
s.rdoc_options = []
|
91
|
+
s.rdoc_options += [ '--title', self.name ]
|
92
|
+
s.rdoc_options += [ '--main', self.main_documentation_file ]
|
93
|
+
self.files_not_in_documentation.each do |file|
|
94
|
+
s.rdoc_options += [ '--exclude', file ]
|
95
|
+
end
|
96
|
+
|
97
|
+
s.files = self.files
|
98
|
+
s.executables = [ 'nanoc3' ]
|
99
|
+
s.require_path = 'lib'
|
100
|
+
s.bindir = 'bin'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
desc 'Remove output files generated by nanoc3'
|
4
|
+
task :clean do
|
5
|
+
# Load site
|
6
|
+
site = Nanoc3::Site.new('.')
|
7
|
+
if site.nil?
|
8
|
+
$stderr.puts 'The current working directory does not seem to be a ' +
|
9
|
+
'valid/complete nanoc site directory; aborting.'
|
10
|
+
exit 1
|
11
|
+
end
|
12
|
+
|
13
|
+
# Clean
|
14
|
+
clean = ::Nanoc3::Tasks::Clean.new(site)
|
15
|
+
clean.run
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3::Tasks
|
4
|
+
|
5
|
+
class Clean
|
6
|
+
|
7
|
+
def initialize(site)
|
8
|
+
@site = site
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
# Load site data
|
13
|
+
@site.load_data
|
14
|
+
|
15
|
+
# Delete all compiled item reps
|
16
|
+
filenames.each do |filename|
|
17
|
+
FileUtils.rm_f filename unless filename.nil?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def filenames
|
24
|
+
@site.items.map do |item|
|
25
|
+
item.reps.map do |rep|
|
26
|
+
rep.raw_path
|
27
|
+
end
|
28
|
+
end.flatten
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
namespace :validate do
|
4
|
+
|
5
|
+
desc 'Validate the site\'s HTML files'
|
6
|
+
task :html do
|
7
|
+
# Load site
|
8
|
+
site = Nanoc3::Site.new('.')
|
9
|
+
if site.nil?
|
10
|
+
$stderr.puts 'The current working directory does not seem to be a ' +
|
11
|
+
'valid/complete nanoc site directory; aborting.'
|
12
|
+
exit 1
|
13
|
+
end
|
14
|
+
|
15
|
+
# Validate
|
16
|
+
validator = ::Nanoc3::Extra::Validators::W3C.new(site, :html)
|
17
|
+
validator.run
|
18
|
+
end
|
19
|
+
|
20
|
+
desc 'Validate the site\'s CSS files'
|
21
|
+
task :css do
|
22
|
+
# Load site
|
23
|
+
site = Nanoc3::Site.new(YAML.load_file(File.join(Dir.getwd, 'config.yaml')))
|
24
|
+
if site.nil?
|
25
|
+
$stderr.puts 'The current working directory does not seem to be a ' +
|
26
|
+
'valid/complete nanoc site directory; aborting.'
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
|
30
|
+
# Validate
|
31
|
+
validator = ::Nanoc3::Extra::Validators::W3C.new(site, :css)
|
32
|
+
validator.run
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/nanoc3/tasks.rb
ADDED
data/lib/nanoc3.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Nanoc3
|
4
|
+
|
5
|
+
# The current nanoc version.
|
6
|
+
VERSION = '3.0.0'
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
# Load requirements
|
11
|
+
require 'yaml'
|
12
|
+
require 'fileutils'
|
13
|
+
|
14
|
+
# Load nanoc
|
15
|
+
require 'nanoc3/base'
|
16
|
+
require 'nanoc3/extra'
|
17
|
+
require 'nanoc3/data_sources'
|
18
|
+
require 'nanoc3/filters'
|
19
|
+
require 'nanoc3/helpers'
|
File without changes
|
data/vendor/cri/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2009 Denis Defreyne and contributors
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/vendor/cri/NEWS
ADDED
File without changes
|
data/vendor/cri/README
ADDED
data/vendor/cri/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
##### Requirements
|
2
|
+
|
3
|
+
# Rake etc
|
4
|
+
require 'rake'
|
5
|
+
require 'minitest/unit'
|
6
|
+
|
7
|
+
# Cri itself
|
8
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/lib'))
|
9
|
+
require 'cri'
|
10
|
+
|
11
|
+
##### Testing
|
12
|
+
|
13
|
+
desc 'Runs all tests'
|
14
|
+
task :test do
|
15
|
+
ENV['QUIET'] ||= 'true'
|
16
|
+
|
17
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + '/..'))
|
18
|
+
|
19
|
+
MiniTest::Unit.autorun
|
20
|
+
|
21
|
+
test_files = Dir['test/test_*.rb']
|
22
|
+
test_files.each { |f| require f }
|
23
|
+
end
|
24
|
+
|
25
|
+
task :default => :test
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module Cri
|
2
|
+
|
3
|
+
# Cri::Base is the central class representing a commandline tool. It has a
|
4
|
+
# list of commands.
|
5
|
+
class Base
|
6
|
+
|
7
|
+
# The CLI's list of commands (should also contain the help command)
|
8
|
+
attr_reader :commands
|
9
|
+
|
10
|
+
# The CLI's help command (required)
|
11
|
+
attr_accessor :help_command
|
12
|
+
|
13
|
+
# Creates a new instance of the commandline tool.
|
14
|
+
def initialize(tool_name)
|
15
|
+
@tool_name = tool_name
|
16
|
+
|
17
|
+
@commands = []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Parses the given commandline arguments and executes the requested
|
21
|
+
# command.
|
22
|
+
def run(args)
|
23
|
+
# Check arguments
|
24
|
+
if args.length == 0
|
25
|
+
@help_command.run([], [])
|
26
|
+
exit 1
|
27
|
+
end
|
28
|
+
|
29
|
+
# Partition options
|
30
|
+
opts_before_command = []
|
31
|
+
command_name = nil
|
32
|
+
opts_and_args_after_command = []
|
33
|
+
stage = 0
|
34
|
+
args.each do |arg|
|
35
|
+
# Update stage if necessary
|
36
|
+
stage = 1 if stage == 0 && !is_option?(arg)
|
37
|
+
|
38
|
+
# Add
|
39
|
+
opts_before_command << arg if stage == 0
|
40
|
+
command_name = arg if stage == 1
|
41
|
+
opts_and_args_after_command << arg if stage == 2
|
42
|
+
|
43
|
+
# Update stage if necessary
|
44
|
+
stage = 2 if stage == 1
|
45
|
+
end
|
46
|
+
|
47
|
+
# Handle options before command
|
48
|
+
begin
|
49
|
+
parsed_arguments = Cri::OptionParser.parse(opts_before_command, global_option_definitions)
|
50
|
+
rescue Cri::OptionParser::IllegalOptionError => e
|
51
|
+
$stderr.puts "illegal option -- #{e}"
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
parsed_arguments[:options].keys.each do |option|
|
55
|
+
handle_option(option)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get command
|
59
|
+
if command_name.nil?
|
60
|
+
$stderr.puts "no command given"
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
command = command_named(command_name)
|
64
|
+
if command.nil?
|
65
|
+
$stderr.puts "no such command: #{command_name}"
|
66
|
+
exit 1
|
67
|
+
end
|
68
|
+
|
69
|
+
# Parse arguments
|
70
|
+
option_definitions = command.option_definitions + global_option_definitions
|
71
|
+
begin
|
72
|
+
parsed_arguments = Cri::OptionParser.parse(opts_and_args_after_command, option_definitions)
|
73
|
+
rescue Cri::OptionParser::IllegalOptionError => e
|
74
|
+
$stderr.puts "illegal option -- #{e}"
|
75
|
+
exit 1
|
76
|
+
rescue Cri::OptionParser::OptionRequiresAnArgumentError => e
|
77
|
+
$stderr.puts "option requires an argument -- #{e}"
|
78
|
+
exit 1
|
79
|
+
end
|
80
|
+
|
81
|
+
# Handle global options
|
82
|
+
global_options = global_option_definitions.map { |o| o[:long] }
|
83
|
+
global_options.delete_if { |o| !parsed_arguments[:options].keys.include?(o.to_sym) }
|
84
|
+
global_options.each { |o| handle_option(o.to_sym) }
|
85
|
+
|
86
|
+
if parsed_arguments[:options].has_key?(:help)
|
87
|
+
# Show help for this command
|
88
|
+
show_help(command)
|
89
|
+
else
|
90
|
+
# Run command
|
91
|
+
command.run(parsed_arguments[:options], parsed_arguments[:arguments])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns the command with the given name.
|
96
|
+
def command_named(name)
|
97
|
+
# Find by exact name or alias
|
98
|
+
command = @commands.find { |c| c.name == name or c.aliases.include?(name) }
|
99
|
+
return command unless command.nil?
|
100
|
+
|
101
|
+
# Find by approximation
|
102
|
+
commands = @commands.select { |c| c.name[0, name.length] == name }
|
103
|
+
if commands.length > 1
|
104
|
+
$stderr.puts "#{@tool_name}: '#{name}' is ambiguous:"
|
105
|
+
$stderr.puts " #{commands.map { |c| c.name }.join(' ') }"
|
106
|
+
exit 1
|
107
|
+
elsif commands.length == 0
|
108
|
+
$stderr.puts "#{@tool_name}: unknown command '#{name}'\n"
|
109
|
+
show_help
|
110
|
+
exit 1
|
111
|
+
else
|
112
|
+
return commands[0]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Shows the help text for the given command, or shows the general help
|
117
|
+
# text if no command is given.
|
118
|
+
def show_help(command=nil)
|
119
|
+
if command.nil?
|
120
|
+
@help_command.run([], [])
|
121
|
+
else
|
122
|
+
@help_command.run([], [ command.name ])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns the list of global option definitions.
|
127
|
+
def global_option_definitions
|
128
|
+
[]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Adds the given command to the list of commands. Adding a command will
|
132
|
+
# also cause the command's +base+ to be set to this instance.
|
133
|
+
def add_command(command)
|
134
|
+
@commands << command
|
135
|
+
command.base = self
|
136
|
+
end
|
137
|
+
|
138
|
+
# Handles the given option.
|
139
|
+
def handle_option(option)
|
140
|
+
false
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
|
145
|
+
# Returns true if the given string is an option (i.e. -foo or --foo),
|
146
|
+
# false otherwise.
|
147
|
+
def is_option?(string)
|
148
|
+
string =~ /^-/
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Cri
|
2
|
+
|
3
|
+
# Cri::Command represents a command that can be executed on the commandline.
|
4
|
+
# 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 Cri::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 Cri::OptionParser documentation for details.
|
55
|
+
#
|
56
|
+
# +arguments+:: An array of strings representing the commandline arguments
|
57
|
+
# given to this command.
|
58
|
+
def run(options, arguments)
|
59
|
+
raise NotImplementedError.new("Command subclasses should override #run")
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns the help text for this command.
|
63
|
+
def help
|
64
|
+
text = ''
|
65
|
+
|
66
|
+
# Append usage
|
67
|
+
text << usage + "\n"
|
68
|
+
|
69
|
+
# Append aliases
|
70
|
+
unless aliases.empty?
|
71
|
+
text << "\n"
|
72
|
+
text << "aliases: #{aliases.join(' ')}\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Append short description
|
76
|
+
text << "\n"
|
77
|
+
text << short_desc + "\n"
|
78
|
+
|
79
|
+
# Append long description
|
80
|
+
text << "\n"
|
81
|
+
text << long_desc.wrap_and_indent(78, 4) + "\n"
|
82
|
+
|
83
|
+
# Append options
|
84
|
+
all_option_definitions = base.global_option_definitions + option_definitions
|
85
|
+
unless all_option_definitions.empty?
|
86
|
+
text << "\n"
|
87
|
+
text << "options:\n"
|
88
|
+
text << "\n"
|
89
|
+
all_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
|