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
35
# 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')
  register_json(h)    unless h.commands.key?('json')
end

.register_agents(klass) ⇒ Object



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

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, …).



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

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



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

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



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

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_json(klass) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/hammer/builtins.rb', line 116

def register_json(klass)
  klass.class_eval do
    task :json do
      desc <<~TXT
        Dump the CLI definition as JSON: tasks grouped exactly like
        the bare-`hammer` listing, each with desc, options, examples,
        aliases, needs. Consumed by the macOS GUI and any tooling
        that wants the full Hammerfile spec.
      TXT
      example 'h:json'
      example 'h:json --all       # include the reserved h: tasks'
      example 'h:json --compact   # minified, single line'
      opt :all,     type: :boolean, desc: 'include reserved built-in h: tasks'
      opt :compact, type: :boolean, desc: 'minified JSON (default: pretty)'
      proc do |opts|
        require 'json'
        spec = self.class.root.export_spec(include_builtins: opts[:all])
        puts opts[:compact] ? JSON.generate(spec) : JSON.pretty_generate(spec)
      end
    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`).



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/hammer/builtins.rb', line 144

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



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

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



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

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.



186
187
188
189
190
191
192
193
194
# File 'lib/hammer/builtins.rb', line 186

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