jashmenn-git-style-binaries 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
@@ -0,0 +1,259 @@
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
+ ## Goal
13
+
14
+ Lets use the imaginary `wordpress` gem. Let's say we have three different
15
+ actions we want to specify:
16
+
17
+ * categories
18
+ * list
19
+ * post
20
+
21
+ Each command has its own binary in a directory structure like this:
22
+
23
+ bin/
24
+ |-- wordpress
25
+ |-- wordpress-categories
26
+ |-- wordpress-list
27
+ `-- wordpress-post
28
+
29
+ The goal is to be able to call commands in this manner:
30
+
31
+ wordpress -h # gives help summary of all commands
32
+ wordpress-list -h # gives long help of wordpress-list
33
+ wordpress list -h # ditto
34
+ echo "about me" | wordpress-post --title="new post" # posts a new post with that title
35
+
36
+ ## Example code
37
+ Our `bin/wordpress` binary is called the *primary* . Our primary only needs to contain the following line:
38
+
39
+ #!/usr/bin/env ruby
40
+ require 'git-style-binary/command'
41
+
42
+ `git-style-binary` will automatically make this command the primary.
43
+
44
+ The `bin/wordpress-post` binary could contain the following:
45
+
46
+ #!/usr/bin/env ruby
47
+ require 'git-style-binary/command'
48
+
49
+ GitStyleBinary.command do
50
+ short_desc "create a blog post"
51
+ banner <<-EOS
52
+ Usage: #{command.full_name} #{all_options_string} {content|STDIN}
53
+
54
+ Posts content to a wordpress blog
55
+
56
+ EOS
57
+ opt :blog, "short name of the blog to use", :default => 'default'
58
+ opt :category, "tag/category. specify multiple times for multiple categories", :type => String, :multi => true
59
+ opt :title, "title for the post", :required => true, :type => String
60
+ opt :type, "type of the content [html|xhtml|text]", :default => 'html', :type => String
61
+
62
+ run do |command|
63
+ command.die :type, "type must be one of [html|xhtml|text]" unless command.opts[:type] =~ /^(x?html|text)$/i
64
+
65
+ puts "Subcommand name: #{command.name.inspect}"
66
+ puts "Options: #{command.opts.inspect}"
67
+ puts "Remaining arguments: #{command.argv.inspect}"
68
+ end
69
+ end
70
+
71
+ And so on with the other binaries.
72
+
73
+ ## Running the binaries
74
+
75
+ Now if we run `wordpress -h` we get the following output:
76
+
77
+ NAME
78
+ wordpress
79
+
80
+ VERSION
81
+ 0.0.1 (c) 2009 Nate Murray - local
82
+
83
+ SYNOPSIS
84
+ wordpress [--version] [--test-primary] [--help] [--verbose] COMMAND [ARGS]
85
+
86
+ SUBCOMMANDS
87
+ wordpress-categories
88
+ do something with categories
89
+
90
+ wordpress-help
91
+ get help for a specific command
92
+
93
+ wordpress-list
94
+ list blog postings
95
+
96
+ wordpress-post
97
+ create a blog post
98
+
99
+
100
+ See 'wordpress help COMMAND' for more information on a specific command.
101
+
102
+ OPTIONS
103
+ -v, --verbose
104
+ verbose
105
+
106
+
107
+ -t, --test-primary=<s>
108
+ test an option on the primary
109
+
110
+
111
+ -e, --version
112
+ Print version and exit
113
+
114
+
115
+ -h, --help
116
+ Show this message
117
+
118
+
119
+
120
+ Default **options**, **version string**, and **usage banner** are automatically selected for you.
121
+ The subcommands and their short descriptions are loaded automatically!
122
+
123
+ You can pass the `-h` flag to any one of the subcommands (with or without the
124
+ connecting `-`) or use the built-in `help` subcommand for the same effect. For instance:
125
+
126
+ $ wordpress help post
127
+
128
+ NAME
129
+ wordpress-post - create a blog post
130
+
131
+ VERSION
132
+ 0.0.1 (c) 2009 Nate Murray - local
133
+
134
+ SYNOPSIS
135
+ wordpress-post [--type] [--version] [--test-primary] [--blog] [--help] [--verbose] [--category]
136
+ [--title] COMMAND [ARGS] {content|STDIN}
137
+
138
+ OPTIONS
139
+ -v, --verbose
140
+ verbose
141
+
142
+
143
+ -t, --test-primary=<s>
144
+ test an option on the primary
145
+
146
+
147
+ -b, --blog=<s>
148
+ short name of the blog to use (default: default)
149
+
150
+
151
+ -c, --category=<s>
152
+ tag/category. specify multiple times for multiple
153
+ categories
154
+
155
+
156
+ -i, --title=<s>
157
+ title for the post
158
+
159
+
160
+ -y, --type=<s>
161
+ type of the content [html|xhtml|text] (default: html)
162
+
163
+
164
+ -e, --version
165
+ Print version and exit
166
+
167
+
168
+ -h, --help
169
+ Show this message
170
+
171
+
172
+ For more examples, see the binaries in `test/fixtures/`.
173
+
174
+ ## Primary options
175
+
176
+ Often you may *want* the primary to have its own set of options. Simply call `GitStyleBinary.primary` with a block like so:
177
+
178
+ #!/usr/bin/env ruby
179
+ require 'git-style-binary/command'
180
+ GitStyleBinary.primary do
181
+ version "#{command.full_name} 0.0.1 (c) 2009 Nate Murray - local"
182
+ opt :test_primary, "a primary string option", :type => String
183
+
184
+ run do |command|
185
+ puts "Primary Options: #{command.opts.inspect}"
186
+ end
187
+ end
188
+
189
+ Primary options are **inherited** by all subcommands. That means in this case
190
+ all subcommands will now get the `--test-primary` option available to them as
191
+ well as this new `version` string.
192
+
193
+ ## Option parsing
194
+
195
+ Option parsing is done by [trollop](http://trollop.rubyforge.org/).
196
+ `git-style-binary` uses this more-or-less exactly. See the [trollop
197
+ documentation](http://trollop.rubyforge.org/) for information on how to setup
198
+ the options and flags.
199
+
200
+ ## The `run` block
201
+
202
+ To get the 'introspection' on the individual binaries every binary is `load`ed
203
+ on `primary help`. We need a way to get that information while not running
204
+ every command when calling `primary help`. To achieve that you need to put what
205
+ will be run in the `run` block.
206
+
207
+ `run` `yields` a `Command` object which contains a number of useful options
208
+ such as `name`, `full_name`, `opts`, and `argv`.
209
+
210
+ * `command.opts` is a hash of the options parsed
211
+ * `command.argv` is an array of the remaining arguments
212
+
213
+ ## Features
214
+ * automatic colorization
215
+ * automatic paging
216
+
217
+ ## To Learn more
218
+
219
+ Play with the examples in the `test/fixtures` directory.
220
+
221
+ ## Credits
222
+ * `git-style-binary` was written by Nate Murray `<nate@natemurray.com>`
223
+ * `trollop` was written by [William Morgan](http://trollop.rubyforge.org/)
224
+ * 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)
225
+ * [`colorize.rb`](http://colorize.rubyforge.org) by Michal Kalbarczyk
226
+ * Automatic less paging by [Nathan Weizenbaum](http://nex-3.com/posts/73-git-style-automatic-paging-in-ruby)
227
+ * Color inspiration from [Brian Henderson](http://xcombinator.com) teaching me how to get `man git` colors using `less` on MacOSX
228
+
229
+ ## TODO
230
+ * automagic tab completion - Automatic for subcommands and options for any library that uses this
231
+
232
+ ## Known Bugs/Problems
233
+ * Young
234
+ * A few places of really ugly code
235
+ * A feeling that this could be done in 1/2 lines of code
236
+
237
+ ## Copyright
238
+
239
+ The MIT License
240
+
241
+ Copyright (c) 2009 Nate Murray. See LICENSE for details.
242
+
243
+ Permission is hereby granted, free of charge, to any person obtaining a copy
244
+ of this software and associated documentation files (the "Software"), to deal
245
+ in the Software without restriction, including without limitation the rights
246
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
247
+ copies of the Software, and to permit persons to whom the Software is
248
+ furnished to do so, subject to the following conditions:
249
+
250
+ The above copyright notice and this permission notice shall be included in
251
+ all copies or substantial portions of the Software.
252
+
253
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
254
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
255
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
256
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
257
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
258
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
259
+ THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "git-style-binaries"
8
+ gem.description = %Q{Ridiculously easy git-style binaries}
9
+ gem.summary =<<-EOF
10
+ Add git-style binaries to your project easily.
11
+ EOF
12
+ gem.email = "nate@natemurray.com"
13
+ gem.homepage = "http://github.com/jashmenn/git-style-binaries"
14
+ gem.authors = ["Nate Murray"]
15
+ gem.add_dependency 'trollop'
16
+ gem.add_dependency 'thoughtbot-shoulda' # for running the tests
17
+
18
+ excludes = /(README\.html)/
19
+ gem.files = (FileList["[A-Z]*.*", "{bin,examples,generators,lib,rails,spec,test}/**/*", 'Rakefile', 'LICENSE*']).delete_if{|f| f =~ excludes}
20
+ gem.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']
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 1
4
+ :patch: 3
@@ -0,0 +1,199 @@
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
+ puts
199
+ end
data/lib/ext/core.rb ADDED
@@ -0,0 +1,16 @@
1
+ class Object
2
+ def returning(value)
3
+ yield(value)
4
+ value
5
+ end unless Object.respond_to?(:returning)
6
+ end
7
+
8
+ class Symbol
9
+ def to_proc
10
+ Proc.new { |*args| args.shift.__send__(self, *args) }
11
+ end
12
+ end
13
+
14
+ class IO
15
+ attr_accessor :use_color
16
+ end
@@ -0,0 +1,21 @@
1
+ require 'git-style-binary/parser'
2
+
3
+ module GitStyleBinary
4
+ class AutoRunner
5
+
6
+ def self.run(argv=ARGV)
7
+ r = new
8
+ r.run
9
+ end
10
+
11
+ def run
12
+ unless GitStyleBinary.run?
13
+ if !GitStyleBinary.current_command
14
+ GitStyleBinary.load_primary
15
+ end
16
+ GitStyleBinary.current_command.run
17
+ end
18
+ end
19
+
20
+ end
21
+ end