Class: TodoRb

Inherits:
Object
  • Object
show all
Defined in:
lib/todo.rb.rb,
lib/todo.rb/version.rb

Constant Summary collapse

TAG_REGEX =
/[@\+]\S+/
VERSION =
'0.2.4'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ TodoRb

Returns a new instance of TodoRb.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/todo.rb.rb', line 9

def initialize(opts={})

  defaults = { 
    todo_file: 'todo.txt',
    done_file: 'done.txt'
  }
  @opts = defaults.merge opts
  @formatter = {
    color: COLORIZER,
    nocolor: "#{COLORIZER} --no-color",
    html: HTML
  }[@opts[:formatter]]

  @todo_file = @opts[:todo_file]
  @backup_file = ".#{@todo_file}.bkp"
  @done_file = @opts[:done_file]
  make_files
end

Instance Attribute Details

#backup_fileObject

Returns the value of attribute backup_file.



7
8
9
# File 'lib/todo.rb.rb', line 7

def backup_file
  @backup_file
end

#done_fileObject

Returns the value of attribute done_file.



7
8
9
# File 'lib/todo.rb.rb', line 7

def done_file
  @done_file
end

#formatterObject

Returns the value of attribute formatter.



7
8
9
# File 'lib/todo.rb.rb', line 7

def formatter
  @formatter
end

#todo_fileObject

Returns the value of attribute todo_file.



7
8
9
# File 'lib/todo.rb.rb', line 7

def todo_file
  @todo_file
end

Class Method Details

.expand_tag(t) ⇒ Object



171
172
173
174
175
176
177
178
179
180
# File 'lib/todo.rb.rb', line 171

def self.expand_tag(t)
  return unless t
  re = /^#{Regexp.escape(t)}/
  match = new.get_report_data.keys.detect {|key| key =~ re} 
  if match && match != t
    match
  else
    t
  end
end

Instance Method Details

#backupObject



37
38
39
# File 'lib/todo.rb.rb', line 37

def backup
  `cp #{todo_file} #{backup_file}`
end

#diffObject



64
65
66
67
# File 'lib/todo.rb.rb', line 64

def diff
  return unless File.exist?(backup_file)
  exec "diff #{backup_file} #{todo_file}"
end

#ed_command!(command, *input_text) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/todo.rb.rb', line 41

def ed_command! command, *input_text
  backup
  text = input_text.empty? ? nil : "\n#{input_text.join(' ')}\n."
  IO.popen("ed -s #{todo_file}", 'w') {|pipe|
    script = <<END
#{command}#{text}
wq
END
    pipe.puts script
    pipe.close
  }
  exec "diff #{backup_file} #{todo_file}"
end

#external_edit(range) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/todo.rb.rb', line 118

def external_edit(range)
  require 'tempfile'
  f = Tempfile.new('todo.rb')
  `sed -n '#{range}p' #{todo_file} > #{f.path}`
  system("#{ENV['EDITOR']}  #{f.path}")
  new_text = File.read(f.path).strip
  range.inspect
  if range != ""
    ed_command! "#{range}c", new_text
  else
    `cp #{f.path} #{todo_file}`
  end
end

#filter(opts = {}) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/todo.rb.rb', line 69

def filter(opts={})
  defaults = {list_file: todo_file, no_exec: false}
  if opts[:list]
    opts[:list_file] = opts[:list] == :todo ? todo_file : done_file
  end
  opts = defaults.merge opts
  tag = opts[:tag]

  # note don't put /< before the grep arg
  grep_filter = tag ? " | grep -i '#{tag}\\>' " : ""
  script = <<END
cat -n #{opts[:list_file]} #{grep_filter} | #{formatter} #{tag ? "'#{tag}'" : ''}
END
  if opts[:no_exec] # just return for further processing
    script
  else
    exec(script)
  end
end

#get_report_dataObject



157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/todo.rb.rb', line 157

def get_report_data 
  [:todo, :done].
    select {|a| File.exist?(send("#{a}_file"))}.
    inject({}) {|m, list|
      file = "#{list}_file"
      File.read(send(file)).scan(TAG_REGEX).group_by {|t| t}.
        map {|k, v|
          m[k] ||= {todo:0,done:0,priority:0}
          m[k][list] = (m[k][list] || 0) + v.size
        }
      m
    }
end

#list_all(tag = nil) ⇒ Object



89
90
91
92
93
# File 'lib/todo.rb.rb', line 89

def list_all tag=nil
  a = filter tag:tag, list_file:todo_file, no_exec:true
  b = filter tag:tag, list_file:done_file, no_exec:true
  exec ["echo 'todo'", a, "echo 'done'", b].join("\n")
end

#make_filesObject



28
29
30
31
32
33
34
35
# File 'lib/todo.rb.rb', line 28

def make_files
  [todo_file, done_file].each do |f|
    if !File.exist?(f)
      $stderr.puts "Missing a #{f} file. Creating."
      `touch #{f}`
    end
  end
end

#mark_done!(range) ⇒ Object



95
96
97
98
99
100
101
102
103
104
# File 'lib/todo.rb.rb', line 95

def mark_done! range
  return unless range =~ /\S/
  backup
  exec <<END
cat #{todo_file} | sed -n '#{range}p' | 
awk '{print d " " $0}' "d=$(date +'%Y-%m-%d')" >> #{done_file}
echo "#{range}d\nwq\n" | ed -s #{todo_file} 
diff #{backup_file} #{todo_file}
END
end

#mark_undone!(range) ⇒ Object



106
107
108
109
110
111
112
113
114
115
# File 'lib/todo.rb.rb', line 106

def mark_undone! range
  return unless range =~ /\S/
  backup
  exec <<END
cat #{done_file} | sed -n '#{range}p' | 
ruby -n -e  'puts $_.split(" ", 2)[1]'  >> #{todo_file}
echo "#{range}d\nwq\n" | ed -s #{done_file} 
diff #{backup_file} #{todo_file}
END
end

#reportObject



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/todo.rb.rb', line 134

def report
  report_data = get_report_data 
  # count priority items per tag
  File.readlines(todo_file).inject(report_data) {|report_data, line|
    line.scan(TAG_REGEX).each {|tag|
      report_data[tag][:priority] ||= 0
      if line =~ /!/
        report_data[tag][:priority] = report_data[tag][:priority] + 1
      end
    }; report_data
  }
  longest_tag_len = report_data.keys.reduce(0) {|max, key| [max, key.length].max} + 1
  placeholders = "%#{longest_tag_len}s %5s %5s %5s" 
  headers = %w(tag pri todo done)
  IO.popen(formatter, 'w') {|pipe|
    pipe.puts(placeholders % headers)
    pipe.puts placeholders.scan(/\d+/).map {|a|'-'*(a.to_i)}.join(' ')
    report_data.keys.sort_by {|k| k.downcase}.each {|k|
      pipe.puts placeholders % [k, report_data[k][:priority], report_data[k][:todo], report_data[k][:done]].map {|x| x == 0 ? ' ' : x}
    }
  }
end

#revertObject



55
56
57
58
59
60
61
62
# File 'lib/todo.rb.rb', line 55

def revert
  return unless File.exist?(backup_file)
  exec <<END
mv #{todo_file} #{backup_file}.2
mv #{backup_file} #{todo_file}
mv #{backup_file}.2 #{backup_file}
END
end