cliqr 1.2.0 → 2.0.0
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 +4 -4
- data/CHANGELOG.md +95 -0
- data/README.md +9 -71
- data/examples/numbers +1 -2
- data/examples/vagrant +0 -3
- data/lib/cliqr.rb +52 -11
- data/lib/cliqr/argument_validation/argument_type_validator.rb +2 -2
- data/lib/cliqr/argument_validation/validator.rb +3 -3
- data/lib/cliqr/{cli → command}/argument_operator.rb +2 -2
- data/lib/cliqr/{cli → command}/argument_operator_context.rb +1 -1
- data/lib/cliqr/{cli/command.rb → command/base_command.rb} +2 -2
- data/lib/cliqr/command/color.rb +174 -0
- data/lib/cliqr/{cli → command}/command_context.rb +68 -20
- data/lib/cliqr/command/shell_banner_builder.rb +17 -0
- data/lib/cliqr/command/shell_command.rb +125 -0
- data/lib/cliqr/command/shell_prompt_builder.rb +26 -0
- data/lib/cliqr/config/action.rb +226 -0
- data/lib/cliqr/config/base.rb +84 -0
- data/lib/cliqr/config/command.rb +137 -0
- data/lib/cliqr/config/dsl.rb +81 -0
- data/lib/cliqr/config/event.rb +43 -0
- data/lib/cliqr/config/event_based.rb +78 -0
- data/lib/cliqr/config/named.rb +55 -0
- data/lib/cliqr/config/option.rb +95 -0
- data/lib/cliqr/config/option_based.rb +130 -0
- data/lib/cliqr/config/shell.rb +87 -0
- data/lib/cliqr/config/validation/validation_set.rb +66 -0
- data/lib/cliqr/config/validation/validator_factory.rb +403 -0
- data/lib/cliqr/config/validation/verifiable.rb +91 -0
- data/lib/cliqr/error.rb +20 -4
- data/lib/cliqr/events/event.rb +56 -0
- data/lib/cliqr/events/event_context.rb +31 -0
- data/lib/cliqr/events/handler.rb +32 -0
- data/lib/cliqr/events/invoker.rb +70 -0
- data/lib/cliqr/{cli → executor}/command_runner_factory.rb +3 -3
- data/lib/cliqr/{cli → executor}/router.rb +4 -4
- data/lib/cliqr/{cli/executor.rb → executor/runner.rb} +25 -10
- data/lib/cliqr/interface.rb +98 -0
- data/lib/cliqr/parser/token_factory.rb +1 -1
- data/lib/cliqr/usage/command_usage_context.rb +94 -0
- data/lib/cliqr/usage/option_usage_context.rb +86 -0
- data/lib/cliqr/usage/templates/partial/action_list.erb +10 -0
- data/lib/cliqr/usage/templates/partial/command_name.erb +3 -0
- data/lib/cliqr/usage/templates/partial/option_list.erb +18 -0
- data/lib/cliqr/usage/templates/partial/usage_info.erb +5 -0
- data/lib/cliqr/usage/templates/usage/cli.erb +4 -0
- data/lib/cliqr/usage/templates/usage/shell.erb +2 -0
- data/lib/cliqr/usage/usage_builder.rb +59 -0
- data/lib/cliqr/util.rb +81 -34
- data/lib/cliqr/version.rb +1 -1
- data/spec/config/action_config_validator_spec.rb +127 -5
- data/spec/config/config_finalize_spec.rb +3 -3
- data/spec/config/config_validator_spec.rb +120 -17
- data/spec/config/option_config_validator_spec.rb +1 -1
- data/spec/dsl/interface_spec.rb +2 -2
- data/spec/dsl/usage_spec.rb +461 -465
- data/spec/executor/action_executor_spec.rb +1 -1
- data/spec/executor/color_executor_spec.rb +125 -0
- data/spec/executor/command_runner_spec.rb +6 -8
- data/spec/executor/event_executor_spec.rb +365 -0
- data/spec/executor/executor_spec.rb +49 -11
- data/spec/executor/help_executor_spec.rb +107 -103
- data/spec/fixtures/action_reader_command.rb +1 -1
- data/spec/fixtures/test_arg_printer_event_handler.rb +9 -0
- data/spec/fixtures/test_color_shell_prompt.rb +13 -0
- data/spec/fixtures/test_empty_event_handler.rb +5 -0
- data/spec/fixtures/test_invoker_event_handler.rb +9 -0
- data/spec/fixtures/test_shell_banner.rb +8 -0
- data/spec/fixtures/test_shell_prompt.rb +13 -0
- data/spec/shell/shell_executor_spec.rb +700 -0
- data/spec/validation/validation_spec.rb +2 -2
- metadata +65 -27
- data/lib/cliqr/cli/config.rb +0 -554
- data/lib/cliqr/cli/interface.rb +0 -107
- data/lib/cliqr/cli/shell_command.rb +0 -69
- data/lib/cliqr/cli/usage_builder.rb +0 -185
- data/lib/cliqr/config_validation/validation_set.rb +0 -48
- data/lib/cliqr/config_validation/validator_factory.rb +0 -319
- data/lib/cliqr/config_validation/verifiable.rb +0 -89
- data/lib/cliqr/dsl.rb +0 -59
- data/spec/executor/shell_executor_spec.rb +0 -233
- data/templates/usage.erb +0 -39
@@ -1,89 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'cliqr/config_validation/validator_factory'
|
4
|
-
require 'cliqr/config_validation/validation_set'
|
5
|
-
require 'cliqr/validation_errors'
|
6
|
-
|
7
|
-
module Cliqr
|
8
|
-
# Validation framework for the command line interface config definition adopted from
|
9
|
-
# lotus/validations by @jodosha
|
10
|
-
#
|
11
|
-
# @api private
|
12
|
-
#
|
13
|
-
# @see https://github.com/lotus/validations
|
14
|
-
module ConfigValidation
|
15
|
-
# If a class includes this module, we add a few useful methods to that class
|
16
|
-
#
|
17
|
-
# @see http://www.ruby-doc.org/core/Module.html#method-i-included
|
18
|
-
#
|
19
|
-
# @return [Object]
|
20
|
-
def self.included(base)
|
21
|
-
base.class_eval do
|
22
|
-
extend Verifiable
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
# Check if the class is valid based on the configured attribute validations
|
27
|
-
#
|
28
|
-
# @return [Boolean] <tt>true</tt> if there are no validation errors
|
29
|
-
def valid?
|
30
|
-
validate
|
31
|
-
|
32
|
-
errors.empty?
|
33
|
-
end
|
34
|
-
|
35
|
-
# Run the validation against all attribute values
|
36
|
-
#
|
37
|
-
# @return [Hash] All validated attributed attributes and their values
|
38
|
-
def validate
|
39
|
-
read_attributes.each do |name, value|
|
40
|
-
validations.validate(name, value, errors)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Get the list of validations to be performed
|
45
|
-
#
|
46
|
-
# @return [Hash] A hash of attribute name to its validator
|
47
|
-
def validations
|
48
|
-
self.class.__send__(:validations)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Read current values for all attributes that must be validated
|
52
|
-
#
|
53
|
-
# @return [Hash] All attributes that must be validated along with their current values
|
54
|
-
def read_attributes
|
55
|
-
{}.tap do |attributes|
|
56
|
-
validations.each_key do |attribute|
|
57
|
-
attributes[attribute] = public_send(attribute)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# Get a list of errors after validation finishes
|
63
|
-
#
|
64
|
-
# @return [Cliqr::ValidationErrors] A wrapper of all errors
|
65
|
-
def errors
|
66
|
-
@errors ||= ValidationErrors.new
|
67
|
-
end
|
68
|
-
|
69
|
-
# Validations DSL
|
70
|
-
module Verifiable
|
71
|
-
# Add a new validation for a attribute
|
72
|
-
#
|
73
|
-
# @param [Symbol] name Name of the attribute to validate
|
74
|
-
# @param [Object] options Configuration to initialize a attribute validator with
|
75
|
-
#
|
76
|
-
# @return [Cliqr::Validation::ValidationSet] A wrapper of all validations configured so far
|
77
|
-
def validates(name, options)
|
78
|
-
validations.add(name, options)
|
79
|
-
end
|
80
|
-
|
81
|
-
# Get or create a new <tt>Cliqr::Validation::ValidationSet</tt>
|
82
|
-
#
|
83
|
-
# @return [Cliqr::Validation::ValidationSet]
|
84
|
-
def validations
|
85
|
-
@validations ||= ValidationSet.new
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
data/lib/cliqr/dsl.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'delegate'
|
4
|
-
|
5
|
-
module Cliqr
|
6
|
-
# Used to separate all dsl methods in a separate block, thus allowing
|
7
|
-
# separation of concerns between non-dsl methods with dsl methods which
|
8
|
-
# improves maintainability.
|
9
|
-
#
|
10
|
-
# @api private
|
11
|
-
module DSL
|
12
|
-
# Entry point for invoking dsl methods
|
13
|
-
#
|
14
|
-
# @param [Hash] args Arguments to be used to build the DSL instance
|
15
|
-
#
|
16
|
-
# @param [Function] block The block to evaluate the DSL
|
17
|
-
#
|
18
|
-
# @return [Cliqr::DSL]
|
19
|
-
def build(*args, &block)
|
20
|
-
base = new(*args)
|
21
|
-
if block_given?
|
22
|
-
delegator = DSLDelegator.new(base)
|
23
|
-
delegator.instance_eval(&block)
|
24
|
-
end
|
25
|
-
base.finalize
|
26
|
-
base
|
27
|
-
end
|
28
|
-
|
29
|
-
# Delegates all DSL methods to the base class. Can be used to keep DSL
|
30
|
-
# methods separate from non-dsl methods. All implementing subclasses will
|
31
|
-
# have to implement a set_config method as described below
|
32
|
-
#
|
33
|
-
# class MyDSLClass
|
34
|
-
# extends Cliqr::DSL
|
35
|
-
#
|
36
|
-
# def set_config(name, value, &block)
|
37
|
-
# # handle config value for attribute "name"
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# This will be invoked as:
|
42
|
-
#
|
43
|
-
# MyDSLClass.build do
|
44
|
-
# attribute 'some-value'
|
45
|
-
# end
|
46
|
-
class DSLDelegator < SimpleDelegator
|
47
|
-
# All dsl methods are handled dynamically by proxying through #set_config
|
48
|
-
#
|
49
|
-
# @param [Symbol] name Name of the method
|
50
|
-
# @param [Array] args Method arguments
|
51
|
-
# @param [Function] block A function to evaluate in the context of the method's arguments
|
52
|
-
#
|
53
|
-
# @return [Object] The return value of the proxied method
|
54
|
-
def method_missing(name, *args, &block)
|
55
|
-
__getobj__.set_config name, args[0], &block
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,233 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
require 'fixtures/test_command'
|
6
|
-
|
7
|
-
describe Cliqr::CLI::Executor do
|
8
|
-
it 'can execute help in command shell' do
|
9
|
-
cli = Cliqr.interface do
|
10
|
-
name 'my-command'
|
11
|
-
handler TestCommand
|
12
|
-
|
13
|
-
action :bla
|
14
|
-
end
|
15
|
-
|
16
|
-
with_input(['help']) do
|
17
|
-
result = cli.execute_internal %w(my-command shell), output: :buffer
|
18
|
-
expect(result[:stdout]).to eq <<-EOS
|
19
|
-
Starting shell for command "my-command"
|
20
|
-
my-command > help.
|
21
|
-
my-command
|
22
|
-
|
23
|
-
USAGE:
|
24
|
-
my-command [actions] [options] [arguments]
|
25
|
-
|
26
|
-
Available options:
|
27
|
-
|
28
|
-
--help, -h : Get helpful information for action "my-command" along with its usage information.
|
29
|
-
|
30
|
-
Available actions:
|
31
|
-
[ Type "my-command help [action-name]" to get more information about that action ]
|
32
|
-
|
33
|
-
bla
|
34
|
-
|
35
|
-
shell -- Execute a shell in the context of "my-command" command.
|
36
|
-
|
37
|
-
help -- The help action for command "my-command" which provides details and usage information on how to use the command.
|
38
|
-
my-command > exit.
|
39
|
-
shell exited with code 0
|
40
|
-
EOS
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'can execute a sub action from shell' do
|
45
|
-
cli = Cliqr.interface do
|
46
|
-
name 'my-command'
|
47
|
-
handler do
|
48
|
-
puts 'base command executed'
|
49
|
-
end
|
50
|
-
|
51
|
-
action :foo do
|
52
|
-
handler do
|
53
|
-
puts 'foo executed'
|
54
|
-
end
|
55
|
-
|
56
|
-
action :bar do
|
57
|
-
handler do
|
58
|
-
puts 'bar executed'
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
with_input(['', 'my-command', 'foo', 'foo bar', 'foo bar help']) do
|
65
|
-
result = cli.execute_internal %w(my-command shell), output: :buffer
|
66
|
-
expect(result[:stdout]).to eq <<-EOS
|
67
|
-
Starting shell for command "my-command"
|
68
|
-
my-command > .
|
69
|
-
base command executed
|
70
|
-
my-command > my-command.
|
71
|
-
base command executed
|
72
|
-
my-command > foo.
|
73
|
-
foo executed
|
74
|
-
my-command > foo bar.
|
75
|
-
bar executed
|
76
|
-
my-command > foo bar help.
|
77
|
-
my-command foo bar
|
78
|
-
|
79
|
-
USAGE:
|
80
|
-
my-command foo bar [actions] [options] [arguments]
|
81
|
-
|
82
|
-
Available options:
|
83
|
-
|
84
|
-
--help, -h : Get helpful information for action "my-command foo bar" along with its usage information.
|
85
|
-
|
86
|
-
Available actions:
|
87
|
-
[ Type "my-command foo bar help [action-name]" to get more information about that action ]
|
88
|
-
|
89
|
-
help -- The help action for command "my-command foo bar" which provides details and usage information on how to use the command.
|
90
|
-
my-command > exit.
|
91
|
-
shell exited with code 0
|
92
|
-
EOS
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
it 'does not allow shell action if shell config is disabled' do
|
97
|
-
cli = Cliqr.interface do
|
98
|
-
name 'my-command'
|
99
|
-
shell :disable
|
100
|
-
arguments :disable
|
101
|
-
end
|
102
|
-
expect { cli.execute_internal %w(my-command shell) }.to(
|
103
|
-
raise_error(Cliqr::Error::IllegalArgumentError, 'invalid command argument "shell"'))
|
104
|
-
end
|
105
|
-
|
106
|
-
it 'can handle errors in shell' do
|
107
|
-
cli = Cliqr.interface do
|
108
|
-
name 'my-command'
|
109
|
-
handler TestCommand
|
110
|
-
arguments :disable
|
111
|
-
|
112
|
-
action :foo do
|
113
|
-
handler do
|
114
|
-
fail StandardError, 'I failed!'
|
115
|
-
end
|
116
|
-
|
117
|
-
action :bar do
|
118
|
-
handler TestCommand
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
with_input(['unknown', '--opt-1 val', 'foo']) do
|
124
|
-
result = cli.execute_internal %w(my-command shell), output: :buffer
|
125
|
-
expect(result[:stdout]).to eq <<-EOS
|
126
|
-
Starting shell for command "my-command"
|
127
|
-
my-command > unknown.
|
128
|
-
invalid command argument "unknown"
|
129
|
-
my-command > --opt-1 val.
|
130
|
-
unknown option "--opt-1"
|
131
|
-
my-command > foo.
|
132
|
-
command 'my-command foo' failed
|
133
|
-
|
134
|
-
Cause: StandardError - I failed!
|
135
|
-
my-command > exit.
|
136
|
-
shell exited with code 0
|
137
|
-
EOS
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
describe 'illegal shell operations' do
|
142
|
-
it 'does not allow shell action if there are no sub-actions' do
|
143
|
-
cli = Cliqr.interface do
|
144
|
-
name 'my-command'
|
145
|
-
help :disable
|
146
|
-
handler TestCommand
|
147
|
-
arguments :disable
|
148
|
-
end
|
149
|
-
expect { cli.execute_internal %w(my-command shell) }.to(
|
150
|
-
raise_error(Cliqr::Error::IllegalArgumentError, 'invalid command argument "shell"'))
|
151
|
-
end
|
152
|
-
|
153
|
-
it 'does not allow shell in shell for base command' do
|
154
|
-
cli = Cliqr.interface do
|
155
|
-
name 'my-command'
|
156
|
-
|
157
|
-
action :foo do
|
158
|
-
action :bar
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
with_input(['shell']) do
|
163
|
-
result = cli.execute_internal %w(my-command shell), output: :buffer
|
164
|
-
expect(result[:stdout]).to eq <<-EOS
|
165
|
-
Starting shell for command "my-command"
|
166
|
-
my-command > shell.
|
167
|
-
command 'my-command shell' failed
|
168
|
-
|
169
|
-
Cause: Cliqr::Error::IllegalCommandError - Cannot run another shell within an already running shell
|
170
|
-
my-command > exit.
|
171
|
-
shell exited with code 0
|
172
|
-
EOS
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'does not allow shell in shell for sub action' do
|
177
|
-
cli = Cliqr.interface do
|
178
|
-
name 'my-command'
|
179
|
-
|
180
|
-
action :foo do
|
181
|
-
action :bar
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
with_input(['shell']) do
|
186
|
-
result = cli.execute_internal %w(my-command foo shell), output: :buffer
|
187
|
-
expect(result[:stdout]).to eq <<-EOS
|
188
|
-
Starting shell for command "my-command foo"
|
189
|
-
my-command foo > shell.
|
190
|
-
command 'my-command foo shell' failed
|
191
|
-
|
192
|
-
Cause: Cliqr::Error::IllegalCommandError - Cannot run another shell within an already running shell
|
193
|
-
my-command foo > exit.
|
194
|
-
shell exited with code 0
|
195
|
-
EOS
|
196
|
-
end
|
197
|
-
|
198
|
-
with_input(['foo shell']) do
|
199
|
-
result = cli.execute_internal %w(my-command shell), output: :buffer
|
200
|
-
expect(result[:stdout]).to eq <<-EOS
|
201
|
-
Starting shell for command "my-command"
|
202
|
-
my-command > foo shell.
|
203
|
-
command 'my-command foo shell' failed
|
204
|
-
|
205
|
-
Cause: Cliqr::Error::IllegalCommandError - Cannot run another shell within an already running shell
|
206
|
-
my-command > exit.
|
207
|
-
shell exited with code 0
|
208
|
-
EOS
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
def with_input(lines, &block)
|
215
|
-
old_stdin = $stdin
|
216
|
-
$stdin = TestIO.new(lines)
|
217
|
-
block.call
|
218
|
-
ensure
|
219
|
-
$stdin = old_stdin
|
220
|
-
end
|
221
|
-
|
222
|
-
# A test class for wrapping stdin
|
223
|
-
class TestIO
|
224
|
-
def initialize(lines)
|
225
|
-
@lines = lines.reverse
|
226
|
-
end
|
227
|
-
|
228
|
-
def gets
|
229
|
-
input = "#{@lines.length > 0 ? @lines.pop : 'exit'}"
|
230
|
-
puts "#{input}."
|
231
|
-
"#{input}\n"
|
232
|
-
end
|
233
|
-
end
|
data/templates/usage.erb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
<%= command %><% unless description.nil? || description.empty? %> -- <%= description %><% end %>
|
2
|
-
|
3
|
-
USAGE:
|
4
|
-
<%= command %><%=
|
5
|
-
' [actions]' if actions? %><%=
|
6
|
-
' [options]' if options? %><%=
|
7
|
-
' [arguments]' if arguments? %><%
|
8
|
-
|
9
|
-
if options? %>
|
10
|
-
|
11
|
-
Available options:
|
12
|
-
<%
|
13
|
-
options.each { |option|
|
14
|
-
%>
|
15
|
-
--<%=
|
16
|
-
'[no-]' if option.boolean?
|
17
|
-
%><%=
|
18
|
-
option.name
|
19
|
-
%><%=
|
20
|
-
", -#{option.short}" if option.short?
|
21
|
-
%><%=
|
22
|
-
if option.details?
|
23
|
-
" : #{" <#{option.type}>" if option.type?}#{" #{option.description}" if option.description?}#{" (default => #{option.default.inspect})" if option.default?}"
|
24
|
-
end
|
25
|
-
%><%
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
if actions? %>
|
30
|
-
|
31
|
-
Available actions:
|
32
|
-
<%= "[ Type \"#{command} help [action-name]\" to get more information about that action ]\n" if help? %><%
|
33
|
-
actions.each { |action|
|
34
|
-
%>
|
35
|
-
<%= action.name %><%= " -- #{action.description}" if action.description? %>
|
36
|
-
<%
|
37
|
-
}
|
38
|
-
%>
|
39
|
-
<% end %>
|