File: lowline.rb

package info (click to toggle)
ditz 0.5-1
  • links: PTS
  • area: main
  • in suites: squeeze, wheezy
  • size: 356 kB
  • ctags: 489
  • sloc: ruby: 3,664; sh: 15; makefile: 12
file content (201 lines) | stat: -rw-r--r-- 4,794 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
require 'tempfile'
require "util"

class Numeric
  def to_pretty_s
    %w(zero one two three four five six seven eight nine ten)[self] || to_s
  end
end

class String
  def dcfirst; self[0..0].downcase + self[1..-1] end
  def blank?; self =~ /\A\s*\z/ end
  def underline; self + "\n" + ("-" * self.length) end
  def pluralize n, b=true
    s = (n == 1 ? self : (self == 'bugfix' ? 'bugfixes' : self + "s")) # oh yeah
    b ? n.to_pretty_s + " " + s : s
  end
  def shortened_email; self =~ /<?(\S+?)@.+/ ? $1 : self end
  def multistrip; strip.gsub(/\n\n+/, "\n\n") end
end

class Array
  def listify prefix=""
    return "" if empty?
    "\n" +
      map_with_index { |x, i| x.to_s.gsub(/^/, "#{prefix}#{i + 1}. ") }.
        join("\n")
  end
end

class Time
  def pretty; strftime "%c" end
  def pretty_date; strftime "%Y-%m-%d" end
  def ago
    diff = (Time.now - self).to_i.abs
    if diff < 60
      "second".pluralize diff
    elsif diff < 60*60*3
      "minute".pluralize(diff / 60)
    elsif diff < 60*60*24*3
      "hour".pluralize(diff / (60*60))
    elsif diff < 60*60*24*7*2
      "day".pluralize(diff / (60*60*24))
    elsif diff < 60*60*24*7*8
      "week".pluralize(diff / (60*60*24*7))
    elsif diff < 60*60*24*7*52
      "month".pluralize(diff / (60*60*24*7*4))
    else
      "year".pluralize(diff / (60*60*24*7*52))
    end
  end
end

module Lowline
  def run_editor
    f = Tempfile.new "ditz"
    yield f
    f.close

    editor = ENV["EDITOR"] || "/usr/bin/vi"
    cmd = "#{editor} #{f.path.inspect}"

    mtime = File.mtime f.path
    system cmd or raise Error, "cannot execute command: #{cmd.inspect}"

    File.mtime(f.path) == mtime ? nil : f.path
  end

  def ask q, opts={}
    default_s = case opts[:default]
      when nil; nil
      when ""; " (enter for none)"
      else; " (enter for #{opts[:default].inspect})"
    end

    tail = case q
      when /[:?]$/; " "
      when /[:?]\s+$/; ""
      else; ": "
    end

    while true
      prompt = [q, default_s, tail].compact.join
      if Ditz::has_readline?
        ans = Readline::readline(prompt)
      else
        print prompt
        ans = STDIN.gets.strip
      end
      if opts[:default]
        ans = opts[:default] if ans.blank?
      else
        next if ans.blank? && !opts[:empty_ok]
      end
      break ans unless (opts[:restrict] && ans !~ opts[:restrict])
    end
  end

  def ask_via_editor q, default=nil
    fn = run_editor do |f|
      f.puts(default || "")
      f.puts q.gsub(/^/, "## ")
      f.puts "##"
      f.puts "## Enter your text above. Lines starting with a '#' will be ignored."
    end
    return unless fn
    IO.read(fn).gsub(/^#.*$/, "").multistrip
  end

  def ask_multiline q
    puts "#{q} (ctrl-d, ., or /stop to stop, /edit to edit, /reset to reset):"
    ans = ""
    while true
      if Ditz::has_readline?
        line = Readline::readline('> ')
      else
        (line = STDIN.gets) && line.strip!
      end
      if line
        if Ditz::has_readline?
          Readline::HISTORY.push(line)
        end
        case line
        when /^\.$/, "/stop"
          break
        when "/reset"
          return ask_multiline(q)
        when "/edit"
          return ask_via_editor(q, ans)
        else
          ans << line + "\n"
        end
      else
        puts
        break
      end
    end
    ans.multistrip
  end

  def ask_yon q
    while true
      print "#{q} (y/n): "
      a = STDIN.gets.strip
      break a if a =~ /^[yn]$/i
    end =~ /y/i
  end

  def ask_for_many plural_name, name=nil
    name ||= plural_name.gsub(/s$/, "")
    stuff = []

    while true
      puts
      puts "Current #{plural_name}:"
      if stuff.empty?
        puts "None!"
      else
        stuff.each_with_index { |c, i| puts "  #{i + 1}) #{c}" }
      end
      puts
      ans = ask "(A)dd #{name}, (r)emove #{name}, or (d)one"
      case ans
      when "a", "A"
        ans = ask "#{name.capitalize} name", ""
        stuff << ans unless ans =~ /^\s*$/
      when "r", "R"
        ans = ask "Remove which #{name}? (1--#{stuff.size})"
        stuff.delete_at(ans.to_i - 1) if ans
      when "d", "D"
        break
      end
    end
    stuff
  end

  def ask_for_selection stuff, name, to_string=:to_s
    puts "Choose a #{name}:"
    stuff.each_with_index do |c, i|
      pretty = case to_string
      when block_given? && to_string # heh
        yield c
      when Symbol
        c.send to_string
      when Proc
        to_string.call c
      else
        raise ArgumentError, "unknown to_string argument type; expecting Proc or Symbol"
      end
      puts "  #{i + 1}) #{pretty}"
    end

    j = while true
      i = ask "#{name.capitalize} (1--#{stuff.size})"
      break i.to_i if i && (1 .. stuff.size).member?(i.to_i)
    end

    stuff[j - 1]
  end
end