zzamboni-things2thl 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +38 -1
- data/VERSION +1 -1
- data/bin/things2thl +59 -29
- data/lib/Things2THL.rb +106 -32
- data/things2thl.gemspec +2 -2
- metadata +2 -2
data/ChangeLog
CHANGED
|
@@ -1,6 +1,43 @@
|
|
|
1
|
+
2009-05-25 Diego Zamboni <diego@zzamboni.org>
|
|
2
|
+
|
|
3
|
+
* VERSION: Version bump to 0.8.0
|
|
4
|
+
|
|
5
|
+
2009-05-25 Diego Zamboni <diego@zzamboni.org>
|
|
6
|
+
|
|
7
|
+
* bin/things2thl, lib/Things2THL.rb: Added new mode of operation
|
|
8
|
+
--inbox (-I) to transfer only tasks from the Inbox.
|
|
9
|
+
|
|
10
|
+
2009-05-25 Diego Zamboni <diego@zzamboni.org>
|
|
11
|
+
|
|
12
|
+
* bin/things2thl, lib/Things2THL.rb: Added printing of some
|
|
13
|
+
statistics at the end - number of items created, total time elapsed.
|
|
14
|
+
Can be disabled by specifying -q twice (-qq).
|
|
15
|
+
|
|
16
|
+
2009-05-25 Diego Zamboni <diego@zzamboni.org>
|
|
17
|
+
|
|
18
|
+
* bin/things2thl, lib/Things2THL.rb: Added option --sync, which
|
|
19
|
+
causes items (areas, projects and tasks) not to be created if they
|
|
20
|
+
already exist. This is useful if you add more items to Things after
|
|
21
|
+
you have transferred to THL, and want to re-transfer just the new
|
|
22
|
+
ones. This option is disabled by default because the duplicate checking is
|
|
23
|
+
done using only the item's name, so if you have multiple entries
|
|
24
|
+
with the same name in Things, they will only be transferred once
|
|
25
|
+
with --sync enabled.
|
|
26
|
+
|
|
27
|
+
2009-05-24 Diego Zamboni <diego@zzamboni.org>
|
|
28
|
+
|
|
29
|
+
* bin/things2thl, lib/Things2THL.rb: Added options --areas-as-tags
|
|
30
|
+
and --areas-as-contexts, which specify that areas in Things should
|
|
31
|
+
be transferred to THL as tags/contexts respectively, instead of
|
|
32
|
+
created as separate entities. Thanks to @biomac101 for the suggestion.
|
|
33
|
+
|
|
34
|
+
2009-05-21 Diego Zamboni <diego@zzamboni.org>
|
|
35
|
+
|
|
36
|
+
* things2thl.gemspec: Regenerated gemspec for version 0.7.0
|
|
37
|
+
|
|
1
38
|
2009-05-21 Diego Zamboni <diego@zzamboni.org>
|
|
2
39
|
|
|
3
|
-
* VERSION, lib/Things2THL.rb: Version bump to 0.7.0
|
|
40
|
+
* ChangeLog, VERSION, lib/Things2THL.rb: Version bump to 0.7.0
|
|
4
41
|
|
|
5
42
|
2009-05-21 Diego Zamboni <diego@zzamboni.org>
|
|
6
43
|
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.8.0
|
data/bin/things2thl
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
require File.join(File.dirname(__FILE__), *%w".. lib Things2THL")
|
|
5
5
|
require "optparse"
|
|
6
6
|
require "ostruct"
|
|
7
|
+
require "time"
|
|
7
8
|
|
|
8
9
|
options=Things2THL.default_options
|
|
9
10
|
opts = OptionParser.new do |opts|
|
|
@@ -14,6 +15,10 @@ opts = OptionParser.new do |opts|
|
|
|
14
15
|
puts self
|
|
15
16
|
exit
|
|
16
17
|
end
|
|
18
|
+
|
|
19
|
+
def yesno(v)
|
|
20
|
+
"(default: #{v ? 'yes' : 'no'})"
|
|
21
|
+
end
|
|
17
22
|
|
|
18
23
|
opts.separator ''
|
|
19
24
|
opts.separator("Modes of operation (required):")
|
|
@@ -25,14 +30,20 @@ opts = OptionParser.new do |opts|
|
|
|
25
30
|
"Convert both projects and areas in Things",
|
|
26
31
|
" to lists in THL. This implies that",
|
|
27
32
|
" projects are not nested inside areas.") { options.structure = :projects_areas_as_lists }
|
|
33
|
+
opts.on("-I", "--inbox", "Transfer only Inbox tasks." ) do
|
|
34
|
+
options.inboxonly = true
|
|
35
|
+
options.structure = :projects_as_lists
|
|
36
|
+
end
|
|
28
37
|
|
|
29
38
|
opts.separator ''
|
|
30
39
|
opts.separator("Options:")
|
|
31
|
-
opts.on("--[no-]areas", "Transfer areas from Things
|
|
40
|
+
opts.on("--[no-]areas", "Transfer areas from Things #{yesno(options.areas)}") { |v| options.areas = v }
|
|
41
|
+
opts.on("--areas-as-tags", "Transfer areas as tags in THL.") { options.areas_as=:tags }
|
|
42
|
+
opts.on("--areas-as-contexts", "Transfer areas as contexts in THL.") { options.areas_as=:contexts }
|
|
32
43
|
opts.on('--[no-]time-tags',
|
|
33
44
|
'Consider tags of the form Xmin/Xsec/Xhr as',
|
|
34
45
|
' time estimates, set them in THL',
|
|
35
|
-
" accordingly
|
|
46
|
+
" accordingly #{yesno(options.timetags)}.") do |value|
|
|
36
47
|
options.timetags = value
|
|
37
48
|
end
|
|
38
49
|
opts.on('--[no-]context-tags [REGEX]',
|
|
@@ -42,6 +53,7 @@ opts = OptionParser.new do |opts|
|
|
|
42
53
|
" Use with no- to disable this feature.") do |regex|
|
|
43
54
|
options.contexttagsregex = case regex; when false:nil; when "":options.contexttagsregex; else regex; end
|
|
44
55
|
end
|
|
56
|
+
opts.on("--sync", "Only transfer new items #{yesno(options.sync)}") { options.sync = true }
|
|
45
57
|
opts.on("--top-level-folder FOLDER", "Do the import inside the named folders,"," instead of the top level",
|
|
46
58
|
" (Inbox, etc. will also be created there"," instead of their corresponding places)") do |toplevel|
|
|
47
59
|
options.toplevel = toplevel
|
|
@@ -65,11 +77,13 @@ opts = OptionParser.new do |opts|
|
|
|
65
77
|
|
|
66
78
|
opts.on("-c", "--completed",
|
|
67
79
|
"Transfer also completed/canceled tasks",
|
|
68
|
-
" and projects
|
|
80
|
+
" and projects #{yesno(options.completed)}") { options.completed = true }
|
|
69
81
|
opts.on("--[no-]archive-completed",
|
|
70
82
|
"If transferring completed/canceled tasks,",
|
|
71
|
-
" also mark them as archived
|
|
72
|
-
opts.on("-q", "--quiet",
|
|
83
|
+
" also mark them as archived #{yesno(options.archivecompleted)}") {|v| options.archivecompleted = v }
|
|
84
|
+
opts.on("-q", "--quiet",
|
|
85
|
+
"Do not print items as they are processed.",
|
|
86
|
+
"Twice: do not print stats at the end.") { options.quiet+=1 }
|
|
73
87
|
# opts.on("-n", "--dry-run", "Do not create anything in THL, just print the items that would be created") { options.dryrun = true }
|
|
74
88
|
# opts.on("-n", "--notes", "Shows only tasks with notes") { options[:tasks] = { :onlynotes => true } }
|
|
75
89
|
# opts.on("-a", "--all", 'Shows all tasks in the focus') { |f| options[:tasks] = { :children => false } }
|
|
@@ -100,7 +114,7 @@ end
|
|
|
100
114
|
######################################################################
|
|
101
115
|
|
|
102
116
|
opts.parse!
|
|
103
|
-
unless options.structure
|
|
117
|
+
unless options.structure || options.inboxonly
|
|
104
118
|
puts "Error: you didn't specify the mode of operation to use."
|
|
105
119
|
puts ''
|
|
106
120
|
opts.show_usage
|
|
@@ -110,27 +124,30 @@ converter = Things2THL.new(options, options.thingsapp, options.thlapp)
|
|
|
110
124
|
things = converter.things
|
|
111
125
|
thl = converter.thl
|
|
112
126
|
|
|
113
|
-
#
|
|
127
|
+
# Start timing
|
|
128
|
+
start=Time.new
|
|
114
129
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
unless options.inboxonly
|
|
131
|
+
# First, traverse all areas
|
|
132
|
+
if options.areas && !options.areas_as
|
|
133
|
+
puts "Processing Areas of Responsibility" unless options.quiet.nonzero?
|
|
134
|
+
things.areas.get.each do |area|
|
|
135
|
+
converter.process(Things2THL::ThingsNode.new(area))
|
|
136
|
+
end
|
|
120
137
|
end
|
|
121
|
-
end
|
|
122
138
|
|
|
123
|
-
# Next, traverse all projects, putting each one inside its corresponding area
|
|
124
|
-
puts "Processing Projects" unless options.quiet
|
|
125
|
-
if options.completed
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
else
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
end
|
|
132
|
-
projlist.each do |project|
|
|
133
|
-
|
|
139
|
+
# Next, traverse all projects, putting each one inside its corresponding area
|
|
140
|
+
puts "Processing Projects" unless options.quiet.nonzero?
|
|
141
|
+
if options.completed
|
|
142
|
+
puts " (fetching all projects - this may take a while)" unless options.quiet.nonzero?
|
|
143
|
+
projlist=things.projects.get
|
|
144
|
+
else
|
|
145
|
+
puts " (fetching only open projects - this may take a while)" unless options.quiet.nonzero?
|
|
146
|
+
projlist=things.projects[its.status.eq(:open)].get
|
|
147
|
+
end
|
|
148
|
+
projlist.each do |project|
|
|
149
|
+
converter.process(Things2THL::ThingsNode.new(project))
|
|
150
|
+
end
|
|
134
151
|
end
|
|
135
152
|
|
|
136
153
|
# Now do the tasks
|
|
@@ -138,13 +155,18 @@ end
|
|
|
138
155
|
# - to_dos returns not only tasks, also projects (not areas)
|
|
139
156
|
# - to-dos returns tasks from all the views: Inbox, Today, Scheduled, Someday, and Next, so we have
|
|
140
157
|
# to separate them and create the appropriate containers as needed
|
|
141
|
-
puts "Processing tasks" unless options.quiet
|
|
158
|
+
puts "Processing tasks" unless options.quiet.nonzero?
|
|
159
|
+
if options.inboxonly
|
|
160
|
+
queryobj=things.lists['Inbox']
|
|
161
|
+
else
|
|
162
|
+
queryobj=things
|
|
163
|
+
end
|
|
142
164
|
if options.completed
|
|
143
|
-
puts " (fetching all tasks - this may take a while)" unless options.quiet
|
|
144
|
-
tasklist=
|
|
165
|
+
puts " (fetching all tasks - this may take a while)" unless options.quiet.nonzero?
|
|
166
|
+
tasklist=queryobj.to_dos.get
|
|
145
167
|
else
|
|
146
|
-
puts " (fetching only open tasks - this may take a while)" unless options.quiet
|
|
147
|
-
tasklist=
|
|
168
|
+
puts " (fetching only open tasks - this may take a while)" unless options.quiet.nonzero?
|
|
169
|
+
tasklist=queryobj.to_dos[its.status.eq(:open)].get
|
|
148
170
|
end
|
|
149
171
|
tasklist.each do |t|
|
|
150
172
|
task=Things2THL::ThingsNode.new(t)
|
|
@@ -152,3 +174,11 @@ tasklist.each do |t|
|
|
|
152
174
|
converter.process(task)
|
|
153
175
|
end
|
|
154
176
|
|
|
177
|
+
# End timing
|
|
178
|
+
diff=Time.new-start
|
|
179
|
+
|
|
180
|
+
# Print stats at the end
|
|
181
|
+
unless options.quiet >= 2
|
|
182
|
+
puts "Conversion done in #{diff} seconds."
|
|
183
|
+
converter.created.each_pair { |key,val| puts " #{val} #{key}#{val!=1 ? 's' : ''} created" }
|
|
184
|
+
end
|
data/lib/Things2THL.rb
CHANGED
|
@@ -263,7 +263,7 @@ module Things2THL
|
|
|
263
263
|
####################################################################
|
|
264
264
|
|
|
265
265
|
class Converter
|
|
266
|
-
attr_accessor :options, :things, :thl
|
|
266
|
+
attr_accessor :options, :things, :thl, :created
|
|
267
267
|
|
|
268
268
|
def initialize(opt_struct = nil, things_location = nil, thl_location = nil)
|
|
269
269
|
@options=opt_struct || Things2THL.default_options
|
|
@@ -295,6 +295,14 @@ module Things2THL
|
|
|
295
295
|
# id_ of each node that belongs to that focus. Existence of the key
|
|
296
296
|
# indicates existence in the focus.
|
|
297
297
|
@cache_focus = {}
|
|
298
|
+
|
|
299
|
+
# Statistics
|
|
300
|
+
@created = {
|
|
301
|
+
:task => 0,
|
|
302
|
+
:list => 0,
|
|
303
|
+
:folder => 0
|
|
304
|
+
}
|
|
305
|
+
|
|
298
306
|
end
|
|
299
307
|
|
|
300
308
|
# Get the type of the THL node that corresponds to the given Things node,
|
|
@@ -360,24 +368,48 @@ module Things2THL
|
|
|
360
368
|
end
|
|
361
369
|
end
|
|
362
370
|
|
|
371
|
+
# Simplified version of find_or_create which simply takes :new and :name
|
|
372
|
+
def simple_find_or_create(what, name, parent = @thl.folders_group.get)
|
|
373
|
+
find_or_create({:new => what, :with_properties => { :name => name } }, parent)
|
|
374
|
+
end
|
|
375
|
+
|
|
363
376
|
# Find or create a list or a folder inside the given parent (or the top-level folders group if not given)
|
|
364
|
-
def find_or_create(
|
|
365
|
-
|
|
366
|
-
|
|
377
|
+
def find_or_create(props, parent = @thl.folders_group.get)
|
|
378
|
+
puts "find_or_create: props = #{props.inspect}" if $DEBUG
|
|
379
|
+
what=props[:new]
|
|
380
|
+
name=(what==:task) ? props[:with_properties][:title] : props[:with_properties][:name]
|
|
381
|
+
parentclass=parent.class_.get
|
|
382
|
+
unless what == :list || what == :folder || what == :task
|
|
383
|
+
raise "find_or_create: 'props[:new]' parameter has to be :list, :folder or :task"
|
|
367
384
|
end
|
|
368
385
|
puts "parent of #{name} = #{parent}" if $DEBUG
|
|
369
|
-
if
|
|
370
|
-
raise "find_or_create: parent is not a folder, it's a #{
|
|
386
|
+
if (what == :folder || what == :list) && parentclass != :folder
|
|
387
|
+
raise "find_or_create: parent is not a folder, it's a #{parentclass}"
|
|
388
|
+
elsif what == :task && parentclass != :list && parentclass != :task
|
|
389
|
+
raise "find_or_create: parent is not a list, it's a #{parentclass}"
|
|
371
390
|
else
|
|
372
|
-
if
|
|
373
|
-
parent.
|
|
391
|
+
if what == :task
|
|
392
|
+
query = parent.tasks[its.title.eq(name)]
|
|
393
|
+
if ! query.get.empty?
|
|
394
|
+
query.get[0]
|
|
395
|
+
else
|
|
396
|
+
@created[what]+=1
|
|
397
|
+
parent.end.make(props)
|
|
398
|
+
end
|
|
374
399
|
else
|
|
375
|
-
parent.
|
|
400
|
+
query = parent.groups[name]
|
|
401
|
+
if query.exists
|
|
402
|
+
query.get
|
|
403
|
+
else
|
|
404
|
+
@created[what]+=1
|
|
405
|
+
parent.end.make(props)
|
|
406
|
+
end
|
|
376
407
|
end
|
|
377
408
|
end
|
|
378
409
|
end
|
|
379
410
|
|
|
380
411
|
def new_folder(name, parent = @thl.folders_group.get)
|
|
412
|
+
@created[:folder]+=1
|
|
381
413
|
parent.end.make(:new => :folder,
|
|
382
414
|
:with_properties => { :name => name })
|
|
383
415
|
end
|
|
@@ -388,7 +420,11 @@ module Things2THL
|
|
|
388
420
|
|
|
389
421
|
unless @top_level_node
|
|
390
422
|
# Create the top-level node if we don't have it cached yet
|
|
391
|
-
|
|
423
|
+
if options.sync
|
|
424
|
+
@top_level_node=simple_find_or_create(:folder, options.toplevel)
|
|
425
|
+
else
|
|
426
|
+
@top_level_node=new_folder(options.toplevel)
|
|
427
|
+
end
|
|
392
428
|
end
|
|
393
429
|
@top_level_node
|
|
394
430
|
end
|
|
@@ -416,17 +452,17 @@ module Things2THL
|
|
|
416
452
|
when 'Trash', 'Today'
|
|
417
453
|
nil
|
|
418
454
|
when 'Inbox', 'Next'
|
|
419
|
-
|
|
455
|
+
simple_find_or_create(:list, focusname, top_level_node)
|
|
420
456
|
when 'Scheduled', 'Logbook'
|
|
421
|
-
|
|
457
|
+
simple_find_or_create((thl_node_type(:project) == :task) ? :list : :folder, focusname, top_level_node)
|
|
422
458
|
when 'Someday'
|
|
423
|
-
|
|
459
|
+
simple_find_or_create(:folder, focusname, top_level_node)
|
|
424
460
|
when 'Projects'
|
|
425
461
|
if thl_node_type(:project) == :task
|
|
426
|
-
|
|
462
|
+
simple_find_or_create(:list, options.projectsfolder || 'Projects', top_level_node)
|
|
427
463
|
else
|
|
428
464
|
if options.projectsfolder
|
|
429
|
-
|
|
465
|
+
simple_find_or_create(:folder, options.projectsfolder, top_level_node)
|
|
430
466
|
else
|
|
431
467
|
top_level_node
|
|
432
468
|
end
|
|
@@ -443,15 +479,15 @@ module Things2THL
|
|
|
443
479
|
when 'Next'
|
|
444
480
|
top_level_node
|
|
445
481
|
when 'Scheduled', 'Logbook'
|
|
446
|
-
|
|
482
|
+
simple_find_or_create((thl_node_type(:project) == :task) ? :list : :folder, focusname, top_level_node)
|
|
447
483
|
when 'Someday'
|
|
448
|
-
|
|
484
|
+
simple_find_or_create(:folder, focusname, top_level_node)
|
|
449
485
|
when 'Projects'
|
|
450
486
|
if thl_node_type(:project) == :task
|
|
451
|
-
|
|
487
|
+
simple_find_or_create(:list, options.projectsfolder || 'Projects', top_level_node)
|
|
452
488
|
else
|
|
453
489
|
if options.projectsfolder
|
|
454
|
-
|
|
490
|
+
simple_find_or_create(:folder, options.projectsfolder, top_level_node)
|
|
455
491
|
else
|
|
456
492
|
top_level_node
|
|
457
493
|
end
|
|
@@ -478,7 +514,7 @@ module Things2THL
|
|
|
478
514
|
return top_level_for_focus('Someday')
|
|
479
515
|
else
|
|
480
516
|
if options.areasfolder
|
|
481
|
-
return
|
|
517
|
+
return simple_find_or_create(:folder, options.areasfolder || 'Areas', top_level_node)
|
|
482
518
|
else
|
|
483
519
|
return top_level_node
|
|
484
520
|
end
|
|
@@ -491,10 +527,10 @@ module Things2THL
|
|
|
491
527
|
if foci.empty?
|
|
492
528
|
if node.project?
|
|
493
529
|
tl=top_level_for_node(node.project)
|
|
494
|
-
if !tl && node.area?
|
|
530
|
+
if !tl && node.area? && !options.areas_as
|
|
495
531
|
tl=top_level_for_node(node.area)
|
|
496
532
|
end
|
|
497
|
-
elsif node.area?
|
|
533
|
+
elsif node.area? && !options.areas_as
|
|
498
534
|
tl=top_level_for_node(node.area)
|
|
499
535
|
end
|
|
500
536
|
return tl
|
|
@@ -530,7 +566,7 @@ module Things2THL
|
|
|
530
566
|
when :area
|
|
531
567
|
tlcontainer
|
|
532
568
|
when :project
|
|
533
|
-
if options.areas && (options.structure != :projects_areas_as_lists) && node.area?
|
|
569
|
+
if options.areas && !options.areas_as && (options.structure != :projects_areas_as_lists) && node.area?
|
|
534
570
|
get_cached_or_process(node.area)
|
|
535
571
|
else
|
|
536
572
|
tlcontainer
|
|
@@ -538,7 +574,7 @@ module Things2THL
|
|
|
538
574
|
when :selected_to_do
|
|
539
575
|
if node.project?
|
|
540
576
|
get_cached_or_process(node.project)
|
|
541
|
-
elsif node.area? && options.areas
|
|
577
|
+
elsif node.area? && options.areas && !options.areas_as
|
|
542
578
|
get_cached_or_process(node.area)
|
|
543
579
|
else
|
|
544
580
|
# It's a loose task
|
|
@@ -552,9 +588,9 @@ module Things2THL
|
|
|
552
588
|
# so if the container is a folder, we have to create a list to hold the task
|
|
553
589
|
if container && (container.class_.get == :folder) && (thl_node_type(node) == :task)
|
|
554
590
|
if node.type == :project
|
|
555
|
-
|
|
591
|
+
simple_find_or_create(:list, options.projectsfolder || 'Projects', container)
|
|
556
592
|
else
|
|
557
|
-
|
|
593
|
+
simple_find_or_create(:list, loose_tasks_name(container), container)
|
|
558
594
|
end
|
|
559
595
|
else
|
|
560
596
|
container
|
|
@@ -566,8 +602,15 @@ module Things2THL
|
|
|
566
602
|
new_node_type = thl_node_type(node)
|
|
567
603
|
new_node_props = props_from_node(node)
|
|
568
604
|
additional_nodes = new_node_props.delete(:__newnodes__)
|
|
569
|
-
|
|
570
|
-
|
|
605
|
+
new_node_spec = {
|
|
606
|
+
:new => new_node_type,
|
|
607
|
+
:with_properties => new_node_props }
|
|
608
|
+
if options.sync
|
|
609
|
+
result=find_or_create(new_node_spec, parent)
|
|
610
|
+
else
|
|
611
|
+
@created[new_node_type]+=1
|
|
612
|
+
result=parent.end.make(new_node_spec)
|
|
613
|
+
end
|
|
571
614
|
if node.type == :area || node.type == :project
|
|
572
615
|
@cache_nodes[node.id_]={}
|
|
573
616
|
@cache_nodes[node.id_][:things_node] = node
|
|
@@ -576,7 +619,12 @@ module Things2THL
|
|
|
576
619
|
# Add new nodes
|
|
577
620
|
if additional_nodes
|
|
578
621
|
additional_nodes.each do |n|
|
|
579
|
-
|
|
622
|
+
if options.sync
|
|
623
|
+
find_or_create(n, result)
|
|
624
|
+
else
|
|
625
|
+
@created[n[:new]]+=1
|
|
626
|
+
result.end.make(n)
|
|
627
|
+
end
|
|
580
628
|
end
|
|
581
629
|
end
|
|
582
630
|
return result
|
|
@@ -598,11 +646,11 @@ module Things2THL
|
|
|
598
646
|
container=container_for(node)
|
|
599
647
|
puts "Container for #{node.name}: #{container}" if $DEBUG
|
|
600
648
|
unless container
|
|
601
|
-
puts "Skipping trashed task '#{node.name}'" unless options.quiet
|
|
649
|
+
puts "Skipping trashed task '#{node.name}'" unless options.quiet.nonzero?
|
|
602
650
|
return
|
|
603
651
|
end
|
|
604
652
|
|
|
605
|
-
unless (options.quiet)
|
|
653
|
+
unless (options.quiet.nonzero?)
|
|
606
654
|
bullet = (node.type == :area) ? "*" : ((node.status == :completed) ? "✓" : (node.status == :canceled) ? "×" : "-")
|
|
607
655
|
puts bullet + " " + node.name
|
|
608
656
|
end
|
|
@@ -689,17 +737,34 @@ module Things2THL
|
|
|
689
737
|
# Process tags
|
|
690
738
|
def process_tags(node, prop, inherit_project_tags, inherit_area_tags)
|
|
691
739
|
tasktags = node.tags.map {|t| t.name }
|
|
740
|
+
taskcontexts = []
|
|
692
741
|
if inherit_project_tags
|
|
693
742
|
# Merge project and area tags
|
|
694
743
|
if node.project?
|
|
695
744
|
tasktags |= node.project.tags.map {|t| t.name }
|
|
696
745
|
if options.areas && node.project.area?
|
|
697
746
|
tasktags |= node.project.area.tags.map {|t| t.name }
|
|
747
|
+
if options.areas_as
|
|
748
|
+
case options.areas_as
|
|
749
|
+
when :tags
|
|
750
|
+
tasktags.push(node.project.area.name)
|
|
751
|
+
when :contexts
|
|
752
|
+
taskcontexts.push(node.project.area.name)
|
|
753
|
+
end
|
|
754
|
+
end
|
|
698
755
|
end
|
|
699
756
|
end
|
|
700
757
|
end
|
|
701
758
|
if options.areas && node.area? && inherit_area_tags
|
|
702
759
|
tasktags |= node.area.tags.map {|t| t.name }
|
|
760
|
+
if options.areas_as
|
|
761
|
+
case options.areas_as
|
|
762
|
+
when :tags
|
|
763
|
+
tasktags.push(node.area.name)
|
|
764
|
+
when :contexts
|
|
765
|
+
taskcontexts.push(node.area.name)
|
|
766
|
+
end
|
|
767
|
+
end
|
|
703
768
|
end
|
|
704
769
|
unless tasktags.empty?
|
|
705
770
|
# First process time-estimate tags if needed
|
|
@@ -742,6 +807,12 @@ module Things2THL
|
|
|
742
807
|
end
|
|
743
808
|
end].join(' ')
|
|
744
809
|
end
|
|
810
|
+
unless taskcontexts.empty?
|
|
811
|
+
prop[:title] = [prop[:title], taskcontexts.map do |c|
|
|
812
|
+
# Contexts cannot have spaces, we also remove any initial @'s before adding our own.
|
|
813
|
+
"@" + c.gsub(/^@+/, "").gsub(/ /, '_')
|
|
814
|
+
end].join(' ')
|
|
815
|
+
end
|
|
745
816
|
end
|
|
746
817
|
|
|
747
818
|
# Check if node is in the Today list
|
|
@@ -835,13 +906,16 @@ module Things2THL
|
|
|
835
906
|
options.database = nil
|
|
836
907
|
options.structure = nil
|
|
837
908
|
options.areas = true
|
|
838
|
-
options.quiet =
|
|
909
|
+
options.quiet = 0
|
|
839
910
|
options.archivecompleted = true
|
|
840
911
|
options.projectsfolder = nil
|
|
841
912
|
options.areasfolder = nil
|
|
842
913
|
options.contexttagsregex = '^@'
|
|
843
914
|
options.timetagsregex = '^(\d+)(min|sec|hr)$'
|
|
844
915
|
options.timetags = false
|
|
916
|
+
options.areas_as = nil
|
|
917
|
+
options.sync = false
|
|
918
|
+
options.inboxonly = false
|
|
845
919
|
return options
|
|
846
920
|
end
|
|
847
921
|
|
data/things2thl.gemspec
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |s|
|
|
4
4
|
s.name = %q{things2thl}
|
|
5
|
-
s.version = "0.
|
|
5
|
+
s.version = "0.8.0"
|
|
6
6
|
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
8
|
s.authors = ["Diego Zamboni"]
|
|
9
|
-
s.date = %q{2009-05-
|
|
9
|
+
s.date = %q{2009-05-25}
|
|
10
10
|
s.default_executable = %q{things2thl}
|
|
11
11
|
s.description = %q{Library and command-line tool for migrating Things data to The Hit List}
|
|
12
12
|
s.email = %q{diego@zzamboni.org}
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: zzamboni-things2thl
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Diego Zamboni
|
|
@@ -9,7 +9,7 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
|
|
12
|
-
date: 2009-05-
|
|
12
|
+
date: 2009-05-25 00:00:00 -07:00
|
|
13
13
|
default_executable: things2thl
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|