class Hoe

def self.add_include_dirs(*dirs)

def self.add_include_dirs(*dirs)
  dirs = dirs.flatten
  include_dirs.concat dirs
  $:.unshift(*dirs)
  s = File::PATH_SEPARATOR
  RUBY_FLAGS.sub!(/-I/, "-I#{dirs.join(s)}#{s}")
end

def self.bad_plugins

def self.bad_plugins
  @bad_plugins
end

def self.load_plugins plugins = Hoe.plugins

def self.load_plugins plugins = Hoe.plugins
  @found  ||= {}
  @loaded ||= {}
  @files  ||= Gem.find_files "hoe/*.rb"
  @files.reverse.each do |path| # reverse so first one wins
    @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.message}. skipping..."
    end
  }.any?
  bad_plugins = plugins - @loaded.keys
  bad_plugins.each do |bad_plugin|
    plugins.delete bad_plugin
  end
  @bad_plugins.concat bad_plugins
  @bad_plugins.uniq!
  return @loaded, @found
end

def self.normalize_names project # :nodoc:

:nodoc:
def self.normalize_names project # :nodoc:
  project    = project.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, "")
  klass      = project.gsub(/(?:^|_)([a-z])/) { $1.upcase }
  klass      = klass.  gsub(/(?:^|-)([a-z])/) { "::#{$1.upcase}" }
  test_klass = klass.  gsub(/(^|::)([A-Z])/) { "#{$1}Test#{$2}" }
  file_name  = project.gsub(/-/, "/")
  return project, file_name, klass, test_klass
end

def self.plugin *plugins

def self.plugin *plugins
  self.plugins.concat plugins
  self.plugins.uniq!
end

def self.plugins

def self.plugins
  @@plugins
end

def self.spec name, &block

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

def activate_plugin_deps

def activate_plugin_deps
  Hoe.plugins.each do |plugin|
    msg = "activate_#{plugin}_deps"
    warn msg if $DEBUG
    send msg if self.respond_to? msg
  end
end

def activate_plugins

def activate_plugins
  with_config do |config, _|
    config_plugins = config["plugins"]
    break unless config_plugins
    Hoe.plugins.concat config_plugins.map(&:intern)
  end
  Hoe.load_plugins Hoe.plugins
  names = Hoe.constants.map(&: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
  initialize_plugins
end

def add_dependencies

def add_dependencies
  self.extra_deps     = normalize_deps extra_deps
  self.extra_dev_deps = normalize_deps extra_dev_deps
  case name
  when "hoe" then
    # do nothing? these deps are already in the hoe spec in the Rakefile
  else
    version = VERSION.split(/\./).first(2).join(".")
    dependency "hoe", "~> #{version}", :development
  end
  seen = {}
  extra_deps.each do |dep|
    next if seen[dep.first]
    seen[dep.first] = true
    spec.add_dependency(*dep)
  end
  extra_dev_deps.each do |dep|
    next if seen[dep.first]
    seen[dep.first] = true
    spec.add_development_dependency(*dep)
  end
end

def check_for_version # :nodoc:

:nodoc:
def check_for_version # :nodoc:
  return if self.version
  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] rescue nil
    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

def define_spec

def define_spec
  self.spec = Gem::Specification.new do |s|
    dirs = Dir["lib"]
    manifest = read_manifest
    abort [
           "Manifest is missing or couldn't be read.",
           "The Manifest is kind of a big deal.",
           "Maybe you're using a gem packaged by a linux project.",
           "It seems like they enjoy breaking other people's code.",
           ].join "\n" unless manifest
    s.name                 = name
    s.version              = version if version
    s.summary              = summary
    s.email                = email
    s.homepage             = homepage || urls["home"] || urls.values.first
    s.description          = description
    s.files                = manifest
    s.bindir               = bindir || "bin"
    s.executables          = s.files.grep(/^#{s.bindir}/) { |f| File.basename(f) }
    s.require_paths        = dirs unless dirs.empty?
    s.rdoc_options         = ["--main", readme_file]
    s.post_install_message = post_install_message
    s.metadata             = (urls.keys & URLS_TO_META_MAP.keys).map { |name|
      [URLS_TO_META_MAP[name], urls[name]]
    }.to_h if urls
    missing "Manifest.txt" if s.files.empty?
    case author
    when Array
      s.authors = author
    else
      s.author  = author
    end
    s.extra_rdoc_files += s.files.grep(/\.(txt|rdoc|md)$/)
    s.extra_rdoc_files.reject! { |f| f =~ %r%^(test|spec|vendor|template|data|tmp)/% }
    s.extra_rdoc_files += @extra_rdoc_files
  end
  check_for_version
  if licenses.empty?
    warn "Defaulting gemspec to MIT license."
    warn "Call license in hoe spec to change."
    license "MIT"
  end
  spec.licenses = licenses
  run_spec_extras
end

def dependency name, version, type = :runtime

def dependency name, version, type = :runtime
  raise "Unknown dependency type: #{type}" unless
    [:runtime, :dev, :development, :developer].include? type
  ary = if type == :runtime then
          extra_deps
        else
          extra_dev_deps
        end
  ary << [name, version]
end

def dependency_target

def dependency_target
  self.name == "hoe" ? extra_deps : extra_dev_deps
end

def developer name, email

def developer name, email
  self.author << name
  self.email  << email
end

def have_gem? name

def have_gem? name
  Gem::Specification.find_by_name name.to_s
rescue Gem::LoadError
  false
end

def initialize name, version = nil # :nodoc:

:nodoc:
def initialize name, version = nil # :nodoc:
  self.name                 = name
  self.version              = version
  self.author               = []
  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.licenses             = []
  self.post_install_message = nil
  self.group_name           = name.downcase
  self.spec                 = nil
  self.spec_extras          = {}
  self.summary              = nil
  self.summary_sentences    = 1
  self.test_globs           = ["test/**/{test,spec}_*.rb",
                               "test/**/*_{test,spec}.rb"]
  manifest = read_manifest
  if manifest then
    self.readme_file  = manifest.grep(/^README\./).first
    self.history_file = manifest.grep(/^History\./).first
  end
  self.history_file ||= Dir.glob("History.{rdoc,txt,md}").first || "History.txt"
  self.readme_file  ||= Dir.glob("README.{rdoc,txt,md}").first || "README.txt"
  abort "Hoe.new {...} removed. Switch to Hoe.spec." if block_given?
end

def initialize_plugins

def initialize_plugins
  Hoe.plugins.each do |plugin|
    msg = "initialize_#{plugin}"
    warn msg if $DEBUG
    send msg if self.respond_to? msg
  end
end

def intuit_values input

def intuit_values input
  readme = input
             .lines
             .chunk { |l| l[/^(?:=+|#+)/] || "" }
             .map(&:last)
             .each_slice(2)
             .to_h { |k, v|
               raise "No body for %p section" % [k[0].strip] \
                 unless v
               kp = k.map { |s|
                 s.strip.chomp(":").sub(/(?:=+|#+)\s*/, '').downcase
               }.join("\n")
               [kp, v.join.strip]
             }
  unless readme.empty? then
    desc     = readme.values_at(*description_sections).join("\n\n")
    summ     = desc.split(/\.\s+/).first(summary_sentences).join(". ")
    self.urls        ||= parse_urls(readme.values.first)
    self.description ||= desc
    self.summary     ||= summ
  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

def license name


Call it multiple times if you are releasing under multiple licenses.
Specify a license for your gem.
#
def license name
  self.licenses << name.to_s
end

def load_plugin_tasks

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
      warn "warning: couldn't activate the #{plugin} plugin, skipping"
      bad << plugin
      next
    end
    (Rake::Task.tasks - old_tasks).each do |task|
      task.plugin = plugin
    end
  end
  @@plugins -= bad
end

def maybe_load_yaml path # :nodoc:

:nodoc:
def maybe_load_yaml path # :nodoc:
  if File.exist? path then
    if YAML.respond_to? :safe_load_file then
      YAML.safe_load_file path, permitted_classes: [Regexp, Symbol]
    else
      YAML.load_file path
    end
  else
    {}
  end
end

def missing name

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

def normalize_deps deps

def normalize_deps deps
  deps = Array(deps)
  deps.each do |o|
    abort "ERROR: Add '~> x.y' to the '#{o}' dependency." if String === o
  end
  deps
end

def paragraphs_of path, *paragraphs

def paragraphs_of path, *paragraphs
  File.read_utf(path).delete("\r").split(/\n\n+/).values_at(*paragraphs)
end

def parse_urls text

def parse_urls text
  lines = text.gsub(/^\* /, "").delete("<>").split(/\n/).grep(/\S+/)
  if lines.first =~ /::/ then
    Hash[lines.map { |line| line.split(/\s*::\s*/) }]
  else
    raise "Please switch readme to hash format for urls."
  end
end

def pluggable!

def pluggable!
  abort "update rubygems to >= 1.3.1" unless  Gem.respond_to? :find_files
  require_rubygems_version ">= 1.3.1"
end

def plugin? name

def plugin? name
  self.class.plugins.include? name
end

def post_initialize

def post_initialize
  activate_plugin_deps
  unless skip_intuit_values?
    intuit_values File.read_utf readme_file if readme_file
  end
  validate_fields
  define_spec
  load_plugin_tasks
  add_dependencies
end

def read_manifest

def read_manifest
  File.read_utf("Manifest.txt").split(/\r?\n\r?/) rescue nil
end

def require_ruby_version *versions

def require_ruby_version *versions
  spec_extras[:required_ruby_version] = versions
end

def require_rubygems_version *versions

def require_rubygems_version *versions
  spec_extras[:required_rubygems_version] = versions
end

def ruby20!

def ruby20!
  require_ruby_version "~> 2.0"
end

def ruby21!

def ruby21!
  require_ruby_version "~> 2.1"
end

def ruby22!

def ruby22!
  require_ruby_version "~> 2.2"
end

def ruby23!

def ruby23!
  require_ruby_version "~> 2.3"
end

def run_spec_extras # :nodoc:

:nodoc:
def run_spec_extras # :nodoc:
  # Do any extra stuff the user wants
  self.spec_extras.each do |msg, val|
    case val
    when Proc
      val.call spec.send(msg)
    else
      spec.send "#{msg}=", val
    end
  end
end

def skip_intuit_values? # :nodoc:

:nodoc:
def skip_intuit_values? # :nodoc:
  %w[summary description homepage].all? { |field| send field }
end

def timebomb n, m, finis = nil, start = nil

def timebomb n, m, finis = nil, start = nil
  require "time"
  finis = Time.parse(finis || "#{Time.now.year}-12-31")
  start = Time.parse(start || "#{Time.now.year}-01-01")
  rest  = (finis - Time.now)
  full  = (finis - start)
  [((n - m) * rest / full).to_i + m, m].max
end

def validate_fields

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

def with_config

def with_config
  config = Hoe::DEFAULT_CONFIG
  rc = File.expand_path("~/.hoerc")
  homeconfig = maybe_load_yaml rc
  config = config.merge homeconfig
  localrc = File.join Dir.pwd, ".hoerc"
  localconfig = maybe_load_yaml(localrc)
  config = config.merge localconfig
  yield config, rc
end