gli 1.6.0 → 2.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/.rvmrc +1 -0
- data/.travis.yml +10 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +201 -0
- data/ObjectModel.graffle +1191 -0
- data/README.rdoc +60 -10
- data/Rakefile +145 -0
- data/bin/gli +12 -30
- data/bin/report_on_rake_results +10 -0
- data/bin/test_all_rubies.sh +6 -0
- data/features/gli_executable.feature +84 -0
- data/features/gli_init.feature +219 -0
- data/features/step_definitions/gli_executable_steps.rb +12 -0
- data/features/step_definitions/gli_init_steps.rb +11 -0
- data/features/step_definitions/todo_steps.rb +69 -0
- data/features/support/env.rb +49 -0
- data/features/todo.feature +182 -0
- data/gli.cheat +95 -0
- data/gli.gemspec +34 -0
- data/lib/gli.rb +11 -571
- data/lib/gli/app.rb +184 -0
- data/lib/gli/app_support.rb +226 -0
- data/lib/gli/command.rb +107 -95
- data/lib/gli/command_line_option.rb +34 -0
- data/lib/gli/command_line_token.rb +13 -9
- data/lib/gli/command_support.rb +200 -0
- data/lib/gli/commands/compound_command.rb +42 -0
- data/lib/gli/commands/help.rb +63 -0
- data/lib/gli/commands/help_modules/command_help_format.rb +134 -0
- data/lib/gli/commands/help_modules/global_help_format.rb +61 -0
- data/lib/gli/commands/help_modules/list_formatter.rb +22 -0
- data/lib/gli/commands/help_modules/options_formatter.rb +50 -0
- data/lib/gli/commands/help_modules/text_wrapper.rb +53 -0
- data/lib/gli/commands/initconfig.rb +67 -0
- data/lib/{support → gli/commands}/scaffold.rb +150 -34
- data/lib/gli/dsl.rb +194 -0
- data/lib/gli/exceptions.rb +13 -4
- data/lib/gli/flag.rb +30 -41
- data/lib/gli/gli_option_parser.rb +98 -0
- data/lib/gli/option_parser_factory.rb +44 -0
- data/lib/gli/options.rb +2 -1
- data/lib/gli/switch.rb +19 -51
- data/lib/gli/terminal.rb +30 -20
- data/lib/gli/version.rb +5 -0
- data/test/apps/README.md +2 -0
- data/test/apps/todo/Gemfile +2 -0
- data/test/apps/todo/README.rdoc +6 -0
- data/test/apps/todo/Rakefile +23 -0
- data/test/apps/todo/bin/todo +52 -0
- data/test/apps/todo/lib/todo/commands/create.rb +22 -0
- data/test/apps/todo/lib/todo/commands/list.rb +53 -0
- data/test/apps/todo/lib/todo/commands/ls.rb +47 -0
- data/test/apps/todo/lib/todo/version.rb +3 -0
- data/test/apps/todo/test/tc_nothing.rb +14 -0
- data/test/apps/todo/todo.gemspec +23 -0
- data/test/apps/todo/todo.rdoc +5 -0
- data/test/config.yaml +10 -0
- data/test/fake_std_out.rb +30 -0
- data/test/gli.reek +122 -0
- data/test/init_simplecov.rb +8 -0
- data/test/option_test_helper.rb +13 -0
- data/test/roodi.yaml +18 -0
- data/test/tc_command.rb +260 -0
- data/test/tc_compount_command.rb +22 -0
- data/test/tc_flag.rb +56 -0
- data/test/tc_gli.rb +611 -0
- data/test/tc_help.rb +223 -0
- data/test/tc_options.rb +31 -0
- data/test/tc_subcommands.rb +162 -0
- data/test/tc_switch.rb +57 -0
- data/test/tc_terminal.rb +97 -0
- data/test/test_helper.rb +13 -0
- metadata +318 -49
- data/lib/gli_version.rb +0 -3
- data/lib/support/help.rb +0 -179
- data/lib/support/initconfig.rb +0 -34
- data/lib/support/rdoc.rb +0 -119
data/lib/gli/options.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'ostruct'
|
2
2
|
|
3
3
|
module GLI
|
4
|
-
# Subclass of OpenStruct that provides hash-like methods for #[] and #[]=. Note that is is *not* a Hash.
|
4
|
+
# Subclass of +OpenStruct+ that provides hash-like methods for #[] and #[]=. Note that is is *not* a Hash.
|
5
|
+
# By using GLI::App#use_openstruct, your options will be coerced into one of these.
|
5
6
|
class Options < OpenStruct
|
6
7
|
|
7
8
|
# Return the value of an attribute
|
data/lib/gli/switch.rb
CHANGED
@@ -1,63 +1,31 @@
|
|
1
|
-
require 'gli/
|
1
|
+
require 'gli/command_line_option.rb'
|
2
2
|
|
3
3
|
module GLI
|
4
4
|
# Defines a command line switch
|
5
|
-
class Switch <
|
5
|
+
class Switch < CommandLineOption #:nodoc:
|
6
6
|
|
7
|
-
|
8
|
-
super(names,description,long_desc)
|
9
|
-
@default_value = false
|
10
|
-
end
|
7
|
+
attr_accessor :default_value
|
11
8
|
|
12
|
-
#
|
13
|
-
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
return result[0]
|
25
|
-
end
|
26
|
-
end
|
27
|
-
@default_value
|
28
|
-
end
|
29
|
-
|
30
|
-
# Used only to configure what's returned if we do not detect this switch on the command line
|
31
|
-
# This allows the configuration file to set a switch as always on
|
32
|
-
def default_value=(default)
|
33
|
-
@default_value = default
|
9
|
+
# Creates a new switch
|
10
|
+
#
|
11
|
+
# names - Array of symbols or strings representing the names of this switch
|
12
|
+
# options - hash of options:
|
13
|
+
# :desc - the short description
|
14
|
+
# :long_desc - the long description
|
15
|
+
# :negatable - true or false if this switch is negatable; defaults to true
|
16
|
+
# :default_value - ignored, switches default to false
|
17
|
+
def initialize(names,options = {})
|
18
|
+
super(names,options)
|
19
|
+
@default_value = false
|
20
|
+
@negatable = options[:negatable].nil? ? true : options[:negatable]
|
34
21
|
end
|
35
22
|
|
36
|
-
|
37
|
-
|
38
|
-
# index 0:: true or false if the arg was found
|
39
|
-
# index 1:: the remaining arg to keep in the command line or nil to remove it
|
40
|
-
def find_me(arg)
|
41
|
-
if @names[arg]
|
42
|
-
return [true,nil]
|
43
|
-
end
|
44
|
-
@names.keys.each() do |name|
|
45
|
-
if name =~ /^-(\w)$/
|
46
|
-
match_string = "^\\-(\\w*)#{$1}(\\w*)$"
|
47
|
-
match_data = arg.match(match_string)
|
48
|
-
if match_data
|
49
|
-
# Note that if [1] and [2] were both empty
|
50
|
-
# we'd have returned above
|
51
|
-
return [true, "-" + match_data[1] + match_data[2]]
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
[false]
|
23
|
+
def arguments_for_option_parser
|
24
|
+
all_forms_a
|
56
25
|
end
|
57
26
|
|
58
|
-
def
|
59
|
-
|
60
|
-
string.length == 1 ? "-#{string}" : "--#{string}"
|
27
|
+
def negatable?
|
28
|
+
@negatable
|
61
29
|
end
|
62
30
|
end
|
63
31
|
end
|
data/lib/gli/terminal.rb
CHANGED
@@ -3,7 +3,7 @@ module GLI
|
|
3
3
|
# as a canonical means to get information about the user's current terminal configuraiton.
|
4
4
|
# GLI uses this to determine the number of columns to use when printing to the screen.
|
5
5
|
#
|
6
|
-
# To access it, use Terminal
|
6
|
+
# To access it, use Terminal.instance. This is a singleton mostly to facilitate testing, but
|
7
7
|
# it seems reasonable enough, since there's only one terminal in effect
|
8
8
|
#
|
9
9
|
# Example:
|
@@ -35,31 +35,46 @@ module GLI
|
|
35
35
|
|
36
36
|
# Call this to cause methods to throw exceptions rather than return a sane default. You
|
37
37
|
# probably don't want to call this unless you are writing tests
|
38
|
-
def make_unsafe!
|
38
|
+
def make_unsafe! #:nodoc:
|
39
39
|
@unsafe = true
|
40
40
|
end
|
41
41
|
|
42
42
|
# Returns true if the given command exists on this system
|
43
43
|
#
|
44
44
|
# +command+:: The command, as a String, to check for, without any path information.
|
45
|
-
def command_exists?(command)
|
45
|
+
def self.command_exists?(command)
|
46
46
|
ENV['PATH'].split(File::PATH_SEPARATOR).any? {|dir| File.exists? File.join(dir, command) }
|
47
47
|
end
|
48
48
|
|
49
|
+
def command_exists?(command)
|
50
|
+
self.class.command_exists?(command)
|
51
|
+
end
|
52
|
+
|
53
|
+
SIZE_DETERMINERS = [
|
54
|
+
[
|
55
|
+
lambda { (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/) },
|
56
|
+
lambda { [ENV['COLUMNS'].to_i, ENV['LINES'].to_i] }
|
57
|
+
],
|
58
|
+
[
|
59
|
+
lambda { (jruby? || (!STDIN.tty? && ENV['TERM'])) && command_exists?('tput') },
|
60
|
+
lambda { [run_command('tput cols').to_i, run_command('tput lines').to_i] }
|
61
|
+
],
|
62
|
+
[
|
63
|
+
lambda { STDIN.tty? && command_exists?('stty') },
|
64
|
+
lambda { run_command('stty size').scan(/\d+/).map { |size_element| size_element.to_i }.reverse }
|
65
|
+
],
|
66
|
+
[
|
67
|
+
lambda { true },
|
68
|
+
lambda { Terminal.default_size },
|
69
|
+
],
|
70
|
+
]
|
71
|
+
|
49
72
|
# Get the size of the current terminal.
|
50
73
|
# Ripped from hirb[https://github.com/cldwalker/hirb/blob/master/lib/hirb/util.rb]
|
51
74
|
#
|
52
75
|
# Returns an Array of size two Ints representing the terminal width and height
|
53
76
|
def size
|
54
|
-
|
55
|
-
[ENV['COLUMNS'].to_i, ENV['LINES'].to_i]
|
56
|
-
elsif (jruby? || (!STDIN.tty? && ENV['TERM'])) && command_exists?('tput')
|
57
|
-
[run_command('tput cols').to_i, run_command('tput lines').to_i]
|
58
|
-
elsif STDIN.tty? && command_exists?('stty')
|
59
|
-
run_command('stty size').scan(/\d+/).map { |size_element| size_element.to_i }.reverse
|
60
|
-
else
|
61
|
-
Terminal.default_size
|
62
|
-
end
|
77
|
+
SIZE_DETERMINERS.select { |predicate,ignore| predicate.call }.first[1].call
|
63
78
|
rescue Exception => ex
|
64
79
|
raise ex if @unsafe
|
65
80
|
Terminal.default_size
|
@@ -68,17 +83,12 @@ module GLI
|
|
68
83
|
private
|
69
84
|
|
70
85
|
# Runs a command using backticks. Extracted to allow for testing
|
71
|
-
def run_command(command)
|
86
|
+
def self.run_command(command)
|
72
87
|
`#{command}`
|
73
88
|
end
|
74
89
|
|
75
90
|
# True if we are JRuby; exposed to allow for testing
|
76
|
-
def jruby
|
77
|
-
|
78
|
-
true
|
79
|
-
else
|
80
|
-
false
|
81
|
-
end
|
82
|
-
end
|
91
|
+
def self.jruby?; RUBY_PLATFORM =~ /java/; end
|
92
|
+
|
83
93
|
end
|
84
94
|
end
|
data/lib/gli/version.rb
ADDED
data/test/apps/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake/clean'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
Rake::RDocTask.new do |rd|
|
7
|
+
rd.main = "README.rdoc"
|
8
|
+
rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
|
9
|
+
rd.title = 'Your application title'
|
10
|
+
end
|
11
|
+
|
12
|
+
spec = eval(File.read('todo.gemspec'))
|
13
|
+
|
14
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'rake/testtask'
|
18
|
+
Rake::TestTask.new do |t|
|
19
|
+
t.libs << "test"
|
20
|
+
t.test_files = FileList['test/tc_*.rb']
|
21
|
+
end
|
22
|
+
|
23
|
+
task :default => :test
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# These would not be in a real GLI app; we do this so we can easily run this on the command line
|
4
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__),'..','..','..','lib'))
|
5
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__),'..','lib'))
|
6
|
+
|
7
|
+
require 'gli'
|
8
|
+
require 'todo/version'
|
9
|
+
|
10
|
+
|
11
|
+
include GLI::App
|
12
|
+
|
13
|
+
program_desc 'Manages tasks'
|
14
|
+
|
15
|
+
config_file "gli_test_todo.rc"
|
16
|
+
|
17
|
+
flag :flag
|
18
|
+
switch :switch
|
19
|
+
switch :otherswitch, :negatable => true
|
20
|
+
|
21
|
+
version Todo::VERSION
|
22
|
+
|
23
|
+
commands_from 'todo/commands'
|
24
|
+
|
25
|
+
command :first do |c| c.action { |g,o,a| puts "first: #{a.join(',')}" } end
|
26
|
+
command :second do |c| c.action { |g,o,a| puts "second: #{a.join(',')}" } end
|
27
|
+
|
28
|
+
command :chained => [ :first, :second ]
|
29
|
+
command [:chained2,:ch2] => [ :second, :first ]
|
30
|
+
|
31
|
+
pre do |global,command,options,args|
|
32
|
+
# Pre logic here
|
33
|
+
# Return true to proceed; false to abourt and not call the
|
34
|
+
# chosen command
|
35
|
+
# Use skips_pre before a command to skip this block
|
36
|
+
# on that command only
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
post do |global,command,options,args|
|
41
|
+
# Post logic here
|
42
|
+
# Use skips_post before a command to skip this
|
43
|
+
# block on that command only
|
44
|
+
end
|
45
|
+
|
46
|
+
on_error do |exception|
|
47
|
+
# Error logic here
|
48
|
+
# return false to skip default error handling
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
exit run(ARGV)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
desc "Create a new task or context"
|
2
|
+
command [:create,:new] do |c|
|
3
|
+
c.desc "Make a new task"
|
4
|
+
c.command :tasks do |tasks|
|
5
|
+
tasks.action do |global,options,args|
|
6
|
+
puts "#{args}"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
c.desc "Make a new context"
|
11
|
+
c.command :contexts do |contexts|
|
12
|
+
contexts.action do |global,options,args|
|
13
|
+
puts "#{args}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
c.default_desc "Makes a new task"
|
18
|
+
c.action do
|
19
|
+
puts "default action"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
desc "List things, such as tasks or contexts"
|
2
|
+
long_desc %(
|
3
|
+
List a whole lot of things that you might be keeping track of
|
4
|
+
in your overall todo list.
|
5
|
+
|
6
|
+
This is your go-to place or finding all of the things that you
|
7
|
+
might have
|
8
|
+
stored in
|
9
|
+
your todo databases.
|
10
|
+
)
|
11
|
+
command [:list] do |c|
|
12
|
+
c.default_command :tasks
|
13
|
+
|
14
|
+
c.desc "Show long form"
|
15
|
+
c.switch [:l,:long]
|
16
|
+
|
17
|
+
c.desc "List tasks"
|
18
|
+
c.long_desc %(
|
19
|
+
Lists all of your tasks that you have, in varying orders, and
|
20
|
+
all that stuff. Yes, this is long, but I need a long description.
|
21
|
+
)
|
22
|
+
c.command :tasks do |tasks|
|
23
|
+
tasks.desc "blah blah crud x whatever"
|
24
|
+
tasks.flag [:x]
|
25
|
+
|
26
|
+
tasks.flag :flag
|
27
|
+
|
28
|
+
tasks.action do |global,options,args|
|
29
|
+
puts "list tasks: #{args.join(',')}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
c.desc "List contexts"
|
34
|
+
c.long_desc %(
|
35
|
+
Lists all of your contexts, which are places you might be
|
36
|
+
where you can do stuff and all that.
|
37
|
+
)
|
38
|
+
c.command :contexts do |contexts|
|
39
|
+
|
40
|
+
contexts.desc "Foobar"
|
41
|
+
contexts.switch [:f,'foobar']
|
42
|
+
|
43
|
+
contexts.desc "Blah"
|
44
|
+
contexts.switch [:b]
|
45
|
+
|
46
|
+
contexts.flag :otherflag
|
47
|
+
|
48
|
+
contexts.action do |global,options,args|
|
49
|
+
puts "list contexts: #{args.join(',')}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# This is copied so I can have two slightly different versions of the same thing
|
2
|
+
desc "LS things, such as tasks or contexts"
|
3
|
+
long_desc %(
|
4
|
+
List a whole lot of things that you might be keeping track of
|
5
|
+
in your overall todo list.
|
6
|
+
|
7
|
+
This is your go-to place or finding all of the things that you
|
8
|
+
might have
|
9
|
+
stored in
|
10
|
+
your todo databases.
|
11
|
+
)
|
12
|
+
command [:ls] do |c|
|
13
|
+
c.desc "Show long form"
|
14
|
+
c.switch [:l,:long]
|
15
|
+
|
16
|
+
c.desc "List tasks"
|
17
|
+
c.long_desc %(
|
18
|
+
Lists all of your tasks that you have, in varying orders, and
|
19
|
+
all that stuff. Yes, this is long, but I need a long description.
|
20
|
+
)
|
21
|
+
c.command :tasks do |tasks|
|
22
|
+
tasks.desc "blah blah crud x whatever"
|
23
|
+
tasks.flag [:x]
|
24
|
+
tasks.action do |global,options,args|
|
25
|
+
puts "ls tasks: #{args.join(',')}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
c.desc "List contexts"
|
30
|
+
c.long_desc %(
|
31
|
+
Lists all of your contexts, which are places you might be
|
32
|
+
where you can do stuff and all that.
|
33
|
+
)
|
34
|
+
c.command :contexts do |contexts|
|
35
|
+
|
36
|
+
contexts.desc "Foobar"
|
37
|
+
contexts.switch [:f,'foobar']
|
38
|
+
|
39
|
+
contexts.desc "Blah"
|
40
|
+
contexts.switch [:b]
|
41
|
+
|
42
|
+
contexts.action do |global,options,args|
|
43
|
+
puts "ls contexts: #{args.join(',')}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Ensure we require the local version and not one we might have installed already
|
2
|
+
require File.join([File.dirname(__FILE__),'lib','todo','version.rb'])
|
3
|
+
spec = Gem::Specification.new do |s|
|
4
|
+
s.name = 'todo'
|
5
|
+
s.version = Todo::VERSION
|
6
|
+
s.author = 'Your Name Here'
|
7
|
+
s.email = 'your@email.address.com'
|
8
|
+
s.homepage = 'http://your.website.com'
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.summary = 'A description of your project'
|
11
|
+
# Add your other files here if you make them
|
12
|
+
s.files = %w(
|
13
|
+
bin/todo
|
14
|
+
)
|
15
|
+
s.require_paths << 'lib'
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = ['README.rdoc','todo.rdoc']
|
18
|
+
s.rdoc_options << '--title' << 'todo' << '--main' << 'README.rdoc' << '-ri'
|
19
|
+
s.bindir = 'bin'
|
20
|
+
s.executables << 'todo'
|
21
|
+
s.add_development_dependency('rake')
|
22
|
+
s.add_development_dependency('rdoc')
|
23
|
+
end
|