Module: Hammer::Recipe

Defined in:
lib/hammer/recipe.rb

Overview

Discovery + helpers for “recipes” - standalone Hammerfile-style scripts shipped under ‘<gem>/recipes/` (and optionally the user’s ‘~/.config/hammer/recipes/`) that are exposed as their own bin scripts in PATH via a tiny Ruby wrapper.

Class Method Summary collapse

Class Method Details

.allObject

{ “name” => “/abs/path/name.rb” }. User-dir entries win over gem entries because they come first in ‘dirs`.



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/hammer/recipe.rb', line 23

def all
  out = {}
  dirs.each do |dir|
    next unless File.directory?(dir)
    Dir.glob(File.join(dir, '*.rb')).sort.each do |path|
      name = File.basename(path, '.rb')
      out[name] ||= path
    end
  end
  out
end

.desc(path) ⇒ Object

First ‘# desc: …` line at the top of the file, or empty string. Cheap - reads only the first ~20 lines, no eval.



42
43
44
45
46
47
48
49
50
# File 'lib/hammer/recipe.rb', line 42

def desc(path)
  return '' unless path && File.file?(path)
  File.foreach(path).first(20).each do |line|
    if (m = line.match(/\A#\s*desc:\s*(.+)$/i))
      return m[1].strip
    end
  end
  ''
end

.dirsObject

Recipe lookup directories, in priority order. User dir is only included when it exists. Honors HAMMER_RECIPES_DIR for overrides (mostly for tests).



14
15
16
17
18
19
# File 'lib/hammer/recipe.rb', line 14

def dirs
  out = [GEM_DIR]
  user = ENV['HAMMER_RECIPES_DIR'] || File.expand_path('~/.config/hammer/recipes')
  out.unshift(user) if File.directory?(user)
  out
end

.groupedObject

Group recipes by their source directory for the listing view. Returns [[source_label, { name => path }], …].



82
83
84
85
86
87
88
89
90
# File 'lib/hammer/recipe.rb', line 82

def grouped
  user_dir = ENV['HAMMER_RECIPES_DIR'] || File.expand_path('~/.config/hammer/recipes')
  groups = { 'gem' => {}, 'user' => {} }
  all.each do |name, path|
    bucket = path.start_with?(user_dir) ? 'user' : 'gem'
    groups[bucket][name] = path
  end
  groups.reject { |_, v| v.empty? }.to_a
end

.installed_path(name) ⇒ Object

If a stub for ‘name` is on PATH, return its absolute path. Detects by reading the file and looking for the literal `Hammer.recipe(’<name>‘` token - cheap and near-zero false positive.



68
69
70
71
72
73
74
75
76
77
78
# File 'lib/hammer/recipe.rb', line 68

def installed_path(name)
  token = "Hammer.recipe('#{name}'"
  ENV.fetch('PATH', '').split(File::PATH_SEPARATOR).each do |dir|
    candidate = File.join(dir, name.to_s)
    next unless File.file?(candidate) && File.executable?(candidate)
    return candidate if File.read(candidate, 512).include?(token)
  rescue StandardError
    next
  end
  nil
end

.path(name) ⇒ Object

Path to the recipe file for ‘name`, or nil if unknown.



36
37
38
# File 'lib/hammer/recipe.rb', line 36

def path(name)
  all[name.to_s]
end

.stub(name) ⇒ Object

Ruby wrapper text printed by ‘hammer self:recipe install`. User redirects it to a file in PATH and chmods +x. The leading comment documents the canonical install command. Name is passed as a string literal so hyphenated names (`git-helper`) work too.



56
57
58
59
60
61
62
63
# File 'lib/hammer/recipe.rb', line 56

def stub(name)
  <<~RUBY
    #!/usr/bin/env ruby
    # install: hammer self:recipe install #{name} > ~/bin/#{name} && chmod +x $_
    require 'lux-hammer'
    Hammer.recipe('#{name}', ARGV)
  RUBY
end