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.
Files changed (78) hide show
  1. data/.gitignore +11 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE.txt +201 -0
  6. data/ObjectModel.graffle +1191 -0
  7. data/README.rdoc +60 -10
  8. data/Rakefile +145 -0
  9. data/bin/gli +12 -30
  10. data/bin/report_on_rake_results +10 -0
  11. data/bin/test_all_rubies.sh +6 -0
  12. data/features/gli_executable.feature +84 -0
  13. data/features/gli_init.feature +219 -0
  14. data/features/step_definitions/gli_executable_steps.rb +12 -0
  15. data/features/step_definitions/gli_init_steps.rb +11 -0
  16. data/features/step_definitions/todo_steps.rb +69 -0
  17. data/features/support/env.rb +49 -0
  18. data/features/todo.feature +182 -0
  19. data/gli.cheat +95 -0
  20. data/gli.gemspec +34 -0
  21. data/lib/gli.rb +11 -571
  22. data/lib/gli/app.rb +184 -0
  23. data/lib/gli/app_support.rb +226 -0
  24. data/lib/gli/command.rb +107 -95
  25. data/lib/gli/command_line_option.rb +34 -0
  26. data/lib/gli/command_line_token.rb +13 -9
  27. data/lib/gli/command_support.rb +200 -0
  28. data/lib/gli/commands/compound_command.rb +42 -0
  29. data/lib/gli/commands/help.rb +63 -0
  30. data/lib/gli/commands/help_modules/command_help_format.rb +134 -0
  31. data/lib/gli/commands/help_modules/global_help_format.rb +61 -0
  32. data/lib/gli/commands/help_modules/list_formatter.rb +22 -0
  33. data/lib/gli/commands/help_modules/options_formatter.rb +50 -0
  34. data/lib/gli/commands/help_modules/text_wrapper.rb +53 -0
  35. data/lib/gli/commands/initconfig.rb +67 -0
  36. data/lib/{support → gli/commands}/scaffold.rb +150 -34
  37. data/lib/gli/dsl.rb +194 -0
  38. data/lib/gli/exceptions.rb +13 -4
  39. data/lib/gli/flag.rb +30 -41
  40. data/lib/gli/gli_option_parser.rb +98 -0
  41. data/lib/gli/option_parser_factory.rb +44 -0
  42. data/lib/gli/options.rb +2 -1
  43. data/lib/gli/switch.rb +19 -51
  44. data/lib/gli/terminal.rb +30 -20
  45. data/lib/gli/version.rb +5 -0
  46. data/test/apps/README.md +2 -0
  47. data/test/apps/todo/Gemfile +2 -0
  48. data/test/apps/todo/README.rdoc +6 -0
  49. data/test/apps/todo/Rakefile +23 -0
  50. data/test/apps/todo/bin/todo +52 -0
  51. data/test/apps/todo/lib/todo/commands/create.rb +22 -0
  52. data/test/apps/todo/lib/todo/commands/list.rb +53 -0
  53. data/test/apps/todo/lib/todo/commands/ls.rb +47 -0
  54. data/test/apps/todo/lib/todo/version.rb +3 -0
  55. data/test/apps/todo/test/tc_nothing.rb +14 -0
  56. data/test/apps/todo/todo.gemspec +23 -0
  57. data/test/apps/todo/todo.rdoc +5 -0
  58. data/test/config.yaml +10 -0
  59. data/test/fake_std_out.rb +30 -0
  60. data/test/gli.reek +122 -0
  61. data/test/init_simplecov.rb +8 -0
  62. data/test/option_test_helper.rb +13 -0
  63. data/test/roodi.yaml +18 -0
  64. data/test/tc_command.rb +260 -0
  65. data/test/tc_compount_command.rb +22 -0
  66. data/test/tc_flag.rb +56 -0
  67. data/test/tc_gli.rb +611 -0
  68. data/test/tc_help.rb +223 -0
  69. data/test/tc_options.rb +31 -0
  70. data/test/tc_subcommands.rb +162 -0
  71. data/test/tc_switch.rb +57 -0
  72. data/test/tc_terminal.rb +97 -0
  73. data/test/test_helper.rb +13 -0
  74. metadata +318 -49
  75. data/lib/gli_version.rb +0 -3
  76. data/lib/support/help.rb +0 -179
  77. data/lib/support/initconfig.rb +0 -34
  78. 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/command_line_token.rb'
1
+ require 'gli/command_line_option.rb'
2
2
 
3
3
  module GLI
4
4
  # Defines a command line switch
5
- class Switch < CommandLineToken #:nodoc:
5
+ class Switch < CommandLineOption #:nodoc:
6
6
 
7
- def initialize(names,description,long_desc=nil)
8
- super(names,description,long_desc)
9
- @default_value = false
10
- end
7
+ attr_accessor :default_value
11
8
 
12
- # Given the argument list, scans it looking for this switch
13
- # returning true if it's in the argumennt list (and removing it from the argument list)
14
- def get_value!(args)
15
- idx = -1
16
- args.each_index do |index|
17
- result = find_me(args[index])
18
- if result[0]
19
- if result[1]
20
- args[index] = result[1]
21
- else
22
- args.delete_at index
23
- end
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
- # Finds the switch in the given arg, returning the arg to keep.
37
- # Returns an array of size 2:
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 self.name_as_string(name)
59
- string = name.to_s
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#instance. This is a singleton mostly to facilitate testing, but
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
- if (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/)
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
- if RUBY_PLATFORM =~ /java/
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
@@ -0,0 +1,5 @@
1
+ module GLI
2
+ unless const_defined? :VERSION
3
+ VERSION = '2.0.0.rc3' #:nodoc:
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ Special-built applications for use in tests that will hopefully reveal
2
+ various features and edge cases
@@ -0,0 +1,2 @@
1
+ source :rubygems
2
+ gemspec
@@ -0,0 +1,6 @@
1
+ = todo
2
+
3
+ Describe your project here
4
+
5
+ :include:todo.rdoc
6
+
@@ -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,3 @@
1
+ module Todo
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,14 @@
1
+ require 'test/unit'
2
+
3
+ class TC_testNothing < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def teardown
9
+ end
10
+
11
+ def test_the_truth
12
+ assert true
13
+ end
14
+ end
@@ -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