murano-cli-commander 4.4.10

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 (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +44 -0
  5. data/.rubocop_todo.yml +77 -0
  6. data/.travis.yml +14 -0
  7. data/DEVELOPMENT +15 -0
  8. data/Gemfile +3 -0
  9. data/History.rdoc +446 -0
  10. data/LICENSE +22 -0
  11. data/Manifest +38 -0
  12. data/README.md +475 -0
  13. data/Rakefile +13 -0
  14. data/bin/murano-cli-commander +104 -0
  15. data/lib/murano-cli-commander.rb +35 -0
  16. data/lib/murano-cli-commander/blank.rb +7 -0
  17. data/lib/murano-cli-commander/command.rb +214 -0
  18. data/lib/murano-cli-commander/configure.rb +14 -0
  19. data/lib/murano-cli-commander/core_ext.rb +2 -0
  20. data/lib/murano-cli-commander/core_ext/array.rb +24 -0
  21. data/lib/murano-cli-commander/core_ext/object.rb +8 -0
  22. data/lib/murano-cli-commander/delegates.rb +25 -0
  23. data/lib/murano-cli-commander/help_formatters.rb +49 -0
  24. data/lib/murano-cli-commander/help_formatters/base.rb +24 -0
  25. data/lib/murano-cli-commander/help_formatters/terminal.rb +19 -0
  26. data/lib/murano-cli-commander/help_formatters/terminal/command_help.erb +35 -0
  27. data/lib/murano-cli-commander/help_formatters/terminal/help.erb +36 -0
  28. data/lib/murano-cli-commander/help_formatters/terminal_compact.rb +11 -0
  29. data/lib/murano-cli-commander/help_formatters/terminal_compact/command_help.erb +27 -0
  30. data/lib/murano-cli-commander/help_formatters/terminal_compact/help.erb +29 -0
  31. data/lib/murano-cli-commander/import.rb +5 -0
  32. data/lib/murano-cli-commander/methods.rb +11 -0
  33. data/lib/murano-cli-commander/platform.rb +7 -0
  34. data/lib/murano-cli-commander/runner.rb +455 -0
  35. data/lib/murano-cli-commander/user_interaction.rb +551 -0
  36. data/lib/murano-cli-commander/version.rb +3 -0
  37. data/murano-cli-commander.gemspec +36 -0
  38. data/spec/command_spec.rb +169 -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 +69 -0
  43. data/spec/help_formatters/terminal_spec.rb +67 -0
  44. data/spec/methods_spec.rb +61 -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 +163 -0
data/Rakefile ADDED
@@ -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 'murano-cli-commander/import'
5
+
6
+ program :name, 'murano-cli-commander'
7
+ program :version, Commander::VERSION
8
+ program :description, 'Commander utility program.'
9
+
10
+ command :init do |c|
11
+ c.syntax = 'murano-cli-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.', 'murano-cli-commander init bin/my_executable'
16
+ c.example 'Create a new modular style template file.', 'murano-cli-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 'murano-cli-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 'murano-cli-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,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 'murano-cli-commander/version'
26
+ require 'murano-cli-commander/blank'
27
+ require 'murano-cli-commander/user_interaction'
28
+ require 'murano-cli-commander/core_ext'
29
+ require 'murano-cli-commander/runner'
30
+ require 'murano-cli-commander/command'
31
+ require 'murano-cli-commander/help_formatters'
32
+ require 'murano-cli-commander/platform'
33
+ require 'murano-cli-commander/delegates'
34
+ require 'murano-cli-commander/methods'
35
+ require 'murano-cli-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,214 @@
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
+ # empty proxy_options before populating via OptionParser
165
+ # prevents duplication of options if the command is run twice
166
+ proxy_options.clear
167
+ @options.each_with_object(OptionParser.new) do |option, opts|
168
+ opts.on(*option[:args], &option[:proc])
169
+ opts
170
+ end.parse! args
171
+ end
172
+
173
+ ##
174
+ # Call the commands when_called block with _args_.
175
+
176
+ def call(args = [])
177
+ object, meth = @when_called[0, 2]
178
+ meth ||= :call
179
+ options = proxy_option_struct
180
+
181
+ case object
182
+ when Proc then object.call(args, options)
183
+ when Class then meth != :call ? object.new.send(meth, args, options) : object.new(args, options)
184
+ else object.send(meth, args, options) if object
185
+ end
186
+ end
187
+
188
+ ##
189
+ # Creates an Options instance populated with the option values
190
+ # collected by the #option_proc.
191
+
192
+ def proxy_option_struct
193
+ proxy_options.each_with_object(Options.new) do |(option, value), options|
194
+ # options that are present will evaluate to true
195
+ value = true if value.nil?
196
+ options.__send__ :"#{option}=", value
197
+ options
198
+ end
199
+ end
200
+
201
+ ##
202
+ # Option proxy proc used when a block is not explicitly passed
203
+ # via the #option method. This allows commander to auto-populate
204
+ # and work with option values.
205
+
206
+ def option_proc(switches)
207
+ ->(value) { proxy_options << [Runner.switch_to_sym(switches.last), value] }
208
+ end
209
+
210
+ def inspect
211
+ "<Commander::Command:#{name}>"
212
+ end
213
+ end
214
+ 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 'murano-cli-commander/core_ext/array'
2
+ require 'murano-cli-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
@@ -0,0 +1,8 @@
1
+ class Object
2
+ ##
3
+ # Return the current binding.
4
+
5
+ def get_binding
6
+ binding
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ module Commander
2
+ module Delegates
3
+ %w(
4
+ add_command
5
+ command
6
+ program
7
+ run!
8
+ global_option
9
+ alias_command
10
+ default_command
11
+ always_trace!
12
+ never_trace!
13
+ ).each do |meth|
14
+ eval <<-END, binding, __FILE__, __LINE__
15
+ def #{meth}(*args, &block)
16
+ ::Commander::Runner.instance.#{meth}(*args, &block)
17
+ end
18
+ END
19
+ end
20
+
21
+ def defined_commands(*args, &block)
22
+ ::Commander::Runner.instance.commands(*args, &block)
23
+ end
24
+ end
25
+ end