cli-console 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.yardopts +1 -0
- data/Gemfile +10 -0
- data/README.md +65 -0
- data/Rakefile +10 -0
- data/UNLICENSE +24 -0
- data/cli-console.gemspec +20 -0
- data/examples/shell.rb +46 -0
- data/lib/cli-console.rb +301 -0
- data/lib/cli-console/task.rb +64 -0
- data/lib/cli-console/version.rb +6 -0
- data/spec/cli-console_spec.rb +108 -0
- data/spec/spec_helper.rb +17 -0
- metadata +61 -0
data/.gitignore
ADDED
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# CLI::Console
|
2
|
+
|
3
|
+
|
4
|
+
Basic library for making interactive command-line applications much easier.
|
5
|
+
|
6
|
+
|
7
|
+
## Features
|
8
|
+
|
9
|
+
* Easy way to add commands and help info to them so it can be shown to user.
|
10
|
+
* Auto-completion for commands.
|
11
|
+
* Command aliasing.
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Simply
|
17
|
+
|
18
|
+
`gem install cli-console`
|
19
|
+
|
20
|
+
### Dependecies
|
21
|
+
|
22
|
+
This library doesn't have any dependencies.
|
23
|
+
Well actually there's no direct dependencies.
|
24
|
+
But in reality need HighLine and Readline.
|
25
|
+
Then why I said there's no dependencies?
|
26
|
+
Because `CLI::Console` will accept any IO class with implements those few functions which currently are provided by HighLine.
|
27
|
+
|
28
|
+
|
29
|
+
## Usage Example
|
30
|
+
|
31
|
+
Take a look at [/examples/shell.rb](/davispuh/examples/shell.rb)
|
32
|
+
|
33
|
+
|
34
|
+
## Documentation
|
35
|
+
|
36
|
+
YARD with markdown is used for documentation (`redcarpet` required)
|
37
|
+
|
38
|
+
## Specs
|
39
|
+
|
40
|
+
RSpec and simplecov are required, to run tests just `rake spec`
|
41
|
+
code coverage will also be generated
|
42
|
+
|
43
|
+
## Authors
|
44
|
+
|
45
|
+
Currently everything (all functions, files, text) in this repository are made by me @davispuh and I've dedicated this repository to public domain.
|
46
|
+
|
47
|
+
|
48
|
+
## Unlicense
|
49
|
+
|
50
|
+
All text, documentation, code and files in this repository are in public domain (including this text, README).
|
51
|
+
It means you can copy, modify, distribute and include in your own work/code, even for commercial purposes, all without asking permission.
|
52
|
+
|
53
|
+
|
54
|
+
## Contributing
|
55
|
+
|
56
|
+
Feel free to improve anything what you see is improvable.
|
57
|
+
|
58
|
+
|
59
|
+
**Warning**: By sending pull request to this repository you dedicate any and all copyright interest in pull request (code files and all other) to the public domain. (files will be in public domain even if pull request doesn't get merged)
|
60
|
+
|
61
|
+
Also before sending pull request you acknowledge that you own all copyrights or have authorization to dedicate them to public domain.
|
62
|
+
|
63
|
+
If you don't want to dedicate code to public domain or if you're not allowed to (eg. you don't own required copyrights) then DON'T send pull request.
|
64
|
+
|
65
|
+
|
data/Rakefile
ADDED
data/UNLICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
2
|
+
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
4
|
+
distribute this software, either in source code form or as a compiled
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
6
|
+
means.
|
7
|
+
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
9
|
+
of this software dedicate any and all copyright interest in the
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
11
|
+
of the public at large and to the detriment of our heirs and
|
12
|
+
successors. We intend this dedication to be an overt act of
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
14
|
+
software under copyright law.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
|
24
|
+
For more information, please refer to <http://unlicense.org/>
|
data/cli-console.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cli-console/version'
|
5
|
+
|
6
|
+
|
7
|
+
Gem::Specification.new do |gem|
|
8
|
+
gem.name = 'cli-console'
|
9
|
+
gem.version = CLI::Console::VERSION
|
10
|
+
gem.authors = ['Dāvis']
|
11
|
+
gem.email = ['davispuh@gmail.com']
|
12
|
+
gem.description = 'Basic library for making interactive command-line applications much easier'
|
13
|
+
gem.summary = 'Create CLI applications easily'
|
14
|
+
gem.homepage = 'https://github.com/davispuh/CLI-Console'
|
15
|
+
|
16
|
+
gem.files = `git ls-files`.split($/)
|
17
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
|
+
gem.require_paths = ['lib']
|
20
|
+
end
|
data/examples/shell.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'highline'
|
2
|
+
require 'cli-console'
|
3
|
+
|
4
|
+
|
5
|
+
class ShellUI
|
6
|
+
private
|
7
|
+
extend CLI::Task
|
8
|
+
|
9
|
+
public
|
10
|
+
|
11
|
+
usage 'Usage: ls'
|
12
|
+
desc 'List file information about current directory'
|
13
|
+
def ls(params)
|
14
|
+
Dir.foreach(Dir.pwd) do |file|
|
15
|
+
puts file
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
usage 'Usage: pwd'
|
20
|
+
desc 'Display current directory'
|
21
|
+
|
22
|
+
def pwd(params)
|
23
|
+
puts "Current directory: #{Dir.pwd}"
|
24
|
+
end
|
25
|
+
|
26
|
+
usage 'Usage: cd <Directory>'
|
27
|
+
desc 'Change current directory'
|
28
|
+
|
29
|
+
def cd(params)
|
30
|
+
Dir.chdir(params[0]) unless params.empty?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
io = HighLine.new
|
35
|
+
shell = ShellUI.new
|
36
|
+
console = CLI::Console.new(io)
|
37
|
+
|
38
|
+
console.addCommand('ls', shell.method(:ls), 'List files')
|
39
|
+
console.addCommand('pwd', shell.method(:pwd), 'Current directory')
|
40
|
+
console.addCommand('cd', shell.method(:cd), 'Change directory')
|
41
|
+
console.addHelpCommand('help', 'Help')
|
42
|
+
console.addExitCommand('exit', 'Exit from program')
|
43
|
+
console.addAlias('quit', 'exit')
|
44
|
+
|
45
|
+
console.start("%s> ",[Dir.method(:pwd)])
|
46
|
+
|
data/lib/cli-console.rb
ADDED
@@ -0,0 +1,301 @@
|
|
1
|
+
require 'cli-console/version'
|
2
|
+
require 'cli-console/task'
|
3
|
+
|
4
|
+
|
5
|
+
# Command-line interface module
|
6
|
+
module CLI
|
7
|
+
# Console class
|
8
|
+
#
|
9
|
+
# ```ruby
|
10
|
+
# # io some input/output class (like HighLine)
|
11
|
+
# console = CLI::Console.new(io)
|
12
|
+
# ```
|
13
|
+
class Console
|
14
|
+
private
|
15
|
+
def initialize(io)
|
16
|
+
@Commands = {}
|
17
|
+
@Aliases = {}
|
18
|
+
@IO = io
|
19
|
+
@Seperator = '-'
|
20
|
+
@SepCount = 30
|
21
|
+
@Backtrace = false
|
22
|
+
@Partial = true
|
23
|
+
@ExitCode = -100
|
24
|
+
@UseReadline = true
|
25
|
+
end
|
26
|
+
|
27
|
+
# Outputs nicely formated exception
|
28
|
+
# displays backtrace if @Backtrace
|
29
|
+
# @param [Exception] exception to display
|
30
|
+
def showException(exception)
|
31
|
+
@IO.say "Exception: #{exception.message.strip}"
|
32
|
+
if @Backtrace
|
33
|
+
@IO.say 'Backtrace:'
|
34
|
+
@IO.indent do |io|
|
35
|
+
exception.backtrace.each do |b|
|
36
|
+
io.say b
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
public
|
43
|
+
attr_accessor :Partial
|
44
|
+
attr_accessor :ExitCode
|
45
|
+
attr_accessor :Seperator
|
46
|
+
attr_accessor :SepCount
|
47
|
+
attr_accessor :Backtrace
|
48
|
+
attr_accessor :UseReadline
|
49
|
+
|
50
|
+
# Adds command
|
51
|
+
# @param commandName [String] name of command
|
52
|
+
# @param command [Method] command method
|
53
|
+
# @param commandDescription [String] short description about command
|
54
|
+
# @param commandLongDescription [String] long description about command
|
55
|
+
# @param commandUsage [String] usage information about command
|
56
|
+
# @return [Array] command information
|
57
|
+
def addCommand(commandName, command, commandDescription='', commandLongDescription = nil, commandUsage = nil)
|
58
|
+
commandLongDescription = command.owner.get_description(command.name) if commandLongDescription == nil
|
59
|
+
commandUsage = command.owner.get_usage(command.name) if commandUsage == nil
|
60
|
+
@Commands[commandName] = [command, commandDescription, commandLongDescription, commandUsage]
|
61
|
+
end
|
62
|
+
|
63
|
+
# Adds name for exit command
|
64
|
+
# @param commandName [String] name of exit command
|
65
|
+
# @param commandDescription [String] short description about command
|
66
|
+
# @param commandLongDescription [String] long description about command
|
67
|
+
# @param commandUsage [String] usage information about command
|
68
|
+
# @return [Array] command information
|
69
|
+
def addExitCommand(commandName, commandDescription='', commandLongDescription = nil, commandUsage = nil)
|
70
|
+
commandLongDescription = 'Exit...' unless commandLongDescription
|
71
|
+
commandUsage = ['exit'] unless commandUsage
|
72
|
+
@Commands[commandName] = [method(:end), commandDescription, commandLongDescription, commandUsage]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Adds name for help command
|
76
|
+
# @param commandName [String] name of exit command
|
77
|
+
# @param commandDescription [String] short description about command
|
78
|
+
# @param commandLongDescription [String] long description about command
|
79
|
+
# @param commandUsage [String] usage information about command
|
80
|
+
# @return [Array] command information
|
81
|
+
def addHelpCommand(commandName, commandDescription='', commandLongDescription = nil, commandUsage = nil)
|
82
|
+
commandLongDescription = 'Display Help for <command>' unless commandLongDescription
|
83
|
+
commandUsage = ['help <command>'] unless commandUsage
|
84
|
+
@Commands[commandName] = [method(:help), commandDescription, commandLongDescription, commandUsage]
|
85
|
+
end
|
86
|
+
|
87
|
+
# Adds alias for command
|
88
|
+
# @param aliasName [String] name of for alias
|
89
|
+
# @param commandNameParms [String] command to alias
|
90
|
+
# @param commandDescription [String] short description about alias
|
91
|
+
# @param commandLongDescription [String] long description about alias
|
92
|
+
# @param commandUsage [String] usage information about alias
|
93
|
+
# @return [Array] alias information
|
94
|
+
def addAlias(aliasName, commandNameParms, commandDescription=nil, commandLongDescription = nil, commandUsage = nil)
|
95
|
+
@Aliases[aliasName] = [commandNameParms, commandDescription, commandLongDescription, commandUsage]
|
96
|
+
end
|
97
|
+
|
98
|
+
# Waits till user enters command
|
99
|
+
# @param inputText [String] text to show to user
|
100
|
+
# @return [String] entered command
|
101
|
+
def getCommand(inputText)
|
102
|
+
@LastCommand = @IO.ask(inputText) do |h|
|
103
|
+
h.whitespace = :strip_and_collapse
|
104
|
+
h.validate = nil
|
105
|
+
h.readline = @UseReadline
|
106
|
+
h.completion = @Commands.keys+@Aliases.keys
|
107
|
+
end
|
108
|
+
@LastCommand = '' if (not @LastCommand.to_s.empty? and @LastCommand[0] == '#')
|
109
|
+
return @LastCommand
|
110
|
+
end
|
111
|
+
|
112
|
+
# @param command [String]
|
113
|
+
# @return [Array]
|
114
|
+
def commandMatch(command)
|
115
|
+
matches = []
|
116
|
+
commandStrings = @Commands.merge(@Aliases)
|
117
|
+
commandStrings.each do |key, value|
|
118
|
+
matches.push([key, value]) if (@Partial and key.start_with?(command)) or key == command
|
119
|
+
end
|
120
|
+
matches
|
121
|
+
end
|
122
|
+
|
123
|
+
# displays matched commands
|
124
|
+
# @param matches [Array]
|
125
|
+
def showMatches(matches)
|
126
|
+
@IO.say('Matches:')
|
127
|
+
matches.each do |value|
|
128
|
+
text = value[0].to_s
|
129
|
+
text += ' - '+value[1][1].to_s unless value[1][1].to_s.empty?
|
130
|
+
@IO.indent(1, text )
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Executes command with parameters
|
135
|
+
# @param commandString [String]
|
136
|
+
# @return command result or error number
|
137
|
+
def processCommand(commandString)
|
138
|
+
return 0 if commandString.to_s.empty?
|
139
|
+
commandWords = []
|
140
|
+
commandString.scan(/([^\s"']+)|"([^"]*)"|'([^']*)'/) do |m|
|
141
|
+
commandWords << m[0] unless m[0].nil?
|
142
|
+
commandWords << m[1] unless m[1].nil?
|
143
|
+
commandWords << m[2] unless m[2].nil?
|
144
|
+
end
|
145
|
+
command = commandWords.shift.downcase
|
146
|
+
|
147
|
+
if (not @Commands.key?(command) and not @Aliases.key?(command))
|
148
|
+
matches = commandMatch(command)
|
149
|
+
if matches.length == 1
|
150
|
+
if matches[0][1][0].class == String
|
151
|
+
oldCommandWords = [matches[0][1][0]]
|
152
|
+
commandWords = @Aliases[matches[0][0]][0].split
|
153
|
+
command = commandWords.shift.downcase
|
154
|
+
commandWords += oldCommandWords
|
155
|
+
else
|
156
|
+
command = matches[0][0]
|
157
|
+
end
|
158
|
+
elsif matches.length > 0
|
159
|
+
@IO.say('Ambiguous command.')
|
160
|
+
showMatches(matches)
|
161
|
+
return -3
|
162
|
+
else
|
163
|
+
@IO.say("Command \"#{command}\" not recognized.")
|
164
|
+
return -2
|
165
|
+
end
|
166
|
+
elsif @Aliases.key?(command)
|
167
|
+
oldCommandWords = commandWords
|
168
|
+
commandWords = @Aliases[command][0].split
|
169
|
+
command = commandWords.shift.downcase
|
170
|
+
commandWords += oldCommandWords
|
171
|
+
end
|
172
|
+
begin
|
173
|
+
return @Commands[command][0].call(commandWords)
|
174
|
+
rescue Exception => e
|
175
|
+
showException(e)
|
176
|
+
end
|
177
|
+
return -1
|
178
|
+
end
|
179
|
+
|
180
|
+
# Starts main CLI loop, waits for user input
|
181
|
+
# @param formatString [String]
|
182
|
+
# @param formatValues [Array]
|
183
|
+
# @return [Fixnum]
|
184
|
+
def start(formatString, formatValues)
|
185
|
+
indent_level = @IO.indent_level
|
186
|
+
loop do
|
187
|
+
begin
|
188
|
+
currentValues = []
|
189
|
+
formatValues.each do |value|
|
190
|
+
if value.respond_to?("call")
|
191
|
+
currentValues.push(value.call)
|
192
|
+
else
|
193
|
+
currentValues.push(value)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
command = getCommand( formatString % currentValues )
|
197
|
+
@IO.indent_level+=1
|
198
|
+
result = processCommand(command)
|
199
|
+
@IO.indent_level-=1
|
200
|
+
return 0 if result == @ExitCode
|
201
|
+
rescue Exception => e
|
202
|
+
showException(e)
|
203
|
+
@IO.indent_level=indent_level
|
204
|
+
end
|
205
|
+
end
|
206
|
+
-1
|
207
|
+
end
|
208
|
+
|
209
|
+
# Displays seperator line
|
210
|
+
def printSeperator
|
211
|
+
@IO.say(@Seperator*@SepCount)
|
212
|
+
end
|
213
|
+
|
214
|
+
# Displays help about command
|
215
|
+
# @param command [String] command for which display help
|
216
|
+
def commandHelp(command)
|
217
|
+
if @Commands.key?(command)
|
218
|
+
printSeperator
|
219
|
+
if not @Commands[command][3].to_a.empty?
|
220
|
+
@IO.indent do |io|
|
221
|
+
@Commands[command][3].each { |c| io.say c}
|
222
|
+
io.newline
|
223
|
+
end
|
224
|
+
end
|
225
|
+
@IO.say(@Commands[command][2]) unless @Commands[command][2].to_s.empty?
|
226
|
+
printSeperator
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Displays usage
|
231
|
+
def usage
|
232
|
+
@IO.say('Type "help" to display available commands')
|
233
|
+
end
|
234
|
+
|
235
|
+
# Shows message to inform how to get more information about command
|
236
|
+
# @param helpCommand [String] command for which display message
|
237
|
+
def command_usage(helpCommand='help')
|
238
|
+
@IO.say("You can type \"#{helpCommand} <command>\" for more info")
|
239
|
+
end
|
240
|
+
|
241
|
+
# Shows help information about command
|
242
|
+
# @param params [Array] command for which show help
|
243
|
+
def help(params=[])
|
244
|
+
if not params.to_a.empty?
|
245
|
+
command = params[0].downcase
|
246
|
+
if (not @Commands.key?(command) and not @Aliases.key?(command))
|
247
|
+
matches = commandMatch command
|
248
|
+
if (matches.length == 1)
|
249
|
+
commandHelp(matches[0][0])
|
250
|
+
elsif matches.length > 0
|
251
|
+
@IO.say('Help for ambiguous command.')
|
252
|
+
showMatches matches
|
253
|
+
else
|
254
|
+
@IO.say("Help for command \"#{params[0]}\" not found!")
|
255
|
+
end
|
256
|
+
elsif @Aliases.key?(command)
|
257
|
+
if not @Aliases[command][2].to_s.empty?
|
258
|
+
@IO.say(@Aliases[command][2])
|
259
|
+
else
|
260
|
+
commandHelp(@Aliases[command][0].split()[0])
|
261
|
+
end
|
262
|
+
else
|
263
|
+
commandHelp(command)
|
264
|
+
end
|
265
|
+
else
|
266
|
+
helpCommand = 'help'
|
267
|
+
printSeperator
|
268
|
+
@IO.indent do |io|
|
269
|
+
@Commands.each do |key,value|
|
270
|
+
if (value[0].name != 'help')
|
271
|
+
helpText = key
|
272
|
+
if (not value[1].to_s.empty?)
|
273
|
+
helpText += ' - '+value[1]
|
274
|
+
end
|
275
|
+
io.say(helpText)
|
276
|
+
else
|
277
|
+
helpCommand = value[0].name
|
278
|
+
end
|
279
|
+
end
|
280
|
+
@Aliases.each do |key, value|
|
281
|
+
helpText = key
|
282
|
+
if (not value[1].to_s.empty?)
|
283
|
+
helpText += ' - '+value[1]
|
284
|
+
else
|
285
|
+
helpText += ' - alias to "'+value[0]+'"'
|
286
|
+
end
|
287
|
+
io.say(helpText)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
command_usage(helpCommand)
|
291
|
+
printSeperator
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# @param params [Array] unused
|
296
|
+
# @return [Fixnum]
|
297
|
+
def end(params=[])
|
298
|
+
@ExitCode
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module CLI
|
2
|
+
# Task module which must be included in class which provides commands
|
3
|
+
#
|
4
|
+
# Example:
|
5
|
+
#
|
6
|
+
# ```ruby
|
7
|
+
# class UI
|
8
|
+
# extend CLI::Task
|
9
|
+
#
|
10
|
+
# usage 'Usage: command'
|
11
|
+
# desc 'command desciption'
|
12
|
+
#
|
13
|
+
# def command(params)
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# end
|
17
|
+
# ```
|
18
|
+
module Task
|
19
|
+
private
|
20
|
+
@@__usage__ = {}
|
21
|
+
@@__desc__ = {}
|
22
|
+
|
23
|
+
# sets usage for command
|
24
|
+
# @param usage [String]
|
25
|
+
# @return @usage
|
26
|
+
def usage(usage)
|
27
|
+
usage = [usage.to_s] unless usage.class == Array
|
28
|
+
@usage = usage
|
29
|
+
end
|
30
|
+
|
31
|
+
# sets description for command
|
32
|
+
# @param desc [String] description
|
33
|
+
# @return @desc
|
34
|
+
def desc(desc)
|
35
|
+
@desc = desc
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_added(method)
|
39
|
+
name = method.to_s
|
40
|
+
return unless name != 'initialize' and (public_instance_methods.include?(name) or public_instance_methods.include?(name.to_sym))
|
41
|
+
@@__desc__[method]=@desc unless @@__desc__.key?(method)
|
42
|
+
@@__usage__[method]=@usage unless @@__usage__.key?(method)
|
43
|
+
@desc = nil
|
44
|
+
@usage = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
public
|
48
|
+
|
49
|
+
# description for command
|
50
|
+
# @param name [String] name of command
|
51
|
+
# @return [String] description
|
52
|
+
def get_description(name)
|
53
|
+
return @@__desc__[name] if @@__desc__.key?(name)
|
54
|
+
end
|
55
|
+
|
56
|
+
# usage information for command
|
57
|
+
# @param name [String] name of command
|
58
|
+
# @return [String] usage
|
59
|
+
def get_usage(name)
|
60
|
+
return @@__usage__[name] if @@__usage__.key?(name)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
class UI
|
5
|
+
private
|
6
|
+
extend CLI::Task
|
7
|
+
|
8
|
+
public
|
9
|
+
|
10
|
+
usage 'Usage: try'
|
11
|
+
desc 'try exception'
|
12
|
+
def try(params)
|
13
|
+
raise Exception, params[0]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe CLI::Console do
|
18
|
+
let(:input) { StringIO.new }
|
19
|
+
let(:output) { StringIO.new }
|
20
|
+
let(:io) { HighLine.new(input, output) }
|
21
|
+
let(:console) { CLI::Console.new(io) }
|
22
|
+
let(:ui) { UI.new }
|
23
|
+
|
24
|
+
def init
|
25
|
+
console.UseReadline = false
|
26
|
+
console.addCommand('try',ui.method(:try))
|
27
|
+
console.addHelpCommand('help')
|
28
|
+
console.addExitCommand('exit')
|
29
|
+
console.addAlias('trymore','try')
|
30
|
+
console.addAlias('quit','exit')
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#initialize' do
|
34
|
+
it 'should return cli-console instance' do
|
35
|
+
console.should be_kind_of(CLI::Console)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#addCommand' do
|
40
|
+
it 'should return array of command data' do
|
41
|
+
commandData = [:test, 'short desc', 'long desc', 'usage']
|
42
|
+
console.addCommand('test', *commandData).should eq(commandData)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#addExitCommand' do
|
47
|
+
it 'should return array of exit command data' do
|
48
|
+
commandData = [console.method(:end), 'exit', 'Exit from program', 'usage']
|
49
|
+
console.addExitCommand('test', commandData[1], commandData[2], commandData[3]).should eq(commandData)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#addHelpCommand' do
|
54
|
+
it 'should return array of help command data' do
|
55
|
+
commandData = [console.method(:help), 'help', 'Help', 'usage']
|
56
|
+
console.addHelpCommand('test', commandData[1], commandData[2], commandData[3]).should eq(commandData)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#addAlias' do
|
61
|
+
it 'should return array of help command data' do
|
62
|
+
commandData = ['command', 'short desc', 'long desc', 'usage']
|
63
|
+
console.addAlias('alias', *commandData).should eq(commandData)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#usage' do
|
68
|
+
it 'should display usage' do
|
69
|
+
console.usage
|
70
|
+
output.string.should eq("Type \"help\" to display available commands\n")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#processCommand' do
|
75
|
+
it 'should execute succesfully' do
|
76
|
+
init
|
77
|
+
console.processCommand('tr')
|
78
|
+
console.processCommand('try more')
|
79
|
+
console.processCommand('q')
|
80
|
+
console.processCommand('quit')
|
81
|
+
console.processCommand('help')
|
82
|
+
console.processCommand('help tr')
|
83
|
+
console.processCommand('help try')
|
84
|
+
console.processCommand('help not')
|
85
|
+
console.processCommand('help e')
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '#start' do
|
90
|
+
def left
|
91
|
+
'left'
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should start CLI' do
|
95
|
+
input << "try lol\nnot found\nexit\n"
|
96
|
+
input.rewind
|
97
|
+
init
|
98
|
+
console.start('%s> ',[method(:left)]).should eq(0)
|
99
|
+
out = 'left> Exception: lol
|
100
|
+
left> Command "not" not recognized.
|
101
|
+
left> '
|
102
|
+
|
103
|
+
output.string.should eq(out)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
|
3
|
+
|
4
|
+
SimpleCov.start
|
5
|
+
|
6
|
+
require_relative '../lib/cli-console.rb'
|
7
|
+
require 'highline'
|
8
|
+
|
9
|
+
|
10
|
+
if HighLine::CHARACTER_MODE == "Win32API"
|
11
|
+
class HighLine
|
12
|
+
# Override Windows' character reading so it's not tied to STDIN.
|
13
|
+
def get_character( input = STDIN )
|
14
|
+
input.getc
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cli-console
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dāvis
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-02 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Basic library for making interactive command-line applications much easier
|
15
|
+
email:
|
16
|
+
- davispuh@gmail.com
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- .gitignore
|
22
|
+
- .yardopts
|
23
|
+
- Gemfile
|
24
|
+
- README.md
|
25
|
+
- Rakefile
|
26
|
+
- UNLICENSE
|
27
|
+
- cli-console.gemspec
|
28
|
+
- examples/shell.rb
|
29
|
+
- lib/cli-console.rb
|
30
|
+
- lib/cli-console/task.rb
|
31
|
+
- lib/cli-console/version.rb
|
32
|
+
- spec/cli-console_spec.rb
|
33
|
+
- spec/spec_helper.rb
|
34
|
+
homepage: https://github.com/davispuh/CLI-Console
|
35
|
+
licenses: []
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.8.25
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: Create CLI applications easily
|
58
|
+
test_files:
|
59
|
+
- spec/cli-console_spec.rb
|
60
|
+
- spec/spec_helper.rb
|
61
|
+
has_rdoc:
|