command_kit 0.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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