cliqr 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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