zzamboni-things2thl 0.4.4 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +33 -0
- data/README +16 -13
- data/VERSION +1 -1
- data/bin/things2thl +29 -12
- data/lib/Things2THL.rb +52 -9
- data/things2thl.gemspec +1 -1
- metadata +1 -1
data/ChangeLog
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
2009-05-19 Diego Zamboni <diego@zzamboni.org>
|
2
|
+
|
3
|
+
* lib/Things2THL.rb: Version bump to 0.5.0
|
4
|
+
|
5
|
+
2009-05-19 Diego Zamboni <diego@zzamboni.org>
|
6
|
+
|
7
|
+
* bin/things2thl, lib/Things2THL.rb: Made it mandatory to specify
|
8
|
+
the mode of operation (--projects-as-lists or --projects-as-tasks).
|
9
|
+
|
10
|
+
2009-05-19 Diego Zamboni <diego@zzamboni.org>
|
11
|
+
|
12
|
+
* bin/things2thl, lib/Things2THL.rb: Added --[no-]time-tags option,
|
13
|
+
which allows time-estimate tags in Things for the form Xsec/Xmin/Xhr
|
14
|
+
(e.g. I use "10min", "30min", "60min") to be converted to the
|
15
|
+
appropriate time estimate attribute of the tasks in THL. For now the
|
16
|
+
format of the time-estimate tags is fixed, but I might add
|
17
|
+
customization if I someone asks for it. This option is disabled by
|
18
|
+
default. Also changed the --context-tags-regex option to be
|
19
|
+
--[no-]context-tags, which allows both specifying the regex and
|
20
|
+
(with --no-) disabling the feature in a single option.
|
21
|
+
|
22
|
+
2009-05-19 Diego Zamboni <diego@zzamboni.org>
|
23
|
+
|
24
|
+
* things2thl.gemspec: Regenerated gemspec for version 0.4.4
|
25
|
+
|
26
|
+
2009-05-19 Diego Zamboni <diego@zzamboni.org>
|
27
|
+
|
28
|
+
* VERSION: Version bump to 0.4.4
|
29
|
+
|
30
|
+
2009-05-19 Diego Zamboni <diego@zzamboni.org>
|
31
|
+
|
32
|
+
* ChangeLog, lib/Things2THL.rb: Updated ChangeLog
|
33
|
+
|
1
34
|
2009-05-19 Diego Zamboni <diego@zzamboni.org>
|
2
35
|
|
3
36
|
* things2thl.gemspec: Regenerated gemspec for version 0.4.3
|
data/README
CHANGED
@@ -7,8 +7,9 @@ Conversion program to transfer data from Things
|
|
7
7
|
|
8
8
|
Written by Diego Zamboni <diego@zzamboni.org>
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
|
11
|
+
INSTALLATION:
|
12
|
+
------------
|
12
13
|
|
13
14
|
You need Things 1.1.1 or later, since things2thl requires Applescript
|
14
15
|
support.
|
@@ -25,21 +26,26 @@ don't have it already, it will be automatically installed by gem.
|
|
25
26
|
USAGE:
|
26
27
|
-----
|
27
28
|
|
28
|
-
Usage: things2thl [options]
|
29
|
+
Usage: things2thl <mode of operation> [options]
|
29
30
|
|
30
|
-
|
31
|
+
Modes of operation (required):
|
31
32
|
-L, --projects-as-lists Convert projects in Things to lists in THL
|
32
|
-
(default)
|
33
33
|
-T, --projects-as-tasks Convert projects in Things to tasks in THL
|
34
|
+
|
35
|
+
Options:
|
34
36
|
--[no-]areas Transfer areas from Things (default: yes)
|
35
|
-
|
37
|
+
--[no-]time-tags Consider tags of the form Xmin/Xsec/Xhr as
|
38
|
+
time estimates, set them in THL
|
39
|
+
accordingly (default: no).
|
40
|
+
--[no-]context-tags [REGEX] Regular expression to identify tags that
|
36
41
|
should be interpreted as contexts.
|
37
|
-
(default: ^@)
|
42
|
+
(default: ^@).
|
43
|
+
Use with no- to disable this feature.
|
38
44
|
--top-level-folder FOLDER Do the import inside the named folders,
|
39
45
|
instead of the top level
|
40
46
|
(Inbox, etc. will also be created there
|
41
47
|
instead of their corresponding places)
|
42
|
-
--projects-
|
48
|
+
--projects-top-level FOLDER The named folder will be created to
|
43
49
|
contain all projects when
|
44
50
|
--projects-as-lists is used (otherwise
|
45
51
|
they will be in the top folders group).
|
@@ -74,11 +80,6 @@ Functionality still missing:
|
|
74
80
|
|
75
81
|
Not sure how to transfer this to THL. Ideas are welcome.
|
76
82
|
|
77
|
-
- Handle "time estimate" tags.
|
78
|
-
|
79
|
-
Plan: Allow specifying certain Things tags (e.g. I use "10min",
|
80
|
-
"30min", "60min") that should be used to set the time estimate for
|
81
|
-
the task in THL.
|
82
83
|
|
83
84
|
Known issues:
|
84
85
|
-------------
|
@@ -92,3 +93,5 @@ Known issues:
|
|
92
93
|
scheduling itself is not transferred, because this information is
|
93
94
|
not accessible through AS from either Things not THL.
|
94
95
|
|
96
|
+
- The format of time estimate tags is fixed for the moment. May add
|
97
|
+
customization if I get any requests for it.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/bin/things2thl
CHANGED
@@ -7,29 +7,42 @@ require "ostruct"
|
|
7
7
|
|
8
8
|
options=Things2THL.default_options
|
9
9
|
opts = OptionParser.new do |opts|
|
10
|
-
|
11
|
-
opts.
|
12
|
-
|
13
|
-
opts.banner = "Usage: things2thl [options]"
|
10
|
+
|
11
|
+
opts.banner = "Usage: things2thl <mode of operation> [options]"
|
14
12
|
|
15
13
|
def opts.show_usage
|
16
14
|
puts self
|
17
15
|
exit
|
18
16
|
end
|
19
17
|
|
20
|
-
opts.
|
21
|
-
opts.
|
18
|
+
opts.separator ''
|
19
|
+
opts.separator("Modes of operation (required):")
|
20
|
+
opts.on("-L", "--projects-as-lists",
|
21
|
+
"Convert projects in Things to lists in THL" ) { options.structure = :projects_as_lists }
|
22
|
+
opts.on("-T", "--projects-as-tasks",
|
23
|
+
"Convert projects in Things to tasks in THL" ) { options.structure = :projects_as_tasks }
|
24
|
+
|
25
|
+
opts.separator ''
|
26
|
+
opts.separator("Options:")
|
22
27
|
opts.on("--[no-]areas", "Transfer areas from Things (default: #{options.areas ? 'yes' : 'no'})") { |v| options.areas = v }
|
23
|
-
opts.on('
|
24
|
-
|
25
|
-
|
28
|
+
opts.on('--[no-]time-tags',
|
29
|
+
'Consider tags of the form Xmin/Xsec/Xhr as',
|
30
|
+
' time estimates, set them in THL',
|
31
|
+
" accordingly (default: #{options.timetags ? 'yes' : 'no'}).") do |value|
|
32
|
+
options.timetags = value
|
33
|
+
end
|
34
|
+
opts.on('--[no-]context-tags [REGEX]',
|
35
|
+
'Regular expression to identify tags that',
|
36
|
+
' should be interpreted as contexts.',
|
37
|
+
" (default: #{options.contexttagsregex}).",
|
38
|
+
" Use with no- to disable this feature.") do |regex|
|
39
|
+
options.contexttagsregex = case regex; when false:nil; when "":options.contexttagsregex; else regex; end
|
26
40
|
end
|
27
|
-
|
28
41
|
opts.on("--top-level-folder FOLDER", "Do the import inside the named folders,"," instead of the top level",
|
29
42
|
" (Inbox, etc. will also be created there"," instead of their corresponding places)") do |toplevel|
|
30
43
|
options.toplevel = toplevel
|
31
44
|
end
|
32
|
-
opts.on("--projects-
|
45
|
+
opts.on("--projects-top-level FOLDER",
|
33
46
|
"The named folder will be created to",
|
34
47
|
" contain all projects when",
|
35
48
|
" --projects-as-lists is used (otherwise",
|
@@ -78,7 +91,11 @@ end
|
|
78
91
|
######################################################################
|
79
92
|
|
80
93
|
opts.parse!
|
81
|
-
|
94
|
+
unless options.structure
|
95
|
+
puts "Error: you didn't specify the mode of operation to use."
|
96
|
+
puts ''
|
97
|
+
opts.show_usage
|
98
|
+
end
|
82
99
|
|
83
100
|
converter = Things2THL.new(options, options.thingsapp, options.thlapp)
|
84
101
|
things = converter.things
|
data/lib/Things2THL.rb
CHANGED
@@ -11,8 +11,8 @@ require 'appscript'; include Appscript
|
|
11
11
|
module Things2THL
|
12
12
|
module Version
|
13
13
|
MAJOR = 0
|
14
|
-
MINOR =
|
15
|
-
PATCH =
|
14
|
+
MINOR = 5
|
15
|
+
PATCH = 0
|
16
16
|
|
17
17
|
STRING = [MAJOR, MINOR, PATCH].join(".")
|
18
18
|
end
|
@@ -73,7 +73,7 @@ module Things2THL
|
|
73
73
|
Proc.new {|node,prop,obj|
|
74
74
|
obj.fix_completed_canceled(node, prop)
|
75
75
|
obj.archive_completed(prop)
|
76
|
-
obj.
|
76
|
+
obj.process_tags(node, prop, true, true)
|
77
77
|
obj.check_today(node, prop)
|
78
78
|
}
|
79
79
|
]
|
@@ -99,7 +99,7 @@ module Things2THL
|
|
99
99
|
Proc.new {|node,prop,obj|
|
100
100
|
obj.fix_completed_canceled(node, prop)
|
101
101
|
obj.archive_completed(prop)
|
102
|
-
obj.
|
102
|
+
obj.process_tags(node, prop, false, true)
|
103
103
|
}
|
104
104
|
],
|
105
105
|
:selected_to_do => [:task,
|
@@ -118,7 +118,7 @@ module Things2THL
|
|
118
118
|
Proc.new {|node,prop,obj|
|
119
119
|
obj.fix_completed_canceled(node, prop)
|
120
120
|
obj.archive_completed(prop)
|
121
|
-
obj.
|
121
|
+
obj.process_tags(node, prop, false, true)
|
122
122
|
obj.check_today(node, prop)
|
123
123
|
}
|
124
124
|
]
|
@@ -132,6 +132,14 @@ module Things2THL
|
|
132
132
|
:task => :title
|
133
133
|
}
|
134
134
|
|
135
|
+
# Time units for time-estimate tags
|
136
|
+
TIMEUNITS = {
|
137
|
+
"sec" => 1,
|
138
|
+
"min" => 60,
|
139
|
+
"hr" => 60*60,
|
140
|
+
"hour" => 60*60,
|
141
|
+
}
|
142
|
+
|
135
143
|
end ### module Constants
|
136
144
|
|
137
145
|
####################################################################
|
@@ -230,7 +238,10 @@ module Things2THL
|
|
230
238
|
|
231
239
|
# Regular expression to match context tags. Compile it here to avoid
|
232
240
|
# repetition later on.
|
233
|
-
options.contexttagsregex_compiled = Regexp.compile(options.contexttagsregex)
|
241
|
+
options.contexttagsregex_compiled = Regexp.compile(options.contexttagsregex) if options.contexttagsregex
|
242
|
+
# Regular expression to match time-estimate tags. Compile it here to avoid
|
243
|
+
# repetition later on.
|
244
|
+
options.timetagsregex_compiled = Regexp.compile(options.timetagsregex) if options.timetagsregex
|
234
245
|
# Structure to keep track of already create items
|
235
246
|
# These hashes are indexed by Things node ID (node.id_). Each element
|
236
247
|
# contains a hash with two elements:
|
@@ -621,8 +632,8 @@ module Things2THL
|
|
621
632
|
prop[:archived] = true if options.archivecompleted && (prop[:completed] || prop[:canceled])
|
622
633
|
end
|
623
634
|
|
624
|
-
#
|
625
|
-
def
|
635
|
+
# Process tags
|
636
|
+
def process_tags(node, prop, inherit_project_tags, inherit_area_tags)
|
626
637
|
tasktags = node.tags.map {|t| t.name }
|
627
638
|
if inherit_project_tags
|
628
639
|
# Merge project and area tags
|
@@ -637,6 +648,36 @@ module Things2THL
|
|
637
648
|
tasktags |= node.area.tags.map {|t| t.name }
|
638
649
|
end
|
639
650
|
unless tasktags.empty?
|
651
|
+
# First process time-estimate tags if needed
|
652
|
+
if options.timetags
|
653
|
+
# Valid time tags will be deleted from the tags list
|
654
|
+
tasktags=tasktags.delete_if do |t|
|
655
|
+
if data=options.timetagsregex_compiled.match(t)
|
656
|
+
timeestimate = nil
|
657
|
+
# If the regex includes only one group, it is assumed to be
|
658
|
+
# the time in minutes. If it includes two groups, the second
|
659
|
+
# group specifies the time unit, as defined in Constants::TIMEUNITS
|
660
|
+
case data.size
|
661
|
+
when 0
|
662
|
+
puts "Invalid time tags regex, does not return any groups: #{options.timetagsregex_compiled.to_s}"
|
663
|
+
when 1
|
664
|
+
# Assumed to be in minutes, timeestimate is in seconds
|
665
|
+
timeestimate = data[1].to_i * 60
|
666
|
+
else
|
667
|
+
# Second one is the units - the rest are ignored
|
668
|
+
timeunit=Constants::TIMEUNITS[data[2]]
|
669
|
+
if !timeunit
|
670
|
+
puts "Invalid time estimate tag, I could not match the time unit: '#{t}'"
|
671
|
+
else
|
672
|
+
timeestimate = data[1].to_i * timeunit
|
673
|
+
end
|
674
|
+
end
|
675
|
+
if timeestimate
|
676
|
+
prop[:estimated_time] = timeestimate
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|
680
|
+
end
|
640
681
|
prop[:title] = [prop[:title], tasktags.map do |t|
|
641
682
|
if options.contexttagsregex_compiled &&
|
642
683
|
options.contexttagsregex_compiled.match(t)
|
@@ -709,12 +750,14 @@ module Things2THL
|
|
709
750
|
options=OpenStruct.new
|
710
751
|
options.completed = false
|
711
752
|
options.database = nil
|
712
|
-
options.structure =
|
753
|
+
options.structure = nil
|
713
754
|
options.areas = true
|
714
755
|
options.quiet = false
|
715
756
|
options.archivecompleted = true
|
716
757
|
options.projectsfolder = nil
|
717
758
|
options.contexttagsregex = '^@'
|
759
|
+
options.timetagsregex = '^(\d+)(min|sec|hr)$'
|
760
|
+
options.timetags = false
|
718
761
|
return options
|
719
762
|
end
|
720
763
|
|
data/things2thl.gemspec
CHANGED