git-style-binaries 0.1.10

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.
@@ -0,0 +1,223 @@
1
+ module GitStyleBinary
2
+ class Parser < Trollop::Parser
3
+ attr_reader :runs, :callbacks
4
+ attr_reader :short_desc
5
+ attr_accessor :command
6
+
7
+ def initialize *a, &b
8
+ super
9
+ @runs = []
10
+ setup_callbacks
11
+ end
12
+
13
+ def setup_callbacks
14
+ @callbacks = {}
15
+ %w(run).each do |event|
16
+ %w(before after).each do |time|
17
+ @callbacks["#{time}_#{event}".to_sym] = []
18
+ instance_eval "def #{time}_#{event}(&block);@callbacks[:#{time}_#{event}] << block;end"
19
+ end
20
+ end
21
+ end
22
+
23
+ def run_callbacks(at, from)
24
+ @callbacks[at].each {|c| c.call(from) }
25
+ end
26
+
27
+ def banner s=nil; @banner = s if s; @banner end
28
+ def short_desc s=nil; @short_desc = s if s; @short_desc end
29
+ def name_desc s=nil; @name_desc = s if s; @name_desc end
30
+
31
+ # Set the theme. Valid values are +:short+ or +:long+. Default +:long+
32
+ attr_writer :theme
33
+
34
+ def theme
35
+ @theme ||= :long
36
+ end
37
+
38
+ ## Adds text to the help display.
39
+ def text s; @order << [:text, s] end
40
+
41
+ def spec_names
42
+ @specs.collect{|name, spec| spec[:long]}
43
+ end
44
+
45
+ # should probably be somewhere else
46
+ def load_all_commands
47
+ GitStyleBinary.subcommand_names.each do |name|
48
+ cmd_file = GitStyleBinary.binary_filename_for(name)
49
+ GitStyleBinary.load_command_file(name, cmd_file)
50
+ end
51
+ end
52
+
53
+ ## Print the help message to 'stream'.
54
+ def educate(stream=$stdout)
55
+ load_all_commands
56
+ width # just calculate it now; otherwise we have to be careful not to
57
+ # call this unless the cursor's at the beginning of a line.
58
+ GitStyleBinary::Helpers::Pager.run_pager
59
+ self.send("educate_#{theme}", stream)
60
+ end
61
+
62
+ def educate_long(stream=$stdout)
63
+ left = {}
64
+
65
+ @specs.each do |name, spec|
66
+ left[name] =
67
+ ((spec[:short] ? "-#{spec[:short]}, " : "") +
68
+ "--#{spec[:long]}" +
69
+ case spec[:type]
70
+ when :flag; ""
71
+ when :int; "=<i>"
72
+ when :ints; "=<i+>"
73
+ when :string; "=<s>"
74
+ when :strings; "=<s+>"
75
+ when :float; "=<f>"
76
+ when :floats; "=<f+>"
77
+ end).colorize(:red)
78
+ end
79
+
80
+ leftcol_width = left.values.map { |s| s.length }.max || 0
81
+ rightcol_start = leftcol_width + 6 # spaces
82
+ leftcol_start = 6
83
+ leftcol_spaces = " " * leftcol_start
84
+
85
+ unless @order.size > 0 && @order.first.first == :text
86
+
87
+ if @name_desc
88
+ stream.puts "NAME".colorize(:red)
89
+ stream.puts "#{leftcol_spaces}"+ colorize_known_words(eval(%Q["#{@name_desc}"])) + "\n"
90
+ stream.puts
91
+ end
92
+
93
+ if @version
94
+ stream.puts "VERSION".colorize(:red)
95
+ stream.puts "#{leftcol_spaces}#@version\n"
96
+ end
97
+
98
+ stream.puts
99
+
100
+ banner = colorize_known_words_array(wrap(eval(%Q["#{@banner}"]) + "\n", :prefix => leftcol_start)) if @banner # lazy banner
101
+ stream.puts banner
102
+
103
+ stream.puts
104
+ stream.puts "OPTIONS".colorize(:red)
105
+ else
106
+ stream.puts "#@banner\n" if @banner
107
+ end
108
+
109
+ @order.each do |what, opt|
110
+ if what == :text
111
+ stream.puts wrap(opt)
112
+ next
113
+ end
114
+
115
+ spec = @specs[opt]
116
+ stream.printf " %-#{leftcol_width}s\n", left[opt]
117
+ desc = spec[:desc] +
118
+ if spec[:default]
119
+ if spec[:desc] =~ /\.$/
120
+ " (Default: #{spec[:default]})"
121
+ else
122
+ " (default: #{spec[:default]})"
123
+ end
124
+ else
125
+ ""
126
+ end
127
+ stream.puts wrap(" %s" % [desc], :prefix => leftcol_start, :width => width - rightcol_start - 1 )
128
+ stream.puts
129
+ stream.puts
130
+ end
131
+
132
+ end
133
+
134
+ def educate_short(stream=$stdout)
135
+ left = {}
136
+
137
+ @specs.each do |name, spec|
138
+ left[name] = "--#{spec[:long]}" +
139
+ (spec[:short] ? ", -#{spec[:short]}" : "") +
140
+ case spec[:type]
141
+ when :flag; ""
142
+ when :int; " <i>"
143
+ when :ints; " <i+>"
144
+ when :string; " <s>"
145
+ when :strings; " <s+>"
146
+ when :float; " <f>"
147
+ when :floats; " <f+>"
148
+ end
149
+ end
150
+
151
+ leftcol_width = left.values.map { |s| s.length }.max || 0
152
+ rightcol_start = leftcol_width + 6 # spaces
153
+ leftcol_start = 0
154
+
155
+ unless @order.size > 0 && @order.first.first == :text
156
+ stream.puts "#@version\n" if @version
157
+ stream.puts colorize_known_words_array(wrap(eval(%Q["#{@banner}"]) + "\n", :prefix => leftcol_start)) if @banner # jit banner
158
+ stream.puts "Options:"
159
+ else
160
+ stream.puts "#@banner\n" if @banner
161
+ end
162
+
163
+ @order.each do |what, opt|
164
+ if what == :text
165
+ stream.puts wrap(opt)
166
+ next
167
+ end
168
+
169
+ spec = @specs[opt]
170
+ stream.printf " %#{leftcol_width}s: ", left[opt]
171
+ desc = spec[:desc] +
172
+ if spec[:default]
173
+ if spec[:desc] =~ /\.$/
174
+ " (Default: #{spec[:default]})"
175
+ else
176
+ " (default: #{spec[:default]})"
177
+ end
178
+ else
179
+ ""
180
+ end
181
+ stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)
182
+ end
183
+
184
+ end
185
+
186
+
187
+ def colorize_known_words_array(txts)
188
+ txts.collect{|txt| colorize_known_words(txt)}
189
+ end
190
+
191
+ def colorize_known_words(txt)
192
+ txt = txt.gsub(/^([A-Z]+\s*)$/, '\1'.colorize(:red)) # all caps words on their own line
193
+ txt = txt.gsub(/\b(#{bin_name})\b/, '\1'.colorize(:light_blue)) # the current command name
194
+ txt = txt.gsub(/\[([^\s]+)\]/, "[".colorize(:magenta) + '\1'.colorize(:green) + "]".colorize(:magenta)) # synopsis options
195
+ end
196
+
197
+ def consume(&block)
198
+ cloaker(&block).bind(self).call
199
+ end
200
+
201
+ def consume_all(blocks)
202
+ blocks.each {|b| consume(&b)}
203
+ end
204
+
205
+ def bin_name
206
+ GitStyleBinary.full_current_command_name
207
+ end
208
+
209
+ def all_options_string
210
+ # '#{spec_names.collect(&:to_s).collect{|name| "[".colorize(:magenta) + "--" + name + "]".colorize(:magenta)}.join(" ")} COMMAND [ARGS]'
211
+ '#{spec_names.collect(&:to_s).collect{|name| "[" + "--" + name + "]"}.join(" ")} COMMAND [ARGS]'
212
+ end
213
+
214
+ def run(&block)
215
+ @runs << block
216
+ end
217
+
218
+ def action(name = :action, &block)
219
+ block.call(self) if block
220
+ end
221
+
222
+ end
223
+ end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + "/../../lib")
3
+ VERSION="0.0.2" # just to test it
4
+ require 'git-style-binary/command'
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + "/../../lib")
3
+ require 'git-style-binary/command'
4
+
5
+ GitStyleBinary.command do
6
+ short_desc "download a flickr image"
7
+ banner <<-EOS
8
+ SYNOPSIS
9
+ #{command.full_name} #{all_options_string} url
10
+
11
+ Downloads an image from flickr
12
+
13
+ EOS
14
+ run do |command|
15
+ puts "would download: #{command.argv.inspect}"
16
+ end
17
+ end
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + "/../../lib")
3
+
4
+ require 'git-style-binary/command'
5
+ GitStyleBinary.primary do
6
+ version "0.0.1 (c) 2009 Nate Murray - local"
7
+ opt :test_primary, "test an option on the primary", :type => String
8
+
9
+ action do
10
+ @categories = ["sports", "news"]
11
+ end
12
+
13
+ before_run do |cmd|
14
+ puts "before_run command #{cmd}"
15
+ end
16
+
17
+ after_run do |cmd|
18
+ puts "after_run command #{cmd}"
19
+ end
20
+
21
+ run do |command|
22
+ puts "Primary Options: #{command.opts.inspect}"
23
+ end
24
+ end
25
+
26
+ # OR
27
+
28
+ # require 'git-style-binary/primary'
29
+ # command = GitStyleBinary::primary("wordpress") do
30
+ # version "#{$0} 0.0.1 (c) 2009 Nate Murray"
31
+ # banner <<-EOS
32
+ # usage: #{$0} #{all_options.collect(:&to_s).join(" ")} COMMAND [ARGS]
33
+ #
34
+ # The wordpress subcommands commands are:
35
+ # {subcommand_names.pretty_print}
36
+ #
37
+ # See 'wordpress help COMMAND' for more information on a specific command.
38
+ # EOS
39
+ # opt :verbose, "verbose", :default => false
40
+ # opt :dry, "dry run", :default => false
41
+ # opt :test_global, "a basic global string option", :type => String
42
+ # end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + "/../../lib")
3
+ require 'git-style-binary/command'
4
+
5
+ GitStyleBinary.command do
6
+ short_desc "do something with categories"
7
+ banner <<-EOS
8
+ SYNOPSIS
9
+ #{command.full_name} #{all_options_string}
10
+
11
+ Does something with categories
12
+
13
+ EOS
14
+ run do |command|
15
+ puts "does something with categories"
16
+ puts @categories.join(" ")
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + "/../../lib")
3
+ require 'git-style-binary/command'
4
+
5
+ GitStyleBinary.command do
6
+ short_desc "list blog postings"
7
+ banner <<-EOS
8
+ SYNOPSIS
9
+ #{command.full_name} #{all_options_string}
10
+
11
+ Lists the posts on the blog
12
+
13
+ EOS
14
+ run do |command|
15
+ puts "listing blog posts"
16
+ end
17
+ end
18
+
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.dirname(__FILE__) + "/../../lib")
3
+ require 'git-style-binary/command'
4
+
5
+ GitStyleBinary.command do
6
+ short_desc "create a blog post"
7
+ banner <<-EOS
8
+ SYNOPSIS
9
+ #{command.full_name} #{all_options_string} {content|STDIN}
10
+
11
+ EOS
12
+ opt :blog, "short name of the blog to use", :default => 'default'
13
+ opt :category, "tag/category. specify multiple times for multiple categories", :type => String, :multi => true
14
+ opt :title, "title for the post", :required => true, :type => String
15
+ opt :type, "type of the content [html|xhtml|text]", :default => 'html', :type => String
16
+
17
+ run do |command|
18
+ command.die :type, "type must be one of [html|xhtml|text]" unless command.opts[:type] =~ /^(x?html|text)$/i
19
+
20
+ puts "Subcommand name: #{command.name.inspect}"
21
+ puts "Options: #{command.opts.inspect}"
22
+ puts "Remaining arguments: #{command.argv.inspect}"
23
+ end
24
+ end
25
+
26
+
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + "/../test_helper.rb"
2
+ require 'git-style-binary/command'
3
+
4
+ class CommandTest < Test::Unit::TestCase
5
+ context "cmd" do
6
+ setup do
7
+ @c = GitStyleBinary::Command.new
8
+ end
9
+
10
+ should "be able to easily work with constraints" do
11
+ assert_equal @c.constraints, []
12
+ @c.constraints << "foo"
13
+ assert_equal @c.constraints, ["foo"]
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + "/test_helper.rb"
2
+
3
+ class GitStyleBinariesTest < Test::Unit::TestCase
4
+ context "parsing basenames" do
5
+ should "accurately parse basenames" do
6
+ assert_equal "wordpress", GitStyleBinary.basename("bin/wordpress")
7
+ assert_equal "wordpress", GitStyleBinary.basename("bin/wordpress-post")
8
+ assert_equal "wordpress", GitStyleBinary.basename("wordpress-post")
9
+ end
10
+
11
+ should "get the current command name" do
12
+ # doesn't really apply any more b/c it calls 'current' which is never the
13
+ # current when your running rake_test_loader.rb
14
+ #
15
+ # assert_equal "wordpress", GitStyleBinary.current_command_name("bin/wordpress", ["--help"])
16
+ # assert_equal "post", GitStyleBinary.current_command_name("bin/wordpress-post", ["--help"])
17
+ # assert_equal "post", GitStyleBinary.current_command_name("bin/wordpress post", ["--help"])
18
+ #assert_equal "post", GitStyleBinary.current_command_name("bin/wordpress post", [])
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,224 @@
1
+ require File.dirname(__FILE__) + "/test_helper.rb"
2
+
3
+ THIS_YEAR=Time.now.year # todo
4
+
5
+ class RunningBinariesTest < Test::Unit::TestCase
6
+ include RunsBinaryFixtures
7
+
8
+ context "when running primary" do
9
+ ["wordpress -h", "wordpress help"].each do |format|
10
+ context "and getting help as a '#{format}'" do
11
+ setup { @stdout, @stderr = bin(format) }
12
+
13
+ should "have the command name and short description" do
14
+ unless format == "wordpress -h" # doesn't apply to wordpress -h
15
+ output_matches /NAME\n\s*wordpress\-help \- get help for a specific command/m
16
+ end
17
+ end
18
+
19
+ should "have a local (not default) version string" do
20
+ output_matches /0\.0\.1 \(c\) 2009 Nate Murray - local/
21
+ end
22
+
23
+ should "get a list of subcommands" do
24
+ output_matches /subcommands/mi
25
+ end
26
+
27
+ should "have subcommand short descriptions" do
28
+ output_matches /post\s*create a blog post/
29
+ output_matches /categories\s*do something with categories/
30
+ output_matches /help\s*get help for a specific command/
31
+ output_matches /list\s*list blog postings/
32
+ end
33
+
34
+ should "have a usage" do
35
+ output_matches /SYNOPSIS/i
36
+ output_matches /wordpress(\-help)? \[/
37
+ end
38
+
39
+ should "be able to ask for help about help"
40
+ end
41
+ end
42
+
43
+ context "and getting help as subcommand" do
44
+ # ["wordpress -h", "wordpress help"].each do |format|
45
+ ["wordpress help"].each do |format|
46
+ context "'#{format}'" do
47
+ should "get help on subcommand post"
48
+ end
49
+ end
50
+ end
51
+
52
+ context "with no options" do
53
+ setup { @stdout, @stderr = bin("wordpress") }
54
+
55
+ should "output the options" do
56
+ output_matches /Primary Options:/
57
+ end
58
+
59
+ should "have the test_primary option" do
60
+ output_matches /test_primary=>nil/
61
+ end
62
+ end
63
+ should "be able to require 'primary' and run just fine"
64
+ end
65
+
66
+ context "when running with an action" do
67
+ # should be the same for both formats
68
+ ["wordpress-categories", "wordpress categories"].each do |bin_format|
69
+ context "#{bin_format}" do
70
+
71
+ context "with action block" do
72
+ setup { @stdout, @stderr = bin("#{bin_format}") }
73
+ should "have the parsed action items in the help output" do
74
+ output_matches /sports news/m
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ context "callbacks" do
82
+ context "on a binary" do
83
+ setup { @stdout, @stderr = bin("wordpress") }
84
+
85
+ %w(before after).each do |time|
86
+ should "run the callback #{time}_run}" do
87
+ assert @stdout.match(/#{time}_run command/)
88
+ end
89
+ end
90
+ end
91
+
92
+ context "on help" do
93
+ setup { @stdout, @stderr = bin("wordpress -h") }
94
+
95
+ %w(before after).each do |time|
96
+ should "not run the callback #{time}_run" do
97
+ assert_nil @stdout.match(/#{time}_run command/)
98
+ end
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+
105
+ context "when running the subcommand" do
106
+ # should be the same for both formats
107
+ ["wordpress-post", "wordpress post"].each do |bin_format|
108
+ context "#{bin_format}" do
109
+
110
+ context "with no options" do
111
+ setup { @stdout, @stderr = bin("#{bin_format}") }
112
+ should "fail because title is required" do
113
+ output_matches /Error: option 'title' must be specified.\s*Try --help for help/m
114
+ end
115
+ end
116
+
117
+ context "with options" do
118
+ setup { @stdout, @stderr = bin("#{bin_format} --title='glendale'") }
119
+ should "be running the subcommand's run block" do
120
+ output_matches /Subcommand name/
121
+ end
122
+ should "have some default options" do
123
+ output_matches /version=>false/
124
+ output_matches /help=>false/
125
+ end
126
+ should "have some primary options" do
127
+ output_matches /test_primary=>nil/
128
+ end
129
+ should "have some local options" do
130
+ output_matches /title=>"glendale"/
131
+ output_matches /type=>"html"/
132
+ end
133
+ end
134
+
135
+ context "testing die statements" do
136
+ setup { @stdout, @stderr = bin("#{bin_format} --title='glendale' --type=yaml") }
137
+
138
+ should "die on invalid options" do
139
+ output_matches /argument \-\-type type must be one of \[html\|xhtml\|text\]/
140
+ end
141
+ end
142
+
143
+ end # end bin_format
144
+ end # end #each
145
+ end
146
+
147
+ ["wordpress help post", "wordpress post -h"].each do |format|
148
+ context "when calling '#{format}'" do
149
+
150
+ setup { @stdout, @stderr = bin(format) }
151
+ should "have a description" do
152
+ output_matches /create a blog post/
153
+ end
154
+
155
+ should "have the proper usage line" do
156
+ output_matches /SYNOPSIS\n\s*wordpress\-post/m
157
+ output_matches /\[--title\]/
158
+ end
159
+
160
+ should "have option flags" do
161
+ output_matches /\-\-title(.*)<s>/
162
+ end
163
+
164
+ should "have primary option flags" do
165
+ output_matches /\-\-test-primary(.*)<s>/
166
+ end
167
+
168
+ should "have default option flags" do
169
+ output_matches /\-\-verbose/
170
+ end
171
+
172
+ should "have trollop default option flags" do
173
+ output_matches /\-e, \-\-version/
174
+ end
175
+
176
+ should "have the correct binary name and short description" do
177
+ output_matches /NAME\n\s*wordpress\-post \- create a blog post/m
178
+ end
179
+
180
+ should "have a the primaries version string" do
181
+ output_matches /0\.0\.1 \(c\) 2009 Nate Murray - local/
182
+ end
183
+
184
+ should "have options" do
185
+ output_matches /Options/i
186
+
187
+ output_matches /\-b, \-\-blog=<s>/
188
+ output_matches /short name of the blog to use/
189
+
190
+ output_matches /-i, \-\-title=<s>/
191
+ output_matches /title for the post/
192
+ end
193
+
194
+ end
195
+ end
196
+
197
+ context "when running a bare primary" do
198
+ ["flickr -h", "flickr help"].each do |format|
199
+ context format do
200
+ setup { @stdout, @stderr = bin(format) }
201
+
202
+ should "have the name and short description" do
203
+ unless format == "flickr -h" # hmm
204
+ output_matches /NAME\n\s*flickr\-help \- get help for a specific command/m
205
+ end
206
+ end
207
+
208
+ should "have a local (not default) version string" do
209
+ output_matches /0\.0\.2 \(c\) 2009/
210
+ end
211
+ end
212
+ end
213
+ ["flickr-download -h", "flickr download -h"].each do |format|
214
+ context format do
215
+ setup { @stdout, @stderr = bin(format) }
216
+
217
+ should "match on usage" do
218
+ output_matches /SYNOPSIS\n\s*flickr\-download/m
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ end