doing 1.0.64 → 1.0.65

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: 6e6ebff7b78368227b7642297b5b88c8f018f0a9049f42478fc070f545421b1c
4
- data.tar.gz: bff5c3852e60db87cacaba489f30fcf93fbdb01a8b7e4cba5fd06b6fc23db936
3
+ metadata.gz: a774718572df78395293b6294bcfa4bac94cfe2cde0ffec43e8bbea60b874534
4
+ data.tar.gz: fba4b65439084eae5b291bd65f5a1d14d49e5b5c4c8b70abd5e8f73fa39b3545
5
5
  SHA512:
6
- metadata.gz: 3c987d7c4a54bb331a3d9db464c5e35b86b1bcc777418547067b8f3bf609756663990c42b53b12d0f36a536f86b3041943eacd539d4d0cf8d1610ff7f3333801
7
- data.tar.gz: 514fa3c1e8acefc9ebfde3e71e517918648b57c6b52c6d2c86bc9fe79d555d158edae4a9a2dc54c91bbfc32962280e328d97e26875114d4e1b0c98f693923b04
6
+ metadata.gz: 01bf52dbc6e7077e6ff2a67ab22504dda4be927f31da8be7e5383136b5cac500cd7920203b7383ebe302af5ddce375e0ee7389273a275edfde27971de8ae87bb
7
+ data.tar.gz: 79e7b8dcf00223118a0e3f5bb648ed33e920dc915909f62d1c21f2a19332f3d35336d3e5ca85a31632416b9fb9364d58db2fb6a4f90e7a200bc7cb706f76e14b
data/README.md CHANGED
@@ -29,7 +29,7 @@ _Side note:_ I actually use the library behind this utility as part of another s
29
29
 
30
30
  ## Installation
31
31
 
32
- The current version of `doing` is <!--VER-->1.0.63<!--END VER-->.
32
+ The current version of `doing` is <!--VER-->1.0.64<!--END VER-->.
33
33
 
34
34
  $ [sudo] gem install doing
35
35
 
@@ -595,6 +595,29 @@ Example: Archive all Currently items for _@client_ that are marked _@done_
595
595
 
596
596
  doing archive @client @done
597
597
 
598
+ ##### Importing
599
+
600
+ Doing can currently only import tasks from Timing.app reports. If you want to sync up your Doing file with Timing's tracking:
601
+
602
+ 1. Open Timing and go to Reports
603
+ 2. Set the date span you want to import into doing
604
+ 3. Group by Project, Then by None
605
+ 4. Include Tasks with Title, (not as subgroup), Timespan, and Notes
606
+ 5. Uncheck App Usage
607
+ 6. Set File Format to JSON and Duration format to "XX:YY:ZZ"
608
+ 7. Include short entries if desired
609
+ 8. Export the report to a new file
610
+
611
+ Now you can run `doing import --type timing -s SECTION PATH`, where SECTION is the name of the section you want to import the entries to (defauts to Currently), and PATH is the path to the JSON file. You can also add a tag (or tags) to all entries, or a custom prefix.
612
+
613
+ (`--type timing` is the only option right now, so it doesn't need to be included)
614
+
615
+ # Import entries to Projects section and add @timing to all new entries
616
+ doing import -s Projects --tag=timing "~/Desktop/All Activities.json"
617
+
618
+ # Import to default section (Currently) and prefix entries with '[Imported]'
619
+ doing import --prefix="[Imported]" "~/Desktop/All Activities.json"
620
+
598
621
  ---
599
622
 
600
623
  ## Extras
data/bin/doing CHANGED
@@ -1394,10 +1394,10 @@ end
1394
1394
  desc 'Import entries from an external source'
1395
1395
  long_desc 'Imports entries from other sources. Currently only handles JSON reports exported from Timing.app.'
1396
1396
  arg_name 'PATH'
1397
- command [:import] do |c|
1397
+ command :import do |c|
1398
1398
  c.desc 'Import type'
1399
1399
  c.arg_name 'TYPE'
1400
- c.flag [:type], default_value: 'timing'
1400
+ c.flag :type, default_value: 'timing'
1401
1401
 
1402
1402
  c.desc 'Target section'
1403
1403
  c.arg_name 'NAME'
@@ -1405,11 +1405,14 @@ command [:import] do |c|
1405
1405
 
1406
1406
  c.desc 'Tag all imported entries'
1407
1407
  c.arg_name 'TAGS'
1408
- c.flag [:tag]
1408
+ c.flag :tag
1409
1409
 
1410
1410
  c.desc 'Prefix entries with'
1411
1411
  c.arg_name 'PREFIX'
1412
- c.flag [:prefix]
1412
+ c.flag :prefix
1413
+
1414
+ c.desc 'Allow entries that overlap existing times'
1415
+ c.switch [:overlap], negatable: true
1413
1416
 
1414
1417
  c.action do |_global_options, options, args|
1415
1418
 
@@ -1417,7 +1420,7 @@ command [:import] do |c|
1417
1420
 
1418
1421
  if options[:type] =~ /^tim/i
1419
1422
  args.each do |path|
1420
- wwid.import_timing(path, { section: section, tag: options[:tag], prefix: options[:prefix] })
1423
+ wwid.import_timing(path, { section: section, tag: options[:tag], prefix: options[:prefix], no_overlap: !options[:overlap] })
1421
1424
  wwid.write(wwid.doing_file)
1422
1425
  end
1423
1426
  else
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '1.0.64'
2
+ VERSION = '1.0.65'
3
3
  end
data/lib/doing/wwid.rb CHANGED
@@ -7,7 +7,7 @@ require 'pp'
7
7
  ##
8
8
  ## @brief Hash helpers
9
9
  ##
10
- class Hash
10
+ class ::Hash
11
11
  def has_tags?(tags, bool = 'AND')
12
12
  tags = tags.split(/ *, */) if tags.is_a? String
13
13
  item = self
@@ -667,6 +667,40 @@ class WWID
667
667
  @results.push(%(Added "#{entry['title']}" to #{section}))
668
668
  end
669
669
 
670
+ def same_time?(item_a, item_b)
671
+ item_a['date'] == item_b['date'] ? get_interval(item_a, false) == get_interval(item_b, false) : false
672
+ end
673
+
674
+ def overlapping_time?(item_a, item_b)
675
+ return true if same_time?(item_a, item_b)
676
+
677
+ start_a = item_a['date']
678
+ interval = get_interval(item_a, false)
679
+ end_a = interval ? start_a + interval.to_i : start_a
680
+ start_b = item_b['date']
681
+ interval = get_interval(item_b, false)
682
+ end_b = interval ? start_b + interval.to_i : start_b
683
+ (start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
684
+ end
685
+
686
+ def dedup(items, no_overlap = false)
687
+
688
+ combined = []
689
+ @content.each do |_k, v|
690
+ combined += v['items']
691
+ end
692
+
693
+ items.delete_if do |item|
694
+ duped = false
695
+ combined.each do |comp|
696
+ duped = no_overlap ? overlapping_time?(item, comp) : same_time?(item, comp)
697
+ break if duped
698
+ end
699
+ # warn "Skipping overlapping entry: #{item['title']}" if duped
700
+ duped
701
+ end
702
+ end
703
+
670
704
  ##
671
705
  ## @brief Imports a Timing report
672
706
  ##
@@ -676,6 +710,8 @@ class WWID
676
710
  ##
677
711
  def import_timing(path, opt = {})
678
712
  section = opt[:section] || @current_section
713
+ opt[:no_overlap] ||= false
714
+
679
715
  add_section(section) unless @content.has_key?(section)
680
716
 
681
717
  add_tags = opt[:tag] ? opt[:tag].split(/[ ,]+/).map { |t| t.sub(/^@?/, '@') }.join(' ') : ''
@@ -690,10 +726,12 @@ class WWID
690
726
  # Only process entries with a start and end date
691
727
  next unless entry.key?('startDate') && entry.key?('endDate')
692
728
 
693
- start_time = Time.parse(entry['startDate'])
694
- end_time = Time.parse(entry['endDate'])
729
+ # Round down seconds and convert UTC to local time
730
+ start_time = Time.parse(entry['startDate'].sub(/:\d\dZ$/, ':00Z')).getlocal
731
+ end_time = Time.parse(entry['endDate'].sub(/:\d\dZ$/, ':00Z')).getlocal
695
732
  next unless start_time && end_time
696
- tags = entry['project'].split(/ ▸ /).map {|proj| proj.gsub(/ +/, '').downcase }
733
+
734
+ tags = entry['project'].split(/ ▸ /).map {|proj| proj.gsub(/[^a-z0-9]+/i, '').downcase }
697
735
  title = "#{prefix} "
698
736
  title += entry.key?('activityTitle') && entry['activityTitle'] != '(Untitled Task)' ? entry['activityTitle'] : 'Working on'
699
737
  tags.each do |tag|
@@ -711,7 +749,10 @@ class WWID
711
749
  new_entry['note'] = entry['notes'].split(/\n/).map(&:chomp) if entry.key?('notes')
712
750
  new_items.push(new_entry)
713
751
  end
714
-
752
+ total = new_items.count
753
+ new_items = dedup(new_items, opt[:no_overlap])
754
+ dups = total - new_items.count
755
+ @results.push(%(Skipped #{dups} items with overlapping times)) if dups > 0
715
756
  @content[section]['items'].concat(new_items)
716
757
  @results.push(%(Imported #{new_items.count} items to #{section}))
717
758
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doing
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.64
4
+ version: 1.0.65
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-22 00:00:00.000000000 Z
11
+ date: 2021-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake