eac_cli 0.12.1 → 0.12.6

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: 7c53ada4b4424ae6524aa6da440544f272018b710e14ebba991c996b4d65e2cc
4
- data.tar.gz: f18ae2d075696710f1b8322aeab9eca055cf0ff38ba57a3aeab86af32f7bf370
3
+ metadata.gz: e9465f0f0d648395bb6616a208f830034405eaed91e6d186f8235cd2b0ea28a6
4
+ data.tar.gz: efd2ab2ad3737f7f12577908cc3c0bda2fbead8ddaa99ae671c72162a3f63bb3
5
5
  SHA512:
6
- metadata.gz: 617c16d42f00d801b0ddcea18719a9d4c898158641a597d66510f068119b76264520b7393d897d105bf21ddcff0691bb0030090daec589af547935c205685a69
7
- data.tar.gz: 64e942e6118081a385f4df9374edcf5770005f463837ffaa9d00024ab21568ab63bfdcd5740183dfd9dcffbec636fbd814ac839618540a10d8d15559154c0e18
6
+ metadata.gz: 88e58527420ebd47d4de3684bdd6d2c18eb6b5b1be87c33043b0d3951d924265d44b9108feed7f3c0cd236ef11546ecf188c2a1c0de0ab73e0b4740c2df63287
7
+ data.tar.gz: 45fb719847efcade7e5c56b015ebd8aefce718d109f11aebb97f7645a681ec5ed53358a3a7beebc63019b77e3847b2be69421e1b9b8bcaacbf7682ecaafdec20
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'eac_ruby_utils/core_ext'
4
+
5
+ module EacCli
6
+ module Docopt
7
+ class RunnerContextReplacement
8
+ common_constructor :runner
9
+
10
+ def argv
11
+ runner.settings[:argv] || ARGV
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'eac_cli/docopt/doc_builder'
4
+ require 'eac_cli/docopt/runner_context_replacement'
4
5
  require 'eac_cli/runner'
5
6
  require 'eac_ruby_utils/console/docopt_runner'
6
7
 
@@ -32,6 +33,10 @@ module EacCli
32
33
  def docopt_options
33
34
  super.merge(options_first: self.class.runner_definition.options_first?)
34
35
  end
36
+
37
+ def runner_context
38
+ @runner_context ||= ::EacCli::Docopt::RunnerContextReplacement.new(self)
39
+ end
35
40
  end
36
41
 
37
42
  def extra_available_subcommands
@@ -12,12 +12,14 @@ module EacCli
12
12
 
13
13
  def parsed_uncached
14
14
  raise 'Definition has no alternatives' if alternatives.empty?
15
+ raise first_error unless alternatives.select(&:success?).any?
15
16
 
16
- alternatives.each do |alt_parser|
17
- return alt_parser.parsed unless alt_parser.error?
18
- end
17
+ alternatives_parsed(true).merge(alternatives_parsed(false))
18
+ end
19
19
 
20
- raise first_error
20
+ def alternatives_parsed(error)
21
+ alternatives.select { |a| error == a.error? }.map(&:parsed).reverse
22
+ .inject(::EacRubyUtils::Struct.new) { |a, e| a.merge(e) }
21
23
  end
22
24
 
23
25
  def alternatives_uncached
@@ -22,6 +22,10 @@ module EacCli
22
22
  error.present?
23
23
  end
24
24
 
25
+ def success?
26
+ !error?
27
+ end
28
+
25
29
  def parsed
26
30
  @parsed ||= collector.to_data.freeze
27
31
  end
@@ -31,11 +35,11 @@ module EacCli
31
35
  attr_accessor :phase
32
36
 
33
37
  def any_collect_argv_value
34
- if argv_current_option?
35
- option_collect_argv_value
36
- else
37
- positional_collect_argv_value
38
+ %w[double_dash long_option short_option].each do |arg_type|
39
+ return send("#{arg_type}_collect_argv_value") if send("argv_current_#{arg_type}?")
38
40
  end
41
+
42
+ positional_collect_argv_value
39
43
  end
40
44
 
41
45
  def collector
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacCli
4
+ class Parser
5
+ class Alternative
6
+ module LongOptions
7
+ LONG_OPTION_PREFIX = '--'
8
+ OPTION_WITH_ARGUMENT_PATTERN = /\A([^=]+)(?:=(.*))\z/.freeze
9
+
10
+ private
11
+
12
+ def argv_current_long_option?
13
+ phase == PHASE_ANY && argv_enum.peek.start_with?(LONG_OPTION_PREFIX) &&
14
+ !argv_current_double_dash?
15
+ end
16
+
17
+ def long_option_collect_argv_value
18
+ option_long, value = parse_option_current_argv
19
+ alternative.options.any? do |option|
20
+ next false unless option.long == option_long
21
+
22
+ if value.nil?
23
+ option_collect_option(option)
24
+ else
25
+ option_argument_collect(option, value)
26
+ end
27
+ end || raise_argv_current_invalid_option
28
+ end
29
+
30
+ def parse_option_current_argv
31
+ m = OPTION_WITH_ARGUMENT_PATTERN.match(argv_enum.peek)
32
+ m ? [m[1], m[2].if_present('')] : [argv_enum.peek, nil]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacCli
4
+ class Parser
5
+ class Alternative
6
+ module OptionArgument
7
+ private
8
+
9
+ attr_accessor :argument_option
10
+
11
+ def argument_option_collect_argv(option)
12
+ self.argument_option = option
13
+ self.phase = PHASE_OPTION_ARGUMENT
14
+ end
15
+
16
+ def option_argument_collect(option, value)
17
+ collector.collect(option, value)
18
+ self.argument_option = nil
19
+ self.phase = PHASE_ANY
20
+ option
21
+ end
22
+
23
+ def option_argument_collect_argv_value
24
+ option_argument_collect(argument_option, argv_enum.peek)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -4,49 +4,20 @@ module EacCli
4
4
  class Parser
5
5
  class Alternative
6
6
  module Options
7
- DOUBLE_DASH = '--'
8
-
9
7
  private
10
8
 
11
- attr_accessor :argument_option, :double_dash
12
-
13
- def argument_option_collect_argv(option)
14
- self.argument_option = option
15
- self.phase = PHASE_OPTION_ARGUMENT
16
- end
17
-
18
- def argv_current_option?
19
- phase == PHASE_ANY && argv_enum.peek.start_with?('-')
20
- end
21
-
22
- def argv_current_double_dash?
23
- argv_enum.peek == DOUBLE_DASH && !double_dash
24
- end
25
-
26
9
  def boolean_option_collect_argv(option)
27
10
  collector.collect(option, true)
28
11
  end
29
12
 
30
- def option_argument_collect_argv_value
31
- collector.collect(argument_option, argv_enum.peek)
32
- self.argument_option = nil
33
- self.phase = PHASE_ANY
34
- end
35
-
36
- def option_collect_argv_value
37
- return double_dash_collect_argv_value if argv_current_double_dash?
38
-
39
- alternative.options.any? do |option|
40
- next false unless [option.short, option.long].include?(argv_enum.peek)
41
-
42
- if option.argument?
43
- argument_option_collect_argv(option)
44
- else
45
- boolean_option_collect_argv(option)
46
- end
13
+ def option_collect_option(option)
14
+ if option.argument?
15
+ argument_option_collect_argv(option)
16
+ else
17
+ boolean_option_collect_argv(option)
18
+ end
47
19
 
48
- true
49
- end || raise_argv_current_invalid_option
20
+ option
50
21
  end
51
22
 
52
23
  def raise_argv_current_invalid_option
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacCli
4
+ class Parser
5
+ class Alternative
6
+ module ShortOptions
7
+ SHORT_OPTION_PREFIX = '-'
8
+
9
+ private
10
+
11
+ def argv_current_short_option?
12
+ phase == PHASE_ANY && argv_enum.peek.start_with?(SHORT_OPTION_PREFIX) &&
13
+ !argv_current_long_option?
14
+ end
15
+
16
+ def find_short_option(char)
17
+ alternative.options.find { |option| short_without_prefix(option.short) == char }
18
+ end
19
+
20
+ def short_option_collect_argv_value
21
+ last_option = nil
22
+ short_without_prefix(argv_enum.peek).each_char do |char|
23
+ raise_error "Option \"#{last_option}\" requires a argument not provided" if
24
+ last_option.present?
25
+
26
+ collected_option = short_option_collect_char(char)
27
+ last_option = collected_option if collected_option.argument?
28
+ end
29
+ end
30
+
31
+ # @return [EacCli::Definition::BaseOption] The option collected.
32
+ def short_option_collect_char(char)
33
+ option = find_short_option(char)
34
+ raise_error "Invalid short option \"#{char}\"" unless option
35
+
36
+ option_collect_option(option)
37
+ end
38
+
39
+ def short_without_prefix(short)
40
+ short.gsub(/\A#{::Regexp.quote(SHORT_OPTION_PREFIX)}/, '')
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -44,48 +44,8 @@ module EacCli
44
44
  extend AfterClassMethods
45
45
  include InstanceMethods
46
46
  ::EacCli::Docopt::RunnerExtension.check(self)
47
- end
48
-
49
- module AfterClassMethods
50
- def create(*runner_context_args)
51
- r = new
52
- r.runner_context = ::EacCli::Runner::Context.new(r, *runner_context_args)
53
- r
54
- end
55
-
56
- def run(*runner_context_args)
57
- r = create(*runner_context_args)
58
- r.parsed
59
- r.run
60
- r
61
- end
62
-
63
- def runner_definition(&block)
64
- @runner_definition ||= super_runner_definition
65
- @runner_definition.instance_eval(&block) if block
66
- @runner_definition
67
- end
68
-
69
- def super_runner_definition
70
- superclass.try(:runner_definition).if_present(&:dup) || ::EacCli::Definition.new
71
- end
72
- end
73
-
74
- module InstanceMethods
75
- def runner_context
76
- return @runner_context if @runner_context
77
-
78
- raise 'Context was required, but was not set yet'
79
- end
80
-
81
- def runner_context=(new_runner_context)
82
- @runner_context = new_runner_context
83
- @parsed = nil
84
- end
85
-
86
- def parsed
87
- @parsed ||= ::EacCli::Parser.new(self.class.runner_definition, runner_context.argv).parsed
88
- end
47
+ include ActiveSupport::Callbacks
48
+ define_callbacks :run
89
49
  end
90
50
  end
91
51
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacCli
4
+ module Runner
5
+ module AfterClassMethods
6
+ def create(*runner_context_args)
7
+ r = new
8
+ r.runner_context = ::EacCli::Runner::Context.new(r, *runner_context_args)
9
+ r
10
+ end
11
+
12
+ def run(*runner_context_args)
13
+ r = create(*runner_context_args)
14
+ r.run_run
15
+ r
16
+ end
17
+
18
+ def runner_definition(&block)
19
+ @runner_definition ||= super_runner_definition
20
+ @runner_definition.instance_eval(&block) if block
21
+ @runner_definition
22
+ end
23
+
24
+ def super_runner_definition
25
+ superclass.try(:runner_definition).if_present(&:dup) || ::EacCli::Definition.new
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacCli
4
+ module Runner
5
+ class Exit < ::StandardError
6
+ attr_reader :status
7
+
8
+ def initialize(status = true)
9
+ @status = status
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EacCli
4
+ module Runner
5
+ module InstanceMethods
6
+ def run_run
7
+ parsed
8
+ run_callbacks(:run) { run }
9
+ rescue ::EacCli::Parser::Error => e
10
+ $stderr.write("#{e}\n")
11
+ rescue ::EacCli::Runner::Exit # rubocop:disable Lint/SuppressedException
12
+ # Do nothing
13
+ end
14
+
15
+ def runner_context
16
+ return @runner_context if @runner_context
17
+
18
+ raise 'Context was required, but was not set yet'
19
+ end
20
+
21
+ def runner_context=(new_runner_context)
22
+ @runner_context = new_runner_context
23
+ @parsed = nil
24
+ end
25
+
26
+ def parsed
27
+ @parsed ||= ::EacCli::Parser.new(self.class.runner_definition, runner_context.argv).parsed
28
+ end
29
+ end
30
+ end
31
+ end
@@ -13,6 +13,23 @@ module EacCli
13
13
  options_argument false
14
14
  bool_opt '-h', '--help', 'Show help.', usage: true
15
15
  end
16
+
17
+ set_callback :run, :before do
18
+ help_run
19
+ end
20
+ end
21
+
22
+ def help_run
23
+ return unless parsed.help?
24
+
25
+ puts help_text
26
+ raise ::EacCli::Runner::Exit
27
+ end
28
+
29
+ def help_text
30
+ r = ::EacCli::Docopt::DocBuilder.new(self.class.runner_definition).to_s
31
+ r += help_extra_text if respond_to?(:help_extra_text)
32
+ r
16
33
  end
17
34
  end
18
35
  end
@@ -2,12 +2,16 @@
2
2
 
3
3
  require 'eac_cli/runner'
4
4
  require 'eac_ruby_utils/core_ext'
5
+ require 'eac_ruby_utils/abstract_methods'
5
6
 
6
7
  module EacCli
7
8
  module RunnerWith
8
9
  module OutputFile
9
10
  common_concern do
10
11
  include ::EacCli::Runner
12
+ include ::EacRubyUtils::AbstractMethods
13
+
14
+ abstract_methods :output_content
11
15
 
12
16
  runner_definition do
13
17
  arg_opt '-o', '--output-file', 'Output to file.'
@@ -18,7 +22,7 @@ module EacCli
18
22
  if parsed.output_file.present?
19
23
  ::File.write(parsed.output_file, output_content)
20
24
  else
21
- out output_content
25
+ $stdout.write(output_content)
22
26
  end
23
27
  end
24
28
  end
@@ -6,6 +6,14 @@ require 'eac_ruby_utils/core_ext'
6
6
  module EacCli
7
7
  module RunnerWith
8
8
  module Subcommands
9
+ class << self
10
+ def runner?(object)
11
+ ::EacCli::Runner.runner?(object) || (
12
+ object.is_a?(::Class) && object < ::EacRubyUtils::Console::DocoptRunner
13
+ )
14
+ end
15
+ end
16
+
9
17
  common_concern do
10
18
  include ::EacCli::Runner
11
19
  end
@@ -19,7 +27,7 @@ module EacCli
19
27
  def available_subcommands_auto
20
28
  self.class.constants
21
29
  .map { |name| [name.to_s.underscore.gsub('_', '-'), self.class.const_get(name)] }
22
- .select { |c| ::EacCli::Runner.runner?(c[1]) }
30
+ .select { |c| ::EacCli::RunnerWith::Subcommands.runner?(c[1]) }
23
31
  .to_h.with_indifferent_access
24
32
  end
25
33
 
@@ -31,6 +39,11 @@ module EacCli
31
39
  end
32
40
  end
33
41
 
42
+ def help_extra_text
43
+ (['Subcommands:'] + available_subcommands.keys.sort.map { |s| " #{s}" })
44
+ .map { |v| "#{v}\n" }.join
45
+ end
46
+
34
47
  def method_missing(method_name, *arguments, &block)
35
48
  return run_with_subcommand(*arguments, &block) if
36
49
  run_with_subcommand_alias_run?(method_name)
@@ -44,7 +57,11 @@ module EacCli
44
57
 
45
58
  def run_with_subcommand
46
59
  if subcommand_name
47
- subcommand_runner.run
60
+ if subcommand_runner.respond_to?(:run_run)
61
+ subcommand_runner.run_run
62
+ else
63
+ subcommand_runner.run
64
+ end
48
65
  else
49
66
  run_without_subcommand
50
67
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EacCli
4
- VERSION = '0.12.1'
4
+ VERSION = '0.12.6'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eac_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 0.12.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esquilo Azul Company
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-03 00:00:00.000000000 Z
11
+ date: 2021-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: eac_ruby_utils
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.50'
19
+ version: '0.55'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.50'
26
+ version: '0.55'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: eac_ruby_gem_support
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -63,20 +63,27 @@ files:
63
63
  - lib/eac_cli/definition/positional_argument.rb
64
64
  - lib/eac_cli/docopt/doc_builder.rb
65
65
  - lib/eac_cli/docopt/doc_builder/alternative.rb
66
+ - lib/eac_cli/docopt/runner_context_replacement.rb
66
67
  - lib/eac_cli/docopt/runner_extension.rb
67
68
  - lib/eac_cli/parser.rb
68
69
  - lib/eac_cli/parser/alternative.rb
69
70
  - lib/eac_cli/parser/alternative/argv.rb
70
71
  - lib/eac_cli/parser/alternative/double_dash.rb
72
+ - lib/eac_cli/parser/alternative/long_options.rb
73
+ - lib/eac_cli/parser/alternative/option_argument.rb
71
74
  - lib/eac_cli/parser/alternative/options.rb
72
75
  - lib/eac_cli/parser/alternative/positionals.rb
76
+ - lib/eac_cli/parser/alternative/short_options.rb
73
77
  - lib/eac_cli/parser/collector.rb
74
78
  - lib/eac_cli/parser/error.rb
75
79
  - lib/eac_cli/patches.rb
76
80
  - lib/eac_cli/patches/object.rb
77
81
  - lib/eac_cli/patches/object/runner_with.rb
78
82
  - lib/eac_cli/runner.rb
83
+ - lib/eac_cli/runner/after_class_methods.rb
79
84
  - lib/eac_cli/runner/context.rb
85
+ - lib/eac_cli/runner/exit.rb
86
+ - lib/eac_cli/runner/instance_methods.rb
80
87
  - lib/eac_cli/runner_with.rb
81
88
  - lib/eac_cli/runner_with/help.rb
82
89
  - lib/eac_cli/runner_with/output_file.rb