reap 0.4.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.
Files changed (48) hide show
  1. data/ChangeLog +2 -0
  2. data/LICENSE +11 -0
  3. data/README +59 -0
  4. data/Reapfile +85 -0
  5. data/bin/reap +103 -0
  6. data/doc/classes/Reap/AnnounceTask.html +331 -0
  7. data/doc/classes/Reap/ChmodTask.html +278 -0
  8. data/doc/classes/Reap/PackageTask.html +372 -0
  9. data/doc/classes/Reap/PublishTask.html +231 -0
  10. data/doc/classes/Reap/RDocTask.html +254 -0
  11. data/doc/classes/Reap/Runner.html +307 -0
  12. data/doc/classes/Reap/Task.html +390 -0
  13. data/doc/classes/Reap/TemplateTask.html +233 -0
  14. data/doc/classes/Reap/TestTask.html +242 -0
  15. data/doc/classes/Reap.html +184 -0
  16. data/doc/created.rid +1 -0
  17. data/doc/files/LICENSE.html +119 -0
  18. data/doc/files/README.html +194 -0
  19. data/doc/files/lib/reap/reap_rb.html +110 -0
  20. data/doc/files/lib/reap/runner_rb.html +113 -0
  21. data/doc/files/lib/reap/task_rb.html +108 -0
  22. data/doc/files/lib/reap/tasks/announce-task_rb.html +113 -0
  23. data/doc/files/lib/reap/tasks/chmod-task_rb.html +101 -0
  24. data/doc/files/lib/reap/tasks/package-task_rb.html +108 -0
  25. data/doc/files/lib/reap/tasks/publish-task_rb.html +101 -0
  26. data/doc/files/lib/reap/tasks/rdoc-task_rb.html +101 -0
  27. data/doc/files/lib/reap/tasks/template-task_rb.html +108 -0
  28. data/doc/files/lib/reap/tasks/test-task_rb.html +101 -0
  29. data/doc/files/lib/reap/template_rb.html +101 -0
  30. data/doc/fr_class_index.html +36 -0
  31. data/doc/fr_file_index.html +39 -0
  32. data/doc/fr_method_index.html +69 -0
  33. data/doc/index.html +24 -0
  34. data/doc/rdoc-style.css +208 -0
  35. data/lib/reap/reap.rb +11 -0
  36. data/lib/reap/runner.rb +95 -0
  37. data/lib/reap/task.rb +103 -0
  38. data/lib/reap/tasks/announce-task.rb +140 -0
  39. data/lib/reap/tasks/chmod-task.rb +72 -0
  40. data/lib/reap/tasks/package-task.rb +153 -0
  41. data/lib/reap/tasks/publish-task.rb +33 -0
  42. data/lib/reap/tasks/rdoc-task.rb +57 -0
  43. data/lib/reap/tasks/template-task.rb +38 -0
  44. data/lib/reap/tasks/test-task.rb +45 -0
  45. data/lib/reap/template.rb +72 -0
  46. data/setup.rb +1361 -0
  47. data/test/test_require.rb +11 -0
  48. metadata +112 -0
@@ -0,0 +1,140 @@
1
+
2
+ require 'net/smtp'
3
+ require 'facet/string/margin'
4
+ require 'facet/string/tab'
5
+ require 'facet/string/center_lines'
6
+ require 'facet/string/clump'
7
+ require 'facet/string/word_wrap'
8
+
9
+ module Reap
10
+
11
+ class AnnounceTask < Task
12
+
13
+ def self.task ; :announce ; end
14
+
15
+ def self.desc ; "Sends [ANN] email to ruby-talk or other list." ; end
16
+
17
+
18
+ def set( section )
19
+ @address = section['to']
20
+ @from = section['from'].to_s
21
+ @server = section['server'].to_s.strip
22
+ @port = section['port'] || 25
23
+ @domain = section['domain'].to_s.strip
24
+ @account = section['account'].to_s
25
+ @authtype = section['authtype'].to_sym
26
+ @subject = "[ANN] #{@config['title']}, v#{@config['version']}"
27
+
28
+ #raise "DOMAIN is a required field" if @domain.empty?
29
+
30
+ announce = %Q{
31
+ |
32
+ |A N N O U N C I N G
33
+ |
34
+ |#{@config['title']}, v#{@config['version']}
35
+ |
36
+ |#{@config['summary']}
37
+ |
38
+ }.margin.center_lines(66)
39
+
40
+ # abstract
41
+ abstract = ''
42
+ desc = @config['description']
43
+ if desc
44
+ abstract << "\n\n"
45
+ abstract << "ABSTRACT: #{desc}".word_wrap(72)
46
+ abstract << "\n"
47
+ end
48
+
49
+ # more info
50
+ info = ''
51
+ info_arr = section['info']
52
+ unless info_arr.empty?
53
+ info << "\n"
54
+ info << "For More Information".center(67)
55
+ info << "\n"
56
+ info_arr.each{ |mi| info << "#{mi}".center(67) }
57
+ info << "\n\n"
58
+ end
59
+
60
+ # slogan
61
+ slogan = ''
62
+ if section['slogan']
63
+ slogan << "\n\n"
64
+ slogan << section['slogan'].center(67)
65
+ slogan << "\n\n"
66
+ end
67
+
68
+ # memo
69
+ memo = ''
70
+ if section['memo']
71
+ memo = ''
72
+ memo << "\n" << ('-' * 72) << "\n"
73
+ memo << "(Memo)\n\n"
74
+ memo << section['memo'].clump.word_wrap(72)
75
+ #memo << "\n"
76
+ end
77
+
78
+ # msg file
79
+ msg = ''
80
+ msg_file = section['file']
81
+ if msg_file and File.file?( msg_file )
82
+ msg << "\n" << ("-" * 72) << "\n"
83
+ msg << "(from #{msg_file})\n\n"
84
+ mg = ''
85
+ File.open( msg_file ) { |f| mg << f.gets(nil) }
86
+ msg << mg.clump.word_wrap(72)
87
+ end
88
+
89
+ # stamp
90
+ stamp = ''
91
+ stamp << "\n" << ("-" * 72) << "\n"
92
+ stamp << %Q{
93
+ |Generated by Reap, a dedicated Ruby Packaging Assistant.
94
+ |Do you Ruby? (http://www.ruby-lang.org)
95
+ }.margin
96
+ stamp << "\n\n"
97
+
98
+ @message = ''
99
+ @message << announce
100
+ @message << abstract
101
+ @message << info
102
+ @message << slogan
103
+ @message << memo
104
+ @message << msg
105
+ @message << stamp
106
+ end
107
+
108
+ def run
109
+ puts "\n#{@message}\n\n"
110
+ print "Send? [Y/n] "
111
+ until inp = $stdin.gets[0,1] ; sleep 1 ; end
112
+ if (inp || 'y').downcase == 'y'
113
+ # ask for password
114
+ print "Password for #{@account}: "
115
+ until passwd = $stdin.gets.strip ; sleep 1 ; end
116
+ mail = %Q{
117
+ |From: #{@from}
118
+ |To: #{@address}
119
+ |Subject: #{@subject}
120
+ |
121
+ |#{@message}
122
+ }.margin
123
+ begin
124
+ # --- Send using SMTP object and an adaptor
125
+ Net::SMTP.start(@server, @port, @domain, @account, passwd, @authtype) do |s|
126
+ s.send_message mail, @from, @address
127
+ end
128
+ puts "Email sent successfully to #{@address}."
129
+ rescue => e
130
+ puts "Email delivery failed."
131
+ puts e
132
+ end
133
+ else
134
+ puts "Reap announce task canceled."
135
+ exit 0
136
+ end
137
+ end
138
+ end
139
+
140
+ end #module Reap
@@ -0,0 +1,72 @@
1
+
2
+ module Reap
3
+
4
+ class ChmodTask < Task
5
+
6
+ def self.task; :chmod ; end
7
+
8
+ def self.desc; "Change the permissions of package files." ; end
9
+
10
+
11
+ def set( section )
12
+ # @user = section['user']
13
+ # @group = section['group']
14
+ # #raise "USER and GROUP are required CHMOD fields." unless @user and @group
15
+ end
16
+
17
+ def run
18
+ puts "Reap is shelling out work to chmod..."
19
+
20
+ # misc
21
+ misc = FileList.new
22
+ misc.include('[A-Z]*')
23
+ misc.exclude('InstalledFiles')
24
+ chmod( misc ) unless misc.empty?
25
+
26
+ # lib
27
+ libs = FileList.new
28
+ libs.include('lib/**/*')
29
+ libs.exclude('lib/CVS/**/*')
30
+ libs.include('packages/*/lib/**/*')
31
+ libs.exclude('packages/*/lib/CVS/**/*')
32
+ libs.exclude('packages/CVS/**/*')
33
+ chmod( libs ) unless libs.empty?
34
+
35
+ # bin
36
+ bins = FileList.new
37
+ bins.include('bin/**/*')
38
+ bins.exclude('bin/CVS/**/*')
39
+ bins.include('packages/*/bin/**/*')
40
+ bins.exclude('packages/*/bin/CVS/**/*')
41
+ bins.exclude('packages/CVS/**/*')
42
+ chmod( bins, 755 ) unless bins.empty?
43
+ end
44
+
45
+ private
46
+
47
+ def chmod( file_list, file_mode=644, dir_mode=755 )
48
+ dirs, files = file_list.partition{ |l| File.directory?(l) }
49
+ unless files.empty?
50
+ fstr = '"' + files.join('" "') + '"'
51
+ sh %{chmod #{file_mode} #{fstr}}
52
+ end
53
+ unless dirs.empty?
54
+ fstr = '"' + dirs.join('" "') + '"'
55
+ sh %{chmod #{dir_mode} #{fstr}}
56
+ end
57
+ end
58
+
59
+ # def chown( file_list, user, group )
60
+ # fstr = '"' + file_list.join('" "') + '"'
61
+ # if user
62
+ # if group
63
+ # sh %{chown #{user}.#{group} #{fstr}}
64
+ # else
65
+ # sh %{chown #{user} #{fstr}}
66
+ # end
67
+ # end
68
+ # end
69
+
70
+ end #class ChmodTask
71
+
72
+ end #module Reap
@@ -0,0 +1,153 @@
1
+
2
+ require 'rubygems'
3
+
4
+ module Reap
5
+
6
+ #
7
+ # Package Task
8
+ #
9
+ # This task allows on to create standard .zip, .tgz, or .tbz
10
+ # packages, plus create gem distributions.
11
+ #
12
+ class PackageTask < Task
13
+
14
+ def self.task ; :package ; end
15
+
16
+ def self.desc ; "Build standard .tar.gz, .tar.bzip2 and .zip packages." ; end
17
+
18
+
19
+ def set( section )
20
+ @dir = section['dir'] || 'pkg'
21
+
22
+ @name = section['name'] || @config['name']
23
+ @version = section['version'] || @config['version'] || '0.0.1'
24
+ @package_name = @name + '--' + @version
25
+
26
+ @author = section['author'] || @config['author']
27
+ @email = section['email'] || @config['email']
28
+ @summary = section['summary'] || @config['summary']
29
+ @project = section['project'] || @config['rubyforge']['project']
30
+ @homepage = section['homepage'] || @config['homepage'] || @config['rubyforge']['homepage']
31
+
32
+ @include = section['include'] || DEFAULT_INCLUDE
33
+ @exclude = MUST_EXCLUDE + section['exclude']
34
+
35
+ @zip = section['zip'].nil? ? true : section['zip']
36
+ @gzip = section['gzip'].nil? ? true : section['zip']
37
+ @bzip2 = section['bzip2'].nil? ? true : section['zip']
38
+ @gem = section['gem'].nil? ? true : section['gem']
39
+
40
+ # gem specific
41
+ if self['platform']
42
+ @platform = ::Gem.const_get(section['platform'])
43
+ else
44
+ @platform = ::Gem::Platform::RUBY
45
+ end
46
+ @autorequire = section['autorequire']
47
+ @requirements = section['requirements'] || []
48
+ @dependencies = section['dependencies'] || []
49
+ @executables = section['executables'] || []
50
+ end
51
+
52
+ def run
53
+ # create package image
54
+ if FileTest.directory?(@dir)
55
+ print "Directory '#{@dir}' already exists. Clobber? [y/N] "
56
+ until inp = $stdin.gets[0,1] ; sleep 1 ; end
57
+ if (inp || 'y').downcase == 'y'
58
+ puts "Removing old directory '#{File.expand_path(@dir)}'..."
59
+ trash_dir = ".trash/#{File.basename(@dir)}"
60
+ FileUtils.mkdir_p(".trash") unless FileTest.directory?(".trash")
61
+ FileUtils.rm_r(trash_dir) if FileTest.exists?(trash_dir)
62
+ FileUtils.mv(@dir, trash_dir)
63
+ else
64
+ puts "Reap package task canceled."
65
+ exit 0
66
+ end
67
+ end
68
+ package_dir_path = "#{@dir}/#{@package_name}"
69
+ package_files = FileList.new
70
+ package_files.include(*@include)
71
+ package_files.exclude(*@exclude) if @exclude and not @exclude.empty?
72
+ FileUtils.mkdir_p @dir #rescue nil
73
+ package_files.each do |fn|
74
+ f = File.join(package_dir_path, fn)
75
+ fdir = File.dirname(f)
76
+ FileUtils.mkdir_p(fdir) if not File.exist?(fdir)
77
+ if File.directory?(fn)
78
+ FileUtils.mkdir_p(f)
79
+ else
80
+ FileUtils.rm_f(f)
81
+ FileUtils.safe_ln(fn, f)
82
+ end
83
+ end
84
+
85
+ # create standard package files
86
+ FileUtils.chdir(@dir) do
87
+ # tar bzip2 for unix
88
+ if @bzip2
89
+ puts "\nReap is shelling out work to tar and bzip2..."
90
+ sh %{tar --bzip2 -cvf #{@package_name}.tbz #{@package_name}}
91
+ end
92
+ # tar gzip for unix
93
+ if @gzip
94
+ puts "\nReap is shelling out work to tar and gzip..."
95
+ sh %{tar --gzip -cvf #{@package_name}.tgz #{@package_name}}
96
+ end
97
+ # zip for windows
98
+ if @zip
99
+ puts "\nReap is shelling out work to zip..."
100
+ sh %{zip -r #{@package_name}.zip #{@package_name}}
101
+ end
102
+ puts
103
+ end
104
+
105
+ # create gem package
106
+ if @gem
107
+ run_gem
108
+ end
109
+ return true
110
+ end
111
+
112
+ private
113
+
114
+ def run_gem
115
+ spec = Gem::Specification.new { |s|
116
+ s.name = @name
117
+ s.version = @version
118
+ @dependencies.each{ |d,v|
119
+ if v
120
+ s.add_dependency(d, v)
121
+ else
122
+ s.add_dependency(d)
123
+ end
124
+ }
125
+ s.platform = @platform
126
+ s.summary = @summary
127
+ s.requirements = @requirements
128
+
129
+ # s.files = Dir.glob("lib/**/*").delete_if {|item| item.include?("CVS")}
130
+ # s.files.concat Dir.glob("bin/**/*").delete_if {|item| item.include?("CVS")}
131
+ package_files = FileList.new
132
+ package_files.include(*@include)
133
+ package_files.exclude(*@exclude) if @exclude and not @exclude.empty?
134
+ s.files = package_files.to_a
135
+
136
+ s.require_path = 'lib'
137
+ s.autorequire = @autorequire if @autorequire
138
+ s.author = @author
139
+ s.email = @email
140
+ s.rubyforge_project = @project
141
+ s.homepage = @homepage
142
+ s.executables = @executables
143
+ s.bindir = "bin"
144
+ }
145
+ puts "Reap is shelling out work to the Gem Package Manager..."
146
+ Gem.manage_gems
147
+ Gem::Builder.new(spec).build
148
+ sh %{mv ./*.gem #{@dir}/}
149
+ end
150
+
151
+ end #class PackageTask
152
+
153
+ end #module Reap
@@ -0,0 +1,33 @@
1
+
2
+ module Reap
3
+
4
+ class PublishTask < Task
5
+
6
+ def self.task ; :publish ; end
7
+
8
+ def self.desc ; "Publish documents to the web." ; end
9
+
10
+
11
+ def set( section )
12
+ @dir = section["dir"]
13
+ #@exclude = section["exclude"]
14
+ @project = section["project"]
15
+ @username = section["username"]
16
+ end
17
+
18
+ def run
19
+ #current_dir = Dir.pwd
20
+ #Dir.chdir( @web_dir )
21
+ #web_files = FileList.new
22
+ #web_files.include('**/*')
23
+ #web_files.exclude(*@web_exclude) if @web_exclude
24
+ #web_files = '"' << web_files.join('" "') << '"'
25
+ cmd = %{scp -r #{@dir}/* #{@username}@rubyforge.org:/var/www/gforge-projects/#{@project}/}
26
+ puts "Reap is shelling out work to scp..."
27
+ puts cmd
28
+ sh(cmd) unless $PRETEND
29
+ end
30
+
31
+ end
32
+
33
+ end
@@ -0,0 +1,57 @@
1
+
2
+ module Reap
3
+
4
+ class RDocTask < Task
5
+
6
+ def self.task; :rdoc ; end
7
+
8
+ def self.desc ; "Generate RDocs." ; end
9
+
10
+
11
+ def set( section )
12
+ @dir = section["dir"] || 'doc/rdoc'
13
+ @main = section["main"]
14
+ @title = section["title"] || @config["title"]
15
+ @template = section["template"] || 'html'
16
+ @include = section["include"] || ['lib/**/*']
17
+ @exclude = section["exclude"]
18
+ @options = section["options"] || []
19
+ end
20
+
21
+ def run
22
+ rdoc_dir = File.expand_path(@dir)
23
+ if FileTest.directory?(@dir)
24
+ print "Directory '#{@dir}' already exists. Clobber? [y/N] "
25
+ until inp = $stdin.gets[0,1] ; sleep 1 ; end ; puts
26
+ if (inp || 'y').downcase == 'y'
27
+ puts "Removing old directory '#{rdoc_dir}'..."
28
+ trash_dir = ".trash/#{File.basename(@dir)}"
29
+ FileUtils.mkdir_p(".trash") unless FileTest.directory?(".trash")
30
+ FileUtils.rm_r(trash_dir) if FileTest.exists?(trash_dir)
31
+ FileUtils.mv(@dir, trash_dir)
32
+ else
33
+ puts "Packmule rdoc task canceled."
34
+ return nil
35
+ end
36
+ end
37
+ rdoc_target = "#{rdoc_dir}/index.html"
38
+ # rdoc files
39
+ rdoc_files = FileList.new
40
+ rdoc_files.include(*@include)
41
+ rdoc_files.exclude(*@exclude)
42
+ rdoc_files = '"' << rdoc_files.join('" "') << '"'
43
+ # build options string
44
+ build = @options.dup
45
+ build << "--main '#{@main}'" if @main
46
+ build << "--title '#{@title}'" if @title
47
+ build << "-T '#{@template}'" if @template
48
+ rdoc_opts = build.join(' ')
49
+ # do it!
50
+ puts "PackMule is shelling work out to RDoc..."
51
+ puts %{rdoc -o #{@dir} #{rdoc_opts}}
52
+ sh %{rdoc -o #{rdoc_dir} #{rdoc_opts} #{rdoc_files}}
53
+ end
54
+
55
+ end
56
+
57
+ end #module Reap
@@ -0,0 +1,38 @@
1
+
2
+ require 'fileutils'
3
+
4
+ module Reap
5
+
6
+ class TemplateTask < Task
7
+
8
+ def self.task ; :template ; end
9
+
10
+ def self.desc ; "Create template configuration file in current directory." ; end
11
+
12
+
13
+ def set( section )
14
+ end
15
+
16
+ def run
17
+ dir = File.dirname(File.dirname(__FILE__))
18
+ tmpf = File.join( dir, 'template.rb' )
19
+ unless File.file?( tmpf )
20
+ puts tmpf
21
+ raise "Tempfile is missing."
22
+ end
23
+
24
+ if File.directory?("Reapfile")
25
+ puts "Why is Reapfile a directory? Cannot comply."
26
+ return
27
+ elsif File.file?("Reapfile")
28
+ puts "Reapfile already exists."
29
+ return
30
+ end
31
+ # copy tmpf to Reapfile
32
+ FileUtils.cp( tmpf, "Reapfile" )
33
+ puts "Reapfile create. You'll need to fill it out."
34
+ end
35
+
36
+ end #class Template
37
+
38
+ end #module Reap
@@ -0,0 +1,45 @@
1
+
2
+ module Reap
3
+
4
+ class TestTask < Task
5
+
6
+ def self.task ; :test ; end
7
+
8
+ def self.desc ; "Run unit tests." ; end
9
+
10
+
11
+ def set( section )
12
+ @libs = ( section["libs"] || ['lib'] ).join(':')
13
+ #@libs = (section["libs"] || []).join(':')
14
+ @files = section["files"] || [ 'test/**/tc*.rb', 'test/**/test*.rb', 'test/**/*test.rb' ]
15
+ @options = section['options']
16
+ end
17
+
18
+ def run
19
+ # get test files
20
+ test_libs = @libs
21
+ test_files = FileList.new
22
+ test_files.include(*@files)
23
+ if test_files.empty?
24
+ puts "No test files found."
25
+ return
26
+ end
27
+ #test_reqs = test_files.gsub(/^(.*)\.rb$/, ' -r"\1"').join(" \\\n")
28
+ #test_opts = " \\\n -- #{@options}" if @options
29
+ puts "Reap is shelling out work to Ruby's Test Suite..."
30
+ begin
31
+ test_files.each { |f|
32
+ ruby %{-r"test/unit" "#{f}"}
33
+ }
34
+ #puts %Q{ ruby %{-I#{test_libs} -e0 -r"test/unit" \\\n#{test_reqs}#{test_opts}} } if $DEBUG
35
+ #ruby %{-I#{test_libs} -e0 -r"test/unit" \\\n#{test_reqs}#{test_opts}}
36
+ #ruby %{-e0 -r"test/unit" \\\n#{test_reqs}#{test_opts}}
37
+ rescue
38
+ puts "Error occured while trying to run tests."
39
+ exit 0
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ end #module Reap
@@ -0,0 +1,72 @@
1
+ --- %YAML:1.0
2
+
3
+ TITLE: &title Your Package
4
+ NAME: &pkg your_package_name
5
+ VERSION: '0.0.1'
6
+ AUTHOR: Your Name
7
+ EMAIL: &email youremail@address.com
8
+ HOMEPAGE: "http://your_package_name.rubyforge.org"
9
+ SUMMARY: One line summary
10
+ DESCRIPTION: >
11
+ Multline description goes here.
12
+
13
+ RUBYFORGE:
14
+ PROJECT: 'your_project_name'
15
+ USERNAME: your_rubyforge_username
16
+
17
+ TEST:
18
+ FILES:
19
+ - 'test/**/tc_*.rb'
20
+ OPTIONS: ~
21
+
22
+ RDOC:
23
+ TITLE: *title
24
+ DIR: 'doc' #'rdoc'
25
+ TEMPLATE: html #ruby-red
26
+ OPTIONS: ['--merge', '--promiscuous', '--all']
27
+ MAIN: README
28
+ INCLUDE:
29
+ - 'README'
30
+ - 'LICEN*'
31
+ - 'lib/**/*.rb'
32
+ - 'bin/**/*.rb'
33
+ EXCLUDE: []
34
+
35
+ PACKAGE:
36
+ DIR: pkg
37
+ INCLUDE:
38
+ - 'lib/**/*'
39
+ - 'bin/**/*'
40
+ - 'bench/**/*'
41
+ - 'test/**/*'
42
+ - 'doc/**/*'
43
+ - 'rdoc/**/*'
44
+ - 'pub/**/*'
45
+ - 'www/**/*'
46
+ - 'demo/**/*'
47
+ - 'samples/**/*'
48
+ - 'examples/**/*'
49
+ - 'setup.rb'
50
+ - '[A-Z]*'
51
+ EXCLUDE:
52
+ - InstalledFiles
53
+ ZIP: true
54
+ GZIP: true
55
+ BZIP2: true
56
+
57
+ ANNOUNCE:
58
+ TO: ruby-talk@ruby-lang.org
59
+ FROM: *email
60
+ DOMAIN: your_domain.net
61
+ SERVER: smtp.your_email_server.com
62
+ PORT: 25
63
+ ACCOUNT: email_account_name
64
+ AUTHTYPE: login #cram_md5 #plain
65
+ FILE: ANN #which file contains tha announcement text
66
+ SLOGAN: ALL YOUR BASE ARE BELONG TO RUBY!
67
+ INFO:
68
+ - http://your_homepage.org
69
+
70
+ GEMSPEC:
71
+ ACTIVE: true
72
+