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.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +95 -0
  3. data/README.md +9 -71
  4. data/examples/numbers +1 -2
  5. data/examples/vagrant +0 -3
  6. data/lib/cliqr.rb +52 -11
  7. data/lib/cliqr/argument_validation/argument_type_validator.rb +2 -2
  8. data/lib/cliqr/argument_validation/validator.rb +3 -3
  9. data/lib/cliqr/{cli → command}/argument_operator.rb +2 -2
  10. data/lib/cliqr/{cli → command}/argument_operator_context.rb +1 -1
  11. data/lib/cliqr/{cli/command.rb → command/base_command.rb} +2 -2
  12. data/lib/cliqr/command/color.rb +174 -0
  13. data/lib/cliqr/{cli → command}/command_context.rb +68 -20
  14. data/lib/cliqr/command/shell_banner_builder.rb +17 -0
  15. data/lib/cliqr/command/shell_command.rb +125 -0
  16. data/lib/cliqr/command/shell_prompt_builder.rb +26 -0
  17. data/lib/cliqr/config/action.rb +226 -0
  18. data/lib/cliqr/config/base.rb +84 -0
  19. data/lib/cliqr/config/command.rb +137 -0
  20. data/lib/cliqr/config/dsl.rb +81 -0
  21. data/lib/cliqr/config/event.rb +43 -0
  22. data/lib/cliqr/config/event_based.rb +78 -0
  23. data/lib/cliqr/config/named.rb +55 -0
  24. data/lib/cliqr/config/option.rb +95 -0
  25. data/lib/cliqr/config/option_based.rb +130 -0
  26. data/lib/cliqr/config/shell.rb +87 -0
  27. data/lib/cliqr/config/validation/validation_set.rb +66 -0
  28. data/lib/cliqr/config/validation/validator_factory.rb +403 -0
  29. data/lib/cliqr/config/validation/verifiable.rb +91 -0
  30. data/lib/cliqr/error.rb +20 -4
  31. data/lib/cliqr/events/event.rb +56 -0
  32. data/lib/cliqr/events/event_context.rb +31 -0
  33. data/lib/cliqr/events/handler.rb +32 -0
  34. data/lib/cliqr/events/invoker.rb +70 -0
  35. data/lib/cliqr/{cli → executor}/command_runner_factory.rb +3 -3
  36. data/lib/cliqr/{cli → executor}/router.rb +4 -4
  37. data/lib/cliqr/{cli/executor.rb → executor/runner.rb} +25 -10
  38. data/lib/cliqr/interface.rb +98 -0
  39. data/lib/cliqr/parser/token_factory.rb +1 -1
  40. data/lib/cliqr/usage/command_usage_context.rb +94 -0
  41. data/lib/cliqr/usage/option_usage_context.rb +86 -0
  42. data/lib/cliqr/usage/templates/partial/action_list.erb +10 -0
  43. data/lib/cliqr/usage/templates/partial/command_name.erb +3 -0
  44. data/lib/cliqr/usage/templates/partial/option_list.erb +18 -0
  45. data/lib/cliqr/usage/templates/partial/usage_info.erb +5 -0
  46. data/lib/cliqr/usage/templates/usage/cli.erb +4 -0
  47. data/lib/cliqr/usage/templates/usage/shell.erb +2 -0
  48. data/lib/cliqr/usage/usage_builder.rb +59 -0
  49. data/lib/cliqr/util.rb +81 -34
  50. data/lib/cliqr/version.rb +1 -1
  51. data/spec/config/action_config_validator_spec.rb +127 -5
  52. data/spec/config/config_finalize_spec.rb +3 -3
  53. data/spec/config/config_validator_spec.rb +120 -17
  54. data/spec/config/option_config_validator_spec.rb +1 -1
  55. data/spec/dsl/interface_spec.rb +2 -2
  56. data/spec/dsl/usage_spec.rb +461 -465
  57. data/spec/executor/action_executor_spec.rb +1 -1
  58. data/spec/executor/color_executor_spec.rb +125 -0
  59. data/spec/executor/command_runner_spec.rb +6 -8
  60. data/spec/executor/event_executor_spec.rb +365 -0
  61. data/spec/executor/executor_spec.rb +49 -11
  62. data/spec/executor/help_executor_spec.rb +107 -103
  63. data/spec/fixtures/action_reader_command.rb +1 -1
  64. data/spec/fixtures/test_arg_printer_event_handler.rb +9 -0
  65. data/spec/fixtures/test_color_shell_prompt.rb +13 -0
  66. data/spec/fixtures/test_empty_event_handler.rb +5 -0
  67. data/spec/fixtures/test_invoker_event_handler.rb +9 -0
  68. data/spec/fixtures/test_shell_banner.rb +8 -0
  69. data/spec/fixtures/test_shell_prompt.rb +13 -0
  70. data/spec/shell/shell_executor_spec.rb +700 -0
  71. data/spec/validation/validation_spec.rb +2 -2
  72. metadata +65 -27
  73. data/lib/cliqr/cli/config.rb +0 -554
  74. data/lib/cliqr/cli/interface.rb +0 -107
  75. data/lib/cliqr/cli/shell_command.rb +0 -69
  76. data/lib/cliqr/cli/usage_builder.rb +0 -185
  77. data/lib/cliqr/config_validation/validation_set.rb +0 -48
  78. data/lib/cliqr/config_validation/validator_factory.rb +0 -319
  79. data/lib/cliqr/config_validation/verifiable.rb +0 -89
  80. data/lib/cliqr/dsl.rb +0 -59
  81. data/spec/executor/shell_executor_spec.rb +0 -233
  82. 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
@@ -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
@@ -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 %>