hoe 1.12.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
@@ -1,3 +1,22 @@
1
+ === 2.0.0 / 2009-06-02
2
+
3
+ * 3 major enhancements:
4
+
5
+ * Added a plugin system and extracted nearly everything into separate plugins.
6
+ * Added Clean, Debug, Deps, Flay, Flog, Inline, Package, Publish, Rake, Rcov, Signing, and Test plugins
7
+
8
+ * 9 minor enhancements:
9
+
10
+ * Added Hoe::spec replacing old Hoe.new spec form. Now with DSL flavors!
11
+ * Added DEFAULT_CONFIG so plugins can add to it.
12
+ * Added pluggable! to declare your package depends on rubygems 1.3.1+.
13
+ * Changes are now included in the gem's description.
14
+ * Deprecated Hoe.new spec form.
15
+ * Filled in all the blanks on rdoc.
16
+ * Refactored nearly all the spec logic down to much smaller/cleaner pieces.
17
+ * Updated templates to use new form. No clue how best to update yours. :P
18
+ * Version number is now auto-searchable by grepping in all the files.
19
+
1
20
  === 1.12.2 / 2009-04-16
2
21
 
3
22
  * 1 minor enhancement:
@@ -4,6 +4,18 @@ README.txt
4
4
  Rakefile
5
5
  bin/sow
6
6
  lib/hoe.rb
7
+ lib/hoe/clean.rb
8
+ lib/hoe/debug.rb
9
+ lib/hoe/deps.rb
10
+ lib/hoe/flay.rb
11
+ lib/hoe/flog.rb
12
+ lib/hoe/inline.rb
13
+ lib/hoe/package.rb
14
+ lib/hoe/publish.rb
15
+ lib/hoe/rake.rb
16
+ lib/hoe/rcov.rb
17
+ lib/hoe/signing.rb
18
+ lib/hoe/test.rb
7
19
  template/.autotest.erb
8
20
  template/History.txt.erb
9
21
  template/Manifest.txt.erb
data/README.txt CHANGED
@@ -6,58 +6,45 @@
6
6
 
7
7
  == DESCRIPTION:
8
8
 
9
- Hoe is a simple rake/rubygems helper for project Rakefiles. It
10
- generates all the usual tasks for projects including rdoc generation,
11
- testing, packaging, and deployment.
12
-
13
- Tasks Provided:
14
-
15
- * announce - Create news email file and post to rubyforge.
16
- * audit - Run ZenTest against the package.
17
- * check_extra_deps - Install missing dependencies.
18
- * check_manifest - Verify the manifest.
19
- * clean - Clean up all the extras.
20
- * config_hoe - Create a fresh ~/.hoerc file.
21
- * debug_gem - Show information about the gem.
22
- * default - Run the default task(s).
23
- * deps:email - Print a contact list for gems dependent on this gem
24
- * deps:fetch - Fetch all the dependent gems of this gem into tarballs
25
- * deps:list - List all the dependent gems of this gem
26
- * docs - Build the docs HTML Files
27
- * email - Generate email announcement file.
28
- * flay - Analyze for code duplication.
29
- * flog - Analyze code complexity.
30
- * gem - Build the gem file hoe-1.9.0.gem
31
- * generate_key - Generate a key for signing your gems.
32
- * install_gem - Install the package as a gem.
33
- * multi - Run the test suite using multiruby.
34
- * package - Build all the packages
35
- * post_blog - Post announcement to blog.
36
- * post_news - Post announcement to rubyforge.
37
- * publish_docs - Publish RDoc to RubyForge.
38
- * rcov - Analyze code coverage with tests
39
- * release - Package and upload the release to rubyforge.
40
- * ridocs - Generate ri locally for testing.
41
- * tasks - Generate a list of tasks for doco.
42
- * test - Run the test suite.
43
- * test_deps - Show which test files fail when run alone.
9
+ Hoe is a rake/rubygems helper for project Rakefiles. It helps generate
10
+ rubygems and includes a dynamic plug-in system allowing for easy
11
+ extensibility. Hoe ships with plug-ins for all your usual project
12
+ tasks including rdoc generation, testing, packaging, and deployment.
13
+
14
+ Plug-ins Provided:
15
+
16
+ * Hoe::Clean
17
+ * Hoe::Debug
18
+ * Hoe::Deps
19
+ * Hoe::Flay
20
+ * Hoe::Flog
21
+ * Hoe::Inline
22
+ * Hoe::Package
23
+ * Hoe::Publish
24
+ * Hoe::RCov
25
+ * Hoe::Signing
26
+ * Hoe::Test
44
27
 
45
28
  See class rdoc for help. Hint: ri Hoe
46
29
 
47
30
  == FEATURES/PROBLEMS:
48
31
 
32
+ * Includes a dynamic plug-in system allowing for easy extensibility.
33
+ * Auto-intuits changes, description, summary, and version.
34
+ * Uses a manifest for safe and secure deployment.
49
35
  * Provides 'sow' for quick project directory creation.
50
- * Make making and maintaining Rakefiles fun and easy.
36
+ * Sow uses a simple ERB templating system allowing you to capture your
37
+ project patterns
51
38
 
52
39
  == SYNOPSIS:
53
40
 
54
41
  % sow [group] project
55
42
 
56
- or
43
+ or:
57
44
 
58
45
  require 'hoe'
59
46
 
60
- Hoe.new(projectname, version) do |p|
47
+ Hoe.spec projectname do
61
48
  # ... project specific data ...
62
49
  end
63
50
 
data/Rakefile CHANGED
@@ -1,31 +1,24 @@
1
1
  # -*- ruby -*-
2
2
 
3
+ $: << 'lib'
4
+
3
5
  require './lib/hoe.rb'
4
6
 
7
+ # TODO:
8
+ # Hoe.plugin :perforce
9
+ # Hoe.plugin :minitest
10
+
5
11
  Hoe.add_include_dirs("../../minitest/dev/lib")
6
12
 
7
- Hoe.new("hoe", Hoe::VERSION) do |hoe|
8
- hoe.rubyforge_name = "seattlerb"
13
+ Hoe.spec "hoe" do
14
+ developer "Ryan Davis", "ryand-ruby@zenspider.com"
9
15
 
10
- hoe.developer("Ryan Davis", "ryand-ruby@zenspider.com")
16
+ self.rubyforge_name = "seattlerb"
17
+ self.testlib = :minitest
11
18
 
12
- hoe.testlib = :minitest
13
- hoe.blog_categories << "Seattle.rb" << "Ruby"
14
- end
19
+ blog_categories << "Seattle.rb" << "Ruby"
15
20
 
16
- desc "Generate a list of tasks for doco. RDOC=1 for commented output"
17
- task :tasks do
18
- tasks = `rake -T`.scan(/rake (\w+)\s+# (.*)/)
19
- tasks.reject! { |t,d| t =~ /^(clobber|tasks|re(package|docs))/ }
20
- max = tasks.map { |x,y| x.size }.max
21
-
22
- tasks.each do |t,d|
23
- if ENV['RDOC'] then
24
- puts "# %-#{max+2}s %s" % [t + "::", d]
25
- else
26
- puts "* %-#{max}s - %s" % [t, d]
27
- end
28
- end
21
+ pluggable!
29
22
  end
30
23
 
31
24
  # vim: syntax=Ruby
data/bin/sow CHANGED
@@ -67,11 +67,9 @@ if $d || $t then
67
67
  FileUtils.mv temp_dir, "#{project}/#{$d ? 'dev' : 'trunk'}", :verbose => true
68
68
  end
69
69
 
70
- WINDOZE = /mswin|mingw/ =~ RUBY_PLATFORM
71
-
72
70
  puts
73
71
  puts "... done, now go fix all occurrences of '#{XIF}':"
74
- if WINDOZE then
72
+ if Hoe::WINDOZE then
75
73
  puts `findstr /N /S /C:#{XIF} #{project}\\*`
76
74
  else
77
75
  puts `find #{project} -type f | xargs grep -n #{XIF}`.gsub(/\A|\n/, "\n ")
data/lib/hoe.rb CHANGED
@@ -19,134 +19,57 @@ rescue Gem::LoadError
19
19
  end
20
20
 
21
21
  ##
22
- # hoe - a tool to help rake
23
- #
24
- # Hoe is a simple rake/rubygems helper for project Rakefiles. It
25
- # generates all the usual tasks for projects including rdoc generation,
26
- # testing, packaging, and deployment.
22
+ # Hoe is a simple rake/rubygems helper for project Rakefiles. It helps
23
+ # generate rubygems and includes a dynamic plug-in system allowing for
24
+ # easy extensibility. Hoe ships with plug-ins for all your usual
25
+ # project tasks including rdoc generation, testing, packaging, and
26
+ # deployment.
27
27
  #
28
28
  # == Using Hoe
29
29
  #
30
30
  # === Basics
31
31
  #
32
- # Use this as a minimal starting point:
33
- #
34
- # require 'hoe'
35
- # require './lib/project.rb'
36
- #
37
- # Hoe.new("project_name", Project::VERSION) do |p|
38
- # p.rubyforge_name = "rf_project"
39
- # p.developer("Joe Blow", "joe@example.com")
40
- # # add other details here
41
- # end
32
+ # Sow generates a new project from scratch. Sow uses a simple ERB
33
+ # templating system allowing you to capture patterns common to your
34
+ # projects. Run `sow` and then see ~/.hoe_template for more info:
42
35
  #
43
- # # add other tasks here
36
+ # % sow project_name
37
+ # ...
38
+ # % cd project_name
44
39
  #
45
- # === Tasks Provided:
46
- #
47
- # announce:: Create news email file and post to rubyforge.
48
- # audit:: Run ZenTest against the package.
49
- # check_extra_deps:: Install missing dependencies.
50
- # check_manifest:: Verify the manifest.
51
- # clean:: Clean up all the extras.
52
- # config_hoe:: Create a fresh ~/.hoerc file.
53
- # debug_gem:: Show information about the gem.
54
- # default:: Run the default task(s).
55
- # deps:email:: Print a contact list for gems dependent on this gem
56
- # deps:fetch:: Fetch all the dependent gems of this gem into tarballs
57
- # deps:list:: List all the dependent gems of this gem
58
- # docs:: Build the docs HTML Files
59
- # email:: Generate email announcement file.
60
- # flay:: Analyze for code duplication.
61
- # flog:: Analyze code complexity.
62
- # gem:: Build the gem file hoe-1.9.0.gem
63
- # generate_key:: Generate a key for signing your gems.
64
- # install_gem:: Install the package as a gem.
65
- # multi:: Run the test suite using multiruby.
66
- # package:: Build all the packages
67
- # post_blog:: Post announcement to blog.
68
- # post_news:: Post announcement to rubyforge.
69
- # publish_docs:: Publish RDoc to RubyForge.
70
- # rcov:: Analyze code coverage with tests
71
- # release:: Package and upload the release to rubyforge.
72
- # ridocs:: Generate ri locally for testing.
73
- # tasks:: Generate a list of tasks for doco.
74
- # test:: Run the test suite.
75
- # test_deps:: Show which test files fail when run alone.
40
+ # and have at it.
76
41
  #
77
42
  # === Extra Configuration Options:
78
43
  #
79
- # Run +config_hoe+ to generate a new ~/.hoerc file. The file is a
80
- # YAML formatted config file with the following settings:
81
- #
82
- # exclude:: A regular expression of files to exclude from
83
- # +check_manifest+.
84
- # publish_on_announce:: Run +publish_docs+ when you run +release+.
85
- # signing_key_file:: Signs your gems with this private key.
86
- # signing_cert_file:: Signs your gem with this certificate.
87
- # blogs:: An array of hashes of blog settings.
88
- #
89
- # Run +config_hoe+ and see ~/.hoerc for examples.
90
- #
91
- # === Signing Gems:
92
- #
93
- # Run the 'generate_key' task. This will:
94
- #
95
- # 1. Configure your ~/.hoerc.
96
- # 2. Generate a signing key and certificate.
97
- # 3. Install the private key and public certificate files into ~/.gem.
98
- # 4. Upload the certificate to RubyForge.
99
- #
100
- # Hoe will now generate signed gems when the package task is run. If you have
101
- # multiple machines you build gems on, be sure to install your key and
102
- # certificate on each machine.
103
- #
104
- # Keep your private key secret! Keep your private key safe!
105
- #
106
- # To make sure your gems are signed run:
44
+ # Hoe maintains a config file for cross-project values. The file is
45
+ # located at <tt>~/.hoerc</tt>. The file is a YAML formatted config file with
46
+ # the following settings (extended by plugins):
107
47
  #
108
- # rake package; tar tf pkg/yourproject-1.2.3.gem
48
+ # exclude:: A regular expression of files to exclude from +check_manifest+.
109
49
  #
110
- # If your gem is signed you will see:
50
+ # Run <tt>`rake config_hoe`</tt> and see ~/.hoerc for examples.
111
51
  #
112
- # data.tar.gz
113
- # data.tar.gz.sig
114
- # metadata.gz
115
- # metadata.gz.sig
52
+ # == Extending Hoe
116
53
  #
117
- # === Platform awareness
54
+ # Hoe can be extended via its plugin system. Hoe searches out all
55
+ # installed files matching <tt>'hoe/*.rb'</tt> and loads them. Those files are
56
+ # expected to define a module matching the file name. The module must
57
+ # define a define task method and can optionally define an initialize
58
+ # method. Both methods must be named to match the file. eg
118
59
  #
119
- # Hoe allows bundling of pre-compiled extensions in the +package+ task.
120
- #
121
- # To create a package for your current platform:
122
- #
123
- # rake package INLINE=1
124
- #
125
- # This will force Hoe analize your +Inline+ already compiled
126
- # extensions and include them in your gem.
127
- #
128
- # If somehow you need to force a specific platform:
129
- #
130
- # rake package INLINE=1 FORCE_PLATFORM=mswin32
131
- #
132
- # This will set the +Gem::Specification+ platform to the one indicated in
133
- # +FORCE_PLATFORM+ (instead of default Gem::Platform::CURRENT)
60
+ # module Hoe::Blah
61
+ # def initialize_blah # optional
62
+ # # ...
63
+ # end
134
64
  #
65
+ # def define_blah_tasks
66
+ # # ...
67
+ # end
68
+ # end
135
69
 
136
70
  class Hoe
137
- VERSION = '1.12.2'
138
- GEMURL = URI.parse 'http://gems.rubyforge.org' # for namespace :deps below
139
-
140
- ruby_prefix = Config::CONFIG['prefix']
141
- sitelibdir = Config::CONFIG['sitelibdir']
142
-
143
- ##
144
- # Configuration for the supported test frameworks for test task.
145
-
146
- SUPPORTED_TEST_FRAMEWORKS = {
147
- :testunit => "test/unit",
148
- :minitest => "minitest/autorun",
149
- }
71
+ # duh
72
+ VERSION = '2.0.0'
150
73
 
151
74
  ##
152
75
  # Used to add extra flags to RUBY_FLAGS.
@@ -162,62 +85,36 @@ class Hoe
162
85
  RUBY_FLAGS = ENV['RUBY_FLAGS'] || default_ruby_flags
163
86
 
164
87
  ##
165
- # Used to add flags to test_unit (e.g., -n test_borked).
166
- #
167
- # eg FILTER="-n test_blah"
168
-
169
- FILTER = ENV['FILTER'] || ENV['TESTOPTS']
88
+ # Default configuration values for .hoerc. Plugins should populate
89
+ # this on load.
170
90
 
171
- # :stopdoc:
91
+ DEFAULT_CONFIG = {
92
+ "exclude" => /tmp$|CVS|\.svn|\.log$/,
93
+ }
172
94
 
173
- DLEXT = Config::CONFIG['DLEXT']
95
+ ##
96
+ # True if you're a masochist developer. Used for building commands.
174
97
 
175
98
  WINDOZE = /mswin|mingw/ =~ RUBY_PLATFORM unless defined? WINDOZE
176
99
 
177
- DIFF = if WINDOZE
178
- 'diff.exe'
179
- else
180
- if system("gdiff", __FILE__, __FILE__)
181
- 'gdiff' # solaris and kin suck
182
- else
183
- 'diff'
184
- end
185
- end unless defined? DIFF
186
-
187
- # :startdoc:
188
-
189
100
  ##
190
101
  # *MANDATORY*: The author(s) of the package. (can be array)
191
102
 
192
103
  attr_accessor :author
193
104
 
194
- ##
195
- # Populated automatically from the manifest. List of executables.
196
-
197
- attr_accessor :bin_files # :nodoc:
198
-
199
- ##
200
- # *Optional*: An array of the project's blog categories. Defaults to project name.
201
-
202
- attr_accessor :blog_categories
203
-
204
105
  ##
205
106
  # Optional: A description of the release's latest changes. Auto-populates.
206
107
 
207
108
  attr_accessor :changes
208
109
 
209
- ##
210
- # Optional: An array of file patterns to delete on clean.
211
-
212
- attr_accessor :clean_globs
213
-
214
110
  ##
215
111
  # Optional: A description of the project. Auto-populates.
216
112
 
217
113
  attr_accessor :description
218
114
 
219
115
  ##
220
- # Optional: What sections from the readme to use for auto-description. Defaults to %w(description).
116
+ # Optional: What sections from the readme to use for
117
+ # auto-description. Defaults to %w(description).
221
118
 
222
119
  attr_accessor :description_sections
223
120
 
@@ -243,46 +140,16 @@ class Hoe
243
140
 
244
141
  attr_accessor :extra_rdoc_files
245
142
 
246
- ##
247
- # Optional: flay threshold to determine threshold failure. [default: 1200-100]
248
-
249
- attr_accessor :flay_threshold
250
-
251
- ##
252
- # Optional: flog threshold to determine threshold failure. [default: 1500-200]
253
-
254
- attr_accessor :flog_threshold
255
-
256
143
  ##
257
144
  # Optional: The filename for the project history. [default: History.txt]
258
145
 
259
146
  attr_accessor :history_file
260
147
 
261
- ##
262
- # Populated automatically from the manifest. List of library files.
263
-
264
- attr_accessor :lib_files # :nodoc:
265
-
266
- ##
267
- # Optional: Array of incompatible versions for multiruby filtering. Used as a regex.
268
-
269
- attr_accessor :multiruby_skip
270
-
271
148
  ##
272
149
  # *MANDATORY*: The name of the release.
273
150
 
274
151
  attr_accessor :name
275
152
 
276
- ##
277
- # Optional: Should package create a tarball? [default: true]
278
-
279
- attr_accessor :need_tar
280
-
281
- ##
282
- # Optional: Should package create a zipfile? [default: false]
283
-
284
- attr_accessor :need_zip
285
-
286
153
  ##
287
154
  # Optional: A post-install message to be displayed when gem is installed.
288
155
 
@@ -293,26 +160,6 @@ class Hoe
293
160
 
294
161
  attr_accessor :readme_file
295
162
 
296
- ##
297
- # Optional: Name of RDoc destination directory on Rubyforge. [default: +name+]
298
-
299
- attr_accessor :remote_rdoc_dir
300
-
301
- ##
302
- # Optional: RSpec dirs. [default: %w(spec lib)]
303
-
304
- attr_accessor :rspec_dirs
305
-
306
- ##
307
- # Optional: RSpec options. [default: []]
308
-
309
- attr_accessor :rspec_options
310
-
311
- ##
312
- # Optional: Flags for RDoc rsync. [default: "-av --delete"]
313
-
314
- attr_accessor :rsync_args
315
-
316
163
  ##
317
164
  # Optional: The name of the rubyforge project. [default: name.downcase]
318
165
 
@@ -338,21 +185,11 @@ class Hoe
338
185
 
339
186
  attr_accessor :summary_sentences
340
187
 
341
- ##
342
- # Populated automatically from the manifest. List of tests.
343
-
344
- attr_accessor :test_files # :nodoc:
345
-
346
188
  ##
347
189
  # Optional: An array of test file patterns [default: test/**/test_*.rb]
348
190
 
349
191
  attr_accessor :test_globs
350
192
 
351
- ##
352
- # Optional: What test library to require [default: :testunit]
353
-
354
- attr_accessor :testlib
355
-
356
193
  ##
357
194
  # Optional: The url(s) of the project. (can be array). Auto-populates.
358
195
 
@@ -364,16 +201,41 @@ class Hoe
364
201
  attr_accessor :version
365
202
 
366
203
  ##
367
- # Add extra dirs to both $: and RUBY_FLAGS (for test runs)
204
+ # Add extra dirs to both $: and RUBY_FLAGS (for test runs and rakefile deps)
368
205
 
369
206
  def self.add_include_dirs(*dirs)
370
207
  dirs = dirs.flatten
371
208
  $:.unshift(*dirs)
372
209
  s = File::PATH_SEPARATOR
373
- Hoe::RUBY_FLAGS.sub!(/-I/, "-I#{dirs.join(s)}#{s}")
210
+ RUBY_FLAGS.sub!(/-I/, "-I#{dirs.join(s)}#{s}")
211
+ end
212
+
213
+ ##
214
+ # Find and load all plugin files.
215
+ #
216
+ # It is called at the end of hoe.rb
217
+
218
+ def self.load_plugins
219
+ loaded = {}
220
+
221
+ Gem.find_files("hoe/*.rb").each do |plugin|
222
+ name = File.basename plugin
223
+ next if loaded[name]
224
+ begin
225
+ load plugin
226
+ loaded[name] = true
227
+ rescue LoadError => e
228
+ warn "error loading #{plugin.inspect}: #{e.message}. skipping..."
229
+ end
230
+ end
374
231
  end
375
232
 
376
- def self.normalize_names project
233
+ ##
234
+ # Normalize a project name into the project, file, and klass cases (?!?).
235
+ #
236
+ # no, I have no idea how to describe this. Does the thing with the stuff.
237
+
238
+ def self.normalize_names project # :nodoc:
377
239
  project = project.tr('-', '_').gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')
378
240
  klass = project.gsub(/(?:^|_)([a-z])/) { $1.upcase }
379
241
  file_name = project
@@ -381,98 +243,50 @@ class Hoe
381
243
  return project, file_name, klass
382
244
  end
383
245
 
384
- def normalize_deps deps
385
- Array(deps).map { |o| String === o ? [o] : o }
386
- end
246
+ ##
247
+ # Activate a plugin.
387
248
 
388
- def missing name
389
- warn "** #{name} is missing or in the wrong format for auto-intuiting."
390
- warn " run `sow blah` and look at its text files"
249
+ def self.plugin name
250
+ self.plugins << name
391
251
  end
392
252
 
393
- def timebomb n, m, finis = '2010-04-01', start = '2009-03-14'
394
- finis = Time.parse finis
395
- start = Time.parse start
396
- rest = (finis - Time.now)
397
- full = (finis - start)
253
+ ##
254
+ # Return the list of activated plugins.
398
255
 
399
- ((n - m) * rest / full).to_i + m
256
+ def self.plugins
257
+ @@plugins ||= []
400
258
  end
401
259
 
402
- def initialize(name, version) # :nodoc:
403
- self.name = name
404
- self.version = version
405
-
406
- # Defaults
407
- self.author = []
408
- self.blog_categories = [name]
409
- self.clean_globs = %w(diff diff.txt email.txt ri deps .source_index
410
- *.gem **/*~ **/.*~ **/*.rbc coverage*)
411
- self.description_sections = %w(description)
412
- self.email = []
413
- self.extra_deps = []
414
- self.extra_dev_deps = []
415
- self.extra_rdoc_files = []
416
- self.flay_threshold = timebomb 1200, 100 # 80% of average :(
417
- self.flog_threshold = timebomb 1500, 1000 # 80% of average :(
418
- self.history_file = "History.txt"
419
- self.multiruby_skip = []
420
- self.need_tar = true
421
- self.need_zip = false
422
- self.post_install_message = nil
423
- self.readme_file = "README.txt"
424
- self.remote_rdoc_dir = name
425
- self.rspec_dirs = %w(spec lib)
426
- self.rspec_options = []
427
- self.rsync_args = '-av --delete'
428
- self.rubyforge_name = name.downcase
429
- self.spec_extras = {}
430
- self.summary_sentences = 1
431
- self.test_globs = ['test/**/test_*.rb']
432
- self.testlib = :testunit
433
-
434
- yield self if block_given?
260
+ ##
261
+ # Create a new hoe-specification executing the supplied block
435
262
 
436
- # Intuit values:
263
+ def self.spec name, &block
264
+ spec = self.new name
265
+ spec.activate_plugins
266
+ spec.instance_eval(&block)
267
+ spec.post_initialize
268
+ spec # TODO: remove?
269
+ end
437
270
 
438
- readme = File.read(readme_file).split(/^(=+ .*)$/)[1..-1] rescue ''
439
- unless readme.empty? then
440
- sections = readme.map { |s|
441
- s =~ /^=/ ? s.strip.downcase.chomp(':').split.last : s.strip
442
- }
443
- sections = Hash[*sections]
444
- desc = sections.values_at(*description_sections).join("\n\n")
445
- summ = desc.split(/\.\s+/).first(summary_sentences).join(". ")
271
+ ##
272
+ # Activate plugin modules and add them to the current instance.
446
273
 
447
- self.description ||= desc
448
- self.summary ||= summ
449
- self.url ||= readme[1].gsub(/^\* /, '').split(/\n/).grep(/\S+/)
450
- else
451
- missing readme_file
274
+ def activate_plugins
275
+ self.class.constants.reject { |n| n =~ /^[A-Z_]+$/ }.each do |name|
276
+ self.extend Hoe.const_get(name)
452
277
  end
453
278
 
454
- self.changes ||= begin
455
- h = File.read(history_file)
456
- h.split(/^(===.*)/)[1..2].join.strip
457
- rescue
458
- missing history_file
459
- ''
460
- end
461
-
462
- %w(email author).each do |field|
463
- value = self.send(field)
464
- if value.nil? or value.empty? then
465
- if Time.now < Time.local(2008, 4, 1) then
466
- warn "Hoe #{field} value not set - Fix by 2008-04-01!"
467
- self.send "#{field}=", "doofus"
468
- else
469
- abort "Hoe #{field} value not set. aborting"
470
- end
471
- end
279
+ self.class.plugins.each do |plugin|
280
+ send "initialize_#{plugin}" rescue nil
472
281
  end
282
+ end
283
+
284
+ ##
285
+ # Add standard and user defined dependencies to the spec.
473
286
 
287
+ def add_dependencies
474
288
  hoe_deps = {
475
- 'rake' => ">= #{RAKEVERSION}",
289
+ 'rake' => ">= #{RAKEVERSION}",
476
290
  'rubyforge' => ">= #{::RubyForge::VERSION}",
477
291
  }
478
292
 
@@ -486,143 +300,37 @@ class Hoe
486
300
  else
487
301
  extra_dev_deps << ['hoe', ">= #{VERSION}"] unless hoe_deps.has_key? name
488
302
  end
489
-
490
- define_tasks
491
303
  end
492
304
 
493
- def developer name, email
494
- self.author << name
495
- self.email << email
496
- end
497
-
498
- def with_config # :nodoc:
499
- rc = File.expand_path("~/.hoerc")
500
- exists = File.exist? rc
501
- config = exists ? YAML.load_file(rc) : {}
502
- yield(config, rc)
503
- end
504
-
505
- def define_tasks # :nodoc:
506
- default_tasks = []
507
-
508
- if File.directory? "test" then
509
- desc 'Run the test suite. Use FILTER or TESTOPTS to add flags/args.'
510
- task :test do
511
- ruby make_test_cmd
512
- end
513
-
514
- desc 'Run the test suite using multiruby.'
515
- task :multi do
516
- ruby make_test_cmd(:multi)
517
- end
518
-
519
- desc 'Show which test files fail when run alone.'
520
- task :test_deps do
521
- tests = Dir["test/**/test_*.rb"] + Dir["test/**/*_test.rb"]
522
-
523
- paths = ['bin', 'lib', 'test'].join(File::PATH_SEPARATOR)
524
- null_dev = WINDOZE ? '> NUL 2>&1' : '&> /dev/null'
525
-
526
- tests.each do |test|
527
- if not system "ruby -I#{paths} #{test} #{null_dev}" then
528
- puts "Dependency Issues: #{test}"
529
- end
530
- end
531
- end
532
-
533
- default_tasks << :test
534
- end
535
-
536
- if File.directory? "spec" then
537
- begin
538
- require 'spec/rake/spectask'
539
-
540
- desc "Run all specifications"
541
- Spec::Rake::SpecTask.new(:spec) do |t|
542
- t.libs = self.rspec_dirs
543
- t.spec_opts = self.rspec_options
544
- end
545
- rescue LoadError
546
- # do nothing
547
- end
548
- default_tasks << :spec
549
- end
550
-
551
- desc 'Run the default task(s).'
552
- task :default => default_tasks
553
-
554
- begin # take a whack at defining rcov tasks
555
- require 'rcov/rcovtask'
556
-
557
- Rcov::RcovTask.new do |t|
558
- pattern = ENV['PATTERN'] || 'test/test_*.rb'
559
-
560
- t.test_files = FileList[pattern]
561
- t.verbose = true
562
- t.rcov_opts << "--no-color"
563
- t.rcov_opts << "--save coverage.info"
564
- t.rcov_opts << "-x ^/"
565
- end
566
-
567
- # this is for my emacs rcov overlay stuff on emacswiki.
568
- task :rcov_overlay do
569
- path = ENV["FILE"]
570
- rcov, eol = Marshal.load(File.read("coverage.info")).last[path], 1
571
- puts rcov[:lines].zip(rcov[:coverage]).map { |line, coverage|
572
- bol, eol = eol, eol + line.length
573
- [bol, eol, "#ffcccc"] unless coverage
574
- }.compact.inspect
575
- end
576
- rescue LoadError
577
- # skip
578
- end
579
-
580
- begin
581
- require 'flay'
582
- require 'flay_task'
583
- FlayTask.new :flay, self.flay_threshold
584
- rescue LoadError
585
- # skip
586
- end
587
-
588
- begin
589
- require 'flog'
590
- require 'flog_task'
591
- FlogTask.new :flog, self.flog_threshold
592
- rescue LoadError
593
- # skip
594
- end
595
-
596
- ############################################################
597
- # Packaging and Installing
598
-
599
- signing_key = nil
600
- cert_chain = []
305
+ ##
306
+ # Define the Gem::Specification.
601
307
 
602
- with_config do |config, path|
603
- break unless config['signing_key_file'] and config['signing_cert_file']
604
- key_file = File.expand_path config['signing_key_file'].to_s
605
- signing_key = key_file if File.exist? key_file
308
+ def define_spec
309
+ self.spec = Gem::Specification.new do |s|
310
+ dirs = Dir['{lib,ext}']
606
311
 
607
- cert_file = File.expand_path config['signing_cert_file'].to_s
608
- cert_chain << cert_file if File.exist? cert_file
609
- end
312
+ s.name = name
313
+ s.version = version if version
314
+ s.summary = summary
315
+ s.email = email
316
+ s.homepage = Array(url).first
317
+ s.rubyforge_project = rubyforge_name
318
+ s.description = description
319
+ s.files = File.read("Manifest.txt").split(/\r?\n\r?/)
320
+ s.executables = s.files.grep(/^bin/) { |f| File.basename(f) }
321
+ s.bindir = "bin"
322
+ s.require_paths = dirs unless dirs.empty?
323
+ s.rdoc_options = ['--main', readme_file]
324
+ s.has_rdoc = true
325
+ s.post_install_message = post_install_message
326
+ s.test_files = Dir[*self.test_globs]
610
327
 
611
- self.spec = Gem::Specification.new do |s|
612
- s.name = name
613
- s.version = version
614
- s.summary = summary
615
328
  case author
616
329
  when Array
617
330
  s.authors = author
618
331
  else
619
- s.author = author
332
+ s.author = author
620
333
  end
621
- s.email = email
622
- s.homepage = Array(url).first
623
- s.rubyforge_project = rubyforge_name
624
-
625
- s.description = description
626
334
 
627
335
  extra_deps.each do |dep|
628
336
  s.add_dependency(*dep)
@@ -632,67 +340,9 @@ class Hoe
632
340
  s.add_development_dependency(*dep)
633
341
  end
634
342
 
635
- s.files = File.read("Manifest.txt").delete("\r").split(/\n/)
636
- s.executables = s.files.grep(/^bin/) { |f| File.basename(f) }
637
-
638
- s.bindir = "bin"
639
- dirs = Dir['{lib,ext}']
640
- s.require_paths = dirs unless dirs.empty?
641
-
642
- s.rdoc_options = ['--main', readme_file]
643
-
644
343
  s.extra_rdoc_files += s.files.grep(/txt$/)
645
344
  s.extra_rdoc_files.reject! { |f| f =~ %r%^(test|spec|vendor|template|data|tmp)/% }
646
345
  s.extra_rdoc_files += @extra_rdoc_files
647
- s.has_rdoc = true
648
-
649
- s.post_install_message = post_install_message
650
-
651
- if test ?f, "test/test_all.rb" then
652
- s.test_file = "test/test_all.rb"
653
- else
654
- s.test_files = Dir[*self.test_globs]
655
- end
656
-
657
- if signing_key and cert_chain then
658
- s.signing_key = signing_key
659
- s.cert_chain = cert_chain
660
- end
661
-
662
- ############################################################
663
- # Allow automatic inclusion of compiled extensions
664
- if ENV['INLINE'] then
665
- s.platform = ENV['FORCE_PLATFORM'] || Gem::Platform::CURRENT
666
-
667
- # Try collecting Inline extensions for +name+
668
- if defined?(Inline) then
669
- directory 'lib/inline'
670
-
671
- Inline.registered_inline_classes.each do |cls|
672
- name = cls.name # TODO: what about X::Y::Z?
673
- # name of the extension is CamelCase
674
- alternate_name = if name =~ /[A-Z]/ then
675
- name.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')
676
- elsif name =~ /_/ then
677
- name.capitalize.gsub(/_([a-z])/) { $1.upcase }
678
- end
679
-
680
- extensions = Dir.chdir(Inline::directory) {
681
- Dir["Inline_{#{name},#{alternate_name}}_*.#{DLEXT}"]
682
- }
683
-
684
- extensions.each do |ext|
685
- # add the inlined extension to the spec files
686
- s.files += ["lib/inline/#{ext}"]
687
-
688
- # include the file in the tasks
689
- file "lib/inline/#{ext}" => ["lib/inline"] do
690
- cp File.join(Inline::directory, ext), "lib/inline"
691
- end
692
- end
693
- end
694
- end
695
- end
696
346
 
697
347
  # Do any extra stuff the user wants
698
348
  spec_extras.each do |msg, val|
@@ -705,448 +355,116 @@ class Hoe
705
355
  end
706
356
  end
707
357
 
708
- desc 'Show information about the gem.'
709
- task :debug_gem do
710
- puts spec.to_ruby
711
- end
712
-
713
- self.lib_files = spec.files.grep(/^(lib|ext)/)
714
- self.bin_files = spec.files.grep(/^bin/)
715
- self.test_files = spec.files.grep(/^test/)
716
-
717
- Rake::GemPackageTask.new spec do |pkg|
718
- pkg.need_tar = @need_tar
719
- pkg.need_zip = @need_zip
720
- end
721
-
722
- desc 'Install the package as a gem.'
723
- task :install_gem => [:clean, :package, :check_extra_deps] do
724
- install_gem Dir['pkg/*.gem'].first
725
- end
726
-
727
- desc 'Package and upload the release to rubyforge.'
728
- task :release => [:clean, :package] do |t|
729
- v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
730
- abort "Versions don't match #{v} vs #{version}" if v != version
731
- pkg = "pkg/#{name}-#{version}"
732
-
733
- if $DEBUG then
734
- puts "release_id = rf.add_release #{rubyforge_name.inspect}, #{name.inspect}, #{version.inspect}, \"#{pkg}.tgz\""
735
- puts "rf.add_file #{rubyforge_name.inspect}, #{name.inspect}, release_id, \"#{pkg}.gem\""
736
- end
737
-
738
- rf = RubyForge.new.configure
739
- puts "Logging in"
740
- rf.login
741
-
742
- c = rf.userconfig
743
- c["release_notes"] = description if description
744
- c["release_changes"] = changes if changes
745
- c["preformatted"] = true
746
-
747
- files = [(@need_tar ? "#{pkg}.tgz" : nil),
748
- (@need_zip ? "#{pkg}.zip" : nil),
749
- "#{pkg}.gem"].compact
750
-
751
- puts "Releasing #{name} v. #{version}"
752
- rf.add_release rubyforge_name, name, version, *files
753
- end
754
-
755
- ############################################################
756
- # Doco
757
-
758
- Rake::RDocTask.new(:docs) do |rd|
759
- rd.main = readme_file
760
- rd.options << '-d' if (`which dot` =~ /\/dot/) unless
761
- ENV['NODOT'] || WINDOZE
762
- rd.rdoc_dir = 'doc'
763
-
764
- rd.rdoc_files += spec.require_paths
765
- rd.rdoc_files += spec.extra_rdoc_files
766
-
767
- title = "#{name}-#{version} Documentation"
768
- title = "#{rubyforge_name}'s " + title if rubyforge_name != name
769
-
770
- rd.options << "-t" << title
771
- end
772
-
773
- desc 'Generate ri locally for testing.'
774
- task :ridocs => :clean do
775
- sh %q{ rdoc --ri -o ri . }
776
- end
777
-
778
- desc 'Publish RDoc to RubyForge.'
779
- task :publish_docs => [:clean, :docs] do
780
- config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
781
- host = "#{config["username"]}@rubyforge.org"
782
-
783
- remote_dir = "/var/www/gforge-projects/#{rubyforge_name}/#{remote_rdoc_dir}"
784
- local_dir = 'doc'
785
-
786
- sh %{rsync #{rsync_args} #{local_dir}/ #{host}:#{remote_dir}}
787
- end
788
-
789
- # no doco for this one
790
- task :publish_on_announce do
791
- with_config do |config, _|
792
- Rake::Task['publish_docs'].invoke if config["publish_on_announce"]
793
- end
794
- end
795
-
796
- ############################################################
797
- # Dependencies:
798
-
799
- namespace :deps do
800
- require 'zlib' # HACK for rubygems 1.3.0
801
- require 'rubygems/remote_fetcher'
802
-
803
- @@index = nil
804
-
805
- def self.get_source_index
806
- return @@index if @@index
807
-
808
- dump = unless File.exist? '.source_index' then
809
- url = GEMURL + "Marshal.#{Gem.marshal_version}.Z"
810
- dump = Gem::RemoteFetcher.fetcher.fetch_path url
811
- dump = Gem.inflate dump
812
- open '.source_index', 'wb' do |io| io.write dump end
813
- dump
814
- else
815
- open '.source_index', 'rb' do |io| io.read end
816
- end
817
-
818
- @@index = Marshal.load dump
819
- end
820
-
821
- def self.get_latest_gems
822
- @@cache ||= get_source_index.latest_specs
823
- end
824
-
825
- def self.get_gems_by_name
826
- @@by_name ||= Hash[*get_latest_gems.map { |gem|
827
- [gem.name, gem, gem.full_name, gem]
828
- }.flatten]
829
- end
830
-
831
- def self.dependent_upon name
832
- get_latest_gems.find_all { |gem|
833
- gem.dependencies.any? { |dep| dep.name == name }
834
- }
835
- end
836
-
837
-
838
- desc "List all the dependent gems of this gem"
839
- task :list do
840
- gems = self.get_gems_by_name
841
- gem = gems[self.name]
842
-
843
- abort "Couldn't find gem: #{self.name}" unless gem
844
-
845
- deps = self.dependent_upon self.name
846
- max = deps.map { |s| s.full_name.size }.max
847
-
848
- puts " dependents:"
849
- unless deps.empty? then
850
- deps.sort_by { |spec| spec.full_name }.each do |spec|
851
- vers = spec.dependencies.find {|s| s.name == name }.requirement_list
852
- puts " %-*s - %s" % [max, spec.full_name, vers.join(", ")]
853
- end
854
- else
855
- puts " none"
856
- end
857
- end
858
-
859
- desc "Print a contact list for gems dependent on this gem"
860
- task :email do
861
- gems = self.get_gems_by_name
862
- gem = gems[self.name]
863
-
864
- abort "Couldn't find gem: #{self.name}" unless gem
865
-
866
- deps = self.dependent_upon self.name
867
-
868
- email = deps.map { |s| s.email }.flatten.sort.uniq
869
- email = email.map { |s| s.split(/,\s*/) }.flatten.sort.uniq
870
-
871
- email.map! { |s| # don't you people realize how easy this is?
872
- s.gsub(/ at | _at_ |\s*(atmark|@nospam@|-at?-|@at?@|<at?>|\[at?\]|\(at?\))\s*/i, '@').gsub(/\s*(dot|\[d(ot)?\]|\.dot\.)\s*/i, '.').gsub(/\s+com$/, '.com')
873
- }
874
-
875
- bad, good = email.partition { |e| e !~ /^[\w.+-]+\@[\w.+-]+$/ }
876
-
877
- warn "Rejecting #{bad.size} email. I couldn't unmunge them." unless
878
- bad.empty?
879
-
880
- puts good.join(", ")
881
- end
882
-
883
- desc "Fetch all the dependent gems of this gem into tarballs"
884
- task :fetch do
885
- gems = self.get_gems_by_name
886
- gem = gems[self.name]
887
- deps = self.dependent_upon self.name
888
-
889
- mkdir "deps" unless File.directory? "deps"
890
- Dir.chdir "deps" do
891
- begin
892
- deps.sort_by { |spec| spec.full_name }.each do |spec|
893
- full_name = spec.full_name
894
- tgz_name = "#{full_name}.tgz"
895
- gem_name = "#{full_name}.gem"
896
-
897
- next if File.exist? tgz_name
898
- FileUtils.rm_rf [full_name, gem_name]
899
-
900
- begin
901
- warn "downloading #{full_name}"
902
- Gem::RemoteFetcher.fetcher.download(spec, GEMURL, Dir.pwd)
903
- FileUtils.mv "cache/#{gem_name}", '.'
904
- rescue Gem::RemoteFetcher::FetchError
905
- warn " failed"
906
- next
907
- end
908
-
909
- warn "converting #{gem_name} to tarball"
910
-
911
- system "gem unpack #{gem_name} 2> /dev/null"
912
- system "gem spec -l #{gem_name} > #{full_name}/gemspec.rb"
913
- system "tar zmcf #{tgz_name} #{full_name}"
914
- FileUtils.rm_rf [full_name, gem_name, "cache"]
915
- end
916
- ensure
917
- FileUtils.rm_rf "cache"
918
- end
919
- end
920
- end
921
- end
922
-
923
- ############################################################
924
- # Misc/Maintenance:
925
-
926
- desc 'Run ZenTest against the package.'
927
- task :audit do
928
- libs = %w(lib test ext).join(File::PATH_SEPARATOR)
929
- sh "zentest -I=#{libs} #{spec.files.grep(/^(lib|test)/).join(' ')}"
930
- end
931
-
932
- task :clobber_rcov # in case rcov didn't load
358
+ unless self.version then
359
+ version = nil
933
360
 
934
- desc 'Clean up all the extras.'
935
- task :clean => [ :clobber_docs, :clobber_package, :clobber_rcov ] do
936
- clean_globs.each do |pattern|
937
- files = Dir[pattern]
938
- rm_rf files, :verbose => true unless files.empty?
361
+ spec.files.each do |file|
362
+ next unless File.exist? file
363
+ version = File.read(file)[/VERSION = ([\"\'])([\d\.]+)\1/, 2]
364
+ break if version
939
365
  end
940
- end
941
366
 
942
- desc 'Install missing dependencies.'
943
- task :check_extra_deps do
944
- # extra_deps = [["rubyforge", ">= 1.0.0"], ["rake", ">= 0.8.1"]]
945
- extra_deps.each do |dep|
946
- begin
947
- gem(*dep)
948
- rescue Gem::LoadError
949
- install_gem(*dep)
950
- end
951
- end
367
+ spec.version = self.version = version
952
368
  end
953
369
 
954
- desc 'Create a fresh ~/.hoerc file.'
955
- task :config_hoe do
956
- with_config do |config, path|
957
- default_config = {
958
- "exclude" => /tmp$|CVS|\.svn|\.log$/,
959
- "publish_on_announce" => false,
960
- "signing_key_file" => "~/.gem/gem-private_key.pem",
961
- "signing_cert_file" => "~/.gem/gem-public_cert.pem",
962
- "blogs" => [
963
- {
964
- "user" => "user",
965
- "password" => "password",
966
- "url" => "url",
967
- "blog_id" => "blog_id",
968
- "extra_headers" => {
969
- "mt_convert_breaks" => "markdown"
970
- },
971
- }
972
- ],
973
- }
974
- File.open(path, "w") do |f|
975
- YAML.dump(default_config.merge(config), f)
976
- end
977
-
978
- editor = ENV['EDITOR'] || 'vi'
979
- system "#{editor} #{path}" if ENV['SHOW_EDITOR'] != 'no'
980
- end
981
- end
370
+ raise "Need version" unless self.version
371
+ end
982
372
 
983
- desc 'Generate email announcement file.'
984
- task :email do
985
- require 'rubyforge'
986
- subject, title, body, urls = announcement
987
-
988
- File.open("email.txt", "w") do |mail|
989
- mail.puts "Subject: [ANN] #{subject}"
990
- mail.puts
991
- mail.puts title
992
- mail.puts
993
- mail.puts urls
994
- mail.puts
995
- mail.puts body
996
- mail.puts
997
- mail.puts urls
998
- end
999
- puts "Created email.txt"
1000
- end
373
+ ##
374
+ # Convenience method to set add to both the author and email fields.
1001
375
 
1002
- desc 'Post announcement to blog.'
1003
- task :post_blog do
1004
- require 'xmlrpc/client'
376
+ def developer name, email
377
+ self.author << name
378
+ self.email << email
379
+ end
1005
380
 
1006
- with_config do |config, path|
1007
- break unless config['blogs']
381
+ ##
382
+ # Create a newly initialized hoe spec. If a block is given, yield on
383
+ # it and finish post_initialize steps. This is deprecated behavior
384
+ # and should be switched from Hoe.new to Hoe.spec.
1008
385
 
1009
- subject, title, body, urls = announcement
1010
- body += "\n\n#{urls}"
386
+ def initialize name, version = nil # :nodoc:
387
+ self.name = name
388
+ self.version = version
1011
389
 
1012
- config['blogs'].each do |site|
1013
- server = XMLRPC::Client.new2(site['url'])
1014
- content = site['extra_headers'].merge(:title => title,
1015
- :description => body,
1016
- :categories => blog_categories)
390
+ self.author = []
391
+ self.changes = nil
392
+ self.description = nil
393
+ self.description_sections = %w(description)
394
+ self.email = []
395
+ self.extra_deps = []
396
+ self.extra_dev_deps = []
397
+ self.extra_rdoc_files = []
398
+ self.history_file = "History.txt"
399
+ self.post_install_message = nil
400
+ self.readme_file = "README.txt"
401
+ self.rubyforge_name = name.downcase
402
+ self.spec = nil
403
+ self.spec_extras = {}
404
+ self.summary = nil
405
+ self.summary_sentences = 1
406
+ self.test_globs = ['test/**/test_*.rb']
407
+ self.url = nil
1017
408
 
1018
- result = server.call('metaWeblog.newPost',
1019
- site['blog_id'],
1020
- site['user'],
1021
- site['password'],
1022
- content,
1023
- true)
1024
- end
1025
- end
409
+ if block_given? then
410
+ warn "Hoe.new {...} deprecated. Switch to Hoe.spec."
411
+ self.activate_plugins
412
+ yield self
413
+ post_initialize
1026
414
  end
415
+ end
1027
416
 
1028
- desc 'Post announcement to rubyforge.'
1029
- task :post_news do
1030
- require 'rubyforge'
1031
- subject, title, body, urls = announcement
417
+ ##
418
+ # Intuit values from the readme and history files.
1032
419
 
1033
- rf = RubyForge.new.configure
1034
- rf.login
1035
- rf.post_news(rubyforge_name, subject, "#{title}\n\n#{body}")
1036
- puts "Posted to rubyforge"
1037
- end
420
+ def intuit_values
421
+ readme = File.read(readme_file).split(/^(=+ .*)$/)[1..-1] rescue ''
422
+ unless readme.empty? then
423
+ sections = readme.map { |s|
424
+ s =~ /^=/ ? s.strip.downcase.chomp(':').split.last : s.strip
425
+ }
426
+ sections = Hash[*sections]
427
+ desc = sections.values_at(*description_sections).join("\n\n")
428
+ summ = desc.split(/\.\s+/).first(summary_sentences).join(". ")
1038
429
 
1039
- desc 'Create news email file and post to rubyforge.'
1040
- task :announce => [:email, :post_news, :post_blog, :publish_on_announce ]
1041
-
1042
- desc 'Verify the manifest.'
1043
- task :check_manifest => :clean do
1044
- f = "Manifest.tmp"
1045
- require 'find'
1046
- files = []
1047
- with_config do |config, _|
1048
- exclusions = config["exclude"]
1049
- abort "exclude entry missing from .hoerc. Aborting." if exclusions.nil?
1050
- Find.find '.' do |path|
1051
- next unless File.file? path
1052
- next if path =~ exclusions
1053
- files << path[2..-1]
1054
- end
1055
- files = files.sort.join "\n"
1056
- File.open f, 'w' do |fp| fp.puts files end
1057
- system "#{DIFF} -du Manifest.txt #{f}"
1058
- rm f
1059
- end
430
+ self.description ||= desc
431
+ self.summary ||= summ
432
+ self.url ||= readme[1].gsub(/^\* /, '').split(/\n/).grep(/\S+/)
433
+ else
434
+ missing readme_file
1060
435
  end
1061
436
 
1062
- desc 'Generate a key for signing your gems.'
1063
- task :generate_key do
1064
- email = Array(spec.email)
1065
- abort "No email in your gemspec" if email.nil? or email.empty?
1066
-
1067
- key_file = with_config { |config, _| config['signing_key_file'] }
1068
- cert_file = with_config { |config, _| config['signing_cert_file'] }
1069
-
1070
- if key_file.nil? or cert_file.nil? then
1071
- ENV['SHOW_EDITOR'] ||= 'no'
1072
- Rake::Task['config_hoe'].invoke
1073
-
1074
- key_file = with_config { |config, _| config['signing_key_file'] }
1075
- cert_file = with_config { |config, _| config['signing_cert_file'] }
1076
- end
1077
-
1078
- key_file = File.expand_path key_file
1079
- cert_file = File.expand_path cert_file
1080
-
1081
- unless File.exist? key_file or File.exist? cert_file then
1082
- warn "NOTICE: using #{email.first} for certificate" if email.size > 1
1083
-
1084
- sh "gem cert --build #{email.first}"
1085
- mv "gem-private_key.pem", key_file, :verbose => true
1086
- mv "gem-public_cert.pem", cert_file, :verbose => true
1087
-
1088
- puts "Installed key and certificate."
1089
-
1090
- rf = RubyForge.new.configure
1091
- rf.login
1092
-
1093
- cert_package = "#{rubyforge_name}-certificates"
1094
-
1095
- begin
1096
- rf.lookup 'package', cert_package
1097
- rescue
1098
- rf.create_package rubyforge_name, cert_package
1099
- end
437
+ self.changes ||= begin
438
+ h = File.read(history_file)
439
+ h.split(/^(===.*)/)[1..2].join.strip
440
+ rescue
441
+ missing history_file
442
+ ''
443
+ end
444
+ end
1100
445
 
1101
- begin
1102
- rf.lookup('release', cert_package)['certificates']
1103
- rf.add_file rubyforge_name, cert_package, 'certificates', cert_file
1104
- rescue
1105
- rf.create_package rubyforge_name, cert_package
1106
- rf.add_release rubyforge_name, cert_package, 'certificates', cert_file
1107
- end
446
+ ##
447
+ # Load activated plugins by calling their define tasks method.
1108
448
 
1109
- puts "Uploaded certificate to release \"certificates\" in package #{cert_package}"
1110
- else
1111
- puts "Keys already exist: #{key_file} and #{cert_file}"
1112
- end
449
+ def load_plugin_tasks
450
+ self.class.plugins.each do |plugin|
451
+ send "define_#{plugin}_tasks"
1113
452
  end
1114
- end # end define
1115
-
1116
- def install_gem name, version = nil
1117
- gem_cmd = Gem.default_exec_format % 'gem'
1118
- sudo = 'sudo ' unless WINDOZE
1119
- local = '--local' unless version
1120
- version = "--version '#{version}'" if version
1121
- sh "#{sudo}#{gem_cmd} install #{local} #{name} #{version}"
1122
453
  end
1123
454
 
1124
- def make_test_cmd multi = false # :nodoc:
1125
- framework = SUPPORTED_TEST_FRAMEWORKS[testlib]
1126
- raise "unsupported test framework #{testlib}" unless framework
1127
-
1128
- tests = ["rubygems", framework] +
1129
- test_globs.map { |g| Dir.glob(g) }.flatten
1130
- tests.map! {|f| %(require "#{f}")}
1131
-
1132
- cmd = "#{RUBY_FLAGS} -e '#{tests.join("; ")}' #{FILTER}"
1133
-
1134
- if multi then
1135
- ENV['EXCLUDED_VERSIONS'] = multiruby_skip.join ":"
1136
- cmd = "-S multiruby #{cmd}"
1137
- end
455
+ ##
456
+ # Bitch about a file that is missing data or unparsable for intuiting values.
1138
457
 
1139
- cmd
458
+ def missing name
459
+ warn "** #{name} is missing or in the wrong format for auto-intuiting."
460
+ warn " run `sow blah` and look at its text files"
1140
461
  end
1141
462
 
1142
- def announcement # :nodoc:
1143
- changes = self.changes.rdoc_to_markdown
1144
- subject = "#{name} #{version} Released"
1145
- title = "#{name} version #{version} has been released!"
1146
- body = "#{description}\n\nChanges:\n\n#{changes}".rdoc_to_markdown
1147
- urls = Array(url).map { |s| "* <#{s.strip.rdoc_to_markdown}>" }.join("\n")
463
+ ##
464
+ # Normalize the dependencies.
1148
465
 
1149
- return subject, title, body, urls
466
+ def normalize_deps deps
467
+ Array(deps).map { |o| String === o ? [o] : o }
1150
468
  end
1151
469
 
1152
470
  ##
@@ -1155,75 +473,60 @@ class Hoe
1155
473
  # changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
1156
474
  # summary, *description = p.paragraphs_of('README.txt', 3, 3..8)
1157
475
 
1158
- def paragraphs_of(path, *paragraphs)
476
+ def paragraphs_of path, *paragraphs
1159
477
  File.read(path).delete("\r").split(/\n\n+/).values_at(*paragraphs)
1160
478
  end
1161
- end
1162
479
 
1163
- module Rake
1164
- module TaskManager
1165
- ##
1166
- # This gives us access to the tasks already defined in rake.
1167
- def all_tasks
1168
- @tasks
1169
- end
480
+ ##
481
+ # Tell the world you're a pluggable package (ie you require rubygems 1.3.1+)
482
+
483
+ def pluggable!
484
+ abort "update rubygems to >= 1.3.1" unless Gem.respond_to? :find_files
485
+ spec_extras[:required_rubygems_version] = '>= 1.3.1'
1170
486
  end
1171
487
 
1172
488
  ##
1173
- # Simple shortcut for Rake.application.all_tasks
1174
- def self.all_tasks
1175
- Rake.application.all_tasks
489
+ # Finalize configuration
490
+
491
+ def post_initialize
492
+ intuit_values
493
+ validate_fields
494
+ add_dependencies
495
+ define_spec
496
+ load_plugin_tasks
1176
497
  end
1177
498
 
1178
499
  ##
1179
- # Hooks into rake and allows us to clear out a task by name or
1180
- # regexp. Use this if you want to completely override a task instead
1181
- # of extend it.
1182
- def self.clear_tasks(*tasks)
1183
- tasks.flatten.each do |name|
1184
- case name
1185
- when Regexp then
1186
- all_tasks.delete_if { |k,_| k =~ name }
1187
- else
1188
- all_tasks.delete(name)
1189
- end
1190
- end
500
+ # Provide a linear degrading value from n to m over start to finis dates.
501
+
502
+ def timebomb n, m, finis = '2010-04-01', start = '2009-03-14'
503
+ finis = Time.parse finis
504
+ start = Time.parse start
505
+ rest = (finis - Time.now)
506
+ full = (finis - start)
507
+
508
+ ((n - m) * rest / full).to_i + m
1191
509
  end
1192
510
 
1193
511
  ##
1194
- # Removes the last action added to a task. Use this when two
1195
- # libraries define the same task and you only want one of the
1196
- # actions.
1197
- #
1198
- # require 'hoe'
1199
- # require 'tasks/rails'
1200
- # Rake.undo("test") # rolls out rails' test task
1201
- def self.undo(*names)
1202
- names.each do |name|
1203
- all_tasks[name].actions.delete_at(-1)
512
+ # Verify that mandatory fields are set.
513
+
514
+ def validate_fields
515
+ %w(email author).each do |field|
516
+ value = self.send(field)
517
+ abort "Hoe #{field} value not set. aborting" if value.nil? or value.empty?
1204
518
  end
1205
519
  end
1206
- end
1207
-
1208
- # :enddoc:
1209
520
 
1210
- class ::Rake::SshDirPublisher # :nodoc:
1211
- attr_reader :host, :remote_dir, :local_dir
1212
- end
521
+ ##
522
+ # Load or create a default config and yield it
1213
523
 
1214
- class String
1215
- def rdoc_to_markdown
1216
- self.gsub(/^mailto:/, '').gsub(/^(=+)/) { "#" * $1.size }
524
+ def with_config # :nodoc:
525
+ rc = File.expand_path("~/.hoerc")
526
+ exists = File.exist? rc
527
+ config = exists ? YAML.load_file(rc) : {}
528
+ yield(config, rc)
1217
529
  end
1218
- end
1219
530
 
1220
- if $0 == __FILE__ then
1221
- out = `rake -T | egrep -v "redocs|repackage|clobber|trunk"`
1222
- if ARGV.empty? then
1223
- # # default:: Run the default tasks.
1224
- puts out.gsub(/(\s*)\#/, '::\1').gsub(/^rake /, '# ')
1225
- else
1226
- # * default - Run the default tasks.
1227
- puts out.gsub(/\#/, '-').gsub(/^rake /, '* ')
1228
- end
531
+ Hoe.load_plugins
1229
532
  end