visionmedia-commander 1.2.2

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.
data/History.txt ADDED
@@ -0,0 +1,48 @@
1
+
2
+ === 1.2.2 / 2008-11-06
3
+
4
+ * 1 Bug Fix:
5
+
6
+ * Forgot to add array.rb
7
+
8
+ === 1.2.0 / 2008-11-06
9
+
10
+ * 2 Major Enhancements:
11
+
12
+ * Added paging ability (similar to 'less')
13
+ * Added coloring to default help generator
14
+
15
+ === 1.1.0 / 2008-11-06
16
+
17
+ * 1 Major Enhancements:
18
+
19
+ * Added dependency for Highline gem, which replaces Commander's user interaction lib
20
+
21
+ === 1.0.4 / 2008-11-04
22
+
23
+ * 1 Minor Enhancements:
24
+
25
+ * Added support for --help and --version flags
26
+
27
+ === 1.0.3 / 2008-11-01
28
+
29
+ * 1 Bug Fix:
30
+
31
+ * Typo causing the gem to fail build on github
32
+
33
+ === 1.0.2 / 2008-11-01
34
+
35
+ * 1 Minor Enhancements:
36
+
37
+ * Added gemspec for github
38
+
39
+ === 1.0.1 / 2008-10-31
40
+
41
+ * 2 Minor Enhancements:
42
+
43
+ * Added shebang line to commander init
44
+ * Added require 'rubygems'
45
+
46
+ === 1.0.0 / 2008-10-31
47
+
48
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,17 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/commander
6
+ commander.gemspec
7
+ lib/commander.rb
8
+ lib/commander/command.rb
9
+ lib/commander/commander.rb
10
+ lib/commander/core_ext/array.rb
11
+ lib/commander/help_generators.rb
12
+ lib/commander/help_generators/default.rb
13
+ lib/commander/manager.rb
14
+ lib/commander/version.rb
15
+ spec/all_spec.rb
16
+ spec/commander_spec.rb
17
+ spec/manager_spec.rb
data/README.txt ADDED
@@ -0,0 +1,76 @@
1
+
2
+ == DESCRIPTION:
3
+
4
+ Commander is a small framework for creating a sub-command utility.
5
+ For example a sub command would be 'git add' or 'git rm', where 'add' and
6
+ 'rm' are sub commands.
7
+
8
+ == FEATURES:
9
+
10
+ * Sub-commands
11
+ * Auto-generated help documentation globally and per sub-command
12
+ * Simple syntax and implementation
13
+ * Extensible help generators for various output formats
14
+ * Use the 'commander' command to initialize a commander driven program
15
+ * Dependent on highline for terminal interaction (ask, choose, etc)
16
+
17
+ == USAGE:
18
+
19
+ require 'commander'
20
+
21
+ init_commander(
22
+ :name => 'Commander',
23
+ :version => Commander::VERSION,
24
+ :description => 'Commander utility program.'
25
+ )
26
+
27
+ command :init do |c|
28
+ c.syntax = 'commander init <filepath>'
29
+ c.description = 'Initialize an empty file with a commander skeleton.'
30
+ c.example 'Apply commander to a blank file.', 'commander init ./bin/my_executable'
31
+ c.option('-r', '--recursive', 'Do something recursively') { puts "I am recursive." }
32
+ c.option('-v', '--verbose', 'Do something verbosely') { puts "I am verbose." }
33
+ c.when_called do |args|
34
+ list = ask 'List some items:', Array
35
+ # Do something with list
36
+ end
37
+ end
38
+
39
+ == KNOWN ISSUES:
40
+
41
+ * none
42
+
43
+ == TODO:
44
+
45
+ * look at newgem gem and copy the whole 'create ./path' verbose listing conventions
46
+ * do testing for these apps like highline does with mock IO
47
+ * look at highline examples and change commander commands to work without new-lines etc
48
+ * more / better documentation
49
+ * help generator options (such as large option description etc)
50
+ * help generators should use erb
51
+ * refactor
52
+
53
+ == LICENSE:
54
+
55
+ (The MIT License)
56
+
57
+ Copyright (c) 2008 FIX
58
+
59
+ Permission is hereby granted, free of charge, to any person obtaining
60
+ a copy of this software and associated documentation files (the
61
+ 'Software'), to deal in the Software without restriction, including
62
+ without limitation the rights to use, copy, modify, merge, publish,
63
+ distribute, sublicense, and/or sell copies of the Software, and to
64
+ permit persons to whom the Software is furnished to do so, subject to
65
+ the following conditions:
66
+
67
+ The above copyright notice and this permission notice shall be
68
+ included in all copies or substantial portions of the Software.
69
+
70
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
71
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
72
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
73
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
74
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
75
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
76
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require './lib/commander.rb'
6
+
7
+ Hoe.new('commander', Commander::VERSION) do |p|
8
+ p.developer('TJ Holowaychuk', 'tj@vision-media.ca')
9
+ p.extra_deps << ['highline', '>= 1.5.0']
10
+ end
11
+
12
+ desc 'Build and install gem.'
13
+ task :build => [:remove, :install_gem] do
14
+ sh "clear"
15
+ end
16
+
17
+ desc 'Remove build data.'
18
+ task :remove => [:clean] do
19
+ sh "clear"
20
+ end
21
+
22
+ desc 'Run rspec suite.'
23
+ task :spec do
24
+ sh "clear"
25
+ sh "spec ./spec/all_spec.rb"
26
+ end
27
+
28
+ desc 'Run rspec suite with specdoc format.'
29
+ task :specd do
30
+ sh "clear"
31
+ sh "spec ./spec/all_spec.rb --format specdoc"
32
+ end
33
+
34
+ # vim: syntax=Ruby
data/bin/commander ADDED
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'commander'
4
+
5
+ init_commander(
6
+ :name => 'Commander',
7
+ :version => Commander::VERSION,
8
+ :description => 'Commander utility program.'
9
+ )
10
+
11
+ command :init do |c|
12
+ c.syntax = 'commander init <filepath>'
13
+ c.description = 'Initialize an empty file with a commander skeleton.'
14
+ c.example 'Create a new file with a commander skeleton.', 'commander init ./bin/my_executable'
15
+ c.when_called do |args|
16
+ abort "Provide a filepath." if args.empty?
17
+ puts
18
+ name = ask 'What is your programs machine name?'
19
+ description = ask 'Describe your program:'
20
+ commands = ask 'List the sub-commands you wish to create:', Array
21
+ begin
22
+ filepath = args.shift
23
+ File.open(filepath, 'w') do |f|
24
+ f.write <<-CODE
25
+ #!/usr/bin/env ruby
26
+
27
+ require 'rubygems'
28
+ require 'commander'
29
+
30
+ init_commander(
31
+ :name => '#{name.capitalize}',
32
+ :version => #{name.capitalize}::VERSION,
33
+ :description => '#{description}'
34
+ )
35
+
36
+ CODE
37
+ commands.each do |command|
38
+ f.write <<-CODE
39
+ command :#{command} do |c|
40
+ c.syntax = ''
41
+ c.description = ''
42
+ c.example 'description', 'code'
43
+ c.when_called do |args|
44
+ # Do something
45
+ end
46
+ end
47
+
48
+ CODE
49
+ end
50
+ end
51
+ say "Created commander skeleton at '#{filepath}'."
52
+ puts
53
+ rescue Exception => e
54
+ abort e
55
+ end
56
+ end
57
+ end
data/lib/commander.rb ADDED
@@ -0,0 +1,9 @@
1
+
2
+ $:.unshift(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'commander/commander'
5
+ require 'highline/import'
6
+
7
+ class Object
8
+ include Commander
9
+ end
@@ -0,0 +1,34 @@
1
+
2
+ module Commander
3
+ class Command
4
+
5
+ attr_accessor :description, :syntax, :examples, :options, :command, :manual
6
+ attr_reader :when_called_proc
7
+
8
+ def initialize(command)
9
+ @command, @options, @examples = command, [], []
10
+ end
11
+
12
+ # Adds an example in the help documentation of this sub-command.
13
+ def example(description, code)
14
+ @examples << { :description => description, :code => code }
15
+ end
16
+
17
+ # Adds an option or 'flag'. These are parsed with +OptionParser+
18
+ # so please view its documentation for help.
19
+ def option(*args, &block)
20
+ @options << { :args => args, :proc => block }
21
+ end
22
+
23
+ # This proc is called when the sub-command is invoked.
24
+ # The proc has instant access to all methods found in
25
+ # interaction.rb
26
+ def when_called(&block)
27
+ @when_called_proc = block
28
+ end
29
+
30
+ def invoke(method_name, *args)
31
+ send(method_name).call *args
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+
2
+ require 'commander/version'
3
+ require 'commander/command'
4
+ require 'commander/manager'
5
+ require 'commander/help_generators'
6
+ require 'commander/core_ext/array'
7
+ require 'optparse'
8
+
9
+ module Commander
10
+
11
+ def init_commander(options = {})
12
+ Commander::Manager.instance options
13
+ end
14
+
15
+ def add_command(command, &block)
16
+ _command = command
17
+ command = Commander::Command.new(_command)
18
+ yield command
19
+ Commander::Manager.instance.add_command command
20
+ end
21
+ alias :command :add_command
22
+
23
+ def get_command(command)
24
+ Commander::Manager.instance.get_command command
25
+ end
26
+
27
+ def command_exists?(command)
28
+ Commander::Manager.instance.include? command
29
+ end
30
+
31
+ def info(option)
32
+ Commander::Manager.instance.info[option]
33
+ end
34
+ end
35
+
@@ -0,0 +1,2 @@
1
+
2
+ require 'commander/help_generators/default'
@@ -0,0 +1,126 @@
1
+
2
+ module Commander
3
+ module HelpGenerators
4
+
5
+ # Default help generator.
6
+ #
7
+ # Example formatting:
8
+ #
9
+ # NAME:
10
+ #
11
+ # Commander-init
12
+ #
13
+ # DESCRIPTION:
14
+ #
15
+ # Initialize an empty file with a commander skeleton.
16
+ #
17
+ # EXAMPLES:
18
+ #
19
+ # # Apply commander to a blank file.
20
+ # commander init ./bin/my_executable
21
+ #
22
+ # OPTIONS:
23
+ #
24
+ # -r, --recursive, Do something recursively
25
+ # -v, --verbose, Do something verbosely
26
+ #
27
+ class Default
28
+
29
+ attr_reader :manager
30
+
31
+ def initialize(manager)
32
+ $terminal.page_at = 22
33
+ @manager = manager
34
+ @command = @manager.user_command
35
+ render
36
+ end
37
+
38
+ # -----------------------------------------------------------
39
+
40
+ protected
41
+
42
+ # -----------------------------------------------------------
43
+
44
+ def render
45
+ say(render_command(@command)) if @command
46
+ say(render_global) unless @command
47
+ end
48
+
49
+ def render_global
50
+ %w[ name description command_list copyright ].collect { |v| send("render_#{v}") }.join
51
+ end
52
+
53
+ def render_name
54
+ o = head 'name'
55
+ o += row 6, @manager.info[:name]
56
+ o += "\n"
57
+ o
58
+ end
59
+
60
+ def render_description
61
+ o = head 'description'
62
+ o += row 6, @manager.info[:description] unless @manager.info[:description].nil?
63
+ o += "\n"
64
+ o
65
+ end
66
+
67
+ def render_command_list
68
+ o = head 'sub-commands'
69
+ o += @manager.commands.collect { |c, command| row(6, c.to_s, command.description) }.join
70
+ o += row 6, "help", "Display this help information, or help for the trailing sub-command."
71
+ o += "\n"
72
+ o
73
+ end
74
+
75
+ def render_command(command)
76
+ o = head 'name'
77
+ o += row 6, "#{@manager.info[:name]}-#{command.command}"
78
+ o += "\n"
79
+
80
+ o += head 'description'
81
+ o += row 6, command.description
82
+ o += "\n"
83
+
84
+ o += head('examples') unless command.examples.empty?
85
+ o += render_command_examples command
86
+ o += "\n"
87
+
88
+ o += head('options') unless command.options.empty?
89
+ o += render_command_options command
90
+ o += "\n\n"
91
+ o
92
+ end
93
+
94
+ def render_command_options(command)
95
+ command.options.collect { |option| row(6, option[:args].join(', ')) }.join
96
+ end
97
+
98
+ def render_command_examples(command)
99
+ command.examples.collect do |example|
100
+ o = row 6, "# #{example[:description]}"
101
+ o += row 6, "#{example[:code]}"
102
+ end.join "\n"
103
+ end
104
+
105
+ def render_copyright
106
+ @manager.info[:copyright].nil? ? "\n" : head('copyright') + row(6, @manager.info[:copyright]) + "\n\n";
107
+ end
108
+
109
+ def head(text)
110
+ "\n <%= color('#{text.upcase}', BOLD) %>:\n"
111
+ end
112
+
113
+ def row(lpad, *args)
114
+ "\n" + (' ' * lpad) + args.collect { |a| a.to_s.ljust(15, ' ') }.join
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ class Hash
121
+ def collect(&block)
122
+ o = []
123
+ self.each_pair { |k, v| o << block.call(k, v)}
124
+ o
125
+ end
126
+ end
@@ -0,0 +1,129 @@
1
+
2
+ module Commander
3
+
4
+ # = Manager
5
+ #
6
+ # Controls management and invocation of sub-commands.
7
+ class Manager
8
+
9
+ attr_reader :command_options, :commands, :info
10
+ attr_reader :user_command, :user_args
11
+
12
+ # Initialize commander singleton.
13
+ #
14
+ # == Keys:
15
+ #
16
+ # * name (required)
17
+ # * version (required)
18
+ # * description
19
+ # * copyright
20
+ #
21
+ # == Examples:
22
+ #
23
+ # init_commander(
24
+ # :name => 'Commander',
25
+ # :version => Commander::VERSION,
26
+ # :description => 'Commander utility program.'
27
+ # )
28
+ #
29
+ def self.instance(options = {})
30
+ @@instance ||= Commander::Manager.new options
31
+ end
32
+
33
+ def self.kill_instance!
34
+ @@instance = nil
35
+ end
36
+
37
+ def initialize(options)
38
+ @info, @command_options = options, {}
39
+ @user_args = ARGV.dup
40
+ @info[:help_generator] ||= Commander::HelpGenerators::Default
41
+ init_version
42
+ at_exit { run }
43
+ end
44
+
45
+ def add_command(command)
46
+ @commands ||= {} and @commands[command.command] = command
47
+ end
48
+
49
+ def get_command(command)
50
+ @commands[command.to_sym]
51
+ end
52
+
53
+ def execute_command
54
+ abort "Invalid command." if not @user_command
55
+ unless @user_command.options.empty?
56
+ opts = OptionParser.new
57
+ @user_command.options.each { |option| opts.on(*option[:args], &option[:proc]) }
58
+ opts.parse! @user_args
59
+ end
60
+ rescue OptionParser::MissingArgument => e
61
+ debug_abort e
62
+ else
63
+ @user_command.invoke(:when_called_proc, @user_args)
64
+ end
65
+
66
+ def valid_command?(command)
67
+ !@commands[command.to_sym].nil? unless command.nil?
68
+ end
69
+ alias :include? :valid_command?
70
+
71
+ def empty?
72
+ @commands.empty?
73
+ end
74
+
75
+ def length
76
+ @commands.length
77
+ end
78
+ alias :size :length
79
+
80
+ def valid_version?(version)
81
+ version.split('.').length == 3 if version.is_a? String
82
+ end
83
+
84
+ def parse_version(version)
85
+ version.split('.').collect { |v| v.to_i } if version.is_a? String
86
+ end
87
+
88
+ def debug_abort(msg, exception = nil)
89
+ abort msg
90
+ end
91
+
92
+ def init_version
93
+ raise "Your program must have a version tuple ('x.x.x')." unless valid_version?(@info[:version])
94
+ @info[:major], @info[:minor], @info[:tiny] = parse_version(@info[:version])
95
+ end
96
+
97
+ def run
98
+ parse_options!
99
+ abort "Invalid arguments." if @user_args.empty?
100
+ @command_options[:help] = true and @user_args.shift if @user_args[0] == 'help'
101
+ set_user_command
102
+ case
103
+ when (@command_options[:help] and @user_args.empty?) then output_help
104
+ when @command_options[:help] then output_help
105
+ else execute_command
106
+ end
107
+ end
108
+
109
+ def parse_options!
110
+ opts = OptionParser.new
111
+ opts.on('--help') { output_help; exit }
112
+ opts.on('--version') { output_version; exit }
113
+ opts.parse! @user_args rescue nil
114
+ end
115
+
116
+ def set_user_command
117
+ @user_command = get_command(@user_args[0]) unless @user_args.empty?
118
+ @user_args.shift
119
+ end
120
+
121
+ def output_help
122
+ @info[:help_generator].new self
123
+ end
124
+
125
+ def output_version
126
+ puts "#{@info[:name]} #{@info[:version]}"
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,7 @@
1
+
2
+ module Commander
3
+ MAJOR = 1
4
+ MINOR = 2
5
+ TINY = 2
6
+ VERSION = [MAJOR, MINOR, TINY].join('.')
7
+ end
data/spec/all_spec.rb ADDED
@@ -0,0 +1,6 @@
1
+
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/commander')
3
+
4
+ Dir['./spec/**/*.rb'].each do |file|
5
+ require file unless file == './spec/all_spec.rb'
6
+ end
@@ -0,0 +1,42 @@
1
+
2
+ describe Commander do
3
+
4
+ before :each do
5
+ init_commander :version => '1.3.2', :name => 'My Program'
6
+ command :test_command do |c|
7
+ c.syntax = 'test_command [options]'
8
+ c.description = 'Just a test command.'
9
+ c.option '-h', '--help', 'View help information.'
10
+ c.option '--version', 'View program version.'
11
+ c.option '-v', '--verbose', 'Verbose output.'
12
+ c.example 'View help', 'test_command --help'
13
+ c.example 'View version', 'test_command --version'
14
+ end
15
+ @manager = Commander::Manager.instance
16
+ end
17
+
18
+ it "should add commands" do
19
+ @manager.length.should == 1
20
+ end
21
+
22
+ it "should fetch commands with the #get_command method" do
23
+ get_command(:test_command).syntax.should == 'test_command [options]'
24
+ end
25
+
26
+ it "should test existance of a command using #command_exists?" do
27
+ command_exists?(:test_command).should == true
28
+ command_exists?(:test).should == false
29
+ end
30
+
31
+ it "should inialize and set the version" do
32
+ info(:version).should == '1.3.2'
33
+ info(:major).should == 1
34
+ info(:minor).should == 3
35
+ info(:tiny).should == 2
36
+ end
37
+
38
+ it "should set program name" do
39
+ info(:name).should == 'My Program'
40
+ end
41
+ end
42
+
@@ -0,0 +1,19 @@
1
+
2
+ describe Commander::Manager do
3
+ before :each do
4
+ @manager = Commander::Manager.instance
5
+ end
6
+
7
+ it "should parse version numbers" do
8
+ @manager.parse_version('1.2.3').should == [1, 2, 3]
9
+ end
10
+
11
+ it "should validate version numbers" do
12
+ @manager.valid_version?('1.2.3').should == true
13
+ end
14
+
15
+ it "should invalidate version numbers" do
16
+ @manager.valid_version?('1.2').should_not == true
17
+ end
18
+
19
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: visionmedia-commander
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.2
5
+ platform: ruby
6
+ authors:
7
+ - TJ Holowaychuk
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-11-06 00:00:00 -08:00
13
+ default_executable: commander
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: highline
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.5.0
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: hoe
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 1.8.2
32
+ version:
33
+ description: Commander is a small framework for creating a sub-command utility. For example a sub command would be 'git add' or 'git rm', where 'add' and 'rm' are sub commands.
34
+ email:
35
+ - tj@vision-media.ca
36
+ executables:
37
+ - commander
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - History.txt
42
+ - Manifest.txt
43
+ - README.txt
44
+ files:
45
+ - History.txt
46
+ - Manifest.txt
47
+ - README.txt
48
+ - Rakefile
49
+ - bin/commander
50
+ - lib/commander.rb
51
+ - lib/commander/command.rb
52
+ - lib/commander/commander.rb
53
+ - lib/commander/help_generators.rb
54
+ - lib/commander/help_generators/default.rb
55
+ - lib/commander/manager.rb
56
+ - lib/commander/version.rb
57
+ - spec/all_spec.rb
58
+ - spec/commander_spec.rb
59
+ - spec/manager_spec.rb
60
+ has_rdoc: true
61
+ homepage:
62
+ post_install_message:
63
+ rdoc_options:
64
+ - --main
65
+ - README.txt
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ requirements: []
81
+
82
+ rubyforge_project: commander
83
+ rubygems_version: 1.2.0
84
+ signing_key:
85
+ specification_version: 2
86
+ summary: Commander is a small framework for creating a sub-command utility
87
+ test_files: []
88
+