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.
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