Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.1.0-alpha.37"
".": "0.1.0-alpha.38"
}
9 changes: 6 additions & 3 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Layout/LineLength:
AllowedPatterns:
- "^\\s*#.*$"
- ^require(_relative)?
- "Orb::(Models|Resources)::"
- "Orb::(Models|Resources|Test)::"
Max: 110

Layout/MultilineArrayLineBreaks:
Expand Down Expand Up @@ -122,9 +122,9 @@ Metrics/PerceivedComplexity:
Naming/BlockForwarding:
Enabled: false

# Underscores are generally useful for disambiguation.
Naming/ClassAndModuleCamelCase:
Exclude:
- "**/*.rbi"
Enabled: false

Naming/MethodParameterName:
Enabled: false
Expand Down Expand Up @@ -202,6 +202,9 @@ Style/MethodCallWithArgsParentheses:
Exclude:
- "**/*.gemspec"

Style/MultilineBlockChain:
Enabled: false

# Perfectly fine.
Style/MultipleComparison:
Enabled: false
Expand Down
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# Changelog

## 0.1.0-alpha.38 (2025-04-05)

Full Changelog: [v0.1.0-alpha.37...v0.1.0-alpha.38](https://github.com/orbcorp/orb-ruby/compare/v0.1.0-alpha.37...v0.1.0-alpha.38)

### Features

* support query, header, and body params that have identical names ([#226](https://github.com/orbcorp/orb-ruby/issues/226)) ([edbbd05](https://github.com/orbcorp/orb-ruby/commit/edbbd057dcfe5cf5eaa12fed6f3cb2f25f56fa19))
* support solargraph generics ([#220](https://github.com/orbcorp/orb-ruby/issues/220)) ([3db38b4](https://github.com/orbcorp/orb-ruby/commit/3db38b4390902cf97c6942f83f1b5aed4e214041))


### Bug Fixes

* converter should transform stringio into string where applicable ([#228](https://github.com/orbcorp/orb-ruby/issues/228)) ([f818391](https://github.com/orbcorp/orb-ruby/commit/f818391228f86c671be20deb723a7570fbcdf18e))


### Chores

* document LSP support in read me ([#225](https://github.com/orbcorp/orb-ruby/issues/225)) ([574fdf4](https://github.com/orbcorp/orb-ruby/commit/574fdf455227a604a4e6370cfad093c278c1e6c4))
* **internal:** codegen related update ([#222](https://github.com/orbcorp/orb-ruby/issues/222)) ([f4b7010](https://github.com/orbcorp/orb-ruby/commit/f4b7010a5f7241a3c3f18ad2dd5000706216f8e9))
* **internal:** codegen related update ([#223](https://github.com/orbcorp/orb-ruby/issues/223)) ([e25b11c](https://github.com/orbcorp/orb-ruby/commit/e25b11c9a06d7fdca01fea78d0860ae41cdb4c52))
* **internal:** run rubocop linter in parallel ([#229](https://github.com/orbcorp/orb-ruby/issues/229)) ([7b6cedd](https://github.com/orbcorp/orb-ruby/commit/7b6cedd9f976a634b4f590237e421d3312495672))
* **internal:** version bump ([#218](https://github.com/orbcorp/orb-ruby/issues/218)) ([906a451](https://github.com/orbcorp/orb-ruby/commit/906a451f0e155d476b227d61d512b5d3cc476e43))
* misc sdk polish ([#224](https://github.com/orbcorp/orb-ruby/issues/224)) ([f2a6cec](https://github.com/orbcorp/orb-ruby/commit/f2a6cecdfe4a4bc98089ca0a6ea31a95a100f499))
* rename confusing `Type::BooleanModel` to `Type::Boolean` ([#227](https://github.com/orbcorp/orb-ruby/issues/227)) ([8950333](https://github.com/orbcorp/orb-ruby/commit/89503331236fa01589fe19228b6549d45f29238b))

## 0.1.0-alpha.37 (2025-04-03)

Full Changelog: [v0.1.0-alpha.36...v0.1.0-alpha.37](https://github.com/orbcorp/orb-ruby/compare/v0.1.0-alpha.36...v0.1.0-alpha.37)
Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ GIT
PATH
remote: .
specs:
orb-billing (0.1.0.pre.alpha.36)
orb-billing (0.1.0.pre.alpha.37)
connection_pool

GEM
Expand Down
34 changes: 29 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,14 @@ The underlying REST API documentation can be found on [docs.withorb.com](https:/

To use this gem, install via Bundler by adding the following to your application's `Gemfile`:

<!-- x-release-please-start-version -->

```ruby
gem "orb-billing", "~> 0.1.0.pre.alpha.36"
gem "orb-billing", "~> 0.1.0.pre.alpha.37"
```

<!-- x-release-please-end -->

To fetch an initial copy of the gem:

```sh
Expand Down Expand Up @@ -130,9 +134,23 @@ orb.customers.create(

## LSP Support

### Sorbet
### Solargraph

This library includes [Solargraph](https://solargraph.org) support for both auto completion and go to definition.

```ruby
gem "solargraph", group: :development
```

After Solargraph is installed, **you must populate its index** either via the provided editor command, or by running the following in your terminal:

**This library emits an intentional warning under the [`tapioca` toolchain](https://github.com/Shopify/tapioca)**. This is normal, and does not impact functionality.
```sh
bundle exec solargraph gems
```

Otherwise Solargraph will not be able to provide type information or auto-completion for any non-indexed libraries.

### Sorbet

This library is written with [Sorbet type definitions](https://sorbet.org/docs/rbi). However, there is no runtime dependency on the `sorbet-runtime`.

Expand All @@ -143,11 +161,17 @@ Due to limitations with the Sorbet type system, where a method otherwise can tak
Please follow Sorbet's [setup guides](https://sorbet.org/docs/adopting) for best experience.

```ruby
model = Orb::Models::CustomerCreateParams.new(email: "example-customer@withorb.com", name: "My Customer")
params = Orb::Models::CustomerCreateParams.new(email: "example-customer@withorb.com", name: "My Customer")

orb.customers.create(**model)
orb.customers.create(**params)
```

Note: **This library emits an intentional warning under the [`tapioca` toolchain](https://github.com/Shopify/tapioca)**. This is normal, and does not impact functionality.

### Ruby LSP

The Ruby LSP has [best effort support](https://shopify.github.io/ruby-lsp/#guessed-types) for inferring type information from Ruby code, and as such it may not always be able to provide accurate type information.

## Advanced

### Making custom/undocumented requests
Expand Down
16 changes: 7 additions & 9 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ require "rubocop/rake_task"

CLEAN.push(*%w[.idea/ .ruby-lsp/ .yardoc/])

xargs = %w[xargs --no-run-if-empty --null --max-procs=0 --max-args=300 --]

multitask(default: [:test])

multitask(:test) do
Expand All @@ -22,17 +20,17 @@ multitask(:test) do
ruby(*%w[-w -e], rb, verbose: false) { fail unless _1 }
end

RuboCop::RakeTask.new(:rubocop) do |t|
t.options = %w[--fail-level E]
if ENV.key?("CI")
t.options += %w[--format github]
end
rubo_find = %w[find ./lib ./test ./rbi -type f -and ( -name *.rb -or -name *.rbi ) -print0]
xargs = %w[xargs --no-run-if-empty --null --max-procs=0 --max-args=300 --]

multitask(:rubocop) do
lint = xargs + %w[rubocop --fail-level E] + (ENV.key?("CI") ? %w[--format github] : [])
sh("#{rubo_find.shelljoin} | #{lint.shelljoin}")
end

multitask(:ruboformat) do
find = %w[find ./lib ./test ./rbi -type f -and ( -name *.rb -or -name *.rbi ) -print0]
fmt = xargs + %w[rubocop --fail-level F --autocorrect --format simple --]
sh("#{find.shelljoin} | #{fmt.shelljoin}")
sh("#{rubo_find.shelljoin} | #{fmt.shelljoin}")
end

multitask(:syntax_tree) do
Expand Down
2 changes: 1 addition & 1 deletion lib/orb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
require_relative "orb/internal/util"
require_relative "orb/internal/type/converter"
require_relative "orb/internal/type/unknown"
require_relative "orb/internal/type/boolean_model"
require_relative "orb/internal/type/boolean"
require_relative "orb/internal/type/enum"
require_relative "orb/internal/type/union"
require_relative "orb/internal/type/array_of"
Expand Down
8 changes: 6 additions & 2 deletions lib/orb/internal/page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module Orb
module Internal
# @generic Elem
#
# @example
# if page.has_next?
# page = page.next_page
Expand All @@ -14,7 +16,7 @@ module Internal
class Page
include Orb::Internal::Type::BasePage

# @return [Array<Object>, nil]
# @return [Array<generic<Elem>>, nil]
attr_accessor :data

# @return [PaginationMetadata]
Expand Down Expand Up @@ -65,6 +67,8 @@ def next_page
end

# @param blk [Proc]
#
# @yieldparam [generic<Elem>]
def auto_paging_each(&blk)
unless block_given?
raise ArgumentError.new("A block must be given to ##{__method__}")
Expand All @@ -88,7 +92,7 @@ class PaginationMetadata < Orb::Internal::Type::BaseModel
# @!attribute has_more
#
# @return [Boolean]
required :has_more, Orb::Internal::Type::BooleanModel
required :has_more, Orb::Internal::Type::Boolean

# @!attribute next_cursor
#
Expand Down
4 changes: 2 additions & 2 deletions lib/orb/internal/transport/base_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def follow_redirect(request, status:, response_headers:)
# @api private
#
# @param status [Integer, Orb::Errors::APIConnectionError]
# @param stream [Enumerable, nil]
# @param stream [Enumerable<String>, nil]
def reap_connection!(status, stream:)
case status
in (..199) | (300..499)
Expand Down Expand Up @@ -328,7 +328,7 @@ def initialize(
# @param send_retry_header [Boolean]
#
# @raise [Orb::Errors::APIError]
# @return [Array(Integer, Net::HTTPResponse, Enumerable)]
# @return [Array(Integer, Net::HTTPResponse, Enumerable<String>)]
private def send_request(request, redirect_count:, retry_count:, send_retry_header:)
url, headers, max_retries, timeout = request.fetch_values(:url, :headers, :max_retries, :timeout)
input = {**request.except(:timeout), deadline: Orb::Internal::Util.monotonic_secs + timeout}
Expand Down
2 changes: 1 addition & 1 deletion lib/orb/internal/transport/pooled_net_requester.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def build_request(request, &blk)
#
# @option request [Float] :deadline
#
# @return [Array(Integer, Net::HTTPResponse, Enumerable)]
# @return [Array(Integer, Net::HTTPResponse, Enumerable<String>)]
def execute(request)
url, deadline = request.fetch_values(:url, :deadline)

Expand Down
8 changes: 5 additions & 3 deletions lib/orb/internal/type/array_of.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ module Type
#
# @abstract
#
# @generic Elem
#
# Array of items of a given type.
class ArrayOf
include Orb::Internal::Type::Converter
Expand Down Expand Up @@ -40,7 +42,7 @@ def ==(other)

# @api private
#
# @param value [Enumerable, Object]
# @param value [Array<Object>, Object]
#
# @param state [Hash{Symbol=>Object}] .
#
Expand Down Expand Up @@ -75,7 +77,7 @@ def coerce(value, state:)

# @api private
#
# @param value [Enumerable, Object]
# @param value [Array<Object>, Object]
#
# @return [Array<Object>, Object]
def dump(value)
Expand All @@ -85,7 +87,7 @@ def dump(value)

# @api private
#
# @return [Orb::Internal::Type::Converter, Class]
# @return [generic<Elem>]
protected def item_type = @item_type_fn.call

# @api private
Expand Down
18 changes: 12 additions & 6 deletions lib/orb/internal/type/base_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,9 @@ def optional(name_sym, type_info, spec = {})
# @param other [Object]
#
# @return [Boolean]
def ==(other) = other.is_a?(Class) && other <= Orb::Internal::Type::BaseModel && other.fields == fields
def ==(other)
other.is_a?(Class) && other <= Orb::Internal::Type::BaseModel && other.fields == fields
end
end

# @param other [Object]
Expand Down Expand Up @@ -256,6 +258,7 @@ def dump(value)
return super
end

is_param = singleton_class <= Orb::Internal::Type::RequestParameters::Converter
acc = {}

coerced.each do |key, val|
Expand All @@ -264,19 +267,21 @@ def dump(value)
in nil
acc.store(name, super(val))
else
mode, api_name, type_fn = field.fetch_values(:mode, :api_name, :type_fn)
mode, type_fn = field.fetch_values(:mode, :type_fn)
case mode
in :coerce
next
else
target = type_fn.call
api_name = is_param ? name : field.fetch(:api_name)
acc.store(api_name, Orb::Internal::Type::Converter.dump(target, val))
end
end
end

known_fields.each_value do |field|
mode, api_name, const = field.fetch_values(:mode, :api_name, :const)
known_fields.each do |name, field|
mode, const = field.fetch_values(:mode, :const)
api_name = is_param ? name : field.fetch(:api_name)
next if mode == :coerce || acc.key?(api_name) || const == Orb::Internal::OMIT
acc.store(api_name, const)
end
Expand Down Expand Up @@ -350,15 +355,16 @@ def initialize(data = {})
in Hash => coerced
@data = coerced
else
raise ArgumentError.new("Expected a #{Hash} or #{Orb::Internal::Type::BaseModel}, got #{data.inspect}")
message = "Expected a #{Hash} or #{Orb::Internal::Type::BaseModel}, got #{data.inspect}"
raise ArgumentError.new(message)
end
end

# @return [String]
def inspect
rows = self.class.known_fields.keys.map do
"#{_1}=#{@data.key?(_1) ? public_send(_1) : ''}"
rescue Orb::ConversionError
rescue Orb::Errors::ConversionError
"#{_1}=#{@data.fetch(_1)}"
end
"#<#{self.class.name}:0x#{object_id.to_s(16)} #{rows.join(' ')}>"
Expand Down
5 changes: 4 additions & 1 deletion lib/orb/internal/type/base_page.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
module Orb
module Internal
module Type
# @generic Elem
#
# This module provides a base implementation for paginated responses in the SDK.
module BasePage
# rubocop:disable Lint/UnusedMethodArgument
Expand All @@ -16,10 +18,11 @@ def next_page = (raise NotImplementedError)

# @param blk [Proc]
#
# @yieldparam [generic<Elem>]
# @return [void]
def auto_paging_each(&blk) = (raise NotImplementedError)

# @return [Enumerable]
# @return [Enumerable<generic<Elem>>]
def to_enum = super(:auto_paging_each)

alias_method :enum_for, :to_enum
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module Type
# @abstract
#
# Ruby has no Boolean class; this is something for models to refer to.
class BooleanModel
class Boolean
extend Orb::Internal::Type::Converter

# @param other [Object]
Expand All @@ -19,7 +19,7 @@ def self.===(other) = other == true || other == false
# @param other [Object]
#
# @return [Boolean]
def self.==(other) = other.is_a?(Class) && other <= Orb::Internal::Type::BooleanModel
def self.==(other) = other.is_a?(Class) && other <= Orb::Internal::Type::Boolean

class << self
# @api private
Expand Down
Loading
Loading