taskchampion-rb 0.9.0 → 0.9.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d661bc07cbe2c900550df0973e28fbc8ca3ed34fb8f607e91bdff8824239a6dc
4
- data.tar.gz: e4c5b2908fcac0ec63dcaa1c9e179a6a0b17701cb9c04c884738b4977f86ed64
3
+ metadata.gz: 97cd610777ff12232ab4625cbbca59e2a9241d1789926dd9a5f21d982876f25d
4
+ data.tar.gz: d8b3232d7fe7fe9cdc518136e08e7b3873683c90ac32cf62e1947179f53ded8c
5
5
  SHA512:
6
- metadata.gz: 7aa047cb7dc2adb780e8c2616f726126df2e07bc53e8a357d507d4742ef099a438ed126a7f5849bb43e86136b14dc8044a6038fe7104e94c9a633db6d61101d1
7
- data.tar.gz: 5fb6d41847c431265d85114505b385e36d05c9e5dc7006c92c3c1e29a89adb015a2486f7620b613b28a8132bb1b30f3e6e4d777ee1ba81e623e17aaae7cc441b
6
+ metadata.gz: 61a011d70095d38bb2009a653fa151115b5327282977243cf6bc56947ab38d488b62a027470c363fe45ee40e17c5673f95857207ceb7d5f1d150b109dc60b469
7
+ data.tar.gz: 71e0d7baa33d944308f03d5ae5fb210b840b8834c7081980073e68f1649f2c21b86c0c7a39763a21f8c676019ae3d94bef1f82803071164c6963d59546c015c9
@@ -0,0 +1,54 @@
1
+ # Taskchampion Ruby Errors
2
+
3
+ ## Hierarchy
4
+
5
+ ```
6
+ StandardError
7
+ └── Taskchampion::Error
8
+ ├── Taskchampion::ThreadError
9
+ ├── Taskchampion::StorageError
10
+ ├── Taskchampion::ValidationError
11
+ ├── Taskchampion::ConfigError
12
+ └── Taskchampion::SyncError
13
+ └── Taskchampion::OutOfSyncError
14
+ ```
15
+
16
+ ## Error Classes
17
+
18
+ - **`Taskchampion::Error`** — Base class for all Taskchampion errors.
19
+ - **`Taskchampion::ThreadError`** — Raised when an object (Replica, Task, etc.) is accessed from a thread other than the one that created it.
20
+ - **`Taskchampion::StorageError`** — Raised for database and storage failures (`Error::Database`), and for wrapped IO/SQLite/cloud infrastructure errors (`Error::Other`).
21
+ - **`Taskchampion::ValidationError`** — Raised for incorrect API usage (`Error::Usage`): bad tag names, empty descriptions, invalid UUIDs, wrong argument types, invalid status symbols.
22
+ - **`Taskchampion::ConfigError`** — Defined for compatibility; not raised by the current TaskChampion error variants. Missing sync keyword arguments raise Ruby `ArgumentError` instead.
23
+ - **`Taskchampion::SyncError`** — Raised for server communication errors (`Error::Server`).
24
+ - **`Taskchampion::OutOfSyncError`** — Raised when the local replica is irrecoverably out of sync with the server (`Error::OutOfSync`). Subclass of `SyncError`. Signals that re-syncing from scratch is required, not just a retry.
25
+
26
+ ## Mapping from TaskChampion Rust errors
27
+
28
+ | Rust variant | Ruby class |
29
+ |---|---|
30
+ | `Error::Database(msg)` | `StorageError` |
31
+ | `Error::Server(msg)` | `SyncError` |
32
+ | `Error::OutOfSync` | `OutOfSyncError` |
33
+ | `Error::Usage(msg)` | `ValidationError` |
34
+ | `Error::Other(_)` / unknown | `StorageError` |
35
+
36
+ ## Usage
37
+
38
+ Rescue any error via the base class or individually:
39
+
40
+ ```ruby
41
+ begin
42
+ replica.sync(config)
43
+ rescue Taskchampion::OutOfSyncError => e
44
+ # local replica is irrecoverably diverged — must re-sync from scratch
45
+ rescue Taskchampion::SyncError => e
46
+ # transient server/network error — may retry
47
+ rescue Taskchampion::StorageError => e
48
+ # database or IO failure
49
+ rescue Taskchampion::ValidationError => e
50
+ # bad input
51
+ rescue Taskchampion::Error => e
52
+ # catch-all for any Taskchampion error
53
+ end
54
+ ```
@@ -6,10 +6,19 @@ pub fn init_errors(module: &RModule) -> Result<(), Error> {
6
6
  module.define_error("StorageError", error_class)?;
7
7
  module.define_error("ValidationError", error_class)?;
8
8
  module.define_error("ConfigError", error_class)?;
9
- module.define_error("SyncError", error_class)?;
9
+ let sync_error_class = module.define_error("SyncError", error_class)?;
10
+ module.define_error("OutOfSyncError", sync_error_class)?;
10
11
  Ok(())
11
12
  }
12
13
 
14
+ pub fn base_error() -> magnus::ExceptionClass {
15
+ let ruby = magnus::Ruby::get().expect("Ruby not available");
16
+ let module = ruby.class_object().const_get::<_, RModule>("Taskchampion")
17
+ .expect("Taskchampion module not found");
18
+ module.const_get::<_, magnus::ExceptionClass>("Error")
19
+ .expect("Error class not initialized")
20
+ }
21
+
13
22
  pub fn thread_error() -> magnus::ExceptionClass {
14
23
  let ruby = magnus::Ruby::get().expect("Ruby not available");
15
24
  let module = ruby.class_object().const_get::<_, RModule>("Taskchampion")
@@ -34,45 +43,29 @@ pub fn validation_error() -> magnus::ExceptionClass {
34
43
  .expect("ValidationError class not initialized")
35
44
  }
36
45
 
37
- pub fn config_error() -> magnus::ExceptionClass {
46
+ pub fn sync_error() -> magnus::ExceptionClass {
38
47
  let ruby = magnus::Ruby::get().expect("Ruby not available");
39
48
  let module = ruby.class_object().const_get::<_, RModule>("Taskchampion")
40
49
  .expect("Taskchampion module not found");
41
- module.const_get::<_, magnus::ExceptionClass>("ConfigError")
42
- .expect("ConfigError class not initialized")
50
+ module.const_get::<_, magnus::ExceptionClass>("SyncError")
51
+ .expect("SyncError class not initialized")
43
52
  }
44
53
 
45
- pub fn sync_error() -> magnus::ExceptionClass {
54
+ pub fn out_of_sync_error() -> magnus::ExceptionClass {
46
55
  let ruby = magnus::Ruby::get().expect("Ruby not available");
47
56
  let module = ruby.class_object().const_get::<_, RModule>("Taskchampion")
48
57
  .expect("Taskchampion module not found");
49
- module.const_get::<_, magnus::ExceptionClass>("SyncError")
50
- .expect("SyncError class not initialized")
58
+ module.const_get::<_, magnus::ExceptionClass>("OutOfSyncError")
59
+ .expect("OutOfSyncError class not initialized")
51
60
  }
52
61
 
53
- // Enhanced error mapping function with context-aware error types
54
62
  pub fn map_taskchampion_error(error: taskchampion::Error) -> Error {
55
- let error_msg = error.to_string();
56
-
57
- // Map TaskChampion errors to appropriate Ruby error types based on error content
58
- if error_msg.contains("No such file") || error_msg.contains("Permission denied") ||
59
- error_msg.contains("storage") || error_msg.contains("database") {
60
- Error::new(storage_error(), format!("Storage error: {}", error_msg))
61
- } else if error_msg.contains("sync") || error_msg.contains("server") ||
62
- error_msg.contains("network") || error_msg.contains("remote") {
63
- Error::new(sync_error(), format!("Synchronization error: {}", error_msg))
64
- } else if error_msg.contains("config") || error_msg.contains("invalid config") {
65
- Error::new(config_error(), format!("Configuration error: {}", error_msg))
66
- } else if error_msg.contains("invalid") || error_msg.contains("parse") ||
67
- error_msg.contains("format") || error_msg.contains("validation") {
68
- Error::new(validation_error(), format!("Validation error: {}", error_msg))
69
- } else {
70
- // Generic TaskChampion error for unknown types
71
- let ruby = magnus::Ruby::get().expect("Ruby not available");
72
- let module = ruby.class_object().const_get::<_, RModule>("Taskchampion")
73
- .expect("Taskchampion module not found");
74
- let error_class = module.const_get::<_, magnus::ExceptionClass>("Error")
75
- .expect("Error class not initialized");
76
- Error::new(error_class, format!("TaskChampion error: {}", error_msg))
63
+ match error {
64
+ taskchampion::Error::Database(msg) => Error::new(storage_error(), msg),
65
+ taskchampion::Error::Server(msg) => Error::new(sync_error(), msg),
66
+ taskchampion::Error::OutOfSync => Error::new(out_of_sync_error(),
67
+ "Local replica is out of sync with the server"),
68
+ taskchampion::Error::Usage(msg) => Error::new(validation_error(), msg),
69
+ _ => Error::new(storage_error(), error.to_string()),
77
70
  }
78
71
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Taskchampion
4
- VERSION = "0.9.0"
4
+ VERSION = "0.9.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: taskchampion-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Case
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-10-16 00:00:00.000000000 Z
11
+ date: 2026-05-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rb_sys
@@ -41,6 +41,7 @@ files:
41
41
  - Cargo.toml
42
42
  - README.md
43
43
  - Rakefile
44
+ - TaskchampionRbErrors.md
44
45
  - docs/ANNOTATION_IMPLEMENTATION.md
45
46
  - docs/API_REFERENCE.md
46
47
  - docs/THREAD_SAFETY.md