rabal 0.0.1 → 0.1.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/CHANGES +13 -0
- data/README.PLUGIN +8 -8
- data/Rakefile +79 -0
- data/lib/rabal.rb +26 -28
- data/lib/rabal/application.rb +53 -15
- data/lib/rabal/directory_tree.rb +3 -3
- data/lib/rabal/error.rb +2 -0
- data/lib/rabal/file_tree.rb +9 -4
- data/lib/rabal/gemspec.rb +50 -0
- data/lib/rabal/logger.rb +15 -6
- data/lib/rabal/plugin.rb +9 -5
- data/lib/rabal/plugin/core.rb +4 -3
- data/lib/rabal/plugin/ext.rb +17 -0
- data/lib/rabal/plugin/foundation.rb +21 -10
- data/lib/rabal/plugin/license.rb +8 -13
- data/lib/rabal/plugin/rubyforge.rb +22 -0
- data/lib/rabal/plugin/spec.rb +6 -0
- data/lib/rabal/plugin/test.rb +7 -0
- data/lib/rabal/plugin_tree.rb +1 -2
- data/lib/rabal/project_tree.rb +7 -2
- data/lib/rabal/specification.rb +128 -0
- data/lib/rabal/tree.rb +19 -5
- data/lib/rabal/usage.rb +8 -5
- data/lib/rabal/util.rb +2 -2
- data/lib/rabal/version.rb +6 -3
- data/resources/trees/bin/rabal.project +3 -3
- data/resources/trees/core/{CHANGES → CHANGES.erb} +1 -1
- data/resources/trees/core/{README → README.erb} +1 -1
- data/resources/trees/core/Rakefile.erb +67 -0
- data/resources/trees/core/lib/rabal.project.rb.erb +0 -2
- data/resources/trees/core/lib/rabal.project/gemspec.rb.erb +51 -0
- data/resources/trees/core/lib/rabal.project/specification.rb.erb +128 -0
- data/resources/trees/core/lib/rabal.project/version.rb.erb +2 -1
- data/resources/trees/ext/ext/rabal.project/ext/mkrf_conf.rb.erb +7 -0
- data/resources/trees/ext/tasks/extension.rb.erb +15 -0
- data/resources/trees/rubyforge/tasks/rubyforge.rb.erb +105 -0
- data/resources/trees/spec/{rabal.project_spec.rb.erb → spec/rabal.project_spec.rb.erb} +0 -0
- data/resources/trees/spec/{spec_helper.rb.erb → spec/spec_helper.rb.erb} +0 -0
- data/resources/trees/spec/tasks/rspec.rb.erb +20 -0
- data/resources/trees/test/tasks/testunit.rb.erb +14 -0
- data/resources/trees/test/{rabal.project_test.rb.erb → test/rabal.project_test.rb.erb} +1 -1
- data/resources/trees/test/{test_helper.rb.erb → test/test_helper.rb.erb} +1 -1
- data/spec/application_spec.rb +47 -0
- data/spec/bin_plugin_spec.rb +1 -1
- data/spec/core_plugin_spec.rb +10 -3
- data/spec/license_plugin_spec.rb +10 -8
- data/spec/plugin_tree_spec.rb +4 -4
- data/spec/spec_plugin_spec.rb +1 -1
- data/spec/test_plugin_spec.rb +1 -1
- data/spec/version_spec.rb +1 -1
- metadata +73 -24
- data/resources/trees/core/Rakefile +0 -0
data/lib/rabal/usage.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require '
|
1
|
+
require 'rabal'
|
2
|
+
|
2
3
|
module Rabal
|
3
4
|
|
4
5
|
# Rabal has unique Usage output requirements and as such the default
|
@@ -24,11 +25,13 @@ module Rabal
|
|
24
25
|
# to dump, or rename
|
25
26
|
def to_s
|
26
27
|
u = ::Main::Usage.new
|
27
|
-
# just transfer directly over these
|
28
|
-
%w[name synopsis
|
28
|
+
# just transfer directly over these chunks
|
29
|
+
%w[name synopsis].each do |chunk|
|
29
30
|
u[chunk.dup] = old_usage[chunk].to_s
|
30
31
|
end
|
31
32
|
|
33
|
+
u['description'] = ::Main::Util.columnize(old_usage['description'].to_s, :indent => 6, :width => 78)
|
34
|
+
|
32
35
|
arguments = app.main.parameters.select{|p| p.type == :argument}
|
33
36
|
global_options = app.main.parameters.select{|p| p.type == :option and app.global_option_names.include?(p.name) }
|
34
37
|
load_options = app.main.parameters.select{|p| p.type == :option and app.plugin_load_option_names.include?(p.name) }
|
@@ -47,7 +50,7 @@ module Rabal
|
|
47
50
|
app.plugin_manager.plugins.sort_by{|c,p| c}.each do |cat,plugins|
|
48
51
|
plugins.each do |key,plugin|
|
49
52
|
pre = " " + (plugin.use_always? ? "*" : " ")
|
50
|
-
s << option_format(pre,"#{plugin.use_name} (#{plugin.register_path})",plugin.description,
|
53
|
+
s << option_format(pre,"#{plugin.use_name} (#{plugin.register_path})",plugin.description,40,43,78)
|
51
54
|
s << "\n"
|
52
55
|
|
53
56
|
# create the module options for this one, if the
|
@@ -92,7 +95,7 @@ module Rabal
|
|
92
95
|
end
|
93
96
|
list.sort_by{|p| p.name}.collect do |p|
|
94
97
|
ps = ""
|
95
|
-
ps << option_format(pre,p.short_synopsis,p.description,
|
98
|
+
ps << option_format(pre,p.short_synopsis,p.description,42,45,78)
|
96
99
|
ps
|
97
100
|
end.join("\n")
|
98
101
|
end
|
data/lib/rabal/util.rb
CHANGED
data/lib/rabal/version.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
begin
|
4
|
-
require '<%=
|
4
|
+
require '<%= project_name %>'
|
5
5
|
rescue LoadError => le
|
6
6
|
$: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
|
7
|
-
require '<%=
|
7
|
+
require '<%= project_name %>'
|
8
8
|
end
|
9
9
|
|
10
|
-
puts "I am the killer app <%=
|
10
|
+
puts "I am the killer app <%= project_name %> at version #{<%= project_name.camelize %>::VERSION}!"
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
$: << File.join(File.dirname(__FILE__),"lib")
|
7
|
+
require '<%= project_name.underscore %>'
|
8
|
+
|
9
|
+
# load all the extra tasks for the project
|
10
|
+
TASK_DIR = File.join(File.dirname(__FILE__),"tasks")
|
11
|
+
FileList[File.join(TASK_DIR,"*.rb")].each do |tasklib|
|
12
|
+
require "tasks/#{File.basename(tasklib)}"
|
13
|
+
end
|
14
|
+
|
15
|
+
task :default => "test:default"
|
16
|
+
|
17
|
+
#-----------------------------------------------------------------------
|
18
|
+
# Documentation
|
19
|
+
#-----------------------------------------------------------------------
|
20
|
+
namespace :doc do
|
21
|
+
|
22
|
+
# generating documentation locally
|
23
|
+
Rake::RDocTask.new do |rdoc|
|
24
|
+
rdoc.rdoc_dir = <%= project_name.camelize %>::SPEC.local_rdoc_dir
|
25
|
+
rdoc.options = <%= project_name.camelize %>::SPEC.rdoc_options
|
26
|
+
rdoc.rdoc_files = <%= project_name.camelize %>::SPEC.rdoc_files
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "View the RDoc documentation locally"
|
30
|
+
task :view => :rdoc do
|
31
|
+
show_files <%= project_name.camelize %>::SPEC.local_rdoc_dir
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
#-----------------------------------------------------------------------
|
37
|
+
# Packaging and Distribution
|
38
|
+
#-----------------------------------------------------------------------
|
39
|
+
namespace :dist do
|
40
|
+
|
41
|
+
GEM_SPEC = eval(<%= project_name.camelize %>:::SPEC.to_ruby)
|
42
|
+
|
43
|
+
Rake::GemPackageTask.new(GEM_SPEC) do |pkg|
|
44
|
+
pkg.need_tar = <%= project_name.camelize %>::SPEC.need_tar
|
45
|
+
pkg.need_zip = <%= project_name.camelize %>::SPEC.need_zip
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Install as a gem"
|
49
|
+
task :install => [:clobber, :package] do
|
50
|
+
sh "sudo gem install pkg/#{<%= project_name.camelize %>::SPEC.full_name}.gem"
|
51
|
+
end
|
52
|
+
|
53
|
+
# uninstall the gem and all executables
|
54
|
+
desc "Uninstall gem"
|
55
|
+
task :uninstall do
|
56
|
+
sh "sudo gem uninstall #{<%= project_name.camelize %>::SPEC.name} -x"
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "dump gemspec"
|
60
|
+
task :gemspec do
|
61
|
+
puts <%= project_name.camelize %>::SPEC.to_ruby
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "reinstall gem"
|
65
|
+
task :reinstall => [:install, :uninstall]
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require '<%= project_name %>/specification'
|
3
|
+
require '<%= project_name %>/version'
|
4
|
+
require 'rake'
|
5
|
+
|
6
|
+
# The Gem Specification plus some extras for <%= project_name %>.
|
7
|
+
module <%= project_name.camelize %>
|
8
|
+
SPEC = <%= project_name.camelize %>::Specification.new do |spec|
|
9
|
+
spec.name = "<%= project_name %>"
|
10
|
+
spec.version = <%= project_name.camelize %>::VERSION
|
11
|
+
spec.rubyforge_project = "<%= project_name %>"
|
12
|
+
spec.author = "<%= root.author %>"
|
13
|
+
spec.email = "<%= root.email %>"
|
14
|
+
spec.homepage = "http://<%= project_name %>.rubyforge.org/"
|
15
|
+
|
16
|
+
spec.summary = "A Summary of <%= project_name %>."
|
17
|
+
spec.description = <<-DESC
|
18
|
+
A longer more detailed description of <%= project_name %>.
|
19
|
+
DESC
|
20
|
+
|
21
|
+
spec.extra_rdoc_files = FileList["[A-Z]*"]
|
22
|
+
spec.has_rdoc = true
|
23
|
+
spec.rdoc_main = "README"
|
24
|
+
spec.rdoc_options = [ "--line-numbers" , "--inline-source" ]
|
25
|
+
|
26
|
+
spec.test_files = FileList["spec/**/*.rb", "test/**/*.rb"]
|
27
|
+
spec.files = spec.test_files + spec.extra_rdoc_files +
|
28
|
+
FileList["lib/**/*.rb", "resources/**/*"]
|
29
|
+
<% if root.has_subtree?(["bin"]) then %>
|
30
|
+
spec.executable = spec.name
|
31
|
+
<% end %>
|
32
|
+
|
33
|
+
# add dependencies
|
34
|
+
# spec.add_dependency("somegem", ">= 0.4.2")
|
35
|
+
<% if root.has_subtree?(["ext"]) then %>
|
36
|
+
spec.add_dependency("mkrf")
|
37
|
+
spec.extensions << "ext/<%= project_name %>/ext/mkrf_conf.rb"
|
38
|
+
<% end %>
|
39
|
+
spec.platform = Gem::Platform::RUBY
|
40
|
+
|
41
|
+
spec.local_rdoc_dir = "doc/rdoc"
|
42
|
+
spec.remote_rdoc_dir = "#{spec.name}/rdoc"
|
43
|
+
spec.local_coverage_dir = "doc/coverage"
|
44
|
+
spec.remote_coverage_dir= "#{spec.name}/coverage"
|
45
|
+
|
46
|
+
spec.remote_site_dir = "#{spec.name}/"
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rubygems/specification'
|
3
|
+
require 'rake'
|
4
|
+
|
5
|
+
module <%= project_name.camelize %>
|
6
|
+
# Add some additional items to Gem::Specification
|
7
|
+
# A <%= project_name.camelize %>::Specification adds additional pieces of information the
|
8
|
+
# typical gem specification
|
9
|
+
class Specification
|
10
|
+
|
11
|
+
RUBYFORGE_ROOT = "/var/www/gforge-projects/"
|
12
|
+
|
13
|
+
# user that accesses remote site
|
14
|
+
attr_accessor :remote_user
|
15
|
+
|
16
|
+
# remote host, default 'rubyforge.org'
|
17
|
+
attr_accessor :remote_host
|
18
|
+
|
19
|
+
# name the rdoc main
|
20
|
+
attr_accessor :rdoc_main
|
21
|
+
|
22
|
+
# local directory in development holding the generated rdoc
|
23
|
+
# default 'doc'
|
24
|
+
attr_accessor :local_rdoc_dir
|
25
|
+
|
26
|
+
# remote directory for storing rdoc, default 'doc'
|
27
|
+
attr_accessor :remote_rdoc_dir
|
28
|
+
|
29
|
+
# local directory for coverage report
|
30
|
+
attr_accessor :local_coverage_dir
|
31
|
+
|
32
|
+
# remote directory for storing coverage reports
|
33
|
+
# This defaults to 'coverage'
|
34
|
+
attr_accessor :remote_coverage_dir
|
35
|
+
|
36
|
+
# local directory for generated website, default +site/public+
|
37
|
+
attr_accessor :local_site_dir
|
38
|
+
|
39
|
+
# remote directory relative to +remote_root+ for the website.
|
40
|
+
# website.
|
41
|
+
attr_accessor :remote_site_dir
|
42
|
+
|
43
|
+
# is a .tgz to be created?, default 'true'
|
44
|
+
attr_accessor :need_tar
|
45
|
+
|
46
|
+
# is a .zip to be created, default 'true'
|
47
|
+
attr_accessor :need_zip
|
48
|
+
|
49
|
+
|
50
|
+
def initialize
|
51
|
+
@remote_user = nil
|
52
|
+
@remote_host = "rubyforge.org"
|
53
|
+
|
54
|
+
@rdoc_main = "README"
|
55
|
+
@local_rdoc_dir = "doc"
|
56
|
+
@remote_rdoc_dir = "doc"
|
57
|
+
@local_coverage_dir = "coverage"
|
58
|
+
@remote_coverage_dir = "coverage"
|
59
|
+
@local_site_dir = "site/public"
|
60
|
+
@remote_site_dir = "."
|
61
|
+
|
62
|
+
@need_tar = true
|
63
|
+
@need_zip = true
|
64
|
+
|
65
|
+
@spec = Gem::Specification.new
|
66
|
+
|
67
|
+
yield self if block_given?
|
68
|
+
|
69
|
+
# update rdoc options to take care of the rdoc_main if it is
|
70
|
+
# there, and add a default title if one is not given
|
71
|
+
if not @spec.rdoc_options.include?("--main") then
|
72
|
+
@spec.rdoc_options.concat(["--main", rdoc_main])
|
73
|
+
end
|
74
|
+
|
75
|
+
if not @spec.rdoc_options.include?("--title") then
|
76
|
+
@spec.rdoc_options.concat(["--title","'#{name} -- #{summary}'"])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# if this gets set then it overwrites what would be the
|
81
|
+
# rubyforge default. If rubyforge project is not set then use
|
82
|
+
# name. If rubyforge project and name are set, but they are
|
83
|
+
# different then assume that name is a subproject of the
|
84
|
+
# rubyforge project
|
85
|
+
def remote_root
|
86
|
+
if rubyforge_project.nil? or
|
87
|
+
rubyforge_project == name then
|
88
|
+
return RUBYFORGE_ROOT + "#{name}/"
|
89
|
+
else
|
90
|
+
return RUBYFORGE_ROOT + "#{rubyforge_project}/#{name}/"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# rdoc files is the same as what would be generated during gem
|
95
|
+
# installation. That is, everything in the require paths plus
|
96
|
+
# the rdoc_extra_files
|
97
|
+
#
|
98
|
+
def rdoc_files
|
99
|
+
flist = extra_rdoc_files.dup
|
100
|
+
@spec.require_paths.each do |rp|
|
101
|
+
flist << FileList["#{rp}/**/*.rb"]
|
102
|
+
end
|
103
|
+
flist.flatten.uniq
|
104
|
+
end
|
105
|
+
|
106
|
+
# calculate the remote directories
|
107
|
+
def remote_root_location
|
108
|
+
"#{remote_user}@#{remote_host}:#{remote_root}"
|
109
|
+
end
|
110
|
+
|
111
|
+
def remote_rdoc_location
|
112
|
+
remote_root_location + @remote_rdoc_dir
|
113
|
+
end
|
114
|
+
|
115
|
+
def remote_coverage_location
|
116
|
+
remote_root_loation + @remote_coverage_dir
|
117
|
+
end
|
118
|
+
|
119
|
+
def remote_site_location
|
120
|
+
remote_root_location + @remote_site_dir
|
121
|
+
end
|
122
|
+
|
123
|
+
# we delegate any other calls to spec
|
124
|
+
def method_missing(method_id,*params,&block)
|
125
|
+
@spec.send method_id, *params, &block
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
namespace :extension do
|
2
|
+
desc "Build the extension(s)"
|
3
|
+
task :build do
|
4
|
+
<%= project_name.camelize %>::SPEC.extensions.each do |extension|
|
5
|
+
path = Pathname.new(extension)
|
6
|
+
parts = path.split
|
7
|
+
conf = parts.last
|
8
|
+
Dir.chdir(path.dirname) do |d|
|
9
|
+
ruby conf.to_s
|
10
|
+
sh "rake default"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'rubyforge'
|
2
|
+
|
3
|
+
#-----------------------------------------------------------------------
|
4
|
+
# Documentation - pushing documentation to rubyforge
|
5
|
+
#-----------------------------------------------------------------------
|
6
|
+
namespace :doc do
|
7
|
+
desc "Deploy the RDoc documentation to rubyforge"
|
8
|
+
task :deploy => :rerdoc do
|
9
|
+
sh "rsync -zav --delete #{<%= project_name.camelize %>::SPEC.local_rdoc_dir}/ #{<%= project_name.camelize %>::SPEC.rubyforge_rdoc_dest}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
#-----------------------------------------------------------------------
|
14
|
+
# Packaging and Distribution - push to rubyforge
|
15
|
+
#-----------------------------------------------------------------------
|
16
|
+
namespace :dist do
|
17
|
+
desc "Release files to rubyforge"
|
18
|
+
task :release => [:clean, :package] do
|
19
|
+
|
20
|
+
rubyforge = RubyForge.new
|
21
|
+
|
22
|
+
# make sure this release doesn't already exist
|
23
|
+
releases = rubyforge.autoconfig['release_ids']
|
24
|
+
if releases.has_key?(<%= project_name.camelize %>::SPEC.name) and releases[<%= project_name.camelize %>::SPEC.name][<%= project_name.camelize %>::VERSION] then
|
25
|
+
abort("Release #{<%= project_name.camelize %>::VERSION} already exists! Unable to release.")
|
26
|
+
end
|
27
|
+
|
28
|
+
config = rubyforge.userconfig
|
29
|
+
config["release_notes"] = <%= project_name.camelize %>::SPEC.description
|
30
|
+
config["release_changes"] = last_changeset
|
31
|
+
config["Prefomatted"] = true
|
32
|
+
|
33
|
+
|
34
|
+
puts "Uploading to rubyforge..."
|
35
|
+
files = FileList[File.join("pkg","#{<%= project_name.camelize %>::SPEC.name}-#{<%= project_name.camelize %>::VERSION}.*")].to_a
|
36
|
+
rubyforge.login
|
37
|
+
rubyforge.add_release(<%= project_name.camelize %>::SPEC.rubyforge_project, <%= project_name.camelize %>::SPEC.name, <%= project_name.camelize %>::VERSION, *files)
|
38
|
+
puts "done."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#-----------------------------------------------------------------------
|
43
|
+
# Announcements - Create an email text file, and post news to rubyforge
|
44
|
+
#-----------------------------------------------------------------------
|
45
|
+
def changes
|
46
|
+
change_file = File.expand_path(File.join(File.basename(__FILE__),"..","CHANGES"))
|
47
|
+
sections = File.read(change_file).split(/^(?===)/)
|
48
|
+
end
|
49
|
+
def last_changeset
|
50
|
+
changes[1]
|
51
|
+
end
|
52
|
+
|
53
|
+
def announcement
|
54
|
+
urls = " #{<%= project_name.camelize %>::SPEC.homepage}"
|
55
|
+
subject = "#{<%= project_name.camelize %>::SPEC.name} #{<%= project_name.camelize %>::VERSION} Released"
|
56
|
+
title = "#{<%= project_name.camelize %>::SPEC.name} version #{<%= project_name.camelize %>::VERSION} has been released."
|
57
|
+
body = <<BODY
|
58
|
+
#{<%= project_name.camelize %>::SPEC.description.rstrip}
|
59
|
+
|
60
|
+
{{ Changelog for Version #{<%= project_name.camelize %>::VERSION} }}
|
61
|
+
|
62
|
+
#{last_changeset.rstrip}
|
63
|
+
|
64
|
+
BODY
|
65
|
+
|
66
|
+
return subject, title, body, urls
|
67
|
+
end
|
68
|
+
|
69
|
+
namespace :announce do
|
70
|
+
desc "create email for ruby-talk"
|
71
|
+
task :email do
|
72
|
+
subject, title, body, urls = announcement
|
73
|
+
|
74
|
+
File.open("email.txt", "w") do |mail|
|
75
|
+
mail.puts "From: #{<%= project_name.camelize %>::SPEC.author} <#{<%= project_name.camelize %>::SPEC.email}>"
|
76
|
+
mail.puts "To: ruby-talk@ruby-lang.org"
|
77
|
+
mail.puts "Date: #{Time.now.rfc2822}"
|
78
|
+
mail.puts "Subject: [ANN] #{subject}"
|
79
|
+
mail.puts
|
80
|
+
mail.puts title
|
81
|
+
mail.puts
|
82
|
+
mail.puts urls
|
83
|
+
mail.puts
|
84
|
+
mail.puts body
|
85
|
+
mail.puts
|
86
|
+
mail.puts urls
|
87
|
+
end
|
88
|
+
puts "Created the following as email.txt:"
|
89
|
+
puts "-" * 72
|
90
|
+
puts File.read("email.txt")
|
91
|
+
puts "-" * 72
|
92
|
+
end
|
93
|
+
|
94
|
+
CLOBBER << "email.txt"
|
95
|
+
|
96
|
+
desc "Post news of #{<%= project_name.camelize %>::SPEC.name} to #{<%= project_name.camelize %>::SPEC.rubyforge_project} on rubyforge"
|
97
|
+
task :post_news do
|
98
|
+
subject, title, body, urls = announcement
|
99
|
+
rubyforge = RubyForge.new
|
100
|
+
rubyforge.login
|
101
|
+
rubyforge.post_news(<%= project_name.camelize %>::SPEC.rubyforge_project, subject, "#{title}\n\n#{urls}\n\n#{body}")
|
102
|
+
puts "Posted to rubyforge"
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|