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.
- checksums.yaml +7 -0
- data/.document +3 -0
- data/.github/workflows/ruby.yml +29 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +29 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +20 -0
- data/README.md +283 -0
- data/Rakefile +23 -0
- data/command_kit.gemspec +60 -0
- data/gemspec.yml +14 -0
- data/lib/command_kit.rb +1 -0
- data/lib/command_kit/arguments.rb +161 -0
- data/lib/command_kit/arguments/argument.rb +111 -0
- data/lib/command_kit/arguments/argument_value.rb +81 -0
- data/lib/command_kit/arguments/usage.rb +6 -0
- data/lib/command_kit/colors.rb +355 -0
- data/lib/command_kit/command.rb +42 -0
- data/lib/command_kit/command_name.rb +95 -0
- data/lib/command_kit/commands.rb +299 -0
- data/lib/command_kit/commands/auto_load.rb +153 -0
- data/lib/command_kit/commands/auto_load/subcommand.rb +90 -0
- data/lib/command_kit/commands/auto_require.rb +138 -0
- data/lib/command_kit/commands/command.rb +12 -0
- data/lib/command_kit/commands/help.rb +43 -0
- data/lib/command_kit/commands/parent_command.rb +21 -0
- data/lib/command_kit/commands/subcommand.rb +51 -0
- data/lib/command_kit/console.rb +141 -0
- data/lib/command_kit/description.rb +89 -0
- data/lib/command_kit/env.rb +43 -0
- data/lib/command_kit/env/home.rb +71 -0
- data/lib/command_kit/env/path.rb +71 -0
- data/lib/command_kit/examples.rb +99 -0
- data/lib/command_kit/exception_handler.rb +55 -0
- data/lib/command_kit/help.rb +62 -0
- data/lib/command_kit/help/man.rb +125 -0
- data/lib/command_kit/inflector.rb +84 -0
- data/lib/command_kit/main.rb +103 -0
- data/lib/command_kit/options.rb +179 -0
- data/lib/command_kit/options/option.rb +171 -0
- data/lib/command_kit/options/option_value.rb +90 -0
- data/lib/command_kit/options/parser.rb +227 -0
- data/lib/command_kit/options/quiet.rb +53 -0
- data/lib/command_kit/options/usage.rb +6 -0
- data/lib/command_kit/options/verbose.rb +55 -0
- data/lib/command_kit/options/version.rb +62 -0
- data/lib/command_kit/os.rb +47 -0
- data/lib/command_kit/pager.rb +115 -0
- data/lib/command_kit/printing.rb +32 -0
- data/lib/command_kit/printing/indent.rb +78 -0
- data/lib/command_kit/program_name.rb +57 -0
- data/lib/command_kit/stdio.rb +138 -0
- data/lib/command_kit/usage.rb +102 -0
- data/lib/command_kit/version.rb +4 -0
- data/lib/command_kit/xdg.rb +138 -0
- data/spec/arguments/argument_spec.rb +169 -0
- data/spec/arguments/argument_value_spec.rb +126 -0
- data/spec/arguments_spec.rb +213 -0
- data/spec/colors_spec.rb +470 -0
- data/spec/command_kit_spec.rb +8 -0
- data/spec/command_name_spec.rb +130 -0
- data/spec/command_spec.rb +49 -0
- data/spec/commands/auto_load/subcommand_spec.rb +82 -0
- data/spec/commands/auto_load_spec.rb +128 -0
- data/spec/commands/auto_require_spec.rb +142 -0
- data/spec/commands/fixtures/test_auto_load/cli/commands/test1.rb +10 -0
- data/spec/commands/fixtures/test_auto_load/cli/commands/test2.rb +10 -0
- data/spec/commands/fixtures/test_auto_require/lib/test_auto_require/cli/commands/test1.rb +10 -0
- data/spec/commands/help_spec.rb +66 -0
- data/spec/commands/parent_command_spec.rb +40 -0
- data/spec/commands/subcommand_spec.rb +99 -0
- data/spec/commands_spec.rb +767 -0
- data/spec/console_spec.rb +201 -0
- data/spec/description_spec.rb +203 -0
- data/spec/env/home_spec.rb +46 -0
- data/spec/env/path_spec.rb +78 -0
- data/spec/env_spec.rb +123 -0
- data/spec/examples_spec.rb +235 -0
- data/spec/exception_handler_spec.rb +103 -0
- data/spec/help_spec.rb +119 -0
- data/spec/inflector_spec.rb +104 -0
- data/spec/main_spec.rb +179 -0
- data/spec/options/option_spec.rb +258 -0
- data/spec/options/option_value_spec.rb +67 -0
- data/spec/options/parser_spec.rb +265 -0
- data/spec/options_spec.rb +137 -0
- data/spec/os_spec.rb +46 -0
- data/spec/pager_spec.rb +154 -0
- data/spec/printing/indent_spec.rb +130 -0
- data/spec/printing_spec.rb +76 -0
- data/spec/program_name_spec.rb +62 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/stdio_spec.rb +264 -0
- data/spec/usage_spec.rb +237 -0
- data/spec/xdg_spec.rb +191 -0
- metadata +156 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module CommandKit
|
|
2
|
+
#
|
|
3
|
+
# Retrieves the current program name (`$PROGRAM_NAME`).
|
|
4
|
+
#
|
|
5
|
+
module ProgramName
|
|
6
|
+
module ModuleMethods
|
|
7
|
+
#
|
|
8
|
+
# Extends {ClassMethods} or {ModuleMethods}, depending on whether
|
|
9
|
+
# {ProgramName} is being included into a class or a module.
|
|
10
|
+
#
|
|
11
|
+
# @param [Class, Module] context
|
|
12
|
+
# The class or module which is including {ProgramName}.
|
|
13
|
+
#
|
|
14
|
+
def included(context)
|
|
15
|
+
super(context)
|
|
16
|
+
|
|
17
|
+
if context.class == Module
|
|
18
|
+
context.extend ModuleMethods
|
|
19
|
+
else
|
|
20
|
+
context.extend ClassMethods
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
extend ModuleMethods
|
|
26
|
+
|
|
27
|
+
#
|
|
28
|
+
# Class-level methods.
|
|
29
|
+
#
|
|
30
|
+
module ClassMethods
|
|
31
|
+
# List of `$PROGRAM_NAME`s that should be ignored.
|
|
32
|
+
IGNORED_PROGRAM_NAMES = [
|
|
33
|
+
'-e', # ruby -e "..."
|
|
34
|
+
'irb', # running in irb
|
|
35
|
+
'rspec' # running in rspec
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
#
|
|
39
|
+
# The current program name (`$PROGRAM_NAME`).
|
|
40
|
+
#
|
|
41
|
+
# @return [String, nil]
|
|
42
|
+
# The `$PROGRAM_NAME` or `nil` if the `$PROGRAM_NAME` is `-e`, `irb`,
|
|
43
|
+
# or `rspec`.
|
|
44
|
+
#
|
|
45
|
+
def program_name
|
|
46
|
+
$PROGRAM_NAME unless IGNORED_PROGRAM_NAMES.include?($PROGRAM_NAME)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
#
|
|
51
|
+
# @see ClassMethods#program_name
|
|
52
|
+
#
|
|
53
|
+
def program_name
|
|
54
|
+
self.class.program_name
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
module CommandKit
|
|
2
|
+
#
|
|
3
|
+
# Provides access to stdin, stdout, and stderr streams.
|
|
4
|
+
#
|
|
5
|
+
# ## Examples
|
|
6
|
+
#
|
|
7
|
+
# class MyCmd
|
|
8
|
+
# include CommandKit::Stdio
|
|
9
|
+
#
|
|
10
|
+
# def main
|
|
11
|
+
# end
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# ## Testing
|
|
15
|
+
#
|
|
16
|
+
# Can be initialized with custom stdin, stdout, and stderr streams for testing
|
|
17
|
+
# purposes.
|
|
18
|
+
#
|
|
19
|
+
# stdin = StringIO.new
|
|
20
|
+
# stdout = StringIO.new
|
|
21
|
+
# stderr = StringIO.new
|
|
22
|
+
# MyCmd.new(stdin: stdin, stdout: stdout, stderr: stderr)
|
|
23
|
+
#
|
|
24
|
+
module Stdio
|
|
25
|
+
#
|
|
26
|
+
# Initializes {#stdin}, {#stdout}, and {#stderr}.
|
|
27
|
+
#
|
|
28
|
+
# @param [IO] stdin
|
|
29
|
+
# The stdin input stream. Defaults to `$stdin`.
|
|
30
|
+
#
|
|
31
|
+
# @param [IO] stdout
|
|
32
|
+
# The stdout output stream. Defaults to `$stdout`.
|
|
33
|
+
#
|
|
34
|
+
# @param [IO] stderr
|
|
35
|
+
# The stderr error output stream. Defaults to `$stderr`.
|
|
36
|
+
#
|
|
37
|
+
def initialize(stdin: nil, stdout: nil, stderr: nil, **kwargs)
|
|
38
|
+
@stdin = stdin
|
|
39
|
+
@stdout = stdout
|
|
40
|
+
@stderr = stderr
|
|
41
|
+
|
|
42
|
+
super(**kwargs)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
#
|
|
46
|
+
# Returns the stdin input stream.
|
|
47
|
+
#
|
|
48
|
+
# @return [$stdin, IO]
|
|
49
|
+
# The initialized `@stdin` value or `$stdin`.
|
|
50
|
+
#
|
|
51
|
+
def stdin
|
|
52
|
+
@stdin || $stdin
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# Returns the stdout output stream.
|
|
57
|
+
#
|
|
58
|
+
# @return [$stdout, IO]
|
|
59
|
+
# The initialized `@stdout` value or `$stdout`.
|
|
60
|
+
#
|
|
61
|
+
def stdout
|
|
62
|
+
@stdout || $stdout
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
# Returns the stderr error output stream.
|
|
67
|
+
#
|
|
68
|
+
# @return [$stderr, IO]
|
|
69
|
+
# The initialized `@stderr` value or `$stderr`.
|
|
70
|
+
#
|
|
71
|
+
def stderr
|
|
72
|
+
@stderr || $stderr
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
#
|
|
76
|
+
# Calls `stdin.gets`.
|
|
77
|
+
#
|
|
78
|
+
def gets(*arguments)
|
|
79
|
+
stdin.gets(*arguments)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
#
|
|
83
|
+
# Calls `stdin.readline`.
|
|
84
|
+
#
|
|
85
|
+
def readline(*arguments)
|
|
86
|
+
stdin.readline(*arguments)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# Calls `stdin.readlines`.
|
|
91
|
+
#
|
|
92
|
+
def readlines(*arguments)
|
|
93
|
+
stdin.readlines(*arguments)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# NOTE: intentionally do not override `Kenrel#p` or `Kernel#pp` to not
|
|
97
|
+
# hijack echo-debugging.
|
|
98
|
+
|
|
99
|
+
#
|
|
100
|
+
# Calls `stdout.putc`.
|
|
101
|
+
#
|
|
102
|
+
def putc(*arguments)
|
|
103
|
+
stdout.putc(*arguments)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
#
|
|
107
|
+
# Calls `stdout.puts`.
|
|
108
|
+
#
|
|
109
|
+
def puts(*arguments)
|
|
110
|
+
stdout.puts(*arguments)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
#
|
|
114
|
+
# Calls `stdout.print`.
|
|
115
|
+
#
|
|
116
|
+
def print(*arguments)
|
|
117
|
+
stdout.print(*arguments)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
#
|
|
121
|
+
# Calls `stdout.printf`.
|
|
122
|
+
#
|
|
123
|
+
def printf(*arguments)
|
|
124
|
+
stdout.printf(*arguments)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
#
|
|
128
|
+
# Overrides `Kernel.abort` to print to {#stderr}.
|
|
129
|
+
#
|
|
130
|
+
# @param [String, nil] message
|
|
131
|
+
# The optional abort message.
|
|
132
|
+
#
|
|
133
|
+
def abort(message=nil)
|
|
134
|
+
stderr.puts(message) if message
|
|
135
|
+
exit(1)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require 'command_kit/command_name'
|
|
2
|
+
require 'command_kit/help'
|
|
3
|
+
|
|
4
|
+
module CommandKit
|
|
5
|
+
#
|
|
6
|
+
# Defines the usage string for a command class.
|
|
7
|
+
#
|
|
8
|
+
# ## Examples
|
|
9
|
+
#
|
|
10
|
+
# include CommandKit::Usage
|
|
11
|
+
#
|
|
12
|
+
# usage "[options] ARG1 ARG2 [ARG3 ...]"
|
|
13
|
+
#
|
|
14
|
+
module Usage
|
|
15
|
+
include CommandName
|
|
16
|
+
include Help
|
|
17
|
+
|
|
18
|
+
module ModuleMethods
|
|
19
|
+
#
|
|
20
|
+
# Extends {ClassMethods} or {ModuleMethods}, depending on whether {Usage}
|
|
21
|
+
# is being included into a class or module.
|
|
22
|
+
#
|
|
23
|
+
# @param [Class, Module] context
|
|
24
|
+
# The class or module which is including {Usage}.
|
|
25
|
+
#
|
|
26
|
+
def included(context)
|
|
27
|
+
super
|
|
28
|
+
|
|
29
|
+
if context.class == Module
|
|
30
|
+
context.extend ModuleMethods
|
|
31
|
+
else
|
|
32
|
+
context.extend ClassMethods
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
extend ModuleMethods
|
|
38
|
+
|
|
39
|
+
#
|
|
40
|
+
# Class-level methods.
|
|
41
|
+
#
|
|
42
|
+
module ClassMethods
|
|
43
|
+
#
|
|
44
|
+
# Gets or sets the class'es usage string(s).
|
|
45
|
+
#
|
|
46
|
+
# @param [String, Array<String>, nil] new_usage
|
|
47
|
+
# If a new_usage argument is given, it will set the class'es usage
|
|
48
|
+
# string(s).
|
|
49
|
+
#
|
|
50
|
+
# @return [String, Array<String>]
|
|
51
|
+
# The class'es or superclass'es usage string(s).
|
|
52
|
+
#
|
|
53
|
+
def usage(new_usage=nil)
|
|
54
|
+
if new_usage
|
|
55
|
+
@usage = new_usage
|
|
56
|
+
else
|
|
57
|
+
@usage || (superclass.usage if superclass.kind_of?(ClassMethods))
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#
|
|
63
|
+
# Similar to {ClassMethods#usage .usage}, but prepends
|
|
64
|
+
# {CommandName#command_name command_name}.
|
|
65
|
+
#
|
|
66
|
+
# @return [Array<String>, String, nil]
|
|
67
|
+
#
|
|
68
|
+
def usage
|
|
69
|
+
case (usage = self.class.usage)
|
|
70
|
+
when Array
|
|
71
|
+
usage.map { |command| "#{command_name} #{command}" }
|
|
72
|
+
when String
|
|
73
|
+
"#{command_name} #{usage}"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#
|
|
78
|
+
# Prints the `usage: ...` output.
|
|
79
|
+
#
|
|
80
|
+
def help_usage
|
|
81
|
+
case (usage = self.usage)
|
|
82
|
+
when Array
|
|
83
|
+
puts "usage: #{usage[0]}"
|
|
84
|
+
|
|
85
|
+
usage[1..].each do |command|
|
|
86
|
+
puts " #{command}"
|
|
87
|
+
end
|
|
88
|
+
when String
|
|
89
|
+
puts "usage: #{usage}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
#
|
|
94
|
+
# Prints the usage.
|
|
95
|
+
#
|
|
96
|
+
# @see #help_usage
|
|
97
|
+
#
|
|
98
|
+
def help
|
|
99
|
+
help_usage
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
require 'command_kit/command_name'
|
|
2
|
+
require 'command_kit/env/home'
|
|
3
|
+
|
|
4
|
+
module CommandKit
|
|
5
|
+
#
|
|
6
|
+
# Provides access to [XDG directories].
|
|
7
|
+
#
|
|
8
|
+
# * `~/.config`
|
|
9
|
+
# * `~/.local/share`
|
|
10
|
+
# * `~/.cache`
|
|
11
|
+
#
|
|
12
|
+
# ## Environment Variables
|
|
13
|
+
#
|
|
14
|
+
# * `XDG_CONFIG_HOME` - The directory that should contain user-specific
|
|
15
|
+
# configuration. Defaults to `~/.config/`.
|
|
16
|
+
# * `XDG_DATA_HOME` - The directory that should contain user-specific data.
|
|
17
|
+
# Defaults to `~/.local/share/`.
|
|
18
|
+
# * `XDG_CACHE_HOME` - The directory that should contain user-specific cache
|
|
19
|
+
# data. Defaults to `~/.cache/`.
|
|
20
|
+
#
|
|
21
|
+
# [XDG directories]: https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
|
22
|
+
#
|
|
23
|
+
module XDG
|
|
24
|
+
include CommandName
|
|
25
|
+
include Env::Home
|
|
26
|
+
|
|
27
|
+
module ModuleMethods
|
|
28
|
+
#
|
|
29
|
+
# Extends {ClassMethods} or {ModuleMethods}, depending on whether {XDG} is
|
|
30
|
+
# being included into a class or a module..
|
|
31
|
+
#
|
|
32
|
+
# @param [Class, Module] context
|
|
33
|
+
# The class or module which is including {XDG}.
|
|
34
|
+
#
|
|
35
|
+
def included(context)
|
|
36
|
+
super(context)
|
|
37
|
+
|
|
38
|
+
if context.class == Module
|
|
39
|
+
context.extend ModuleMethods
|
|
40
|
+
else
|
|
41
|
+
context.extend ClassMethods
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
extend ModuleMethods
|
|
47
|
+
|
|
48
|
+
module ClassMethods
|
|
49
|
+
#
|
|
50
|
+
# Gets or sets the XDG sub-directory name used by the command.
|
|
51
|
+
#
|
|
52
|
+
# @param [#to_s, nil] new_namespace
|
|
53
|
+
# If a new_namespace argument is given, it will set the class'es
|
|
54
|
+
# {#xdg_namespace} string.
|
|
55
|
+
#
|
|
56
|
+
# @return [String]
|
|
57
|
+
# The class'es or superclass'es {#xdg_namespace}. Defaults to
|
|
58
|
+
# {CommandName::ClassMethods#command_name} if no {#xdg_namespace} has
|
|
59
|
+
# been defined.
|
|
60
|
+
#
|
|
61
|
+
def xdg_namespace(new_namespace=nil)
|
|
62
|
+
if new_namespace
|
|
63
|
+
@xdg_namespace = new_namespace.to_s
|
|
64
|
+
else
|
|
65
|
+
@xdg_namespace || (superclass.xdg_namespace if superclass.kind_of?(ClassMethods)) || command_name
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# The `~/.config/<xdg_namespace>` directory.
|
|
71
|
+
#
|
|
72
|
+
# @return [String]
|
|
73
|
+
attr_reader :config_dir
|
|
74
|
+
|
|
75
|
+
# The `~/.local/share/<xdg_namespace>` directory.
|
|
76
|
+
#
|
|
77
|
+
# @return [String]
|
|
78
|
+
attr_reader :local_share_dir
|
|
79
|
+
|
|
80
|
+
# The `~/.cache/<xdg_namespace>` directory.
|
|
81
|
+
#
|
|
82
|
+
# @return [String]
|
|
83
|
+
attr_reader :cache_dir
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
# Initializes {#config_dir}, {#local_share_dir}, and {#cache_dir}.
|
|
87
|
+
#
|
|
88
|
+
# @param [Hash{Symbol => Object}] kwargs
|
|
89
|
+
# Additional keyword arguments.
|
|
90
|
+
#
|
|
91
|
+
# @note
|
|
92
|
+
# If the `$XDG_CONFIG_HOME` env variable is set, then {#config_dir} will
|
|
93
|
+
# be initialized to effectively `$XDG_CONFIG_HOME/<xdg_namespace>`.
|
|
94
|
+
# Otherwise {#config_dir} will be initialized to
|
|
95
|
+
# `~/.config/<xdg_namespace>`.
|
|
96
|
+
#
|
|
97
|
+
# @note
|
|
98
|
+
# If the `$XDG_DATA_HOME` env variable is set, then {#local_share_dir}
|
|
99
|
+
# will be initialized to effectively `$XDG_DATA_HOME/<xdg_namespace>`.
|
|
100
|
+
# Otherwise {#local_share_dir} will be initialized to
|
|
101
|
+
# `~/.local/share/<xdg_namespace>`.
|
|
102
|
+
#
|
|
103
|
+
# @note
|
|
104
|
+
# If the `$XDG_CACHE_HOME` env variable is set, then {#cache_dir} will
|
|
105
|
+
# be initialized to effectively `$XDG_CACHE_HOME/<xdg_namespace>`.
|
|
106
|
+
# Otherwise {#cache_dir} will be initialized to
|
|
107
|
+
# `~/.cache/<xdg_namespace>`.
|
|
108
|
+
#
|
|
109
|
+
def initialize(**kwargs)
|
|
110
|
+
super(**kwargs)
|
|
111
|
+
|
|
112
|
+
xdg_config_home = env.fetch('XDG_CONFIG_HOME') do
|
|
113
|
+
File.join(home_dir,'.config')
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
@config_dir = File.join(xdg_config_home,xdg_namespace)
|
|
117
|
+
|
|
118
|
+
xdg_data_home = env.fetch('XDG_DATA_HOME') do
|
|
119
|
+
File.join(home_dir,'.local','share')
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
@local_share_dir = File.join(xdg_data_home,xdg_namespace)
|
|
123
|
+
|
|
124
|
+
xdg_cache_home = env.fetch('XDG_CACHE_HOME') do
|
|
125
|
+
File.join(home_dir,'.cache')
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
@cache_dir = File.join(xdg_cache_home,xdg_namespace)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
#
|
|
132
|
+
# @see ClassMethods#xdg_namespace
|
|
133
|
+
#
|
|
134
|
+
def xdg_namespace
|
|
135
|
+
self.class.xdg_namespace
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'command_kit/arguments/argument'
|
|
3
|
+
|
|
4
|
+
describe Arguments::Argument do
|
|
5
|
+
let(:name) { :foo }
|
|
6
|
+
let(:type) { String }
|
|
7
|
+
let(:usage) { 'FOO' }
|
|
8
|
+
let(:default) { 'foo' }
|
|
9
|
+
let(:required) { true }
|
|
10
|
+
let(:repeats) { false }
|
|
11
|
+
let(:desc) { 'Foo argument' }
|
|
12
|
+
|
|
13
|
+
subject do
|
|
14
|
+
described_class.new name, type: type,
|
|
15
|
+
usage: usage,
|
|
16
|
+
default: default,
|
|
17
|
+
required: required,
|
|
18
|
+
repeats: repeats,
|
|
19
|
+
desc: desc
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "#initialize" do
|
|
23
|
+
context "when the type: keyword is given" do
|
|
24
|
+
subject { described_class.new(name, type: type, desc: desc) }
|
|
25
|
+
|
|
26
|
+
it "must set #type" do
|
|
27
|
+
expect(subject.type).to eq(type)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "when the type: keyword is not given" do
|
|
32
|
+
subject { described_class.new(name, desc: desc) }
|
|
33
|
+
|
|
34
|
+
it "default #type to String" do
|
|
35
|
+
expect(subject.type).to eq(String)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context "when the usage: keyword is given" do
|
|
40
|
+
subject { described_class.new(name, usage: usage, desc: desc) }
|
|
41
|
+
|
|
42
|
+
it "must include usage: in #usage" do
|
|
43
|
+
expect(subject.usage).to include(usage)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context "when the usage: keyword is not given" do
|
|
48
|
+
subject { described_class.new(name, desc: desc) }
|
|
49
|
+
|
|
50
|
+
it "should use uppercased argument name in #usage" do
|
|
51
|
+
expect(subject.usage).to include(name.to_s.upcase)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context "when the default: keyword is given" do
|
|
56
|
+
subject { described_class.new(name, default: default, desc: desc) }
|
|
57
|
+
|
|
58
|
+
it "must set #default" do
|
|
59
|
+
expect(subject.default).to eq(default)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
context "when the default: keyword is not given" do
|
|
64
|
+
subject { described_class.new(name, desc: desc) }
|
|
65
|
+
|
|
66
|
+
it "default #default to String" do
|
|
67
|
+
expect(subject.default).to eq(nil)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
context "when the required: keyword is given" do
|
|
72
|
+
subject { described_class.new(name, required: required, desc: desc) }
|
|
73
|
+
|
|
74
|
+
it "must set #required" do
|
|
75
|
+
expect(subject.required).to eq(required)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
context "when the required: keyword is not given" do
|
|
80
|
+
subject { described_class.new(name, desc: desc) }
|
|
81
|
+
|
|
82
|
+
it "default #required to String" do
|
|
83
|
+
expect(subject.required).to eq(true)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context "when the repeats: keyword is given" do
|
|
88
|
+
subject { described_class.new(name, repeats: repeats, desc: desc) }
|
|
89
|
+
|
|
90
|
+
it "must set #repeats" do
|
|
91
|
+
expect(subject.repeats).to eq(repeats)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context "when the repeats: keyword is not given" do
|
|
96
|
+
subject { described_class.new(name, desc: desc) }
|
|
97
|
+
|
|
98
|
+
it "default #repeats to String" do
|
|
99
|
+
expect(subject.repeats).to eq(false)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context "when the desc: keyword is given" do
|
|
104
|
+
subject { described_class.new(name, desc: desc) }
|
|
105
|
+
|
|
106
|
+
it "must set #desc" do
|
|
107
|
+
expect(subject.desc).to eq(desc)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
context "when the desc: keyword is not given" do
|
|
112
|
+
it do
|
|
113
|
+
expect {
|
|
114
|
+
described_class.new(name)
|
|
115
|
+
}.to raise_error(ArgumentError)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe "#repeats?" do
|
|
121
|
+
context "when initialized with repeats: true" do
|
|
122
|
+
let(:repeats) { true }
|
|
123
|
+
|
|
124
|
+
it { expect(subject.repeats?).to be(true) }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
context "when initialized with repeats: false" do
|
|
128
|
+
let(:repeats) { false }
|
|
129
|
+
|
|
130
|
+
it { expect(subject.repeats?).to be(false) }
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
describe "#usage" do
|
|
135
|
+
let(:usage) { 'FOO' }
|
|
136
|
+
|
|
137
|
+
context "initialized with required: true" do
|
|
138
|
+
let(:required) { true }
|
|
139
|
+
|
|
140
|
+
it "must return the usage unchanged" do
|
|
141
|
+
expect(subject.usage).to eq(usage)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
context "initialized with required: false" do
|
|
146
|
+
let(:required) { false }
|
|
147
|
+
|
|
148
|
+
it "must wrap the usage in [ ] brackets" do
|
|
149
|
+
expect(subject.usage).to eq("[#{usage}]")
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
context "initialized with repeats: true" do
|
|
154
|
+
let(:repeats) { true }
|
|
155
|
+
|
|
156
|
+
it "must append the ... ellipses" do
|
|
157
|
+
expect(subject.usage).to eq("#{usage} ...")
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
context "initialized with repeats: false" do
|
|
162
|
+
let(:repeats) { false }
|
|
163
|
+
|
|
164
|
+
it "must return the usage name unchanged" do
|
|
165
|
+
expect(subject.usage).to eq("#{usage}")
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|