Module: DhanHQ::WriteResult
- Defined in:
- lib/DhanHQ/write_result.rb
Overview
Interprets the several shapes a write currently uses to signal failure.
The model write methods do not share a return contract. Depending on which class
and which failure you hit, a rejected write comes back as nil, as false, or as
a ErrorObject — and Models::AlertOrder.modify can return either
of the first two from the same method. A caller cannot write one error branch.
Unifying those contracts is a breaking change for the applications that depend on
this gem, so it is staged (see CHANGELOG). This module is step one: it puts the
knowledge of "what does failure look like" in exactly one place, and backs the bang
variants (+place!+, modify!, cancel!, …) that give callers a single, explicit
failure mode to rescue today.
Constant Summary collapse
- SUPPRESSION_KEY =
Thread-local flag set while a bang variant is calling through.
:dhanhq_suppress_write_deprecation
Class Method Summary collapse
-
.describe(result, errors = nil) ⇒ String
Best available explanation for a failure.
-
.errors_from(receiver) ⇒ Hash?
Validation errors carried by a model instance, when it has any.
-
.failure?(result) ⇒ Boolean
Whether a write result represents a rejected or failed operation.
-
.module_label(mod) ⇒ String
Reads a module's declared name, falling back to
to_sso an anonymous class still yields something readable rather than an object address. -
.operation_label(receiver, name) ⇒ String
Label identifying the operation that failed, for the exception message.
-
.report_ambiguous_failure(result, operation:) ⇒ Object
Reports, once per call site, that a non-bang write signalled failure through a value whose shape is going to change in 4.0.0.
-
.shape_of(result) ⇒ String
Names the shape a failure arrived in, for the notice.
- .success?(result) ⇒ Boolean
- .suppressed? ⇒ Boolean
-
.suppressing_deprecation ⇒ Object
Runs the block with WriteResult.report_ambiguous_failure disabled on this thread.
-
.unwrap!(result, operation:, error_class: DhanHQ::OrderError, errors: nil) ⇒ Object
Returns the result, or raises carrying whatever diagnostics the failure held.
Class Method Details
.describe(result, errors = nil) ⇒ String
Best available explanation for a failure.
154 155 156 157 158 159 160 161 |
# File 'lib/DhanHQ/write_result.rb', line 154 def describe(result, errors = nil) return result.errors.to_s if result.is_a?(DhanHQ::ErrorObject) return errors.to_s if errors && !errors.empty? # `nil` and `false` carry nothing, so say which of the two it was rather than # inventing a cause. result.nil? ? "the API returned no record" : "the API rejected the request" end |
.errors_from(receiver) ⇒ Hash?
Validation errors carried by a model instance, when it has any.
144 145 146 147 148 149 |
# File 'lib/DhanHQ/write_result.rb', line 144 def errors_from(receiver) return nil if receiver.is_a?(Module) return nil unless receiver.respond_to?(:errors) receiver.errors end |
.failure?(result) ⇒ Boolean
Whether a write result represents a rejected or failed operation.
31 32 33 |
# File 'lib/DhanHQ/write_result.rb', line 31 def failure?(result) result.nil? || result == false || result.is_a?(DhanHQ::ErrorObject) end |
.module_label(mod) ⇒ String
Reads a module's declared name, falling back to to_s so an anonymous class
still yields something readable rather than an object address.
136 137 138 |
# File 'lib/DhanHQ/write_result.rb', line 136 def module_label(mod) mod.name || mod.to_s end |
.operation_label(receiver, name) ⇒ String
Label identifying the operation that failed, for the exception message.
126 127 128 129 130 |
# File 'lib/DhanHQ/write_result.rb', line 126 def operation_label(receiver, name) return "#{module_label(receiver)}.#{name}" if receiver.is_a?(Module) "#{module_label(receiver.class)}##{name}" end |
.report_ambiguous_failure(result, operation:) ⇒ Object
Reports, once per call site, that a non-bang write signalled failure through a value whose shape is going to change in 4.0.0.
Step two of the migration: the notice tells a maintainer which of their call sites still branch on the old return value, so they can move to the bang variant before the non-bang contract unifies on ErrorObject. Returns the result untouched — this observes, it never alters behaviour.
Silent when the write succeeded, when the caller opted out via
config.warn_on_ambiguous_write_failure = false, or when reached through a bang
variant (those callers have already migrated — see suppressing_deprecation).
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/DhanHQ/write_result.rb', line 74 def report_ambiguous_failure(result, operation:) return result unless failure?(result) return result if suppressed? return result unless DhanHQ.configuration&.warn_on_ambiguous_write_failure? DhanHQ::Deprecation.warn_once( operation, "#{operation} reported failure as #{shape_of(result)}. Write methods return " \ "nil, false or a DhanHQ::ErrorObject inconsistently today and will all return " \ "DhanHQ::ErrorObject in 4.0.0, which is truthy — an `if result` failure branch " \ "will invert. Use #{operation}! to get a DhanHQ::OrderError instead, or set " \ "config.warn_on_ambiguous_write_failure = false to silence this." ) result end |
.shape_of(result) ⇒ String
Names the shape a failure arrived in, for the notice.
114 115 116 117 118 119 |
# File 'lib/DhanHQ/write_result.rb', line 114 def shape_of(result) return "nil" if result.nil? return "false" if result == false "a DhanHQ::ErrorObject" end |
.success?(result) ⇒ Boolean
37 38 39 |
# File 'lib/DhanHQ/write_result.rb', line 37 def success?(result) !failure?(result) end |
.suppressed? ⇒ Boolean
107 108 109 |
# File 'lib/DhanHQ/write_result.rb', line 107 def suppressed? Thread.current[SUPPRESSION_KEY] == true end |
.suppressing_deprecation ⇒ Object
Runs the block with report_ambiguous_failure disabled on this thread.
Used by the bang variants: they call the non-bang method to get its result, and a
caller who has already moved to place! does not need telling to move to
place!. Thread-local so a concurrent thread still gets its own notices.
98 99 100 101 102 103 104 |
# File 'lib/DhanHQ/write_result.rb', line 98 def suppressing_deprecation previous = Thread.current[SUPPRESSION_KEY] Thread.current[SUPPRESSION_KEY] = true yield ensure Thread.current[SUPPRESSION_KEY] = previous end |
.unwrap!(result, operation:, error_class: DhanHQ::OrderError, errors: nil) ⇒ Object
Returns the result, or raises carrying whatever diagnostics the failure held.
53 54 55 56 57 |
# File 'lib/DhanHQ/write_result.rb', line 53 def unwrap!(result, operation:, error_class: DhanHQ::OrderError, errors: nil) return result if success?(result) raise error_class, "#{operation} failed: #{describe(result, errors)}" end |