taskchampion-rb 0.2.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.
- checksums.yaml +7 -0
- data/.claude/settings.local.json +14 -0
- data/.rubocop.yml +21 -0
- data/CHANGELOG.md +15 -0
- data/Cargo.lock +3671 -0
- data/Cargo.toml +7 -0
- data/README.md +112 -0
- data/Rakefile +28 -0
- data/docs/API_REFERENCE.md +419 -0
- data/docs/THREAD_SAFETY.md +370 -0
- data/docs/breakthrough.md +246 -0
- data/docs/description.md +3 -0
- data/docs/phase_3_plan.md +482 -0
- data/docs/plan.md +612 -0
- data/example.md +465 -0
- data/examples/basic_usage.rb +278 -0
- data/examples/sync_workflow.rb +480 -0
- data/ext/taskchampion/Cargo.toml +20 -0
- data/ext/taskchampion/extconf.rb +6 -0
- data/ext/taskchampion/src/access_mode.rs +132 -0
- data/ext/taskchampion/src/annotation.rs +77 -0
- data/ext/taskchampion/src/dependency_map.rs +65 -0
- data/ext/taskchampion/src/error.rs +78 -0
- data/ext/taskchampion/src/lib.rs +41 -0
- data/ext/taskchampion/src/operation.rs +234 -0
- data/ext/taskchampion/src/operations.rs +180 -0
- data/ext/taskchampion/src/replica.rs +289 -0
- data/ext/taskchampion/src/status.rs +186 -0
- data/ext/taskchampion/src/tag.rs +77 -0
- data/ext/taskchampion/src/task.rs +388 -0
- data/ext/taskchampion/src/thread_check.rs +61 -0
- data/ext/taskchampion/src/util.rs +131 -0
- data/ext/taskchampion/src/working_set.rs +72 -0
- data/lib/taskchampion/version.rb +5 -0
- data/lib/taskchampion.rb +41 -0
- data/sig/taskchampion.rbs +4 -0
- data/taskchampion-0.2.0.gem +0 -0
- metadata +96 -0
@@ -0,0 +1,278 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Basic usage examples for TaskChampion Ruby bindings
|
5
|
+
# This file demonstrates common patterns and workflows
|
6
|
+
|
7
|
+
require 'taskchampion'
|
8
|
+
require 'securerandom'
|
9
|
+
require 'tmpdir'
|
10
|
+
|
11
|
+
puts "TaskChampion Ruby Basic Usage Examples"
|
12
|
+
puts "=" * 40
|
13
|
+
|
14
|
+
# Create a temporary directory for this example
|
15
|
+
temp_dir = Dir.mktmpdir("taskchampion-example")
|
16
|
+
db_path = File.join(temp_dir, "tasks")
|
17
|
+
|
18
|
+
begin
|
19
|
+
# 1. CREATE TASK DATABASE
|
20
|
+
puts "\n1. Creating task database at #{db_path}"
|
21
|
+
replica = Taskchampion::Replica.new_on_disk(db_path, create_if_missing: true)
|
22
|
+
|
23
|
+
# 2. CREATE AND MODIFY TASKS
|
24
|
+
puts "\n2. Creating and modifying tasks"
|
25
|
+
|
26
|
+
# Create operations collection for batching changes
|
27
|
+
operations = Taskchampion::Operations.new
|
28
|
+
|
29
|
+
# Create first task
|
30
|
+
uuid1 = SecureRandom.uuid
|
31
|
+
puts "Creating task with UUID: #{uuid1}"
|
32
|
+
task1 = replica.create_task(uuid1, operations)
|
33
|
+
|
34
|
+
# Set task properties
|
35
|
+
task1.set_description("Learn TaskChampion Ruby bindings", operations)
|
36
|
+
task1.set_status(Taskchampion::Status.pending, operations)
|
37
|
+
task1.set_priority("H", operations) # High priority
|
38
|
+
task1.add_tag(Taskchampion::Tag.new("learning"), operations)
|
39
|
+
task1.add_tag(Taskchampion::Tag.new("ruby"), operations)
|
40
|
+
|
41
|
+
# Add annotation
|
42
|
+
annotation = Taskchampion::Annotation.new(Time.now, "Started learning TaskChampion")
|
43
|
+
task1.add_annotation(annotation, operations)
|
44
|
+
|
45
|
+
# Create second task
|
46
|
+
uuid2 = SecureRandom.uuid
|
47
|
+
puts "Creating task with UUID: #{uuid2}"
|
48
|
+
task2 = replica.create_task(uuid2, operations)
|
49
|
+
task2.set_description("Write example code", operations)
|
50
|
+
task2.set_status(Taskchampion::Status.pending, operations)
|
51
|
+
task2.set_priority("M", operations) # Medium priority
|
52
|
+
task2.add_tag(Taskchampion::Tag.new("coding"), operations)
|
53
|
+
|
54
|
+
# Set due date (tomorrow)
|
55
|
+
task2.set_due(Time.now + 86400, operations)
|
56
|
+
|
57
|
+
# Create third task - already completed
|
58
|
+
uuid3 = SecureRandom.uuid
|
59
|
+
puts "Creating completed task with UUID: #{uuid3}"
|
60
|
+
task3 = replica.create_task(uuid3, operations)
|
61
|
+
task3.set_description("Read TaskChampion documentation", operations)
|
62
|
+
task3.set_status(Taskchampion::Status.completed, operations)
|
63
|
+
task3.add_tag(Taskchampion::Tag.new("learning"), operations)
|
64
|
+
task3.set_end(Time.now, operations)
|
65
|
+
|
66
|
+
# 3. COMMIT CHANGES TO STORAGE
|
67
|
+
puts "\n3. Committing changes to storage"
|
68
|
+
replica.commit_operations(operations)
|
69
|
+
puts "Committed #{operations.length} operations"
|
70
|
+
|
71
|
+
# 4. QUERY AND DISPLAY TASKS
|
72
|
+
puts "\n4. Querying and displaying tasks"
|
73
|
+
|
74
|
+
# Get all task UUIDs
|
75
|
+
all_uuids = replica.task_uuids
|
76
|
+
puts "Total tasks in database: #{all_uuids.length}"
|
77
|
+
|
78
|
+
# Retrieve and display each task
|
79
|
+
all_uuids.each_with_index do |uuid, index|
|
80
|
+
task = replica.task(uuid)
|
81
|
+
next unless task
|
82
|
+
|
83
|
+
puts "\nTask #{index + 1}:"
|
84
|
+
puts " UUID: #{task.uuid}"
|
85
|
+
puts " Description: #{task.description}"
|
86
|
+
puts " Status: #{task.status.to_s.capitalize}"
|
87
|
+
puts " Priority: #{task.priority || 'None'}"
|
88
|
+
|
89
|
+
# Display tags
|
90
|
+
if !task.tags.empty?
|
91
|
+
tag_names = task.tags.map(&:name)
|
92
|
+
puts " Tags: #{tag_names.join(', ')}"
|
93
|
+
end
|
94
|
+
|
95
|
+
# Display dates
|
96
|
+
puts " Created: #{task.entry.strftime('%Y-%m-%d %H:%M:%S')}" if task.entry
|
97
|
+
puts " Due: #{task.due.strftime('%Y-%m-%d %H:%M:%S')}" if task.due
|
98
|
+
puts " Completed: #{task.end.strftime('%Y-%m-%d %H:%M:%S')}" if task.end
|
99
|
+
|
100
|
+
# Display annotations
|
101
|
+
if !task.annotations.empty?
|
102
|
+
puts " Annotations:"
|
103
|
+
task.annotations.each do |annotation|
|
104
|
+
puts " [#{annotation.entry.strftime('%Y-%m-%d %H:%M:%S')}] #{annotation.description}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Status checks
|
109
|
+
puts " Active: #{task.active?}"
|
110
|
+
puts " Pending: #{task.pending?}"
|
111
|
+
puts " Completed: #{task.completed?}"
|
112
|
+
end
|
113
|
+
|
114
|
+
# 5. FILTER AND SEARCH TASKS
|
115
|
+
puts "\n5. Filtering and searching tasks"
|
116
|
+
|
117
|
+
# Get all tasks as objects
|
118
|
+
all_tasks = all_uuids.map { |uuid| replica.task(uuid) }.compact
|
119
|
+
|
120
|
+
# Find pending tasks
|
121
|
+
pending_tasks = all_tasks.select(&:pending?)
|
122
|
+
puts "Pending tasks: #{pending_tasks.length}"
|
123
|
+
|
124
|
+
# Find completed tasks
|
125
|
+
completed_tasks = all_tasks.select(&:completed?)
|
126
|
+
puts "Completed tasks: #{completed_tasks.length}"
|
127
|
+
|
128
|
+
# Find high priority tasks
|
129
|
+
high_priority_tasks = all_tasks.select { |t| t.priority == "H" }
|
130
|
+
puts "High priority tasks: #{high_priority_tasks.length}"
|
131
|
+
|
132
|
+
# Find tasks with specific tag
|
133
|
+
learning_tag = Taskchampion::Tag.new("learning")
|
134
|
+
learning_tasks = all_tasks.select { |t| t.has_tag?(learning_tag) }
|
135
|
+
puts "Learning tasks: #{learning_tasks.length}"
|
136
|
+
|
137
|
+
# Find tasks due today or tomorrow
|
138
|
+
tomorrow = Time.now + 86400
|
139
|
+
due_soon = all_tasks.select { |t| t.due && t.due <= tomorrow }
|
140
|
+
puts "Tasks due soon: #{due_soon.length}"
|
141
|
+
|
142
|
+
# 6. MODIFY EXISTING TASKS
|
143
|
+
puts "\n6. Modifying existing tasks"
|
144
|
+
|
145
|
+
# Complete the first task
|
146
|
+
operations2 = Taskchampion::Operations.new
|
147
|
+
|
148
|
+
# Retrieve task fresh from storage
|
149
|
+
task_to_complete = replica.task(uuid1)
|
150
|
+
if task_to_complete && task_to_complete.pending?
|
151
|
+
puts "Completing task: #{task_to_complete.description}"
|
152
|
+
task_to_complete.set_status(Taskchampion::Status.completed, operations2)
|
153
|
+
task_to_complete.set_end(Time.now, operations2)
|
154
|
+
|
155
|
+
# Add completion annotation
|
156
|
+
completion_note = Taskchampion::Annotation.new(Time.now, "Completed successfully!")
|
157
|
+
task_to_complete.add_annotation(completion_note, operations2)
|
158
|
+
|
159
|
+
# Commit the changes
|
160
|
+
replica.commit_operations(operations2)
|
161
|
+
puts "Task completed and committed"
|
162
|
+
end
|
163
|
+
|
164
|
+
# 7. WORKING WITH WORKING SET
|
165
|
+
puts "\n7. Working with Working Set"
|
166
|
+
|
167
|
+
working_set = replica.working_set
|
168
|
+
largest_index = working_set.largest_index
|
169
|
+
puts "Largest task index: #{largest_index}"
|
170
|
+
|
171
|
+
# Access tasks by index
|
172
|
+
(1..largest_index).each do |index|
|
173
|
+
task = working_set.by_index(index)
|
174
|
+
if task
|
175
|
+
puts "Task ##{index}: #{task.description}"
|
176
|
+
|
177
|
+
# Find index by UUID
|
178
|
+
found_index = working_set.by_uuid(task.uuid)
|
179
|
+
puts " UUID #{task.uuid} maps to index #{found_index}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# 8. WORKING WITH DEPENDENCIES
|
184
|
+
puts "\n8. Working with Dependencies"
|
185
|
+
|
186
|
+
dep_map = replica.dependency_map(rebuild: false)
|
187
|
+
|
188
|
+
# Check dependencies for each task
|
189
|
+
all_uuids.each do |uuid|
|
190
|
+
deps = dep_map.dependencies(uuid)
|
191
|
+
dependents = dep_map.dependents(uuid)
|
192
|
+
has_deps = dep_map.has_dependency?(uuid)
|
193
|
+
|
194
|
+
task = replica.task(uuid)
|
195
|
+
if task
|
196
|
+
puts "Task '#{task.description}':"
|
197
|
+
puts " Has dependencies: #{has_deps}"
|
198
|
+
puts " Depends on: #{deps.length} tasks"
|
199
|
+
puts " Blocks: #{dependents.length} tasks"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# 9. USER DEFINED ATTRIBUTES (UDAs)
|
204
|
+
puts "\n9. Working with User Defined Attributes"
|
205
|
+
|
206
|
+
operations3 = Taskchampion::Operations.new
|
207
|
+
test_task = replica.task(uuid2)
|
208
|
+
|
209
|
+
if test_task
|
210
|
+
# Set custom UDAs
|
211
|
+
test_task.set_uda("project", "website", "company-website", operations3)
|
212
|
+
test_task.set_uda("estimate", "hours", "8", operations3)
|
213
|
+
test_task.set_uda("client", "name", "ACME Corp", operations3)
|
214
|
+
|
215
|
+
replica.commit_operations(operations3)
|
216
|
+
|
217
|
+
# Retrieve UDAs
|
218
|
+
fresh_task = replica.task(uuid2)
|
219
|
+
if fresh_task
|
220
|
+
puts "UDAs for '#{fresh_task.description}':"
|
221
|
+
|
222
|
+
website = fresh_task.uda("project", "website")
|
223
|
+
hours = fresh_task.uda("estimate", "hours")
|
224
|
+
client = fresh_task.uda("client", "name")
|
225
|
+
|
226
|
+
puts " Project: #{website}" if website
|
227
|
+
puts " Estimated hours: #{hours}" if hours
|
228
|
+
puts " Client: #{client}" if client
|
229
|
+
|
230
|
+
# Get all UDAs
|
231
|
+
all_udas = fresh_task.udas
|
232
|
+
puts " All UDAs: #{all_udas.inspect}" unless all_udas.empty?
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# 10. FINAL STATISTICS
|
237
|
+
puts "\n10. Final Statistics"
|
238
|
+
|
239
|
+
# Refresh task list
|
240
|
+
final_uuids = replica.task_uuids
|
241
|
+
final_tasks = final_uuids.map { |uuid| replica.task(uuid) }.compact
|
242
|
+
|
243
|
+
total_tasks = final_tasks.length
|
244
|
+
pending_count = final_tasks.count(&:pending?)
|
245
|
+
completed_count = final_tasks.count(&:completed?)
|
246
|
+
high_priority_count = final_tasks.count { |t| t.priority == "H" }
|
247
|
+
tagged_count = final_tasks.count { |t| !t.tags.empty? }
|
248
|
+
|
249
|
+
puts "Database Summary:"
|
250
|
+
puts " Total tasks: #{total_tasks}"
|
251
|
+
puts " Pending: #{pending_count}"
|
252
|
+
puts " Completed: #{completed_count}"
|
253
|
+
puts " High priority: #{high_priority_count}"
|
254
|
+
puts " Tagged: #{tagged_count}"
|
255
|
+
|
256
|
+
# Storage information
|
257
|
+
puts "\nStorage Information:"
|
258
|
+
puts " Local operations: #{replica.num_local_operations}"
|
259
|
+
puts " Undo points: #{replica.num_undo_points}"
|
260
|
+
|
261
|
+
puts "\nExample completed successfully!"
|
262
|
+
puts "Database stored at: #{db_path}"
|
263
|
+
|
264
|
+
rescue => e
|
265
|
+
puts "Error: #{e.class} - #{e.message}"
|
266
|
+
puts e.backtrace.first(5).join("\n") if e.backtrace
|
267
|
+
ensure
|
268
|
+
# Clean up temporary directory
|
269
|
+
if temp_dir && File.exist?(temp_dir)
|
270
|
+
FileUtils.remove_entry(temp_dir)
|
271
|
+
puts "\nCleaned up temporary directory: #{temp_dir}"
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
puts "\nFor more examples, see:"
|
276
|
+
puts "- examples/sync_workflow.rb - Synchronization examples"
|
277
|
+
puts "- docs/API_REFERENCE.md - Complete API documentation"
|
278
|
+
puts "- docs/THREAD_SAFETY.md - Thread safety guidelines"
|