command_kit 0.1.0.pre1

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.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.github/workflows/ruby.yml +29 -0
  4. data/.gitignore +7 -0
  5. data/.rspec +1 -0
  6. data/.yardopts +1 -0
  7. data/ChangeLog.md +29 -0
  8. data/Gemfile +14 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +283 -0
  11. data/Rakefile +23 -0
  12. data/command_kit.gemspec +60 -0
  13. data/gemspec.yml +14 -0
  14. data/lib/command_kit.rb +1 -0
  15. data/lib/command_kit/arguments.rb +161 -0
  16. data/lib/command_kit/arguments/argument.rb +111 -0
  17. data/lib/command_kit/arguments/argument_value.rb +81 -0
  18. data/lib/command_kit/arguments/usage.rb +6 -0
  19. data/lib/command_kit/colors.rb +355 -0
  20. data/lib/command_kit/command.rb +42 -0
  21. data/lib/command_kit/command_name.rb +95 -0
  22. data/lib/command_kit/commands.rb +299 -0
  23. data/lib/command_kit/commands/auto_load.rb +153 -0
  24. data/lib/command_kit/commands/auto_load/subcommand.rb +90 -0
  25. data/lib/command_kit/commands/auto_require.rb +138 -0
  26. data/lib/command_kit/commands/command.rb +12 -0
  27. data/lib/command_kit/commands/help.rb +43 -0
  28. data/lib/command_kit/commands/parent_command.rb +21 -0
  29. data/lib/command_kit/commands/subcommand.rb +51 -0
  30. data/lib/command_kit/console.rb +141 -0
  31. data/lib/command_kit/description.rb +89 -0
  32. data/lib/command_kit/env.rb +43 -0
  33. data/lib/command_kit/env/home.rb +71 -0
  34. data/lib/command_kit/env/path.rb +71 -0
  35. data/lib/command_kit/examples.rb +99 -0
  36. data/lib/command_kit/exception_handler.rb +55 -0
  37. data/lib/command_kit/help.rb +62 -0
  38. data/lib/command_kit/help/man.rb +125 -0
  39. data/lib/command_kit/inflector.rb +84 -0
  40. data/lib/command_kit/main.rb +103 -0
  41. data/lib/command_kit/options.rb +179 -0
  42. data/lib/command_kit/options/option.rb +171 -0
  43. data/lib/command_kit/options/option_value.rb +90 -0
  44. data/lib/command_kit/options/parser.rb +227 -0
  45. data/lib/command_kit/options/quiet.rb +53 -0
  46. data/lib/command_kit/options/usage.rb +6 -0
  47. data/lib/command_kit/options/verbose.rb +55 -0
  48. data/lib/command_kit/options/version.rb +62 -0
  49. data/lib/command_kit/os.rb +47 -0
  50. data/lib/command_kit/pager.rb +115 -0
  51. data/lib/command_kit/printing.rb +32 -0
  52. data/lib/command_kit/printing/indent.rb +78 -0
  53. data/lib/command_kit/program_name.rb +57 -0
  54. data/lib/command_kit/stdio.rb +138 -0
  55. data/lib/command_kit/usage.rb +102 -0
  56. data/lib/command_kit/version.rb +4 -0
  57. data/lib/command_kit/xdg.rb +138 -0
  58. data/spec/arguments/argument_spec.rb +169 -0
  59. data/spec/arguments/argument_value_spec.rb +126 -0
  60. data/spec/arguments_spec.rb +213 -0
  61. data/spec/colors_spec.rb +470 -0
  62. data/spec/command_kit_spec.rb +8 -0
  63. data/spec/command_name_spec.rb +130 -0
  64. data/spec/command_spec.rb +49 -0
  65. data/spec/commands/auto_load/subcommand_spec.rb +82 -0
  66. data/spec/commands/auto_load_spec.rb +128 -0
  67. data/spec/commands/auto_require_spec.rb +142 -0
  68. data/spec/commands/fixtures/test_auto_load/cli/commands/test1.rb +10 -0
  69. data/spec/commands/fixtures/test_auto_load/cli/commands/test2.rb +10 -0
  70. data/spec/commands/fixtures/test_auto_require/lib/test_auto_require/cli/commands/test1.rb +10 -0
  71. data/spec/commands/help_spec.rb +66 -0
  72. data/spec/commands/parent_command_spec.rb +40 -0
  73. data/spec/commands/subcommand_spec.rb +99 -0
  74. data/spec/commands_spec.rb +767 -0
  75. data/spec/console_spec.rb +201 -0
  76. data/spec/description_spec.rb +203 -0
  77. data/spec/env/home_spec.rb +46 -0
  78. data/spec/env/path_spec.rb +78 -0
  79. data/spec/env_spec.rb +123 -0
  80. data/spec/examples_spec.rb +235 -0
  81. data/spec/exception_handler_spec.rb +103 -0
  82. data/spec/help_spec.rb +119 -0
  83. data/spec/inflector_spec.rb +104 -0
  84. data/spec/main_spec.rb +179 -0
  85. data/spec/options/option_spec.rb +258 -0
  86. data/spec/options/option_value_spec.rb +67 -0
  87. data/spec/options/parser_spec.rb +265 -0
  88. data/spec/options_spec.rb +137 -0
  89. data/spec/os_spec.rb +46 -0
  90. data/spec/pager_spec.rb +154 -0
  91. data/spec/printing/indent_spec.rb +130 -0
  92. data/spec/printing_spec.rb +76 -0
  93. data/spec/program_name_spec.rb +62 -0
  94. data/spec/spec_helper.rb +6 -0
  95. data/spec/stdio_spec.rb +264 -0
  96. data/spec/usage_spec.rb +237 -0
  97. data/spec/xdg_spec.rb +191 -0
  98. metadata +156 -0
@@ -0,0 +1,53 @@
1
+ require 'command_kit/options'
2
+
3
+ module CommandKit
4
+ module Options
5
+ #
6
+ # Defines a `-q`,`--quiet` option.
7
+ #
8
+ # ## Examples
9
+ #
10
+ # include CommandKit::Options::Quiet
11
+ #
12
+ # def main(*argv)
13
+ # # ...
14
+ # puts "verbose output" unless quiet?
15
+ # # ...
16
+ # end
17
+ #
18
+ module Quiet
19
+ include Options
20
+
21
+ module ModuleMethods
22
+ #
23
+ # Defines a `-q, --quiet` option.
24
+ #
25
+ # @param [Class, Module] context
26
+ # The class or module including {Quiet}.
27
+ #
28
+ def included(context)
29
+ super(context)
30
+
31
+ if context.class == Module
32
+ context.extend ModuleMethods
33
+ else
34
+ context.option :quiet, short: '-q', desc: 'Enables quiet output' do
35
+ @quiet = true
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ extend ModuleMethods
42
+
43
+ #
44
+ # Determines if quiet mode is enabled.
45
+ #
46
+ # @return [Boolean]
47
+ #
48
+ def quiet?
49
+ @quiet
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,6 @@
1
+ module CommandKit
2
+ module Options
3
+ module Usage
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,55 @@
1
+ require 'command_kit/options'
2
+
3
+ module CommandKit
4
+ module Options
5
+ #
6
+ # Defines a `-v`,`--verbose` option.
7
+ #
8
+ # ## Examples
9
+ #
10
+ # include Options::Verbose
11
+ #
12
+ # def main(*argv)
13
+ # # ...
14
+ # puts "verbose output" if verbose?
15
+ # # ...
16
+ # end
17
+ #
18
+ module Verbose
19
+ include Options
20
+
21
+ module ModuleMethods
22
+ #
23
+ # Defines a `-v, --verbose` option or extends {ModuleMethods}, depending
24
+ # on whether {Options::Verbose} is being included into a class or a
25
+ # module.
26
+ #
27
+ # @param [Class, Module] context
28
+ # The class or module including {Verbose}.
29
+ #
30
+ def included(context)
31
+ super(context)
32
+
33
+ if context.class == Module
34
+ context.extend ModuleMethods
35
+ else
36
+ context.option :verbose, short: '-v', desc: 'Enables verbose output' do
37
+ @verbose = true
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ extend ModuleMethods
44
+
45
+ #
46
+ # Determines if verbose mode is enabled.
47
+ #
48
+ # @return [Boolean]
49
+ #
50
+ def verbose?
51
+ @verbose
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,62 @@
1
+ require 'command_kit/options'
2
+
3
+ module CommandKit
4
+ module Options
5
+ #
6
+ # Defines a version option.
7
+ #
8
+ module Version
9
+ #
10
+ # Includes {Options}, extends {Version::ClassMethods}, and defines a
11
+ # `-V, --version` option.
12
+ #
13
+ def self.included(command)
14
+ command.include Options
15
+ command.extend ClassMethods
16
+
17
+ command.option :version, short: '-V',
18
+ desc: 'Prints the version and exits' do
19
+ print_version
20
+ exit(0)
21
+ end
22
+ end
23
+
24
+ #
25
+ # Defines class-level methods.
26
+ #
27
+ module ClassMethods
28
+ #
29
+ # Gets or sets the version string.
30
+ #
31
+ # @param [String, nil] new_version
32
+ # If given a new version String, it will set the class'es version
33
+ # string.
34
+ #
35
+ # @return [String, nil]
36
+ # The classes version string.
37
+ #
38
+ def version(new_version=nil)
39
+ if new_version
40
+ @version = new_version
41
+ else
42
+ @version || (superclass.version if superclass.kind_of?(ClassMethods))
43
+ end
44
+ end
45
+ end
46
+
47
+ #
48
+ # @see ClassMethods#version
49
+ #
50
+ def version
51
+ self.class.version
52
+ end
53
+
54
+ #
55
+ # Prints the version.
56
+ #
57
+ def print_version
58
+ puts "#{command_name} #{version}"
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,47 @@
1
+ module CommandKit
2
+ #
3
+ # Provides methods for determining the current OS.
4
+ #
5
+ # ## Examples
6
+ #
7
+ # include CommandKit::OS
8
+ #
9
+ # def main(*argv)
10
+ # if linux?
11
+ # # ...
12
+ # elsif macos?
13
+ # # ...
14
+ # elsif windows?
15
+ # # ...
16
+ # end
17
+ # end
18
+ #
19
+ module OS
20
+ #
21
+ # Determines if the current OS is Linux.
22
+ #
23
+ # @return [Boolean]
24
+ #
25
+ def linux?
26
+ RUBY_PLATFORM.include?('linux')
27
+ end
28
+
29
+ #
30
+ # Determines if the current OS is macOS.
31
+ #
32
+ # @return [Boolean]
33
+ #
34
+ def macos?
35
+ RUBY_PLATFORM.include?('darwin')
36
+ end
37
+
38
+ #
39
+ # Determines if the current OS is Windows.
40
+ #
41
+ # @return [Boolean]
42
+ #
43
+ def windows?
44
+ Gem.win_platform?
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'command_kit/stdio'
4
+ require 'command_kit/env'
5
+ require 'command_kit/env/path'
6
+
7
+ module CommandKit
8
+ #
9
+ # Allows opening a pager, such as `less` or `more`.
10
+ #
11
+ # ## Examples
12
+ #
13
+ # class CLI < CommandKit::Command
14
+ #
15
+ # include CommandKit::Pager
16
+ #
17
+ # def run
18
+ # pager do |io|
19
+ # end
20
+ # end
21
+ #
22
+ # end
23
+ #
24
+ # ## Environment Variables
25
+ #
26
+ # * `PAGER` - The optional command to override the default pager (usually
27
+ # `less -r` or `more -r`).
28
+ # * `PATH` - The list of directories to search for the default pager program
29
+ # (either `less` or `more`).
30
+ #
31
+ # ## Alternatives
32
+ #
33
+ # * [tty-pager](https://github.com/piotrmurach/tty-pager#readme)
34
+ #
35
+ module Pager
36
+ include Stdio
37
+ include Env
38
+ include Env::Path
39
+
40
+ # Common pager commands.
41
+ PAGERS = ['less -r', 'more -r']
42
+
43
+ #
44
+ # Initializes the pager.
45
+ #
46
+ # @note
47
+ # Respects the `PAGER` env variable, or attemps to find `less` or
48
+ # `more` by searching the `PATH` env variable.
49
+ #
50
+ def initialize(**kwargs)
51
+ super(**kwargs)
52
+
53
+ @pager = env.fetch('PAGER') do
54
+ PAGERS.find do |command|
55
+ bin = command.split(' ',2).first
56
+
57
+ command_installed?(bin)
58
+ end
59
+ end
60
+ end
61
+
62
+ #
63
+ # Opens a pager pipe.
64
+ #
65
+ # @yield [io]
66
+ # The given block will be passed the IO pipe to the pager.
67
+ #
68
+ # @yieldparam [IO]
69
+ # The IO pipe to the pager.
70
+ #
71
+ def pager
72
+ if !stdout.tty? || @pager.nil?
73
+ # fallback to stdout if the process does not have a console or we could
74
+ # not find a suitable pager command.
75
+ yield stdout
76
+ return
77
+ end
78
+
79
+ io = IO.popen(@pager,'w')
80
+ pid = io.pid
81
+
82
+ begin
83
+ yield io
84
+ rescue Errno::EPIPE
85
+ ensure
86
+ io.close
87
+
88
+ begin
89
+ Process.waitpid(pid)
90
+ rescue Errno::EPIPE, Errno::ECHILD
91
+ end
92
+ end
93
+ end
94
+
95
+ #
96
+ # Pages the data if it's longer the console's height, otherwise prints the
97
+ # data to {Stdio#stdout stdout}.
98
+ #
99
+ # @param [Array<String>, #to_s] data
100
+ # The data to print.
101
+ #
102
+ def print_or_page(data)
103
+ line_count = case data
104
+ when Array then data.length
105
+ else data.to_s.each_line.count
106
+ end
107
+
108
+ if line_count > console_height
109
+ pager { |io| io.puts(data) }
110
+ else
111
+ stdout.puts(data)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'command_kit/stdio'
4
+
5
+ module CommandKit
6
+ #
7
+ # Provides printing methods.
8
+ #
9
+ module Printing
10
+ include Stdio
11
+
12
+ #
13
+ # Prints the error message to {Stdio#stderr stderr}.
14
+ #
15
+ # @param [String] message
16
+ # The error message.
17
+ #
18
+ def print_error(message)
19
+ stderr.puts message
20
+ end
21
+
22
+ #
23
+ # Prints an exception to {Stdio#stderr stderr}.
24
+ #
25
+ # @param [Exception] error
26
+ # The error to print.
27
+ #
28
+ def print_exception(error)
29
+ print_error error.full_message(highlight: stderr.tty?)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,78 @@
1
+ module CommandKit
2
+ module Printing
3
+ #
4
+ # Adds the ability to automatically indent all calls to `puts`.
5
+ #
6
+ # ## Examples
7
+ #
8
+ # include Printing::Indent
9
+ #
10
+ # def main
11
+ # puts "regular output:"
12
+ #
13
+ # indent(4) do
14
+ # puts "indented output"
15
+ # puts "..."
16
+ # end
17
+ #
18
+ # puts "back to regular output"
19
+ # end
20
+ #
21
+ module Indent
22
+ #
23
+ # Initializes the indententation level to zero.
24
+ #
25
+ def initialize(**kwargs)
26
+ @indent = 0
27
+
28
+ super(**kwargs)
29
+ end
30
+
31
+ #
32
+ # Increases the indentation level by two, yields, then restores the
33
+ # indentation level.
34
+ #
35
+ # @param [Integer] n
36
+ # How much to increase the indentation level by.
37
+ #
38
+ # @yield []
39
+ # The given block will be called after the indentation level has been
40
+ # increased.
41
+ #
42
+ # @return [Integer]
43
+ # If no block is given, the indententation level will be returned.
44
+ #
45
+ def indent(n=2)
46
+ if block_given?
47
+ begin
48
+ original_indent = @indent
49
+ @indent += n
50
+
51
+ yield
52
+ ensure
53
+ @indent = original_indent
54
+ end
55
+ else
56
+ @indent
57
+ end
58
+ end
59
+
60
+ #
61
+ # Indents and prints the lines to stdout.
62
+ #
63
+ # @param [Array<String>] lines
64
+ # The lines to indent and print.
65
+ #
66
+ def puts(*lines)
67
+ if (@indent > 0 && !lines.empty?)
68
+ padding = " " * @indent
69
+
70
+ super(*lines.map { |line| "#{padding}#{line}" })
71
+ else
72
+ super(*lines)
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+ end