git-style-binaries 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,280 @@
1
+ git-style-binaries
2
+ ==================
3
+
4
+ Ridiculously easy git-style binaries.
5
+
6
+ This gem uses [`trollop`](http://trollop.rubyforge.org/) for option parsing
7
+
8
+ ## Installation
9
+
10
+ gem install jashmenn-git-style-binaries --source=http://gems.github.com
11
+
12
+ ## Screencast
13
+
14
+ Checkout <a href="http://www.xcombinator.com/movies/git-style-binaries.mov">the new screencast!</a>
15
+
16
+ <a href="http://www.xcombinator.com/movies/git-style-binaries.mov"><img src="http://github.com/jashmenn/git-style-binaries/tree/master/doc/gsb-screencast.png?raw=true" width='880' height='784' border=0></a>
17
+
18
+ ## Try it out
19
+
20
+ cd `gem env gemdir`/gems/jashmenn-git-style-binaries-0.1.4/test/fixtures
21
+ ./wordpress -h
22
+ ./wordpress help post
23
+
24
+ ## Goal
25
+
26
+ Lets use the imaginary `wordpress` gem. Let's say we have three different
27
+ actions we want to specify:
28
+
29
+ * categories
30
+ * list
31
+ * post
32
+
33
+ Each command has its own binary in a directory structure like this:
34
+
35
+ bin/
36
+ |-- wordpress
37
+ |-- wordpress-categories
38
+ |-- wordpress-list
39
+ `-- wordpress-post
40
+
41
+ The goal is to be able to call commands in this manner:
42
+
43
+ wordpress -h # gives help summary of all commands
44
+ wordpress-list -h # gives long help of wordpress-list
45
+ wordpress list -h # ditto
46
+ echo "about me" | wordpress-post --title="new post" # posts a new post with that title
47
+
48
+ ## Example code
49
+ Our `bin/wordpress` binary is called the *primary* . Our primary only needs to contain the following line:
50
+
51
+ #!/usr/bin/env ruby
52
+ require 'git-style-binary/command'
53
+
54
+ `git-style-binary` will automatically make this command the primary.
55
+
56
+ The `bin/wordpress-post` binary could contain the following:
57
+
58
+ #!/usr/bin/env ruby
59
+ require 'git-style-binary/command'
60
+
61
+ GitStyleBinary.command do
62
+ short_desc "create a blog post"
63
+ banner <<-EOS
64
+ Usage: #{command.full_name} #{all_options_string} {content|STDIN}
65
+
66
+ Posts content to a wordpress blog
67
+
68
+ EOS
69
+ opt :blog, "short name of the blog to use", :default => 'default'
70
+ opt :category, "tag/category. specify multiple times for multiple categories", :type => String, :multi => true
71
+ opt :title, "title for the post", :required => true, :type => String
72
+ opt :type, "type of the content [html|xhtml|text]", :default => 'html', :type => String
73
+
74
+ run do |command|
75
+ command.die :type, "type must be one of [html|xhtml|text]" unless command.opts[:type] =~ /^(x?html|text)$/i
76
+
77
+ puts "Subcommand name: #{command.name.inspect}"
78
+ puts "Options: #{command.opts.inspect}"
79
+ puts "Remaining arguments: #{command.argv.inspect}"
80
+ end
81
+ end
82
+
83
+ And so on with the other binaries.
84
+
85
+ ## Running the binaries
86
+
87
+ Now if we run `wordpress -h` we get the following output:
88
+
89
+ NAME
90
+ wordpress
91
+
92
+ VERSION
93
+ 0.0.1 (c) 2009 Nate Murray - local
94
+
95
+ SYNOPSIS
96
+ wordpress [--version] [--test-primary] [--help] [--verbose] COMMAND [ARGS]
97
+
98
+ SUBCOMMANDS
99
+ wordpress-categories
100
+ do something with categories
101
+
102
+ wordpress-help
103
+ get help for a specific command
104
+
105
+ wordpress-list
106
+ list blog postings
107
+
108
+ wordpress-post
109
+ create a blog post
110
+
111
+
112
+ See 'wordpress help COMMAND' for more information on a specific command.
113
+
114
+ OPTIONS
115
+ -v, --verbose
116
+ verbose
117
+
118
+
119
+ -t, --test-primary=<s>
120
+ test an option on the primary
121
+
122
+
123
+ -e, --version
124
+ Print version and exit
125
+
126
+
127
+ -h, --help
128
+ Show this message
129
+
130
+
131
+
132
+ Default **options**, **version string**, and **usage banner** are automatically selected for you.
133
+ The subcommands and their short descriptions are loaded automatically!
134
+
135
+ You can pass the `-h` flag to any one of the subcommands (with or without the
136
+ connecting `-`) or use the built-in `help` subcommand for the same effect. For instance:
137
+
138
+ $ wordpress help post
139
+
140
+ NAME
141
+ wordpress-post - create a blog post
142
+
143
+ VERSION
144
+ 0.0.1 (c) 2009 Nate Murray - local
145
+
146
+ SYNOPSIS
147
+ wordpress-post [--type] [--version] [--test-primary] [--blog] [--help] [--verbose] [--category]
148
+ [--title] COMMAND [ARGS] {content|STDIN}
149
+
150
+ OPTIONS
151
+ -v, --verbose
152
+ verbose
153
+
154
+
155
+ -t, --test-primary=<s>
156
+ test an option on the primary
157
+
158
+
159
+ -b, --blog=<s>
160
+ short name of the blog to use (default: default)
161
+
162
+
163
+ -c, --category=<s>
164
+ tag/category. specify multiple times for multiple
165
+ categories
166
+
167
+
168
+ -i, --title=<s>
169
+ title for the post
170
+
171
+
172
+ -y, --type=<s>
173
+ type of the content [html|xhtml|text] (default: html)
174
+
175
+
176
+ -e, --version
177
+ Print version and exit
178
+
179
+
180
+ -h, --help
181
+ Show this message
182
+
183
+
184
+ For more examples, see the binaries in `test/fixtures/`.
185
+
186
+ ## Primary options
187
+
188
+ Often you may *want* the primary to have its own set of options. Simply call `GitStyleBinary.primary` with a block like so:
189
+
190
+ #!/usr/bin/env ruby
191
+ require 'git-style-binary/command'
192
+ GitStyleBinary.primary do
193
+ version "#{command.full_name} 0.0.1 (c) 2009 Nate Murray - local"
194
+ opt :test_primary, "a primary string option", :type => String
195
+
196
+ run do |command|
197
+ puts "Primary Options: #{command.opts.inspect}"
198
+ end
199
+ end
200
+
201
+ Primary options are **inherited** by all subcommands. That means in this case
202
+ all subcommands will now get the `--test-primary` option available to them as
203
+ well as this new `version` string.
204
+
205
+ ## Option parsing
206
+
207
+ Option parsing is done by [trollop](http://trollop.rubyforge.org/).
208
+ `git-style-binary` uses this more-or-less exactly. See the [trollop
209
+ documentation](http://trollop.rubyforge.org/) for information on how to setup
210
+ the options and flags.
211
+
212
+ ## Callbacks
213
+
214
+ Callbacks are available on the primary and subcommands. Available callbacks currently
215
+ are before/after_run. These execute before the run block of the command parser and take
216
+ take one argument, which is the command itself
217
+
218
+ ## The `run` block
219
+
220
+ To get the 'introspection' on the individual binaries every binary is `load`ed
221
+ on `primary help`. We need a way to get that information while not running
222
+ every command when calling `primary help`. To achieve that you need to put what
223
+ will be run in the `run` block.
224
+
225
+ `run` `yields` a `Command` object which contains a number of useful options
226
+ such as `name`, `full_name`, `opts`, and `argv`.
227
+
228
+ * `command.opts` is a hash of the options parsed
229
+ * `command.argv` is an array of the remaining arguments
230
+
231
+ ## Features
232
+ * automatic colorization
233
+ * automatic paging
234
+
235
+ ## To Learn more
236
+
237
+ Play with the examples in the `test/fixtures` directory.
238
+
239
+ ## Credits
240
+ * `git-style-binary` was written by Nate Murray `<nate@natemurray.com>`
241
+ * `trollop` was written by [William Morgan](http://trollop.rubyforge.org/)
242
+ * Inspiration comes from Ari Lerner's [git-style-binaries](http://blog.xnot.org/2008/12/16/git-style-binaries/) for [PoolParty.rb](http://poolpartyrb.com)
243
+ * [`colorize.rb`](http://colorize.rubyforge.org) by Michal Kalbarczyk
244
+ * Automatic less paging by [Nathan Weizenbaum](http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby)
245
+ * Color inspiration from [Brian Henderson](http://xcombinator.com) teaching me how to get `man git` colors using `less` on MacOSX
246
+
247
+ ## TODO
248
+ * automagic tab completion - Automatic for subcommands and options for any library that uses this
249
+
250
+ ## Known Bugs/Problems
251
+ * Young
252
+ * A few places of really ugly code
253
+ * A feeling that this could be done in 1/2 lines of code
254
+
255
+ ## Authors
256
+ By Nate Murray and Ari Lerner
257
+
258
+ ## Copyright
259
+
260
+ The MIT License
261
+
262
+ Copyright (c) 2009 Nate Murray. See LICENSE for details.
263
+
264
+ Permission is hereby granted, free of charge, to any person obtaining a copy
265
+ of this software and associated documentation files (the "Software"), to deal
266
+ in the Software without restriction, including without limitation the rights
267
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
268
+ copies of the Software, and to permit persons to whom the Software is
269
+ furnished to do so, subject to the following conditions:
270
+
271
+ The above copyright notice and this permission notice shall be included in
272
+ all copies or substantial portions of the Software.
273
+
274
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
275
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
276
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
277
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
278
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
279
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
280
+ THE SOFTWARE.
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gemspec|
7
+ gemspec.name = "git-style-binaries"
8
+ gemspec.description = %Q{Ridiculously easy git-style binaries}
9
+ gemspec.summary =<<-EOF
10
+ Add git-style binaries to your project easily.
11
+ EOF
12
+ gemspec.email = "nate@natemurray.com"
13
+ gemspec.homepage = "http://github.com/jashmenn/git-style-binaries"
14
+ gemspec.authors = ["Nate Murray"]
15
+ gemspec.add_dependency 'trollop'
16
+ gemspec.add_dependency 'shoulda' # for running the tests
17
+
18
+ excludes = /(README\.html)/
19
+ gemspec.files = (FileList["[A-Z]*.*", "{bin,examples,generators,lib,rails,spec,test,vendor}/**/*", 'Rakefile', 'LICENSE*']).delete_if{|f| f =~ excludes}
20
+ gemspec.extra_rdoc_files = FileList["README*", "ChangeLog*", "LICENSE*"].delete_if{|f| f =~ excludes}
21
+ end
22
+ rescue LoadError
23
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
24
+ end
25
+
26
+ require 'rake/testtask'
27
+ Rake::TestTask.new(:test) do |test|
28
+ test.libs << 'lib' << 'test'
29
+ test.pattern = 'test/**/*_test.rb'
30
+ test.verbose = true
31
+ end
32
+
33
+ begin
34
+ require 'rcov/rcovtask'
35
+ Rcov::RcovTask.new do |test|
36
+ test.libs << 'test'
37
+ test.pattern = 'test/**/*_test.rb'
38
+ test.verbose = true
39
+ end
40
+ rescue LoadError
41
+ task :rcov do
42
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
43
+ end
44
+ end
45
+
46
+
47
+ task :default => :test
48
+
49
+ require 'rake/rdoctask'
50
+ Rake::RDocTask.new do |rdoc|
51
+ if File.exist?('VERSION.yml')
52
+ config = YAML.load(File.read('VERSION.yml'))
53
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
54
+ else
55
+ version = ""
56
+ end
57
+
58
+ rdoc.rdoc_dir = 'rdoc'
59
+ rdoc.title = "git-style-binaries #{version}"
60
+ rdoc.rdoc_files.include('README*')
61
+ rdoc.rdoc_files.include('lib/**/*.rb')
62
+ end
63
+
64
+ task :bump => ['version:bump:patch', 'gemspec', 'build']
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 10
3
+ :major: 0
4
+ :minor: 1
@@ -0,0 +1,198 @@
1
+ #
2
+ # Colorize String class extension.
3
+ #
4
+ class String
5
+
6
+ #
7
+ # Version string
8
+ #
9
+ COLORIZE_VERSION = '0.5.6'
10
+
11
+ #
12
+ # Colors Hash
13
+ #
14
+ COLORS = {
15
+ :black => 0,
16
+ :red => 1,
17
+ :green => 2,
18
+ :yellow => 3,
19
+ :blue => 4,
20
+ :magenta => 5,
21
+ :cyan => 6,
22
+ :white => 7,
23
+ :default => 9,
24
+
25
+ :light_black => 10,
26
+ :light_red => 11,
27
+ :light_green => 12,
28
+ :light_yellow => 13,
29
+ :light_blue => 14,
30
+ :light_magenta => 15,
31
+ :light_cyan => 16,
32
+ :light_white => 17
33
+ }
34
+
35
+ #
36
+ # Modes Hash
37
+ #
38
+ MODES = {
39
+ :default => 0, # Turn off all attributes
40
+ #:bright => 1, # Set bright mode
41
+ :underline => 4, # Set underline mode
42
+ :blink => 5, # Set blink mode
43
+ :swap => 7, # Exchange foreground and background colors
44
+ :hide => 8 # Hide text (foreground color would be the same as background)
45
+ }
46
+
47
+ protected
48
+
49
+ #
50
+ # Set color values in new string intance
51
+ #
52
+ def set_color_parameters( params )
53
+ if (params.instance_of?(Hash))
54
+ @color = params[:color]
55
+ @background = params[:background]
56
+ @mode = params[:mode]
57
+ @uncolorized = params[:uncolorized]
58
+ self
59
+ else
60
+ nil
61
+ end
62
+ end
63
+
64
+ public
65
+
66
+ #
67
+ # Change color of string
68
+ #
69
+ # Examples:
70
+ #
71
+ # puts "This is blue".colorize( :blue )
72
+ # puts "This is light blue".colorize( :light_blue )
73
+ # puts "This is also blue".colorize( :color => :blue )
74
+ # puts "This is blue with red background".colorize( :color => :light_blue, :background => :red )
75
+ # puts "This is blue with red background".colorize( :light_blue ).colorize( :background => :red )
76
+ # puts "This is blue text on red".blue.on_red
77
+ # puts "This is red on blue".colorize( :red ).on_blue
78
+ # puts "This is red on blue and underline".colorize( :red ).on_blue.underline
79
+ # puts "This is blue text on red".blue.on_red.blink
80
+ #
81
+ def colorize( params )
82
+
83
+ unless STDOUT.use_color
84
+ return self unless STDOUT.isatty
85
+ end
86
+ return self if ENV['NO_COLOR']
87
+
88
+ begin
89
+ require 'Win32/Console/ANSI' if PLATFORM =~ /win32/
90
+ rescue LoadError
91
+ raise 'You must gem install win32console to use color on Windows'
92
+ end
93
+
94
+ color_parameters = {}
95
+
96
+ if (params.instance_of?(Hash))
97
+ color_parameters[:color] = COLORS[params[:color]]
98
+ color_parameters[:background] = COLORS[params[:background]]
99
+ color_parameters[:mode] = MODES[params[:mode]]
100
+ elsif (params.instance_of?(Symbol))
101
+ color_parameters[:color] = COLORS[params]
102
+ end
103
+
104
+ color_parameters[:color] ||= @color || 9
105
+ color_parameters[:background] ||= @background || 9
106
+ color_parameters[:mode] ||= @mode || 0
107
+
108
+ color_parameters[:uncolorized] ||= @uncolorized || self.dup
109
+
110
+ # calculate bright mode
111
+ color_parameters[:color] += 50 if color_parameters[:color] > 10
112
+
113
+ color_parameters[:background] += 50 if color_parameters[:background] > 10
114
+
115
+ return "\033[#{color_parameters[:mode]};#{color_parameters[:color]+30};#{color_parameters[:background]+40}m#{color_parameters[:uncolorized]}\033[0m".set_color_parameters( color_parameters )
116
+ end
117
+
118
+
119
+ #
120
+ # Return uncolorized string
121
+ #
122
+ def uncolorize
123
+ return @uncolorized || self
124
+ end
125
+
126
+ #
127
+ # Return true if sting is colorized
128
+ #
129
+ def colorized?
130
+ return !@uncolorized.nil?
131
+ end
132
+
133
+ #
134
+ # Make some color and on_color methods
135
+ #
136
+ COLORS.each_key do | key |
137
+ eval <<-"end_eval"
138
+ def #{key.to_s}
139
+ return self.colorize( :color => :#{key.to_s} )
140
+ end
141
+ def on_#{key.to_s}
142
+ return self.colorize( :background => :#{key.to_s} )
143
+ end
144
+ end_eval
145
+ end
146
+
147
+ #
148
+ # Methods for modes
149
+ #
150
+ MODES.each_key do | key |
151
+ eval <<-"end_eval"
152
+ def #{key.to_s}
153
+ return self.colorize( :mode => :#{key.to_s} )
154
+ end
155
+ end_eval
156
+ end
157
+
158
+ class << self
159
+
160
+ #
161
+ # Return array of available modes used by colorize method
162
+ #
163
+ def modes
164
+ keys = []
165
+ MODES.each_key do | key |
166
+ keys << key
167
+ end
168
+ keys
169
+ end
170
+
171
+ #
172
+ # Return array of available colors used by colorize method
173
+ #
174
+ def colors
175
+ keys = []
176
+ COLORS.each_key do | key |
177
+ keys << key
178
+ end
179
+ keys
180
+ end
181
+
182
+ #
183
+ # Display color matrix with color names.
184
+ #
185
+ def color_matrix( txt = "[X]" )
186
+ size = String.colors.length
187
+ String.colors.each do | color |
188
+ String.colors.each do | back |
189
+ print txt.colorize( :color => color, :background => back )
190
+ end
191
+ puts " < #{color}"
192
+ end
193
+ String.colors.reverse.each_with_index do | back, index |
194
+ puts "#{"|".rjust(txt.length)*(size-index)} < #{back}"
195
+ end
196
+ end
197
+ end
198
+ end