module Hen::DSL

Some helper methods for use inside of a Hen definition.

Public Instance Methods

config() click to toggle source

The Hen configuration.

# File lib/hen/dsl.rb, line 44
def config
  extend_object(Hen.config.dup) {
    # Always return a duplicate for a value,
    # hence making the configuration immutable
    def [](key)  # :nodoc:
      fetch(key).dup
    rescue IndexError
      {}
    end
  }
end
execute(*commands) click to toggle source

Find a command that is executable and run it. Intended for platform-dependent alternatives (Command A is not available? Then try B instead).

# File lib/hen/dsl.rb, line 76
def execute(*commands)
  if command = File.which_command(commands)
    sh(command) { |ok, res|
      warn "Error while executing command: #{command} " <<
           "(return code #{res.exitstatus})" unless ok
    }
  else
    warn "Command not found: #{commands.join('; ')}"
  end
end
git() { |init_git| ... } click to toggle source

Encapsulates tasks targeting at Git, skipping those if the current project is not controlled by Git. Yields a Git object via init_git.

# File lib/hen/dsl.rb, line 157
def git
  have_git? ? yield(init_git) : skipping('Git')
end
have_task?(t) click to toggle source

Return true if task t is defined, false otherwise.

# File lib/hen/dsl.rb, line 69
def have_task?(t)
  tasks.key?(t.to_s)
end
mangle_files!(*args) click to toggle source

Clean up the file lists in args by removing duplicates and either deleting any files that are not managed by the source code management system (untracked files) or, if the project is not version-controlled or the SCM is not recognized, deleting any files that don't exist.

The return value indicates whether source control is in effect.

Currently supported SCM's (in that order): Git, SVN.

# File lib/hen/dsl.rb, line 96
def mangle_files!(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}

  managed_files = [:git, :svn].find { |scm|
    res = send(scm) { |scm_obj| scm_obj.managed_files }
    break res if res
  } if !options.key?(:managed) || options[:managed]

  args.compact.each { |files|
    files.uniq!

    if managed_files
      files.replace(files & managed_files)
    else
      files.delete_if { |file| !File.readable?(file) }
    end
  }

  !!managed_files
end
map_options(options) click to toggle source

Map options hash to array of command line arguments.

# File lib/hen/dsl.rb, line 131
def map_options(options)
  options.map { |option, value|
    option = '--' << option.to_s.tr('_', '-')

    case value
      when Array  then value.map { |_value| [option, _value] }
      when String then [option, value]
      else value ? option : nil
    end
  }.compact.flatten
end
rubygems(&block) click to toggle source

Encapsulates tasks targeting at RubyGems.org, skipping those if RubyGem's 'push' command is not available. Yields an optional proc to obtain RubyGems (pseudo-)objects from (via call; reaching out to init_rubygems).

# File lib/hen/dsl.rb, line 147
def rubygems(&block)
  if have_rubygems?
    call_block(block) { |*args| init_rubygems }
  else
    skipping 'RubyGems'
  end
end
set_options(object, options, type = object.class) click to toggle source

Set options on object by calling the corresponding setter method for each option; warns about illegal options. Optionally, use type to describe object (defaults to its class).

# File lib/hen/dsl.rb, line 120
def set_options(object, options, type = object.class)
  options.each { |option, value|
    if object.respond_to?(setter = "#{option}=")
      object.send(setter, value)
    else
      warn "Unknown #{type} option: #{option}"
    end
  }
end
svn() { |init_svn| ... } click to toggle source

Encapsulates tasks targeting at SVN, skipping those if the current project is not controlled by SVN. Yields an SVN object via init_svn.

# File lib/hen/dsl.rb, line 163
def svn
  have_svn? ? yield(init_svn) : skipping('SVN')
end
task!(t, *args, &block) click to toggle source

Define task t, but overwrite any existing task of that name! (Rake usually just adds them up.)

# File lib/hen/dsl.rb, line 63
def task!(t, *args, &block)
  tasks.delete(t.to_s)
  task(t, *args, &block)
end
tasks() click to toggle source

Get a handle on the currently defined tasks.

# File lib/hen/dsl.rb, line 57
def tasks
  Rake.application.instance_variable_get(:@tasks)
end

Private Instance Methods

call_block(block, *args, &block2) click to toggle source

Calls block block with args, appending an optional passed block if requested by block.

# File lib/hen/dsl.rb, line 343
def call_block(block, *args, &block2)
  args << block2 if block.arity > args.size
  block[*args]
end
extend_object(object, *blocks, &block2) click to toggle source

Extend object with given blocks.

# File lib/hen/dsl.rb, line 322
def extend_object(object, *blocks, &block2)
  singleton_class = object.singleton_class

  blocks.push(block2).compact.reverse_each { |block|
    singleton_class.class_eval(&block)
  }

  object
end
have_git?() click to toggle source

Checks whether the current project is managed by Git.

# File lib/hen/dsl.rb, line 200
def have_git?
  File.directory?('.git')
end
have_rubygems?() click to toggle source

Loads the RubyGems push command, giving a nicer error message if it's not found.

# File lib/hen/dsl.rb, line 190
def have_rubygems?
  require 'rubygems/command_manager'
  require 'rubygems/commands/push_command'

  Gem::Commands::PushCommand
rescue LoadError, NameError
  missing_lib 'rubygems (gemcutter)'
end
have_svn?() click to toggle source

Checks whether the current project is managed by SVN.

# File lib/hen/dsl.rb, line 205
def have_svn?
  File.directory?('.svn')
end
init_git() click to toggle source

Prepare the use of Git. Returns the Git (pseudo-)object.

# File lib/hen/dsl.rb, line 226
def init_git
  return unless have_git?

  pseudo_object {
    def method_missing(cmd, *args)  # :nodoc:
      options = args.last.is_a?(Hash) ? args.pop : {}
      options[:verbose] = Hen.verbose unless options.key?(:verbose)

      DSL.send(:sh, 'git', cmd.to_s.tr('_', '-'), *args << options)
    end

    def run(cmd, *args)  # :nodoc:
      %x{git #{args.unshift(cmd.to_s.tr('_', '-')).join(' ')}}
    end

    def remote_for_branch(branch = 'master', default = 'origin')  # :nodoc:
      remotes = run(:branch, '-r').scan(%r{(\S+)/#{Regexp.escape(branch)}$})
      remotes.flatten!

      if env_remote = ENV['HEN_REMOTE']
        env_remote if remotes.include?(env_remote)
      else
        remotes.include?(default) ? default : remotes.first
      end
    end

    def url_for_remote(remote = remote_for_branch)  # :nodoc:
      run(:remote, '-v')[%r{^#{Regexp.escape(remote)}\s+(\S+)}, 1] if remote
    end

    def find_remote(regexp, default = 'origin')  # :nodoc:
      remotes = run(:remote, '-v').split($/).grep(regexp)
      remotes.map! { |x| x.split[0..1] }

      if env_remote = ENV['HEN_REMOTE']
        remotes.assoc(env_remote)
      else
        remotes.assoc(default) || remotes.first
      end
    end

    def easy_clone(url, dir = '.', remote = 'origin')  # :nodoc:
      clone '-n', '-o', remote, url, dir
    end

    def local_clone(dir, src = '.')  # :nodoc:
      clone '-n', src, dir
    end

    def checkout_remote_branch(remote, branch = 'master')  # :nodoc:
      checkout '-b', branch, "#{remote}/#{branch}"
    end

    def checkout_fetched_branch(url, branch = 'master')  # :nodoc:
      fetch '--depth', '1', url, branch
      checkout '-b', branch, 'FETCH_HEAD'
    end

    def add_and_commit(msg)  # :nodoc:
      add '.'
      commit '-m', msg
    end

    def managed_files  # :nodoc:
      run(:ls_files).split($/)
    end
  }
end
init_rubygems() click to toggle source

Prepare the use of RubyGems.org. Returns the RubyGems (pseudo-)object.

# File lib/hen/dsl.rb, line 211
def init_rubygems
  return unless have_rubygems?

  pseudo_object {
    def method_missing(cmd, *args)  # :nodoc:
      run(cmd, *args)
    end

    def run(cmd, *args)  # :nodoc:
      Gem::CommandManager.instance.run([cmd.to_s.tr('_', '-'), *args])
    end
  }
end
init_svn() click to toggle source

Prepare the use of SVN. Returns the SVN (pseudo-)object.

# File lib/hen/dsl.rb, line 296
def init_svn
  return unless have_svn?

  pseudo_object {
    def method_missing(cmd, *args)  # :nodoc:
      options = args.last.is_a?(Hash) ? args.pop : {}
      options[:verbose] = Hen.verbose unless options.key?(:verbose)

      DSL.send(:sh, 'svn', cmd.to_s.tr('_', '-'), *args << options)
    end

    def run(cmd, *args)  # :nodoc:
      %x{svn #{args.unshift(cmd.to_s.tr('_', '-')).join(' ')}}
    end

    def version  # :nodoc:
      %x{svnversion}[/\d+/]
    end

    def managed_files  # :nodoc:
      run(:list, '--recursive').split($/)
    end
  }
end
missing_lib(lib, do_warn = $DEBUG) click to toggle source

Warn about missing library lib (if do_warn is true) and return false.

# File lib/hen/dsl.rb, line 176
def missing_lib(lib, do_warn = $DEBUG)
  warn "Please install the `#{lib}' library for additional tasks." if do_warn
  false
end
pseudo_object(&block) click to toggle source

Create a (pseudo-)object.

# File lib/hen/dsl.rb, line 333
def pseudo_object(&block)
  extend_object(Object.new, block) {
    instance_methods.each { |method|
      undef_method(method) unless method =~ /\A__|\Aobject_id\z/
    }
  }
end
require_lib(lib, do_warn = true) click to toggle source
# File lib/hen/dsl.rb, line 181
def require_lib(lib, do_warn = true)
  require lib
  true
rescue LoadError
  missing_lib(lib, do_warn)
end
skipping(name, do_warn = Hen.verbose) click to toggle source

Warn about skipping tasks for name (if do_warn is true) and return nil.

# File lib/hen/dsl.rb, line 170
def skipping(name, do_warn = Hen.verbose)
  warn "Skipping #{name} tasks." if do_warn
  nil
end