simple-cli 0.2.18 → 0.2.19

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: 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