Skip to content

Commit

Permalink
Use ServiceShape as the container for operations and rename Shapes to…
Browse files Browse the repository at this point in the history
… Schema (#276)
  • Loading branch information
mullermp authored Feb 17, 2025
1 parent d4711fd commit c32b7c0
Show file tree
Hide file tree
Showing 37 changed files with 345 additions and 439 deletions.
26 changes: 13 additions & 13 deletions gems/smithy-client/lib/smithy-client/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def build_input(operation_name, params = {})
# names. These are valid arguments to {#build_input} and are also
# valid methods.
def operation_names
self.class.schema.operation_names
self.class.service.operation_names
end

# @api private
Expand All @@ -47,11 +47,11 @@ def inspect
# opportunity to register options with default values.
def build_config(plugins, options)
config = Configuration.new
config.add_option(:schema)
config.add_option(:service)
plugins.each do |plugin|
plugin.add_options(config) if plugin.respond_to?(:add_options)
end
config.build!(options.merge(schema: self.class.schema))
config.build!(options.merge(service: self.class.service))
end

# Gives each plugin the opportunity to register handlers for this client.
Expand All @@ -72,7 +72,7 @@ def after_initialize(plugins)
def context_for(operation_name, params)
HandlerContext.new(
operation_name: operation_name,
operation: config.schema.operation(operation_name),
operation: config.service.operation(operation_name),
client: self,
params: params,
config: config
Expand Down Expand Up @@ -150,24 +150,24 @@ def plugins
Array(@plugins).freeze
end

# @return [Model::Schema]
def schema
@schema ||= Model::Schema.new
# @return [Model::Shapes::ServiceShape]
def service
@service ||= Model::Shapes::ServiceShape.new
end

# @param [Schema] schema
def schema=(schema)
@schema = schema
# @param [ServiceShape] service
def service=(service)
@service = service
define_operation_methods
end

# @option options [Schema] :schema (Schema.new)
# @option options [ServiceShape] :service (ServiceShape.new)
# @option options [Array<Plugin>] :plugins ([]) A list of plugins to
# add to the client class created.
# @return [Class<Client::Base>]
def define(options = {})
subclass = Class.new(self)
subclass.schema = options[:schema] || schema
subclass.service = options[:service] || service
Array(options[:plugins]).each do |plugin|
subclass.add_plugin(plugin)
end
Expand All @@ -179,7 +179,7 @@ def define(options = {})

def define_operation_methods
operations_module = Module.new
@schema.operation_names.each do |method_name|
@service.operation_names.each do |method_name|
operations_module.send(:define_method, method_name) do |*args, &block|
params = args[0] || {}
options = args[1] || {}
Expand Down
12 changes: 5 additions & 7 deletions gems/smithy-client/lib/smithy-client/cbor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ class Error < StandardError; end
# Malformed buffer, expected more bytes
class OutOfBytesError < Error
def initialize(requested_bytes, left)
super("Out of bytes. Trying to read #{requested_bytes} " \
"bytes but buffer contains only #{left}")
super("Out of bytes. Trying to read #{requested_bytes} bytes but buffer contains only #{left}")
end
end

Expand All @@ -52,8 +51,7 @@ def initialize(type)
# Malformed buffer, more bytes than expected
class ExtraBytesError < Error
def initialize(pos, size)
super('Extra bytes follow after decoding item. ' \
"Read #{pos} / #{size} bytes")
super("Extra bytes follow after decoding item. Read #{pos} / #{size} bytes")
end
end

Expand All @@ -68,14 +66,14 @@ def initialize(add_info)
end

class << self
# @param [Hash] data
# @return [String] cbor
# @param [nil, BigDecimal, Time, Tagged, String, Hash, Array] data
# @return [String] bytes
def encode(data)
Encoder.new.add(data).bytes
end

# @param [String] bytes
# @return [Hash]
# @return [nil, BigDecimal, Time, Tagged, String, Hash, Array]
def decode(bytes)
Decoder.new(bytes.force_encoding(Encoding::BINARY)).decode
end
Expand Down
16 changes: 8 additions & 8 deletions gems/smithy-client/lib/smithy-client/cbor/decoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
module Smithy
module Client
module CBOR
# Pure Ruby implementation of CBOR Decoder
# @api private
# rubocop:disable Metrics/ClassLength
class Decoder
FIVE_BIT_MASK = 0x1F
TAG_TYPE_EPOCH = 1
TAG_TYPE_BIGNUM = 2
TAG_TYPE_NEG_BIGNUM = 3
TAG_TYPE_BIGDEC = 4

def initialize(bytes)
@buffer = bytes
@pos = 0
Expand All @@ -24,12 +30,6 @@ def decode

private

FIVE_BIT_MASK = 0x1F
TAG_TYPE_EPOCH = 1
TAG_TYPE_BIGNUM = 2
TAG_TYPE_NEG_BIGNUM = 3
TAG_TYPE_BIGDEC = 4

# high level, generic decode. Based on the next type.
# Consumes and returns the next item as a ruby object.
# rubocop:disable Metrics
Expand Down Expand Up @@ -234,7 +234,7 @@ def read_half
# by 1024 (2^10) to get exp-15-10
Math.ldexp(1024 + mant, exp - 25)
end
if (b16[15]).zero?
if b16[15].zero?
val
else
-val
Expand Down
40 changes: 20 additions & 20 deletions gems/smithy-client/lib/smithy-client/cbor/encoder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,27 @@
module Smithy
module Client
module CBOR
# Pure ruby implementation of CBOR encoder.
# @api private
class Encoder
MAJOR_TYPE_UNSIGNED_INT = 0x00 # 000_00000 - Major Type 0 - unsigned int
MAJOR_TYPE_NEGATIVE_INT = 0x20 # 001_00000 - Major Type 1 - negative int
MAJOR_TYPE_BYTE_STR = 0x40 # 010_00000 - Major Type 2 (Byte String)
MAJOR_TYPE_STR = 0x60 # 011_00000 - Major Type 3 (Text String)
MAJOR_TYPE_ARRAY = 0x80 # 100_00000 - Major Type 4 (Array)
MAJOR_TYPE_MAP = 0xa0 # 101_00000 - Major Type 5 (Map)
MAJOR_TYPE_TAG = 0xc0 # 110_00000 - Major type 6 (Tag)
MAJOR_TYPE_SIMPLE = 0xe0 # 111_00000 - Major type 7 (111) + 5 bit 0

FLOAT_BYTES = 0xfa # 111_11010 - Major type 7 (Float) + value: 26
DOUBLE_BYTES = 0xfb # 111_ 11011 - Major type 7 (Float) + value: 26

# https://www.rfc-editor.org/rfc/rfc8949.html#tags
TAG_TYPE_EPOCH = 1
TAG_BIGNUM_BASE = 2
TAG_TYPE_BIGDEC = 4

MAX_INTEGER = 18_446_744_073_709_551_616 # 2^64

def initialize
@buffer = String.new
end
Expand Down Expand Up @@ -39,25 +58,6 @@ def add(value)

private

MAJOR_TYPE_UNSIGNED_INT = 0x00 # 000_00000 - Major Type 0 - unsigned int
MAJOR_TYPE_NEGATIVE_INT = 0x20 # 001_00000 - Major Type 1 - negative int
MAJOR_TYPE_BYTE_STR = 0x40 # 010_00000 - Major Type 2 (Byte String)
MAJOR_TYPE_STR = 0x60 # 011_00000 - Major Type 3 (Text String)
MAJOR_TYPE_ARRAY = 0x80 # 100_00000 - Major Type 4 (Array)
MAJOR_TYPE_MAP = 0xa0 # 101_00000 - Major Type 5 (Map)
MAJOR_TYPE_TAG = 0xc0 # 110_00000 - Major type 6 (Tag)
MAJOR_TYPE_SIMPLE = 0xe0 # 111_00000 - Major type 7 (111) + 5 bit 0

FLOAT_BYTES = 0xfa # 111_11010 - Major type 7 (Float) + value: 26
DOUBLE_BYTES = 0xfb # 111_ 11011 - Major type 7 (Float) + value: 26

# https://www.rfc-editor.org/rfc/rfc8949.html#tags
TAG_TYPE_EPOCH = 1
TAG_BIGNUM_BASE = 2
TAG_TYPE_BIGDEC = 4

MAX_INTEGER = 18_446_744_073_709_551_616 # 2^64

def add_array(value)
start_array(value.size)
value.each { |di| add(di) }
Expand Down
14 changes: 7 additions & 7 deletions gems/smithy-client/lib/smithy-client/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ module Client
# #=> raises an ArgumentError, :price was not added as an option
#
class Configuration
# @api private
Defaults = Class.new(Array) do
def each(&block)
reverse.to_a.each(&block)
end
end

def initialize
@defaults = Hash.new { |h, k| h[k] = Defaults.new }
end
Expand Down Expand Up @@ -150,13 +157,6 @@ def apply_defaults(struct, options)
DefaultResolver.new(struct).resolve
end

# @api private
Defaults = Class.new(Array) do
def each(&block)
reverse.to_a.each(&block)
end
end

# @api private
class DynamicDefault
attr_accessor :block
Expand Down
34 changes: 17 additions & 17 deletions gems/smithy-client/spec/smithy-client/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
module Smithy
module Client
describe Base do
let(:schema) { Model::Schema.new }
let(:client_class) { Base.define(schema: schema) }
let(:service) { Model::Shapes::ServiceShape.new }
let(:client_class) { Base.define(service: service) }
let(:plugin_a) { Plugin.new }
let(:plugin_b) { Plugin.new }

Expand All @@ -19,8 +19,8 @@ module Client
expect(subject.config).to be_kind_of(Struct)
end

it 'contains a schema' do
expect(subject.config.schema).to be(client_class.schema)
it 'contains a service shape' do
expect(subject.config.service).to be(client_class.service)
end

it 'passes constructor args to the config' do
Expand All @@ -46,7 +46,7 @@ module Client
let(:input) { subject.build_input(:operation) }

before(:each) do
schema.add_operation(:operation, Model::Shapes::OperationShape.new)
service.add_operation(:operation, Model::Shapes::OperationShape.new)
end

it 'returns an Input' do
Expand Down Expand Up @@ -101,7 +101,7 @@ module Client
let(:input) { Input.new }

before(:each) do
schema.add_operation(:operation, Model::Shapes::OperationShape.new)
service.add_operation(:operation, Model::Shapes::OperationShape.new)
allow(subject).to receive(:build_input).and_return(input)
allow(input).to receive(:send_request)
end
Expand Down Expand Up @@ -235,17 +235,17 @@ module Client
end
end

describe '.schema' do
it 'defaults to a Schema' do
expect(client_class.schema).to be_kind_of(Model::Schema)
describe '.service' do
it 'defaults to a ServiceShape' do
expect(client_class.service).to be_kind_of(Model::Shapes::ServiceShape)
end
end

describe '.schema=' do
describe '.service=' do
it 'can be set' do
schema = Model::Schema.new
client_class.schema = schema
expect(client_class.schema).to be(schema)
service = Model::Shapes::ServiceShape.new
client_class.service = service
expect(client_class.service).to be(service)
end
end

Expand All @@ -255,10 +255,10 @@ module Client
expect(client_class.ancestors).to include(Client::Base)
end

it 'sets the schema on the client class' do
schema = Model::Schema.new
client_class = Base.define(schema: schema)
expect(client_class.schema).to be(schema)
it 'sets the service on the client class' do
service = Model::Shapes::ServiceShape.new
client_class = Base.define(service: service)
expect(client_class.service).to be(service)
end

it 'extends from subclasses of client' do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def to_h

it 'performs a deeply nested conversion of values' do
client_class = ClientHelper.sample_service
rules = client_class.const_get(:Shapes).const_get(:SCHEMA).operation(:operation).input
rules = client_class.const_get(:Schema).const_get(:SERVICE).operation(:operation).input
structure = client_class.const_get(:Types).const_get(:Structure)

params = structure.new(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Client
describe ParamValidator do
let(:shapes) { ClientHelper.sample_shapes }
let(:sample_service) { ClientHelper.sample_service(shapes: shapes) }
let(:schema) { sample_service.const_get(:Shapes).const_get(:SCHEMA) }
let(:schema) { sample_service.const_get(:Schema).const_get(:SERVICE) }

def validate(params, expected_errors = [])
rules = schema.operation(:operation).input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module Plugins
it 'calls the param converter' do
client = client_class.new
params = {}
input = sample_service.const_get(:Shapes).const_get(:SCHEMA).operation(:operation).input
input = sample_service.const_get(:Schema).const_get(:SERVICE).operation(:operation).input
expect(Client::ParamConverter).to receive(:new).with(input).and_call_original
expect_any_instance_of(Client::ParamConverter).to receive(:convert).with(params).and_call_original
client.operation(params)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ module Plugins
it 'calls the param validator' do
client = client_class.new
params = {}
input = sample_service.const_get(:Shapes).const_get(:SCHEMA).operation(:operation).input
input = sample_service.const_get(:Schema).const_get(:SERVICE).operation(:operation).input
expect(Client::ParamValidator).to receive(:new).with(input).and_call_original
expect_any_instance_of(Client::ParamValidator).to receive(:validate!).with(params).and_call_original
client.operation(params)
Expand Down
1 change: 0 additions & 1 deletion gems/smithy-model/lib/smithy-model.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# frozen_string_literal: true

require_relative 'smithy-model/schema'
require_relative 'smithy-model/shapes'
require_relative 'smithy-model/structure'
require_relative 'smithy-model/union'
Expand Down
Loading

0 comments on commit c32b7c0

Please sign in to comment.