gli_aziz_light 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +17 -0
  6. data/CONTRIBUTING.md +23 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE.txt +201 -0
  9. data/ObjectModel.graffle +1191 -0
  10. data/README.rdoc +109 -0
  11. data/Rakefile +126 -0
  12. data/bin/gli +59 -0
  13. data/bin/report_on_rake_results +10 -0
  14. data/bin/test_all_rubies.sh +6 -0
  15. data/features/gli_executable.feature +90 -0
  16. data/features/gli_init.feature +232 -0
  17. data/features/step_definitions/gli_executable_steps.rb +18 -0
  18. data/features/step_definitions/gli_init_steps.rb +11 -0
  19. data/features/step_definitions/todo_steps.rb +88 -0
  20. data/features/support/env.rb +53 -0
  21. data/features/todo.feature +413 -0
  22. data/features/todo_legacy.feature +128 -0
  23. data/gli.cheat +95 -0
  24. data/gli.gemspec +34 -0
  25. data/gli.rdoc +73 -0
  26. data/lib/gli.rb +35 -0
  27. data/lib/gli/app.rb +286 -0
  28. data/lib/gli/app_support.rb +341 -0
  29. data/lib/gli/command.rb +171 -0
  30. data/lib/gli/command_finder.rb +41 -0
  31. data/lib/gli/command_line_option.rb +34 -0
  32. data/lib/gli/command_line_token.rb +63 -0
  33. data/lib/gli/command_support.rb +181 -0
  34. data/lib/gli/commands/compound_command.rb +42 -0
  35. data/lib/gli/commands/doc.rb +231 -0
  36. data/lib/gli/commands/help.rb +95 -0
  37. data/lib/gli/commands/help_modules/arg_name_formatter.rb +20 -0
  38. data/lib/gli/commands/help_modules/command_finder.rb +60 -0
  39. data/lib/gli/commands/help_modules/command_help_format.rb +156 -0
  40. data/lib/gli/commands/help_modules/global_help_format.rb +70 -0
  41. data/lib/gli/commands/help_modules/help_completion_format.rb +31 -0
  42. data/lib/gli/commands/help_modules/list_formatter.rb +23 -0
  43. data/lib/gli/commands/help_modules/one_line_wrapper.rb +18 -0
  44. data/lib/gli/commands/help_modules/options_formatter.rb +49 -0
  45. data/lib/gli/commands/help_modules/text_wrapper.rb +53 -0
  46. data/lib/gli/commands/help_modules/tty_only_wrapper.rb +23 -0
  47. data/lib/gli/commands/help_modules/verbatim_wrapper.rb +16 -0
  48. data/lib/gli/commands/initconfig.rb +74 -0
  49. data/lib/gli/commands/rdoc_document_listener.rb +116 -0
  50. data/lib/gli/commands/scaffold.rb +401 -0
  51. data/lib/gli/dsl.rb +226 -0
  52. data/lib/gli/exceptions.rb +71 -0
  53. data/lib/gli/flag.rb +68 -0
  54. data/lib/gli/gli_option_block_parser.rb +84 -0
  55. data/lib/gli/gli_option_parser.rb +156 -0
  56. data/lib/gli/option_parser_factory.rb +81 -0
  57. data/lib/gli/option_parsing_result.rb +21 -0
  58. data/lib/gli/options.rb +23 -0
  59. data/lib/gli/switch.rb +35 -0
  60. data/lib/gli/terminal.rb +101 -0
  61. data/lib/gli/version.rb +5 -0
  62. data/test/apps/README.md +2 -0
  63. data/test/apps/todo/Gemfile +2 -0
  64. data/test/apps/todo/README.rdoc +6 -0
  65. data/test/apps/todo/Rakefile +23 -0
  66. data/test/apps/todo/bin/todo +63 -0
  67. data/test/apps/todo/lib/todo/commands/create.rb +24 -0
  68. data/test/apps/todo/lib/todo/commands/list.rb +63 -0
  69. data/test/apps/todo/lib/todo/commands/ls.rb +47 -0
  70. data/test/apps/todo/lib/todo/commands/make.rb +52 -0
  71. data/test/apps/todo/lib/todo/version.rb +3 -0
  72. data/test/apps/todo/test/tc_nothing.rb +14 -0
  73. data/test/apps/todo/todo.gemspec +23 -0
  74. data/test/apps/todo/todo.rdoc +5 -0
  75. data/test/apps/todo_legacy/Gemfile +2 -0
  76. data/test/apps/todo_legacy/README.rdoc +6 -0
  77. data/test/apps/todo_legacy/Rakefile +23 -0
  78. data/test/apps/todo_legacy/bin/todo +61 -0
  79. data/test/apps/todo_legacy/lib/todo/commands/create.rb +24 -0
  80. data/test/apps/todo_legacy/lib/todo/commands/list.rb +63 -0
  81. data/test/apps/todo_legacy/lib/todo/commands/ls.rb +47 -0
  82. data/test/apps/todo_legacy/lib/todo/version.rb +3 -0
  83. data/test/apps/todo_legacy/test/tc_nothing.rb +14 -0
  84. data/test/apps/todo_legacy/todo.gemspec +23 -0
  85. data/test/apps/todo_legacy/todo.rdoc +5 -0
  86. data/test/apps/todo_plugins/commands/third.rb +1 -0
  87. data/test/config.yaml +10 -0
  88. data/test/fake_std_out.rb +30 -0
  89. data/test/init_simplecov.rb +8 -0
  90. data/test/option_test_helper.rb +13 -0
  91. data/test/tc_command.rb +508 -0
  92. data/test/tc_compound_command.rb +22 -0
  93. data/test/tc_doc.rb +325 -0
  94. data/test/tc_flag.rb +62 -0
  95. data/test/tc_gli.rb +773 -0
  96. data/test/tc_help.rb +387 -0
  97. data/test/tc_options.rb +43 -0
  98. data/test/tc_subcommand_parsing.rb +104 -0
  99. data/test/tc_subcommands.rb +260 -0
  100. data/test/tc_switch.rb +55 -0
  101. data/test/tc_terminal.rb +100 -0
  102. data/test/tc_verbatim_wrapper.rb +36 -0
  103. data/test/test_helper.rb +20 -0
  104. metadata +330 -0
@@ -0,0 +1,95 @@
1
+ require 'erb'
2
+ require 'gli/command'
3
+ require 'gli/terminal'
4
+ require 'gli/commands/help_modules/list_formatter'
5
+ require 'gli/commands/help_modules/text_wrapper'
6
+ require 'gli/commands/help_modules/one_line_wrapper'
7
+ require 'gli/commands/help_modules/verbatim_wrapper'
8
+ require 'gli/commands/help_modules/tty_only_wrapper'
9
+ require 'gli/commands/help_modules/options_formatter'
10
+ require 'gli/commands/help_modules/global_help_format'
11
+ require 'gli/commands/help_modules/command_help_format'
12
+ require 'gli/commands/help_modules/help_completion_format'
13
+ require 'gli/commands/help_modules/command_finder'
14
+ require 'gli/commands/help_modules/arg_name_formatter'
15
+
16
+ module GLI
17
+ module Commands
18
+ SORTERS = {
19
+ :manually => lambda { |list| list },
20
+ :alpha => lambda { |list| list.sort },
21
+ }
22
+
23
+ WRAPPERS = {
24
+ :to_terminal => HelpModules::TextWrapper,
25
+ :never => HelpModules::OneLineWrapper,
26
+ :one_line => HelpModules::OneLineWrapper,
27
+ :tty_only => HelpModules::TTYOnlyWrapper,
28
+ :none => HelpModules::VerbatimWrapper,
29
+ :verbatim => HelpModules::VerbatimWrapper,
30
+ }
31
+ # The help command used for the two-level interactive help system
32
+ class Help < Command
33
+ @@skips_pre = true
34
+ @@skips_post = true
35
+ @@skips_around = true
36
+
37
+ # Configure help to explicitly skip or not skip the pre block when the help command runs.
38
+ # This is here because the creation of the help command is outside of the client programmer's control
39
+ def self.skips_pre=(skips_pre) ; @@skips_pre = skips_pre ; end
40
+
41
+ # Configure help to explicitly skip or not skip the post block when the help command runs.
42
+ # This is here because the creation of the help command is outside of the client programmer's control
43
+ def self.skips_post=(skips_post) ; @@skips_post = skips_post ; end
44
+
45
+ # Configure help to explicitly skip or not skip the around block when the help command runs.
46
+ # This is here because the creation of the help command is outside of the client programmer's control
47
+ def self.skips_around=(skips_around) ; @@skips_around = skips_around ; end
48
+
49
+ def initialize(app,output=$stdout,error=$stderr)
50
+ super(:names => :help,
51
+ :description => 'Shows a list of commands or help for one command',
52
+ :arguments_name => 'command',
53
+ :long_desc => 'Gets help for the application or its commands. Can also list the commands in a way helpful to creating a bash-style completion function')
54
+ @app = app
55
+ @parent = app
56
+ @sorter = SORTERS[@app.help_sort_type]
57
+ @text_wrapping_class = WRAPPERS[@app.help_text_wrap_type]
58
+
59
+ desc 'List commands one per line, to assist with shell completion'
60
+ switch :c
61
+
62
+ action do |global_options,options,arguments|
63
+ if global_options[:version] && !global_options[:help]
64
+ puts "#{@app.exe_name} version #{@app.version_string}"
65
+ else
66
+ show_help(global_options,options,arguments,output,error)
67
+ end
68
+ end
69
+ end
70
+
71
+ def skips_pre ; @@skips_pre ; end
72
+ def skips_post ; @@skips_post ; end
73
+ def skips_around ; @@skips_around ; end
74
+
75
+ private
76
+
77
+ def show_help(global_options,options,arguments,out,error)
78
+ command_finder = HelpModules::CommandFinder.new(@app,arguments,error)
79
+ if options[:c]
80
+ help_output = HelpModules::HelpCompletionFormat.new(@app,command_finder,arguments).format
81
+ out.puts help_output unless help_output.nil?
82
+ elsif arguments.empty? || options[:c]
83
+ out.puts HelpModules::GlobalHelpFormat.new(@app,@sorter,@text_wrapping_class).format
84
+ else
85
+ name = arguments.shift
86
+ command = command_finder.find_command(name)
87
+ unless command.nil?
88
+ out.puts HelpModules::CommandHelpFormat.new(command,@app,@app.exe_name.to_s,@sorter,@text_wrapping_class).format
89
+ end
90
+ end
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,20 @@
1
+ module GLI
2
+ module Commands
3
+ module HelpModules
4
+ # Handles wrapping text
5
+ class ArgNameFormatter
6
+ def format(arguments_description,arguments_options)
7
+ return '' if String(arguments_description).strip == ''
8
+ desc = arguments_description
9
+ if arguments_options.include? :optional
10
+ desc = "[#{desc}]"
11
+ end
12
+ if arguments_options.include? :multiple
13
+ desc = "#{desc}[, #{desc}]*"
14
+ end
15
+ " " + desc
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,60 @@
1
+ module GLI
2
+ module Commands
3
+ module HelpModules
4
+ # Finds commands from the application/command data structures
5
+ class CommandFinder
6
+
7
+ attr_reader :last_unknown_command
8
+ attr_reader :last_found_command
9
+ attr_writer :squelch_stderr
10
+
11
+ def initialize(app,arguments,error)
12
+ @app = app
13
+ @arguments = arguments
14
+ @error = error
15
+ @squelch_stderr = false
16
+ @last_unknown_command = nil
17
+ end
18
+
19
+ def find_command(name)
20
+ command = find_command_from_base(name,@app)
21
+ return if unknown_command?(command,name,@error)
22
+ @last_found_command = command
23
+ while !@arguments.empty?
24
+ name = @arguments.shift
25
+ command = find_command_from_base(name,command)
26
+ return if unknown_command?(command,name,@error)
27
+ @last_found_command = command
28
+ end
29
+ command
30
+ end
31
+
32
+ private
33
+
34
+ # Given the name of a command to find, and a base, either the app or another command, returns
35
+ # the command object or nil.
36
+ def find_command_from_base(command_name,base)
37
+ base.commands.values.select { |command|
38
+ if [command.name,Array(command.aliases)].flatten.map(&:to_s).any? { |_| _ == command_name }
39
+ command
40
+ end
41
+ }.first
42
+ end
43
+
44
+ # Checks if the return from find_command was unknown and, if so, prints an error
45
+ # for the user on the error device, returning true or false if the command was unknown.
46
+ def unknown_command?(command,name,error)
47
+ if command.nil?
48
+ @last_unknown_command = name
49
+ unless @squelch_stderr
50
+ error.puts "error: Unknown command '#{name}'. Use '#{@app.exe_name} help' for a list of commands."
51
+ end
52
+ true
53
+ else
54
+ false
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,156 @@
1
+ require 'erb'
2
+
3
+ module GLI
4
+ module Commands
5
+ module HelpModules
6
+ class CommandHelpFormat
7
+ def initialize(command,app,basic_invocation,sorter,wrapper_class=TextWrapper)
8
+ @basic_invocation = basic_invocation
9
+ @app = app
10
+ @command = command
11
+ @sorter = sorter
12
+ @wrapper_class = wrapper_class
13
+ end
14
+
15
+ def format
16
+ command_wrapper = @wrapper_class.new(Terminal.instance.size[0],4 + @command.name.to_s.size + 3)
17
+ wrapper = @wrapper_class.new(Terminal.instance.size[0],4)
18
+
19
+ options_description = OptionsFormatter.new(flags_and_switches(@command,@app),@sorter,@wrapper_class).format
20
+ commands_description = format_subcommands(@command)
21
+
22
+ synopses = []
23
+ one_line_usage = basic_usage
24
+ one_line_usage << @command.arguments_description
25
+ if @command.commands.empty?
26
+ synopses << one_line_usage
27
+ else
28
+ synopses = sorted_synopses
29
+ if @command.has_action?
30
+ synopses.unshift(one_line_usage)
31
+ end
32
+
33
+ end
34
+
35
+ COMMAND_HELP.result(binding)
36
+ end
37
+
38
+ private
39
+ COMMAND_HELP = ERB.new(%q(NAME
40
+ <%= @command.name %> - <%= command_wrapper.wrap(@command.description) %>
41
+
42
+ SYNOPSIS
43
+ <% synopses.each do |s| %>
44
+ <%= s %>
45
+ <% end %>
46
+ <% unless @command.long_description.nil? %>
47
+
48
+ DESCRIPTION
49
+ <%= wrapper.wrap(@command.long_description) %>
50
+ <% end %>
51
+ <% if options_description.strip.length != 0 %>
52
+
53
+ COMMAND OPTIONS
54
+ <%= options_description %>
55
+ <% end %>
56
+ <% unless @command.commands.empty? %>
57
+
58
+ COMMANDS
59
+ <%= commands_description %>
60
+ <% end %>),nil,'<>')
61
+
62
+ def command_with_subcommand_usage(sub,is_default_command)
63
+ usage = basic_usage
64
+ sub_options = if @app.subcommand_option_handling_strategy == :legacy
65
+ @command.flags.merge(@command.switches).select { |_,o| o.associated_command == sub }
66
+ else
67
+ sub.flags.merge(sub.switches)
68
+ end
69
+ usage << sub_options.map { |option_name,option|
70
+ option.names_and_aliases.map { |_|
71
+ CommandLineOption.name_as_string(_,false) + (option.kind_of?(Flag) ? " #{option.argument_name }" : '')
72
+ }.join('|')
73
+ }.map { |_| "[#{_}]" }.sort.join(' ')
74
+ usage << ' '
75
+ if is_default_command
76
+ usage << "[#{sub.name}]"
77
+ else
78
+ usage << sub.name.to_s
79
+ end
80
+ usage << ArgNameFormatter.new.format(sub.arguments_description,sub.arguments_options)
81
+ usage
82
+ end
83
+
84
+ def flags_and_switches(command,app)
85
+ if app.subcommand_option_handling_strategy == :legacy
86
+ (
87
+ command.topmost_ancestor.flags_declaration_order +
88
+ command.topmost_ancestor.switches_declaration_order
89
+ ).select { |option| option.associated_command == command }
90
+ else
91
+ (
92
+ command.flags_declaration_order +
93
+ command.switches_declaration_order
94
+ )
95
+ end
96
+ end
97
+
98
+ def basic_usage
99
+ usage = @basic_invocation.dup
100
+ usage << " [global options]" unless global_flags_and_switches.empty?
101
+ usage << " #{path_to_command}"
102
+ usage << " [command options]" unless flags_and_switches(@command,@app).empty?
103
+ usage << " "
104
+ usage
105
+ end
106
+
107
+ def path_to_command
108
+ path = []
109
+ c = @command
110
+ while c.kind_of? Command
111
+ path.unshift(c.name)
112
+ c = c.parent
113
+ end
114
+ path.join(' ')
115
+ end
116
+
117
+ def global_flags_and_switches
118
+ @app.flags.merge(@app.switches)
119
+ end
120
+
121
+ def format_subcommands(command)
122
+ commands_array = @sorter.call(command.commands_declaration_order).map { |cmd|
123
+ if command.get_default_command == cmd.name
124
+ [cmd.names,String(cmd.description) + " (default)"]
125
+ else
126
+ [cmd.names,cmd.description]
127
+ end
128
+ }
129
+ if command.has_action?
130
+ commands_array.unshift(["<default>",command.default_description])
131
+ end
132
+ formatter = ListFormatter.new(commands_array,@wrapper_class)
133
+ StringIO.new.tap { |io| formatter.output(io) }.string
134
+ end
135
+
136
+ def sorted_synopses
137
+ synopses_command = {}
138
+ @command.commands.each do |name,sub|
139
+ default = @command.get_default_command == name
140
+ synopsis = command_with_subcommand_usage(sub,default)
141
+ synopses_command[synopsis] = sub
142
+ end
143
+ synopses = synopses_command.keys.sort { |one,two|
144
+ if synopses_command[one].name == @command.get_default_command
145
+ -1
146
+ elsif synopses_command[two].name == @command.get_default_command
147
+ 1
148
+ else
149
+ synopses_command[one] <=> synopses_command[two]
150
+ end
151
+ }
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,70 @@
1
+ require 'erb'
2
+
3
+ module GLI
4
+ module Commands
5
+ module HelpModules
6
+ class GlobalHelpFormat
7
+ def initialize(app,sorter,wrapper_class)
8
+ @app = app
9
+ @sorter = sorter
10
+ @wrapper_class = wrapper_class
11
+ end
12
+
13
+ def format
14
+ program_desc = @app.program_desc
15
+ program_long_desc = @app.program_long_desc
16
+ if program_long_desc
17
+ wrapper = @wrapper_class.new(Terminal.instance.size[0],4)
18
+ program_long_desc = "\n #{wrapper.wrap(program_long_desc)}\n\n" if program_long_desc
19
+ else
20
+ program_long_desc = "\n"
21
+ end
22
+
23
+ command_formatter = ListFormatter.new(@sorter.call(@app.commands_declaration_order.reject(&:nodoc)).map { |command|
24
+ [[command.name,Array(command.aliases)].flatten.join(', '),command.description]
25
+ }, @wrapper_class)
26
+ stringio = StringIO.new
27
+ command_formatter.output(stringio)
28
+ commands = stringio.string
29
+
30
+ global_option_descriptions = OptionsFormatter.new(global_flags_and_switches,@sorter,@wrapper_class).format
31
+
32
+ GLOBAL_HELP.result(binding)
33
+ end
34
+
35
+ private
36
+
37
+ GLOBAL_HELP = ERB.new(%q(NAME
38
+ <%= @app.exe_name %> - <%= program_desc %>
39
+ <%= program_long_desc %>
40
+ SYNOPSIS
41
+ <%= usage_string %>
42
+
43
+ <% unless @app.version_string.nil? %>
44
+ VERSION
45
+ <%= @app.version_string %>
46
+
47
+ <% end %>
48
+ <% unless global_flags_and_switches.empty? %>
49
+ GLOBAL OPTIONS
50
+ <%= global_option_descriptions %>
51
+
52
+ <% end %>
53
+ COMMANDS
54
+ <%= commands %>),nil,'<>')
55
+
56
+ def global_flags_and_switches
57
+ @app.flags_declaration_order + @app.switches_declaration_order
58
+ end
59
+
60
+ def usage_string
61
+ "#{@app.exe_name} ".tap do |string|
62
+ string << "[global options] " unless global_flags_and_switches.empty?
63
+ string << "command "
64
+ string << "[command options] [arguments...]"
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,31 @@
1
+ module GLI
2
+ module Commands
3
+ module HelpModules
4
+ class HelpCompletionFormat
5
+ def initialize(app,command_finder,args)
6
+ @app = app
7
+ @command_finder = command_finder
8
+ @command_finder.squelch_stderr = true
9
+ @args = args
10
+ end
11
+
12
+ def format
13
+ name = @args.shift
14
+
15
+ base = @command_finder.find_command(name)
16
+ base = @command_finder.last_found_command if base.nil?
17
+ base = @app if base.nil?
18
+
19
+ prefix_to_match = @command_finder.last_unknown_command
20
+
21
+ base.commands.values.map { |command|
22
+ [command.name,command.aliases]
23
+ }.flatten.compact.map(&:to_s).sort.select { |command_name|
24
+ prefix_to_match.nil? || command_name =~ /^#{prefix_to_match}/
25
+ }.join("\n")
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ module GLI
2
+ module Commands
3
+ module HelpModules
4
+ # Given a list of two-element lists, formats on the terminal
5
+ class ListFormatter
6
+ def initialize(list,wrapper_class=TextWrapper)
7
+ @list = list
8
+ @wrapper_class = wrapper_class
9
+ end
10
+
11
+ # Output the list to the output_device
12
+ def output(output_device)
13
+ return if @list.empty?
14
+ max_width = @list.map { |_| _[0].length }.max
15
+ wrapper = @wrapper_class.new(Terminal.instance.size[0],4 + max_width + 3)
16
+ @list.each do |(name,description)|
17
+ output_device.printf(" %-#{max_width}s - %s\n",name,wrapper.wrap(String(description).strip))
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end