Class: Hoe
- Inherits:
-
Object
- Object
- Hoe
- Includes:
- Rake::DSL
- Defined in:
- lib/hoe.rb
Overview
Hoe is a simple rake/rubygems helper for project Rakefiles. It helps generate rubygems and includes a dynamic plug-in system allowing for easy extensibility. Hoe ships with plug-ins for all your usual project tasks including rdoc generation, testing, packaging, and deployment.
Using Hoe
Basics
Sow generates a new project from scratch. Sow uses a simple ERB templating system allowing you to capture patterns common to your projects. Run `sow` and then see ~/.hoe_template for more info:
% sow project_name
...
% cd project_name
and have at it.
Extra Configuration Options:
Hoe maintains a config file for cross-project values. The file is located at ~/.hoerc. The file is a YAML formatted config file with the following settings (extended by plugins):
exclude |
A regular expression of files to exclude from check_manifest. |
Run `rake config_hoe` and see ~/.hoerc for examples.
Extending Hoe
Hoe can be extended via its plugin system. Hoe searches out all installed files matching 'hoe/*.rb' and loads them. Those files are expected to define a module matching the file name. The module must define a define task method and can optionally define an initialize method. Both methods must be named to match the file. eg
module Hoe::Blah
def initialize_blah # optional
# ...
end
def define_blah_tasks
# ...
end
end
Defined Under Namespace
Modules: Clean, Compiler, Debug, Deps, Flay, Flog, GemPreludeSucks, Gemcutter, Inline, Newb, Package, Publish, RCov, Racc, RubyForge, Signing, Test
Constant Summary
- VERSION =
duh
'2.9.4'- RUBY_DEBUG =
Used to add extra flags to RUBY_FLAGS.
ENV['RUBY_DEBUG']
- RUBY_FLAGS =
Used to specify flags to ruby [has smart default].
ENV['RUBY_FLAGS'] || default_ruby_flags
- DEFAULT_CONFIG =
Default configuration values for .hoerc. Plugins should populate this on load.
{ "exclude" => /tmp$|CVS|\.svn|\.log$/, }
- WINDOZE =
/mswin|mingw/ =~ RUBY_PLATFORM
- @@plugins =
[:clean, :debug, :deps, :flay, :flog, :newb, :package, :publish, :rcov, :gemcutter, :signing, :test]
Instance Attribute Summary (collapse)
-
- (Object) author
MANDATORY: The author(s) of the package.
-
- (Object) changes
Optional: A description of the release's latest changes.
-
- (Object) description
Optional: A description of the project.
-
- (Object) description_sections
Optional: What sections from the readme to use for auto-description.
-
- (Object) email
MANDATORY: The author's email address(es).
-
- (Object) extra_deps
Optional: An array of rubygem dependencies.
-
- (Object) extra_dev_deps
Optional: An array of rubygem developer dependencies.
-
- (Object) extra_rdoc_files
Optional: Extra files you want to add to RDoc.
-
- (Object) history_file
Optional: The filename for the project history.
-
- (Object) name
MANDATORY: The name of the release.
-
- (Object) post_install_message
Optional: A post-install message to be displayed when gem is installed.
-
- (Object) readme_file
Optional: The filename for the project readme.
-
- (Object) rubyforge_name
Optional: The name of the rubyforge project.
-
- (Object) spec
The Gem::Specification.
-
- (Object) spec_extras
Optional: A hash of extra values to set in the gemspec.
-
- (Object) summary
Optional: A short summary of the project.
-
- (Object) summary_sentences
Optional: Number of sentences from description for summary.
-
- (Object) test_globs
Optional: An array of test file patterns [default: test/*/test_.rb].
-
- (Object) url
Optional: The url(s) of the project.
-
- (Object) version
MANDATORY: The version.
Class Method Summary (collapse)
-
+ (Object) add_include_dirs(*dirs)
Add extra dirs to both $: and RUBY_FLAGS (for test runs and rakefile deps).
-
+ (Object) load_plugins(plugins = Hoe.plugins)
Find and load all plugin files.
-
+ (Object) normalize_names(project)
Normalize a project name into the project, file, and klass cases (?!?).
-
+ (Object) plugin(*plugins)
Activates plugins.
-
+ (Object) plugins
The list of active plugins.
-
+ (Object) spec(name, &block)
Execute the Hoe DSL to define your project's Hoe specification (which interally creates a gem specification).
Instance Method Summary (collapse)
-
- (Object) activate_plugins
Activate plugin modules and add them to the current instance.
-
- (Object) add_dependencies
Add standard and user defined dependencies to the spec.
-
- (Object) define_spec
Define the Gem::Specification.
-
- (Object) dependency(name, version, type = :runtime)
Add a dependency declaration to your spec.
-
- (Object) dependency_target
Returns the proper dependency list for the thingy.
-
- (Object) developer(name, email)
Convenience method to set add to both the author and email fields.
-
- (Hoe) initialize(name, version = nil)
constructor
Create a newly initialized hoe spec.
-
- (Object) intuit_values
Intuit values from the readme and history files.
-
- (Object) load_plugin_tasks
Load activated plugins by calling their define tasks method.
-
- (Object) missing(name)
Bitch about a file that is missing data or unparsable for intuiting values.
-
- (Object) normalize_deps(deps)
Normalize the dependencies.
-
- (Object) paragraphs_of(path, *paragraphs)
Reads a file at path and spits out an array of the paragraphs specified.
-
- (Object) pluggable!
Tell the world you're a pluggable package (ie you require rubygems 1.3.1+).
-
- (Boolean) plugin?(name)
Is a plugin activated? Used for guarding missing plugins in your hoe spec:.
-
- (Object) post_initialize
Finalize configuration.
-
- (Object) require_ruby_version(version)
Declare that your gem requires a specific ruby version.
-
- (Object) require_rubygems_version(version)
Declare that your gem requires a specific rubygems version.
-
- (Object) timebomb(n, m, finis = '2010-04-01', start = '2009-03-14')
Provide a linear degrading value from n to m over start to finis dates.
-
- (Object) validate_fields
Verify that mandatory fields are set.
-
- (Object) with_config {|config, rc| ... }
Loads ~/.hoerc and yields the configuration and its path.
Constructor Details
- (Hoe) initialize(name, version = nil)
Create a newly initialized hoe spec. If a block is given, yield on it and finish post_initialize steps. This is deprecated behavior and should be switched from Hoe.new to Hoe.spec.
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/hoe.rb', line 472 def initialize name, version = nil # :nodoc: self.name = name self.version = version self. = [] self.changes = nil self.description = nil self.description_sections = %w(description) self.email = [] self.extra_deps = [] self.extra_dev_deps = [] self.extra_rdoc_files = [] self.history_file = "History.txt" self. = nil self.readme_file = "README.txt" self.rubyforge_name = name.downcase self.spec = nil self.spec_extras = {} self.summary = nil self.summary_sentences = 1 self.test_globs = ['test/**/test_*.rb'] self.url = nil if block_given? then warn "Hoe.new {...} deprecated. Switch to Hoe.spec." Hoe.load_plugins self.activate_plugins yield self post_initialize end end |
Instance Attribute Details
- (Object) author
MANDATORY: The author(s) of the package. (can be array)
Use the #developer method to fill in both author and email cleanly.
106 107 108 |
# File 'lib/hoe.rb', line 106 def @author end |
- (Object) changes
Optional: A description of the release's latest changes. Auto-populates to the top entry of History.txt.
112 113 114 |
# File 'lib/hoe.rb', line 112 def changes @changes end |
- (Object) description
Optional: A description of the project. Auto-populates from the first paragraph of the DESCRIPTION section of README.txt.
See also: Hoe#summary and Hoe.paragraphs_of.
120 121 122 |
# File 'lib/hoe.rb', line 120 def description @description end |
- (Object) description_sections
Optional: What sections from the readme to use for auto-description. Defaults to %w(description).
126 127 128 |
# File 'lib/hoe.rb', line 126 def description_sections @description_sections end |
- (Object) email
MANDATORY: The author's email address(es). (can be array)
Use the #developer method to fill in both author and email cleanly.
133 134 135 |
# File 'lib/hoe.rb', line 133 def email @email end |
- (Object) extra_deps
Optional: An array of rubygem dependencies.
extra_deps << ['blah', '~> 1.0']
140 141 142 |
# File 'lib/hoe.rb', line 140 def extra_deps @extra_deps end |
- (Object) extra_dev_deps
Optional: An array of rubygem developer dependencies.
145 146 147 |
# File 'lib/hoe.rb', line 145 def extra_dev_deps @extra_dev_deps end |
- (Object) extra_rdoc_files
Optional: Extra files you want to add to RDoc.
.txt files are automatically included (excluding the obvious).
152 153 154 |
# File 'lib/hoe.rb', line 152 def extra_rdoc_files @extra_rdoc_files end |
- (Object) history_file
Optional: The filename for the project history. [default: History.txt]
157 158 159 |
# File 'lib/hoe.rb', line 157 def history_file @history_file end |
- (Object) name
MANDATORY: The name of the release.
Set via Hoe.spec.
164 165 166 |
# File 'lib/hoe.rb', line 164 def name @name end |
- (Object) post_install_message
Optional: A post-install message to be displayed when gem is installed.
169 170 171 |
# File 'lib/hoe.rb', line 169 def @post_install_message end |
- (Object) readme_file
Optional: The filename for the project readme. [default: README.txt]
174 175 176 |
# File 'lib/hoe.rb', line 174 def readme_file @readme_file end |
- (Object) rubyforge_name
Optional: The name of the rubyforge project. [default: name.downcase]
179 180 181 |
# File 'lib/hoe.rb', line 179 def rubyforge_name @rubyforge_name end |
- (Object) spec
The Gem::Specification.
184 185 186 |
# File 'lib/hoe.rb', line 184 def spec @spec end |
- (Object) spec_extras
Optional: A hash of extra values to set in the gemspec. Value may be a proc.
spec_extras[:required_rubygems_version] = '>= 1.3.2'
(tho, see #pluggable! if that's all you want to do)
193 194 195 |
# File 'lib/hoe.rb', line 193 def spec_extras @spec_extras end |
- (Object) summary
Optional: A short summary of the project. Auto-populates from the first sentence of the description.
See also: Hoe#description and Hoe.paragraphs_of.
201 202 203 |
# File 'lib/hoe.rb', line 201 def summary @summary end |
- (Object) summary_sentences
Optional: Number of sentences from description for summary. Defaults to 1.
206 207 208 |
# File 'lib/hoe.rb', line 206 def summary_sentences @summary_sentences end |
- (Object) test_globs
Optional: An array of test file patterns [default: test/*/test_.rb]
211 212 213 |
# File 'lib/hoe.rb', line 211 def test_globs @test_globs end |
- (Object) url
Optional: The url(s) of the project. (can be array). Auto-populates to a list of urls read from the beginning of README.txt.
218 219 220 |
# File 'lib/hoe.rb', line 218 def url @url end |
- (Object) version
MANDATORY: The version. Don't hardcode! use a constant in the project.
223 224 225 |
# File 'lib/hoe.rb', line 223 def version @version end |
Class Method Details
+ (Object) add_include_dirs(*dirs)
Add extra dirs to both $: and RUBY_FLAGS (for test runs and rakefile deps)
228 229 230 231 232 233 |
# File 'lib/hoe.rb', line 228 def self.add_include_dirs(*dirs) dirs = dirs.flatten $:.unshift(*dirs) s = File::PATH_SEPARATOR RUBY_FLAGS.sub!(/-I/, "-I#{dirs.join(s)}#{s}") end |
+ (Object) load_plugins(plugins = Hoe.plugins)
Find and load all plugin files.
It is called at the end of hoe.rb
240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/hoe.rb', line 240 def self.load_plugins plugins = Hoe.plugins @found ||= {} @loaded ||= {} @files ||= Gem.find_files "hoe/*.rb" @files.reverse.each do |path| @found[File.basename(path, ".rb").intern] = path end :keep_doing_this while @found.map { |name, plugin| next unless plugins.include? name next if @loaded[name] begin warn "loading #{plugin}" if $DEBUG @loaded[name] = require plugin rescue LoadError => e warn "error loading #{plugin.inspect}: #{e.}. skipping..." end }.any? return @loaded, @found end |
+ (Object) normalize_names(project)
Normalize a project name into the project, file, and klass cases (?!?).
no, I have no idea how to describe this. Does the thing with the stuff.
268 269 270 271 272 273 274 |
# File 'lib/hoe.rb', line 268 def self.normalize_names project # :nodoc: project = project.tr('-', '_').gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '') klass = project.gsub(/(?:^|_)([a-z])/) { $1.upcase } file_name = project return project, file_name, klass end |
+ (Object) plugin(*plugins)
Activates plugins. If a plugin cannot be loaded it will be ignored.
Plugins may also be activated through a plugins array in ~/.hoerc. This should only be used for plugins that aren't critical to your project and plugins that you want to use on other projects.
284 285 286 287 |
# File 'lib/hoe.rb', line 284 def self.plugin *plugins self.plugins.concat plugins self.plugins.uniq! end |
+ (Object) plugins
The list of active plugins.
292 293 294 |
# File 'lib/hoe.rb', line 292 def self.plugins @@plugins end |
+ (Object) spec(name, &block)
Execute the Hoe DSL to define your project's Hoe specification (which interally creates a gem specification). All hoe attributes and methods are available within block. Eg:
Hoe.spec name do
# ... project specific data ...
end
305 306 307 308 309 310 311 312 313 |
# File 'lib/hoe.rb', line 305 def self.spec name, &block Hoe.load_plugins spec = self.new name spec.activate_plugins spec.instance_eval(&block) spec.post_initialize spec # TODO: remove? end |
Instance Method Details
- (Object) activate_plugins
Activate plugin modules and add them to the current instance.
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/hoe.rb', line 318 def activate_plugins with_config do |config, _| config_plugins = config['plugins'] break unless config_plugins Hoe.plugins.concat config_plugins.map { |plugin| plugin.intern } end Hoe.load_plugins Hoe.plugins names = Hoe.constants.map { |s| s.to_s } names.reject! { |n| n =~ /^[A-Z_]+$/ } names.each do |name| next unless Hoe.plugins.include? name.downcase.intern warn "extend #{name}" if $DEBUG self.extend Hoe.const_get(name) end Hoe.plugins.each do |plugin| msg = "initialize_#{plugin}" warn msg if $DEBUG send msg if self.respond_to? msg end end |
- (Object) add_dependencies
Add standard and user defined dependencies to the spec.
362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/hoe.rb', line 362 def add_dependencies self.extra_deps = normalize_deps extra_deps self.extra_dev_deps = normalize_deps extra_dev_deps case name when 'hoe' then extra_deps << ['rake', ">= #{RAKEVERSION}"] when 'rubyforge', 'rake', 'gemcutter' then # avoid circular dependencies for hoe's (potentially) hoe'd dependencies else extra_dev_deps << ['hoe', ">= #{VERSION}"] end end |
- (Object) define_spec
Define the Gem::Specification.
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 |
# File 'lib/hoe.rb', line 386 def define_spec self.spec = Gem::Specification.new do |s| dirs = Dir['lib'] s.name = name s.version = version if version s.summary = summary s.email = email s.homepage = Array(url).first s.rubyforge_project = rubyforge_name s.description = description s.files = files = File.read_utf("Manifest.txt").split(/\r?\n\r?/) s.executables = s.files.grep(/^bin/) { |f| File.basename(f) } s.bindir = "bin" s.require_paths = dirs unless dirs.empty? s. = ['--main', readme_file] s. = s.test_files = Dir[*self.test_globs] missing "Manifest.txt" if files.empty? case when Array s. = else s. = end extra_deps.each do |dep| s.add_dependency(*dep) end extra_dev_deps.each do |dep| s.add_development_dependency(*dep) end s.extra_rdoc_files += s.files.grep(/txt$/) s.extra_rdoc_files.reject! { |f| f =~ %r%^(test|spec|vendor|template|data|tmp)/% } s.extra_rdoc_files += @extra_rdoc_files end unless self.version then version = nil version_re = /VERSION += +([\"\'])([\d][\w\.]+)\1/ spec.files.each do |file| next unless File.exist? file version = File.read_utf(file)[version_re, 2] break if version end spec.version = self.version = version if version unless self.version then spec.version = self.version = "0.borked" warn "** Add 'VERSION = \"x.y.z\"' to your code," warn " add a version to your hoe spec," warn " or fix your Manifest.txt" end end # Do any extra stuff the user wants spec_extras.each do |msg, val| case val when Proc val.call spec.send(msg) else spec.send "#{msg}=", val end end end |
- (Object) dependency(name, version, type = :runtime)
Add a dependency declaration to your spec. Pass :dev to type for developer dependencies.
347 348 349 350 351 352 353 354 355 356 357 |
# File 'lib/hoe.rb', line 347 def dependency name, version, type = :runtime ary = case type when :runtime then extra_deps when :dev, :development, :developer then extra_dev_deps else raise "Unknown dependency type: #{type}" end ary << [name, version] end |
- (Object) dependency_target
Returns the proper dependency list for the thingy.
379 380 381 |
# File 'lib/hoe.rb', line 379 def dependency_target self.name == 'hoe' ? extra_deps : extra_dev_deps end |
- (Object) developer(name, email)
Convenience method to set add to both the author and email fields.
462 463 464 465 |
# File 'lib/hoe.rb', line 462 def developer name, email self. << name self.email << email end |
- (Object) intuit_values
Intuit values from the readme and history files.
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 |
# File 'lib/hoe.rb', line 507 def intuit_values header_re = /^((?:=+|#+) .*)$/ readme = File.read_utf(readme_file).split(header_re)[1..-1] rescue '' unless readme.empty? then sections = Hash[*readme.map { |s| s =~ /^[=#]/ ? s.strip.downcase.chomp(':').split.last : s.strip }] desc = sections.values_at(*description_sections).join("\n\n") summ = desc.split(/\.\s+/).first(summary_sentences).join(". ") self.description ||= desc self.summary ||= summ self.url ||= readme[1].gsub(/^\* /, '').split(/\n/).grep(/\S+/) else missing readme_file end self.changes ||= begin h = File.read_utf(history_file) h.split(/^(={2,}|\#{2,})/)[1..2].join.strip rescue missing history_file '' end end |
- (Object) load_plugin_tasks
Load activated plugins by calling their define tasks method.
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 |
# File 'lib/hoe.rb', line 537 def load_plugin_tasks bad = [] $plugin_max = self.class.plugins.map { |s| s.to_s.size }.max self.class.plugins.each do |plugin| warn "define: #{plugin}" if $DEBUG old_tasks = Rake::Task.tasks.dup begin send "define_#{plugin}_tasks" rescue NoMethodError => e warn "warning: couldn't activate the #{plugin} plugin, skipping" if Rake.application..trace or $DEBUG bad << plugin next end (Rake::Task.tasks - old_tasks).each do |task| task.plugin = plugin end end @@plugins -= bad end |
- (Object) missing(name)
Bitch about a file that is missing data or unparsable for intuiting values.
567 568 569 570 |
# File 'lib/hoe.rb', line 567 def missing name warn "** #{name} is missing or in the wrong format for auto-intuiting." warn " run `sow blah` and look at its text files" end |
- (Object) normalize_deps(deps)
Normalize the dependencies.
575 576 577 578 579 580 581 582 583 584 |
# File 'lib/hoe.rb', line 575 def normalize_deps deps Array(deps).map { |o| if String === o then warn "WAR\NING: HOE DEPRECATION: Add '>= 0' to the '#{o}' dependency." [o, ">= 0"] else o end } end |
- (Object) paragraphs_of(path, *paragraphs)
Reads a file at path and spits out an array of the paragraphs specified.
changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
summary, *description = p.paragraphs_of('README.txt', 3, 3..8)
592 593 594 |
# File 'lib/hoe.rb', line 592 def paragraphs_of path, *paragraphs File.read_utf(path).delete("\r").split(/\n\n+/).values_at(*paragraphs) end |
- (Object) pluggable!
Tell the world you're a pluggable package (ie you require rubygems 1.3.1+)
This uses require_rubygems_version. Last one wins. Make sure you account for that.
602 603 604 605 |
# File 'lib/hoe.rb', line 602 def pluggable! abort "update rubygems to >= 1.3.1" unless Gem.respond_to? :find_files require_rubygems_version '>= 1.3.1' end |
- (Boolean) plugin?(name)
Is a plugin activated? Used for guarding missing plugins in your hoe spec:
Hoe.spec "blah" do
if plugin? :enhancement then
self.enhancement = true # or whatever...
end
end
617 618 619 |
# File 'lib/hoe.rb', line 617 def plugin? name self.class.plugins.include? name end |
- (Object) post_initialize
Finalize configuration
624 625 626 627 628 629 630 |
# File 'lib/hoe.rb', line 624 def post_initialize intuit_values validate_fields add_dependencies define_spec load_plugin_tasks end |
- (Object) require_ruby_version(version)
Declare that your gem requires a specific ruby version. Last one wins.
642 643 644 |
# File 'lib/hoe.rb', line 642 def require_ruby_version version spec_extras[:required_ruby_version] = version end |
- (Object) require_rubygems_version(version)
Declare that your gem requires a specific rubygems version. Last one wins.
635 636 637 |
# File 'lib/hoe.rb', line 635 def require_rubygems_version version spec_extras[:required_rubygems_version] = version end |
- (Object) timebomb(n, m, finis = '2010-04-01', start = '2009-03-14')
Provide a linear degrading value from n to m over start to finis dates.
649 650 651 652 653 654 655 656 657 |
# File 'lib/hoe.rb', line 649 def timebomb n, m, finis = '2010-04-01', start = '2009-03-14' require 'time' finis = Time.parse finis start = Time.parse start rest = (finis - Time.now) full = (finis - start) [((n - m) * rest / full).to_i + m, m].max end |
- (Object) validate_fields
Verify that mandatory fields are set.
662 663 664 665 666 667 |
# File 'lib/hoe.rb', line 662 def validate_fields %w(email author).each do |field| value = self.send(field) abort "Hoe #{field} value not set. aborting" if value.nil? or value.empty? end end |
- (Object) with_config {|config, rc| ... }
Loads ~/.hoerc and yields the configuration and its path
672 673 674 675 676 677 |
# File 'lib/hoe.rb', line 672 def with_config rc = File.("~/.hoerc") exists = File.exist? rc config = exists ? YAML.load_file(rc) : {} yield(config, rc) end |