commander-fastlane 4.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +37 -0
  5. data/.rubocop_todo.yml +77 -0
  6. data/.travis.yml +12 -0
  7. data/DEVELOPMENT +15 -0
  8. data/Gemfile +3 -0
  9. data/History.rdoc +428 -0
  10. data/LICENSE +22 -0
  11. data/Manifest +38 -0
  12. data/README.md +460 -0
  13. data/Rakefile +13 -0
  14. data/bin/commander +104 -0
  15. data/commander.gemspec +31 -0
  16. data/lib/commander.rb +35 -0
  17. data/lib/commander/blank.rb +7 -0
  18. data/lib/commander/command.rb +210 -0
  19. data/lib/commander/configure.rb +14 -0
  20. data/lib/commander/core_ext.rb +2 -0
  21. data/lib/commander/core_ext/array.rb +24 -0
  22. data/lib/commander/core_ext/object.rb +8 -0
  23. data/lib/commander/delegates.rb +25 -0
  24. data/lib/commander/help_formatters.rb +49 -0
  25. data/lib/commander/help_formatters/base.rb +24 -0
  26. data/lib/commander/help_formatters/terminal.rb +19 -0
  27. data/lib/commander/help_formatters/terminal/command_help.erb +35 -0
  28. data/lib/commander/help_formatters/terminal/help.erb +44 -0
  29. data/lib/commander/help_formatters/terminal_compact.rb +11 -0
  30. data/lib/commander/help_formatters/terminal_compact/command_help.erb +27 -0
  31. data/lib/commander/help_formatters/terminal_compact/help.erb +35 -0
  32. data/lib/commander/import.rb +5 -0
  33. data/lib/commander/methods.rb +11 -0
  34. data/lib/commander/platform.rb +7 -0
  35. data/lib/commander/runner.rb +484 -0
  36. data/lib/commander/user_interaction.rb +528 -0
  37. data/lib/commander/version.rb +3 -0
  38. data/spec/command_spec.rb +157 -0
  39. data/spec/configure_spec.rb +37 -0
  40. data/spec/core_ext/array_spec.rb +18 -0
  41. data/spec/core_ext/object_spec.rb +19 -0
  42. data/spec/help_formatters/terminal_compact_spec.rb +195 -0
  43. data/spec/help_formatters/terminal_spec.rb +190 -0
  44. data/spec/methods_spec.rb +20 -0
  45. data/spec/runner_spec.rb +646 -0
  46. data/spec/spec_helper.rb +78 -0
  47. data/spec/ui_spec.rb +30 -0
  48. metadata +175 -0
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ desc 'Run specs'
6
+ RSpec::Core::RakeTask.new do |t|
7
+ t.verbose = false
8
+ t.rspec_opts = '--color --order random'
9
+ end
10
+
11
+ RuboCop::RakeTask.new
12
+
13
+ task default: [:spec, :rubocop]
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'commander/import'
5
+
6
+ program :name, 'commander'
7
+ program :version, Commander::VERSION
8
+ program :description, 'Commander utility program.'
9
+
10
+ command :init do |c|
11
+ c.syntax = 'commander init [option] <file>'
12
+ c.summary = 'Initialize a commander template'
13
+ c.description = 'Initialize an empty <file> with a commander template,
14
+ allowing very quick creation of commander executables.'
15
+ c.example 'Create a new classic style template file.', 'commander init bin/my_executable'
16
+ c.example 'Create a new modular style template file.', 'commander init --modular bin/my_executable'
17
+ c.option '-m', '--modular', 'Initialize a modular style template'
18
+ c.action do |args, options|
19
+ file = args.shift || abort('file argument required.')
20
+ name = ask 'Machine name of program: '
21
+ description = ask 'Describe your program: '
22
+ commands = ask_for_array 'List the commands you wish to create: '
23
+ begin
24
+ if options.modular
25
+ File.open(file, 'w') do |f|
26
+ f.write <<-"...".gsub!(/^ {10}/, '')
27
+ #!/usr/bin/env ruby
28
+
29
+ require 'rubygems'
30
+ require 'commander'
31
+
32
+ class MyApplication
33
+ include Commander::Methods
34
+ # include whatever modules you need
35
+
36
+ def run
37
+ program :name, '#{name}'
38
+ program :version, '0.0.1'
39
+ program :description, '#{description}'
40
+
41
+ ...
42
+ commands.each do |command|
43
+ f.write <<-"...".gsub!(/^ {12}/, '')
44
+ command :#{command} do |c|
45
+ c.syntax = '#{name} #{command} [options]'
46
+ c.summary = ''
47
+ c.description = ''
48
+ c.example 'description', 'command example'
49
+ c.option '--some-switch', 'Some switch that does something'
50
+ c.action do |args, options|
51
+ # Do something or c.when_called #{name.capitalize}::Commands::#{command.capitalize}
52
+ end
53
+ end
54
+
55
+ ...
56
+ end
57
+ f.write <<-"...".gsub!(/^ {12}/, '')
58
+ run!
59
+ end
60
+ end
61
+
62
+ MyApplication.new.run if $0 == __FILE__
63
+ ...
64
+ end
65
+
66
+ File.chmod(0755, file)
67
+ say "Initialized modular template in #{file}"
68
+ else
69
+ File.open(file, 'w') do |f|
70
+ f.write <<-"...".gsub!(/^ {10}/, '')
71
+ #!/usr/bin/env ruby
72
+
73
+ require 'rubygems'
74
+ require 'commander/import'
75
+
76
+ program :name, '#{name}'
77
+ program :version, '0.0.1'
78
+ program :description, '#{description}'
79
+
80
+ ...
81
+ commands.each do |command|
82
+ f.write <<-"...".gsub!(/^ {12}/, '')
83
+ command :#{command} do |c|
84
+ c.syntax = '#{name} #{command} [options]'
85
+ c.summary = ''
86
+ c.description = ''
87
+ c.example 'description', 'command example'
88
+ c.option '--some-switch', 'Some switch that does something'
89
+ c.action do |args, options|
90
+ # Do something or c.when_called #{name.capitalize}::Commands::#{command.capitalize}
91
+ end
92
+ end
93
+
94
+ ...
95
+ end
96
+ end
97
+ File.chmod 0755, file
98
+ say "Initialized template in #{file}"
99
+ end
100
+ rescue => e
101
+ abort e
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
+ require 'commander/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'commander-fastlane'
7
+ s.version = Commander::VERSION
8
+ s.authors = ['TJ Holowaychuk', 'Gabriel Gilder']
9
+ s.email = ['gabriel@gabrielgilder.com']
10
+ s.license = 'MIT'
11
+ s.homepage = 'https://github.com/commander-rb/commander'
12
+ s.summary = 'The complete solution for Ruby command-line executables'
13
+ s.description = 'The complete solution for Ruby command-line executables. Commander bridges the gap between other terminal related libraries you know and love (OptionParser, HighLine), while providing many new features, and an elegant API.'
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
+ s.require_paths = ['lib']
19
+
20
+ s.add_runtime_dependency('highline', '~> 1.7.2')
21
+
22
+ s.add_development_dependency('rspec', '~> 3.2')
23
+ s.add_development_dependency('rake')
24
+ s.add_development_dependency('simplecov')
25
+ if RUBY_VERSION < '2.0'
26
+ s.add_development_dependency('rubocop', '~> 0.41.1')
27
+ s.add_development_dependency('json', '< 2.0')
28
+ else
29
+ s.add_development_dependency('rubocop', '~> 0.46')
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+ #--
2
+ # Copyright (c) 2008-2009 TJ Holowaychuk <tj@vision-media.ca>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require 'highline/import'
25
+ require 'commander/version'
26
+ require 'commander/blank'
27
+ require 'commander/user_interaction'
28
+ require 'commander/core_ext'
29
+ require 'commander/runner'
30
+ require 'commander/command'
31
+ require 'commander/help_formatters'
32
+ require 'commander/platform'
33
+ require 'commander/delegates'
34
+ require 'commander/methods'
35
+ require 'commander/configure'
@@ -0,0 +1,7 @@
1
+ module Blank
2
+ def self.included(base)
3
+ base.class_eval do
4
+ instance_methods.each { |m| undef_method m unless m =~ /^__|object_id/ }
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,210 @@
1
+ require 'optparse'
2
+
3
+ module Commander
4
+ class Command
5
+ attr_accessor :name, :examples, :syntax, :description
6
+ attr_accessor :summary, :proxy_options, :options
7
+
8
+ ##
9
+ # Options struct.
10
+
11
+ class Options
12
+ include Blank
13
+
14
+ def initialize
15
+ @table = {}
16
+ end
17
+
18
+ def __hash__
19
+ @table
20
+ end
21
+
22
+ def method_missing(meth, *args)
23
+ meth.to_s =~ /=$/ ? @table[meth.to_s.chop.to_sym] = args.first : @table[meth]
24
+ end
25
+
26
+ def default(defaults = {})
27
+ @table = defaults.merge! @table
28
+ end
29
+
30
+ def inspect
31
+ "<Commander::Command::Options #{ __hash__.map { |k, v| "#{k}=#{v.inspect}" }.join(', ') }>"
32
+ end
33
+ end
34
+
35
+ ##
36
+ # Initialize new command with specified _name_.
37
+
38
+ def initialize(name)
39
+ @name, @examples, @when_called = name.to_s, [], []
40
+ @options, @proxy_options = [], []
41
+ end
42
+
43
+ ##
44
+ # Add a usage example for this command.
45
+ #
46
+ # Usage examples are later displayed in help documentation
47
+ # created by the help formatters.
48
+ #
49
+ # === Examples
50
+ #
51
+ # command :something do |c|
52
+ # c.example "Should do something", "my_command something"
53
+ # end
54
+ #
55
+
56
+ def example(description, command)
57
+ @examples << [description, command]
58
+ end
59
+
60
+ ##
61
+ # Add an option.
62
+ #
63
+ # Options are parsed via OptionParser so view it
64
+ # for additional usage documentation. A block may optionally be
65
+ # passed to handle the option, otherwise the _options_ struct seen below
66
+ # contains the results of this option. This handles common formats such as:
67
+ #
68
+ # -h, --help options.help # => bool
69
+ # --[no-]feature options.feature # => bool
70
+ # --large-switch options.large_switch # => bool
71
+ # --file FILE options.file # => file passed
72
+ # --list WORDS options.list # => array
73
+ # --date [DATE] options.date # => date or nil when optional argument not set
74
+ #
75
+ # === Examples
76
+ #
77
+ # command :something do |c|
78
+ # c.option '--recursive', 'Do something recursively'
79
+ # c.option '--file FILE', 'Specify a file'
80
+ # c.option('--info', 'Display info') { puts "handle with block" }
81
+ # c.option '--[no-]feature', 'With or without feature'
82
+ # c.option '--list FILES', Array, 'List the files specified'
83
+ #
84
+ # c.when_called do |args, options|
85
+ # do_something_recursively if options.recursive
86
+ # do_something_with_file options.file if options.file
87
+ # end
88
+ # end
89
+ #
90
+ # === Help Formatters
91
+ #
92
+ # This method also parses the arguments passed in order to determine
93
+ # which were switches, and which were descriptions for the
94
+ # option which can later be used within help formatters
95
+ # using option[:switches] and option[:description].
96
+ #
97
+ # === Input Parsing
98
+ #
99
+ # Since Commander utilizes OptionParser you can pre-parse and evaluate
100
+ # option arguments. Simply require 'optparse/time', or 'optparse/date', as these
101
+ # objects must respond to #parse.
102
+ #
103
+ # c.option '--time TIME', Time
104
+ # c.option '--date [DATE]', Date
105
+ #
106
+
107
+ def option(*args, &block)
108
+ switches, description = Runner.separate_switches_from_description(*args)
109
+ proc = block || option_proc(switches)
110
+ @options << {
111
+ args: args,
112
+ proc: proc,
113
+ switches: switches,
114
+ description: description,
115
+ }
116
+ end
117
+
118
+ ##
119
+ # Handle execution of command. The handler may be a class,
120
+ # object, or block (see examples below).
121
+ #
122
+ # === Examples
123
+ #
124
+ # # Simple block handling
125
+ # c.when_called do |args, options|
126
+ # # do something
127
+ # end
128
+ #
129
+ # # Create inst of Something and pass args / options
130
+ # c.when_called MyLib::Command::Something
131
+ #
132
+ # # Create inst of Something and use arbitrary method
133
+ # c.when_called MyLib::Command::Something, :some_method
134
+ #
135
+ # # Pass an object to handle callback (requires method symbol)
136
+ # c.when_called SomeObject, :some_method
137
+ #
138
+
139
+ def when_called(*args, &block)
140
+ fail ArgumentError, 'must pass an object, class, or block.' if args.empty? && !block
141
+ @when_called = block ? [block] : args
142
+ end
143
+ alias action when_called
144
+
145
+ ##
146
+ # Run the command with _args_.
147
+ #
148
+ # * parses options, call option blocks
149
+ # * invokes when_called proc
150
+ #
151
+
152
+ def run(*args)
153
+ call parse_options_and_call_procs(*args)
154
+ end
155
+
156
+ #:stopdoc:
157
+
158
+ ##
159
+ # Parses options and calls associated procs,
160
+ # returning the arguments remaining.
161
+
162
+ def parse_options_and_call_procs(*args)
163
+ return args if args.empty?
164
+ @options.each_with_object(OptionParser.new) do |option, opts|
165
+ opts.on(*option[:args], &option[:proc])
166
+ opts
167
+ end.parse! args
168
+ end
169
+
170
+ ##
171
+ # Call the commands when_called block with _args_.
172
+
173
+ def call(args = [])
174
+ object = @when_called.shift
175
+ meth = @when_called.shift || :call
176
+ options = proxy_option_struct
177
+ case object
178
+ when Proc then object.call(args, options)
179
+ when Class then meth != :call ? object.new.send(meth, args, options) : object.new(args, options)
180
+ else object.send(meth, args, options) if object
181
+ end
182
+ end
183
+
184
+ ##
185
+ # Creates an Options instance populated with the option values
186
+ # collected by the #option_proc.
187
+
188
+ def proxy_option_struct
189
+ proxy_options.each_with_object(Options.new) do |(option, value), options|
190
+ # options that are present will evaluate to true
191
+ value = true if value.nil?
192
+ options.__send__ :"#{option}=", value
193
+ options
194
+ end
195
+ end
196
+
197
+ ##
198
+ # Option proxy proc used when a block is not explicitly passed
199
+ # via the #option method. This allows commander to auto-populate
200
+ # and work with option values.
201
+
202
+ def option_proc(switches)
203
+ ->(value) { proxy_options << [Runner.switch_to_sym(switches.last), value] }
204
+ end
205
+
206
+ def inspect
207
+ "<Commander::Command:#{name}>"
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,14 @@
1
+ module Commander
2
+ def configure(*configuration_opts, &configuration_block)
3
+ configuration_module = Module.new
4
+ configuration_module.extend Commander::Methods
5
+
6
+ configuration_module.class_exec(*configuration_opts, &configuration_block)
7
+
8
+ configuration_module.class_exec do
9
+ run!
10
+ end
11
+ end
12
+
13
+ module_function :configure
14
+ end
@@ -0,0 +1,2 @@
1
+ require 'commander/core_ext/array'
2
+ require 'commander/core_ext/object'
@@ -0,0 +1,24 @@
1
+ class Array
2
+ ##
3
+ # Split _string_ into an array. Used in
4
+ # conjunction with Highline's #ask, or #ask_for_array
5
+ # methods, which must respond to #parse.
6
+ #
7
+ # This method allows escaping of whitespace. For example
8
+ # the arguments foo bar\ baz will become ['foo', 'bar baz']
9
+ #
10
+ # === Example
11
+ #
12
+ # # ask invokes Array#parse
13
+ # list = ask 'Favorite cookies:', Array
14
+ #
15
+ # # or use ask_for_CLASS
16
+ # list = ask_for_array 'Favorite cookies: '
17
+ #
18
+
19
+ def self.parse(string)
20
+ # Using reverse + lookahead to work around Ruby 1.8's lack of lookbehind
21
+ # TODO: simplify now that we don't support Ruby 1.8
22
+ string.reverse.split(/\s(?!\\)/).reverse.map { |s| s.reverse.gsub('\\ ', ' ') }
23
+ end
24
+ end