bones 2.5.1 → 3.0.0
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.
- 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
|