Module: Hammer::Builtins

Defined in:
lib/hammer/builtins.rb

Overview

Built-in tasks of the ‘hammer` binary. Everything but :default lives under the reserved `h:` namespace (e.g. `hammer h:update`, `hammer h:recipes`) so the built-ins never collide with a project’s own root tasks. Only the bare ‘hammer` invocation and the `-h`/`–help`/`help` request are handled at root - bare fires :default, which also carries the `–version` convenience flag.

Defined Under Namespace

Modules: RecipesActions

Class Method Summary collapse

Class Method Details

.register(klass) ⇒ Object

Single registration entry point - identical in every context (project Hammerfile or bare ‘hammer` binary). Namespacing under `h:` removes the old collision worries, so there’s no core vs no-project split and no hidden-desc dance: the same tasks register everywhere, always dispatchable, and surface in the listing only under the extended ‘–help` view (the `@builtin_namespace` flag).



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/hammer/builtins.rb', line 17

def register(klass)
  register_default(klass) unless klass.commands.key?('default')

  existed = klass.namespaces.key?('h')
  klass.namespace(:h) {}          # ensure/reopen the reserved subclass
  h = klass.namespaces['h']
  # Flag the tree so the compact listing prunes it - the built-ins
  # only show under the extended `--help` view (always dispatchable).
  # Skip when the user already owns an `h:` namespace, so their own
  # tasks stay visible in the bare listing.
  h.instance_variable_set(:@builtin_namespace, true) unless existed
  register_help(h)    unless h.commands.key?('help')
  register_update(h)  unless h.commands.key?('update')
  register_agents(h)  unless h.commands.key?('agents')
  register_version(h) unless h.commands.key?('version')
  register_recipes(h) unless h.commands.key?('recipes')
  register_init(h)    unless h.commands.key?('init')
end

.register_agents(klass) ⇒ Object



88
89
90
91
92
93
94
95
# File 'lib/hammer/builtins.rb', line 88

def register_agents(klass)
  klass.class_eval do
    task :agents do
      desc 'Print AGENTS.md (Hammerfile authoring docs for AI assistants)'
      proc { Hammer.print_ai_help }
    end
  end
end

.register_default(klass) ⇒ Object

‘:default` fires on bare `hammer` and on leading-flag invocations (other than -h/–help). Hidden from listings (no desc). All it does now is print help - the old flag opts (–update, –ai, …) moved to dedicated tasks (:update, :agents, …).



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/hammer/builtins.rb', line 61

def register_default(klass)
  klass.class_eval do
    task :default do
      opt :version, type: :boolean, alias: :v, desc: 'print lux-hammer version'
      # Inlined rather than dispatched to :version - going through
      # `hammer :version` would print the gray run banner. The
      # implementation is one line; not worth the indirection.
      proc do |opts|
        if opts[:version]
          puts Hammer::VERSION
        else
          self.class.root.print_help
        end
      end
    end
  end
end

.register_help(klass) ⇒ Object



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/hammer/builtins.rb', line 36

def register_help(klass)
  klass.class_eval do
    task :help do
      desc <<~TXT
        Show help. Optional TARGET = command name or namespace (`ns:`).

        Without TARGET prints the extended top-level help (commands,
        recipes, global flags, examples). With a command path prints
        per-command help; with a namespace prefix prints that
        namespace's command listing.
      TXT
      example 'h:help'
      example 'h:help build'
      example 'h:help db:'
      proc do |opts|
        self.class.root.print_help(opts[:args].first, extended: true)
      end
    end
  end
end

.register_init(klass) ⇒ Object



106
107
108
109
110
111
112
113
# File 'lib/hammer/builtins.rb', line 106

def register_init(klass)
  klass.class_eval do
    task :init do
      desc 'Write a starter Hammerfile in the current directory'
      proc { Hammer::Builtins.write_starter_hammerfile }
    end
  end
end

.register_recipes(klass) ⇒ Object

‘:recipes` rolls all recipe-management actions into one task. Bare invocation lists; opts pick the action and positional args carry the recipe name (and optional target path for –install). Run via `–run NAME [ARGS]` - use `–` to forward flags to the recipe itself (e.g. `hammer h:recipes –run srt – –help`).



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/hammer/builtins.rb', line 120

def register_recipes(klass)
  klass.class_eval do
    task :recipes do
      desc <<~TXT
        Manage recipes - the standalone Hammerfile-style scripts
        bundled with the gem (and under ~/.config/hammer/recipes).
        Bare invocation lists; flags pick the action.
      TXT
      opt :install, type: :boolean, desc: 'install recipe stub (picker if no NAME). With TARGET path: write + chmod.'
      opt :show,    type: :boolean, desc: 'cat recipe source'
      opt :path,    type: :boolean, desc: 'print recipe abs path'
      opt :edit,    type: :boolean, desc: 'open recipe in $EDITOR (copies gem -> user dir first)'
      opt :run,     type: :boolean, desc: 'run a recipe without installing its bin (forwards remaining args)'
      example 'h:recipes'
      example 'h:recipes --install srt ~/bin/srt    # write + chmod in one shot'
      example 'h:recipes --install srt > ~/bin/srt && chmod +x $_'
      example 'h:recipes --show srt'
      example 'h:recipes --run srt extract movie.mp4'
      example 'h:recipes --run srt -- --help        # -- forwards flags to the recipe'
      proc do |opts|
        args = opts[:args]
        if opts[:install]
          Hammer::Builtins::RecipesActions.install(args[0], args[1])
        elsif opts[:show]
          Hammer::Builtins::RecipesActions.show(Hammer::Builtins::RecipesActions.require_name!(args[0], 'show'))
        elsif opts[:path]
          Hammer::Builtins::RecipesActions.path(Hammer::Builtins::RecipesActions.require_name!(args[0], 'path'))
        elsif opts[:edit]
          Hammer::Builtins::RecipesActions.edit(Hammer::Builtins::RecipesActions.require_name!(args[0], 'edit'))
        elsif opts[:run]
          name = Hammer::Builtins::RecipesActions.require_name!(args[0], 'run')
          Hammer.recipe(name, args[1..])
        else
          Hammer::Builtins::RecipesActions.list
        end
      end
    end
  end
end

.register_update(klass) ⇒ Object



79
80
81
82
83
84
85
86
# File 'lib/hammer/builtins.rb', line 79

def register_update(klass)
  klass.class_eval do
    task :update do
      desc 'Rebuild + reinstall lux-hammer from main'
      proc { Hammer.self_update }
    end
  end
end

.register_version(klass) ⇒ Object



97
98
99
100
101
102
103
104
# File 'lib/hammer/builtins.rb', line 97

def register_version(klass)
  klass.class_eval do
    task :version do
      desc 'Print lux-hammer version'
      proc { puts Hammer::VERSION }
    end
  end
end

.write_starter_hammerfileObject

Writes ./Hammerfile with the canonical starter template. Refuses if one already exists - ‘init` must not clobber.



162
163
164
165
166
167
168
169
170
# File 'lib/hammer/builtins.rb', line 162

def write_starter_hammerfile
  target = File.join(Dir.pwd, 'Hammerfile')
  if File.exist?(target)
    Shell.print_error "Hammerfile already exists at #{target}"
    exit 1
  end
  File.write(target, Hammer::STARTER_HAMMERFILE)
  Shell.say "created #{target}", :green
end