simple-cli 0.2.18 → 0.2.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 878de3c5c0b5d23d08e6cfe44d511fd68b0e41493f44e056d2936e456f2d56cf
4
- data.tar.gz: 69cabfc40adca2cc0a20a64dfe41f2feab5b892ad43dfe98ce84e3a60b21345d
3
+ metadata.gz: 7ad5562abdf4690d3ba8a6733c0669f42cdffe673c9a9833f1e4d8e43c4d048b
4
+ data.tar.gz: 1ab4c259ffb2372efd1caaf6aed9b5df6e634cfa849b7fd22d071c00e87179fc
5
5
  SHA512:
6
- metadata.gz: 8ba516fa41c773609493db0b26aaca5074547e42c7b62db8aaf200165384c1134f25af92b08949dc4d945e5568b025db6ca0c25bea56b9497eaab6972e37d59d
7
- data.tar.gz: 21c7e58196d8289c52119b32888bd505ceeef48b7233a8ed1b67f86963f5f2e713e3e0112b64943e2eacee425ee83f1dbedd74b3ba8c08e60681303290ebf72c
6
+ metadata.gz: 4d821d8d77506188106ad50627f7336569a61cd07dc60ace53697c6d7d2cd8ce6ce63a881b69454e0f791ae3c771dd91cf36a07e2e2b3b39c2e5da393f17093c
7
+ data.tar.gz: 7e2d94b98fa2f5e068a91869da0624891a271ea320845719b08196fd25b3f87137f6958cf3dba66fa8b24144daaff018e3c70a19d8d6144b34188bb06deffc1a
@@ -2,6 +2,8 @@
2
2
  # rubocop:disable Metrics/CyclomaticComplexity
3
3
  # rubocop:disable Metrics/MethodLength
4
4
 
5
+ require_relative "./module_ex"
6
+
5
7
  class Simple::CLI::Runner::CommandHelp
6
8
  def self.option_names(app, subcommand)
7
9
  new(app, subcommand).option_names
@@ -9,10 +11,12 @@ class Simple::CLI::Runner::CommandHelp
9
11
  []
10
12
  end
11
13
 
12
- def initialize(mod, method)
13
- raise(ArgumentError, "#{method.inspect} should be a Symbol") unless method.is_a?(Symbol)
14
- @mod = mod
15
- @method = method
14
+ def initialize(mod, method_id)
15
+ raise(ArgumentError, "#{method_id.inspect} should be a Symbol") unless method_id.is_a?(Symbol)
16
+
17
+ @method_id = method_id
18
+ @method = mod.instance_method(@method_id)
19
+ @method_parameters_ex = mod.method_parameters_ex(@method_id)
16
20
  end
17
21
 
18
22
  # First line of the help as read from the method comments.
@@ -26,9 +30,7 @@ class Simple::CLI::Runner::CommandHelp
26
30
  end
27
31
 
28
32
  def option_names
29
- method = @mod.instance_method(@method)
30
-
31
- option_names = method.parameters.map do |mode, name|
33
+ option_names = @method_parameters_ex.map do |mode, name, _|
32
34
  case mode
33
35
  when :key then name
34
36
  when :keyreq then name
@@ -42,20 +44,27 @@ class Simple::CLI::Runner::CommandHelp
42
44
 
43
45
  # A help string constructed from the commands method signature.
44
46
  def interface(binary_name, command_name)
45
- method = @mod.instance_method(@method)
46
-
47
- options = []
48
- args = []
47
+ args = @method_parameters_ex.map do |mode, name|
48
+ case mode
49
+ when :req then "<#{name}>"
50
+ when :opt then "[ <#{name}> ]"
51
+ when :rest then "[ <#{name}> .. ]"
52
+ end
53
+ end.compact
49
54
 
50
- method.parameters.each do |mode, name|
55
+ options = @method_parameters_ex.map do |mode, name, default_value|
51
56
  case mode
52
- when :req then args << "<#{name}>"
53
- when :key then options << "[ --#{name}[=<#{name}>] ]"
54
- when :keyreq then options << "--#{name}[=<#{name}>]"
55
- when :opt then args << "[ <#{name}> ]"
56
- when :rest then args << "[ <#{name}> .. ]"
57
+ when :key then
58
+ case default_value
59
+ when false then "[ --#{name} ]"
60
+ when true then "[ --no-#{name} ]"
61
+ when nil then "[ --#{name}=<#{name}> ]"
62
+ else "[ --#{name}=#{default_value} ]"
63
+ end
64
+ when :keyreq then
65
+ "--#{name}=<#{name}>"
57
66
  end
58
- end
67
+ end.compact
59
68
 
60
69
  help = "#{binary_name} #{command_to_string(command_name)}"
61
70
  help << " #{options.join(' ')}" unless options.empty?
@@ -71,7 +80,7 @@ class Simple::CLI::Runner::CommandHelp
71
80
 
72
81
  def comments
73
82
  @comments ||= begin
74
- file, line = @mod.instance_method(@method).source_location
83
+ file, line = @method.source_location
75
84
  extract_comments(from: parsed_source(file), before_line: line)
76
85
  end
77
86
  end
@@ -0,0 +1,69 @@
1
+ # rubocop:disable Metrics/MethodLength
2
+ # rubocop:disable Metrics/AbcSize
3
+
4
+ class Module
5
+ #
6
+ # returns an array with entries like the following:
7
+ #
8
+ # [ :key, name, default_value ]
9
+ # [ :keyreq, name [, nil ] ]
10
+ # [ :req, name [, nil ] ]
11
+ # [ :opt, name [, nil ] ]
12
+ # [ :rest, name [, nil ] ]
13
+ #
14
+ def method_parameters_ex(method_id)
15
+ method = instance_method(method_id)
16
+ parameters = method.parameters
17
+
18
+ # method parameters with a :key mode are optional keyword arguments. We only
19
+ # support defaults for those - if there are none we abort here already.
20
+ keys = parameters.map { |mode, name| name if mode == :key }.compact
21
+ return parameters if keys.empty?
22
+
23
+ # We are now doing a fake call to the method, with a minimal viable set of
24
+ # arguments, to let the ruby runtime fill in default values for arguments.
25
+ # We do not, however, let the call complete. Instead we use a TracePoint to
26
+ # abort as soon as the method is called, and use the its binding to determine
27
+ # the default values.
28
+
29
+ fake_recipient = Object.new.extend(self)
30
+ fake_call_args = minimal_arguments(method)
31
+
32
+ trace_point = TracePoint.trace(:call) do |tp|
33
+ throw :received_fake_call, tp.binding if tp.defined_class == self && tp.method_id == method_id
34
+ end
35
+
36
+ bnd = catch(:received_fake_call) do
37
+ fake_recipient.send(method_id, *fake_call_args)
38
+ end
39
+
40
+ trace_point.disable
41
+
42
+ # extract default values from the received binding, and merge with the
43
+ # parameters array.
44
+ default_values = keys.each_with_object({}) do |key_parameter, hsh|
45
+ hsh[key_parameter] = bnd.local_variable_get(key_parameter)
46
+ end
47
+
48
+ parameters.map do |mode, name|
49
+ [mode, name, default_values[name]]
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ # returns a minimal Array of arguments, which is suitable for a call to the method
56
+ def minimal_arguments(method)
57
+ # Build an arguments array with holds all required parameters. The actual
58
+ # values for these arguments doesn't matter at all.
59
+ args = method.parameters.select { |mode, _name| mode == :req }
60
+
61
+ # Add a hash with all required keyword arguments
62
+ required_keyword_args = method.parameters.each_with_object({}) do |(mode, name), hsh|
63
+ hsh[name] = :anything if mode == :keyreq
64
+ end
65
+ args << required_keyword_args if required_keyword_args
66
+
67
+ args
68
+ end
69
+ end
@@ -1,5 +1,5 @@
1
1
  module Simple
2
2
  module CLI
3
- VERSION = "0.2.18"
3
+ VERSION = "0.2.19"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.18
4
+ version: 0.2.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - radiospiel
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-06-08 00:00:00.000000000 Z
12
+ date: 2019-07-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -89,6 +89,7 @@ files:
89
89
  - lib/simple/cli/runner.rb
90
90
  - lib/simple/cli/runner/autocompletion.rb
91
91
  - lib/simple/cli/runner/command_help.rb
92
+ - lib/simple/cli/runner/module_ex.rb
92
93
  - lib/simple/cli/version.rb
93
94
  - log/.gitkeep
94
95
  - simple-cli.gemspec
@@ -113,8 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
114
  - !ruby/object:Gem::Version
114
115
  version: '0'
115
116
  requirements: []
116
- rubyforge_project:
117
- rubygems_version: 2.7.6
117
+ rubygems_version: 3.0.2
118
118
  signing_key:
119
119
  specification_version: 4
120
120
  summary: Simple CLI builder for ruby