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
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
- 'integrated/**'
- 'stl-preview-head/**'
- 'stl-preview-base/**'
pull_request:
branches-ignore:
- 'stl-preview-head/**'
- 'stl-preview-base/**'

jobs:
lint:
Expand Down
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.8"
".": "0.1.0-alpha.9"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 7
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-103a28182099d9866bc8c40db00f3356fe5be36302874e7ee84ee4fd2f593859.yml
openapi_spec_hash: 30241efa79f9aab6e430c29383d9a2cf
config_hash: 4ab8d35881cc0191126ff443317e03ba
configured_endpoints: 10
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/brand-dev%2Fbrand.dev-3f6d4c0f819a0d3128951d315ad216df22050fbc47c5f601d261d56f8b1d80a5.yml
openapi_spec_hash: 8e7953259a1b6bd7440a780eccad1742
config_hash: 8f3ee44d690a305369555016a77ed016
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## 0.1.0-alpha.9 (2025-06-19)

Full Changelog: [v0.1.0-alpha.8...v0.1.0-alpha.9](https://github.com/brand-dot-dev/ruby-sdk/compare/v0.1.0-alpha.8...v0.1.0-alpha.9)

### Features

* **api:** manual updates ([169c21b](https://github.com/brand-dot-dev/ruby-sdk/commit/169c21b016f153befa54e0d2a68fbe0a8fe6df7e))
* **api:** manual updates ([e3f5264](https://github.com/brand-dot-dev/ruby-sdk/commit/e3f5264df830ac3cc62db19ba13050d7822f0259))


### Bug Fixes

* issue where we cannot mutate arrays on base model derivatives ([ebaaa42](https://github.com/brand-dot-dev/ruby-sdk/commit/ebaaa42de2ed5b3f20120dcba81a42e85cba778a))


### Chores

* **ci:** enable for pull requests ([1e06613](https://github.com/brand-dot-dev/ruby-sdk/commit/1e066138d45a47d25eaf469e9a472279252ada3a))
* **internal:** version bump ([90fada6](https://github.com/brand-dot-dev/ruby-sdk/commit/90fada6f55ae8d314784042718e7de258694575b))

## 0.1.0-alpha.8 (2025-06-12)

Full Changelog: [v0.1.0-alpha.7...v0.1.0-alpha.8](https://github.com/brand-dot-dev/ruby-sdk/compare/v0.1.0-alpha.7...v0.1.0-alpha.8)
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:
brand.dev (0.1.0.pre.alpha.7)
brand.dev (0.1.0.pre.alpha.8)
connection_pool

GEM
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ To use this gem, install via Bundler by adding the following to your application
<!-- x-release-please-start-version -->

```ruby
gem "brand.dev", "~> 0.1.0.pre.alpha.8"
gem "brand.dev", "~> 0.1.0.pre.alpha.9"
```

<!-- x-release-please-end -->
Expand Down
6 changes: 6 additions & 0 deletions lib/brand_dev.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,13 @@
require_relative "brand_dev/models/brand_retrieve_naics_response"
require_relative "brand_dev/models/brand_retrieve_params"
require_relative "brand_dev/models/brand_retrieve_response"
require_relative "brand_dev/models/brand_retrieve_simplified_params"
require_relative "brand_dev/models/brand_retrieve_simplified_response"
require_relative "brand_dev/models/brand_screenshot_params"
require_relative "brand_dev/models/brand_screenshot_response"
require_relative "brand_dev/models/brand_search_params"
require_relative "brand_dev/models/brand_search_response"
require_relative "brand_dev/models/brand_styleguide_params"
require_relative "brand_dev/models/brand_styleguide_response"
require_relative "brand_dev/models"
require_relative "brand_dev/resources/brand"
22 changes: 22 additions & 0 deletions lib/brand_dev/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,28 @@ class Error < StandardError
end

class ConversionError < BrandDev::Errors::Error
# @return [StandardError, nil]
def cause = @cause.nil? ? super : @cause

# @api private
#
# @param on [Class<StandardError>]
# @param method [Symbol]
# @param target [Object]
# @param value [Object]
# @param cause [StandardError, nil]
def initialize(on:, method:, target:, value:, cause: nil)
cls = on.name.split("::").last

message = [
"Failed to parse #{cls}.#{method} from #{value.class} to #{target.inspect}.",
"To get the unparsed API response, use #{cls}[#{method.inspect}].",
cause && "Cause: #{cause.message}"
].filter(&:itself).join(" ")

@cause = cause
super(message)
end
end

class APIError < BrandDev::Errors::Error
Expand Down
7 changes: 6 additions & 1 deletion lib/brand_dev/internal/type/array_of.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,14 @@ def hash = [self.class, item_type].hash
#
# @param state [Hash{Symbol=>Object}] .
#
# @option state [Boolean, :strong] :strictness
# @option state [Boolean] :translate_names
#
# @option state [Boolean] :strictness
#
# @option state [Hash{Symbol=>Object}] :exactness
#
# @option state [Class<StandardError>] :error
#
# @option state [Integer] :branched
#
# @return [Array<Object>, Object]
Expand All @@ -74,6 +78,7 @@ def coerce(value, state:)

unless value.is_a?(Array)
exactness[:no] += 1
state[:error] = TypeError.new("#{value.class} can't be coerced into #{Array}")
return value
end

Expand Down
102 changes: 77 additions & 25 deletions lib/brand_dev/internal/type/base_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def fields
[BrandDev::Internal::Type::Converter.type_info(type_info), type_info]
end

setter = "#{name_sym}="
setter = :"#{name_sym}="
api_name = info.fetch(:api_name, name_sym)
nilable = info.fetch(:nil?, false)
const = if required && !nilable
Expand All @@ -84,30 +84,61 @@ def fields
type_fn: type_fn
}

define_method(setter) { @data.store(name_sym, _1) }
define_method(setter) do |value|
target = type_fn.call
state = BrandDev::Internal::Type::Converter.new_coerce_state(translate_names: false)
coerced = BrandDev::Internal::Type::Converter.coerce(target, value, state: state)
status = @coerced.store(name_sym, state.fetch(:error) || true)
stored =
case [target, status]
in [BrandDev::Internal::Type::Converter | Symbol, true]
coerced
else
value
end
@data.store(name_sym, stored)
end

# rubocop:disable Style/CaseEquality
# rubocop:disable Metrics/BlockLength
define_method(name_sym) do
target = type_fn.call
value = @data.fetch(name_sym) { const == BrandDev::Internal::OMIT ? nil : const }
state = {strictness: :strong, exactness: {yes: 0, no: 0, maybe: 0}, branched: 0}
if (nilable || !required) && value.nil?
nil
else
BrandDev::Internal::Type::Converter.coerce(
target,
value,
state: state

case @coerced[name_sym]
in true | false if BrandDev::Internal::Type::Converter === target
@data.fetch(name_sym)
in ::StandardError => e
raise BrandDev::Errors::ConversionError.new(
on: self.class,
method: __method__,
target: target,
value: @data.fetch(name_sym),
cause: e
)
else
Kernel.then do
value = @data.fetch(name_sym) { const == BrandDev::Internal::OMIT ? nil : const }
state = BrandDev::Internal::Type::Converter.new_coerce_state(translate_names: false)
if (nilable || !required) && value.nil?
nil
else
BrandDev::Internal::Type::Converter.coerce(
target, value, state: state
)
end
rescue StandardError => e
raise BrandDev::Errors::ConversionError.new(
on: self.class,
method: __method__,
target: target,
value: value,
cause: e
)
end
end
rescue StandardError => e
cls = self.class.name.split("::").last
message = [
"Failed to parse #{cls}.#{__method__} from #{value.class} to #{target.inspect}.",
"To get the unparsed API response, use #{cls}[#{__method__.inspect}].",
"Cause: #{e.message}"
].join(" ")
raise BrandDev::Errors::ConversionError.new(message)
end
# rubocop:enable Metrics/BlockLength
# rubocop:enable Style/CaseEquality
end

# @api private
Expand Down Expand Up @@ -207,37 +238,44 @@ class << self
#
# @param state [Hash{Symbol=>Object}] .
#
# @option state [Boolean, :strong] :strictness
# @option state [Boolean] :translate_names
#
# @option state [Boolean] :strictness
#
# @option state [Hash{Symbol=>Object}] :exactness
#
# @option state [Class<StandardError>] :error
#
# @option state [Integer] :branched
#
# @return [self, Object]
def coerce(value, state:)
exactness = state.fetch(:exactness)

if value.is_a?(self.class)
if value.is_a?(self)
exactness[:yes] += 1
return value
end

unless (val = BrandDev::Internal::Util.coerce_hash(value)).is_a?(Hash)
exactness[:no] += 1
state[:error] = TypeError.new("#{value.class} can't be coerced into #{Hash}")
return value
end
exactness[:yes] += 1

keys = val.keys.to_set
instance = new
data = instance.to_h
status = instance.instance_variable_get(:@coerced)

# rubocop:disable Metrics/BlockLength
fields.each do |name, field|
mode, required, target = field.fetch_values(:mode, :required, :type)
api_name, nilable, const = field.fetch_values(:api_name, :nilable, :const)
src_name = state.fetch(:translate_names) ? api_name : name

unless val.key?(api_name)
unless val.key?(src_name)
if required && mode != :dump && const == BrandDev::Internal::OMIT
exactness[nilable ? :maybe : :no] += 1
else
Expand All @@ -246,9 +284,10 @@ def coerce(value, state:)
next
end

item = val.fetch(api_name)
keys.delete(api_name)
item = val.fetch(src_name)
keys.delete(src_name)

state[:error] = nil
converted =
if item.nil? && (nilable || !required)
exactness[nilable ? :yes : :maybe] += 1
Expand All @@ -262,6 +301,8 @@ def coerce(value, state:)
item
end
end

status.store(name, state.fetch(:error) || true)
data.store(name, converted)
end
# rubocop:enable Metrics/BlockLength
Expand Down Expand Up @@ -437,7 +478,18 @@ def to_yaml(*a) = BrandDev::Internal::Type::Converter.dump(self.class, self).to_
# Create a new instance of a model.
#
# @param data [Hash{Symbol=>Object}, self]
def initialize(data = {}) = (@data = BrandDev::Internal::Util.coerce_hash!(data).to_h)
def initialize(data = {})
@data = {}
@coerced = {}
BrandDev::Internal::Util.coerce_hash!(data).each do
if self.class.known_fields.key?(_1)
public_send(:"#{_1}=", _2)
else
@data.store(_1, _2)
@coerced.store(_1, false)
end
end
end

class << self
# @api private
Expand Down
8 changes: 7 additions & 1 deletion lib/brand_dev/internal/type/boolean.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@ def self.==(other) = other.is_a?(Class) && other <= BrandDev::Internal::Type::Bo
class << self
# @api private
#
# Coerce value to Boolean if possible, otherwise return the original value.
#
# @param value [Boolean, Object]
#
# @param state [Hash{Symbol=>Object}] .
#
# @option state [Boolean, :strong] :strictness
# @option state [Boolean] :translate_names
#
# @option state [Boolean] :strictness
#
# @option state [Hash{Symbol=>Object}] :exactness
#
# @option state [Class<StandardError>] :error
#
# @option state [Integer] :branched
#
# @return [Boolean, Object]
Expand Down
Loading
Loading