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
@@ -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
+