hiiro 0.1.71 → 0.1.72
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 +4 -4
- data/CLAUDE.md +153 -0
- data/bin/h-branch +25 -4
- data/lib/hiiro/options.rb +143 -118
- data/lib/hiiro/version.rb +1 -1
- data/lib/hiiro.rb +4 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5f96d3544bba42161e843e3e9478eb09a72b0cf32b2ec0736ef9a3e074d247cc
|
|
4
|
+
data.tar.gz: 8cb67c7ae3a7de600bb43b75b8399fc998359a7ac869241485a582561d8225a5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3397f01c85baa33ad040dff94823fec9ed78475aafe2b18a008df3aea3766c2f55ef622988b2b9a4b8b0e34ed0679015bafecf76b295f744d72449c127680844
|
|
7
|
+
data.tar.gz: 8c9fd7fe66febe8af0eca35c980fbf550ec2fd1461d845be4d0f481825fb77aa0e22075753db294f0d5de79a3f3f23cef3da7859d0fe1d4a983d77db7d0f4018
|
data/CLAUDE.md
CHANGED
|
@@ -78,11 +78,164 @@ hiiro.add_subcmd(:pwd) do |*args, **values|
|
|
|
78
78
|
end
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
+
## Creating Subcommands
|
|
82
|
+
|
|
83
|
+
There are two ways to add subcommands to Hiiro:
|
|
84
|
+
|
|
85
|
+
### 1. External Bin File (Preferred)
|
|
86
|
+
|
|
87
|
+
Create a new executable `bin/h-<name>` that uses `Hiiro.run`:
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
#!/usr/bin/env ruby
|
|
91
|
+
require 'hiiro'
|
|
92
|
+
|
|
93
|
+
Hiiro.run(*ARGV, plugins: [:Tasks]) {
|
|
94
|
+
add_subcmd(:list) {
|
|
95
|
+
puts "Listing items..."
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
add_subcmd(:add) { |name, path=nil|
|
|
99
|
+
puts "Adding #{name} at #{path}"
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
add_subcmd(:remove) { |name=nil|
|
|
103
|
+
if name.nil?
|
|
104
|
+
puts "Usage: h mycommand remove <name>"
|
|
105
|
+
next
|
|
106
|
+
end
|
|
107
|
+
puts "Removed #{name}"
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This creates commands like `h mycommand list`, `h mycommand add foo /path`.
|
|
113
|
+
|
|
114
|
+
### 2. Nested Subcommands via build_hiiro
|
|
115
|
+
|
|
116
|
+
For complex command hierarchies with shared state, create a nested Hiiro instance:
|
|
117
|
+
|
|
118
|
+
```ruby
|
|
119
|
+
def self.add_subcommands(hiiro)
|
|
120
|
+
hiiro.add_subcmd(:task) do |*args|
|
|
121
|
+
tm = TaskManager.new(hiiro, scope: :task)
|
|
122
|
+
build_hiiro(hiiro, tm).run
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.build_hiiro(parent_hiiro, tm)
|
|
127
|
+
bin_name = [parent_hiiro.bin, parent_hiiro.subcmd || ''].join('-')
|
|
128
|
+
|
|
129
|
+
Hiiro.init(bin_name:, args: parent_hiiro.args) do |h|
|
|
130
|
+
h.add_subcmd(:list) { tm.list }
|
|
131
|
+
h.add_subcmd(:start) { |name| tm.start_task(name) }
|
|
132
|
+
h.add_subcmd(:switch) { |name=nil|
|
|
133
|
+
name ||= tm.select_task_interactive
|
|
134
|
+
tm.switch_to_task(tm.task_by_name(name))
|
|
135
|
+
}
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
This pattern:
|
|
141
|
+
- Passes remaining args from parent to child via `args: parent_hiiro.args`
|
|
142
|
+
- Allows shared state (like `tm`) across all nested subcommands
|
|
143
|
+
- Creates commands like `h task list`, `h task start foo`
|
|
144
|
+
|
|
145
|
+
## Library Components (lib/)
|
|
146
|
+
|
|
147
|
+
The `lib/hiiro.rb` file and `lib/hiiro/` directory contain the core framework classes:
|
|
148
|
+
|
|
149
|
+
### Hiiro (lib/hiiro.rb)
|
|
150
|
+
|
|
151
|
+
Main entry point with class methods:
|
|
152
|
+
- `Hiiro.run(*ARGV, plugins: [...]) { ... }` - Initialize and run immediately
|
|
153
|
+
- `Hiiro.init(*ARGV, plugins: [...]) { ... }` - Initialize without running (returns hiiro instance)
|
|
154
|
+
|
|
155
|
+
Instance methods available in subcommand blocks:
|
|
156
|
+
- `git` - Returns `Hiiro::Git` instance for git operations
|
|
157
|
+
- `sk(lines)` - Interactive selection via skim
|
|
158
|
+
- `pins` - Key-value storage per command
|
|
159
|
+
- `todo_manager` - Todo item management
|
|
160
|
+
- `history` - Command history tracking
|
|
161
|
+
- `attach_method(name, &block)` - Add methods to hiiro instance dynamically
|
|
162
|
+
- `make_child(subcmd, *args)` - Create nested Hiiro for sub-subcommands
|
|
163
|
+
|
|
164
|
+
### Hiiro::PrefixMatcher (lib/hiiro/prefix_matcher.rb)
|
|
165
|
+
|
|
166
|
+
Handles abbreviation matching for commands and items:
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
matcher = Hiiro::PrefixMatcher.new(items, :name)
|
|
170
|
+
result = matcher.find("pre") # Find items where name starts with "pre"
|
|
171
|
+
result.match? # Any matches?
|
|
172
|
+
result.one? # Exactly one match?
|
|
173
|
+
result.ambiguous? # Multiple matches?
|
|
174
|
+
result.first&.item # Get first matching item
|
|
175
|
+
result.resolved&.item # Get exact or single match
|
|
176
|
+
|
|
177
|
+
# Path-based matching for hierarchical names (e.g., "task/subtask")
|
|
178
|
+
result = matcher.resolve_path("t/s")
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Hiiro::Git (lib/hiiro/git.rb)
|
|
182
|
+
|
|
183
|
+
Git operations wrapper with submodules for branches, worktrees, remotes, and PRs:
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
git = hiiro.git
|
|
187
|
+
git.root # Repository root path
|
|
188
|
+
git.branch # Current branch name
|
|
189
|
+
git.branches # List all branches
|
|
190
|
+
git.worktrees # List all worktrees
|
|
191
|
+
git.add_worktree(path, branch:) # Create worktree
|
|
192
|
+
git.move_worktree(from, to) # Rename worktree
|
|
193
|
+
git.current_pr # Get current PR info
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Hiiro::Sk (lib/hiiro/sk.rb)
|
|
197
|
+
|
|
198
|
+
Integration with `sk` (skim) fuzzy finder:
|
|
199
|
+
|
|
200
|
+
```ruby
|
|
201
|
+
selected = Hiiro::Sk.select(["option1", "option2", "option3"])
|
|
202
|
+
# Returns selected string or nil if cancelled
|
|
203
|
+
|
|
204
|
+
value = Hiiro::Sk.map_select({ "Display 1" => "value1", "Display 2" => "value2" })
|
|
205
|
+
# Shows keys, returns corresponding value
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Hiiro::TodoManager (lib/hiiro/todo.rb)
|
|
209
|
+
|
|
210
|
+
Todo item management with task association:
|
|
211
|
+
|
|
212
|
+
```ruby
|
|
213
|
+
tm = Hiiro::TodoManager.new
|
|
214
|
+
tm.add("Fix bug", tags: "urgent", task_info: { task_name: "feature" })
|
|
215
|
+
tm.start(0) # Mark item as started
|
|
216
|
+
tm.done(0) # Mark item as done
|
|
217
|
+
tm.active # Items not done/skipped
|
|
218
|
+
tm.filter_by_task("feature") # Items for specific task
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Hiiro::History (lib/hiiro/history.rb)
|
|
222
|
+
|
|
223
|
+
Command history tracking with tmux/git/task context:
|
|
224
|
+
|
|
225
|
+
```ruby
|
|
226
|
+
History.track(cmd: full_command, hiiro: self) # Auto-called after commands
|
|
227
|
+
History.by_task("feature") # Filter by task
|
|
228
|
+
History.by_branch("main") # Filter by git branch
|
|
229
|
+
History.by_session("work") # Filter by tmux session
|
|
230
|
+
```
|
|
231
|
+
|
|
81
232
|
## Key Files
|
|
82
233
|
|
|
83
234
|
- `bin/h` - Core framework (~420 lines)
|
|
84
235
|
- `bin/h-*` - External subcommands (tmux wrappers, video operations)
|
|
85
236
|
- `plugins/*.rb` - Reusable plugin modules (Pins, Project, Task, Tmux, Notify)
|
|
237
|
+
- `lib/hiiro.rb` - Main Hiiro class and Runners
|
|
238
|
+
- `lib/hiiro/*.rb` - Supporting classes (Git, PrefixMatcher, Sk, Todo, History)
|
|
86
239
|
|
|
87
240
|
## External Dependencies
|
|
88
241
|
|
data/bin/h-branch
CHANGED
|
@@ -241,8 +241,8 @@ checkout_branch = lambda { |branch = nil, *args|
|
|
|
241
241
|
system('git', 'checkout', branch, *args)
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
hiiro.add_subcmd(:checkout, checkout_branch)
|
|
245
|
-
hiiro.add_subcmd(:co, checkout_branch)
|
|
244
|
+
hiiro.add_subcmd(:checkout, &checkout_branch)
|
|
245
|
+
hiiro.add_subcmd(:co, &checkout_branch)
|
|
246
246
|
|
|
247
247
|
remove_branch = lambda { |branch = nil, *args|
|
|
248
248
|
unless branch
|
|
@@ -275,14 +275,35 @@ hiiro.add_subcmd(:duplicate) { |new_name = nil, source = nil|
|
|
|
275
275
|
puts "Created branch '#{new_name}' from '#{source}'"
|
|
276
276
|
}
|
|
277
277
|
|
|
278
|
+
hiiro.add_subcmd(:test) { |*args|
|
|
279
|
+
opts = Hiiro::Options.parse(args) do
|
|
280
|
+
option :remote, short: 'r', default: 'origin', desc: 'Remote name'
|
|
281
|
+
option :from, short: 'f', desc: 'Local branch or commit to push'
|
|
282
|
+
option :to, short: 't', desc: 'Remote branch name'
|
|
283
|
+
flag :force, short: 'F', desc: 'Force push'
|
|
284
|
+
flag :set_upstream, short: 'u', desc: 'Set upstream tracking'
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
{
|
|
288
|
+
remote_as_method: opts.remote,
|
|
289
|
+
remote_as_sym_key: opts[:remote],
|
|
290
|
+
remote_as_string_key: opts['remote'],
|
|
291
|
+
force_as_method: opts.force,
|
|
292
|
+
force_as_sym_key: opts[:force],
|
|
293
|
+
force_as_string_key: opts['force'],
|
|
294
|
+
}.each do |k,v|
|
|
295
|
+
puts "#{k} => #{v}"
|
|
296
|
+
end
|
|
297
|
+
}
|
|
298
|
+
|
|
278
299
|
hiiro.add_subcmd(:push) { |*args|
|
|
279
|
-
opts = Hiiro::Options.
|
|
300
|
+
opts = Hiiro::Options.parse(args) do
|
|
280
301
|
option :remote, short: 'r', default: 'origin', desc: 'Remote name'
|
|
281
302
|
option :from, short: 'f', desc: 'Local branch or commit to push'
|
|
282
303
|
option :to, short: 't', desc: 'Remote branch name'
|
|
283
304
|
flag :force, short: 'F', desc: 'Force push'
|
|
284
305
|
flag :set_upstream, short: 'u', desc: 'Set upstream tracking'
|
|
285
|
-
end
|
|
306
|
+
end
|
|
286
307
|
|
|
287
308
|
local_ref = opts[:from] || hiiro.git.branch
|
|
288
309
|
remote_branch = opts[:to] || local_ref
|
data/lib/hiiro/options.rb
CHANGED
|
@@ -1,167 +1,192 @@
|
|
|
1
1
|
class Hiiro
|
|
2
2
|
class Options
|
|
3
|
-
|
|
4
|
-
attr_reader :name, :short, :type, :default, :desc, :multi
|
|
5
|
-
|
|
6
|
-
def initialize(name, short: nil, type: :string, default: nil, desc: nil, multi: false)
|
|
7
|
-
@name = name.to_sym
|
|
8
|
-
@short = short&.to_s
|
|
9
|
-
@type = type
|
|
10
|
-
@default = default
|
|
11
|
-
@desc = desc
|
|
12
|
-
@multi = multi
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def flag?
|
|
16
|
-
type == :flag
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def long_form
|
|
20
|
-
"--#{name.to_s.tr('_', '-')}"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def short_form
|
|
24
|
-
short ? "-#{short}" : nil
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def match?(arg)
|
|
28
|
-
arg == long_form || arg == short_form
|
|
29
|
-
end
|
|
3
|
+
attr_reader :definitions
|
|
30
4
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
when :integer then value.to_i
|
|
34
|
-
when :float then value.to_f
|
|
35
|
-
else value
|
|
36
|
-
end
|
|
37
|
-
end
|
|
5
|
+
def self.parse(args, &block)
|
|
6
|
+
new(&block).parse!(args)
|
|
38
7
|
end
|
|
39
8
|
|
|
40
|
-
|
|
41
|
-
|
|
9
|
+
def self.setup(&block)
|
|
10
|
+
new(&block)
|
|
11
|
+
end
|
|
42
12
|
|
|
43
|
-
def initialize(
|
|
44
|
-
@raw_args = raw_args.dup
|
|
13
|
+
def initialize(&block)
|
|
45
14
|
@definitions = {}
|
|
46
|
-
@values = {}
|
|
47
|
-
@remaining_args = []
|
|
48
|
-
@parsed = false
|
|
49
|
-
|
|
50
15
|
instance_eval(&block) if block
|
|
51
|
-
parse! if block
|
|
52
16
|
end
|
|
53
17
|
|
|
54
|
-
# DSL: define a toggle flag (default false, presence inverts)
|
|
55
18
|
def flag(name, short: nil, default: false, desc: nil)
|
|
56
19
|
defn = Definition.new(name, short: short, type: :flag, default: default, desc: desc)
|
|
57
20
|
@definitions[name.to_sym] = defn
|
|
58
21
|
self
|
|
59
22
|
end
|
|
60
23
|
|
|
61
|
-
# DSL: define an option that takes a value
|
|
62
24
|
def option(name, short: nil, type: :string, default: nil, desc: nil, multi: false)
|
|
63
25
|
defn = Definition.new(name, short: short, type: type, default: default, desc: desc, multi: multi)
|
|
64
26
|
@definitions[name.to_sym] = defn
|
|
65
27
|
self
|
|
66
28
|
end
|
|
67
29
|
|
|
68
|
-
def parse
|
|
69
|
-
|
|
30
|
+
def parse(args)
|
|
31
|
+
Args.new(@definitions, args)
|
|
32
|
+
end
|
|
70
33
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
34
|
+
def parse!(args)
|
|
35
|
+
parse(args)
|
|
36
|
+
end
|
|
74
37
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
38
|
+
class Args
|
|
39
|
+
attr_reader :remaining_args, :original_args
|
|
40
|
+
alias args remaining_args
|
|
78
41
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
parse_short_options(arg, args)
|
|
86
|
-
else
|
|
87
|
-
@remaining_args << arg
|
|
88
|
-
end
|
|
42
|
+
def initialize(definitions, raw_args)
|
|
43
|
+
@definitions = definitions
|
|
44
|
+
@original_args = raw_args.dup.freeze
|
|
45
|
+
@values = {}
|
|
46
|
+
@remaining_args = []
|
|
47
|
+
do_parse(raw_args.dup)
|
|
89
48
|
end
|
|
90
49
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def [](name)
|
|
96
|
-
@values[name.to_sym]
|
|
97
|
-
end
|
|
50
|
+
def [](name)
|
|
51
|
+
@values[name.to_sym]
|
|
52
|
+
end
|
|
98
53
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
else
|
|
105
|
-
return @values[name] if @definitions.key?(name)
|
|
54
|
+
def fetch(name, default = nil)
|
|
55
|
+
key = name.to_sym
|
|
56
|
+
return @values[key] if @values.key?(key)
|
|
57
|
+
return yield if block_given?
|
|
58
|
+
default
|
|
106
59
|
end
|
|
107
|
-
super
|
|
108
|
-
end
|
|
109
60
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
61
|
+
def uses_option?(name)
|
|
62
|
+
key = name.to_sym
|
|
63
|
+
return false unless @definitions.key?(key)
|
|
64
|
+
@values[key] != @definitions[key].default
|
|
65
|
+
end
|
|
114
66
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
67
|
+
def to_h
|
|
68
|
+
@values.dup
|
|
69
|
+
end
|
|
118
70
|
|
|
119
|
-
|
|
71
|
+
def method_missing(name, *args, &block)
|
|
72
|
+
name_str = name.to_s
|
|
73
|
+
if name_str.end_with?('?')
|
|
74
|
+
key = name_str.chomp('?').to_sym
|
|
75
|
+
return !!@values[key] if @definitions.key?(key)
|
|
76
|
+
else
|
|
77
|
+
return @values[name] if @definitions.key?(name)
|
|
78
|
+
end
|
|
79
|
+
super
|
|
80
|
+
end
|
|
120
81
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
name = opt.sub(/^--/, '').tr('-', '_').to_sym
|
|
125
|
-
else
|
|
126
|
-
name = arg.sub(/^--/, '').tr('-', '_').to_sym
|
|
127
|
-
value = nil
|
|
82
|
+
def respond_to_missing?(name, include_private = false)
|
|
83
|
+
key = name.to_s.chomp('?').to_sym
|
|
84
|
+
@definitions.key?(key) || super
|
|
128
85
|
end
|
|
129
86
|
|
|
130
|
-
|
|
131
|
-
|
|
87
|
+
def do_parse(args)
|
|
88
|
+
@definitions.each do |name, defn|
|
|
89
|
+
@values[name] = defn.multi ? [] : defn.default
|
|
90
|
+
end
|
|
132
91
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
92
|
+
while args.any?
|
|
93
|
+
arg = args.shift
|
|
94
|
+
|
|
95
|
+
if arg == '--'
|
|
96
|
+
@remaining_args.concat(args)
|
|
97
|
+
break
|
|
98
|
+
elsif arg.start_with?('--')
|
|
99
|
+
parse_long_option(arg, args)
|
|
100
|
+
elsif arg.start_with?('-') && arg.length > 1
|
|
101
|
+
parse_short_options(arg, args)
|
|
102
|
+
else
|
|
103
|
+
@remaining_args << arg
|
|
104
|
+
end
|
|
105
|
+
end
|
|
138
106
|
end
|
|
139
|
-
end
|
|
140
107
|
|
|
141
|
-
|
|
142
|
-
|
|
108
|
+
def parse_long_option(arg, args)
|
|
109
|
+
if arg.include?('=')
|
|
110
|
+
opt, value = arg.split('=', 2)
|
|
111
|
+
name = opt.sub(/^--/, '').tr('-', '_').to_sym
|
|
112
|
+
else
|
|
113
|
+
name = arg.sub(/^--/, '').tr('-', '_').to_sym
|
|
114
|
+
value = nil
|
|
115
|
+
end
|
|
143
116
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
next unless defn
|
|
117
|
+
defn = @definitions[name]
|
|
118
|
+
return unless defn
|
|
147
119
|
|
|
148
120
|
if defn.flag?
|
|
149
|
-
@values[
|
|
150
|
-
elsif idx == chars.length - 1
|
|
151
|
-
store_value(defn, args.shift)
|
|
121
|
+
@values[name] = !defn.default
|
|
152
122
|
else
|
|
153
|
-
|
|
154
|
-
|
|
123
|
+
value ||= args.shift
|
|
124
|
+
store_value(defn, value)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def parse_short_options(arg, args)
|
|
129
|
+
chars = arg.sub(/^-/, '').chars
|
|
130
|
+
|
|
131
|
+
chars.each_with_index do |char, idx|
|
|
132
|
+
defn = @definitions.values.find { |d| d.short == char }
|
|
133
|
+
next unless defn
|
|
134
|
+
|
|
135
|
+
if defn.flag?
|
|
136
|
+
@values[defn.name] = !defn.default
|
|
137
|
+
elsif idx == chars.length - 1
|
|
138
|
+
store_value(defn, args.shift)
|
|
139
|
+
else
|
|
140
|
+
store_value(defn, chars[(idx + 1)..].join)
|
|
141
|
+
break
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def store_value(defn, value)
|
|
147
|
+
coerced = defn.coerce(value)
|
|
148
|
+
if defn.multi
|
|
149
|
+
@values[defn.name] << coerced
|
|
150
|
+
else
|
|
151
|
+
@values[defn.name] = coerced
|
|
155
152
|
end
|
|
156
153
|
end
|
|
157
154
|
end
|
|
158
155
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
@
|
|
156
|
+
class Definition
|
|
157
|
+
attr_reader :name, :short, :type, :default, :desc, :multi
|
|
158
|
+
|
|
159
|
+
def initialize(name, short: nil, type: :string, default: nil, desc: nil, multi: false)
|
|
160
|
+
@name = name.to_sym
|
|
161
|
+
@short = short&.to_s
|
|
162
|
+
@type = type
|
|
163
|
+
@default = default
|
|
164
|
+
@desc = desc
|
|
165
|
+
@multi = multi
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def flag?
|
|
169
|
+
type == :flag
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def long_form
|
|
173
|
+
"--#{name.to_s.tr('_', '-')}"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def short_form
|
|
177
|
+
short ? "-#{short}" : nil
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def match?(arg)
|
|
181
|
+
arg == long_form || arg == short_form
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def coerce(value)
|
|
185
|
+
case type
|
|
186
|
+
when :integer then value.to_i
|
|
187
|
+
when :float then value.to_f
|
|
188
|
+
else value
|
|
189
|
+
end
|
|
165
190
|
end
|
|
166
191
|
end
|
|
167
192
|
end
|
data/lib/hiiro/version.rb
CHANGED
data/lib/hiiro.rb
CHANGED
|
@@ -144,8 +144,10 @@ class Hiiro
|
|
|
144
144
|
runners.add_default(handler, **global_values, **values)
|
|
145
145
|
end
|
|
146
146
|
|
|
147
|
-
def add_subcommand(
|
|
148
|
-
|
|
147
|
+
def add_subcommand(*names, **values, &handler)
|
|
148
|
+
names.each do |name|
|
|
149
|
+
runners.add_subcommand(name, handler, **global_values, **values)
|
|
150
|
+
end
|
|
149
151
|
end
|
|
150
152
|
alias add_subcmd add_subcommand
|
|
151
153
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hiiro
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.72
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joshua Toyota
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-02-
|
|
11
|
+
date: 2026-02-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pry
|