ditz-str 0.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.
Files changed (65) hide show
  1. data/.document +5 -0
  2. data/Gemfile +14 -0
  3. data/Gemfile.lock +24 -0
  4. data/LICENSE +674 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +19 -0
  7. data/README.txt +143 -0
  8. data/Rakefile +55 -0
  9. data/VERSION +1 -0
  10. data/bin/ditz-str +189 -0
  11. data/bugs/issue-02615b8c3dd0382c92f350ce2158ecfe94d11ef8.yaml +22 -0
  12. data/bugs/issue-06a3bbf35a60c4da2d8ea0fdc86164263126d6b2.yaml +22 -0
  13. data/bugs/issue-0c00c1d7fdffaad304e62d79d9b3d5e92547055b.yaml +38 -0
  14. data/bugs/issue-20dad4b4533d6d76d496fe5970098f1eb8efd561.yaml +26 -0
  15. data/bugs/issue-360ae6529dbc66358fde6b532cbea79ece37a670.yaml +22 -0
  16. data/bugs/issue-5177d61bf3c2783f71ef63e6e2c5e720247ef699.yaml +18 -0
  17. data/bugs/issue-695b564c210da1965a2bb38eef782178aead6952.yaml +26 -0
  18. data/bugs/issue-7d0ce6429a9fb5fa09ce3376a8921a5ecb7ecfe5.yaml +34 -0
  19. data/bugs/issue-a04462fa22ab6e1b02cfdd052d1f6c6f491f08f5.yaml +22 -0
  20. data/bugs/issue-bca54ca5107eabc3b281701041cc36ea0641cbdd.yaml +26 -0
  21. data/bugs/issue-d0c7d04b014d705c5fd865e4d487b5e5b6983c33.yaml +26 -0
  22. data/bugs/issue-f94b879842aa0274aa74fc2833252d4a06ec65cc.yaml +22 -0
  23. data/bugs/project.yaml +18 -0
  24. data/data/ditz-str/blue-check.png +0 -0
  25. data/data/ditz-str/close.rhtml +39 -0
  26. data/data/ditz-str/component.rhtml +38 -0
  27. data/data/ditz-str/dropdown.css +11 -0
  28. data/data/ditz-str/dropdown.js +58 -0
  29. data/data/ditz-str/edit_issue.rhtml +53 -0
  30. data/data/ditz-str/green-bar.png +0 -0
  31. data/data/ditz-str/green-check.png +0 -0
  32. data/data/ditz-str/header.gif +0 -0
  33. data/data/ditz-str/header_over.gif +0 -0
  34. data/data/ditz-str/index.rhtml +148 -0
  35. data/data/ditz-str/issue.rhtml +152 -0
  36. data/data/ditz-str/issue_table.rhtml +28 -0
  37. data/data/ditz-str/new_component.rhtml +28 -0
  38. data/data/ditz-str/new_issue.rhtml +57 -0
  39. data/data/ditz-str/new_release.rhtml +29 -0
  40. data/data/ditz-str/plugins/git-sync.rb +83 -0
  41. data/data/ditz-str/plugins/git.rb +153 -0
  42. data/data/ditz-str/plugins/issue-claiming.rb +174 -0
  43. data/data/ditz-str/red-check.png +0 -0
  44. data/data/ditz-str/release.rhtml +111 -0
  45. data/data/ditz-str/style.css +236 -0
  46. data/data/ditz-str/unassigned.rhtml +37 -0
  47. data/data/ditz-str/yellow-bar.png +0 -0
  48. data/ditz-str.gemspec +121 -0
  49. data/lib/ditzstr/brick.rb +251 -0
  50. data/lib/ditzstr/file-storage.rb +54 -0
  51. data/lib/ditzstr/hook.rb +67 -0
  52. data/lib/ditzstr/html.rb +104 -0
  53. data/lib/ditzstr/lowline.rb +201 -0
  54. data/lib/ditzstr/model-objects.rb +346 -0
  55. data/lib/ditzstr/model.rb +265 -0
  56. data/lib/ditzstr/operator.rb +593 -0
  57. data/lib/ditzstr/trollop.rb +614 -0
  58. data/lib/ditzstr/util.rb +61 -0
  59. data/lib/ditzstr/view.rb +16 -0
  60. data/lib/ditzstr/views.rb +157 -0
  61. data/lib/ditzstr.rb +69 -0
  62. data/man/ditz.1 +38 -0
  63. data/test/helper.rb +18 -0
  64. data/test/test_ditz-str.rb +7 -0
  65. metadata +219 -0
@@ -0,0 +1,614 @@
1
+ ## lib/trollop.rb -- trollop command-line processing library
2
+ ## Author:: William Morgan (mailto: wmorgan-trollop@masanjin.net)
3
+ ## Copyright:: Copyright 2007 William Morgan
4
+ ## License:: GNU GPL version 2
5
+
6
+ module Trollop
7
+
8
+ VERSION = "1.8.2"
9
+
10
+ ## Thrown by Parser in the event of a commandline error. Not needed if
11
+ ## you're using the Trollop::options entry.
12
+ class CommandlineError < StandardError; end
13
+
14
+ ## Thrown by Parser if the user passes in '-h' or '--help'. Handled
15
+ ## automatically by Trollop#options.
16
+ class HelpNeeded < StandardError; end
17
+
18
+ ## Thrown by Parser if the user passes in '-h' or '--version'. Handled
19
+ ## automatically by Trollop#options.
20
+ class VersionNeeded < StandardError; end
21
+
22
+ ## Regex for floating point numbers
23
+ FLOAT_RE = /^-?((\d+(\.\d+)?)|(\.\d+))$/
24
+
25
+ ## Regex for parameters
26
+ PARAM_RE = /^-(-|\.$|[^\d\.])/
27
+
28
+ ## The commandline parser. In typical usage, the methods in this class
29
+ ## will be handled internally by Trollop#options, in which case only the
30
+ ## methods #opt, #banner and #version, #depends, and #conflicts will
31
+ ## typically be called.
32
+ class Parser
33
+
34
+ ## The set of values that indicate a flag type of option when one of
35
+ ## the values is given to the :type parameter to #opt.
36
+ FLAG_TYPES = [:flag, :bool, :boolean]
37
+
38
+ ## The set of values that indicate an option that takes a single
39
+ ## parameter when one of the values is given to the :type parameter to
40
+ ## #opt.
41
+ SINGLE_ARG_TYPES = [:int, :integer, :string, :double, :float]
42
+
43
+ ## The set of values that indicate an option that takes multiple
44
+ ## parameters when one of the values is given to the :type parameter to
45
+ ## #opt.
46
+ MULTI_ARG_TYPES = [:ints, :integers, :strings, :doubles, :floats]
47
+
48
+ ## The set of values specifiable as the :type parameter to #opt.
49
+ TYPES = FLAG_TYPES + SINGLE_ARG_TYPES + MULTI_ARG_TYPES
50
+
51
+ INVALID_SHORT_ARG_REGEX = /[\d-]/ #:nodoc:
52
+
53
+ ## The values from the commandline that were not interpreted by #parse.
54
+ attr_reader :leftovers
55
+
56
+ ## The complete configuration hashes for each option. (Mainly useful
57
+ ## for testing.)
58
+ attr_reader :specs
59
+
60
+ ## Initializes the parser, and instance-evaluates any block given.
61
+ def initialize *a, &b
62
+ @version = nil
63
+ @leftovers = []
64
+ @specs = {}
65
+ @long = {}
66
+ @short = {}
67
+ @order = []
68
+ @constraints = []
69
+ @stop_words = []
70
+ @stop_on_unknown = false
71
+
72
+ #instance_eval(&b) if b # can't take arguments
73
+ cloaker(&b).bind(self).call(*a) if b
74
+ end
75
+
76
+ ## Add an option. 'name' is the argument name, a unique identifier
77
+ ## for the option that you will use internally. 'desc' a string
78
+ ## description which will be displayed in help messages. Takes the
79
+ ## following optional arguments:
80
+ ##
81
+ ## * :long: Specify the long form of the argument, i.e. the form
82
+ ## with two dashes. If unspecified, will be automatically derived
83
+ ## based on the argument name.
84
+ ## * :short: Specify the short form of the argument, i.e. the form
85
+ ## with one dash. If unspecified, will be automatically derived
86
+ ## based on the argument name.
87
+ ## * :type: Require that the argument take a parameter or parameters
88
+ ## of type 'type'. For a single parameter, the value can be a
89
+ ## member of the SINGLE_ARG_TYPES constant or a corresponding class
90
+ ## (e.g. Integer for :int). For multiple parameters, the value can
91
+ ## be a member of the MULTI_ARG_TYPES constant. If unset, the
92
+ ## default argument type is :flag, meaning that the argument does
93
+ ## not take a parameter. The specification of :type is not
94
+ ## necessary if :default is given.
95
+ ## * :default: Set the default value for an argument. Without a
96
+ ## default value, the hash returned by #parse (and thus
97
+ ## Trollop#options) will not contain the argument unless it is
98
+ ## given on the commandline. The argument type is derived
99
+ ## automatically from the class of the default value given, if
100
+ ## any. Specifying a :flag argument on the commandline whose
101
+ ## default value is true will change its value to false.
102
+ ## * :required: If set to true, the argument must be provided on the
103
+ ## commandline.
104
+ ## * :multi: If set to true, allows multiple instances of the
105
+ ## option. Otherwise, only a single instance of the option is
106
+ ## allowed.
107
+ def opt name, desc="", opts={}
108
+ raise ArgumentError, "you already have an argument named '#{name}'" if @specs.member? name
109
+
110
+ ## fill in :type
111
+ opts[:type] =
112
+ case opts[:type]
113
+ when :flag, :boolean, :bool; :flag
114
+ when :int, :integer; :int
115
+ when :ints, :integers; :ints
116
+ when :string; :string
117
+ when :strings; :strings
118
+ when :double, :float; :float
119
+ when :doubles, :floats; :floats
120
+ when Class
121
+ case opts[:type].to_s # sigh... there must be a better way to do this
122
+ when 'TrueClass', 'FalseClass'; :flag
123
+ when 'String'; :string
124
+ when 'Integer'; :int
125
+ when 'Float'; :float
126
+ else
127
+ raise ArgumentError, "unsupported argument type '#{opts[:type].class.name}'"
128
+ end
129
+ when nil; nil
130
+ else
131
+ raise ArgumentError, "unsupported argument type '#{opts[:type]}'" unless TYPES.include?(opts[:type])
132
+ end
133
+
134
+ type_from_default =
135
+ case opts[:default]
136
+ when Integer; :int
137
+ when Numeric; :float
138
+ when TrueClass, FalseClass; :flag
139
+ when String; :string
140
+ when Array
141
+ if opts[:default].empty?
142
+ raise ArgumentError, "multiple argument type cannot be deduced from an empty array for '#{opts[:default][0].class.name}'"
143
+ end
144
+ case opts[:default][0] # the first element determines the types
145
+ when Integer; :ints
146
+ when Numeric; :floats
147
+ when String; :strings
148
+ else
149
+ raise ArgumentError, "unsupported multiple argument type '#{opts[:default][0].class.name}'"
150
+ end
151
+ when nil; nil
152
+ else
153
+ raise ArgumentError, "unsupported argument type '#{opts[:default].class.name}'"
154
+ end
155
+
156
+ raise ArgumentError, ":type specification and default type don't match" if opts[:type] && type_from_default && opts[:type] != type_from_default
157
+
158
+ opts[:type] = (opts[:type] || type_from_default || :flag)
159
+
160
+ ## fill in :long
161
+ opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.gsub("_", "-")
162
+ opts[:long] =
163
+ case opts[:long]
164
+ when /^--([^-].*)$/
165
+ $1
166
+ when /^[^-]/
167
+ opts[:long]
168
+ else
169
+ raise ArgumentError, "invalid long option name #{opts[:long].inspect}"
170
+ end
171
+ raise ArgumentError, "long option name #{opts[:long].inspect} is already taken; please specify a (different) :long" if @long[opts[:long]]
172
+
173
+ ## fill in :short
174
+ opts[:short] = opts[:short].to_s if opts[:short] unless opts[:short] == :none
175
+ opts[:short] =
176
+ case opts[:short]
177
+ when nil
178
+ c = opts[:long].split(//).find { |c| c !~ INVALID_SHORT_ARG_REGEX && !@short.member?(c) }
179
+ raise ArgumentError, "can't generate a short option name for #{opts[:long].inspect}: out of unique characters" unless c
180
+ c
181
+ when /^-(.)$/
182
+ $1
183
+ when /^.$/
184
+ opts[:short]
185
+ when :none
186
+ nil
187
+ else
188
+ raise ArgumentError, "invalid short option name '#{opts[:short].inspect}'"
189
+ end
190
+ if opts[:short]
191
+ raise ArgumentError, "short option name #{opts[:short].inspect} is already taken; please specify a (different) :short" if @short[opts[:short]]
192
+ raise ArgumentError, "a short option name can't be a number or a dash" if opts[:short] =~ INVALID_SHORT_ARG_REGEX
193
+ end
194
+
195
+ ## fill in :default for flags
196
+ opts[:default] = false if opts[:type] == :flag && opts[:default].nil?
197
+
198
+ ## fill in :multi
199
+ opts[:multi] ||= false
200
+
201
+ opts[:desc] ||= desc
202
+ @long[opts[:long]] = name
203
+ @short[opts[:short]] = name if opts[:short]
204
+ @specs[name] = opts
205
+ @order << [:opt, name]
206
+ end
207
+
208
+ ## Sets the version string. If set, the user can request the version
209
+ ## on the commandline. Should be of the form "<program name>
210
+ ## <version number>".
211
+ def version s=nil; @version = s if s; @version end
212
+
213
+ ## Adds text to the help display.
214
+ def banner s; @order << [:text, s] end
215
+ alias :text :banner
216
+
217
+ ## Marks two (or more!) options as requiring each other. Only handles
218
+ ## undirected (i.e., mutual) dependencies. Directed dependencies are
219
+ ## better modeled with Trollop::die.
220
+ def depends *syms
221
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
222
+ @constraints << [:depends, syms]
223
+ end
224
+
225
+ ## Marks two (or more!) options as conflicting.
226
+ def conflicts *syms
227
+ syms.each { |sym| raise ArgumentError, "unknown option '#{sym}'" unless @specs[sym] }
228
+ @constraints << [:conflicts, syms]
229
+ end
230
+
231
+ ## Defines a set of words which cause parsing to terminate when encountered,
232
+ ## such that any options to the left of the word are parsed as usual, and
233
+ ## options to the right of the word are left intact.
234
+ ##
235
+ ## A typical use case would be for subcommand support, where these would be
236
+ ## set to the list of subcommands. A subsequent Trollop invocation would
237
+ ## then be used to parse subcommand options.
238
+ def stop_on *words
239
+ @stop_words = [*words].flatten
240
+ end
241
+
242
+ ## Similar to stop_on, but stops on any unknown word when encountered (unless
243
+ ## it is a parameter for an argument).
244
+ def stop_on_unknown
245
+ @stop_on_unknown = true
246
+ end
247
+
248
+ ## yield successive arg, parameter pairs
249
+ def each_arg args # :nodoc:
250
+ remains = []
251
+ i = 0
252
+
253
+ until i >= args.length
254
+ if @stop_words.member? args[i]
255
+ remains += args[i .. -1]
256
+ return remains
257
+ end
258
+ case args[i]
259
+ when /^--$/ # arg terminator
260
+ remains += args[(i + 1) .. -1]
261
+ return remains
262
+ when /^--(\S+?)=(\S+)$/ # long argument with equals
263
+ yield "--#{$1}", [$2]
264
+ i += 1
265
+ when /^--(\S+)$/ # long argument
266
+ params = collect_argument_parameters(args, i + 1)
267
+ unless params.empty?
268
+ num_params_taken = yield args[i], params
269
+ unless num_params_taken
270
+ if @stop_on_unknown
271
+ remains += args[i + 1 .. -1]
272
+ return remains
273
+ else
274
+ remains += params
275
+ end
276
+ end
277
+ i += 1 + num_params_taken
278
+ else # long argument no parameter
279
+ yield args[i], nil
280
+ i += 1
281
+ end
282
+ when /^-(\S+)$/ # one or more short arguments
283
+ shortargs = $1.split(//)
284
+ shortargs.each_with_index do |a, j|
285
+ if j == (shortargs.length - 1)
286
+ params = collect_argument_parameters(args, i + 1)
287
+ unless params.empty?
288
+ num_params_taken = yield "-#{a}", params
289
+ unless num_params_taken
290
+ if @stop_on_unknown
291
+ remains += args[i + 1 .. -1]
292
+ return remains
293
+ else
294
+ remains += params
295
+ end
296
+ end
297
+ i += 1 + num_params_taken
298
+ else # argument no parameter
299
+ yield "-#{a}", nil
300
+ i += 1
301
+ end
302
+ else
303
+ yield "-#{a}", nil
304
+ end
305
+ end
306
+ else
307
+ if @stop_on_unknown
308
+ remains += args[i .. -1]
309
+ return remains
310
+ else
311
+ remains << args[i]
312
+ i += 1
313
+ end
314
+ end
315
+ end
316
+
317
+ remains
318
+ end
319
+
320
+ def parse cmdline #:nodoc:
321
+ vals = {}
322
+ required = {}
323
+
324
+ opt :version, "Print version and exit" if @version unless @specs[:version] || @long["version"]
325
+ opt :help, "Show this message" unless @specs[:help] || @long["help"]
326
+
327
+ @specs.each do |sym, opts|
328
+ required[sym] = true if opts[:required]
329
+ vals[sym] = opts[:default]
330
+ end
331
+
332
+ ## resolve symbols
333
+ given_args = {}
334
+ @leftovers = each_arg cmdline do |arg, params|
335
+ sym =
336
+ case arg
337
+ when /^-([^-])$/
338
+ @short[$1]
339
+ when /^--([^-]\S*)$/
340
+ @long[$1]
341
+ else
342
+ raise CommandlineError, "invalid argument syntax: '#{arg}'"
343
+ end
344
+ raise CommandlineError, "unknown argument '#{arg}'" unless sym
345
+
346
+ if given_args.include?(sym) && !@specs[sym][:multi]
347
+ raise CommandlineError, "option '#{arg}' specified multiple times"
348
+ end
349
+
350
+ given_args[sym] ||= {}
351
+
352
+ given_args[sym][:arg] = arg
353
+ given_args[sym][:params] ||= []
354
+
355
+ # The block returns the number of parameters taken.
356
+ num_params_taken = 0
357
+
358
+ unless params.nil?
359
+ if SINGLE_ARG_TYPES.include?(@specs[sym][:type])
360
+ given_args[sym][:params] << params[0, 1] # take the first parameter
361
+ num_params_taken = 1
362
+ elsif MULTI_ARG_TYPES.include?(@specs[sym][:type])
363
+ given_args[sym][:params] << params # take all the parameters
364
+ num_params_taken = params.size
365
+ end
366
+ end
367
+
368
+ num_params_taken
369
+ end
370
+
371
+ ## check for version and help args
372
+ raise VersionNeeded if given_args.include? :version
373
+ raise HelpNeeded if given_args.include? :help
374
+
375
+ ## check constraint satisfaction
376
+ @constraints.each do |type, syms|
377
+ constraint_sym = syms.find { |sym| given_args[sym] }
378
+ next unless constraint_sym
379
+
380
+ case type
381
+ when :depends
382
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} requires --#{@specs[sym][:long]}" unless given_args.include? sym }
383
+ when :conflicts
384
+ syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym][:long]} conflicts with --#{@specs[sym][:long]}" if given_args.include?(sym) && (sym != constraint_sym) }
385
+ end
386
+ end
387
+
388
+ required.each do |sym, val|
389
+ raise CommandlineError, "option '#{sym}' must be specified" unless given_args.include? sym
390
+ end
391
+
392
+ ## parse parameters
393
+ given_args.each do |sym, given_data|
394
+ arg = given_data[:arg]
395
+ params = given_data[:params]
396
+
397
+ opts = @specs[sym]
398
+ raise CommandlineError, "option '#{arg}' needs a parameter" if params.empty? && opts[:type] != :flag
399
+
400
+ case opts[:type]
401
+ when :flag
402
+ vals[sym] = !opts[:default]
403
+ when :int, :ints
404
+ vals[sym] = params.map { |pg| pg.map { |p| parse_integer_parameter p, arg } }
405
+ when :float, :floats
406
+ vals[sym] = params.map { |pg| pg.map { |p| parse_float_parameter p, arg } }
407
+ when :string, :strings
408
+ vals[sym] = params.map { |pg| pg.map { |p| p.to_s } }
409
+ end
410
+
411
+ if SINGLE_ARG_TYPES.include?(opts[:type])
412
+ unless opts[:multi] # single parameter
413
+ vals[sym] = vals[sym][0][0]
414
+ else # multiple options, each with a single parameter
415
+ vals[sym] = vals[sym].map { |p| p[0] }
416
+ end
417
+ elsif MULTI_ARG_TYPES.include?(opts[:type]) && !opts[:multi]
418
+ vals[sym] = vals[sym][0] # single option, with multiple parameters
419
+ end
420
+ # else: multiple options, with multiple parameters
421
+ end
422
+
423
+ vals
424
+ end
425
+
426
+ def parse_integer_parameter param, arg #:nodoc:
427
+ raise CommandlineError, "option '#{arg}' needs an integer" unless param =~ /^\d+$/
428
+ param.to_i
429
+ end
430
+
431
+ def parse_float_parameter param, arg #:nodoc:
432
+ raise CommandlineError, "option '#{arg}' needs a floating-point number" unless param =~ FLOAT_RE
433
+ param.to_f
434
+ end
435
+
436
+ def collect_argument_parameters args, start_at #:nodoc:
437
+ params = []
438
+ pos = start_at
439
+ while args[pos] && args[pos] !~ PARAM_RE && !@stop_words.member?(args[pos]) do
440
+ params << args[pos]
441
+ pos += 1
442
+ end
443
+ params
444
+ end
445
+
446
+ def width #:nodoc:
447
+ @width ||=
448
+ if $stdout.tty?
449
+ begin
450
+ require 'curses'
451
+ Curses::init_screen
452
+ x = Curses::cols
453
+ Curses::close_screen
454
+ x
455
+ rescue Exception
456
+ 80
457
+ end
458
+ else
459
+ 80
460
+ end
461
+ end
462
+
463
+ ## Print the help message to 'stream'.
464
+ def educate stream=$stdout
465
+ width # just calculate it now; otherwise we have to be careful not to
466
+ # call this unless the cursor's at the beginning of a line.
467
+
468
+ left = {}
469
+ @specs.each do |name, spec|
470
+ left[name] = "--#{spec[:long]}" +
471
+ (spec[:short] ? ", -#{spec[:short]}" : "") +
472
+ case spec[:type]
473
+ when :flag; ""
474
+ when :int; " <i>"
475
+ when :ints; " <i+>"
476
+ when :string; " <s>"
477
+ when :strings; " <s+>"
478
+ when :float; " <f>"
479
+ when :floats; " <f+>"
480
+ end
481
+ end
482
+
483
+ leftcol_width = left.values.map { |s| s.length }.max || 0
484
+ rightcol_start = leftcol_width + 6 # spaces
485
+
486
+ unless @order.size > 0 && @order.first.first == :text
487
+ stream.puts "#@version\n" if @version
488
+ stream.puts "Options:"
489
+ end
490
+
491
+ @order.each do |what, opt|
492
+ if what == :text
493
+ stream.puts wrap(opt)
494
+ next
495
+ end
496
+
497
+ spec = @specs[opt]
498
+ stream.printf " %#{leftcol_width}s: ", left[opt]
499
+ desc = spec[:desc] +
500
+ if spec[:default]
501
+ if spec[:desc] =~ /\.$/
502
+ " (Default: #{spec[:default]})"
503
+ else
504
+ " (default: #{spec[:default]})"
505
+ end
506
+ else
507
+ ""
508
+ end
509
+ stream.puts wrap(desc, :width => width - rightcol_start - 1, :prefix => rightcol_start)
510
+ end
511
+ end
512
+
513
+ def wrap_line str, opts={} # :nodoc:
514
+ prefix = opts[:prefix] || 0
515
+ width = opts[:width] || (self.width - 1)
516
+ start = 0
517
+ ret = []
518
+ until start > str.length
519
+ nextt =
520
+ if start + width >= str.length
521
+ str.length
522
+ else
523
+ x = str.rindex(/\s/, start + width)
524
+ x = str.index(/\s/, start) if x && x < start
525
+ x || str.length
526
+ end
527
+ ret << (ret.empty? ? "" : " " * prefix) + str[start ... nextt]
528
+ start = nextt + 1
529
+ end
530
+ ret
531
+ end
532
+
533
+ def wrap str, opts={} # :nodoc:
534
+ if str == ""
535
+ [""]
536
+ else
537
+ str.split("\n").map { |s| wrap_line s, opts }.flatten
538
+ end
539
+ end
540
+
541
+ ## instance_eval but with ability to handle block arguments
542
+ ## thanks to why: http://redhanded.hobix.com/inspect/aBlockCostume.html
543
+ def cloaker &b #:nodoc:
544
+ (class << self; self; end).class_eval do
545
+ define_method :cloaker_, &b
546
+ meth = instance_method :cloaker_
547
+ remove_method :cloaker_
548
+ meth
549
+ end
550
+ end
551
+ end
552
+
553
+ ## The top-level entry method into Trollop. Creates a Parser object,
554
+ ## passes the block to it, then parses +args+ with it, handling any
555
+ ## errors or requests for help or version information appropriately
556
+ ## (and then exiting). Modifies +args+ in place. Returns a hash of
557
+ ## option values.
558
+ ##
559
+ ## The block passed in should contain one or more calls to #opt
560
+ ## (Parser#opt), one or more calls to text (Parser#text), and
561
+ ## probably a call to version (Parser#version).
562
+ ##
563
+ ## See the synopsis in README.txt for examples.
564
+ def options args = ARGV, *a, &b
565
+ @p = Parser.new(*a, &b)
566
+ begin
567
+ vals = @p.parse args
568
+ args.clear
569
+ @p.leftovers.each { |l| args << l }
570
+ vals
571
+ rescue CommandlineError => e
572
+ $stderr.puts "Error: #{e.message}."
573
+ $stderr.puts "Try --help for help."
574
+ exit(-1)
575
+ rescue HelpNeeded
576
+ @p.educate
577
+ exit
578
+ rescue VersionNeeded
579
+ puts @p.version
580
+ exit
581
+ end
582
+ end
583
+
584
+ ## Informs the user that their usage of 'arg' was wrong, as detailed by
585
+ ## 'msg', and dies. Example:
586
+ ##
587
+ ## options do
588
+ ## opt :volume, :default => 0.0
589
+ ## end
590
+ ##
591
+ ## die :volume, "too loud" if opts[:volume] > 10.0
592
+ ## die :volume, "too soft" if opts[:volume] < 0.1
593
+ ##
594
+ ## In the one-argument case, simply print that message, a notice
595
+ ## about -h, and die. Example:
596
+ ##
597
+ ## options do
598
+ ## opt :whatever # ...
599
+ ## end
600
+ ##
601
+ ## Trollop::die "need at least one filename" if ARGV.empty?
602
+ def die arg, msg=nil
603
+ if msg
604
+ $stderr.puts "Error: argument --#{@p.specs[arg][:long]} #{msg}."
605
+ else
606
+ $stderr.puts "Error: #{arg}."
607
+ end
608
+ $stderr.puts "Try --help for help."
609
+ exit(-1)
610
+ end
611
+
612
+ module_function :options, :die
613
+
614
+ end # module
@@ -0,0 +1,61 @@
1
+ class Object
2
+ def returning o; yield o; o end # k-combinator
3
+ end
4
+
5
+ module Enumerable
6
+ def count_of(&b); select(&b).size end
7
+ def max_of(&b); map(&b).max end
8
+ def min_of(&b); map(&b).min end
9
+ end
10
+
11
+ class Array
12
+ def uniq_by; inject({}) { |h, o| h[yield(o)] = o; h }.values end
13
+ end
14
+
15
+ class NilClass
16
+ def blank?; true end
17
+ end
18
+
19
+ module Enumerable
20
+ def map_with_index # sigh...
21
+ ret = []
22
+ each_with_index { |e, i| ret << yield(e, i) }
23
+ ret
24
+ end
25
+
26
+ def argfind
27
+ each { |e| x = yield(e); return x if x }
28
+ nil
29
+ end
30
+
31
+ def group_by
32
+ inject({}) do |groups, element|
33
+ (groups[yield(element)] ||= []) << element
34
+ groups
35
+ end
36
+ end if RUBY_VERSION < '1.9'
37
+
38
+ end
39
+
40
+ class Array
41
+ def first_duplicate
42
+ sa = sort
43
+ (1 .. sa.length).argfind { |i| (sa[i] == sa[i - 1]) && sa[i] }
44
+ end
45
+
46
+ def to_h
47
+ Hash[*flatten]
48
+ end
49
+
50
+ def flatten_one_level
51
+ inject([]) do |ret, e|
52
+ case e
53
+ when Array
54
+ ret + e
55
+ else
56
+ ret << e
57
+ end
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,16 @@
1
+ module DitzStr
2
+
3
+ class View
4
+ def self.add_to_view type, &block
5
+ @views ||= {}
6
+ @views[type] ||= []
7
+ @views[type] << block
8
+ end
9
+
10
+ def self.view_additions_for type
11
+ @views ||= {}
12
+ @views[type] || []
13
+ end
14
+ end
15
+
16
+ end