squake 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7860b4b9cfbf3110355582ab95ce9faee0055fc6ea852b00093703fbcf8f7c8d
4
- data.tar.gz: 6f05154a58469f7f52f9730bf808a3005961b7ba29e7f6ce8fe47e47b27cc651
3
+ metadata.gz: '00325909416eb7545b395e8a0ffa0ee164b6c9ec125f5f9900c5f3efe7f1e058'
4
+ data.tar.gz: 003ce1f90f3e379f995169079672319a8a044db9f46684582a59d7c333b082d0
5
5
  SHA512:
6
- metadata.gz: d2065bbbe6bbbffa5067acf0810dbfe2c3ef32b50b5bce14b949f170a138f29ec16d2897093d9305af615e768ebcaa6da24873660572c24141e09f11b896cf08
7
- data.tar.gz: 53f6a57201c32df605f6d30932baa4408bc3eafd7c02fb6f2dff6f55d0313c1e0b0f501980aa93e17bcea5ecd3bc11491f81639d138aa4c60005e62237689e92
6
+ metadata.gz: '06795250b08b0b20e15d7283c7f29e9761a9f21a3553ed269f4c2b49bffee2afdae3d5143577ded233cafe1b86fde494471ef60363c635c8bcbd7d4cd9e2322c'
7
+ data.tar.gz: 6eebe00fa09b233feb52fc156e1bd7b922d4831d53e1da6f90381dbc9830d70f14e6ea935801cfc79f4ab328ff034ece20b8fde985433c07c6797d07cfe6fc19
data/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.2.0] - 2023-06-15
11
+
12
+ ### Added
13
+
14
+ * request carbon emissions (without price quote)
15
+
16
+ ## [0.1.0] - 2023-06-14
17
+
18
+ Initial release of an MVP/POC library. Only v2 of the SQUAKE API is supported.
19
+
20
+ ### Added
21
+
22
+ * request carbon emission and price quote
23
+ * make a purchase
24
+ * retrieve a purchase
25
+ * cancel a purchase
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 squake-earth
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -4,20 +4,16 @@ Find the documentation here: [docs](https://docs.squake.earth/).
4
4
 
5
5
  ## Installation
6
6
 
7
- Via git:
7
+ Via rubygems:
8
8
 
9
9
  ```ruby
10
- # Gemfile
11
-
12
- gem 'squake', git: 'git@github.com:squake-earth/squake-ruby'
10
+ gem 'squake'
13
11
  ```
14
12
 
15
- Via rubygems:
13
+ Via git:
16
14
 
17
15
  ```ruby
18
- # Gemfile
19
-
20
- gem 'squake', '~> 0.1.0'
16
+ gem 'squake', git: 'git@github.com:squake-earth/squake-ruby'
21
17
  ```
22
18
 
23
19
  ## Auth
@@ -28,13 +24,13 @@ You need a different API Key for production and sandbox.
28
24
  ## Functionality
29
25
 
30
26
  * compute emission values
31
- * request a price quote (with a product id)
27
+ * request a price quote for your emissions (with a product id)
32
28
  * place a purchase order (with a price quote id)
33
29
  * get a list of all available products (includes price information)
34
30
 
35
31
  ## Usage
36
32
 
37
- Calculate emissions and include a price quote:
33
+ Initialize the client:
38
34
 
39
35
  ```ruby
40
36
  config = Squake::Config.new(
@@ -48,7 +44,36 @@ config = Squake::Config.new(
48
44
  # the SQUAKE client emits canonical log lines, e.g.
49
45
  # Request started http_method=get http_path=/api/v2/calculations
50
46
  client = Squake::Client.new(config: config)
47
+ ```
48
+
49
+ Calculate emissions
50
+
51
+ ```ruby
52
+ items = [
53
+ {
54
+ type: 'flight',
55
+ methodology: 'ICAO',
56
+ origin: 'BER',
57
+ destination: 'SIN',
58
+ booking_class: 'economy',
59
+ number_of_travellers: 2,
60
+ aircraft_type: '350',
61
+ external_reference: 'booking-id',
62
+ }
63
+ ]
64
+
65
+ # returns Squake::Model::Carbon
66
+ carbon = Squake::Calculation.create(
67
+ client: client, # required
68
+ items: items, # required
69
+ carbon_unit: 'gram', # optional, default: 'gram', other options: 'kilogram', 'tonne'
70
+ expand: [], # optional, default: [], allowed values: 'items' to enrich the response
71
+ )
72
+ ```
73
+
74
+ Calculate emissions and include a price quote:
51
75
 
76
+ ```ruby
52
77
  # Find all available item types and methodologies here:
53
78
  # https://docs-v2.squake.earth/group/endpoint-calculations
54
79
  items = [
@@ -71,6 +96,7 @@ pricing = Squake::CalculationWithPricing.quote(
71
96
  product: 'product-id', # required
72
97
  currency: 'EUR', # optional, default: 'EUR'
73
98
  carbon_unit: 'gram', # optional, default: 'gram', other options: 'kilogram', 'tonne'
99
+ expand: [], # optional, default: [], allowed values: 'items', 'product', 'price' to enrich the response
74
100
  )
75
101
  ```
76
102
 
@@ -98,3 +124,31 @@ Squake::Purchase.cancel(
98
124
  id: purchase.id, # required
99
125
  )
100
126
  ```
127
+
128
+ ## Contributions
129
+
130
+ We welcome contributions from the community. Before starting work on a major feature, please get in touch with us either via email or by opening an issue on GitHub. "Major feature" means anything that changes user-facing features or significant changes to the codebase itself.
131
+
132
+ Please commit small and focused PRs with descriptive commit messages. If you are unsure about a PR, please open a draft PR to get early feedback. A PR must have a short description ("what"), a motiviation ("why"), and, if applicable, instructions how to test the changes, measure performance improvements, etc.
133
+
134
+ ## Publishing a new version
135
+
136
+ Have a Rubygems API key in your `~/.gem/credentials` file.
137
+
138
+ ```shell
139
+ ---
140
+ :rubygems_squake: rubygems_xxx
141
+ ```
142
+
143
+ Then run:
144
+
145
+ ```shell
146
+ bin/release
147
+ ```
148
+
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
@@ -0,0 +1,36 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # https://docs-v2.squake.earth/operation/operation-post-calculations
5
+ module Squake
6
+ class Calculation
7
+ extend T::Sig
8
+
9
+ ENDPOINT = T.let('/v2/calculations', String)
10
+
11
+ sig do
12
+ params(
13
+ client: Squake::Client,
14
+ items: T::Array[Squake::Model::Items::BaseType],
15
+ carbon_unit: String,
16
+ expand: T::Array[String],
17
+ ).returns(Squake::Model::Carbon)
18
+ end
19
+ def self.create(client:, items:, carbon_unit: 'gram', expand: [])
20
+ result = client.call(
21
+ path: ENDPOINT,
22
+ method: :post,
23
+ params: {
24
+ items: items.map(&:serialize),
25
+ carbon_unit: carbon_unit,
26
+ expand: expand,
27
+ },
28
+ )
29
+ raise Squake::APIError.new(response: result) unless result.success?
30
+
31
+ Squake::Model::Carbon.from_api_response(
32
+ T.cast(result.body, T::Hash[Symbol, T.untyped]),
33
+ )
34
+ end
35
+ end
36
+ end
data/lib/squake/config.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'logger'
5
+
4
6
  module Squake
5
7
  class Config < T::Struct
6
8
  extend T::Sig
@@ -10,7 +12,7 @@ module Squake
10
12
 
11
13
  const :api_key, String
12
14
  const :keep_alive_timeout, Integer, default: 30
13
- const :logger, Logger, factory: -> { Logger.new($stdout) }
15
+ const :logger, ::Logger, factory: -> { ::Logger.new($stdout) }
14
16
  const :sandbox_mode, T::Boolean, default: true
15
17
  const :enforced_api_base, T.nilable(String)
16
18
 
@@ -0,0 +1,53 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Squake
5
+ module Model
6
+ class Carbon < T::Struct
7
+ extend T::Sig
8
+
9
+ const :quantity, BigDecimal
10
+ const :unit, CarbonUnit, default: CarbonUnit::GRAM
11
+ const :items, T.nilable(T::Array[T::Hash[Symbol, T.untyped]]) # @TODO: resolve to typed items?
12
+
13
+ sig { params(response_body: T::Hash[Symbol, T.untyped]).returns(Squake::Model::Carbon) }
14
+ def self.from_api_response(response_body)
15
+ Squake::Model::Carbon.new(
16
+ quantity: BigDecimal(String(response_body.fetch(:quantity))),
17
+ unit: CarbonUnit.deserialize(response_body.fetch(:unit)),
18
+ items: response_body.fetch(:items, nil),
19
+ )
20
+ end
21
+
22
+ sig do
23
+ params(
24
+ unit: CarbonUnit,
25
+ ).returns(Carbon)
26
+ end
27
+ def in!(unit)
28
+ # this is a bit hacky, but it optimizes memory usages and we don't need `T.must`
29
+ # everywhere if we were to use a prop instead of a const.
30
+ @quantity = CarbonUnit.convert(quantity, self.unit, to: unit)
31
+ @unit = unit
32
+ self
33
+ end
34
+
35
+ sig do
36
+ params(
37
+ other: Carbon,
38
+ ).returns(Carbon)
39
+ end
40
+ def +(other)
41
+ other_qty = CarbonUnit.convert(other.quantity, other.unit, to: CarbonUnit::GRAM)
42
+ self_qty = CarbonUnit.convert(quantity, unit, to: CarbonUnit::GRAM)
43
+
44
+ Carbon.new(quantity: other_qty + self_qty)
45
+ end
46
+
47
+ sig { returns(Numeric) }
48
+ def fractional
49
+ quantity.to_f.round(unit.precision)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,105 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # as per International System of Units ("SI", or "metric system")
5
+ # see: https://www.nist.gov/pml/owm/si-units-mass
6
+ module Squake
7
+ module Model
8
+ class CarbonUnit < T::Enum
9
+ extend T::Sig
10
+
11
+ enums do
12
+ GRAM = new('gram')
13
+ KILOGRAM = new('kilogram')
14
+ TONNE = new('tonne')
15
+ end
16
+
17
+ sig { returns(String) }
18
+ def serialize_to_abbreviation
19
+ case self
20
+ when CarbonUnit::GRAM then 'g'
21
+ when CarbonUnit::KILOGRAM then 'kg'
22
+ when CarbonUnit::TONNE then 't'
23
+ else
24
+ T.absurd(self)
25
+ end
26
+ end
27
+
28
+ sig do
29
+ params(
30
+ carbon_quantity: T.any(Integer, Float, Rational, BigDecimal),
31
+ carbon_unit: CarbonUnit,
32
+ to: CarbonUnit,
33
+ ).returns(BigDecimal)
34
+ end
35
+ def self.convert(carbon_quantity, carbon_unit, to: CarbonUnit::GRAM)
36
+ case carbon_unit
37
+ when CarbonUnit::GRAM then gram_to_unit(carbon_quantity, to)
38
+ when CarbonUnit::KILOGRAM then kilogram_to_unit(carbon_quantity, to)
39
+ when CarbonUnit::TONNE then tonne_to_unit(carbon_quantity, to)
40
+ else
41
+ T.absurd(carbon_unit)
42
+ end
43
+ end
44
+
45
+ sig { returns(Integer) }
46
+ def precision
47
+ case self
48
+ when CarbonUnit::GRAM then 0
49
+ when CarbonUnit::KILOGRAM then 3
50
+ when CarbonUnit::TONNE then 6
51
+ else
52
+ T.absurd(self)
53
+ end
54
+ end
55
+
56
+ sig do
57
+ params(
58
+ carbon_quantity: T.any(Integer, Float, Rational, BigDecimal),
59
+ to: CarbonUnit,
60
+ ).returns(BigDecimal)
61
+ end
62
+ private_class_method def self.gram_to_unit(carbon_quantity, to)
63
+ case to
64
+ when CarbonUnit::GRAM then BigDecimal(carbon_quantity)
65
+ when CarbonUnit::KILOGRAM then BigDecimal(carbon_quantity) / 1_000
66
+ when CarbonUnit::TONNE then BigDecimal(carbon_quantity) / 1_000_000
67
+ else
68
+ T.absurd(to)
69
+ end
70
+ end
71
+
72
+ sig do
73
+ params(
74
+ carbon_quantity: T.any(Integer, Float, Rational, BigDecimal),
75
+ to: CarbonUnit,
76
+ ).returns(BigDecimal)
77
+ end
78
+ private_class_method def self.kilogram_to_unit(carbon_quantity, to)
79
+ case to
80
+ when CarbonUnit::GRAM then BigDecimal(carbon_quantity) * 1_000
81
+ when CarbonUnit::KILOGRAM then BigDecimal(carbon_quantity)
82
+ when CarbonUnit::TONNE then BigDecimal(carbon_quantity) / 1_000
83
+ else
84
+ T.absurd(to)
85
+ end
86
+ end
87
+
88
+ sig do
89
+ params(
90
+ carbon_quantity: T.any(Integer, Float, Rational, BigDecimal),
91
+ to: CarbonUnit,
92
+ ).returns(BigDecimal)
93
+ end
94
+ private_class_method def self.tonne_to_unit(carbon_quantity, to)
95
+ case to
96
+ when CarbonUnit::GRAM then BigDecimal(carbon_quantity) * 1_000_000
97
+ when CarbonUnit::KILOGRAM then BigDecimal(carbon_quantity) * 1_000
98
+ when CarbonUnit::TONNE then BigDecimal(carbon_quantity)
99
+ else
100
+ T.absurd(to)
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Squake
5
- VERSION = '0.1.0'
5
+ VERSION = '0.2.1'
6
6
  end
data/lib/squake.rb CHANGED
@@ -3,5 +3,8 @@
3
3
 
4
4
  require 'sorbet-runtime'
5
5
  require 'oj'
6
+ require 'net/http'
6
7
 
7
- require_relative 'squake/version'
8
+ Dir[File.join(__dir__, './**/*', '*.rb')].each { require(_1) }
9
+
10
+ module Squake; end
@@ -0,0 +1,22 @@
1
+ # typed: true
2
+
3
+ # DO NOT EDIT MANUALLY
4
+ # This is an autogenerated file for dynamic methods in `ActiveSupport::Callbacks`.
5
+ # Please instead update this file by running `bin/tapioca dsl ActiveSupport::Callbacks`.
6
+
7
+ module ActiveSupport::Callbacks
8
+ include GeneratedInstanceMethods
9
+
10
+ mixes_in_class_methods GeneratedClassMethods
11
+
12
+ module GeneratedClassMethods
13
+ def __callbacks; end
14
+ def __callbacks=(value); end
15
+ def __callbacks?; end
16
+ end
17
+
18
+ module GeneratedInstanceMethods
19
+ def __callbacks; end
20
+ def __callbacks?; end
21
+ end
22
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
- - 'Team SQUAKE :rocket:'
7
+ - SQUAKE
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-14 00:00:00.000000000 Z
11
+ date: 2023-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-http
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: oj
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,20 @@ dependencies:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: byebug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rubocop-dbl
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -101,12 +129,17 @@ executables: []
101
129
  extensions: []
102
130
  extra_rdoc_files: []
103
131
  files:
132
+ - CHANGELOG.md
133
+ - LICENSE
104
134
  - README.md
105
135
  - lib/squake.rb
106
136
  - lib/squake/api_error.rb
137
+ - lib/squake/calculation.rb
107
138
  - lib/squake/calculation_with_pricing.rb
108
139
  - lib/squake/client.rb
109
140
  - lib/squake/config.rb
141
+ - lib/squake/model/carbon.rb
142
+ - lib/squake/model/carbon_unit.rb
110
143
  - lib/squake/model/items/base_type.rb
111
144
  - lib/squake/model/items/private_jet/squake.rb
112
145
  - lib/squake/model/price.rb
@@ -118,6 +151,7 @@ files:
118
151
  - lib/squake/response.rb
119
152
  - lib/squake/util.rb
120
153
  - lib/squake/version.rb
154
+ - sorbet/rbi/dsl/active_support/callbacks.rbi
121
155
  homepage: https://github.com/squake-earth/squake-ruby
122
156
  licenses:
123
157
  - MIT