gli 1.6.0 → 2.0.0.rc3
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.
- 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
|