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
-
.register(klass) ⇒ Object
Single registration entry point - identical in every context (project Hammerfile or bare
hammerbinary). - .register_agents(klass) ⇒ Object
-
.register_cron(klass) ⇒ Object
The job server: runs every task that declares
cron '<expr>'on its schedule, in the foreground, with a localhost web UI for status, logs and manual triggers. -
.register_default(klass) ⇒ Object
:defaultfires on barehammerand on leading-flag invocations (other than -h/--help). - .register_help(klass) ⇒ Object
- .register_init(klass) ⇒ Object
- .register_json(klass) ⇒ Object
-
.register_recipes(klass) ⇒ Object
:recipesrolls all recipe-management actions into one task. - .register_update(klass) ⇒ Object
- .register_version(klass) ⇒ Object
-
.write_starter_hammerfile ⇒ Object
Writes ./Hammerfile with the canonical starter template.
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 36 |
# 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') register_cron(h) unless h.commands.key?('cron') end |
.register_agents(klass) ⇒ Object
90 91 92 93 94 95 96 97 |
# File 'lib/hammer/builtins.rb', line 90 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_cron(klass) ⇒ Object
The job server: runs every task that declares cron '<expr>' on
its schedule, in the foreground, with a localhost web UI for
status, logs and manual triggers. Per-job logs land in log/hammer/
(rotated at 1 MB, max 2 files), state in tmp/hammer/cron.state.json.
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 121 def register_cron(klass) klass.class_eval do task :cron do desc <<~TXT Job server: run tasks that declare a `cron '<expr>'` schedule. Runs in the foreground (Ctrl-C to stop) with a web UI on localhost for job status, per-job logs and manual runs. Use --service to print a launchd plist / systemd unit and let the OS supervise it. TXT example 'h:cron' example 'h:cron --port=7777' example 'h:cron --pass=secret' example 'h:cron --list' example 'h:cron --service > ~/.config/systemd/user/hammer-cron.service' opt :port, type: :integer, default: 4267, desc: 'web UI port (binds 127.0.0.1 only)' opt :pass, type: :string, desc: 'HTTP basic-auth password for the web UI (or CRON_HTTP_PASS env)' opt :list, type: :boolean, desc: 'print scheduled jobs + next runs, then exit' opt :service, type: :boolean, desc: 'print a launchd plist (macOS) / systemd unit (linux)' proc do |opts| if self.class.root.instance_variable_get(:@no_hammerfile) error "no Hammerfile found - h:cron needs a project with scheduled tasks" end require_relative 'cron_server' server = Hammer::CronServer.new(self.class.root, port: opts[:port], pass: opts[:pass] || ENV['CRON_HTTP_PASS']) if opts[:service] server.print_service_unit elsif opts[:list] server.print_startup_summary else server.run! end end 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, ...).
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/hammer/builtins.rb', line 63 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
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/hammer/builtins.rb', line 38 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
108 109 110 111 112 113 114 115 |
# File 'lib/hammer/builtins.rb', line 108 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
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/hammer/builtins.rb', line 160 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).
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/hammer/builtins.rb', line 188 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
81 82 83 84 85 86 87 88 |
# File 'lib/hammer/builtins.rb', line 81 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
99 100 101 102 103 104 105 106 |
# File 'lib/hammer/builtins.rb', line 99 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_hammerfile ⇒ Object
Writes ./Hammerfile with the canonical starter template. Refuses
if one already exists - init must not clobber.
230 231 232 233 234 235 236 237 238 |
# File 'lib/hammer/builtins.rb', line 230 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 |