{"id":18586010,"url":"https://github.com/cloud66-oss/exception_extensions","last_synced_at":"2025-04-10T13:31:38.863Z","repository":{"id":56848096,"uuid":"224454139","full_name":"cloud66-oss/exception_extensions","owner":"cloud66-oss","description":"Ruby Gem providing some useful extensions for Ruby Exceptions","archived":false,"fork":false,"pushed_at":"2019-12-05T16:10:23.000Z","size":21,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-24T15:27:14.799Z","etag":null,"topics":["ruby","rubygem"],"latest_commit_sha":null,"homepage":"https://www.cloud66.com","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cloud66-oss.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-11-27T14:53:52.000Z","updated_at":"2022-08-31T11:18:38.000Z","dependencies_parsed_at":"2022-09-07T01:01:31.191Z","dependency_job_id":null,"html_url":"https://github.com/cloud66-oss/exception_extensions","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud66-oss%2Fexception_extensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud66-oss%2Fexception_extensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud66-oss%2Fexception_extensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cloud66-oss%2Fexception_extensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cloud66-oss","download_url":"https://codeload.github.com/cloud66-oss/exception_extensions/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248225708,"owners_count":21068078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ruby","rubygem"],"created_at":"2024-11-07T00:36:21.700Z","updated_at":"2025-04-10T13:31:33.849Z","avatar_url":"https://github.com/cloud66-oss.png","language":"Ruby","readme":"\u003cimg src=\"http://cdn2-cloud66-com.s3.amazonaws.com/images/oss-sponsorship.png\" width=150/\u003e\n\n# ExceptionExtensions\n\nExceptionExtensions provides some custom Exception types to handle Exception collections. It also provides some helpers that enable traversal of the exceptions and the their causes.\n\nWhenever you perform a fanout operation that then joins again, there could potentially be more than one exception raised. This library provides some simple and easy to use classes to handle these scenarios.\n\nTo illustrate this, assume we want to perform an operation that itself does three things internally. Each of the three things it does occur in parallel. At the end of the operation we can gather all the exceptions that might have occurred. We can then raise a `StandardErrorCollection` (or custom collection that has the `CauseEnumerable` mixin) to encapsulate all of these exceptions. In the future, to log these for example, we can determine the exception path for each distinct exception via the `ExceptionPathTraverser`.\n\n## Install\n\nInstalling the gem directly:\n```\ngem install exception_extensions\n```\n\nIf using `bundler`, add to your `Gemfile`:\n\n```\ngem 'exception_extensions'\n```\n\n## Usage Examples\n\n### Assume the following operation\n```ruby\ndef the_operation\n  # collection of exceptions\n  exceptions = []\n  (1..2).each do |i|\n    begin\n      if i == 1\n        # cause \"divided by 0\" error\n        1/0\n      else\n        # cause \"ArgumentError\"\n        raise ArgumentError.new('expected a 1')\n      end\n    rescue =\u003e exc\n      exceptions \u003c\u003c exc\n    end\n  end\n  # raise a collection exception\n  raise ::ExceptionExtensions::StandardErrorCollection.new(exceptions, 'multiple exceptions occurred during the_operation') unless exceptions.empty?\nend\n```\n\n### Example1: Calling the_operation directly\n```ruby\nbegin\n  the_operation  \nrescue =\u003e exc\n  # output exception\n  puts \"exception0 class: #{exc.class.name}\"\n  puts \"exception0 message: #{exc.message}\"\n  # we can look at the collection of exception causes directly\n  # for Exceptions that implement ::ExceptionExtensions::CauseEnumerable\n  exc.causes.each_with_index do |cause, idx| \n    puts \"exception#{idx+1} class: #{cause.class.name}\"\n    puts \"exception#{idx+1} message: #{cause.message}\"\n  end\nend\n```\n**OUTPUT** \n```\nexception0 class: ExceptionExtensions::StandardErrorCollection\nexception0 message: multiple exceptions occurred during the_operation\nexception1 class: ZeroDivisionError\nexception1 message: divided by 0\nexception2 class: ArgumentError\nexception2 message: expected a 1\n```\n\n### Example2: Calling the_operation indirectly resulting in an exception chain\n```ruby\n# here, we illustrate traversing the exception chain\ndef handle_operations\n  the_operation  \nrescue =\u003e exc\n  raise \"Unable to handle operations\"  \nend\n\nbegin\n  handle_operations\nrescue =\u003e exc\n  # now, we create a path traverser for each unique exception path\n  # (there may be causes within cause for an exception chain)\n  exception_traverser = ::ExceptionExtensions::ExceptionPathTraverser.new(exc)\n  # traverse each unique exception path \n  exception_traverser.each do |exception_path| \n    # output exception information\n    exception_path.each_with_index do |exception, idx| \n      puts \"exception#{idx} class: #{exception.class.name}\"\n      puts \"exception#{idx} message: #{exception.message}\"\n    end\n    # output exception information as a chain of messages    \n    puts \"JOINED: \\\"#{exception_path.join(' =\u003e ')}\\\"\"\n    puts\n  end\nend\n```\n**OUTPUT** \n```\nexception0 class: RuntimeError\nexception0 message: Unable to handle operations\nexception1 class: ExceptionExtensions::StandardErrorCollection\nexception1 message: multiple exceptions occurred during the_operation\nexception2 class: ZeroDivisionError\nexception2 message: divided by 0\nJOINED: \"Unable to handle operations =\u003e multiple exceptions occurred during the_operation =\u003e divided by 0\"\n\nexception0 class: RuntimeError\nexception0 message: Unable to handle operations\nexception1 class: ExceptionExtensions::StandardErrorCollection\nexception1 message: multiple exceptions occurred during the_operation\nexception2 class: ArgumentError\nexception2 message: expected a 1\nJOINED: \"Unable to handle operations =\u003e multiple exceptions occurred during the_operation =\u003e expected a 1\"\n\n```  \n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloud66-oss%2Fexception_extensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcloud66-oss%2Fexception_extensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcloud66-oss%2Fexception_extensions/lists"}