shebang 0.1

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/.gems ADDED
@@ -0,0 +1,3 @@
1
+ bacon
2
+ yard
3
+ rdiscount
@@ -0,0 +1,10 @@
1
+ # Ignore build related files
2
+ doc
3
+ pkg/*.gem
4
+
5
+ # Ignore common crap
6
+ .DS_Store
7
+ Thumbs.db
8
+
9
+ # Keep those funky gitkeep files
10
+ !.gitkeep
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use --create 1.9.2@shebang
@@ -0,0 +1,16 @@
1
+ script: "rvm gemset import .gems; rake test"
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - ree
7
+ - rbx
8
+ - rbx-2.0
9
+ - jruby
10
+
11
+ notifications:
12
+ email: false
13
+
14
+ branches:
15
+ only:
16
+ - master
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2011, Yorick Peterse
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,154 @@
1
+ # README
2
+
3
+ Shebang is a nice wrapper around OptionParser that makes it easier to write
4
+ commandline executables. I wrote it after getting fed up of having to re-invent
5
+ the same wheel every time I wanted to write a commandline executable. For
6
+ example, a relatively simple command using OptionParser directly may look like
7
+ the following:
8
+
9
+ require 'optparse'
10
+
11
+ @options = {:force => false, :f => false, :name => nil, :n => nil}
12
+ parser = OptionParser.new do |opt|
13
+ opt.banner = <<-TXT.strip
14
+ Runs an example command.
15
+
16
+ Usage:
17
+ $ foobar.rb [OPTIONS]
18
+ TXT
19
+
20
+ opt.summary_indent = ' '
21
+
22
+ opt.separator "\nOptions:\n"
23
+
24
+ opt.on('-h', '--help', 'Shows this help message') do
25
+ puts parser
26
+ exit
27
+ end
28
+
29
+ opt.on('-v', '--version', 'Shows the current version') do
30
+ puts '0.1'
31
+ exit
32
+ end
33
+
34
+ opt.on('-f', '--force', 'Forces the command to run') do
35
+ @options[:force] = @options[:f] = true
36
+ end
37
+
38
+ opt.on('-n', '--name NAME', 'A person\'s name') do |name|
39
+ @options[:name] = @options[:n] = name
40
+ end
41
+ end
42
+
43
+ parser.parse!
44
+
45
+ puts "Your name is #{@options[:name]}"
46
+
47
+ Using Shebang this can be done as following:
48
+
49
+ require 'shebang'
50
+
51
+ class Greet < Shebang::Command
52
+ command :default
53
+ banner 'Runs an example command.'
54
+ usage '$ foobar.rb [OPTIONS]'
55
+
56
+ o :h, :help , 'Shows this help message' , :method => :help
57
+ o :v, :version, 'Shows the current version', :method => :version
58
+ o :f, :force , 'Forces the command to run'
59
+ o :n, :name , 'A person\'s name', :type => String
60
+
61
+ def version
62
+ puts '0.1'
63
+ exit
64
+ end
65
+
66
+ def index
67
+ puts "Your name is #{@options[:n]}"
68
+ end
69
+ end
70
+
71
+ Shebang.run
72
+
73
+ ## Usage
74
+
75
+ As shown in the example above commands can be created by extending the class
76
+ ``Shebang::Command`` and calling the class method ``command()``. Each command
77
+ required an instance method called ``index()`` to be defined, this method is
78
+ called once OptionParser has been set up and the commandline arguments have
79
+ been parsed:
80
+
81
+ require 'shebang'
82
+
83
+ class Greet < Shebang::Command
84
+ command :default
85
+
86
+ def index
87
+
88
+ end
89
+ end
90
+
91
+ Options can be retrieved using the method ``option()`` which takes either the
92
+ short or long name of an option, in both cases it will result in the same value
93
+ (given the option names belong to the same option):
94
+
95
+ option(:h) === option(:help) # => true
96
+
97
+ Options can be added using the class method ``option()`` or it's alias ``o()``.
98
+ Besides the features offered by OptionParser options can specify a method to
99
+ execute in case that particular option has been specified. This can be done by
100
+ passing the ``:method`` key to the option method:
101
+
102
+ option :f, :foobar, 'Calls a method', :method => :foobar
103
+
104
+ Now whenever the ``-f`` of ``--foobar`` option is set the method ``foobar()``
105
+ will be executed **without** stopping the rest of the command. This means that
106
+ you'll have to manually call ``Kernel.exit()`` if you want to stop the execution
107
+ process if a certain option is specified.
108
+
109
+ Shebang comes with support for defining sub commands. Sub commands are nothing
110
+ more than different methods than the default one. Say you have a class
111
+ ``Git::Submodule``, to run the command itself you'd invoke the default method on
112
+ this class (index by default):
113
+
114
+ cmd = Git::Submodule.new
115
+
116
+ cmd.parse([...])
117
+ cmd.index
118
+
119
+ To show the status of a submodule you'd invoke ``git submodule status``, this
120
+ translates to the following code:
121
+
122
+ cmd = Git::Submodule.new
123
+
124
+ cmd.parse([...])
125
+ cmd.status
126
+
127
+ Shebang takes care of this using ``Shebang.run()``. The first commandline
128
+ argument that does not start with ``-`` (and this isn't an option) is considered
129
+ the command name. If there's another argument that's not a switch following that
130
+ one will be used as the method name. This means that in order to invoke
131
+ ``Git::Submodule#index`` you'd type the following into your terminal:
132
+
133
+ git.rb submodule
134
+
135
+ If you want to invoke a method other than the default one you'd do the
136
+ following:
137
+
138
+ git.rb submodule status
139
+
140
+ In other words, the syntax of a Shebang command is the following:
141
+
142
+ script [COMMAND] [METHOD] [ARGS] [OPTIONS]
143
+
144
+ ## Configuration
145
+
146
+ Various options of Shebang can be configured by modifying the hash
147
+ ``Shebang::Config``. For example, if you want to change the format of all the
148
+ headers in the help message you can do so as following:
149
+
150
+ Shebang::Config[:heading] = "\n== %s:\n"
151
+
152
+ You can also change the name of the default command:
153
+
154
+ Shebang::Config[:default_command] = :my_default_command
@@ -0,0 +1,11 @@
1
+ require File.expand_path('../lib/shebang', __FILE__)
2
+
3
+ module Shebang
4
+ Gemspec = Gem::Specification::load(File.expand_path('../shebang.gemspec', __FILE__))
5
+ end
6
+
7
+ task_dir = File.expand_path('../task', __FILE__)
8
+
9
+ Dir.glob("#{task_dir}/*.rake").each do |f|
10
+ import(f)
11
+ end
@@ -0,0 +1,35 @@
1
+ require File.expand_path('../../lib/shebang', __FILE__)
2
+
3
+ class Greet < Shebang::Command
4
+ command :default
5
+ banner 'Runs an example command.'
6
+ usage '$ ruby example/basic.rb [OPTIONS]'
7
+
8
+ o :h, :help , 'Shows this help message' , :method => :help
9
+ o :v, :version, 'Shows the current version', :method => :version
10
+ o :f, :force , 'Forces the command to run'
11
+ o :n, :name , 'A person\'s name', :type => String,
12
+ :required => true, :default => 'Shebang'
13
+
14
+ # $ ruby example/basic.rb
15
+ # $ ruby example/basic.rb default
16
+ # $ ruby example/basic.rb default index
17
+ def index
18
+ puts "Your name is #{option(:n)}"
19
+ end
20
+
21
+ # $ ruby example/basic.rb test
22
+ # $ ruby example/basic.rb default test
23
+ def test
24
+ puts 'This is a test method'
25
+ end
26
+
27
+ protected
28
+
29
+ def version
30
+ puts Shebang::Version
31
+ exit
32
+ end
33
+ end
34
+
35
+ Shebang.run
File without changes
@@ -0,0 +1,104 @@
1
+ require 'rubygems'
2
+ require 'optparse'
3
+ require File.expand_path('../shebang/version', __FILE__)
4
+ require File.expand_path('../shebang/command', __FILE__)
5
+ require File.expand_path('../shebang/option' , __FILE__)
6
+
7
+ ##
8
+ # Shebang is a nice wrapper around OptionParser that makes it easier to write
9
+ # commandline executables.
10
+ #
11
+ # @author Yorick Peterse
12
+ # @since 0.1
13
+ #
14
+ module Shebang
15
+ #:nodoc:
16
+ class Error < StandardError; end
17
+
18
+ # Hash containing various configuration options.
19
+ Config = {
20
+ # The name of the default command to invoke when no command is specified.
21
+ :default_command => :default,
22
+
23
+ # The name of the default method to invoke.
24
+ :default_method => :index,
25
+
26
+ # The amount of spaces to insert before each option.
27
+ :indent => ' ',
28
+
29
+ # The format for each header for help topics, options, etc.
30
+ :heading => "\n%s:\n",
31
+
32
+ # When set to true Shebang will raise an exception for errors instead of
33
+ # just printing a message.
34
+ :raise => true
35
+ }
36
+
37
+ # Hash containing the names of all commands and their classes.
38
+ Commands = {}
39
+
40
+ class << self
41
+ ##
42
+ # Runs a command based on the command line arguments. If no command is given
43
+ # this method will try to invoke the default command.
44
+ #
45
+ # @author Yorick Peterse
46
+ # @since 0.1
47
+ # @param [Array] argv Array containing the command line arguments to parse.
48
+ #
49
+ def run(argv = ARGV)
50
+ self.error("No commands have been registered") if Commands.empty?
51
+
52
+ command = Config[:default_command].to_sym
53
+ method = Config[:default_method].to_sym
54
+
55
+ if !argv.empty?
56
+ # Get the command name
57
+ if argv[0][0] != '-' and Commands.key?(argv[0].to_sym)
58
+ command = argv.delete_at(0).to_sym
59
+ end
60
+ end
61
+
62
+ if Commands.key?(command)
63
+ klass = Commands[command].new
64
+
65
+ # Get the method to call.
66
+ if argv[0] and argv[0][0] != '-' and klass.respond_to?(argv[0].to_sym)
67
+ method = argv.delete_at(0).to_sym
68
+ end
69
+
70
+ # Parse the arguments and prepare all the options.
71
+ argv = klass.parse(argv)
72
+
73
+ # Call the method and pass the commandline arguments to it.
74
+ if klass.respond_to?(method)
75
+ if klass.class.instance_method(method).arity != 0
76
+ klass.send(method, argv)
77
+ else
78
+ klass.send(method)
79
+ end
80
+ else
81
+ error("The command #{command} does not have a #{method}() method")
82
+ end
83
+ else
84
+ error("The command #{command} does not exist")
85
+ end
86
+ end
87
+
88
+ ##
89
+ # Raises an exception or prints a regular error message to STDERR based on
90
+ # the :raise configuration option.
91
+ #
92
+ # @author Yorick Peterse
93
+ # @since 0.1
94
+ # @param [String] message The message to display.
95
+ #
96
+ def error(message)
97
+ if Config[:raise] === true
98
+ raise(Error, message)
99
+ else
100
+ abort "\e[0;31mError:\e[0m #{message}"
101
+ end
102
+ end
103
+ end # class << self
104
+ end # Shebang
File without changes
@@ -0,0 +1,274 @@
1
+ module Shebang
2
+ ##
3
+ # Shebang::Command is where the party really starts. By extending this class
4
+ # other classes can become fully fledged commands with their own options,
5
+ # banners, callbacks, and so on. In it's most basic form a command looks like
6
+ # the following:
7
+ #
8
+ # class MyCommand < Shebang::Command
9
+ # command 'my-command'
10
+ #
11
+ # def index
12
+ #
13
+ # end
14
+ # end
15
+ #
16
+ # The class method command() is used to register the class to the specified
17
+ # name, without this Shebang would be unable to call it.
18
+ #
19
+ # Defining options can be done by calling the class method option() or it's
20
+ # alias o():
21
+ #
22
+ # class MyCommand < Shebang::Command
23
+ # command 'my-command'
24
+ #
25
+ # o :h, :help, 'Shows this help message', :method => :help
26
+ #
27
+ # def index
28
+ #
29
+ # end
30
+ # end
31
+ #
32
+ # If you're going to define a help option, and you most likely will, you don't
33
+ # have to manually add a method that shows the message as the Command class
34
+ # already comes with an instance method for this, simply called help().
35
+ #
36
+ # For more information on options see Shebang::Option#initialize().
37
+ #
38
+ # @author Yorick Peterse
39
+ # @since 0.1
40
+ #
41
+ class Command
42
+ # Several methods that become available as class methods once
43
+ # Shebang::Command is extended by another class.
44
+ module ClassMethods
45
+ ##
46
+ # Binds a class to the specified command name.
47
+ #
48
+ # @author Yorick Peterse
49
+ # @since 0.1
50
+ # @param [#to_sym] name The name of the command.
51
+ # @param [Hash] options Hash containing various options for the command.
52
+ # @option options :parent The name of the parent command.
53
+ #
54
+ def command(name, options = {})
55
+ name = name.to_sym
56
+
57
+ if Shebang::Commands.key?(name)
58
+ Shebang.error("The command #{name} has already been registered")
59
+ end
60
+
61
+ Shebang::Commands[name] = self
62
+ end
63
+
64
+ ##
65
+ # Sets the banner for the command, trailing or leading newlines will
66
+ # be removed.
67
+ #
68
+ # @author Yorick Peterse
69
+ # @since 0.1
70
+ # @param [String] text The content of the banner.
71
+ #
72
+ def banner(text)
73
+ @__banner = text.strip
74
+ end
75
+
76
+ ##
77
+ # A small shortcut for defining the syntax of a command. This method is
78
+ # just a shortcut for the following:
79
+ #
80
+ # help('Usage', 'foobar [OPTIONS]'
81
+ #
82
+ # @author Yorick Peterse
83
+ # @since 0.1
84
+ # @param [String] text The content of the usage block.
85
+ #
86
+ def usage(text)
87
+ help('Usage', text)
88
+ end
89
+
90
+ ##
91
+ # Sets a general "help topic" with a custom title and content.
92
+ #
93
+ # @example
94
+ # help('License', 'MIT License')
95
+ #
96
+ # @author Yorick Peterse
97
+ # @since 0.1
98
+ # @param [String] title The title of the topic.
99
+ # @param [String] text The content of the topic.
100
+ #
101
+ def help(title, text)
102
+ @__help_topics ||= {}
103
+ @__help_topics[title] = text.strip
104
+ end
105
+
106
+ ##
107
+ # Creates a new option for a command.
108
+ #
109
+ # @example
110
+ # o :h, :help, 'Shows this help message', :method => :help
111
+ # o :l, :list, 'A list of numbers' , :type => Array
112
+ #
113
+ # @author Yorick Peterse
114
+ # @since 0.1
115
+ # @see Shebang::Option#initialize
116
+ #
117
+ def option(short, long, desc = nil, options = {})
118
+ @__options ||= []
119
+ option = Shebang::Option.new(short, long, desc, options)
120
+
121
+ @__options.push(option)
122
+ end
123
+ alias :o :option
124
+ end # ClassMethods
125
+
126
+ ##
127
+ # Modifies the class that inherits this class so that the module
128
+ # Shebang::Comand::ClassMethods extends the class.
129
+ #
130
+ # @author Yorick Peterse
131
+ # @since 09-08-2011
132
+ # @param [Class] by The class that inherits from Shebang::Command.
133
+ #
134
+ def self.inherited(by)
135
+ by.extend(Shebang::Command::ClassMethods)
136
+ end
137
+
138
+ ##
139
+ # Creates a new instance of the command and sets up OptionParser.
140
+ #
141
+ # @author Yorick Peterse
142
+ # @since 0.1
143
+ #
144
+ def initialize
145
+ @option_parser = OptionParser.new do |opt|
146
+ opt.banner = banner
147
+ opt.summary_indent = Shebang::Config[:indent]
148
+
149
+ # Process each help topic
150
+ help_topics.each do |title, text|
151
+ opt.separator "#{Shebang::Config[:heading]}#{
152
+ Shebang::Config[:indent]}#{text}" % title
153
+ end
154
+
155
+ opt.separator "#{Shebang::Config[:heading]}" % 'Options'
156
+
157
+ # Add all the options
158
+ options.each do |option|
159
+ opt.on(*option.option_parser) do |value|
160
+ option.value = value
161
+
162
+ # Run a method?
163
+ if !option.options[:method].nil? \
164
+ and respond_to?(option.options[:method])
165
+ # Pass the value to the method?
166
+ if self.class.instance_method(option.options[:method]).arity != 0
167
+ send(option.options[:method], value)
168
+ else
169
+ send(option.options[:method])
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ ##
178
+ # Parses the command line arguments using OptionParser.
179
+ #
180
+ # @author Yorick Peterse
181
+ # @since 0.1
182
+ # @param [Array] argv Array containing the command line arguments to parse.
183
+ # @return [Array] argv Array containing all the command line arguments after
184
+ # it has been processed.
185
+ #
186
+ def parse(argv = [])
187
+ @option_parser.parse!(argv)
188
+
189
+ options.each do |option|
190
+ if option.required? and !option.has_value?
191
+ Shebang.error("The -#{option.short} option is required")
192
+ end
193
+ end
194
+
195
+ return argv
196
+ end
197
+
198
+ ##
199
+ # Returns the banner of the current class.
200
+ #
201
+ # @author Yorick Peterse
202
+ # @since 0.1
203
+ # @return [String]
204
+ #
205
+ def banner
206
+ self.class.instance_variable_get(:@__banner)
207
+ end
208
+
209
+ ##
210
+ # Returns all help topics for the current class.
211
+ #
212
+ # @author Yorick Peterse
213
+ # @since 0.1
214
+ # @return [Hash]
215
+ #
216
+ def help_topics
217
+ self.class.instance_variable_get(:@__help_topics) || {}
218
+ end
219
+
220
+ ##
221
+ # Returns an array of all the options for the current class.
222
+ #
223
+ # @author Yorick Peterse
224
+ # @since 0.1
225
+ # @return [Array]
226
+ #
227
+ def options
228
+ self.class.instance_variable_get(:@__options) || []
229
+ end
230
+
231
+ ##
232
+ # Method that is called whenever a command has to be executed.
233
+ #
234
+ # @author Yorick Peterse
235
+ # @since 0.1
236
+ #
237
+ def index
238
+ raise(NotImplementedError, "You need to define your own index() method")
239
+ end
240
+
241
+ ##
242
+ # Returns the value of a given option. The option can be specified using
243
+ # either the short or long name.
244
+ #
245
+ # @example
246
+ # puts "Hello #{option(:name)}
247
+ #
248
+ # @author Yorick Peterse
249
+ # @since 0.1
250
+ # @param [#to_sym] opt The name of the option.
251
+ # @return [Mixed]
252
+ #
253
+ def option(opt)
254
+ opt = opt.to_sym
255
+
256
+ options.each do |op|
257
+ if op.short === opt or op.long === opt
258
+ return op.value
259
+ end
260
+ end
261
+ end
262
+
263
+ ##
264
+ # Shows the help message for the current class.
265
+ #
266
+ # @author Yorick Peterse
267
+ # @since 0.1
268
+ #
269
+ def help
270
+ puts @option_parser
271
+ exit
272
+ end
273
+ end # Command
274
+ end # Shebang
@@ -0,0 +1,95 @@
1
+ module Shebang
2
+ ##
3
+ # Class that represents a single option that's passed to OptionParser.
4
+ #
5
+ # @author Yorick Peterse
6
+ # @since 0.1
7
+ #
8
+ class Option
9
+ attr_reader :short, :long, :description, :options
10
+ attr_accessor :value
11
+
12
+ ##
13
+ # Creates a new instance of the Option class.
14
+ #
15
+ # @author Yorick Peterse
16
+ # @since 0.1
17
+ # @param [#to_sym] short The short option name such as :h.
18
+ # @param [#to_sym] long The long option name such as :help.
19
+ # @param [String] desc The description of the option.
20
+ # @param [Hash] options Hash containing various configuration options for
21
+ # the OptionParser option.
22
+ # @option options :type The type of value for the option, set to TrueClass
23
+ # by default.
24
+ # @option options :key The key to use to indicate a value whenever the type
25
+ # of an option is something else than TrueClass or FalseClass. This option
26
+ # is set to "VALUE" by default.
27
+ # @option options :method A symbol that refers to a method that should be
28
+ # called whenever the option is specified.
29
+ # @option options :required Indicates that the option has to be specified.
30
+ # @option options :default The default value of the option.
31
+ #
32
+ def initialize(short, long, desc = nil, options = {})
33
+ @short, @long = short.to_sym, long.to_sym
34
+ @description = desc
35
+ @options = {
36
+ :type => TrueClass,
37
+ :key => 'VALUE',
38
+ :method => nil,
39
+ :required => false,
40
+ :default => nil
41
+ }.merge(options)
42
+
43
+ @value = @options[:default]
44
+ end
45
+
46
+ ##
47
+ # Builds an array containing all the required parameters for
48
+ # OptionParser#on().
49
+ #
50
+ # @author Yorick Peterse
51
+ # @since 0.1
52
+ # @return [Array]
53
+ #
54
+ def option_parser
55
+ params = ["-#{@short}", "--#{@long}", nil, @options[:type]]
56
+
57
+ if !@description.nil? and !@description.empty?
58
+ params[2] = @description
59
+ end
60
+
61
+ # Set the correct format for the long/short option based on the type.
62
+ if ![TrueClass, FalseClass].include?(@options[:type])
63
+ params[1] += " #{@options[:key]}"
64
+ end
65
+
66
+ return params
67
+ end
68
+
69
+ ##
70
+ # Checks if the value of an option is not nil and not empty.
71
+ #
72
+ # @author Yorick Peterse
73
+ # @since 0.1
74
+ # @return [TrueClass|FalseClass]
75
+ #
76
+ def has_value?
77
+ if !@value.nil? and !@value.empty?
78
+ return true
79
+ else
80
+ return false
81
+ end
82
+ end
83
+
84
+ ##
85
+ # Indicates whether or not the option requires a value.
86
+ #
87
+ # @author Yorick Peterse
88
+ # @since 0.1
89
+ # @return [TrueClass|FalseClass]
90
+ #
91
+ def required?
92
+ return @options[:required]
93
+ end
94
+ end # Option
95
+ end # Shebang
@@ -0,0 +1,39 @@
1
+ #:nodoc:
2
+ module Bacon
3
+ #:nodoc:
4
+ module ColorOutput
5
+ #:nodoc:
6
+ def handle_specification(name)
7
+ puts spaces + name
8
+ yield
9
+ puts if Counter[:context_depth] == 1
10
+ end
11
+
12
+ #:nodoc:
13
+ def handle_requirement(description)
14
+ error = yield
15
+
16
+ if !error.empty?
17
+ puts "#{spaces} \e[31m- #{description} [FAILED]\e[0m"
18
+ else
19
+ puts "#{spaces} \e[32m- #{description}\e[0m"
20
+ end
21
+ end
22
+
23
+ #:nodoc:
24
+ def handle_summary
25
+ print ErrorLog if Backtraces
26
+ puts "%d specifications (%d requirements), %d failures, %d errors" %
27
+ Counter.values_at(:specifications, :requirements, :failed, :errors)
28
+ end
29
+
30
+ #:nodoc:
31
+ def spaces
32
+ if Counter[:context_depth] === 0
33
+ Counter[:context_depth] = 1
34
+ end
35
+
36
+ return ' ' * (Counter[:context_depth] - 1)
37
+ end
38
+ end # ColorOutput
39
+ end # Bacon
@@ -0,0 +1,65 @@
1
+ require 'bacon'
2
+ require 'stringio'
3
+ require File.expand_path('../bacon/color_output', __FILE__)
4
+
5
+ Bacon.extend(Bacon::ColorOutput)
6
+ Bacon.summary_on_exit
7
+
8
+ ##
9
+ # Runs the block in a new thread and redirects $stdout and $stderr. The output
10
+ # normally stored in these variables is stored in an instance of StringIO which
11
+ # is returned as a hash.
12
+ #
13
+ # @example
14
+ # out = catch_output do
15
+ # puts 'hello'
16
+ # end
17
+ #
18
+ # puts out # => {:stdout => "hello\n", :stderr => ""}
19
+ #
20
+ # @author Yorick Peterse
21
+ # @return [Hash]
22
+ #
23
+ def catch_output
24
+ data = {
25
+ :stdout => nil,
26
+ :stderr => nil
27
+ }
28
+
29
+ Thread.new do
30
+ $stdout, $stderr = StringIO.new, StringIO.new
31
+
32
+ yield
33
+
34
+ $stdout.rewind
35
+ $stderr.rewind
36
+
37
+ data[:stdout], data[:stderr] = $stdout.read, $stderr.read
38
+
39
+ $stdout, $stderr = STDOUT, STDERR
40
+ end.join
41
+
42
+ return data
43
+ end
44
+
45
+ ##
46
+ # Allows developers to create stubbed objects similar to Mocha's stub() method.
47
+ #
48
+ # @example
49
+ # obj = stub(:language => 'Ruby')
50
+ # puts obj.language # => "Ruby"
51
+ #
52
+ # @author Yorick Peterse
53
+ # @param [Hash] attributes A hash containing all the attributes to set and
54
+ # their values.
55
+ # @return [Class]
56
+ #
57
+ def stub(attributes)
58
+ obj = Struct.new(*attributes.keys).new
59
+
60
+ attributes.each do |k, v|
61
+ obj.send("#{k}=", v)
62
+ end
63
+
64
+ return obj
65
+ end
@@ -0,0 +1,4 @@
1
+ module Shebang
2
+ #:nodoc:
3
+ Version = '0.1'
4
+ end
File without changes
@@ -0,0 +1,21 @@
1
+ require File.expand_path('../lib/shebang/version', __FILE__)
2
+
3
+ path = File.expand_path('../', __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'shebang'
7
+ s.version = Shebang::Version
8
+ s.date = '09-08-2011'
9
+ s.authors = ['Yorick Peterse']
10
+ s.email = 'yorickpeterse@gmail.com'
11
+ s.summary = 'Shebang is a nice wrapper around OptionParser that makes it
12
+ easier to write commandline executables.'
13
+ s.homepage = 'https://github.com/yorickpeterse/shebang'
14
+ s.description = s.summary
15
+ s.files = `cd #{path}; git ls-files`.split("\n").sort
16
+ s.has_rdoc = 'yard'
17
+
18
+ s.add_development_dependency('rake' , ['~> 0.9.2'])
19
+ s.add_development_dependency('yard' , ['~> 0.7.2'])
20
+ s.add_development_dependency('bacon', ['~> 1.1.0'])
21
+ end
File without changes
@@ -0,0 +1,21 @@
1
+ class SpecCommand < Shebang::Command
2
+ command :default
3
+ banner 'The default command.'
4
+ usage 'shebang.rb [COMMAND] [OPTIONS]'
5
+
6
+ o :v, :version, 'Shows the current version', :method => :version
7
+
8
+ def index
9
+ puts 'index method'
10
+ end
11
+
12
+ def test
13
+ puts 'test method'
14
+ end
15
+
16
+ protected
17
+
18
+ def version
19
+ puts '0.1'
20
+ end
21
+ end # SpecCommand
@@ -0,0 +1,2 @@
1
+ require File.expand_path('../../lib/shebang', __FILE__)
2
+ require File.expand_path('../../lib/shebang/spec/helper', __FILE__)
@@ -0,0 +1,39 @@
1
+ require File.expand_path('../../helper', __FILE__)
2
+ require File.expand_path('../../fixtures/command', __FILE__)
3
+
4
+ describe('Shebang::Command') do
5
+ it('The name should be registered') do
6
+ Shebang::Commands[:default].should == SpecCommand
7
+ end
8
+
9
+ it('The banner should be set') do
10
+ Shebang::Commands[:default].instance_variable_get(:@__banner).should \
11
+ === 'The default command.'
12
+
13
+ Shebang::Commands[:default].new.banner.should === 'The default command.'
14
+ end
15
+
16
+ it('A help topic should be set') do
17
+ Shebang::Commands[:default].instance_variable_get(
18
+ :@__help_topics
19
+ )['Usage'].should === 'shebang.rb [COMMAND] [OPTIONS]'
20
+
21
+ Shebang::Commands[:default].new.help_topics['Usage'].should \
22
+ === 'shebang.rb [COMMAND] [OPTIONS]'
23
+ end
24
+
25
+ it('An option should be set') do
26
+ option = Shebang::Commands[:default].instance_variable_get(:@__options)[0]
27
+
28
+ option.short.should === :v
29
+ option.long.should === :version
30
+ option.description.should === 'Shows the current version'
31
+ option.options[:method].should === :version
32
+ option.value = '0.1'
33
+
34
+ Shebang::Commands[:default].new.options[0].short.should === option.short
35
+
36
+ Shebang::Commands[:default].new.option(:v).should === option.value
37
+ Shebang::Commands[:default].new.option(:version).should === option.value
38
+ end
39
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path('../../helper', __FILE__)
2
+
3
+ describe('Shebang::Option') do
4
+ it('Create a new option') do
5
+ option = Shebang::Option.new(:h, :help, 'help message', :method => :test)
6
+
7
+ option.short.should === :h
8
+ option.long.should === :help
9
+ option.description.should === 'help message'
10
+
11
+ option.options[:method].should === :test
12
+ option.options[:type].should == TrueClass
13
+
14
+ option.required?.should === false
15
+ option.has_value?.should === false
16
+ end
17
+
18
+ it('Convert to OptionParser arguments') do
19
+ option = Shebang::Option.new(:h, :help, 'help message', :method => :test)
20
+
21
+ option.option_parser.should === ['-h', '--help', 'help message', TrueClass]
22
+ end
23
+ end
@@ -0,0 +1,66 @@
1
+ require File.expand_path('../../helper', __FILE__)
2
+ require File.expand_path('../../fixtures/command', __FILE__)
3
+
4
+ module Kernel
5
+ def abort(*args)
6
+ $stderr.puts(*args)
7
+ end
8
+
9
+ def exit(*args); end
10
+ end
11
+
12
+ describe('Shebang') do
13
+ it('Raise an error message') do
14
+ should.raise?(Shebang::Error) do
15
+ Shebang.error('test')
16
+ end
17
+ end
18
+
19
+ it('Display an error message') do
20
+ Shebang::Config[:raise] = false
21
+
22
+ output = catch_output do
23
+ Shebang.error('test')
24
+ end
25
+
26
+ output[:stderr].include?('test').should === true
27
+ end
28
+
29
+ it('Invoke the default command') do
30
+ [[], ['default'], ['default', 'index']].each do |argv|
31
+ output = catch_output do
32
+ Shebang.run(argv)
33
+ end
34
+
35
+ output[:stdout].strip.should === 'index method'
36
+ end
37
+ end
38
+
39
+ it('Invoke the default command with an alternative method') do
40
+ [['test'], ['default', 'test']].each do |argv|
41
+ output = catch_output do
42
+ Shebang.run(argv)
43
+ end
44
+
45
+ output[:stdout].strip.should === 'test method'
46
+ end
47
+ end
48
+
49
+ it('Show a help message') do
50
+ output = catch_output do
51
+ Shebang.run(['--help'])
52
+ end
53
+
54
+ output[:stdout].include?('The default command').should === true
55
+ output[:stdout].include?('shebang.rb [COMMAND] [OPTIONS]').should === true
56
+ output[:stdout].include?('Options').should === true
57
+ end
58
+
59
+ it('Shows the current version') do
60
+ output = catch_output do
61
+ Shebang.run(['--version'])
62
+ end
63
+
64
+ output[:stdout].include?('0.1').should === true
65
+ end
66
+ end # describe
@@ -0,0 +1,33 @@
1
+ # Task group used for building various elements such as the Gem and the
2
+ # documentation.
3
+ namespace :build do
4
+ desc 'Builds the documentation using YARD'
5
+ task :doc do
6
+ gem_path = File.expand_path('../../', __FILE__)
7
+ command = "yard doc #{gem_path}/lib -m markdown -M rdiscount -o #{gem_path}/doc "
8
+ command += "-r #{gem_path}/README.md --private --protected"
9
+
10
+ sh(command)
11
+ end
12
+
13
+ desc 'Builds a new Gem'
14
+ task :gem do
15
+ gem_path = File.expand_path('../../', __FILE__)
16
+ gemspec_path = File.join(
17
+ gem_path,
18
+ "#{Shebang::Gemspec.name}-#{Shebang::Gemspec.version.version}.gem"
19
+ )
20
+
21
+ pkg_path = File.join(
22
+ gem_path,
23
+ 'pkg',
24
+ "#{Shebang::Gemspec.name}-#{Shebang::Gemspec.version.version}.gem"
25
+ )
26
+
27
+ # Build and install the gem
28
+ sh('gem', 'build' , File.join(gem_path, 'shebang.gemspec'))
29
+ sh('mv' , gemspec_path, pkg_path)
30
+ sh('gem', 'install' , pkg_path)
31
+ end
32
+ end # namespace :build
33
+
@@ -0,0 +1,6 @@
1
+ desc 'Runs all the tests'
2
+ task :test do
3
+ Dir.glob(File.expand_path('../../spec/shebang/*.rb', __FILE__)).each do |f|
4
+ require(f)
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: shebang
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: "0.1"
6
+ platform: ruby
7
+ authors:
8
+ - Yorick Peterse
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-08-09 00:00:00 +02:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rake
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 0.9.2
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: yard
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 0.7.2
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: bacon
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.1.0
47
+ type: :development
48
+ version_requirements: *id003
49
+ description: Shebang is a nice wrapper around OptionParser that makes it easier to write commandline executables.
50
+ email: yorickpeterse@gmail.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - .gems
59
+ - .gitignore
60
+ - .rvmrc
61
+ - .travis.yml
62
+ - LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - example/basic.rb
66
+ - lib/.gitkeep
67
+ - lib/shebang.rb
68
+ - lib/shebang/.gitkeep
69
+ - lib/shebang/command.rb
70
+ - lib/shebang/option.rb
71
+ - lib/shebang/spec/bacon/color_output.rb
72
+ - lib/shebang/spec/helper.rb
73
+ - lib/shebang/version.rb
74
+ - pkg/.gitkeep
75
+ - shebang.gemspec
76
+ - spec/.gitkeep
77
+ - spec/fixtures/command.rb
78
+ - spec/helper.rb
79
+ - spec/shebang/command.rb
80
+ - spec/shebang/option.rb
81
+ - spec/shebang/shebang.rb
82
+ - task/build.rake
83
+ - task/test.rake
84
+ has_rdoc: yard
85
+ homepage: https://github.com/yorickpeterse/shebang
86
+ licenses: []
87
+
88
+ post_install_message:
89
+ rdoc_options: []
90
+
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: "0"
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: "0"
105
+ requirements: []
106
+
107
+ rubyforge_project:
108
+ rubygems_version: 1.6.2
109
+ signing_key:
110
+ specification_version: 3
111
+ summary: Shebang is a nice wrapper around OptionParser that makes it easier to write commandline executables.
112
+ test_files: []
113
+