visionmedia-commander 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
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
+