commander-tools 0.1.0

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.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/command.rb +147 -0
  3. metadata +57 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '05063299fe8d358adfd25b631a9e2f4d97fc1167171b0179731051606513fecf'
4
+ data.tar.gz: aac4e4fb0961d048c61d26082aaa5866577c5c2b111f2197c6f9846bb69665d8
5
+ SHA512:
6
+ metadata.gz: 6560b4bae0716524907bc7cd9c574408923ee2a4455e2d19bfe91e5601aa0bbfddc6bfbe2f868382e377a70ac403d510a138faff8609a81f4db899f0bd9f1d50
7
+ data.tar.gz: 74234827b5c2ea05d6df688636ea7508b0c549fed9006ec29dce364265abec94a15a0af5102191937ec8bfe8bd58c4c75a94130715009f53b4be5ba1c89e4a6c
data/lib/command.rb ADDED
@@ -0,0 +1,147 @@
1
+ require 'did_you_mean'
2
+
3
+ class Commander
4
+ class Command
5
+ attr_reader :name, :description, :options, :block
6
+
7
+ def initialize(name, description = '', &block)
8
+ @name = name.to_s
9
+ @description = description
10
+ @options = []
11
+ @block = block
12
+ end
13
+
14
+ def add_option(switches, description = '')
15
+ @options << Option.new(switches, description)
16
+ end
17
+ end
18
+
19
+ class Option
20
+ attr_reader :switches, :description, :key
21
+
22
+ def initialize(switches, description)
23
+ @switches = switches # e.g., ["-v", "--version"]
24
+ @description = description
25
+ @key = switches.find { |s| s.start_with?('--') }&.sub(/^--/, '')&.tr('-', '_') ||
26
+ switches.find { |s| s.start_with?('-') }&.sub(/^-/, '')
27
+ end
28
+
29
+ def matches?(arg)
30
+ @switches.include?(arg)
31
+ end
32
+ end
33
+
34
+ def initialize
35
+ @commands = {}
36
+ @global_options = []
37
+ end
38
+
39
+ def add_command(name, description = '', &block)
40
+ cmd = Command.new(name, description, &block)
41
+ @commands[cmd.name] = cmd
42
+ cmd
43
+ end
44
+
45
+ def add_option(switches, description = '')
46
+ @global_options << Option.new(switches, description)
47
+ end
48
+
49
+ def parse(args = ARGV)
50
+ global_parsed, remaining_args = parse_options(args, @global_options)
51
+
52
+ command_name = remaining_args.shift
53
+
54
+ if command_name.nil?
55
+ handle_no_command(global_parsed)
56
+ return
57
+ end
58
+
59
+ if @commands.key?(command_name)
60
+ command = @commands[command_name]
61
+ cmd_parsed, command_args = parse_options(remaining_args, command.options)
62
+
63
+ combined_options = global_parsed.merge(cmd_parsed)
64
+
65
+ if command.block
66
+ command.block.call(combined_options, command_args)
67
+ end
68
+ else
69
+ raise_unknown_command(command_name)
70
+ end
71
+ end
72
+
73
+ def display_usage
74
+ puts "Available commands:"
75
+ @commands.each do |name, cmd|
76
+ puts " #{name} - #{cmd.description}"
77
+ cmd.options.each do |opt|
78
+ puts " #{opt.switches.join(', ')}: #{opt.description}"
79
+ end
80
+ end
81
+ puts "\nGlobal options:"
82
+ @global_options.each do |opt|
83
+ puts " #{opt.switches.join(', ')}: #{opt.description}"
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def parse_options(args, available_options)
90
+ parsed = {}
91
+ remaining = []
92
+ i = 0
93
+
94
+ while i < args.length
95
+ arg = args[i]
96
+ if arg.start_with?('-')
97
+ option = available_options.find { |opt| opt.matches?(arg) }
98
+ if option
99
+ if args[i + 1] && !args[i + 1].start_with?('-')
100
+ parsed[option.key.to_sym] = args[i + 1]
101
+ i += 2
102
+ else
103
+ parsed[option.key.to_sym] = true
104
+ i += 1
105
+ end
106
+ else
107
+ raise_unknown_option(arg, available_options)
108
+ end
109
+ else
110
+ remaining << arg
111
+ i += 1
112
+ end
113
+ end
114
+
115
+ [parsed, remaining]
116
+ end
117
+
118
+ def raise_unknown_command(command_name)
119
+ corrector = DidYouMean::SpellChecker.new(dictionary: @commands.keys)
120
+ suggestions = corrector.correct(command_name)
121
+
122
+ msg = "error: unknown command '#{command_name}'"
123
+ msg += "\n\nDid you mean?\n\t#{suggestions.join("\n\t")}" unless suggestions.empty?
124
+
125
+ abort msg
126
+ end
127
+
128
+ def raise_unknown_option(option_name, available_options)
129
+ all_switches = available_options.flat_map(&:switches)
130
+ corrector = DidYouMean::SpellChecker.new(dictionary: all_switches)
131
+ suggestions = corrector.correct(option_name)
132
+
133
+ msg = "error: unknown option '#{option_name}'"
134
+ msg += "\n\nDid you mean?\n\t#{suggestions.join("\n\t")}" unless suggestions.empty?
135
+
136
+ abort msg
137
+ end
138
+
139
+ def handle_no_command(options)
140
+ if options[:version] || options[:v]
141
+ puts "Commander CLI v1.0.0"
142
+ else
143
+ puts "error: no command specified."
144
+ display_usage
145
+ end
146
+ end
147
+ end
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: commander-tools
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Your Name
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 2026-09-16 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: did_you_mean
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
26
+ description: Commander-tools gem providing CLI command parsing with suggestions
27
+ email:
28
+ - dodi66412@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/command.rb
34
+ homepage: https://github.com/jjjm03299-wq/didactic-parakeet
35
+ licenses:
36
+ - MIT
37
+ metadata:
38
+ homepage_uri: https://github.com/jjjm03299-wq/didactic-parakeet
39
+ source_code_uri: https://github.com/jjjm03299-wq/didactic-parakeet
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '2.5'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubygems_version: 3.6.2
55
+ specification_version: 4
56
+ summary: A custom CLI commander tools gem
57
+ test_files: []