clino 0.1.1 → 0.1.3
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/CODE_OF_CONDUCT.md +1 -1
- data/README.md +19 -18
- data/lib/clino/common/utils.rb +5 -0
- data/lib/clino/domain/input_parser.rb +22 -26
- data/lib/clino/domain/result_obtainer.rb +5 -1
- data/lib/clino/domain/signature/base.rb +2 -2
- data/lib/clino/domain/signature/cli_signature.rb +32 -4
- data/lib/clino/interfaces/base/base_cli.rb +19 -5
- data/lib/clino/interfaces/cli.rb +10 -4
- data/lib/clino/interfaces/min.rb +1 -1
- data/lib/clino/version.rb +1 -1
- 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: df8da7e0b98d842743ff6574a23b88f48382faa9ccc218734b9696db55758799
|
4
|
+
data.tar.gz: ec26f662643aa566eaf2572d79a0d50dbb96a1d23550899329967a3299708b1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1accf77eb7242b41b00a9b19cedecb00a6116d429016123714a9bc0f08dc82d371216b9bfbe733ee411a18da97074c0e919f1e5b88248f5786293003be8ec695
|
7
|
+
data.tar.gz: b96437b5d23babb6a6749e23414ed5aef3bc3effe2690399ccb22136a5e686f3be8ec9f97a8bdd419ef66e69c993495bf4baeb25aac121c40d9f678cb094f9eb
|
data/CODE_OF_CONDUCT.md
CHANGED
@@ -39,7 +39,7 @@ This Code of Conduct applies within all community spaces, and also applies when
|
|
39
39
|
|
40
40
|
## Enforcement
|
41
41
|
|
42
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at
|
42
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at snusmumrmail@gmail.com. All complaints will be reviewed and investigated promptly and fairly.
|
43
43
|
|
44
44
|
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
45
45
|
|
data/README.md
CHANGED
@@ -6,12 +6,20 @@ It is inspired by the [Thor](https://github.com/rails/thor) and [Typer](https://
|
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
-
|
9
|
+
Install this gem as a regular gem:
|
10
|
+
|
11
|
+
```bash
|
12
|
+
gem install clino
|
13
|
+
```
|
14
|
+
|
15
|
+
or add this line to your application's Gemfile:
|
10
16
|
|
11
17
|
```ruby
|
12
18
|
gem 'clino'
|
13
19
|
```
|
14
20
|
|
21
|
+
Link: [RubyGems](https://rubygems.org/gems/clino)
|
22
|
+
|
15
23
|
## Usage
|
16
24
|
|
17
25
|
### Interfaces
|
@@ -40,14 +48,10 @@ Let's write a simple script that takes a name as an argument and prints a greeti
|
|
40
48
|
|
41
49
|
require "clino/interfaces/min"
|
42
50
|
|
43
|
-
|
44
|
-
"Hello, #{name}!"
|
45
|
-
end
|
46
|
-
|
47
|
-
Min.new(:hello).start
|
51
|
+
Min.new(->(name) { "Hello, #{name}!" }).start
|
48
52
|
```
|
49
53
|
|
50
|
-
Writing
|
54
|
+
Writing lambda containing only business logic is enough, as the input and output handling is done by the `Min` interface.
|
51
55
|
|
52
56
|
Run the script with the following command:
|
53
57
|
|
@@ -64,7 +68,7 @@ ruby hello.rb --help
|
|
64
68
|
or
|
65
69
|
|
66
70
|
```bash
|
67
|
-
ruby hello.rb
|
71
|
+
ruby hello.rb -h
|
68
72
|
```
|
69
73
|
|
70
74
|
It will print the following output:
|
@@ -77,7 +81,6 @@ Arguments:
|
|
77
81
|
<name> [string]
|
78
82
|
|
79
83
|
Usage: hello.rb [arguments] [options]
|
80
|
-
Use --h, --help to print this help message.
|
81
84
|
```
|
82
85
|
#### Randomizer Minimalistic Example
|
83
86
|
|
@@ -132,7 +135,7 @@ ruby min_randomizer.rb --help
|
|
132
135
|
or
|
133
136
|
|
134
137
|
```bash
|
135
|
-
ruby min_randomizer.rb
|
138
|
+
ruby min_randomizer.rb -h
|
136
139
|
```
|
137
140
|
|
138
141
|
It will print the following output:
|
@@ -155,7 +158,6 @@ Options:
|
|
155
158
|
[--incl] [string] [default: unknown]
|
156
159
|
|
157
160
|
Usage: min_randomizer.rb [arguments] [options]
|
158
|
-
Use --h, --help to print this help message.
|
159
161
|
```
|
160
162
|
|
161
163
|
As we can see, ruby's metaprogramming capabilities allow us to create a simple CLI, however it doesn't provide a way to handle complex input.
|
@@ -164,7 +166,9 @@ Unfortunately, ruby doesn't allow inspecting the method's signature default valu
|
|
164
166
|
|
165
167
|
#### Randomizer Advanced Example
|
166
168
|
|
167
|
-
Let's write an advanced version of the randomizer that has CLI signature.
|
169
|
+
Let's write an advanced version of the randomizer that has CLI signature.
|
170
|
+
|
171
|
+
Our entry point is the `run` method, which is called with the parsed and validated input.
|
168
172
|
|
169
173
|
```ruby
|
170
174
|
# randomizer.rb
|
@@ -210,7 +214,7 @@ RandomGeneratorCLI.new.start
|
|
210
214
|
Run the script with the following command:
|
211
215
|
|
212
216
|
```bash
|
213
|
-
ruby randomizer.rb 1 2 --alg uni --i
|
217
|
+
ruby randomizer.rb 1 2 --alg uni --i # => some number from [1.0, 2.0]
|
214
218
|
```
|
215
219
|
|
216
220
|
Get help with the following command:
|
@@ -222,7 +226,7 @@ ruby randomizer.rb --help
|
|
222
226
|
or
|
223
227
|
|
224
228
|
```bash
|
225
|
-
ruby randomizer.rb
|
229
|
+
ruby randomizer.rb -h
|
226
230
|
```
|
227
231
|
|
228
232
|
It will print the following output:
|
@@ -247,10 +251,9 @@ Options:
|
|
247
251
|
# Algorithm to use (uni or exp)
|
248
252
|
--alg (-a) [string]
|
249
253
|
# Include upper bound
|
250
|
-
[--
|
254
|
+
[--incl] (-i) [bool] [default: false]
|
251
255
|
|
252
256
|
Usage: randomizer.rb [arguments] [options]
|
253
|
-
Use --h, --help to print this help message.
|
254
257
|
```
|
255
258
|
|
256
259
|
As we can see, all the default values, helping notes, and types are written out, and the input validation is handled automatically.
|
@@ -304,7 +307,6 @@ Arguments:
|
|
304
307
|
<height> [positive_integer]
|
305
308
|
|
306
309
|
Usage: weight_calculator.rb [arguments] [options]
|
307
|
-
Use --h, --help to print this help message.
|
308
310
|
```
|
309
311
|
|
310
312
|
## Improvements
|
@@ -316,7 +318,6 @@ Use --h, --help to print this help message.
|
|
316
318
|
- [ ] Add CI/CD
|
317
319
|
- [ ] Add more examples
|
318
320
|
- [ ] Create a proper documentation
|
319
|
-
- [ ] Better boolean flag handling
|
320
321
|
|
321
322
|
## Contributing
|
322
323
|
|
data/lib/clino/common/utils.rb
CHANGED
@@ -4,10 +4,18 @@ require "optparse"
|
|
4
4
|
|
5
5
|
module InputParser
|
6
6
|
def parse_input(args_and_opts, signature)
|
7
|
+
args_and_opts = args_and_opts.map do |arg|
|
8
|
+
idx = 0
|
9
|
+
idx += 1 while arg[idx..].start_with?("-") && idx < arg.length
|
10
|
+
part_to_replace = arg[idx..].gsub("-", "_")
|
11
|
+
arg[0...idx] + part_to_replace
|
12
|
+
end
|
13
|
+
|
7
14
|
input = {}
|
8
15
|
pos_args = []
|
16
|
+
allowed_options = signature.allowed_options
|
9
17
|
args_and_opts.each do |arg|
|
10
|
-
break if
|
18
|
+
break if allowed_options.include?(arg)
|
11
19
|
|
12
20
|
pos_args << arg
|
13
21
|
end
|
@@ -19,32 +27,20 @@ module InputParser
|
|
19
27
|
input[arg.name] = load_input arg.type, val if arg
|
20
28
|
end
|
21
29
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
if signature_opt.required?
|
35
|
-
opt.on(*aliases, "--#{name} #{name.upcase}") do |v|
|
36
|
-
input[name] = load_input signature.opts[name].type, v
|
37
|
-
end
|
38
|
-
else
|
39
|
-
opt.on(*aliases, "--#{name}") do |v|
|
40
|
-
input[name] = load_input signature.opts[name].type, v
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
opt.on("--h", "--help", "Prints this help") do
|
45
|
-
input[:help] = true
|
30
|
+
prev_opt_name = nil
|
31
|
+
allowed_option_to_name = signature.allowed_option_to_name
|
32
|
+
opts.each do |opt|
|
33
|
+
if allowed_options.include?(opt)
|
34
|
+
prev_opt_name = allowed_option_to_name[opt]
|
35
|
+
input[prev_opt_name] = true
|
36
|
+
elsif input[prev_opt_name] == true
|
37
|
+
input[prev_opt_name] = load_input signature.opts[prev_opt_name].type, opt
|
38
|
+
prev_opt_name = nil
|
39
|
+
else
|
40
|
+
raise ArgumentError, "Can't parse #{opt} option"
|
46
41
|
end
|
47
|
-
end
|
42
|
+
end
|
43
|
+
|
48
44
|
input
|
49
45
|
end
|
50
46
|
end
|
@@ -16,8 +16,10 @@ module ResultObtainer
|
|
16
16
|
end
|
17
17
|
|
18
18
|
signature.opts.each do |opt_name, opt|
|
19
|
+
next if opt.exec_skip
|
20
|
+
|
19
21
|
if opt.required?
|
20
|
-
keyword_values[opt_name] = input[opt_name]
|
22
|
+
keyword_values[opt_name] = input[opt_name] if input.key?(opt_name)
|
21
23
|
else
|
22
24
|
keyword_values[opt_name] = input[opt_name] unless input[opt_name].nil?
|
23
25
|
end
|
@@ -25,6 +27,8 @@ module ResultObtainer
|
|
25
27
|
|
26
28
|
default_opts = signature.default_opts
|
27
29
|
default_opts.each do |opt_name, opt|
|
30
|
+
next if signature.opts[opt_name].exec_skip
|
31
|
+
|
28
32
|
keyword_values[opt_name] = opt unless keyword_values.key?(opt_name) || opt == :unknown
|
29
33
|
end
|
30
34
|
|
@@ -33,9 +33,9 @@ module Base
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
OptSignature = Struct.new(*BaseSignatureStruct.members, :aliases) do
|
36
|
+
OptSignature = Struct.new(*BaseSignatureStruct.members, :aliases, :exec_skip) do
|
37
37
|
include BaseSignature
|
38
|
-
def initialize(name:, type: :string, default: :none, desc: nil, aliases: [])
|
38
|
+
def initialize(name:, type: :string, default: :none, desc: nil, aliases: [], exec_skip: false)
|
39
39
|
super
|
40
40
|
end
|
41
41
|
end
|
@@ -10,7 +10,16 @@ class CliSignature
|
|
10
10
|
def initialize
|
11
11
|
@args = {}
|
12
12
|
@args_arr = []
|
13
|
-
@opts = {
|
13
|
+
@opts = {
|
14
|
+
help: Base::OptSignature.new(
|
15
|
+
name: :help,
|
16
|
+
type: :bool,
|
17
|
+
desc: "Prints this help message",
|
18
|
+
aliases: %w[-h],
|
19
|
+
default: false,
|
20
|
+
exec_skip: true
|
21
|
+
)
|
22
|
+
}
|
14
23
|
@description = nil
|
15
24
|
@help = nil
|
16
25
|
end
|
@@ -49,7 +58,6 @@ class CliSignature
|
|
49
58
|
unless @opts.empty?
|
50
59
|
@help += "\nOptions:\n"
|
51
60
|
@opts.each do |name, option|
|
52
|
-
name = "[no-]#{name}" if option.type == :bool
|
53
61
|
opt_part = " #{option.required? ? "--#{name}" : "[--#{name}]"}"
|
54
62
|
if option.aliases && !option.aliases.empty?
|
55
63
|
aliases = option.aliases.join(", ")
|
@@ -64,8 +72,6 @@ class CliSignature
|
|
64
72
|
|
65
73
|
@help += "\nUsage: #{program_name} [arguments] [options]"
|
66
74
|
|
67
|
-
@help += "\nUse --h, --help to print this help message.\n"
|
68
|
-
|
69
75
|
@help
|
70
76
|
end
|
71
77
|
|
@@ -108,4 +114,26 @@ class CliSignature
|
|
108
114
|
end
|
109
115
|
args
|
110
116
|
end
|
117
|
+
|
118
|
+
def allowed_options
|
119
|
+
if @allowed_options.nil?
|
120
|
+
@allowed_options = Set.new
|
121
|
+
@allowed_option_to_name = {}
|
122
|
+
@opts.each_value do |opt|
|
123
|
+
long_opt = "--#{opt.name}"
|
124
|
+
@allowed_options.add(long_opt)
|
125
|
+
@allowed_option_to_name[long_opt] = opt.name
|
126
|
+
opt.aliases.each do |alias_|
|
127
|
+
@allowed_options.add(alias_)
|
128
|
+
@allowed_option_to_name[alias_] = opt.name
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
@allowed_options
|
133
|
+
end
|
134
|
+
|
135
|
+
def allowed_option_to_name
|
136
|
+
allowed_options if @allowed_option_to_name.nil?
|
137
|
+
@allowed_option_to_name
|
138
|
+
end
|
111
139
|
end
|
@@ -5,14 +5,28 @@ module BaseCli
|
|
5
5
|
include ResultObtainer
|
6
6
|
|
7
7
|
def start(args = ARGV)
|
8
|
-
input =
|
8
|
+
input = parse_args_by_signature args
|
9
|
+
return if input.nil?
|
9
10
|
|
11
|
+
print_result run_instance input
|
12
|
+
end
|
13
|
+
|
14
|
+
def start_raw(args)
|
15
|
+
input = parse_args_by_signature args
|
16
|
+
return if input.nil?
|
17
|
+
|
18
|
+
run_instance input
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_args_by_signature(args)
|
22
|
+
parse_input args, @signature
|
23
|
+
end
|
24
|
+
|
25
|
+
def run_instance(input)
|
10
26
|
if input[:help]
|
11
|
-
|
12
|
-
return
|
27
|
+
return @signature.help
|
13
28
|
end
|
14
|
-
|
15
|
-
print_result call_method_with_args @signature, @method, input
|
29
|
+
call_method_with_args @signature, @method, input
|
16
30
|
end
|
17
31
|
|
18
32
|
def print_help
|
data/lib/clino/interfaces/cli.rb
CHANGED
@@ -8,7 +8,14 @@ require_relative "base/base_cli"
|
|
8
8
|
|
9
9
|
class Cli
|
10
10
|
class << self
|
11
|
-
attr_reader :
|
11
|
+
attr_reader :description
|
12
|
+
def opt_buffer
|
13
|
+
@opt_buffer || {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def arg_buffer
|
17
|
+
@arg_buffer || {}
|
18
|
+
end
|
12
19
|
|
13
20
|
def desc(description)
|
14
21
|
@description = description
|
@@ -16,8 +23,7 @@ class Cli
|
|
16
23
|
|
17
24
|
def opt(name, type: :string, desc: nil, aliases: [], default: :none)
|
18
25
|
@opt_buffer ||= {}
|
19
|
-
|
20
|
-
aliases = aliases.map { |a| "-#{bool_prefix}#{general_strip a, "-"}" }
|
26
|
+
aliases = aliases.map { |a| "-#{general_strip a, "-"}" }
|
21
27
|
default = load_input type, default unless default == :none
|
22
28
|
@opt_buffer[name] = Base::OptSignature.new(name: name, type: type, default: default, desc: desc,
|
23
29
|
aliases: aliases)
|
@@ -39,7 +45,7 @@ class Cli
|
|
39
45
|
end
|
40
46
|
|
41
47
|
@signature.opts.each_key do |name|
|
42
|
-
@signature.add_opt(self.class.opt_buffer[name])
|
48
|
+
@signature.add_opt(self.class.opt_buffer[name]) if self.class.opt_buffer.key? name
|
43
49
|
end
|
44
50
|
|
45
51
|
@signature.description = self.class.description
|
data/lib/clino/interfaces/min.rb
CHANGED
data/lib/clino/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: clino
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tikhon Zaikin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-02-
|
11
|
+
date: 2024-02-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |-
|
14
14
|
clino is a minimalistic CLI generator
|