bones 2.5.1 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +2 -0
- data/README.rdoc +54 -306
- data/Rakefile +28 -37
- data/bin/bones +10 -3
- data/{spec/data/data → default}/.bnsignore +3 -1
- data/{data → default}/History.txt.bns +0 -0
- data/{data → default}/README.txt.bns +0 -0
- data/default/Rakefile.bns +21 -0
- data/{data → default}/bin/NAME.bns +0 -0
- data/{data → default}/lib/NAME.rb.bns +0 -0
- data/{data → default}/spec/NAME_spec.rb.bns +0 -0
- data/{data → default}/spec/spec_helper.rb.bns +0 -0
- data/{data → default}/test/test_NAME.rb +0 -0
- data/lib/bones.rb +73 -31
- data/lib/bones/annotation_extractor.rb +16 -26
- data/lib/bones/app.rb +87 -58
- data/lib/bones/app/command.rb +143 -64
- data/lib/bones/app/create.rb +93 -0
- data/lib/bones/app/file_manager.rb +7 -8
- data/lib/bones/app/freeze.rb +59 -0
- data/lib/bones/app/info.rb +39 -0
- data/lib/bones/app/unfreeze.rb +44 -0
- data/lib/bones/colors.rb +54 -0
- data/lib/bones/gem_package_task.rb +71 -0
- data/lib/bones/helpers.rb +93 -0
- data/lib/bones/plugins/ann.rb +166 -0
- data/lib/bones/plugins/bones_plugin.rb +193 -0
- data/lib/bones/plugins/gem.rb +274 -0
- data/lib/bones/plugins/notes.rb +45 -0
- data/lib/bones/plugins/rdoc.rb +93 -0
- data/lib/bones/plugins/test.rb +57 -0
- data/lib/bones/smtp_tls.rb +1 -0
- data/spec/bones/app/file_manager_spec.rb +6 -6
- data/spec/bones/app_spec.rb +14 -18
- data/spec/bones_spec.rb +9 -4
- data/{data → spec/data/default}/.bnsignore +0 -0
- data/spec/data/{data → default}/History +0 -0
- data/spec/data/{data → default}/NAME/NAME.rb.bns +0 -0
- data/spec/data/{data → default}/README.txt.bns +0 -0
- data/{data → spec/data/default}/Rakefile.bns +0 -0
- data/spec/data/{data → default}/lib/NAME.rb.bns +0 -0
- metadata +94 -68
- data/lib/bones/app/create_command.rb +0 -86
- data/lib/bones/app/freeze_command.rb +0 -73
- data/lib/bones/app/info_command.rb +0 -58
- data/lib/bones/app/unfreeze_command.rb +0 -53
- data/lib/bones/app/update_command.rb +0 -47
- data/lib/bones/debug.rb +0 -72
- data/lib/bones/tasks/ann.rake +0 -80
- data/lib/bones/tasks/bones.rake +0 -20
- data/lib/bones/tasks/gem.rake +0 -201
- data/lib/bones/tasks/git.rake +0 -40
- data/lib/bones/tasks/notes.rake +0 -27
- data/lib/bones/tasks/post_load.rake +0 -34
- data/lib/bones/tasks/rdoc.rake +0 -51
- data/lib/bones/tasks/rubyforge.rake +0 -55
- data/lib/bones/tasks/setup.rb +0 -292
- data/lib/bones/tasks/spec.rake +0 -54
- data/lib/bones/tasks/svn.rake +0 -47
- data/lib/bones/tasks/test.rake +0 -40
- data/lib/bones/tasks/zentest.rake +0 -36
- data/spec/data/data/Rakefile.bns +0 -30
- data/tasks/ann.rake +0 -80
- data/tasks/bones.rake +0 -20
- data/tasks/gem.rake +0 -201
- data/tasks/git.rake +0 -40
- data/tasks/notes.rake +0 -27
- data/tasks/post_load.rake +0 -34
- data/tasks/rdoc.rake +0 -51
- data/tasks/rubyforge.rake +0 -55
- data/tasks/setup.rb +0 -292
- data/tasks/spec.rake +0 -54
- data/tasks/svn.rake +0 -47
- data/tasks/test.rake +0 -40
- data/tasks/zentest.rake +0 -36
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
module Bones::App
|
3
|
+
class Info < Command
|
4
|
+
|
5
|
+
def self.initialize_info
|
6
|
+
synopsis 'bones info'
|
7
|
+
summary 'show information about available skeletons'
|
8
|
+
description 'Shows information about available skeletons.'
|
9
|
+
end
|
10
|
+
|
11
|
+
def run
|
12
|
+
skeleton_dir = File.join(mrbones_dir, DEFAULT_SKELETON)
|
13
|
+
skeleton_dir = ::Bones.path(DEFAULT_SKELETON) unless test(?d, skeleton_dir)
|
14
|
+
|
15
|
+
msg = "\n"
|
16
|
+
msg << "The default project skeleton will be copied from:\n"
|
17
|
+
msg << " " << skeleton_dir << "\n\n"
|
18
|
+
|
19
|
+
fmt = " %-12s => %s\n"
|
20
|
+
msg << "Available projects skeletons are:\n"
|
21
|
+
Dir.glob(File.join(mrbones_dir, '*')).sort.each do |fn|
|
22
|
+
next if fn =~ %r/\.archive$/
|
23
|
+
next if File.basename(fn) == DEFAULT_SKELETON
|
24
|
+
|
25
|
+
if test(?f, fn)
|
26
|
+
msg << fmt % [File.basename(fn), File.read(fn).strip]
|
27
|
+
else
|
28
|
+
msg << " " << File.basename(fn) << "\n"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
stdout.puts msg
|
33
|
+
stdout.puts
|
34
|
+
end
|
35
|
+
|
36
|
+
end # class Info
|
37
|
+
end # module Bones::App
|
38
|
+
|
39
|
+
# EOF
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
module Bones::App
|
3
|
+
class Unfreeze < Command
|
4
|
+
|
5
|
+
def self.initialize_unfreeze
|
6
|
+
synopsis 'bones unfreeze [skeleton_name]'
|
7
|
+
|
8
|
+
summary 'remove a skeleton from ~/.mrbones/'
|
9
|
+
|
10
|
+
description <<-__
|
11
|
+
Removes the named skeleton from the '~/.mrbones/' folder. If a name is
|
12
|
+
not given then the default skeleton is removed.
|
13
|
+
__
|
14
|
+
|
15
|
+
option(standard_options[:verbose])
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
fm = FileManager.new(
|
20
|
+
:source => repository || ::Bones.path(DEFAULT_SKELETON),
|
21
|
+
:destination => output_dir,
|
22
|
+
:stdout => stdout,
|
23
|
+
:stderr => stderr,
|
24
|
+
:verbose => verbose?
|
25
|
+
)
|
26
|
+
|
27
|
+
if fm.archive_destination
|
28
|
+
stdout.puts "Project skeleton #{name.inspect} has been unfrozen"
|
29
|
+
else
|
30
|
+
stdout.puts "Project skeleton #{name.inspect} is not frozen " <<
|
31
|
+
"(no action taken)"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse( args )
|
36
|
+
opts = super args
|
37
|
+
config[:name] = args.empty? ? DEFAULT_SKELETON : args.join('_')
|
38
|
+
config[:output_dir] = File.join(mrbones_dir, name)
|
39
|
+
end
|
40
|
+
|
41
|
+
end # class Unfreeze
|
42
|
+
end # module Bones::App
|
43
|
+
|
44
|
+
# EOF
|
data/lib/bones/colors.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
module Bones::Colors
|
3
|
+
extend self
|
4
|
+
|
5
|
+
COLOR_CODES = {
|
6
|
+
:clear => 0,
|
7
|
+
:reset => 0, # synonym for :clear
|
8
|
+
:bold => 1,
|
9
|
+
:dark => 2,
|
10
|
+
:italic => 3, # not widely implemented
|
11
|
+
:underline => 4,
|
12
|
+
:underscore => 4, # synonym for :underline
|
13
|
+
:blink => 5,
|
14
|
+
:rapid_blink => 6, # not widely implemented
|
15
|
+
:negative => 7, # no reverse because of String#reverse
|
16
|
+
:concealed => 8,
|
17
|
+
:strikethrough => 9, # not widely implemented
|
18
|
+
:black => 30,
|
19
|
+
:red => 31,
|
20
|
+
:green => 32,
|
21
|
+
:yellow => 33,
|
22
|
+
:blue => 34,
|
23
|
+
:magenta => 35,
|
24
|
+
:cyan => 36,
|
25
|
+
:white => 37,
|
26
|
+
:on_black => 40,
|
27
|
+
:on_red => 41,
|
28
|
+
:on_green => 42,
|
29
|
+
:on_yellow => 43,
|
30
|
+
:on_blue => 44,
|
31
|
+
:on_magenta => 45,
|
32
|
+
:on_cyan => 46,
|
33
|
+
:on_white => 47
|
34
|
+
}
|
35
|
+
|
36
|
+
COLOR_CODES.each { |name,code|
|
37
|
+
module_eval <<-CODE
|
38
|
+
def #{name.to_s}( str )
|
39
|
+
"\e[#{code}m\#{str}\e[0m"
|
40
|
+
end
|
41
|
+
CODE
|
42
|
+
}
|
43
|
+
|
44
|
+
def colorize( str, *args )
|
45
|
+
args.each { |name|
|
46
|
+
code = COLOR_CODES[name]
|
47
|
+
next if code.nil?
|
48
|
+
str = "\e[#{code}m#{str}\e[0m"
|
49
|
+
}
|
50
|
+
str
|
51
|
+
end
|
52
|
+
end # module Bones::Colors
|
53
|
+
|
54
|
+
# EOF
|
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
require 'find'
|
3
|
+
require 'rake/packagetask'
|
4
|
+
require 'rubygems/user_interaction'
|
5
|
+
require 'rubygems/builder'
|
6
|
+
|
7
|
+
class Bones::GemPackageTask < Rake::PackageTask
|
8
|
+
|
9
|
+
# Ruby GEM spec containing the metadata for this package. The
|
10
|
+
# name, version and package_files are automatically determined
|
11
|
+
# from the GEM spec and don't need to be explicitly provided.
|
12
|
+
#
|
13
|
+
attr_accessor :gem_spec
|
14
|
+
|
15
|
+
# Create a GEM Package task library. Automatically define the gem
|
16
|
+
# if a block is given. If no block is supplied, then +define+
|
17
|
+
# needs to be called to define the task.
|
18
|
+
#
|
19
|
+
def initialize(gem_spec)
|
20
|
+
init(gem_spec)
|
21
|
+
yield self if block_given?
|
22
|
+
define if block_given?
|
23
|
+
end
|
24
|
+
|
25
|
+
# Initialization tasks without the "yield self" or define
|
26
|
+
# operations.
|
27
|
+
#
|
28
|
+
def init(gem)
|
29
|
+
super(gem.name, gem.version)
|
30
|
+
@gem_spec = gem
|
31
|
+
@package_files += gem_spec.files if gem_spec.files
|
32
|
+
end
|
33
|
+
|
34
|
+
# Create the Rake tasks and actions specified by this
|
35
|
+
# GemPackageTask. (+define+ is automatically called if a block is
|
36
|
+
# given to +new+).
|
37
|
+
#
|
38
|
+
def define
|
39
|
+
super
|
40
|
+
task :prereqs
|
41
|
+
task :package => ['gem:prereqs', "#{package_dir_path}/#{gem_file}"]
|
42
|
+
|
43
|
+
file "#{package_dir_path}/#{gem_file}" => [package_dir_path] + package_files do
|
44
|
+
when_writing("Creating GEM") {
|
45
|
+
chdir(package_dir_path) do
|
46
|
+
Gem::Builder.new(gem_spec).build
|
47
|
+
verbose(true) {
|
48
|
+
mv gem_file, "../#{gem_file}"
|
49
|
+
}
|
50
|
+
end
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
file package_dir_path do
|
55
|
+
mkdir_p package_dir rescue nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
#
|
61
|
+
def gem_file
|
62
|
+
if @gem_spec.platform == Gem::Platform::RUBY
|
63
|
+
"#{package_name}.gem"
|
64
|
+
else
|
65
|
+
"#{package_name}-#{@gem_spec.platform}.gem"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end # class Bones::GemPackageTask
|
70
|
+
|
71
|
+
# EOF
|
@@ -0,0 +1,93 @@
|
|
1
|
+
|
2
|
+
module Bones::Helpers
|
3
|
+
|
4
|
+
DEV_NULL = File.exist?('/dev/null') ? '/dev/null' : 'NUL:'
|
5
|
+
SUDO = if system("which sudo > #{DEV_NULL} 2>&1") then 'sudo'
|
6
|
+
else '' end unless defined? SUDO
|
7
|
+
RCOV = "#{RUBY} -S rcov"
|
8
|
+
RDOC = "#{RUBY} -S rdoc"
|
9
|
+
GEM = "#{RUBY} -S gem"
|
10
|
+
HAVE_SVN = (Dir.entries(Dir.pwd).include?('.svn') and
|
11
|
+
system("svn --version 2>&1 > #{DEV_NULL}"))
|
12
|
+
|
13
|
+
HAVE = Hash.new(false)
|
14
|
+
|
15
|
+
def have?( key, &block )
|
16
|
+
return HAVE[key] if block.nil?
|
17
|
+
HAVE[key] = block.call
|
18
|
+
end
|
19
|
+
|
20
|
+
def quiet( &block )
|
21
|
+
io = [STDOUT.dup, STDERR.dup]
|
22
|
+
STDOUT.reopen DEV_NULL
|
23
|
+
STDERR.reopen DEV_NULL
|
24
|
+
block.call
|
25
|
+
ensure
|
26
|
+
STDOUT.reopen io.first
|
27
|
+
STDERR.reopen io.last
|
28
|
+
io.each {|x| x.close}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Reads a file at +path+ and spits out an array of the +paragraphs+
|
32
|
+
# specified.
|
33
|
+
#
|
34
|
+
# changes = paragraphs_of('History.txt', 0..1).join("\n\n")
|
35
|
+
# summary, *description = paragraphs_of('README.txt', 3, 3..8)
|
36
|
+
#
|
37
|
+
def paragraphs_of( path, *paragraphs )
|
38
|
+
title = String === paragraphs.first ? paragraphs.shift : nil
|
39
|
+
ary = File.read(path).delete("\r").split(/\n\n+/)
|
40
|
+
|
41
|
+
result = if title
|
42
|
+
tmp, matching = [], false
|
43
|
+
rgxp = %r/^=+\s*#{Regexp.escape(title)}/i
|
44
|
+
paragraphs << (0..-1) if paragraphs.empty?
|
45
|
+
|
46
|
+
ary.each do |val|
|
47
|
+
if val =~ rgxp
|
48
|
+
break if matching
|
49
|
+
matching = true
|
50
|
+
rgxp = %r/^=+/i
|
51
|
+
elsif matching
|
52
|
+
tmp << val
|
53
|
+
end
|
54
|
+
end
|
55
|
+
tmp
|
56
|
+
else ary end
|
57
|
+
|
58
|
+
result.values_at(*paragraphs)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Find a rake task using the task name and remove any description text. This
|
62
|
+
# will prevent the task from being displayed in the list of available tasks.
|
63
|
+
#
|
64
|
+
def remove_desc_for_task( names )
|
65
|
+
Array(names).each do |task_name|
|
66
|
+
task = Rake.application.tasks.find {|t| t.name == task_name}
|
67
|
+
next if task.nil?
|
68
|
+
task.instance_variable_set :@comment, nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end # module Bones::Helpers
|
73
|
+
|
74
|
+
# We need a "valid" method thtat determines if a string is suitable for use
|
75
|
+
# in the gem specification.
|
76
|
+
#
|
77
|
+
class Object
|
78
|
+
def valid?
|
79
|
+
return !(self.empty? or self == "\000") if self.respond_to?(:to_str)
|
80
|
+
return false
|
81
|
+
end
|
82
|
+
|
83
|
+
# Adds the given arguments to the include path if they are not already there
|
84
|
+
#
|
85
|
+
def ensure_in_path( *args )
|
86
|
+
args.each do |path|
|
87
|
+
path = File.expand_path(path)
|
88
|
+
$:.unshift(path) if test(?d, path) and not $:.include?(path)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# EOF
|
@@ -0,0 +1,166 @@
|
|
1
|
+
|
2
|
+
module Bones::Plugins::Ann
|
3
|
+
include ::Bones::Helpers
|
4
|
+
extend self
|
5
|
+
|
6
|
+
module Syntax
|
7
|
+
def use_gmail( user = nil )
|
8
|
+
email = ::Bones.config.ann.email
|
9
|
+
user ||= ::Bones.config.email
|
10
|
+
|
11
|
+
email.username user
|
12
|
+
email.server 'smtp.gmail.com'
|
13
|
+
email.port 587
|
14
|
+
email.authtype :plain
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize_ann
|
19
|
+
::Bones.config {
|
20
|
+
desc 'Configuration for creating and mailing an announcement message.'
|
21
|
+
ann {
|
22
|
+
file 'announcement.txt', :desc => <<-__
|
23
|
+
When announcing a release of your project the announcement text will
|
24
|
+
be written to this file.
|
25
|
+
__
|
26
|
+
|
27
|
+
text nil, :desc => 'Extra text to be appended to the announcement.'
|
28
|
+
|
29
|
+
paragraphs Array.new, :desc => <<-__
|
30
|
+
Array of paragraphs from the README file to include in the
|
31
|
+
announcement. The paragraphs are identified by their heading name in
|
32
|
+
the README, but when listed here they can be given as lowercase or
|
33
|
+
uppercase.
|
34
|
+
__
|
35
|
+
|
36
|
+
desc <<-__
|
37
|
+
Configuration for e-mailing the announcement.
|
38
|
+
|
39
|
+
A convenience method is provided for configuring Mr Bones to use
|
40
|
+
gmail for sending project announcements. The project's e-mail
|
41
|
+
address isused by default if a gmail username is not supplied.
|
42
|
+
|
|
43
|
+
| use_gmail
|
44
|
+
| use_gmail 'username'
|
45
|
+
|
|
46
|
+
Use the latter form of the method is your gmail username is
|
47
|
+
different then the project's e-mail address.
|
48
|
+
__
|
49
|
+
email {
|
50
|
+
from nil, :desc => <<-__
|
51
|
+
The name to show on the 'from' line of the annoucement e-mail.
|
52
|
+
This will default to the author name or the project e-mail if an
|
53
|
+
author is not specified.
|
54
|
+
__
|
55
|
+
|
56
|
+
to %w(ruby-talk@ruby-lang.org), :desc => 'An array of e-mail recipients.'
|
57
|
+
|
58
|
+
server 'localhost', :desc => 'The server used to send the announcement e-mail.'
|
59
|
+
|
60
|
+
port 25, :desc => 'The server port number to connect to.'
|
61
|
+
|
62
|
+
domain ENV['HOSTNAME'], :desc => <<-__
|
63
|
+
The originating domain of the e-mail. This safely deafaults to the
|
64
|
+
local hostname.
|
65
|
+
__
|
66
|
+
|
67
|
+
username nil, :desc => 'The e-mail account name used to log into the e-mail server.'
|
68
|
+
|
69
|
+
password nil, :desc => 'The e-mail password used to log into the e-mail server.'
|
70
|
+
|
71
|
+
authtype :plain, :desc => <<-__
|
72
|
+
The authentication type used by the e-mail server. This should be
|
73
|
+
one of :plain, :login, or :cram_md5. See the documentation on the
|
74
|
+
Net::SMTP class for more information.
|
75
|
+
__
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
have?(:ann) { true }
|
81
|
+
end
|
82
|
+
|
83
|
+
def post_load
|
84
|
+
config = ::Bones.config
|
85
|
+
|
86
|
+
config.exclude << "^#{Regexp.escape(config.ann.file)}$"
|
87
|
+
config.ann.email.from ||= Array(config.authors).first || config.email
|
88
|
+
config.ann.email.username ||= config.email
|
89
|
+
config.ann.email.domain ||= 'localhost'
|
90
|
+
end
|
91
|
+
|
92
|
+
def define_tasks
|
93
|
+
config = ::Bones.config
|
94
|
+
namespace :ann do
|
95
|
+
|
96
|
+
# A prerequisites task that all other tasks depend upon
|
97
|
+
task :prereqs
|
98
|
+
|
99
|
+
file config.ann.file do
|
100
|
+
ann = config.ann
|
101
|
+
puts "Generating #{ann.file}"
|
102
|
+
File.open(ann.file,'w') do |fd|
|
103
|
+
fd.puts("#{config.name} version #{config.version}")
|
104
|
+
fd.puts(" by #{Array(config.authors).first}") if config.authors
|
105
|
+
fd.puts(" #{config.url}") if config.url.valid?
|
106
|
+
fd.puts(" (the \"#{config.release_name}\" release)") if config.release_name
|
107
|
+
fd.puts
|
108
|
+
fd.puts("== DESCRIPTION")
|
109
|
+
fd.puts
|
110
|
+
fd.puts(config.description)
|
111
|
+
fd.puts
|
112
|
+
fd.puts(config.changes.sub(%r/^.*$/, '== CHANGES'))
|
113
|
+
fd.puts
|
114
|
+
ann.paragraphs.each do |p|
|
115
|
+
fd.puts "== #{p.upcase}"
|
116
|
+
fd.puts
|
117
|
+
fd.puts paragraphs_of(config.readme_file, p).join("\n\n")
|
118
|
+
fd.puts
|
119
|
+
end
|
120
|
+
fd.puts ann.text if ann.text
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
desc "Create an announcement file"
|
125
|
+
task :announcement => ['ann:prereqs', config.ann.file]
|
126
|
+
|
127
|
+
desc "Send an email announcement"
|
128
|
+
task :email => ['ann:prereqs', config.ann.file] do
|
129
|
+
ann = config.ann
|
130
|
+
email = config.ann.email
|
131
|
+
|
132
|
+
from = email.from
|
133
|
+
to = Array(email.to)
|
134
|
+
|
135
|
+
### build a mail header for RFC 822
|
136
|
+
rfc822msg = "From: #{from}\n"
|
137
|
+
rfc822msg << "To: #{to.join(',')}\n"
|
138
|
+
rfc822msg << "Subject: [ANN] #{config.name} #{config.version}"
|
139
|
+
rfc822msg << " (#{config.release_name})" if config.release_name
|
140
|
+
rfc822msg << "\n"
|
141
|
+
rfc822msg << "Date: #{Time.new.rfc822}\n"
|
142
|
+
rfc822msg << "Message-Id: "
|
143
|
+
rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{email.domain}>\n\n"
|
144
|
+
rfc822msg << File.read(ann.file)
|
145
|
+
|
146
|
+
params = [:server, :port, :domain, :username, :password, :authtype].map { |key| email[key] }
|
147
|
+
|
148
|
+
if params[4].nil?
|
149
|
+
STDOUT.write "Please enter your e-mail password (#{params[3]}): "
|
150
|
+
params[4] = STDIN.gets.chomp
|
151
|
+
end
|
152
|
+
|
153
|
+
### send email
|
154
|
+
Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
|
155
|
+
end
|
156
|
+
end # namespace :ann
|
157
|
+
|
158
|
+
desc 'Alias to ann:announcement'
|
159
|
+
task :ann => 'ann:announcement'
|
160
|
+
|
161
|
+
CLOBBER << config.ann.file
|
162
|
+
end
|
163
|
+
|
164
|
+
end # module Bones::Plugins::Ann
|
165
|
+
|
166
|
+
# EOF
|