clino 0.1.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b5da44c716b390337107099e942d034e182f87d0c201db938ce33edb25afec00
4
- data.tar.gz: aab08f2034e3334083e04f85073a7e3762eaa095a64c5514107e3ddb5899a4e9
3
+ metadata.gz: df8da7e0b98d842743ff6574a23b88f48382faa9ccc218734b9696db55758799
4
+ data.tar.gz: ec26f662643aa566eaf2572d79a0d50dbb96a1d23550899329967a3299708b1f
5
5
  SHA512:
6
- metadata.gz: b0a9cb88be968997e96874262e24adb6a6d005babec72d6c797ba6871f5f0f1cfc6d76dffd3a2fc05ac4a88d10ab5182d468a80f746dfdfcebc3622122952e09
7
- data.tar.gz: 65354f82b88c9bf681233a6e062aa7c83b848f09c6866f1c3dc51ce48352f707d8699834363ca604d69102b291adecd6f9220fe6526e0ff7a8d13801c3079d2e
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 tikhon.zaikin@ematiq.com. All complaints will be reviewed and investigated promptly and fairly.
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
@@ -48,14 +48,10 @@ Let's write a simple script that takes a name as an argument and prints a greeti
48
48
 
49
49
  require "clino/interfaces/min"
50
50
 
51
- def hello(name)
52
- "Hello, #{name}!"
53
- end
54
-
55
- Min.new(:hello).start
51
+ Min.new(->(name) { "Hello, #{name}!" }).start
56
52
  ```
57
53
 
58
- Writing method containing only business logic is enough, as the input and output handling is done by the `Min` interface.
54
+ Writing lambda containing only business logic is enough, as the input and output handling is done by the `Min` interface.
59
55
 
60
56
  Run the script with the following command:
61
57
 
@@ -72,7 +68,7 @@ ruby hello.rb --help
72
68
  or
73
69
 
74
70
  ```bash
75
- ruby hello.rb --h
71
+ ruby hello.rb -h
76
72
  ```
77
73
 
78
74
  It will print the following output:
@@ -85,7 +81,6 @@ Arguments:
85
81
  <name> [string]
86
82
 
87
83
  Usage: hello.rb [arguments] [options]
88
- Use --h, --help to print this help message.
89
84
  ```
90
85
  #### Randomizer Minimalistic Example
91
86
 
@@ -140,7 +135,7 @@ ruby min_randomizer.rb --help
140
135
  or
141
136
 
142
137
  ```bash
143
- ruby min_randomizer.rb --h
138
+ ruby min_randomizer.rb -h
144
139
  ```
145
140
 
146
141
  It will print the following output:
@@ -163,7 +158,6 @@ Options:
163
158
  [--incl] [string] [default: unknown]
164
159
 
165
160
  Usage: min_randomizer.rb [arguments] [options]
166
- Use --h, --help to print this help message.
167
161
  ```
168
162
 
169
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.
@@ -232,7 +226,7 @@ ruby randomizer.rb --help
232
226
  or
233
227
 
234
228
  ```bash
235
- ruby randomizer.rb --h
229
+ ruby randomizer.rb -h
236
230
  ```
237
231
 
238
232
  It will print the following output:
@@ -260,7 +254,6 @@ Options:
260
254
  [--incl] (-i) [bool] [default: false]
261
255
 
262
256
  Usage: randomizer.rb [arguments] [options]
263
- Use --h, --help to print this help message.
264
257
  ```
265
258
 
266
259
  As we can see, all the default values, helping notes, and types are written out, and the input validation is handled automatically.
@@ -314,7 +307,6 @@ Arguments:
314
307
  <height> [positive_integer]
315
308
 
316
309
  Usage: weight_calculator.rb [arguments] [options]
317
- Use --h, --help to print this help message.
318
310
  ```
319
311
 
320
312
  ## Improvements
@@ -6,3 +6,8 @@ def general_strip(str, substring = " ")
6
6
  str = str[0...-substring_len] while str.end_with?(substring)
7
7
  str
8
8
  end
9
+
10
+ def is_callable_with_parameters?(arg)
11
+ # Check if the argument is callable
12
+ arg.respond_to?(:call) && arg.parameters
13
+ end
@@ -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 arg.start_with?("--")
18
+ break if allowed_options.include?(arg)
11
19
 
12
20
  pos_args << arg
13
21
  end
@@ -19,25 +27,20 @@ module InputParser
19
27
  input[arg.name] = load_input arg.type, val if arg
20
28
  end
21
29
 
22
- OptionParser.new do |opt|
23
- signature.opts.each_key do |name|
24
- signature_opt = signature.opts[name]
25
- aliases = signature_opt.aliases
26
-
27
- if signature_opt.required?
28
- opt.on(*aliases, "--#{name} #{name.upcase}") do |v|
29
- input[name] = load_input signature.opts[name].type, v
30
- end
31
- else
32
- opt.on(*aliases, "--#{name}") do |v|
33
- input[name] = load_input signature.opts[name].type, v
34
- end
35
- end
36
- end
37
- opt.on("--h", "--help", "Prints this help") do
38
- 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"
39
41
  end
40
- end.parse!(opts)
42
+ end
43
+
41
44
  input
42
45
  end
43
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
@@ -63,8 +72,6 @@ class CliSignature
63
72
 
64
73
  @help += "\nUsage: #{program_name} [arguments] [options]"
65
74
 
66
- @help += "\nUse --h, --help to print this help message.\n"
67
-
68
75
  @help
69
76
  end
70
77
 
@@ -107,4 +114,26 @@ class CliSignature
107
114
  end
108
115
  args
109
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
110
139
  end
@@ -5,14 +5,28 @@ module BaseCli
5
5
  include ResultObtainer
6
6
 
7
7
  def start(args = ARGV)
8
- input = parse_input args, @signature
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
- print_help
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
@@ -8,7 +8,14 @@ require_relative "base/base_cli"
8
8
 
9
9
  class Cli
10
10
  class << self
11
- attr_reader :opt_buffer, :arg_buffer, :description
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,7 +23,7 @@ class Cli
16
23
 
17
24
  def opt(name, type: :string, desc: nil, aliases: [], default: :none)
18
25
  @opt_buffer ||= {}
19
- aliases = aliases.map { |a| "--#{general_strip a, "-"}" }
26
+ aliases = aliases.map { |a| "-#{general_strip a, "-"}" }
20
27
  default = load_input type, default unless default == :none
21
28
  @opt_buffer[name] = Base::OptSignature.new(name: name, type: type, default: default, desc: desc,
22
29
  aliases: aliases)
@@ -38,7 +45,7 @@ class Cli
38
45
  end
39
46
 
40
47
  @signature.opts.each_key do |name|
41
- @signature.add_opt(self.class.opt_buffer[name])
48
+ @signature.add_opt(self.class.opt_buffer[name]) if self.class.opt_buffer.key? name
42
49
  end
43
50
 
44
51
  @signature.description = self.class.description
@@ -13,7 +13,7 @@ class Min
13
13
 
14
14
  def initialize(command)
15
15
  @method = method command if command.is_a? Symbol
16
- @method = command if command.is_a? Method
16
+ @method = command if is_callable_with_parameters? command
17
17
 
18
18
  @signature = CliSignature.from_func @method
19
19
  end
data/lib/clino/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Clino
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.3"
5
5
  end
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.2
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 00:00:00.000000000 Z
11
+ date: 2024-02-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  clino is a minimalistic CLI generator