doing 1.0.21 → 1.0.22

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a5b37a6be186a84231607095b3d365922e544bd0fe9b2fedb93427e6bbbd82f
4
- data.tar.gz: 8d164c8a14642d66f46cd48e238ea43f1e765ed43c4a689c1600bfb42dd8a8cd
3
+ metadata.gz: 73e09fb9dbc14de53c2464dba86178c402ecdba46d89873d83aea2abe97e1454
4
+ data.tar.gz: d8c1d0a5762a7fbef26522f1664414538647a6fd5b4b5f466844b4a1503cad98
5
5
  SHA512:
6
- metadata.gz: f03dd15248dce1ada9aa541b548768234fb10ae95cecf4424e29c001e9229e19238f121d83377fc81f9543ea88bcfc90c21e816663cad05955f8c4148da8d004
7
- data.tar.gz: caf24a8c97de4c758043e0f6c0fb9fac3bd0f10df9381a124ba89015c541bdbc24a6691c3c5181a4ad49f554d38bdde4b156bd5b8deb36617f4ff6351e341288
6
+ metadata.gz: 968381dd7b6c260a550f6dad755a54f2388baaaaa84ace9a7ea1feafad92b889db04b3084f8236296c4b2bca45613abf2f2d11147b9c0afecf9dd21b869fdaac
7
+ data.tar.gz: f585f589879ea6f4c772a71be98c7d31622eee2c3a6a32b42d268890590f0239fb6755eb75d44bf14cf9d559460190edb0980655c535e75f350970fde1ad11ec
data/README.md CHANGED
@@ -95,7 +95,9 @@ A basic configuration looks like this:
95
95
 
96
96
  ### Per-folder configuration
97
97
 
98
- Any options found in a `.doingrc` anywhere in the hierarchy between your current folder and your home folder will be appended to the base configuration, overriding or extending existing options. This allows you to put a `.doingrc` file into the base of a project and add specific configurations (such as default tags) when working in that project on the command line.
98
+ Any options found in a `.doingrc` anywhere in the hierarchy between your current folder and your home folder will be appended to the base configuration, overriding or extending existing options. This allows you to put a `.doingrc` file into the base of a project and add specific configurations (such as default tags) when working in that project on the command line. These can be cascaded, with the closest `.doingrc` to your current directory taking precedence, though I'm not sure why you'd want to deal with that.
99
+
100
+ This can also be used to define custom HTML output on a per-project basis using the html_template option for custom templates.
99
101
 
100
102
  Any part of the configuration can be copied into these local files and modified. You only need to include the parts you want to change or add.
101
103
 
@@ -550,6 +552,12 @@ Feel free to [poke around](http://github.com/ttscoff/doing/), I'll try to add mo
550
552
 
551
553
  ## Changelog
552
554
 
555
+ #### 1.0.22
556
+
557
+ - Fix handling of "local" config files, allowing per-project configurations
558
+ - Allow cascading of local config files
559
+ - Allow `doing today` and `yesterday` to specify a section
560
+
553
561
  #### 1.0.21
554
562
 
555
563
  - Add legitimate regex search capabilities
data/bin/doing CHANGED
@@ -555,7 +555,7 @@ end
555
555
 
556
556
  desc 'List all entries'
557
557
  long_desc 'The argument can be a section name, @tag(s) or both. "pick" or "choose" as an argument will offer a section menu.'
558
- arg_name 'section [tags]'
558
+ arg_name '[section|@tags]'
559
559
  command :show do |c|
560
560
  c.desc 'Tag boolean (AND,OR,NONE)'
561
561
  c.default_value "OR"
@@ -723,6 +723,11 @@ end
723
723
 
724
724
  desc 'List entries from today'
725
725
  command :today do |c|
726
+ c.desc 'Specify a section'
727
+ c.arg_name 'section_name'
728
+ c.default_value "All"
729
+ c.flag [:s,:section], :default_value => 'All'
730
+
726
731
  c.desc 'Show time intervals on @done tasks'
727
732
  c.default_value true
728
733
  c.switch [:t,:times], :default_value => true
@@ -738,7 +743,7 @@ command :today do |c|
738
743
 
739
744
  options[:t] = true if options[:totals]
740
745
 
741
- puts wwid.today(options[:t],options[:output],{:totals => options[:totals]}).chomp
746
+ puts wwid.today(options[:t],options[:output],{:totals => options[:totals], :section => options[:s]}).chomp
742
747
 
743
748
  end
744
749
  end
@@ -790,9 +795,12 @@ command :on do |c|
790
795
  end
791
796
 
792
797
  desc 'List entries from yesterday'
793
- default_value wwid.current_section
794
- arg_name 'section'
795
798
  command :yesterday do |c|
799
+ c.desc 'Specify a section'
800
+ c.arg_name 'section_name'
801
+ c.default_value "All"
802
+ c.flag [:s,:section], :default_value => 'All'
803
+
796
804
  c.desc 'Output to export format (csv|html|json)'
797
805
  c.flag [:o,:output]
798
806
 
@@ -806,7 +814,7 @@ command :yesterday do |c|
806
814
 
807
815
  c.action do |global_options, options,args|
808
816
  section = args.length > 0 ? args.join(" ") : wwid.current_section
809
- puts wwid.yesterday(section,options[:t],options[:o],{:totals => options[:totals]}).chomp
817
+ puts wwid.yesterday(options[:s],options[:t],options[:o],{:totals => options[:totals]}).chomp
810
818
 
811
819
  end
812
820
  end
@@ -814,7 +822,7 @@ end
814
822
  desc 'Show the last entry'
815
823
  command :last do |c|
816
824
  c.desc 'Specify a section'
817
- c.default_value wwid.current_section
825
+ c.default_value "All"
818
826
  c.flag [:s,:section]
819
827
 
820
828
  c.action do |global_options,options,args|
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '1.0.21'
2
+ VERSION = '1.0.22'
3
3
  end
@@ -3,6 +3,9 @@
3
3
  require 'deep_merge'
4
4
  require 'pp'
5
5
 
6
+ ##
7
+ ## @brief String helpers
8
+ ##
6
9
  class String
7
10
  def cap_first
8
11
  self.sub(/^\w/) do |m|
@@ -10,6 +13,11 @@ class String
10
13
  end
11
14
  end
12
15
 
16
+ ##
17
+ ## @brief Turn raw urls into HTML links
18
+ ##
19
+ ## @param opt (Hash) Additional Options
20
+ ##
13
21
  def link_urls(opt={})
14
22
  opt[:format] ||= :html
15
23
  if opt[:format] == :html
@@ -31,20 +39,32 @@ class String
31
39
  end
32
40
  end
33
41
 
42
+ ##
43
+ ## @brief Main "What Was I Doing" methods
44
+ ##
34
45
  class WWID
35
46
  attr_accessor :content, :sections, :current_section, :doing_file, :config, :user_home, :default_config_file, :results
36
47
 
48
+ ##
49
+ ## @brief Initializes the object.
50
+ ##
37
51
  def initialize
38
52
  @content = {}
39
53
  @doingrc_needs_update = false
40
54
  @default_config_file = '.doingrc'
41
55
  end
42
56
 
57
+ ##
58
+ ## @brief Read user configuration and merge with defaults
59
+ ##
60
+ ## @param opt (Hash) Additional Options
61
+ ##
43
62
  def configure(opt={})
44
63
  @timers = {}
45
64
  @config_file == File.join(@user_home, @default_config_file)
46
65
 
47
- @config = read_config
66
+ read_config
67
+
48
68
  user_config = @config.dup
49
69
  @results = []
50
70
 
@@ -110,10 +130,9 @@ class WWID
110
130
 
111
131
  @config[:include_notes] ||= true
112
132
 
113
- File.open(@config_file, 'w') { |yf| YAML::dump(@config, yf) } if @config != user_config || @doingrc_needs_update
114
-
133
+ File.open(@config_file, 'w') { |yf| YAML::dump(@config, yf) } unless @config == user_config
115
134
 
116
- @config = @config.deep_merge(@local_config)
135
+ @config = @local_config.deep_merge(@config)
117
136
 
118
137
  @current_section = @config['current_section']
119
138
  @default_template = @config['templates']['default']['template']
@@ -121,9 +140,16 @@ class WWID
121
140
 
122
141
  end
123
142
 
124
- def init_doing_file(input=nil)
143
+ ##
144
+ ## @brief Initializes the doing file.
145
+ ##
146
+ ## @param path (String) Override path to a doing file, optional
147
+ ##
148
+ def init_doing_file(path=nil)
125
149
  @doing_file = File.expand_path(@config['doing_file'])
126
150
 
151
+ input = path
152
+
127
153
  if input.nil?
128
154
  create(@doing_file) unless File.exists?(@doing_file)
129
155
  input = IO.read(@doing_file)
@@ -178,14 +204,27 @@ class WWID
178
204
  }
179
205
  end
180
206
 
207
+ ##
208
+ ## @brief Return the contents of the HAML template for HTML output
209
+ ##
210
+ ## @return (String) HAML template
211
+ ##
181
212
  def haml_template
182
213
  IO.read(File.join(File.dirname(__FILE__), '../templates/doing.haml'))
183
214
  end
184
215
 
216
+ ##
217
+ ## @brief Return the contents of the CSS template for HTML output
218
+ ##
219
+ ## @return (String) CSS template
220
+ ##
185
221
  def css_template
186
222
  IO.read(File.join(File.dirname(__FILE__), '../templates/doing.css'))
187
223
  end
188
224
 
225
+ ##
226
+ ## @brief Create a new doing file
227
+ ##
189
228
  def create(filename=nil)
190
229
  if filename.nil?
191
230
  filename = @doing_file
@@ -197,37 +236,51 @@ class WWID
197
236
  end
198
237
  end
199
238
 
239
+ ##
240
+ ## @brief Finds a project-specific configuration file
241
+ ##
242
+ ## @return (String) A file path
243
+ ##
200
244
  def find_local_config
201
245
 
202
246
  config = {}
203
247
  dir = Dir.pwd
204
248
 
205
- local_config_file = nil
249
+ local_config_files = []
206
250
 
207
251
  while (dir != '/' && (dir =~ /[A-Z]:\//) == nil)
208
252
  if File.exists? File.join(dir, @default_config_file)
209
- return File.join(dir, @default_config_file)
253
+ local_config_files.push(File.join(dir, @default_config_file))
210
254
  end
211
255
 
212
256
  dir = File.dirname(dir)
213
257
  end
214
258
 
215
- false
259
+ local_config_files
216
260
  end
217
261
 
262
+ ##
263
+ ## @brief Reads a configuration.
264
+ ##
218
265
  def read_config
219
266
  if Dir.respond_to?('home')
220
267
  @config_file = File.join(Dir.home, @default_config_file)
221
268
  else
222
269
  @config_file = File.join(File.expand_path("~"), @default_config_file)
223
270
  end
224
- @doingrc_needs_update = true if File.exists? @config_file
225
- additional = find_local_config
271
+ # @doingrc_needs_update = true if File.exists? @config_file
272
+ additional_configs = find_local_config
226
273
 
227
274
  begin
275
+ @local_config = {}
276
+
228
277
  @config = YAML.load_file(@config_file) || {} if File.exists?(@config_file)
229
- @local_config = YAML.load_file(additional) || {} if additional
230
- @config.deep_merge(@local_config)
278
+ additional_configs.each { |cfg|
279
+ new_config = YAML.load_file(cfg) || {} if cfg
280
+ @local_config = @local_config.deep_merge(new_config)
281
+ }
282
+
283
+ # @config.deep_merge(@local_config)
231
284
  rescue
232
285
  @config = {}
233
286
  @local_config = {}
@@ -235,6 +288,11 @@ class WWID
235
288
  end
236
289
  end
237
290
 
291
+ ##
292
+ ## @brief Create a process for an editor and wait for the file handle to return
293
+ ##
294
+ ## @param input (String) Text input for editor
295
+ ##
238
296
  def fork_editor(input="")
239
297
  tmpfile = Tempfile.new(['doing','.md'])
240
298
 
@@ -268,11 +326,13 @@ class WWID
268
326
  input
269
327
  end
270
328
 
271
- # This takes a multi-line string and formats it as an entry
272
- # Params:
273
- # +input+:: String
274
- # Returns:
275
- # [title(String), note(Array)]
329
+ #
330
+ # @brief Takes a multi-line string and formats it as an entry
331
+ #
332
+ # @return (Array) [(String)title, (Array)note]
333
+ #
334
+ # @param input (String) The string to parse
335
+ #
276
336
  def format_input(input)
277
337
  raise "No content in entry" if input.nil? || input.strip.length == 0
278
338
  input_lines = input.split(/[\n\r]+/)
@@ -287,11 +347,17 @@ class WWID
287
347
  [title, note]
288
348
  end
289
349
 
290
- # Converts `input` string into a Time object when `input` takes on the
291
- # following formats:
292
- # - interval format e.g. '1d2h30m', '45m' etc.
293
- # - a semantic phrase e.g. 'yesterday 5:30pm'
294
- # - a strftime e.g. '2016-03-15 15:32:04 PDT'
350
+ #
351
+ # @brief Converts input string into a Time object when input takes on the
352
+ # following formats:
353
+ # - interval format e.g. '1d2h30m', '45m' etc.
354
+ # - a semantic phrase e.g. 'yesterday 5:30pm'
355
+ # - a strftime e.g. '2016-03-15 15:32:04 PDT'
356
+ #
357
+ # @param input (String) String to chronify
358
+ #
359
+ # @return (DateTime) result
360
+ #
295
361
  def chronify(input)
296
362
  now = Time.now
297
363
  raise "Invalid time expression #{input.inspect}" if input.to_s.strip == ""
@@ -312,10 +378,15 @@ class WWID
312
378
  end
313
379
  end
314
380
 
315
- # Converts simple strings into seconds that can be added to a Time object
316
- # Params:
317
- # +qty+:: HH:MM or XX[dhm][[XXhm][XXm]] (1d2h30m, 45m, 1.5d, 1h20m, etc.)
318
- # Returns seconds (Integer)
381
+ #
382
+ # @brief Converts simple strings into seconds that can be added to a Time
383
+ # object
384
+ #
385
+ # @param qty (String) HH:MM or XX[dhm][[XXhm][XXm]] (1d2h30m, 45m,
386
+ # 1.5d, 1h20m, etc.)
387
+ #
388
+ # @return (Integer) seconds
389
+ #
319
390
  def chronify_qty(qty)
320
391
  minutes = 0
321
392
  if qty.strip =~ /^(\d+):(\d\d)$/
@@ -339,14 +410,30 @@ class WWID
339
410
  minutes * 60
340
411
  end
341
412
 
413
+ ##
414
+ ## @brief List sections
415
+ ##
416
+ ## @return (Array) section titles
417
+ ##
342
418
  def sections
343
419
  @content.keys
344
420
  end
345
421
 
422
+ ##
423
+ ## @brief Adds a section.
424
+ ##
425
+ ## @param title (String) The new section title
426
+ ##
346
427
  def add_section(title)
347
428
  @content[title.cap_first] = {'original' => "#{title}:", 'items' => []}
348
429
  end
349
430
 
431
+ ##
432
+ ## @brief Attempt to match a string with an existing section
433
+ ##
434
+ ## @param frag (String) The user-provided string
435
+ ## @param guessed (Boolean) already guessed and failed
436
+ ##
350
437
  def guess_section(frag,guessed=false)
351
438
  return "All" if frag =~ /all/i
352
439
  sections.each {|section| return section.cap_first if frag.downcase == section.downcase }
@@ -377,6 +464,12 @@ class WWID
377
464
  section ? section.cap_first : guessed
378
465
  end
379
466
 
467
+ ##
468
+ ## @brief Attempt to match a string with an existing view
469
+ ##
470
+ ## @param frag (String) The user-provided string
471
+ ## @param guessed (Boolean) already guessed
472
+ ##
380
473
  def guess_view(frag,guessed=false)
381
474
  views.each {|view| return view if frag.downcase == view.downcase}
382
475
  view = false
@@ -399,6 +492,13 @@ class WWID
399
492
  view
400
493
  end
401
494
 
495
+ ##
496
+ ## @brief Adds an entry
497
+ ##
498
+ ## @param title (String) The entry title
499
+ ## @param section (String) The section to add to
500
+ ## @param opt (Hash) Additional Options {:date, :note, :back, :timed}
501
+ ##
402
502
  def add_item(title,section=nil,opt={})
403
503
  section ||= @current_section
404
504
  add_section(section) unless @content.has_key?(section)
@@ -443,6 +543,12 @@ class WWID
443
543
  @results.push(%Q{Added "#{entry['title']}" to #{section}})
444
544
  end
445
545
 
546
+ ##
547
+ ## @brief Return the content of the last note for a given section
548
+ ##
549
+ ## @param section (String) The section to retrieve from, default
550
+ ## Currently
551
+ ##
446
552
  def last_note(section=@current_section)
447
553
  section = guess_section(section)
448
554
  if @content.has_key?(section)
@@ -454,6 +560,11 @@ class WWID
454
560
  end
455
561
  end
456
562
 
563
+ ##
564
+ ## @brief Tag the last entry or X entries
565
+ ##
566
+ ## @param opt (Hash) Additional Options
567
+ ##
457
568
  def tag_last(opt={})
458
569
  opt[:section] ||= @current_section
459
570
  opt[:count] ||= 1
@@ -555,6 +666,13 @@ class WWID
555
666
  write(@doing_file)
556
667
  end
557
668
 
669
+ ##
670
+ ## @brief Add a note to the last entry in a section
671
+ ##
672
+ ## @param section (String) The section, default Currently
673
+ ## @param note (String) The note to add
674
+ ## @param replace (Bool) Should replace existing note
675
+ ##
558
676
  def note_last(section, note, replace=false)
559
677
  section = guess_section(section)
560
678
 
@@ -590,10 +708,17 @@ class WWID
590
708
  end
591
709
  end
592
710
 
593
- # accepts one tag and the raw text of a new item
594
- # if the passed tag is on any item, it's replaced with @done
595
- # if new_item is not nil, it's tagged with the passed tag and inserted
596
- # This is for use where only one instance of a given tag should exist (@meanwhile)
711
+
712
+ #
713
+ # @brief Accepts one tag and the raw text of a new item if the passed tag
714
+ # is on any item, it's replaced with @done. if new_item is not
715
+ # nil, it's tagged with the passed tag and inserted. This is for
716
+ # use where only one instance of a given tag should exist
717
+ # (@meanwhile)
718
+ #
719
+ # @param tag (String) Tag to replace
720
+ # @param opt (Hash) Additional Options
721
+ #
597
722
  def stop_start(tag,opt={})
598
723
  opt[:section] ||= @current_section
599
724
  opt[:archive] ||= false
@@ -645,6 +770,11 @@ class WWID
645
770
  write(@doing_file)
646
771
  end
647
772
 
773
+ ##
774
+ ## @brief Write content to file or STDOUT
775
+ ##
776
+ ## @param file (String) The filepath to write to
777
+ ##
648
778
  def write(file=nil)
649
779
  unless @other_content_top
650
780
  output = ""
@@ -670,6 +800,11 @@ class WWID
670
800
  end
671
801
  end
672
802
 
803
+ ##
804
+ ## @brief Restore a backed up version of a file
805
+ ##
806
+ ## @param file (String) The filepath to restore
807
+ ##
673
808
  def restore_backup(file)
674
809
  if File.exists?(file+"~")
675
810
  puts file+"~"
@@ -679,6 +814,11 @@ class WWID
679
814
  end
680
815
 
681
816
 
817
+ ##
818
+ ## @brief Generate a menu of sections and allow user selection
819
+ ##
820
+ ## @return (String) The selected section name
821
+ ##
682
822
  def choose_section
683
823
  sections.each_with_index {|section, i|
684
824
  puts "% 3d: %s" % [i+1, section]
@@ -689,10 +829,20 @@ class WWID
689
829
  return sections[num.to_i - 1]
690
830
  end
691
831
 
832
+ ##
833
+ ## @brief List available views
834
+ ##
835
+ ## @return (Array) View names
836
+ ##
692
837
  def views
693
838
  @config.has_key?('views') ? @config['views'].keys : []
694
839
  end
695
840
 
841
+ ##
842
+ ## @brief Generate a menu of views and allow user selection
843
+ ##
844
+ ## @return (String) The selected view name
845
+ ##
696
846
  def choose_view
697
847
  views.each_with_index {|view, i|
698
848
  puts "% 3d: %s" % [i+1, view]
@@ -703,6 +853,11 @@ class WWID
703
853
  return views[num.to_i - 1]
704
854
  end
705
855
 
856
+ ##
857
+ ## @brief Gets a view from configuration
858
+ ##
859
+ ## @param title (String) The title of the view to retrieve
860
+ ##
706
861
  def get_view(title)
707
862
  if @config['views'].has_key?(title)
708
863
  return @config['views'][title]
@@ -710,6 +865,12 @@ class WWID
710
865
  false
711
866
  end
712
867
 
868
+ ##
869
+ ## @brief Overachieving function for displaying contents of a section.
870
+ ## This is a fucking mess. I mean, Jesus Christ.
871
+ ##
872
+ ## @param opt (Hash) Additional Options
873
+ ##
713
874
  def list_section(opt={})
714
875
  opt[:count] ||= 0
715
876
  count = opt[:count] - 1
@@ -1084,6 +1245,16 @@ EOTEMPLATE
1084
1245
  return out
1085
1246
  end
1086
1247
 
1248
+ ##
1249
+ ## @brief Move entries from a section to Archive or other specified
1250
+ ## section
1251
+ ##
1252
+ ## @param section (String) The source section
1253
+ ## @param count (Integer) The count
1254
+ ## @param destination (String) The destination section
1255
+ ## @param tags (Array) Tags to archive
1256
+ ## @param bool (String) Tag boolean combinator
1257
+ ##
1087
1258
  def archive(section="Currently",count=5,destination=nil,tags=nil,bool=nil,export=nil)
1088
1259
 
1089
1260
  section = choose_section if section.nil? || section =~ /choose/i
@@ -1113,6 +1284,13 @@ EOTEMPLATE
1113
1284
  end
1114
1285
  end
1115
1286
 
1287
+ ##
1288
+ ## @brief Helper function, performs the actual archiving
1289
+ ##
1290
+ ## @param section (String) The source section
1291
+ ## @param destination (String) The destination section
1292
+ ## @param opt (Hash) Additional Options
1293
+ ##
1116
1294
  def do_archive(section, destination, opt={})
1117
1295
  count = opt[:count] || 5
1118
1296
  tags = opt[:tags] || []
@@ -1176,6 +1354,11 @@ EOTEMPLATE
1176
1354
  end
1177
1355
  end
1178
1356
 
1357
+ ##
1358
+ ## @brief A dictionary of colors
1359
+ ##
1360
+ ## @return (String) ANSI escape sequence
1361
+ ##
1179
1362
  def colors
1180
1363
  color = {}
1181
1364
  color['black'] = "\033[0;0;30m"
@@ -1221,18 +1404,28 @@ EOTEMPLATE
1221
1404
  end
1222
1405
 
1223
1406
 
1224
- def all(order="")
1225
- order = "asc" if order == ""
1226
- cfg = @config['templates']['default_template']
1227
- list_section({:section => @current_section, :wrap_width => cfg['wrap_width'], :count => 0, :format => cfg['date_format'], :template => cfg['template'], :order => order})
1228
- end
1229
-
1407
+ ##
1408
+ ## @brief Show all entries from the current day
1409
+ ##
1410
+ ## @param times (Boolean) show times
1411
+ ## @param output (String) output format
1412
+ ## @param opt (Hash) Options
1413
+ ##
1230
1414
  def today(times=true,output=nil,opt={})
1231
1415
  opt[:totals] ||= false
1232
1416
  cfg = @config['templates']['today']
1233
- list_section({:section => @current_section, :wrap_width => cfg['wrap_width'], :count => 0, :format => cfg['date_format'], :template => cfg['template'], :order => "asc", :today => true, :times => times, :output => output, :totals => opt[:totals]})
1417
+ list_section({:section => opt[:section], :wrap_width => cfg['wrap_width'], :count => 0, :format => cfg['date_format'], :template => cfg['template'], :order => "asc", :today => true, :times => times, :output => output, :totals => opt[:totals]})
1234
1418
  end
1235
1419
 
1420
+ ##
1421
+ ## @brief Display entries within a date range
1422
+ ##
1423
+ ## @param dates (Array) [start, end]
1424
+ ## @param section (String) The section
1425
+ ## @param times (Bool) Show times
1426
+ ## @param output (String) Output format
1427
+ ## @param opt (Hash) Additional Options
1428
+ ##
1236
1429
  def list_date(dates,section,times=nil,output=nil,opt={})
1237
1430
  opt[:totals] ||= false
1238
1431
  section = guess_section(section)
@@ -1244,12 +1437,27 @@ EOTEMPLATE
1244
1437
  list_section({:section => section, :count => 0, :order => "asc", :date_filter => dates, :times => times, :output => output, :totals => opt[:totals] })
1245
1438
  end
1246
1439
 
1440
+ ##
1441
+ ## @brief Show entries from the previous day
1442
+ ##
1443
+ ## @param section (String) The section
1444
+ ## @param times (Bool) Show times
1445
+ ## @param output (String) Output format
1446
+ ## @param opt (Hash) Additional Options
1447
+ ##
1247
1448
  def yesterday(section,times=nil,output=nil,opt={})
1248
1449
  opt[:totals] ||= false
1249
1450
  section = guess_section(section)
1250
1451
  list_section({:section => section, :count => 0, :order => "asc", :yesterday => true, :times => times, :output => output, :totals => opt[:totals] })
1251
1452
  end
1252
1453
 
1454
+ ##
1455
+ ## @brief Show recent entries
1456
+ ##
1457
+ ## @param count (Integer) The number to show
1458
+ ## @param section (String) The section to show from, default Currently
1459
+ ## @param opt (Hash) Additional Options
1460
+ ##
1253
1461
  def recent(count=10,section=nil,opt={})
1254
1462
  times = opt[:t] || true
1255
1463
  opt[:totals] ||= false
@@ -1259,6 +1467,12 @@ EOTEMPLATE
1259
1467
  list_section({:section => section, :wrap_width => cfg['wrap_width'], :count => count, :format => cfg['date_format'], :template => cfg['template'], :order => "asc", :times => times, :totals => opt[:totals] })
1260
1468
  end
1261
1469
 
1470
+ ##
1471
+ ## @brief Show the last entry
1472
+ ##
1473
+ ## @param times (Bool) Show times
1474
+ ## @param section (String) Section to pull from, default Currently
1475
+ ##
1262
1476
  def last(times=true,section=nil)
1263
1477
  section ||= @current_section
1264
1478
  section = guess_section(section)
@@ -1266,6 +1480,11 @@ EOTEMPLATE
1266
1480
  list_section({:section => section, :wrap_width => cfg['wrap_width'], :count => 1, :format => cfg['date_format'], :template => cfg['template'], :times => times})
1267
1481
  end
1268
1482
 
1483
+ ##
1484
+ ## @brief Get total elapsed time for all tags in selection
1485
+ ##
1486
+ ## @param format (String) return format (html, json, or text)
1487
+ ##
1269
1488
  def tag_times(format="text")
1270
1489
 
1271
1490
  return "" if @timers.empty?
@@ -1335,39 +1554,43 @@ EOS
1335
1554
  end
1336
1555
  end
1337
1556
 
1338
- # Uses autotag: configuration to turn keywords into tags for time tracking.
1339
- # Does not repeat tags in a title, and only converts the first instance of
1340
- # an untagged keyword
1341
- def autotag(title)
1342
- return unless title
1557
+ # @brief Uses 'autotag' configuration to turn keywords into tags for time tracking.
1558
+ # Does not repeat tags in a title, and only converts the first instance of an
1559
+ # untagged keyword
1560
+ #
1561
+ # @param text (String) The text to tag
1562
+ #
1563
+ def autotag(text)
1564
+ return unless text
1343
1565
  @config['autotag']['whitelist'].each {|tag|
1344
- title.sub!(/(?<!@)(#{tag.strip})\b/i) do |m|
1566
+ text.sub!(/(?<!@)(#{tag.strip})\b/i) do |m|
1345
1567
  m.downcase! if tag =~ /[a-z]/
1346
1568
  "@#{m}"
1347
- end unless title =~ /@#{tag}\b/i
1569
+ end unless text =~ /@#{tag}\b/i
1348
1570
  }
1349
1571
  tail_tags = []
1350
1572
  @config['autotag']['synonyms'].each {|tag, v|
1351
1573
  v.each {|word|
1352
- if title =~ /\b#{word}\b/i
1574
+ if text =~ /\b#{word}\b/i
1353
1575
  tail_tags.push(tag)
1354
1576
  end
1355
1577
  }
1356
1578
  }
1357
1579
  if tail_tags.length > 0
1358
- title + ' ' + tail_tags.uniq.map {|t| '@'+t }.join(' ')
1580
+ text + ' ' + tail_tags.uniq.map {|t| '@'+t }.join(' ')
1359
1581
  else
1360
- title
1582
+ text
1361
1583
  end
1362
1584
  end
1363
1585
 
1364
- def autotag_item(item)
1365
- item['title'] = autotag(item['title'])
1366
- item
1367
- end
1368
-
1369
1586
  private
1370
1587
 
1588
+ ##
1589
+ ## @brief Gets the interval between entry's start date and @done date
1590
+ ##
1591
+ ## @param item (Hash) The entry
1592
+ ## @param formatted (Bool) Return human readable time (default seconds)
1593
+ ##
1371
1594
  def get_interval(item, formatted=true)
1372
1595
  done = nil
1373
1596
  start = nil
@@ -1400,6 +1623,11 @@ EOS
1400
1623
  seconds > 0 ? "%02d:%02d:%02d" % fmt_time(seconds) : false
1401
1624
  end
1402
1625
 
1626
+ ##
1627
+ ## @brief Format human readable time from seconds
1628
+ ##
1629
+ ## @param seconds The seconds
1630
+ ##
1403
1631
  def fmt_time(seconds)
1404
1632
  if seconds.nil?
1405
1633
  return [0, 0, 0]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doing
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.21
4
+ version: 1.0.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra