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
@@ -0,0 +1,12 @@
1
+ Given /^I have GLI installed$/ do
2
+ add_to_lib_path(GLI_LIB_PATH)
3
+ end
4
+
5
+ Given /^my terminal size is "([^"]*)"$/ do |terminal_size|
6
+ if terminal_size =~/^(\d+)x(\d+)$/
7
+ ENV['COLUMNS'] = $1
8
+ ENV['LINES'] = $2
9
+ else
10
+ raise "Terminal size should be COLxLines, e.g. 80x24"
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ Given /^GLI's libs are in my path$/ do
2
+ ENV['RUBYLIB'] = GLI_LIB_PATH
3
+ end
4
+
5
+ Given /^I make sure todo's lib dir is in my lib path$/ do
6
+ add_to_lib_path("./lib")
7
+ end
8
+
9
+ Given /^todo's libs are no longer in my load path$/ do
10
+ remove_from_lib_path("./lib")
11
+ end
@@ -0,0 +1,69 @@
1
+ Given /^todo's bin directory is in my path/ do
2
+ add_to_path(File.expand_path(File.join(File.dirname(__FILE__),'..','..','test','apps','todo','bin')))
3
+ end
4
+
5
+
6
+ Given /^a clean home directory$/ do
7
+ FileUtils.rm_rf File.join(ENV['HOME'],'gli_test_todo.rc')
8
+ end
9
+
10
+ Then /^the config file should contain a section for each command and subcommand$/ do
11
+ config = File.open(File.join(ENV['HOME'],'gli_test_todo.rc')) do |file|
12
+ YAML::load(file)
13
+ end
14
+ config.keys.should include(:flag)
15
+ config[:flag].should == 'foo'
16
+ config[:flag].tap do |flag|
17
+ if flag.respond_to?(:encoding)
18
+ flag.encoding.name.should == 'UTF-8'
19
+ end
20
+ end
21
+ config.keys.should include(:switch)
22
+ config[:switch].should == true
23
+ config.keys.should include(:otherswitch)
24
+ config[:otherswitch].should == false
25
+ config.keys.should include('commands')
26
+ %w(chained chained2 create first list ls second).map(&:to_sym).each do |command_name|
27
+ config['commands'].keys.should include(command_name)
28
+ end
29
+ config['commands'][:create].keys.should include('commands')
30
+ config['commands'][:create]['commands'].should include(:tasks)
31
+ config['commands'][:create]['commands'].should include(:contexts)
32
+
33
+ config['commands'][:list].keys.should include('commands')
34
+ config['commands'][:list]['commands'].should include(:tasks)
35
+ config['commands'][:list]['commands'].should include(:contexts)
36
+ end
37
+
38
+ Given /^a config file that specifies defaults for some commands with subcommands$/ do
39
+ @config = {
40
+ 'commands' => {
41
+ :list => {
42
+ 'commands' => {
43
+ :tasks => {
44
+ :flag => 'foobar',
45
+ },
46
+ :contexts => {
47
+ :otherflag => 'crud',
48
+ },
49
+ }
50
+ }
51
+ }
52
+ }
53
+ File.open(File.join(ENV['HOME'],'gli_test_todo.rc'),'w') do |file|
54
+ file.puts @config.to_yaml
55
+ end
56
+ end
57
+
58
+ Then /^I should see the defaults for '(.*)' from the config file in the help$/ do |command_path|
59
+ if command_path == 'list tasks'
60
+ step %{the output should match /--flag.*default: foobar/}
61
+ unescape(all_output).should_not =~ /#{unescape("--otherflag.*default: crud")}/m
62
+ elsif command_path == 'list contexts'
63
+ step %{the output should match /--otherflag.*default: crud/}
64
+ unescape(all_output).should_not =~ /#{unescape("--flag.*default: foobar")}/m
65
+ else
66
+ raise "Don't know how to test for command path #{command_path}"
67
+ end
68
+ end
69
+
@@ -0,0 +1,49 @@
1
+ begin
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ rescue LoadError
5
+ # Don't care
6
+ end
7
+ require 'aruba/cucumber'
8
+ require 'fileutils'
9
+
10
+ # Adds GLI's bin dir to our path
11
+ ENV['PATH'] = "#{File.expand_path(File.dirname(__FILE__) + '/../../bin')}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
12
+ GLI_LIB_PATH = File.expand_path(File.join(File.dirname(__FILE__),'..','..','lib'))
13
+
14
+ GLI_GEMSET = 'gli-testing'
15
+ TMP_PATH = 'tmp/aruba'
16
+
17
+ Before do
18
+ # Not sure how else to get this dynamically
19
+ @dirs = [TMP_PATH]
20
+ @aruba_timeout_seconds = 5
21
+ @original_path = ENV['PATH'].split(File::PATH_SEPARATOR)
22
+ @original_home = ENV['HOME']
23
+ new_home = "/tmp/fakehome"
24
+ FileUtils.rm_rf new_home
25
+ FileUtils.mkdir new_home
26
+ ENV['HOME'] = new_home
27
+ end
28
+
29
+ After do |scenario|
30
+ ENV['RUBYLIB'] = ''
31
+ todo_app_dir = File.join(TMP_PATH,'todo')
32
+ if File.exists? todo_app_dir
33
+ FileUtils.rm_rf(todo_app_dir)
34
+ end
35
+ ENV['PATH'] = @original_path.join(File::PATH_SEPARATOR)
36
+ ENV['HOME'] = @original_home
37
+ end
38
+
39
+ def add_to_path(dir)
40
+ ENV['PATH'] = "#{dir}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
41
+ end
42
+
43
+ def add_to_lib_path(path)
44
+ ENV["RUBYLIB"] = (String(ENV["RUBYLIB"]).split(File::PATH_SEPARATOR) + [path]).join(File::PATH_SEPARATOR)
45
+ end
46
+
47
+ def remove_from_lib_path(path)
48
+ ENV["RUBYLIB"] = (String(ENV["RUBYLIB"]).split(File::PATH_SEPARATOR) - [path]).join(File::PATH_SEPARATOR)
49
+ end
@@ -0,0 +1,182 @@
1
+ Feature: The todo app has a nice user interface
2
+ As a user of the todo application
3
+ It should have a nice UI, since it's GLI-powered
4
+
5
+ Background:
6
+ Given I have GLI installed
7
+ And GLI's libs are in my path
8
+ And my terminal size is "80x24"
9
+ And todo's bin directory is in my path
10
+
11
+ Scenario: Getting Help for todo in general
12
+ When I successfully run `todo help`
13
+ Then the output should contain:
14
+ """
15
+ NAME
16
+ todo - Manages tasks
17
+
18
+ SYNOPSIS
19
+ todo [global options] command [command options] [arguments...]
20
+
21
+ VERSION
22
+ 0.0.1
23
+
24
+ GLOBAL OPTIONS
25
+ --flag=arg - (default: none)
26
+ --help - Show this message
27
+ --[no-]otherswitch -
28
+ --[no-]switch -
29
+
30
+ COMMANDS
31
+ chained -
32
+ chained2, ch2 -
33
+ create, new - Create a new task or context
34
+ first -
35
+ help - Shows a list of commands or help for one command
36
+ initconfig - Initialize the config file using current global options
37
+ list - List things, such as tasks or contexts
38
+ ls - LS things, such as tasks or contexts
39
+ second -
40
+ """
41
+
42
+ Scenario: Getting Help for a top level command of todo
43
+ When I successfully run `todo help list`
44
+ Then the output should contain:
45
+ """
46
+ NAME
47
+ list - List things, such as tasks or contexts
48
+
49
+ SYNOPSIS
50
+ todo [global options] list [command options] [--flag arg] [-x arg] [tasks]
51
+ todo [global options] list [command options] [--otherflag arg] [-b] [-f|--foobar] contexts
52
+
53
+ DESCRIPTION
54
+ List a whole lot of things that you might be keeping track of in your
55
+ overall todo list.
56
+
57
+ This is your go-to place or finding all of the things that you might have
58
+ stored in your todo databases.
59
+
60
+ COMMAND OPTIONS
61
+ -l, --[no-]long - Show long form
62
+
63
+ COMMANDS
64
+ contexts - List contexts
65
+ tasks - List tasks (default)
66
+ """
67
+
68
+ Scenario: Getting Help for a sub command of todo list
69
+ When I successfully run `todo help list tasks`
70
+ Then the output should contain:
71
+ """
72
+ NAME
73
+ tasks - List tasks
74
+
75
+ SYNOPSIS
76
+ todo [global options] list tasks [command options]
77
+
78
+ DESCRIPTION
79
+ Lists all of your tasks that you have, in varying orders, and all that
80
+ stuff. Yes, this is long, but I need a long description.
81
+
82
+ COMMAND OPTIONS
83
+ --flag=arg - (default: none)
84
+ -x arg - blah blah crud x whatever (default: none)
85
+ """
86
+
87
+ Scenario: Getting Help for a sub command with no command options
88
+ When I successfully run `todo help new`
89
+ Then the output should contain:
90
+ """
91
+ NAME
92
+ create - Create a new task or context
93
+
94
+ SYNOPSIS
95
+ todo [global options] create [command options]
96
+ todo [global options] create [command options] contexts
97
+ todo [global options] create [command options] tasks
98
+
99
+ COMMANDS
100
+ <default> - Makes a new task
101
+ contexts - Make a new context
102
+ tasks - Make a new task
103
+ """
104
+ And the output should not contain "COMMAND OPTIONS"
105
+
106
+ Scenario: Running list w/out subcommand performs list tasks by default
107
+ When I successfully run `todo list boo yay`
108
+ Then the output should contain "list tasks: boo,yay"
109
+
110
+ Scenario: Running list w/out subcommand or any arguments performs list tasks by default
111
+ When I successfully run `todo list`
112
+ Then the output should contain "list tasks:"
113
+
114
+ Scenario: Running chained commands works
115
+ When I successfully run `todo chained foo bar`
116
+ Then the output should contain:
117
+ """
118
+ first: foo,bar
119
+ second: foo,bar
120
+ """
121
+
122
+ Scenario: Running chained commands works and is ordered
123
+ When I successfully run `todo chained2 foo bar`
124
+ Then the output should contain:
125
+ """
126
+ second: foo,bar
127
+ first: foo,bar
128
+ """
129
+
130
+ Scenario: Running chained commands works and is ordered
131
+ When I successfully run `todo ch2 foo bar`
132
+ Then the output should contain:
133
+ """
134
+ second: foo,bar
135
+ first: foo,bar
136
+ """
137
+
138
+ Scenario: Running ls w/out subcommand shows help and an error
139
+ When I run `todo ls`
140
+ Then the exit status should not be 0
141
+ And the stderr should contain "error: Command 'ls' requires a subcommand"
142
+ And the stdout should contain:
143
+ """
144
+ NAME
145
+ ls - LS things, such as tasks or contexts
146
+
147
+ SYNOPSIS
148
+ todo [global options] ls [command options] [-b] [-f|--foobar] contexts
149
+ todo [global options] ls [command options] [-x arg] tasks
150
+
151
+ DESCRIPTION
152
+ List a whole lot of things that you might be keeping track of in your
153
+ overall todo list.
154
+
155
+ This is your go-to place or finding all of the things that you might have
156
+ stored in your todo databases.
157
+
158
+ COMMAND OPTIONS
159
+ -l, --[no-]long - Show long form
160
+
161
+ COMMANDS
162
+ contexts - List contexts
163
+ tasks - List tasks
164
+ """
165
+
166
+
167
+ Scenario: Init Config makes a reasonable config file
168
+ Given a clean home directory
169
+ When I successfully run `todo --flag foo --switch --no-otherswitch initconfig`
170
+ Then the config file should contain a section for each command and subcommand
171
+
172
+ Scenario: Configuration percolates to the app
173
+ Given a clean home directory
174
+ And a config file that specifies defaults for some commands with subcommands
175
+ When I successfully run `todo help list tasks`
176
+ Then I should see the defaults for 'list tasks' from the config file in the help
177
+
178
+ Scenario: Do it again because aruba buffers all output
179
+ Given a clean home directory
180
+ And a config file that specifies defaults for some commands with subcommands
181
+ When I successfully run `todo help list contexts`
182
+ Then I should see the defaults for 'list contexts' from the config file in the help
data/gli.cheat ADDED
@@ -0,0 +1,95 @@
1
+ gli - create command-suite apps, a la git, using this awesome Ruby DSL
2
+ ======================================================================
3
+
4
+ Setup and Usage
5
+ ---------------
6
+
7
+ Installation:
8
+ $ gem install gli
9
+
10
+ Show list of commands
11
+ $ gli help [command]
12
+
13
+ Show help for one command
14
+ $ gli help init
15
+
16
+ Create a new GLI-based project with the commands foo and bar
17
+ $ gli init project_name foo bar
18
+
19
+ Create a new GLI-based project with an ext directory
20
+ $ gli init -e project_name foo bar
21
+
22
+ Create a new GLI-based project without a test directory (bad!)
23
+ $ gli init --notest project_name foo bar
24
+
25
+ Create a new GLI-based project somewhere else than .
26
+ $ gli -r /tmp init project_name foo bar
27
+
28
+ Just see what GLI would create
29
+ $ gli -n init -e project_name foo bar
30
+
31
+
32
+ Using GLI's DSL
33
+ ---------------
34
+
35
+ Create a switch (option that takes no args)
36
+
37
+ desc 'Dry-run; don't change the disk
38
+ switch [:n,'dry-run']
39
+ # Both -n and --dry-run will work
40
+ * --no-dry-run will set the switch to false
41
+ # Access in code via global_options[:n]
42
+ # or global_options[:'dry-run']
43
+
44
+ Create it on one line
45
+ switch :n,'dry-run', :desc => 'Dry-run; don't change the disk
46
+
47
+ Don't create a negatable version
48
+ switch :n,'dry-run', :negatable => false, :desc => 'Dry-run; don't change the disk
49
+ # --no-dry-run is not accepted
50
+
51
+ Create a flag (option that takes an argument)
52
+
53
+ desc 'Location of the config file'
54
+ arg_name 'path_to_file'
55
+ default_value '~/.glirc'
56
+ flag [:c,:conf], :must_match => /^\..*rc$/
57
+ # Both -c and --conf work, if this flag is omitted
58
+ # then the default of ~/.glirc is avaialble to the code
59
+ # The argument must match the given regex
60
+ # Access in code via global_options[:c] (or :conf)
61
+
62
+ Create a flag in a more compact style
63
+
64
+ flag :c,:conf, :desc => 'Location of the config file',
65
+ :arg_name => 'path_to_file', :default_value => '~/.glirc'
66
+
67
+ Create a command
68
+
69
+ desc 'Get the list of open tickets'
70
+ command [:tickets] do |c|
71
+ c.desc 'Only assigned to me'
72
+ c.switch [:m,:me]
73
+
74
+ c.desc 'Show only tickets for one project'
75
+ c.flag [:p,:project,'only-project']
76
+
77
+ c.action do |global_options,options,args|
78
+ # global_options has the global options as a hash
79
+ # options are the command specific ones (e.g. options[:p])
80
+ # args are the command line arguments that weren't parsed
81
+ # raise an exception or exit_now! if things go wrong
82
+ end
83
+ end
84
+
85
+ Set up stuff ahead of time
86
+
87
+ pre do |global_options,command,options,args|
88
+ return true if things_are_ok
89
+ return false if we_should_abort_the_command
90
+ end
91
+
92
+ Use GLI
93
+
94
+ exit run(ARGV)
95
+ # run returns a suitable exit status
data/gli.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # Make sure we get the gli that's local
2
+ require File.join([File.dirname(__FILE__),'lib','gli','version.rb'])
3
+
4
+ spec = Gem::Specification.new do |s|
5
+ s.name = 'gli'
6
+ s.version = GLI::VERSION
7
+ s.author = 'David Copeland'
8
+ s.email = 'davidcopeland@naildrivin5.com'
9
+ s.homepage = 'http://davetron5000.github.com/gli'
10
+ s.platform = Gem::Platform::RUBY
11
+ s.summary = 'A Git Like Interface for building command line apps'
12
+ s.description = 'An application and API for describing command line interfaces that can be used to quickly create a shell for executing command-line tasks. The command line user interface is similar to Git''s, in that it takes global options, a command, command-specific options, and arguments'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = 'gli'
17
+ s.require_paths = ["lib"]
18
+
19
+ s.has_rdoc = true
20
+ s.extra_rdoc_files = ['README.rdoc', 'gli.rdoc']
21
+ s.rdoc_options << '--title' << 'Git Like Interface' << '--main' << 'README.rdoc'
22
+ s.bindir = 'bin'
23
+ s.rubyforge_project = 'gli'
24
+ s.add_development_dependency('rake', '~> 0.9.2.2')
25
+ s.add_development_dependency('rdoc', '~> 3.11')
26
+ s.add_development_dependency('roodi', '~> 2.1.0')
27
+ s.add_development_dependency('reek')
28
+ s.add_development_dependency('grancher', '~> 0.1.5')
29
+ s.add_development_dependency('rainbow', '~> 1.1.1')
30
+ s.add_development_dependency('clean_test')
31
+ s.add_development_dependency('aruba', '~> 0.4.7')
32
+ s.add_development_dependency('sdoc')
33
+ end
34
+