squake 0.2.4 → 0.3.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 +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +75 -46
- data/lib/squake/calculation.rb +16 -8
- data/lib/squake/calculation_with_pricing.rb +15 -7
- data/lib/squake/client.rb +4 -4
- data/lib/squake/config.rb +5 -5
- data/lib/squake/errors/api_error_result.rb +22 -0
- data/lib/squake/errors/api_error_source.rb +12 -0
- data/lib/squake/model/carbon.rb +2 -2
- data/lib/squake/model/price.rb +7 -9
- data/lib/squake/model/pricing.rb +8 -5
- data/lib/squake/model/product.rb +4 -4
- data/lib/squake/products.rb +15 -7
- data/lib/squake/purchase.rb +46 -21
- data/lib/squake/return.rb +64 -0
- data/lib/squake/version.rb +1 -1
- data/lib/squake.rb +29 -4
- metadata +5 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f7838d5d10515e9d94811494249d36e789e441a04ab31f7e94c83c306a9fb2bf
         | 
| 4 | 
            +
              data.tar.gz: 61d6f7415ec816567ebf260493d43f1a3515090b9062e1740b339f4eb40de405
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 314d29865f690a9d4f7faf867269686dc5b184e9e36aa988d5ea19c60b75d608e09d9e90ccd086f733cfb01dd753c8c8b036a406cb48f1d3444d61f57b049fdc
         | 
| 7 | 
            +
              data.tar.gz: 1234e584e92277e455c8d3094b3624e54e37b972af10c27c1f6836ce5bb4ca54f92f2b548fe95be5dca2531b6c9d7f0a87072aae1fb0afd4e5f06be163287394
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 | |
| 7 7 |  | 
| 8 8 | 
             
            ## [Unreleased]
         | 
| 9 9 |  | 
| 10 | 
            +
            ## [0.3.0] - 2023-06-21
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ### Added
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            * added `Squake.configure`
         | 
| 15 | 
            +
            * introduced global config allowig to omit the `client` from all service calls
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            ### Changed
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            * All public services now return a `Return` class that contains the actual data or an error object. This replaces the throwing of errors for control-flow.
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            ## [0.2.1 - 0.2.4] - 2023-06-21
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            ### Fixed
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            * Boilerplate bugs
         | 
| 26 | 
            +
             | 
| 10 27 | 
             
            ## [0.2.0] - 2023-06-15
         | 
| 11 28 |  | 
| 12 29 | 
             
            ### Added
         | 
    
        data/README.md
    CHANGED
    
    | @@ -2,6 +2,8 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            Find the documentation here: [docs](https://docs.squake.earth/).
         | 
| 4 4 |  | 
| 5 | 
            +
            This gem follows SemVer, however only after a stable release 1.0.0 is made.
         | 
| 6 | 
            +
             | 
| 5 7 | 
             
            ## Installation
         | 
| 6 8 |  | 
| 7 9 | 
             
            Via rubygems:
         | 
| @@ -10,10 +12,10 @@ Via rubygems: | |
| 10 12 | 
             
            gem 'squake'
         | 
| 11 13 | 
             
            ```
         | 
| 12 14 |  | 
| 13 | 
            -
             | 
| 15 | 
            +
            Test the latest version via git:
         | 
| 14 16 |  | 
| 15 17 | 
             
            ```ruby
         | 
| 16 | 
            -
            gem 'squake', git: 'git@github.com:squake-earth/squake-ruby'
         | 
| 18 | 
            +
            gem 'squake', git: 'git@github.com:squake-earth/squake-ruby', branch: :main
         | 
| 17 19 | 
             
            ```
         | 
| 18 20 |  | 
| 19 21 | 
             
            ## Auth
         | 
| @@ -30,7 +32,9 @@ You need a different API Key for production and sandbox. | |
| 30 32 |  | 
| 31 33 | 
             
            ## Usage
         | 
| 32 34 |  | 
| 33 | 
            -
            Initialize the client | 
| 35 | 
            +
            ### Initialize the client
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            either explicitly anywhere in the app
         | 
| 34 38 |  | 
| 35 39 | 
             
            ```ruby
         | 
| 36 40 | 
             
            config = Squake::Config.new(
         | 
| @@ -46,9 +50,34 @@ config = Squake::Config.new( | |
| 46 50 | 
             
            client = Squake::Client.new(config: config)
         | 
| 47 51 | 
             
            ```
         | 
| 48 52 |  | 
| 49 | 
            -
             | 
| 53 | 
            +
            or once globally in e.g. an initializer
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            ```ruby
         | 
| 56 | 
            +
            Squake.configure do |config|
         | 
| 57 | 
            +
              config.api_key = ENV.fetch('SQUAKE_API_KEY') # optional if ENV var `SQUAKE_API_KEY` is set
         | 
| 58 | 
            +
              config.sandbox_mode = true                   # set to `false` for production
         | 
| 59 | 
            +
              config.keep_alive_timeout = 30               # optional, default: 30
         | 
| 60 | 
            +
              config.logger = Logger.new($stdout)          # Set this to `Rails.logger` when using Rails
         | 
| 61 | 
            +
              config.enforced_api_base = nil               # for testing to e.g. point to a local server
         | 
| 62 | 
            +
            end
         | 
| 63 | 
            +
            ```
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            If you have the API Key in an ENV var named `SQUAKE_API_KEY`, you don't need any further config.
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            ### Fetch available products
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            ```ruby
         | 
| 70 | 
            +
            context = Squake::Products.get
         | 
| 71 | 
            +
            products = context.result # [Squake::Model::Product]
         | 
| 72 | 
            +
            ```
         | 
| 73 | 
            +
             | 
| 74 | 
            +
            ### Define items you want emissions to be computed
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            Find all available item types and methodologies in the [docs](https://docs-v2.squake.earth/group/endpoint-calculations).
         | 
| 50 77 |  | 
| 51 78 | 
             
            ```ruby
         | 
| 79 | 
            +
            # NOTE: some items are also available as typed objects, found at `lib/squake/model/items/**/*.rb`
         | 
| 80 | 
            +
            #       where `.../items/private_jet/squake` is the item for type "private_jet" and methodology "squake".
         | 
| 52 81 | 
             
            items = [
         | 
| 53 82 | 
             
              {
         | 
| 54 83 | 
             
                type: 'flight',
         | 
| @@ -59,69 +88,81 @@ items = [ | |
| 59 88 | 
             
                number_of_travellers: 2,
         | 
| 60 89 | 
             
                aircraft_type: '350',
         | 
| 61 90 | 
             
                external_reference: 'booking-id',
         | 
| 62 | 
            -
              }
         | 
| 91 | 
            +
              },
         | 
| 92 | 
            +
              Squake::Model::Items::PrivateJet::Squake.new(
         | 
| 93 | 
            +
                origin: 'SIN',
         | 
| 94 | 
            +
                destination: 'HND',
         | 
| 95 | 
            +
                external_reference: 'my-booking-id',
         | 
| 96 | 
            +
                identifier: 'P180',
         | 
| 97 | 
            +
                identifier_kind: 'ICAO',
         | 
| 98 | 
            +
              ),
         | 
| 63 99 | 
             
            ]
         | 
| 100 | 
            +
            ```
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            ### Calculate emissions (without price quote)
         | 
| 64 103 |  | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
              client: client,        # required
         | 
| 104 | 
            +
            ```ruby
         | 
| 105 | 
            +
            context = Squake::Calculation.create(
         | 
| 68 106 | 
             
              items: items,          # required
         | 
| 69 107 | 
             
              carbon_unit: 'gram',   # optional, default: 'gram', other options: 'kilogram', 'tonne'
         | 
| 70 108 | 
             
              expand: [],            # optional, default: [], allowed values: 'items' to enrich the response
         | 
| 109 | 
            +
              client: client,        # optional
         | 
| 71 110 | 
             
            )
         | 
| 111 | 
            +
             | 
| 112 | 
            +
            # alias: context.failed?
         | 
| 113 | 
            +
            if context.success?
         | 
| 114 | 
            +
              context.result # Squake::Model::Carbon
         | 
| 115 | 
            +
            else
         | 
| 116 | 
            +
              context.errors # [Squake::Errors::APIErrorResult]
         | 
| 117 | 
            +
            end
         | 
| 72 118 | 
             
            ```
         | 
| 73 119 |  | 
| 74 | 
            -
            Calculate emissions and include a price quote | 
| 120 | 
            +
            ### Calculate emissions and include a price quote
         | 
| 75 121 |  | 
| 76 122 | 
             
            ```ruby
         | 
| 77 | 
            -
             | 
| 78 | 
            -
            #   https://docs-v2.squake.earth/group/endpoint-calculations
         | 
| 79 | 
            -
            items = [
         | 
| 80 | 
            -
              {
         | 
| 81 | 
            -
                type: 'flight',
         | 
| 82 | 
            -
                methodology: 'ICAO',
         | 
| 83 | 
            -
                origin: 'BER',
         | 
| 84 | 
            -
                destination: 'SIN',
         | 
| 85 | 
            -
                booking_class: 'economy',
         | 
| 86 | 
            -
                number_of_travellers: 2,
         | 
| 87 | 
            -
                aircraft_type: '350',
         | 
| 88 | 
            -
                external_reference: 'booking-id',
         | 
| 89 | 
            -
              }
         | 
| 90 | 
            -
            ]
         | 
| 91 | 
            -
             | 
| 92 | 
            -
            # returns Squake::Model::Pricing
         | 
| 93 | 
            -
            pricing = Squake::CalculationWithPricing.quote(
         | 
| 94 | 
            -
              client: client,        # required
         | 
| 123 | 
            +
            context = Squake::CalculationWithPricing.quote(
         | 
| 95 124 | 
             
              items: items,          # required
         | 
| 96 125 | 
             
              product: 'product-id', # required
         | 
| 97 126 | 
             
              currency: 'EUR',       # optional, default: 'EUR'
         | 
| 98 127 | 
             
              carbon_unit: 'gram',   # optional, default: 'gram', other options: 'kilogram', 'tonne'
         | 
| 99 128 | 
             
              expand: [],            # optional, default: [], allowed values: 'items', 'product', 'price' to enrich the response
         | 
| 129 | 
            +
              client: client,        # optional
         | 
| 100 130 | 
             
            )
         | 
| 131 | 
            +
             | 
| 132 | 
            +
            if context.success?
         | 
| 133 | 
            +
              context.result # Squake::Model::Pricing
         | 
| 134 | 
            +
            else
         | 
| 135 | 
            +
              context.errors # [Squake::Errors::APIErrorResult]
         | 
| 136 | 
            +
            end
         | 
| 101 137 | 
             
            ```
         | 
| 102 138 |  | 
| 103 | 
            -
            Place a purchase order | 
| 139 | 
            +
            ### Place a purchase order
         | 
| 140 | 
            +
             | 
| 141 | 
            +
            by default the library injects a `SecureRandom.uuid` as `external_reference` to ensure idempotency, i.e. you can safely retry the request if it fails.
         | 
| 104 142 |  | 
| 105 143 | 
             
            ```ruby
         | 
| 106 144 | 
             
            uuid = SecureRandom.uuid
         | 
| 107 145 |  | 
| 108 146 | 
             
            # returns Squake::Model::Purchase
         | 
| 109 | 
            -
             | 
| 110 | 
            -
              client: client,           # required
         | 
| 147 | 
            +
            context = Squake::Purchase.create(
         | 
| 111 148 | 
             
              pricing: pricing.id,      # required, from above
         | 
| 112 149 | 
             
              external_reference: uuid, # optional, default: SecureRandom.uuid, used for idempotency, if given, MUST be unique
         | 
| 150 | 
            +
              client: client,           # optional
         | 
| 113 151 | 
             
            )
         | 
| 114 152 |  | 
| 153 | 
            +
            context.result # Squake::Model::Purchase
         | 
| 154 | 
            +
            context.errors # [Squake::Errors::APIErrorResult]
         | 
| 155 | 
            +
             | 
| 115 156 | 
             
            # retrieve the purchase later
         | 
| 116 157 | 
             
            Squake::Purchase.retrieve(
         | 
| 117 | 
            -
              client: client,  # required
         | 
| 118 158 | 
             
              id: purchase.id, # required
         | 
| 159 | 
            +
              client: client,  # optional
         | 
| 119 160 | 
             
            )
         | 
| 120 161 |  | 
| 121 162 | 
             
            # within 14 days, you can cancel the purchase worry-free
         | 
| 122 163 | 
             
            Squake::Purchase.cancel(
         | 
| 123 | 
            -
              client: client,  # required
         | 
| 124 164 | 
             
              id: purchase.id, # required
         | 
| 165 | 
            +
              client: client,  # optional
         | 
| 125 166 | 
             
            )
         | 
| 126 167 | 
             
            ```
         | 
| 127 168 |  | 
| @@ -133,22 +174,10 @@ Please commit small and focused PRs with descriptive commit messages. If you are | |
| 133 174 |  | 
| 134 175 | 
             
            ## Publishing a new version
         | 
| 135 176 |  | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
            ```shell
         | 
| 139 | 
            -
            ---
         | 
| 140 | 
            -
            :rubygems_squake: rubygems_xxx
         | 
| 141 | 
            -
            ```
         | 
| 142 | 
            -
             | 
| 143 | 
            -
            Then run:
         | 
| 177 | 
            +
            run
         | 
| 144 178 |  | 
| 145 179 | 
             
            ```shell
         | 
| 146 180 | 
             
            bin/release
         | 
| 147 181 | 
             
            ```
         | 
| 148 182 |  | 
| 149 | 
            -
            which will guide you through the release process | 
| 150 | 
            -
             | 
| 151 | 
            -
            * create a new git tag from current main
         | 
| 152 | 
            -
            * create a GitHub release from the tag
         | 
| 153 | 
            -
            * build the gem locally
         | 
| 154 | 
            -
            * publish the gem to RubyGems
         | 
| 183 | 
            +
            which will guide you through the release process.
         | 
    
        data/lib/squake/calculation.rb
    CHANGED
    
    | @@ -10,13 +10,13 @@ module Squake | |
| 10 10 |  | 
| 11 11 | 
             
                sig do
         | 
| 12 12 | 
             
                  params(
         | 
| 13 | 
            -
                    client: Squake::Client,
         | 
| 14 13 | 
             
                    items: T::Array[T.any(Squake::Model::Items::BaseType, T::Hash[T.any(String, Symbol), T.untyped])],
         | 
| 15 14 | 
             
                    carbon_unit: String,
         | 
| 16 15 | 
             
                    expand: T::Array[String],
         | 
| 17 | 
            -
             | 
| 16 | 
            +
                    client: Squake::Client,
         | 
| 17 | 
            +
                  ).returns(Squake::Return[Squake::Model::Carbon])
         | 
| 18 18 | 
             
                end
         | 
| 19 | 
            -
                def self.create( | 
| 19 | 
            +
                def self.create(items:, carbon_unit: 'gram', expand: [], client: Squake::Client.new)
         | 
| 20 20 | 
             
                  # @TODO: add typed objects for all possible items. Until then, we allow either a Hash or a T::Struct
         | 
| 21 21 | 
             
                  items = items.map do |item|
         | 
| 22 22 | 
             
                    item.is_a?(T::Struct) ? item.serialize : item
         | 
| @@ -26,16 +26,24 @@ module Squake | |
| 26 26 | 
             
                    path: ENDPOINT,
         | 
| 27 27 | 
             
                    method: :post,
         | 
| 28 28 | 
             
                    params: {
         | 
| 29 | 
            -
                      items: items | 
| 29 | 
            +
                      items: items,
         | 
| 30 30 | 
             
                      carbon_unit: carbon_unit,
         | 
| 31 31 | 
             
                      expand: expand,
         | 
| 32 32 | 
             
                    },
         | 
| 33 33 | 
             
                  )
         | 
| 34 | 
            -
                  raise Squake::APIError.new(response: result) unless result.success?
         | 
| 35 34 |  | 
| 36 | 
            -
                   | 
| 37 | 
            -
                     | 
| 38 | 
            -
             | 
| 35 | 
            +
                  if result.success?
         | 
| 36 | 
            +
                    carbon = Squake::Model::Carbon.from_api_response(
         | 
| 37 | 
            +
                      T.cast(result.body, T::Hash[Symbol, T.untyped]),
         | 
| 38 | 
            +
                    )
         | 
| 39 | 
            +
                    Return.new(result: carbon)
         | 
| 40 | 
            +
                  else
         | 
| 41 | 
            +
                    error = Squake::Errors::APIErrorResult.new(
         | 
| 42 | 
            +
                      code: :"api_error_#{result.code}",
         | 
| 43 | 
            +
                      detail: result.error_message,
         | 
| 44 | 
            +
                    )
         | 
| 45 | 
            +
                    Return.new(errors: [error])
         | 
| 46 | 
            +
                  end
         | 
| 39 47 | 
             
                end
         | 
| 40 48 | 
             
              end
         | 
| 41 49 | 
             
            end
         | 
| @@ -10,15 +10,15 @@ module Squake | |
| 10 10 |  | 
| 11 11 | 
             
                sig do
         | 
| 12 12 | 
             
                  params(
         | 
| 13 | 
            -
                    client: Squake::Client,
         | 
| 14 13 | 
             
                    items: T::Array[T.any(Squake::Model::Items::BaseType, T::Hash[T.any(String, Symbol), T.untyped])],
         | 
| 15 14 | 
             
                    product: String,
         | 
| 16 15 | 
             
                    currency: String,
         | 
| 17 16 | 
             
                    carbon_unit: String,
         | 
| 18 17 | 
             
                    expand: T::Array[String],
         | 
| 19 | 
            -
             | 
| 18 | 
            +
                    client: Squake::Client,
         | 
| 19 | 
            +
                  ).returns(Squake::Return[Squake::Model::Pricing])
         | 
| 20 20 | 
             
                end
         | 
| 21 | 
            -
                def self.quote( | 
| 21 | 
            +
                def self.quote(items:, product:, currency: 'EUR', carbon_unit: 'gram', expand: [], client: Squake::Client.new)
         | 
| 22 22 | 
             
                  # @TODO: add typed objects for all possible items. Until then, we allow either a Hash or a T::Struct
         | 
| 23 23 | 
             
                  items = items.map do |item|
         | 
| 24 24 | 
             
                    item.is_a?(T::Struct) ? item.serialize : item
         | 
| @@ -35,11 +35,19 @@ module Squake | |
| 35 35 | 
             
                      expand: expand,
         | 
| 36 36 | 
             
                    },
         | 
| 37 37 | 
             
                  )
         | 
| 38 | 
            -
                  raise Squake::APIError.new(response: result) unless result.success?
         | 
| 39 38 |  | 
| 40 | 
            -
                   | 
| 41 | 
            -
                     | 
| 42 | 
            -
             | 
| 39 | 
            +
                  if result.success?
         | 
| 40 | 
            +
                    pricing = Squake::Model::Pricing.from_api_response(
         | 
| 41 | 
            +
                      T.cast(result.body, T::Hash[Symbol, T.untyped]),
         | 
| 42 | 
            +
                    )
         | 
| 43 | 
            +
                    Return.new(result: pricing)
         | 
| 44 | 
            +
                  else
         | 
| 45 | 
            +
                    error = Squake::Errors::APIErrorResult.new(
         | 
| 46 | 
            +
                      code: :"api_error_#{result.code}",
         | 
| 47 | 
            +
                      detail: result.error_message,
         | 
| 48 | 
            +
                    )
         | 
| 49 | 
            +
                    Return.new(errors: [error])
         | 
| 50 | 
            +
                  end
         | 
| 43 51 | 
             
                end
         | 
| 44 52 | 
             
              end
         | 
| 45 53 | 
             
            end
         | 
    
        data/lib/squake/client.rb
    CHANGED
    
    | @@ -14,9 +14,9 @@ module Squake | |
| 14 14 | 
             
                  )
         | 
| 15 15 | 
             
                end
         | 
| 16 16 |  | 
| 17 | 
            -
                sig { params(config: Squake::Config).void }
         | 
| 18 | 
            -
                def initialize(config:)
         | 
| 19 | 
            -
                  @config = config
         | 
| 17 | 
            +
                sig { params(config: T.nilable(Squake::Config)).void }
         | 
| 18 | 
            +
                def initialize(config: nil)
         | 
| 19 | 
            +
                  @config = T.let(config || T.must(Squake.configuration), Squake::Config)
         | 
| 20 20 | 
             
                end
         | 
| 21 21 |  | 
| 22 22 | 
             
                sig do
         | 
| @@ -53,7 +53,7 @@ module Squake | |
| 53 53 | 
             
                end
         | 
| 54 54 | 
             
                private def execute_request(method:, path:, headers: {}, params: nil, api_base: nil, api_key: nil)
         | 
| 55 55 | 
             
                  api_base ||= @config.api_base
         | 
| 56 | 
            -
                  api_key ||= @config.api_key
         | 
| 56 | 
            +
                  api_key ||= T.must(@config.api_key)
         | 
| 57 57 |  | 
| 58 58 | 
             
                  body_params = nil
         | 
| 59 59 | 
             
                  query_params = nil
         | 
    
        data/lib/squake/config.rb
    CHANGED
    
    | @@ -10,11 +10,11 @@ module Squake | |
| 10 10 | 
             
                DEFAULT_BASE_URL = T.let('https://api.squake.earth', String)
         | 
| 11 11 | 
             
                SANDBOX_BASE_URL = T.let('https://api.sandbox.squake.earth', String)
         | 
| 12 12 |  | 
| 13 | 
            -
                 | 
| 14 | 
            -
                 | 
| 15 | 
            -
                 | 
| 16 | 
            -
                 | 
| 17 | 
            -
                 | 
| 13 | 
            +
                prop :api_key, T.nilable(String)
         | 
| 14 | 
            +
                prop :keep_alive_timeout, Integer, default: 30
         | 
| 15 | 
            +
                prop :logger, ::Logger, factory: -> { ::Logger.new($stdout) }
         | 
| 16 | 
            +
                prop :sandbox_mode, T::Boolean, default: true
         | 
| 17 | 
            +
                prop :enforced_api_base, T.nilable(String)
         | 
| 18 18 |  | 
| 19 19 | 
             
                sig { returns(String) }
         | 
| 20 20 | 
             
                def api_base
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require_relative 'api_error_source'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Squake
         | 
| 7 | 
            +
              module Errors
         | 
| 8 | 
            +
                #
         | 
| 9 | 
            +
                # https://jsonapi.org/format/#errors
         | 
| 10 | 
            +
                #
         | 
| 11 | 
            +
                # > Error objects MUST be returned as an array keyed by errors in the top level of a JSON:API document.
         | 
| 12 | 
            +
                #
         | 
| 13 | 
            +
                class APIErrorResult < T::Struct
         | 
| 14 | 
            +
                  const :code, Symbol # An application-specific error code
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  # A human-readable explanation specific to this occurrence of the problem.
         | 
| 17 | 
            +
                  # Like title, this field's value can be localized.
         | 
| 18 | 
            +
                  const :detail, T.nilable(String)
         | 
| 19 | 
            +
                  const :source, T.nilable(APIErrorSource)
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Squake
         | 
| 5 | 
            +
              module Errors
         | 
| 6 | 
            +
                class APIErrorSource < T::Struct
         | 
| 7 | 
            +
                  const :attribute, T.any(Symbol, String)
         | 
| 8 | 
            +
                  const :model, T.nilable(String), default: nil
         | 
| 9 | 
            +
                  const :id, T.nilable(String), default: nil # external reference if given
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
    
        data/lib/squake/model/carbon.rb
    CHANGED
    
    | @@ -15,8 +15,8 @@ module Squake | |
| 15 15 | 
             
                  sig { params(response_body: T::Hash[Symbol, T.untyped]).returns(Squake::Model::Carbon) }
         | 
| 16 16 | 
             
                  def self.from_api_response(response_body)
         | 
| 17 17 | 
             
                    Squake::Model::Carbon.new(
         | 
| 18 | 
            -
                      quantity: BigDecimal(String(response_body.fetch(: | 
| 19 | 
            -
                      unit: CarbonUnit.deserialize(response_body.fetch(: | 
| 18 | 
            +
                      quantity: BigDecimal(String(response_body.fetch(:carbon_quantity))),
         | 
| 19 | 
            +
                      unit: CarbonUnit.deserialize(response_body.fetch(:carbon_unit)),
         | 
| 20 20 | 
             
                      items: response_body.fetch(:items, nil),
         | 
| 21 21 | 
             
                    )
         | 
| 22 22 | 
             
                  end
         | 
    
        data/lib/squake/model/price.rb
    CHANGED
    
    | @@ -9,21 +9,19 @@ module Squake | |
| 9 9 | 
             
                  const :id, String
         | 
| 10 10 | 
             
                  const :product, String
         | 
| 11 11 | 
             
                  const :unit_amount, BigDecimal
         | 
| 12 | 
            -
                  const :valid_from,  | 
| 12 | 
            +
                  const :valid_from, Date
         | 
| 13 13 | 
             
                  const :carbon_unit, String
         | 
| 14 14 | 
             
                  const :currency, String
         | 
| 15 15 |  | 
| 16 16 | 
             
                  sig { params(response_body: T::Hash[Symbol, T.untyped]).returns(Squake::Model::Price) }
         | 
| 17 17 | 
             
                  def self.from_api_response(response_body)
         | 
| 18 | 
            -
                    product = response_body.fetch(:price, {})
         | 
| 19 | 
            -
             | 
| 20 18 | 
             
                    Squake::Model::Price.new(
         | 
| 21 | 
            -
                      id:  | 
| 22 | 
            -
                      product:  | 
| 23 | 
            -
                      unit_amount:  | 
| 24 | 
            -
                      valid_from: Date.parse( | 
| 25 | 
            -
                      carbon_unit:  | 
| 26 | 
            -
                      currency:  | 
| 19 | 
            +
                      id: response_body.fetch(:id),
         | 
| 20 | 
            +
                      product: response_body.fetch(:product),
         | 
| 21 | 
            +
                      unit_amount: BigDecimal(response_body.fetch(:unit_amount).to_s),
         | 
| 22 | 
            +
                      valid_from: Date.parse(response_body.fetch(:valid_from)),
         | 
| 23 | 
            +
                      carbon_unit: response_body.fetch(:carbon_unit),
         | 
| 24 | 
            +
                      currency: response_body.fetch(:currency),
         | 
| 27 25 | 
             
                    )
         | 
| 28 26 | 
             
                  end
         | 
| 29 27 | 
             
                end
         | 
    
        data/lib/squake/model/pricing.rb
    CHANGED
    
    | @@ -24,8 +24,8 @@ module Squake | |
| 24 24 | 
             
                  const :carbon_quantity, BigDecimal
         | 
| 25 25 | 
             
                  const :carbon_unit, String
         | 
| 26 26 | 
             
                  const :payment_link, T.nilable(String)
         | 
| 27 | 
            -
                  const :price, Squake::Model::Price
         | 
| 28 | 
            -
                  const :product, Squake::Model::Product
         | 
| 27 | 
            +
                  const :price, T.any(Squake::Model::Price, String)
         | 
| 28 | 
            +
                  const :product, T.any(Squake::Model::Product, String)
         | 
| 29 29 | 
             
                  const :valid_until, Date
         | 
| 30 30 | 
             
                  const :currency, String, default: 'EUR'
         | 
| 31 31 | 
             
                  const :total, Integer
         | 
| @@ -33,10 +33,13 @@ module Squake | |
| 33 33 |  | 
| 34 34 | 
             
                  sig { params(response_body: T::Hash[Symbol, T.untyped]).returns(Squake::Model::Pricing) }
         | 
| 35 35 | 
             
                  def self.from_api_response(response_body)
         | 
| 36 | 
            -
                     | 
| 37 | 
            -
                     | 
| 36 | 
            +
                    price_or_id = T.let(response_body.fetch(:price), T.any(String, T::Hash[Symbol, T.untyped]))
         | 
| 37 | 
            +
                    price = price_or_id.is_a?(Hash) ? Squake::Model::Price.from_api_response(price_or_id) : price_or_id
         | 
| 38 38 |  | 
| 39 | 
            -
                     | 
| 39 | 
            +
                    product_or_id = T.let(response_body.fetch(:product), T.any(String, T::Hash[Symbol, T.untyped]))
         | 
| 40 | 
            +
                    product = product_or_id.is_a?(Hash) ? Squake::Model::Product.from_api_response(product_or_id) : product_or_id
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    items = response_body.fetch(:items, []) || []
         | 
| 40 43 | 
             
                    items.map! do |item|
         | 
| 41 44 | 
             
                      item[:carbon_quantity] = item.fetch(:carbon_quantity).to_d
         | 
| 42 45 | 
             
                      item[:distance] = item.fetch(:distance).to_d
         | 
    
        data/lib/squake/model/product.rb
    CHANGED
    
    | @@ -8,14 +8,14 @@ module Squake | |
| 8 8 |  | 
| 9 9 | 
             
                  const :id, String
         | 
| 10 10 | 
             
                  const :title, String
         | 
| 11 | 
            +
                  const :certifications, T::Array[String], default: []
         | 
| 11 12 |  | 
| 12 13 | 
             
                  sig { params(response_body: T::Hash[Symbol, T.untyped]).returns(Squake::Model::Product) }
         | 
| 13 14 | 
             
                  def self.from_api_response(response_body)
         | 
| 14 | 
            -
                    product = response_body.fetch(:product, {})
         | 
| 15 | 
            -
             | 
| 16 15 | 
             
                    Squake::Model::Product.new(
         | 
| 17 | 
            -
                      id:  | 
| 18 | 
            -
                      title:  | 
| 16 | 
            +
                      id: response_body.fetch(:id),
         | 
| 17 | 
            +
                      title: response_body.fetch(:title),
         | 
| 18 | 
            +
                      certifications: response_body.fetch(:certifications, []),
         | 
| 19 19 | 
             
                    )
         | 
| 20 20 | 
             
                  end
         | 
| 21 21 | 
             
                end
         | 
    
        data/lib/squake/products.rb
    CHANGED
    
    | @@ -11,12 +11,12 @@ module Squake | |
| 11 11 |  | 
| 12 12 | 
             
                sig do
         | 
| 13 13 | 
             
                  params(
         | 
| 14 | 
            -
                    client: Squake::Client,
         | 
| 15 | 
            -
                    locale: String,
         | 
| 16 14 | 
             
                    product_id: T.nilable(String),
         | 
| 17 | 
            -
             | 
| 15 | 
            +
                    locale: String,
         | 
| 16 | 
            +
                    client: Squake::Client,
         | 
| 17 | 
            +
                  ).returns(Squake::Return[T::Array[Squake::Model::Product]])
         | 
| 18 18 | 
             
                end
         | 
| 19 | 
            -
                def self.get( | 
| 19 | 
            +
                def self.get(product_id: nil, locale: DEFAULT_LOCALE, client: Squake::Client.new)
         | 
| 20 20 | 
             
                  path = product_id.nil? ? ENDPOINT : "#{ENDPOINT}/#{product_id}"
         | 
| 21 21 |  | 
| 22 22 | 
             
                  result = client.call(
         | 
| @@ -26,10 +26,18 @@ module Squake | |
| 26 26 | 
             
                      locale: locale,
         | 
| 27 27 | 
             
                    },
         | 
| 28 28 | 
             
                  )
         | 
| 29 | 
            -
                  raise Squake::APIError.new(response: result) unless result.success?
         | 
| 30 29 |  | 
| 31 | 
            -
                   | 
| 32 | 
            -
                     | 
| 30 | 
            +
                  if result.success?
         | 
| 31 | 
            +
                    products = T.cast(Array(result.body), T::Array[T::Hash[Symbol, T.untyped]]).map do |product_data|
         | 
| 32 | 
            +
                      Squake::Model::Product.from_api_response(product_data)
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                    Return.new(result: products)
         | 
| 35 | 
            +
                  else
         | 
| 36 | 
            +
                    error = Squake::Errors::APIErrorResult.new(
         | 
| 37 | 
            +
                      code: :"api_error_#{result.code}",
         | 
| 38 | 
            +
                      detail: result.error_message,
         | 
| 39 | 
            +
                    )
         | 
| 40 | 
            +
                    Return.new(errors: [error])
         | 
| 33 41 | 
             
                  end
         | 
| 34 42 | 
             
                end
         | 
| 35 43 | 
             
              end
         | 
    
        data/lib/squake/purchase.rb
    CHANGED
    
    | @@ -11,16 +11,16 @@ module Squake | |
| 11 11 | 
             
                # rubocop:disable Metrics/ParameterLists,  Layout/LineLength
         | 
| 12 12 | 
             
                sig do
         | 
| 13 13 | 
             
                  params(
         | 
| 14 | 
            -
                    client: Squake::Client,
         | 
| 15 14 | 
             
                    pricing: String,
         | 
| 16 15 | 
             
                    confirmation_document: T.nilable(T::Hash[Symbol, T.untyped]),
         | 
| 17 16 | 
             
                    certificate_document: T.nilable(T::Hash[Symbol, T.untyped]),
         | 
| 18 17 | 
             
                    metadata: T.nilable(T::Hash[Symbol, T.untyped]),
         | 
| 19 18 | 
             
                    external_reference: String, # used for idempotency, if given, MUST be unique
         | 
| 20 19 | 
             
                    expand: T::Array[String],
         | 
| 21 | 
            -
             | 
| 20 | 
            +
                    client: Squake::Client,
         | 
| 21 | 
            +
                  ).returns(Squake::Return[Squake::Model::Purchase])
         | 
| 22 22 | 
             
                end
         | 
| 23 | 
            -
                def self.create( | 
| 23 | 
            +
                def self.create(pricing:, confirmation_document: nil, certificate_document: nil, metadata: nil, external_reference: SecureRandom.uuid, expand: [], client: Squake::Client.new)
         | 
| 24 24 | 
             
                  result = client.call(
         | 
| 25 25 | 
             
                    path: ENDPOINT,
         | 
| 26 26 | 
             
                    method: :post,
         | 
| @@ -33,48 +33,73 @@ module Squake | |
| 33 33 | 
             
                      expand: expand,
         | 
| 34 34 | 
             
                    },
         | 
| 35 35 | 
             
                  )
         | 
| 36 | 
            -
                  raise Squake::APIError.new(response: result) unless result.success?
         | 
| 37 36 |  | 
| 38 | 
            -
                   | 
| 39 | 
            -
                     | 
| 40 | 
            -
             | 
| 37 | 
            +
                  if result.success?
         | 
| 38 | 
            +
                    purchase = Squake::Model::Purchase.from_api_response(
         | 
| 39 | 
            +
                      T.cast(result.body, T::Hash[Symbol, T.untyped]),
         | 
| 40 | 
            +
                    )
         | 
| 41 | 
            +
                    Return.new(result: purchase)
         | 
| 42 | 
            +
                  else
         | 
| 43 | 
            +
                    error = Squake::Errors::APIErrorResult.new(
         | 
| 44 | 
            +
                      code: :"api_error_#{result.code}",
         | 
| 45 | 
            +
                      detail: result.error_message,
         | 
| 46 | 
            +
                    )
         | 
| 47 | 
            +
                    Return.new(errors: [error])
         | 
| 48 | 
            +
                  end
         | 
| 41 49 | 
             
                end
         | 
| 42 50 | 
             
                # rubocop:enable Metrics/ParameterLists,  Layout/LineLength
         | 
| 43 51 |  | 
| 44 52 | 
             
                sig do
         | 
| 45 53 | 
             
                  params(
         | 
| 46 | 
            -
                    client: Squake::Client,
         | 
| 47 54 | 
             
                    id: String,
         | 
| 48 | 
            -
             | 
| 55 | 
            +
                    client: Squake::Client,
         | 
| 56 | 
            +
                  ).returns(T.nilable(Squake::Return[Squake::Model::Purchase]))
         | 
| 49 57 | 
             
                end
         | 
| 50 | 
            -
                def self.retrieve( | 
| 58 | 
            +
                def self.retrieve(id:, client: Squake::Client.new)
         | 
| 51 59 | 
             
                  result = client.call(
         | 
| 52 60 | 
             
                    path: "#{ENDPOINT}/#{id}",
         | 
| 53 61 | 
             
                  )
         | 
| 54 62 | 
             
                  return nil if result.code == 404
         | 
| 55 | 
            -
                  raise Squake::APIError.new(response: result) unless result.success?
         | 
| 56 63 |  | 
| 57 | 
            -
                   | 
| 58 | 
            -
                     | 
| 59 | 
            -
             | 
| 64 | 
            +
                  if result.success?
         | 
| 65 | 
            +
                    purchase = Squake::Model::Purchase.from_api_response(
         | 
| 66 | 
            +
                      T.cast(result.body, T::Hash[Symbol, T.untyped]),
         | 
| 67 | 
            +
                    )
         | 
| 68 | 
            +
                    Return.new(result: purchase)
         | 
| 69 | 
            +
                  else
         | 
| 70 | 
            +
                    error = Squake::Errors::APIErrorResult.new(
         | 
| 71 | 
            +
                      code: :"api_error_#{result.code}",
         | 
| 72 | 
            +
                      detail: result.error_message,
         | 
| 73 | 
            +
                    )
         | 
| 74 | 
            +
                    Return.new(errors: [error])
         | 
| 75 | 
            +
                  end
         | 
| 60 76 | 
             
                end
         | 
| 61 77 |  | 
| 62 78 | 
             
                sig do
         | 
| 63 79 | 
             
                  params(
         | 
| 64 | 
            -
                    client: Squake::Client,
         | 
| 65 80 | 
             
                    id: String,
         | 
| 66 | 
            -
             | 
| 81 | 
            +
                    client: Squake::Client,
         | 
| 82 | 
            +
                  ).returns(T.nilable(Squake::Return[Squake::Model::Purchase]))
         | 
| 67 83 | 
             
                end
         | 
| 68 | 
            -
                def self.cancel( | 
| 84 | 
            +
                def self.cancel(id:, client: Squake::Client.new)
         | 
| 69 85 | 
             
                  result = client.call(
         | 
| 70 86 | 
             
                    path: "#{ENDPOINT}/#{id}/cancel",
         | 
| 71 87 | 
             
                    method: :post,
         | 
| 72 88 | 
             
                  )
         | 
| 73 | 
            -
                   | 
| 89 | 
            +
                  return nil if result.code == 404
         | 
| 74 90 |  | 
| 75 | 
            -
                   | 
| 76 | 
            -
                     | 
| 77 | 
            -
             | 
| 91 | 
            +
                  if result.success?
         | 
| 92 | 
            +
                    purchase = Squake::Model::Purchase.from_api_response(
         | 
| 93 | 
            +
                      T.cast(result.body, T::Hash[Symbol, T.untyped]),
         | 
| 94 | 
            +
                    )
         | 
| 95 | 
            +
                    Return.new(result: purchase)
         | 
| 96 | 
            +
                  else
         | 
| 97 | 
            +
                    error = Squake::Errors::APIErrorResult.new(
         | 
| 98 | 
            +
                      code: :"api_error_#{result.code}",
         | 
| 99 | 
            +
                      detail: result.error_message,
         | 
| 100 | 
            +
                    )
         | 
| 101 | 
            +
                    Return.new(errors: [error])
         | 
| 102 | 
            +
                  end
         | 
| 78 103 | 
             
                end
         | 
| 79 104 | 
             
              end
         | 
| 80 105 | 
             
            end
         | 
| @@ -0,0 +1,64 @@ | |
| 1 | 
            +
            # typed: strict
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require_relative 'errors/api_error_result'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            module Squake
         | 
| 7 | 
            +
              class Return
         | 
| 8 | 
            +
                class Failure < StandardError; end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                FAILURE_MSG_NO_ARGS = 'Must provide either a result or errors'
         | 
| 11 | 
            +
                FAILURE_MSG_BOTH_ARGS = 'Cannot provide both a result and errors'
         | 
| 12 | 
            +
                FAILURE_ERRORS_CALLED_WHEN_SUCCESS = 'Cannot call errors when result is present'
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                extend T::Sig
         | 
| 15 | 
            +
                extend T::Generic
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                Error = type_member { { fixed: Errors::APIErrorResult } }
         | 
| 18 | 
            +
                Result = type_member { { upper: Object } }
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                sig { params(result: T.nilable(Result), errors: T.nilable(T::Array[Error])).void }
         | 
| 21 | 
            +
                def initialize(result: nil, errors: nil)
         | 
| 22 | 
            +
                  raise Failure, FAILURE_MSG_NO_ARGS if result.nil? && errors.nil?
         | 
| 23 | 
            +
                  raise Failure, FAILURE_MSG_BOTH_ARGS if present?(result) && present?(errors)
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  @result = result
         | 
| 26 | 
            +
                  @errors = errors
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                sig { returns(T::Boolean) }
         | 
| 30 | 
            +
                def success?
         | 
| 31 | 
            +
                  present?(@result)
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                sig { returns(T::Boolean) }
         | 
| 35 | 
            +
                def failed?
         | 
| 36 | 
            +
                  !success?
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                sig { returns(T::Array[Error]) }
         | 
| 40 | 
            +
                def errors
         | 
| 41 | 
            +
                  raise Failure, FAILURE_ERRORS_CALLED_WHEN_SUCCESS if success?
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  T.must(@errors)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                sig { returns(Result) }
         | 
| 47 | 
            +
                def result
         | 
| 48 | 
            +
                  raise Failure, @errors&.map(&:serialize) if failed?
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  T.must(@result)
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                # courtesy to Rails, see: https://api.rubyonrails.org/v7.0.5/classes/Object.html
         | 
| 54 | 
            +
                sig { params(object: T.untyped).returns(T::Boolean) }
         | 
| 55 | 
            +
                private def blank?(object)
         | 
| 56 | 
            +
                  object.respond_to?(:empty?) ? !!object.empty? : !object
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                sig { params(object: T.untyped).returns(T::Boolean) }
         | 
| 60 | 
            +
                private def present?(object)
         | 
| 61 | 
            +
                  !blank?(object)
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
            end
         | 
    
        data/lib/squake/version.rb
    CHANGED
    
    
    
        data/lib/squake.rb
    CHANGED
    
    | @@ -5,11 +5,36 @@ require 'sorbet-runtime' | |
| 5 5 | 
             
            require 'oj'
         | 
| 6 6 | 
             
            require 'net/http'
         | 
| 7 7 |  | 
| 8 | 
            -
            Dir[File.join(__dir__, './**/*', '*.rb')].each { require(_1) }
         | 
| 9 | 
            -
             | 
| 10 | 
            -
            module Squake; end
         | 
| 11 | 
            -
             | 
| 12 8 | 
             
            Oj.default_options = {
         | 
| 13 9 | 
             
              mode: :compat, # required to dump hashes with symbol-keys
         | 
| 14 10 | 
             
              symbol_keys: true,
         | 
| 15 11 | 
             
            }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Dir[File.join(__dir__, './**/*', '*.rb')].each { require(_1) }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            module Squake
         | 
| 16 | 
            +
              class << self
         | 
| 17 | 
            +
                extend T::Sig
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                sig { returns(T.nilable(Squake::Config)) }
         | 
| 20 | 
            +
                attr_accessor :configuration
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                sig do
         | 
| 23 | 
            +
                  params(
         | 
| 24 | 
            +
                    _: T.proc.params(configuration: Squake::Config).void,
         | 
| 25 | 
            +
                  ).void
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
                def configure(&_)
         | 
| 28 | 
            +
                  self.configuration ||= Squake::Config.new(
         | 
| 29 | 
            +
                    api_key: ENV.fetch('SQUAKE_API_KEY', nil),
         | 
| 30 | 
            +
                    keep_alive_timeout: ENV.fetch('SQUAKE_KEEP_ALIVE_TIMEOUT', 30).to_i,
         | 
| 31 | 
            +
                    sandbox_mode: ENV.fetch('SQUAKE_SANDBOX_MODE', 'true').casecmp?('true'),
         | 
| 32 | 
            +
                    enforced_api_base: ENV.fetch('SQUAKE_API_BASE', nil),
         | 
| 33 | 
            +
                  )
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  yield(T.must(configuration))
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            Squake.configure(&:itself) unless ENV['SQUAKE_API_KEY'].nil?
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: squake
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - SQUAKE
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023-06- | 
| 11 | 
            +
            date: 2023-06-23 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: net-http
         | 
| @@ -138,6 +138,8 @@ files: | |
| 138 138 | 
             
            - lib/squake/calculation_with_pricing.rb
         | 
| 139 139 | 
             
            - lib/squake/client.rb
         | 
| 140 140 | 
             
            - lib/squake/config.rb
         | 
| 141 | 
            +
            - lib/squake/errors/api_error_result.rb
         | 
| 142 | 
            +
            - lib/squake/errors/api_error_source.rb
         | 
| 141 143 | 
             
            - lib/squake/model/carbon.rb
         | 
| 142 144 | 
             
            - lib/squake/model/carbon_unit.rb
         | 
| 143 145 | 
             
            - lib/squake/model/items/base_type.rb
         | 
| @@ -149,6 +151,7 @@ files: | |
| 149 151 | 
             
            - lib/squake/products.rb
         | 
| 150 152 | 
             
            - lib/squake/purchase.rb
         | 
| 151 153 | 
             
            - lib/squake/response.rb
         | 
| 154 | 
            +
            - lib/squake/return.rb
         | 
| 152 155 | 
             
            - lib/squake/util.rb
         | 
| 153 156 | 
             
            - lib/squake/version.rb
         | 
| 154 157 | 
             
            - sorbet/rbi/dsl/active_support/callbacks.rbi
         |