lux-hammer 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ae2c5c9dbcd3b17941440e327e04e84dbffaec7209e4ce15b205cf83525b3724
4
- data.tar.gz: 516eb4a4cb0f8f02f489eb00d2e4500cfe70f600eaebe192fb1749c81fe37074
3
+ metadata.gz: 7007c5628c3466147f7776a2de86832fa8737623ef7d91c8c4dc4a4b3db7e557
4
+ data.tar.gz: 38d2781742e9cb9d8d12c22b3e8c416fe9f26901a7ef0bed678b206f872a9468
5
5
  SHA512:
6
- metadata.gz: d922e58738cb3afc95c54864fc79d9a6ec556e3634a94f258711652abf220ba7f436e1d0f0cf24f48ba9c6372af22339d8377b491c9de93f708e19a7ca13692d
7
- data.tar.gz: 6ad385997b87bf70ba58ec3ae6d701b3717d5e9584ef00aae29ebeb5c9b3666a39f6032277e275987f6de94161809767eeb838e288718fda09287327009756b6
6
+ metadata.gz: d3dd10a43530fd33c1535ea38086eb3a86ce8d3750e3f79acb765b390b667ab70048bda841e3ab3959effcc1438aa0557e07bfd7f24d727d64a8e963a3ed8b6c
7
+ data.tar.gz: e976dc67d490f64c44044fab9dcad7e2b5431570eefdada070feb2689daba6fea8af46572ba223a6f801c881917ff522f519d08cf19218bd530ac438f91d4759
data/.version CHANGED
@@ -1 +1 @@
1
- 0.2.3
1
+ 0.2.4
data/README.md CHANGED
@@ -4,11 +4,11 @@ The bastard Frankenstein child of Rake, Thor, and Joshua. Sewn
4
4
  together from three good ideas, with the rest of each parent left on
5
5
  the cutting room floor.
6
6
 
7
- Drop a `Hammerfile`, run `hammer`, ship.
7
+ Drop a `Hammerfile`, run `hammer`, ship. AI LLM-s love `hammer`.
8
8
 
9
9
  ```ruby
10
10
  namespace :db do # Rake-style colon paths
11
- define :migrate do # Joshua-style define block
11
+ task :migrate do # Joshua-style task block
12
12
  desc 'Run pending migrations'
13
13
  opt :pretend, type: :boolean, alias: :p # Thor-style typed opts
14
14
  proc do |o|
@@ -40,7 +40,7 @@ migrating pretend=true
40
40
  that most CLIs never reach for.
41
41
 
42
42
  * **From [Joshua](https://github.com/dux/joshua)** we took the
43
- *`define :name do ... end` block DSL* - declarative metadata up
43
+ *`task :name do ... end` block DSL* - declarative metadata up
44
44
  top, one `proc do |opts| ... end` at the bottom doing the work. No
45
45
  `def`-and-`desc` split, no class required, no boilerplate between
46
46
  "what this command is" and "what it does".
@@ -67,7 +67,7 @@ This installs the `hammer` binary and exposes `require 'lux-hammer'`.
67
67
  Create a `Hammerfile` in your project root:
68
68
 
69
69
  ```ruby
70
- define :hello do
70
+ task :hello do
71
71
  desc 'say hi'
72
72
  proc do |opts|
73
73
  say.green "hello #{opts[:args].first || 'world'}"
@@ -115,7 +115,7 @@ Hammer takes typed options, positional fill, and any common flag form:
115
115
 
116
116
  ```ruby
117
117
  # Hammerfile
118
- define :greet do
118
+ task :greet do
119
119
  desc 'Say hello'
120
120
  opt :name
121
121
  opt :loud, type: :boolean, alias: :l
@@ -159,7 +159,7 @@ end
159
159
 
160
160
  ```ruby
161
161
  # hammer - one arg system, real aliases, no usage string to maintain
162
- define :greet do
162
+ task :greet do
163
163
  desc 'Say hello'
164
164
  alt :g
165
165
  opt :name
@@ -173,13 +173,13 @@ and there's one place to look for everything the command takes.
173
173
 
174
174
  ## The two styles
175
175
 
176
- ### `define :name do ... end` (block DSL)
176
+ ### `task :name do ... end` (block DSL)
177
177
 
178
178
  The block's **last expression must be `proc do |opts| ... end`**. That
179
179
  proc is the handler. Everything before it is metadata.
180
180
 
181
181
  ```ruby
182
- define :build do
182
+ task :build do
183
183
  desc 'Build the project'
184
184
  example 'build prod -v'
185
185
  opt :verbose, type: :boolean, alias: :v
@@ -371,7 +371,7 @@ Anything in ARGV without `-` / `--` fills the next un-set
371
371
  **non-boolean** opt, in declaration order:
372
372
 
373
373
  ```ruby
374
- define :deploy do
374
+ task :deploy do
375
375
  opt :url
376
376
  opt :env, default: 'dev'
377
377
  proc { |opts| ... }
@@ -403,7 +403,7 @@ Always a `Hash` with **symbol keys**. Keys present:
403
403
  * `opts[:args]` - array of positional ARGV not absorbed by an opt
404
404
 
405
405
  ```ruby
406
- define :show do
406
+ task :show do
407
407
  opt :env, default: 'dev'
408
408
  opt :loud, type: :boolean
409
409
  proc { |opts| p opts }
@@ -435,12 +435,12 @@ colon-paths from the root binary - just like `rake db:migrate`:
435
435
 
436
436
  ```ruby
437
437
  namespace :db do
438
- define :migrate do
438
+ task :migrate do
439
439
  proc { |opts| ... }
440
440
  end
441
441
 
442
442
  namespace :users do
443
- define :list do
443
+ task :list do
444
444
  proc { |opts| ... }
445
445
  end
446
446
  end
@@ -453,7 +453,9 @@ Then:
453
453
  hammer db:migrate
454
454
  hammer db:users:list
455
455
  hammer db # bare namespace lists everything under it
456
+ hammer db: # trailing colon: full per-task help for every command
456
457
  hammer db:migrate -h # per-command help
458
+ hammer : # trailing colon at root: full help for every command
457
459
  ```
458
460
 
459
461
  Namespaces nest to any depth. There is no per-level dispatch - the root
@@ -470,13 +472,13 @@ before { Dotenv.load } # runs before every command
470
472
 
471
473
  namespace :db do
472
474
  before { hammer :env } # runs before every db:* command
473
- define :migrate do
475
+ task :migrate do
474
476
  proc { |opts| ... } # no boilerplate require inside
475
477
  end
476
478
  end
477
479
  ```
478
480
 
479
- `before` is intentionally not available inside `define` - the proc body
481
+ `before` is intentionally not available inside `task` - the proc body
480
482
  *is* the command body, just put the setup line at the top of the proc.
481
483
 
482
484
  Pairs naturally with hidden commands (next section): keep `:env` /
@@ -488,13 +490,13 @@ A command declared without a `desc` is **hidden from help listings**
488
490
  but stays fully dispatchable and `hammer`-callable:
489
491
 
490
492
  ```ruby
491
- define :env do
493
+ task :env do
492
494
  proc { |_| require './config/env' } # no desc -> hidden
493
495
  end
494
496
 
495
497
  namespace :db do
496
498
  before { hammer :env } # call it from a hook
497
- define :migrate do
499
+ task :migrate do
498
500
  desc 'Run migrations'
499
501
  proc { |_| ... }
500
502
  end
@@ -509,17 +511,17 @@ end
509
511
  Declare commands that must run before this one (Rake-style task deps):
510
512
 
511
513
  ```ruby
512
- define :env do
514
+ task :env do
513
515
  proc { |_| require './config/env' } # hidden helper
514
516
  end
515
517
 
516
- define :app do
518
+ task :app do
517
519
  needs :env # runs `env` first
518
520
  desc 'start the app'
519
521
  proc { |opts| App.start }
520
522
  end
521
523
 
522
- define :deploy do
524
+ task :deploy do
523
525
  needs :env, :build # multiple prereqs, in order
524
526
  proc { |opts| ... }
525
527
  end
@@ -542,7 +544,7 @@ only once. Prereqs run with default options (no argv passed through).
542
544
  `alt :short_name` (or several) registers extra names for a command:
543
545
 
544
546
  ```ruby
545
- define :server do
547
+ task :server do
546
548
  alt :s, :srv
547
549
  proc { |opts| ... }
548
550
  end
@@ -558,7 +560,7 @@ From inside any command's proc - or from outside via the class - you can
558
560
  invoke other commands without re-shelling out:
559
561
 
560
562
  ```ruby
561
- define :deploy do
563
+ task :deploy do
562
564
  proc do |opts|
563
565
  hammer :build, env: 'prod', verbose: true
564
566
  hammer 'db:migrate'
@@ -729,7 +731,7 @@ load auto: true # recursive scan for *_hammer.rb from here
729
731
  ```ruby
730
732
  # tasks/db_hammer.rb
731
733
  namespace :db do
732
- define :migrate do
734
+ task :migrate do
733
735
  desc 'Run pending migrations'
734
736
  opt :pretend, type: :boolean, alias: :p
735
737
  proc { |o| say.green "migrating pretend=#{o[:pretend].inspect}" }
@@ -739,7 +741,7 @@ end
739
741
 
740
742
  ```ruby
741
743
  # tasks/deploy_hammer.rb
742
- define :deploy do
744
+ task :deploy do
743
745
  desc 'Deploy to prod'
744
746
  proc do |_|
745
747
  hammer 'db:migrate' # cross-file invocation just works
@@ -777,7 +779,7 @@ hidden directory.
777
779
  ### Fragment shape
778
780
 
779
781
  A `*_hammer.rb` file is a **block-DSL fragment** - same surface as a
780
- `Hammerfile`: `define`, `namespace`, and nested `load`. Not a class
782
+ `Hammerfile`: `task`, `namespace`, and nested `load`. Not a class
781
783
  re-open. If you want to extend a `Hammer` subclass in the classic
782
784
  `desc` + `def` style across files, use plain `require_relative`.
783
785
 
@@ -801,7 +803,7 @@ Same shape as a Hammerfile, just inline:
801
803
  require 'lux-hammer'
802
804
 
803
805
  Hammer.run(ARGV) do
804
- define :hello do
806
+ task :hello do
805
807
  desc 'say hi'
806
808
  opt :loud, type: :boolean, alias: :l
807
809
  proc do |opts|
@@ -845,7 +847,7 @@ end
845
847
 
846
848
  ```ruby
847
849
  # Simple top-level command
848
- define :build do
850
+ task :build do
849
851
  desc 'Build the project'
850
852
  example 'build prod -v'
851
853
  example 'build --env=staging'
@@ -860,7 +862,7 @@ define :build do
860
862
  end
861
863
 
862
864
  # Command that calls another command
863
- define :deploy do
865
+ task :deploy do
864
866
  desc 'Deploy to URL'
865
867
  alt :ship
866
868
  opt :url, req: true
@@ -875,7 +877,7 @@ end
875
877
 
876
878
  # Namespace with two levels of nesting
877
879
  namespace :db do
878
- define :migrate do
880
+ task :migrate do
879
881
  desc 'Run pending migrations'
880
882
  alt :m
881
883
  example 'db:migrate 3 --pretend'
@@ -888,7 +890,7 @@ namespace :db do
888
890
  end
889
891
 
890
892
  namespace :users do
891
- define :list do
893
+ task :list do
892
894
  desc 'List users'
893
895
  opt :role, default: 'all'
894
896
  opt :limit, type: :integer, default: 100
@@ -898,7 +900,7 @@ namespace :db do
898
900
  end
899
901
  end
900
902
 
901
- define :create do
903
+ task :create do
902
904
  desc 'Create a user'
903
905
  opt :email, req: true
904
906
  opt :admin, type: :boolean
@@ -968,7 +970,7 @@ directly. Useful for embedding or testing:
968
970
  require 'lux-hammer'
969
971
 
970
972
  class MyCli < Hammer
971
- define :greet do
973
+ task :greet do
972
974
  opt :loud, type: :boolean
973
975
  proc do |opts|
974
976
  msg = "hello #{opts[:args].first}"
@@ -1006,7 +1008,7 @@ few small things that have been bugging me about both for years.
1006
1008
  | Lines of code | ~6,000 | ~400 |
1007
1009
  | Runtime deps | a few | zero |
1008
1010
  | Root constants | `Thor`, `Thor::Group`, `Thor::Shell`, `Thor::Actions`, ... | just `Hammer` |
1009
- | Command DSL | `desc 'usage', 'help'` + `method_option` + `def name(arg)` | `define :name do ... proc do \|opts\| end end` (or classic `desc` + `def`) |
1011
+ | Command DSL | `desc 'usage', 'help'` + `method_option` + `def name(arg)` | `task :name do ... proc do \|opts\| end end` (or classic `desc` + `def`) |
1010
1012
  | Opts container | `Thor::CoreExt::HashWithIndifferentAccess` | plain `Hash` with symbol keys |
1011
1013
  | Positional args | method positional params + `method_option`, two parallel systems | declared-order opts fill from positional, single system |
1012
1014
  | Sub-namespaces | `register SubClass, 'name', '...'` (inheritance ceremony) | `namespace :name do ... end` (no classes needed) |
@@ -7,8 +7,8 @@ class Hammer
7
7
  @klass = klass
8
8
  end
9
9
 
10
- def define(name, &block)
11
- @klass.define(name, &block)
10
+ def task(name, &block)
11
+ @klass.task(name, &block)
12
12
  end
13
13
 
14
14
  def namespace(name, &block)
@@ -1,5 +1,5 @@
1
1
  class Hammer
2
- # Context object for `define :name do ... end` blocks. Exposes
2
+ # Context object for `task :name do ... end` blocks. Exposes
3
3
  # desc/example/opt/alt; the block's return value (a `proc do |opts|`)
4
4
  # becomes the command handler.
5
5
  class CommandBuilder
data/lib/lux-hammer.rb CHANGED
@@ -11,7 +11,7 @@ require_relative 'hammer/command_builder'
11
11
  # Class DSL:
12
12
  #
13
13
  # class MyCli < Hammer
14
- # define :build do
14
+ # task :build do
15
15
  # desc 'Build the project'
16
16
  # example 'build -v --env=prod'
17
17
  # opt :verbose, type: :boolean, alias: :v
@@ -27,7 +27,7 @@ require_relative 'hammer/command_builder'
27
27
  # Block DSL is identical, just inside `Hammer.run`:
28
28
  #
29
29
  # Hammer.run(ARGV) do
30
- # define :hello do
30
+ # task :hello do
31
31
  # desc 'Greet someone'
32
32
  # opt :loud, type: :boolean, alias: :l
33
33
  # proc do |opts|
@@ -124,17 +124,17 @@ class Hammer
124
124
  # return a Proc as its last expression. That proc is the handler and
125
125
  # receives a single `opts` hash with symbol keys; positional ARGV
126
126
  # lives at `opts[:args]`.
127
- def define(name, &block)
127
+ def task(name, &block)
128
128
  cmd = Command.new(name: name.to_s)
129
129
  handler = CommandBuilder.new(cmd).instance_eval(&block)
130
130
  unless handler.is_a?(Proc)
131
131
  raise Error, <<~MSG
132
- define(:#{name}) block must end with a `proc do |opts| ... end`.
132
+ task(:#{name}) block must end with a `proc do |opts| ... end`.
133
133
  The proc's return value is what becomes the command handler.
134
134
 
135
135
  Example:
136
136
 
137
- define :#{name} do
137
+ task :#{name} do
138
138
  desc 'what it does'
139
139
  example '#{name} foo --env=prod'
140
140
  opt :env, default: 'dev'
@@ -148,7 +148,7 @@ class Hammer
148
148
  cmd.handler = handler
149
149
  commands[cmd.name] = cmd
150
150
 
151
- # `define` ignores pending class-level state, but clear it so a
151
+ # `task` ignores pending class-level state, but clear it so a
152
152
  # later `def` doesn't accidentally consume stale metadata.
153
153
  @pending_desc = nil
154
154
  @pending_examples = []
@@ -158,11 +158,11 @@ class Hammer
158
158
  end
159
159
 
160
160
  # Open a namespace (group of commands). Everything inside the block
161
- # (define, nested namespace, ...) belongs to that namespace, evaluated
161
+ # (task, nested namespace, ...) belongs to that namespace, evaluated
162
162
  # against an anonymous Hammer subclass.
163
163
  #
164
164
  # namespace :db do
165
- # define :migrate do ... end
165
+ # task :migrate do ... end
166
166
  # namespace :users do ... end
167
167
  # end
168
168
  def namespace(name, &block)
@@ -189,7 +189,7 @@ class Hammer
189
189
  # before { |opts| Dotenv.load }
190
190
  # namespace :db do
191
191
  # before { hammer :env }
192
- # define :migrate do ... end
192
+ # task :migrate do ... end
193
193
  # end
194
194
  def before(&block)
195
195
  before_hooks << block
@@ -300,6 +300,19 @@ class Hammer
300
300
  return print_help(target)
301
301
  end
302
302
 
303
+ # Trailing colon ("db:") -> expanded namespace listing with full
304
+ # per-command help on every task. Bare ":" expands the root.
305
+ if name.end_with?(':') && name != ':'
306
+ bare = name.chomp(':')
307
+ ns = resolve_namespace(bare)
308
+ return print_namespace_help(bare, ns, full: true) if ns
309
+ Shell.print_error("unknown namespace: #{bare}")
310
+ print_help
311
+ exit 1
312
+ elsif name == ':'
313
+ return print_help(nil, full: true)
314
+ end
315
+
303
316
  cmd, owner = resolve(name)
304
317
  return owner.run_command(cmd, argv, full: name) if cmd
305
318
 
@@ -429,29 +442,52 @@ class Hammer
429
442
  scan.include?('-h') || scan.include?('--help')
430
443
  end
431
444
 
432
- def print_help(target = nil)
445
+ def print_help(target = nil, full: false)
433
446
  if target
447
+ # `help ns:` is equivalent to `ns:` - expanded namespace listing.
448
+ if target.end_with?(':') && target != ':'
449
+ bare = target.chomp(':')
450
+ ns = resolve_namespace(bare)
451
+ return print_namespace_help(bare, ns, full: true) if ns
452
+ Shell.print_error("unknown: #{target}")
453
+ return
454
+ end
434
455
  cmd, _ = resolve(target)
435
456
  return print_command_help(cmd, target) if cmd
436
457
  ns = resolve_namespace(target)
437
- return print_namespace_help(target, ns) if ns
458
+ return print_namespace_help(target, ns, full: full) if ns
438
459
  Shell.print_error("unknown: #{target}")
439
460
  return
440
461
  end
441
462
 
442
463
  Shell.say "Usage: #{program_name} COMMAND [ARGS]", :cyan
443
- Shell.say ''
444
- print_command_list(self)
464
+ if full
465
+ each_command { |path, c| print_full_block(path, c) unless c.desc.empty? }
466
+ else
467
+ Shell.say ''
468
+ print_command_list(self)
469
+ end
445
470
  print_footer
446
471
  end
447
472
 
448
- def print_namespace_help(prefix, ns)
473
+ def print_namespace_help(prefix, ns, full: false)
449
474
  Shell.say "Usage: #{program_name} #{prefix}:COMMAND [ARGS]", :cyan
450
- Shell.say ''
451
- print_command_list(ns, prefix)
475
+ if full
476
+ ns.each_command(prefix) { |path, c| print_full_block(path, c) unless c.desc.empty? }
477
+ else
478
+ Shell.say ''
479
+ print_command_list(ns, prefix)
480
+ end
452
481
  print_footer
453
482
  end
454
483
 
484
+ # One "task block" for the expanded listing: blank line separator
485
+ # then the standard per-command help (usage + desc + options + examples).
486
+ def print_full_block(path, cmd)
487
+ Shell.say ''
488
+ print_command_help(cmd, path)
489
+ end
490
+
455
491
  HOMEPAGE ||= 'https://github.com/dux/hammer'.freeze
456
492
 
457
493
  def print_footer
@@ -548,7 +584,7 @@ class Hammer
548
584
 
549
585
  # Inside a command's `proc do |opts| ... end`, call sibling commands:
550
586
  #
551
- # define :deploy do
587
+ # task :deploy do
552
588
  # proc do |opts|
553
589
  # hammer :build
554
590
  # hammer 'db:migrate', pretend: true
@@ -564,7 +600,7 @@ class Hammer
564
600
  # ----- block DSL -----------------------------------------------------
565
601
 
566
602
  # Define and run a CLI inline. Inside the block use
567
- # `define :name do ... end`, `namespace`, and `load`.
603
+ # `task :name do ... end`, `namespace`, and `load`.
568
604
  #
569
605
  # Without a block: load ./Hammerfile if it exists, otherwise
570
606
  # auto-discover *_hammer.rb under Dir.pwd, then dispatch ARGV.
@@ -606,7 +642,7 @@ class Hammer
606
642
  Shell.say "create one - example:"
607
643
  puts
608
644
  Shell.say <<~RUBY
609
- define :hello do
645
+ task :hello do
610
646
  desc 'say hello'
611
647
  proc do |opts|
612
648
  say.green "hello \#{opts[:args].first || 'world'}"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lux-hammer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dino Reic
@@ -61,7 +61,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
61
  - !ruby/object:Gem::Version
62
62
  version: '0'
63
63
  requirements: []
64
- rubygems_version: 4.0.8
64
+ rubygems_version: 4.0.10
65
65
  specification_version: 4
66
66
  summary: Thor-inspired tiny CLI builder
67
67
  test_files: []