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,12 @@
1
+ # encoding: utf-8
2
+
3
+ # A command that echoes the actions and options back
4
+ class ActionReaderCommand < Cliqr.command
5
+ def execute(context)
6
+ puts "command = #{context.command}\n\n"
7
+ puts "executing action = #{context.action_name}" if context.action?
8
+ context.options.each do |option|
9
+ puts "[option] #{option.name} => #{option.value}"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ # A argument operator that splits the value by ','
4
+ class CSVArgumentOperator < Cliqr.operator
5
+ def operate(value)
6
+ value.split(',')
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ # A command that echoes the value for option named 'test-option'
4
+ class TestOptionTypeCheckerCommand < Cliqr.command
5
+ def execute(context)
6
+ puts "test-option is of type #{context.option('test-option').value.class}"
7
+ end
8
+ end
@@ -0,0 +1,113 @@
1
+ # encoding: utf-8
2
+
3
+ require 'argument_parser_spec_helper'
4
+
5
+ describe Cliqr::Parser do
6
+ it 'can parse a command with an action' do
7
+ cli = Cliqr.interface do
8
+ name 'my-command'
9
+ handler TestCommand
10
+
11
+ action 'my-action' do
12
+ handler TestCommand
13
+ end
14
+ end
15
+ config = cli.config
16
+ parsed_input = Cliqr::Parser::ParsedInput.new(:command => 'my-command',
17
+ :options => [])
18
+ assert_results(config, ['my-action'], parsed_input, config.action('my-action'))
19
+ end
20
+
21
+ it 'can parse a command with a nested action' do
22
+ cli = Cliqr.interface do
23
+ name 'my-command'
24
+ handler TestCommand
25
+
26
+ action 'my-action-1' do
27
+ handler TestCommand
28
+
29
+ action 'my-action-2' do
30
+ handler TestCommand
31
+
32
+ action 'my-action-3' do
33
+ handler TestCommand
34
+ end
35
+ end
36
+ end
37
+ end
38
+ config = cli.config
39
+ parsed_input = Cliqr::Parser::ParsedInput.new(:command => 'my-command',
40
+ :options => [])
41
+ assert_results(config, %w(my-action-1 my-action-2 my-action-3), parsed_input,
42
+ config.action('my-action-1').action('my-action-2').action('my-action-3'))
43
+ end
44
+
45
+ it 'can parse a command with an action and options' do
46
+ cli = Cliqr.interface do
47
+ name 'my-command'
48
+ handler TestCommand
49
+
50
+ action 'my-action' do
51
+ handler TestCommand
52
+
53
+ option 'test-option-1' do
54
+ short 't'
55
+ end
56
+
57
+ option 'test-option-2' do
58
+ short 'p'
59
+ end
60
+ end
61
+ end
62
+ config = cli.config
63
+ parsed_input = Cliqr::Parser::ParsedInput.new(:command => 'my-command',
64
+ :options => [
65
+ {
66
+ :name => 'test-option-1',
67
+ :value => 'abcd'
68
+ },
69
+ {
70
+ :name => 'test-option-2',
71
+ :value => 'qwe'
72
+ }
73
+ ])
74
+ assert_results(config, %w(my-action -t abcd --test-option-2 qwe), parsed_input, config.action('my-action'))
75
+ end
76
+
77
+ it 'can parse a command with nested action and options' do
78
+ cli = Cliqr.interface do
79
+ name 'my-command'
80
+ handler TestCommand
81
+
82
+ action 'my-action-1' do
83
+ handler TestCommand
84
+
85
+ action 'my-action-2' do
86
+ handler TestCommand
87
+
88
+ option 'test-option-1' do
89
+ short 't'
90
+ end
91
+
92
+ option 'test-option-2' do
93
+ short 'p'
94
+ end
95
+ end
96
+ end
97
+ end
98
+ config = cli.config
99
+ parsed_input = Cliqr::Parser::ParsedInput.new(:command => 'my-command',
100
+ :options => [
101
+ {
102
+ :name => 'test-option-1',
103
+ :value => 'abcd'
104
+ },
105
+ {
106
+ :name => 'test-option-2',
107
+ :value => 'qwe'
108
+ }
109
+ ])
110
+ assert_results(config, %w(my-action-1 -t abcd --test-option-2 qwe my-action-2), parsed_input,
111
+ config.action('my-action-1').action('my-action-2'))
112
+ end
113
+ end
@@ -1,16 +1,10 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'spec_helper'
4
-
5
- require 'cliqr/parser/argument_parser'
6
- require 'cliqr/parser/parsed_input'
7
-
8
- require 'fixtures/test_command'
9
- require 'fixtures/option_reader_command'
3
+ require 'argument_parser_spec_helper'
10
4
 
11
5
  describe Cliqr::Parser do
12
6
  TEST_CLI = Cliqr.interface do
13
- basename 'my-command'
7
+ name 'my-command'
14
8
  handler TestCommand
15
9
  arguments :disable
16
10
 
@@ -19,10 +13,9 @@ describe Cliqr::Parser do
19
13
  end
20
14
  end
21
15
  CONFIG = TEST_CLI.config
22
- PARSER = Cliqr::Parser
23
16
 
24
17
  it 'can parse no argument command' do
25
- expect(PARSER.parse(CONFIG, [])).to eq(Cliqr::Parser::ParsedInput.new(:command => 'my-command', :options => []))
18
+ assert_results(CONFIG, [], Cliqr::Parser::ParsedInput.new(:command => 'my-command', :options => []))
26
19
  end
27
20
 
28
21
  it 'can parse command with option using long name' do
@@ -33,7 +26,7 @@ describe Cliqr::Parser do
33
26
  :value => 'abcd'
34
27
  }
35
28
  ])
36
- expect(PARSER.parse(CONFIG, %w(--test-option abcd))).to eq(parsed_input)
29
+ assert_results(CONFIG, %w(--test-option abcd), parsed_input)
37
30
  end
38
31
 
39
32
  it 'can parse multiple options' do
@@ -49,13 +42,13 @@ describe Cliqr::Parser do
49
42
  }
50
43
  ])
51
44
  cli = Cliqr.interface do
52
- basename 'my-command'
45
+ name 'my-command'
53
46
  handler TestCommand
54
47
 
55
48
  option 'test-option-1'
56
49
  option 'test-option-2'
57
50
  end
58
- expect(Cliqr::Parser.parse(cli.config, %w(--test-option-1 abcd --test-option-2 xyz))).to eq(parsed_input)
51
+ assert_results(cli.config, %w(--test-option-1 abcd --test-option-2 xyz), parsed_input)
59
52
  end
60
53
 
61
54
  it 'can parse command with option using short name' do
@@ -66,36 +59,36 @@ describe Cliqr::Parser do
66
59
  :value => 'abcd'
67
60
  }
68
61
  ])
69
- expect(PARSER.parse(CONFIG, %w(-t abcd))).to eq(parsed_input)
62
+ assert_results(CONFIG, %w(-t abcd), parsed_input)
70
63
  end
71
64
 
72
65
  it 'cannot parse unknown options' do
73
- expect { PARSER.parse(CONFIG, %w(--unknown-option abcd)) }.to(
66
+ expect { Cliqr::Parser.parse(CONFIG, %w(--unknown-option abcd)) }.to(
74
67
  raise_error(Cliqr::Error::UnknownCommandOption, 'unknown option "--unknown-option"'))
75
- expect { PARSER.parse(CONFIG, %w(-u abcd)) }.to(
68
+ expect { Cliqr::Parser.parse(CONFIG, %w(-u abcd)) }.to(
76
69
  raise_error(Cliqr::Error::UnknownCommandOption, 'unknown option "-u"'))
77
70
  end
78
71
 
79
72
  it 'cannot parse invalid options' do
80
- expect { PARSER.parse(CONFIG, %w(--1)) }.to(
81
- raise_error(Cliqr::Error::InvalidArgumentError, 'invalid command argument "--1"'))
82
- expect { PARSER.parse(CONFIG, %w(-$)) }.to(
83
- raise_error(Cliqr::Error::InvalidArgumentError, 'invalid command argument "-$"'))
73
+ expect { Cliqr::Parser.parse(CONFIG, %w(--1)) }.to(
74
+ raise_error(Cliqr::Error::IllegalArgumentError, 'invalid command argument "--1"'))
75
+ expect { Cliqr::Parser.parse(CONFIG, %w(-$)) }.to(
76
+ raise_error(Cliqr::Error::IllegalArgumentError, 'invalid command argument "-$"'))
84
77
  end
85
78
 
86
79
  it 'cannot parse option without value if required' do
87
- expect { PARSER.parse(CONFIG, %w(--test-option)) }.to(
80
+ expect { Cliqr::Parser.parse(CONFIG, %w(--test-option)) }.to(
88
81
  raise_error(Cliqr::Error::OptionValueMissing, 'a value must be defined for argument "--test-option"'))
89
82
  end
90
83
 
91
84
  it 'cannot parse option if it has multiple values' do
92
- expect { PARSER.parse(CONFIG, %w(--test-option val1 --test-option val2)) }.to(
85
+ expect { Cliqr::Parser.parse(CONFIG, %w(--test-option val1 --test-option val2)) }.to(
93
86
  raise_error(Cliqr::Error::MultipleOptionValues, 'multiple values for option "--test-option"'))
94
87
  end
95
88
 
96
89
  it 'can parse command with arguments' do
97
90
  cli = Cliqr.interface do
98
- basename 'my-command'
91
+ name 'my-command'
99
92
  handler TestCommand
100
93
  arguments :enable
101
94
 
@@ -106,19 +99,19 @@ describe Cliqr::Parser do
106
99
  parsed_input = Cliqr::Parser::ParsedInput.new(:command => 'my-command',
107
100
  :options => {},
108
101
  :arguments => ['value1'])
109
- expect(PARSER.parse(cli.config, %w(value1))).to eq(parsed_input)
102
+ assert_results(cli.config, ['value1'], parsed_input)
110
103
  end
111
104
 
112
105
  it 'can parse command with one option and one argument' do
113
106
  parsed_input = Cliqr::Parser::ParsedInput.new(:command => 'my-command',
114
107
  :options => [
115
- {
116
- :name => 'test-option',
117
- :value => 'abcd'
118
- }],
108
+ {
109
+ :name => 'test-option',
110
+ :value => 'abcd'
111
+ }],
119
112
  :arguments => ['value1'])
120
113
  cli = Cliqr.interface do
121
- basename 'my-command'
114
+ name 'my-command'
122
115
  handler TestCommand
123
116
  arguments :enable
124
117
 
@@ -127,13 +120,13 @@ describe Cliqr::Parser do
127
120
  end
128
121
  end
129
122
 
130
- expect(PARSER.parse(cli.config, %w(-t abcd value1))).to eq(parsed_input)
131
- expect(PARSER.parse(cli.config, %w(value1 -t abcd))).to eq(parsed_input)
123
+ assert_results(cli.config, %w(-t abcd value1), parsed_input)
124
+ assert_results(cli.config, %w(value1 -t abcd), parsed_input)
132
125
  end
133
126
 
134
127
  it 'can parse command with a mix of options and arguments' do
135
128
  cli = Cliqr.interface do
136
- basename 'my-command'
129
+ name 'my-command'
137
130
  handler TestCommand
138
131
  arguments :enable
139
132
 
@@ -149,17 +142,17 @@ describe Cliqr::Parser do
149
142
  parsed_input = Cliqr::Parser::ParsedInput.new(:command => 'my-command',
150
143
  :arguments => %w(value1 value2),
151
144
  :options => [
152
- {
153
- :name => 'test-option-1',
154
- :value => 'abcd'
155
- },
156
- {
157
- :name => 'test-option-2',
158
- :value => 'qwe'
159
- }
160
- ])
161
- expect(PARSER.parse(config, %w(-t abcd -p qwe value1 value2))).to eq(parsed_input)
162
- expect(PARSER.parse(config, %w(value1 -t abcd value2 -p qwe))).to eq(parsed_input)
163
- expect(PARSER.parse(config, %w(-t abcd value1 -p qwe value2))).to eq(parsed_input)
145
+ {
146
+ :name => 'test-option-1',
147
+ :value => 'abcd'
148
+ },
149
+ {
150
+ :name => 'test-option-2',
151
+ :value => 'qwe'
152
+ }
153
+ ])
154
+ assert_results(config, %w(-t abcd -p qwe value1 value2), parsed_input)
155
+ assert_results(config, %w(value1 -t abcd value2 -p qwe), parsed_input)
156
+ assert_results(config, %w(-t abcd value1 -p qwe value2), parsed_input)
164
157
  end
165
158
  end
@@ -17,6 +17,7 @@ end
17
17
  if ENV['COVERAGE']
18
18
  require 'simplecov'
19
19
  SimpleCov.start do
20
+ add_filter '/spec/'
20
21
  SimpleCov.minimum_coverage 100
21
22
  end
22
23
  end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'fixtures/test_command'
6
+
7
+ describe Cliqr::ArgumentValidation::Validator do
8
+ it 'does not allow multiple actions at the same level in the same command' do
9
+ cli = Cliqr.interface do
10
+ name 'my-command'
11
+ handler TestCommand
12
+
13
+ action 'my-action' do
14
+ handler TestCommand
15
+ arguments :disable
16
+ end
17
+
18
+ action 'another-action' do
19
+ handler TestCommand
20
+ end
21
+ end
22
+ expect { cli.execute_internal %w(my-action another-action) }.to(
23
+ raise_error(Cliqr::Error::IllegalArgumentError, "invalid command argument \"another-action\""))
24
+ end
25
+
26
+ it 'does not allow illegal nesting of actions in a command' do
27
+ cli = Cliqr.interface do
28
+ name 'my-command'
29
+ handler TestCommand
30
+
31
+ action 'my-action' do
32
+ handler TestCommand
33
+ option 'test-option'
34
+
35
+ action 'third-action' do
36
+ handler TestCommand
37
+ option 'third-option'
38
+ end
39
+ end
40
+
41
+ action 'another-action' do
42
+ handler TestCommand
43
+ option 'test-option'
44
+ arguments :disable
45
+ end
46
+ end
47
+ expect { cli.execute_internal %w(another-action third-action) }.to(
48
+ raise_error(Cliqr::Error::IllegalArgumentError, "invalid command argument \"third-action\""))
49
+ end
50
+ end
@@ -10,7 +10,7 @@ require 'fixtures/test_option_reader_command'
10
10
  describe Cliqr::ArgumentValidation::Validator do
11
11
  it 'can validate numerical arguments' do
12
12
  cli = Cliqr.interface do
13
- basename 'my-command'
13
+ name 'my-command'
14
14
  handler TestOptionReaderCommand
15
15
 
16
16
  option 'test-option' do
@@ -18,31 +18,49 @@ describe Cliqr::ArgumentValidation::Validator do
18
18
  end
19
19
  end
20
20
 
21
- result = cli.execute %w(--test-option 123), output: :buffer
21
+ result = cli.execute_internal %w(--test-option 123), output: :buffer
22
22
  expect(result[:stdout]).to eq <<-EOS
23
23
  123
24
24
  EOS
25
25
  end
26
26
 
27
+ it 'does not allow string for numeric option types in action' do
28
+ cli = Cliqr.interface do
29
+ name 'my-command'
30
+ handler TestCommand
31
+
32
+ action :bla do
33
+ option 'age' do
34
+ type :numeric
35
+ end
36
+ end
37
+ end
38
+
39
+ expect do
40
+ cli.execute_internal %w(bla --age abcd)
41
+ end.to raise_error(Cliqr::Error::IllegalArgumentError,
42
+ "illegal argument error - only values of type 'numeric' allowed for option 'age'")
43
+ end
44
+
27
45
  it 'does not allow string for numeric option types' do
28
46
  cli = Cliqr.interface do
29
- basename 'my-command'
47
+ name 'my-command'
30
48
  handler TestCommand
31
49
 
32
- option 'age' do
50
+ option :age do
33
51
  type :numeric
34
52
  end
35
53
  end
36
54
 
37
55
  expect do
38
- cli.execute %w(--age abcd)
56
+ cli.execute_internal %w(--age abcd)
39
57
  end.to raise_error(Cliqr::Error::IllegalArgumentError,
40
58
  "illegal argument error - only values of type 'numeric' allowed for option 'age'")
41
59
  end
42
60
 
43
61
  it 'can validate boolean option arguments' do
44
62
  cli = Cliqr.interface do
45
- basename 'my-command'
63
+ name 'my-command'
46
64
  handler TestOptionReaderCommand
47
65
 
48
66
  option 'test-option' do
@@ -50,7 +68,7 @@ describe Cliqr::ArgumentValidation::Validator do
50
68
  end
51
69
  end
52
70
 
53
- result = cli.execute %w(--test-option), output: :buffer
71
+ result = cli.execute_internal %w(--test-option), output: :buffer
54
72
  expect(result[:stdout]).to eq <<-EOS
55
73
  true
56
74
  EOS
@@ -58,7 +76,7 @@ true
58
76
 
59
77
  it 'can validate boolean option argumentswith short name' do
60
78
  cli = Cliqr.interface do
61
- basename 'my-command'
79
+ name 'my-command'
62
80
  handler TestOptionReaderCommand
63
81
 
64
82
  option 'test-option' do
@@ -67,7 +85,7 @@ true
67
85
  end
68
86
  end
69
87
 
70
- result = cli.execute %w(-t), output: :buffer
88
+ result = cli.execute_internal %w(-t), output: :buffer
71
89
  expect(result[:stdout]).to eq <<-EOS
72
90
  true
73
91
  EOS
@@ -75,7 +93,7 @@ true
75
93
 
76
94
  it 'can validate boolean option arguments for false' do
77
95
  cli = Cliqr.interface do
78
- basename 'my-command'
96
+ name 'my-command'
79
97
  handler TestOptionReaderCommand
80
98
 
81
99
  option 'test-option' do
@@ -83,7 +101,7 @@ true
83
101
  end
84
102
  end
85
103
 
86
- result = cli.execute %w(--no-test-option), output: :buffer
104
+ result = cli.execute_internal %w(--no-test-option), output: :buffer
87
105
  expect(result[:stdout]).to eq <<-EOS
88
106
  false
89
107
  EOS
@@ -91,7 +109,7 @@ false
91
109
 
92
110
  it 'does not allow string for boolean option types' do
93
111
  cli = Cliqr.interface do
94
- basename 'my-command'
112
+ name 'my-command'
95
113
  handler TestCommand
96
114
  arguments :disable
97
115
 
@@ -101,14 +119,14 @@ false
101
119
  end
102
120
 
103
121
  expect do
104
- cli.execute %w(--opt qwe)
105
- end.to raise_error(Cliqr::Error::InvalidArgumentError,
122
+ cli.execute_internal %w(--opt qwe)
123
+ end.to raise_error(Cliqr::Error::IllegalArgumentError,
106
124
  "invalid command argument \"qwe\"")
107
125
  end
108
126
 
109
127
  it 'allows numeric options to be optional' do
110
128
  cli = Cliqr.interface do
111
- basename 'my-command'
129
+ name 'my-command'
112
130
  description 'this is an awesome command...try it out'
113
131
  handler TestCommand
114
132
 
@@ -117,7 +135,7 @@ false
117
135
  end
118
136
  end
119
137
 
120
- result = cli.execute [], output: :buffer
138
+ result = cli.execute_internal [], output: :buffer
121
139
  expect(result[:stdout]).to eq <<-EOS
122
140
  test command executed
123
141
  EOS
@@ -125,7 +143,7 @@ test command executed
125
143
 
126
144
  it 'allows boolean options to be optional' do
127
145
  cli = Cliqr.interface do
128
- basename 'my-command'
146
+ name 'my-command'
129
147
  description 'this is an awesome command...try it out'
130
148
  handler TestCommand
131
149
 
@@ -134,7 +152,7 @@ test command executed
134
152
  end
135
153
  end
136
154
 
137
- result = cli.execute [], output: :buffer
155
+ result = cli.execute_internal [], output: :buffer
138
156
  expect(result[:stdout]).to eq <<-EOS
139
157
  test command executed
140
158
  EOS