cliqr 1.1.0 → 1.2.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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +128 -1
  3. data/README.md +97 -71
  4. data/examples/README.md +12 -0
  5. data/examples/hbase +58 -0
  6. data/examples/my-command +63 -0
  7. data/examples/numbers +55 -0
  8. data/examples/vagrant +90 -0
  9. data/lib/cliqr.rb +17 -2
  10. data/lib/cliqr/argument_validation/argument_type_validator.rb +2 -2
  11. data/lib/cliqr/argument_validation/validator.rb +1 -1
  12. data/lib/cliqr/cli/argument_operator.rb +44 -0
  13. data/lib/cliqr/cli/argument_operator_context.rb +20 -0
  14. data/lib/cliqr/cli/command.rb +1 -1
  15. data/lib/cliqr/cli/command_context.rb +93 -12
  16. data/lib/cliqr/cli/command_runner_factory.rb +2 -2
  17. data/lib/cliqr/cli/config.rb +301 -33
  18. data/lib/cliqr/cli/executor.rb +14 -9
  19. data/lib/cliqr/cli/interface.rb +22 -7
  20. data/lib/cliqr/cli/router.rb +6 -2
  21. data/lib/cliqr/cli/shell_command.rb +69 -0
  22. data/lib/cliqr/cli/usage_builder.rb +185 -0
  23. data/lib/cliqr/config_validation/validator_factory.rb +59 -5
  24. data/lib/cliqr/error.rb +10 -4
  25. data/lib/cliqr/parser/action_token.rb +23 -0
  26. data/lib/cliqr/parser/argument_parser.rb +1 -1
  27. data/lib/cliqr/parser/argument_token.rb +1 -4
  28. data/lib/cliqr/parser/argument_tree_walker.rb +40 -8
  29. data/lib/cliqr/parser/option_token.rb +2 -1
  30. data/lib/cliqr/parser/parsed_input.rb +21 -2
  31. data/lib/cliqr/parser/parsed_input_builder.rb +11 -7
  32. data/lib/cliqr/parser/token.rb +3 -9
  33. data/lib/cliqr/parser/token_factory.rb +1 -1
  34. data/lib/cliqr/util.rb +135 -0
  35. data/lib/cliqr/version.rb +1 -1
  36. data/spec/argument_parser_spec_helper.rb +15 -0
  37. data/spec/config/action_config_validator_spec.rb +146 -0
  38. data/spec/config/config_finalize_spec.rb +1 -1
  39. data/spec/config/config_validator_spec.rb +29 -19
  40. data/spec/config/option_config_validator_spec.rb +13 -13
  41. data/spec/dsl/interface_spec.rb +1 -168
  42. data/spec/dsl/usage_spec.rb +705 -0
  43. data/spec/executor/action_executor_spec.rb +205 -0
  44. data/spec/executor/executor_spec.rb +405 -17
  45. data/spec/executor/help_executor_spec.rb +424 -0
  46. data/spec/executor/shell_executor_spec.rb +233 -0
  47. data/spec/fixtures/action_reader_command.rb +12 -0
  48. data/spec/fixtures/csv_argument_operator.rb +8 -0
  49. data/spec/fixtures/test_option_type_checker_command.rb +8 -0
  50. data/spec/parser/action_argument_parser_spec.rb +113 -0
  51. data/spec/parser/argument_parser_spec.rb +37 -44
  52. data/spec/spec_helper.rb +1 -0
  53. data/spec/validation/action_argument_validator_spec.rb +50 -0
  54. data/spec/validation/{argument_validation_spec.rb → command_argument_validation_spec.rb} +36 -18
  55. data/spec/validation/error_spec.rb +1 -1
  56. data/tasks/rdoc.rake +16 -0
  57. data/tasks/rubucop.rake +14 -0
  58. data/tasks/yard.rake +21 -0
  59. data/templates/usage.erb +39 -0
  60. metadata +48 -11
@@ -0,0 +1,146 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'fixtures/test_command'
6
+
7
+ describe Cliqr::CLI::Config do
8
+ it 'does not allow multiple actions with same name' do
9
+ def define_interface
10
+ Cliqr.interface do
11
+ name 'my-command'
12
+ description 'a command used to test cliqr'
13
+ handler TestCommand
14
+
15
+ action 'my-action' do
16
+ handler TestCommand
17
+ end
18
+
19
+ action 'my-action' do
20
+ handler TestCommand
21
+ end
22
+ end
23
+ end
24
+ expect { define_interface }.to(
25
+ raise_error(Cliqr::Error::DuplicateActions, 'multiple actions named "my-action"'))
26
+ end
27
+
28
+ it 'does not allow empty name' do
29
+ def define_interface
30
+ Cliqr.interface do
31
+ name 'my-command'
32
+ description 'a command used to test cliqr'
33
+ handler TestCommand
34
+
35
+ action '' do
36
+ handler TestCommand
37
+ end
38
+ end
39
+ end
40
+ expect { define_interface }.to(raise_error(Cliqr::Error::ValidationError,
41
+ "invalid Cliqr interface configuration - [actions[1] - 'name' cannot be empty]"))
42
+ end
43
+
44
+ it 'does not allow nil name' do
45
+ def define_interface
46
+ Cliqr.interface do
47
+ name 'my-command'
48
+ description 'a command used to test cliqr'
49
+ handler TestCommand
50
+
51
+ action nil do
52
+ handler TestCommand
53
+ end
54
+ end
55
+ end
56
+ expect { define_interface }.to(raise_error(Cliqr::Error::ValidationError,
57
+ "invalid Cliqr interface configuration - [actions[1] - 'name' cannot be nil]"))
58
+ end
59
+
60
+ it 'does not allow invalid characters in name' do
61
+ def define_interface
62
+ Cliqr.interface do
63
+ name 'my-command'
64
+ description 'a command used to test cliqr'
65
+ handler TestCommand
66
+
67
+ action 'invalid-char-!' do
68
+ handler TestCommand
69
+ end
70
+ end
71
+ end
72
+ expect { define_interface }.to(
73
+ raise_error(Cliqr::Error::ValidationError,
74
+ "invalid Cliqr interface configuration - [action \"invalid-char-!\" - value for 'name' must match /^[a-zA-Z0-9_\\-]+$/; actual: \"invalid-char-!\"]"))
75
+ end
76
+
77
+ it 'does not allow command handler to be null if help is disabled and action present' do
78
+ def define_interface
79
+ Cliqr.interface do
80
+ name 'my-command'
81
+ description 'a command used to test cliqr'
82
+ handler TestCommand
83
+
84
+ action 'my-action' do
85
+ help :disable
86
+ end
87
+ end
88
+ end
89
+ expect { define_interface }.to(raise_error(Cliqr::Error::ValidationError,
90
+ 'invalid Cliqr interface configuration - [' \
91
+ "action \"my-action\" - invalid value for handler; fix one of - ['handler' cannot be nil]]"))
92
+ end
93
+
94
+ it 'only accepts command handler that extend from Cliqr::CLI::Command' do
95
+ def define_interface
96
+ Cliqr.interface do
97
+ name 'my-command'
98
+ description 'a command used to test cliqr'
99
+ handler TestCommand
100
+
101
+ action 'my-action' do
102
+ handler Object
103
+ end
104
+ end
105
+ end
106
+ expect { define_interface }.to(raise_error(Cliqr::Error::ValidationError,
107
+ 'invalid Cliqr interface configuration - [' \
108
+ "action \"my-action\" - invalid value for handler; fix one of - [" \
109
+ "handler of type 'Object' does not extend from 'Cliqr::CLI::Command', " \
110
+ "handler should be a 'Proc' not 'Object']]"))
111
+ end
112
+
113
+ it 'throws multiple errors if more than one issue exists in config' do
114
+ def define_interface
115
+ Cliqr.interface do
116
+ name 'invalid-name-!@#'
117
+ handler Object
118
+
119
+ action 'my-action' do
120
+ handler Object
121
+
122
+ action nil do
123
+ help :disable
124
+ end
125
+
126
+ action 'bla' do
127
+ help :disable
128
+ end
129
+ end
130
+ end
131
+ end
132
+ expect { define_interface }.to(
133
+ raise_error(Cliqr::Error::ValidationError,
134
+ 'invalid Cliqr interface configuration - [' \
135
+ "value for 'name' must match /^[a-zA-Z0-9_\\-]+$/; actual: \"invalid-name-!@#\", " \
136
+ 'invalid value for handler; fix one of - [' \
137
+ "handler of type 'Object' does not extend from 'Cliqr::CLI::Command', " \
138
+ "handler should be a 'Proc' not 'Object'], " \
139
+ "action \"my-action\" - invalid value for handler; fix one of - [" \
140
+ "handler of type 'Object' does not extend from 'Cliqr::CLI::Command', " \
141
+ "handler should be a 'Proc' not 'Object'], " \
142
+ "action \"my-action\" - actions[1] - 'name' cannot be nil, " \
143
+ "action \"my-action\" - actions[1] - invalid value for handler; fix one of - ['handler' cannot be nil], " \
144
+ "action \"my-action\" - action \"bla\" - invalid value for handler; fix one of - ['handler' cannot be nil]]"))
145
+ end
146
+ end
@@ -6,7 +6,7 @@ describe Cliqr::CLI::Config do
6
6
  it 'sets proper defaults for unset values' do
7
7
  config = Cliqr::CLI::Config.new
8
8
  config.finalize
9
- expect(config.basename).to eq('')
9
+ expect(config.name).to eq('')
10
10
  expect(config.description).to eq('')
11
11
  expect(config.handler).to eq(nil)
12
12
  expect(config.options).to eq([])
@@ -5,57 +5,64 @@ require 'spec_helper'
5
5
  require 'fixtures/test_command'
6
6
 
7
7
  describe Cliqr::CLI::Config do
8
- it 'does not allow empty basename' do
8
+ it 'does not allow empty name' do
9
9
  expect do
10
10
  Cliqr.interface do
11
- basename ''
11
+ name ''
12
12
  handler TestCommand
13
13
  end
14
14
  end.to(raise_error(Cliqr::Error::ValidationError,
15
- "invalid Cliqr interface configuration - ['basename' cannot be empty]"))
15
+ "invalid Cliqr interface configuration - ['name' cannot be empty]"))
16
16
  end
17
17
 
18
- it 'does not allow nil basename' do
18
+ it 'does not allow nil name' do
19
19
  expect do
20
20
  Cliqr.interface do
21
- basename nil
21
+ name nil
22
22
  handler TestCommand
23
23
  end
24
24
  end.to(raise_error(Cliqr::Error::ValidationError,
25
- "invalid Cliqr interface configuration - ['basename' cannot be nil]"))
25
+ "invalid Cliqr interface configuration - ['name' cannot be nil]"))
26
26
  end
27
27
 
28
- it 'does not allow invalid characters in basename' do
28
+ it 'does not allow invalid characters in name' do
29
29
  expect do
30
30
  Cliqr.interface do
31
- basename 'invalid-char-!'
31
+ name 'invalid-char-!'
32
32
  handler TestCommand
33
33
  end
34
34
  end.to(raise_error(Cliqr::Error::ValidationError,
35
- "invalid Cliqr interface configuration - [value for 'basename' must match /^[a-zA-Z0-9_\\-]+$/; actual: \"invalid-char-!\"]"))
35
+ "invalid Cliqr interface configuration - [value for 'name' must match /^[a-zA-Z0-9_\\-]+$/; actual: \"invalid-char-!\"]"))
36
36
  end
37
37
 
38
- it 'does not allow command handler to be null' do
39
- expect do
38
+ it 'does not allow command handler to be null if no action present' do
39
+ def define_interface
40
40
  Cliqr.interface do
41
- basename 'my-command'
41
+ name 'my-command'
42
+ help :disable
42
43
  end
43
- end.to(raise_error(Cliqr::Error::ValidationError, "invalid Cliqr interface configuration - ['handler' cannot be nil]"))
44
+ end
45
+ expect { define_interface }.to(raise_error(Cliqr::Error::ValidationError,
46
+ 'invalid Cliqr interface configuration - [' \
47
+ "invalid value for handler; fix one of - ['handler' cannot be nil]]"))
44
48
  end
45
49
 
46
50
  it 'only accepts command handler that extend from Cliqr::CLI::Command' do
47
51
  expect do
48
52
  Cliqr.interface do
49
- basename 'my-command'
53
+ name 'my-command'
50
54
  handler Object
51
55
  end
52
56
  end.to(raise_error(Cliqr::Error::ValidationError,
53
- "invalid Cliqr interface configuration - [value 'Object' of type 'Class' for 'handler' does not extend from 'Cliqr::CLI::Command']"))
57
+ 'invalid Cliqr interface configuration - [' \
58
+ 'invalid value for handler; fix one of - [' \
59
+ "handler of type 'Object' does not extend from 'Cliqr::CLI::Command', " \
60
+ "handler should be a 'Proc' not 'Object']]"))
54
61
  end
55
62
 
56
63
  it 'expects that config options should not be nil' do
57
64
  config = Cliqr::CLI::Config.new
58
- config.basename = 'my-command'
65
+ config.name = 'my-command'
59
66
  config.handler = TestCommand
60
67
  config.options = nil
61
68
  config.finalize
@@ -66,11 +73,14 @@ describe Cliqr::CLI::Config do
66
73
  it 'throws multiple errors if more than one issue exists in config' do
67
74
  expect do
68
75
  Cliqr.interface do
69
- basename 'invalid-name-!@#'
76
+ name 'invalid-name-!@#'
70
77
  handler Object
71
78
  end
72
79
  end.to(raise_error(Cliqr::Error::ValidationError,
73
- "invalid Cliqr interface configuration - [value for 'basename' must match /^[a-zA-Z0-9_\\-]+$/; actual: \"invalid-name-!@#\", " \
74
- "value 'Object' of type 'Class' for 'handler' does not extend from 'Cliqr::CLI::Command']"))
80
+ 'invalid Cliqr interface configuration - [' \
81
+ "value for 'name' must match /^[a-zA-Z0-9_\\-]+$/; actual: \"invalid-name-!@#\", " \
82
+ 'invalid value for handler; fix one of - [' \
83
+ "handler of type 'Object' does not extend from 'Cliqr::CLI::Command', " \
84
+ "handler should be a 'Proc' not 'Object']]"))
75
85
  end
76
86
  end
@@ -6,7 +6,7 @@ describe Cliqr::CLI::OptionConfig do
6
6
  it 'does not allow multiple options with same long name' do
7
7
  expect do
8
8
  Cliqr.interface do
9
- basename 'my-command'
9
+ name 'my-command'
10
10
  description 'a command used to test cliqr'
11
11
  handler TestCommand
12
12
 
@@ -24,7 +24,7 @@ describe Cliqr::CLI::OptionConfig do
24
24
  it 'does not allow multiple options with same short name' do
25
25
  expect do
26
26
  Cliqr.interface do
27
- basename 'my-command'
27
+ name 'my-command'
28
28
  description 'a command used to test cliqr'
29
29
  handler TestCommand
30
30
 
@@ -42,7 +42,7 @@ describe Cliqr::CLI::OptionConfig do
42
42
  it 'does not allow option with empty long name' do
43
43
  expect do
44
44
  Cliqr.interface do
45
- basename 'my-command'
45
+ name 'my-command'
46
46
  description 'a command used to test cliqr'
47
47
  handler TestCommand
48
48
 
@@ -57,7 +57,7 @@ describe Cliqr::CLI::OptionConfig do
57
57
  it 'does not allow option with empty short name' do
58
58
  expect do
59
59
  Cliqr.interface do
60
- basename 'my-command'
60
+ name 'my-command'
61
61
  description 'a command used to test cliqr'
62
62
  handler TestCommand
63
63
 
@@ -66,13 +66,13 @@ describe Cliqr::CLI::OptionConfig do
66
66
  end
67
67
  end
68
68
  end.to(raise_error(Cliqr::Error::ValidationError,
69
- "invalid Cliqr interface configuration - [options[1] - 'short' cannot be empty]"))
69
+ "invalid Cliqr interface configuration - [option \"option-1\" - 'short' cannot be empty]"))
70
70
  end
71
71
 
72
72
  it 'does not allow option with nil long name' do
73
73
  expect do
74
74
  Cliqr.interface do
75
- basename 'my-command'
75
+ name 'my-command'
76
76
  description 'a command used to test cliqr'
77
77
  handler TestCommand
78
78
 
@@ -85,7 +85,7 @@ describe Cliqr::CLI::OptionConfig do
85
85
  it 'does not allow option with nil long name for second option' do
86
86
  expect do
87
87
  Cliqr.interface do
88
- basename 'my-command'
88
+ name 'my-command'
89
89
  description 'a command used to test cliqr'
90
90
  handler TestCommand
91
91
 
@@ -99,7 +99,7 @@ describe Cliqr::CLI::OptionConfig do
99
99
  it 'does not allow multiple characters in short name' do
100
100
  expect do
101
101
  Cliqr.interface do
102
- basename 'my-command'
102
+ name 'my-command'
103
103
  description 'a command used to test cliqr'
104
104
  handler TestCommand
105
105
 
@@ -108,13 +108,13 @@ describe Cliqr::CLI::OptionConfig do
108
108
  end
109
109
  end
110
110
  end.to(raise_error(Cliqr::Error::ValidationError,
111
- "invalid Cliqr interface configuration - [options[1] - value for 'short' must match /^[a-z0-9A-Z]$/; actual: \"p1\"]"))
111
+ "invalid Cliqr interface configuration - [option \"option-1\" - value for 'short' must match /^[a-z0-9A-Z]$/; actual: \"p1\"]"))
112
112
  end
113
113
 
114
114
  it 'does not allow invalid type values' do
115
115
  expect do
116
116
  Cliqr.interface do
117
- basename 'my-command'
117
+ name 'my-command'
118
118
  description 'a command used to test cliqr'
119
119
  handler TestCommand
120
120
 
@@ -123,13 +123,13 @@ describe Cliqr::CLI::OptionConfig do
123
123
  end
124
124
  end
125
125
  end.to(raise_error(Cliqr::Error::ValidationError,
126
- "invalid Cliqr interface configuration - [options[1] - invalid type 'random']"))
126
+ "invalid Cliqr interface configuration - [option \"option-1\" - invalid type 'random']"))
127
127
  end
128
128
 
129
129
  it 'does not allow empty type values' do
130
130
  expect do
131
131
  Cliqr.interface do
132
- basename 'my-command'
132
+ name 'my-command'
133
133
  description 'a command used to test cliqr'
134
134
  handler TestCommand
135
135
 
@@ -138,6 +138,6 @@ describe Cliqr::CLI::OptionConfig do
138
138
  end
139
139
  end
140
140
  end.to(raise_error(Cliqr::Error::ValidationError,
141
- "invalid Cliqr interface configuration - [options[1] - invalid type '']"))
141
+ "invalid Cliqr interface configuration - [option \"option-1\" - invalid type '']"))
142
142
  end
143
143
  end
@@ -11,87 +11,9 @@ describe Cliqr::CLI::Interface do
11
11
  end.to(raise_error(Cliqr::Error::ConfigNotFound, 'a valid config should be defined'))
12
12
  end
13
13
 
14
- it 'builds a base command with name' do
15
- cli = Cliqr.interface do
16
- basename 'my-command'
17
- description 'a command used to test cliqr'
18
- handler TestCommand
19
- arguments :disable
20
- end
21
-
22
- expect(cli.usage).to eq <<-EOS
23
- my-command -- a command used to test cliqr
24
-
25
- USAGE:
26
- my-command
27
- EOS
28
- end
29
-
30
- it 'only makes basename and handler to be required' do
31
- cli = Cliqr.interface do
32
- basename 'my-command'
33
- handler TestCommand
34
- arguments :disable
35
- end
36
-
37
- expect(cli.usage).to eq <<-EOS
38
- my-command
39
-
40
- USAGE:
41
- my-command
42
- EOS
43
- end
44
-
45
- it 'allows options for a command' do
46
- cli = Cliqr.interface do
47
- basename 'my-command'
48
- description 'a command used to test cliqr'
49
- handler TestCommand
50
- arguments :disable
51
-
52
- option 'option-1' do
53
- short 'p'
54
- description 'a nice option to have'
55
- end
56
- end
57
-
58
- expect(cli.usage).to eq <<-EOS
59
- my-command -- a command used to test cliqr
60
-
61
- USAGE:
62
- my-command [options]
63
-
64
- Available options:
65
-
66
- --option-1, -p : a nice option to have
67
- EOS
68
- end
69
-
70
- it 'allows command options to optionally have description, type and short name' do
71
- cli = Cliqr.interface do
72
- basename 'my-command'
73
- description 'a command used to test cliqr'
74
- handler TestCommand
75
- arguments :disable
76
-
77
- option 'option-1'
78
- end
79
-
80
- expect(cli.usage).to eq <<-EOS
81
- my-command -- a command used to test cliqr
82
-
83
- USAGE:
84
- my-command [options]
85
-
86
- Available options:
87
-
88
- --option-1
89
- EOS
90
- end
91
-
92
14
  it 'has options if added during build phase' do
93
15
  cli = Cliqr.interface do
94
- basename 'my-command'
16
+ name 'my-command'
95
17
  description 'a command used to test cliqr'
96
18
  handler TestCommand
97
19
 
@@ -102,93 +24,4 @@ Available options:
102
24
  end
103
25
  expect(cli.config.options?).to be_truthy
104
26
  end
105
-
106
- it 'allows command options to have a numeric value type' do
107
- cli = Cliqr.interface do
108
- basename 'my-command'
109
- description 'a command used to test cliqr'
110
- handler TestCommand
111
- arguments :disable
112
-
113
- option 'option-1' do
114
- description 'a numeric option'
115
- short 'p'
116
- type :numeric
117
- end
118
- end
119
-
120
- expect(cli.usage).to eq <<-EOS
121
- my-command -- a command used to test cliqr
122
-
123
- USAGE:
124
- my-command [options]
125
-
126
- Available options:
127
-
128
- --option-1, -p : <numeric> a numeric option
129
- EOS
130
- end
131
-
132
- it 'allows command options to have a boolean value type' do
133
- cli = Cliqr.interface do
134
- basename 'my-command'
135
- description 'a command used to test cliqr'
136
- handler TestCommand
137
- arguments :disable
138
-
139
- option 'option-1' do
140
- description 'a boolean option'
141
- short 'p'
142
- type :boolean
143
- end
144
- end
145
-
146
- expect(cli.usage).to eq <<-EOS
147
- my-command -- a command used to test cliqr
148
-
149
- USAGE:
150
- my-command [options]
151
-
152
- Available options:
153
-
154
- --[no-]option-1, -p : <boolean> a boolean option
155
- EOS
156
- end
157
-
158
- it 'allows interface to enable arbitrary argument list parsing without options' do
159
- cli = Cliqr.interface do
160
- basename 'my-command'
161
- handler TestCommand
162
- arguments :enable
163
- end
164
-
165
- expect(cli.usage).to eq <<-EOS
166
- my-command
167
-
168
- USAGE:
169
- my-command [arguments]
170
- EOS
171
- end
172
-
173
- it 'allows interface to enable arbitrary argument list parsing' do
174
- cli = Cliqr.interface do
175
- basename 'my-command'
176
- handler TestCommand
177
- arguments :enable
178
-
179
- option 'option-1'
180
- end
181
-
182
- expect(cli.usage).to eq <<-EOS
183
- my-command
184
-
185
- USAGE:
186
- my-command [options] [arguments]
187
-
188
- Available options:
189
-
190
- --option-1
191
- EOS
192
- end
193
-
194
27
  end