From 03d1659e487d5df1db49a1d0b66a655fddc4cc2f Mon Sep 17 00:00:00 2001 From: Matt Muller <53055821+mullermp@users.noreply.github.com> Date: Fri, 20 Dec 2024 14:11:33 -0500 Subject: [PATCH] Slim down vise and add new tests (#228) --- gems/smithy/lib/smithy.rb | 1 + .../smithy/anvil/client/views/client_class.rb | 5 +- .../lib/smithy/anvil/client/views/errors.rb | 9 ++- .../lib/smithy/anvil/client/views/types.rb | 9 ++- gems/smithy/lib/smithy/plan.rb | 8 +-- gems/smithy/lib/smithy/vise.rb | 17 +----- gems/smithy/lib/smithy/vise/enum_shape.rb | 25 --------- gems/smithy/lib/smithy/vise/int_enum_shape.rb | 25 --------- gems/smithy/lib/smithy/vise/list_shape.rb | 17 ------ gems/smithy/lib/smithy/vise/map_shape.rb | 21 ------- gems/smithy/lib/smithy/vise/member_shape.rb | 25 --------- gems/smithy/lib/smithy/vise/model.rb | 53 ------------------ .../smithy/lib/smithy/vise/operation_index.rb | 28 ++++++---- .../smithy/lib/smithy/vise/operation_shape.rb | 25 --------- gems/smithy/lib/smithy/vise/resource_shape.rb | 44 --------------- gems/smithy/lib/smithy/vise/service_index.rb | 19 ++++--- gems/smithy/lib/smithy/vise/service_shape.rb | 25 --------- gems/smithy/lib/smithy/vise/shape.rb | 55 ++++++------------- .../smithy/lib/smithy/vise/structure_shape.rb | 25 --------- gems/smithy/lib/smithy/vise/trait.rb | 19 ------- gems/smithy/lib/smithy/vise/union_shape.rb | 25 --------- .../fixtures/vise_multi_service/model.json | 11 ++++ .../fixtures/vise_multi_service/model.smithy | 7 +++ .../spec/fixtures/vise_no_service/model.json | 4 ++ .../fixtures/vise_no_service/model.smithy | 3 + .../spec/smithy/vise/operation_index_spec.rb | 27 +++++++++ .../spec/smithy/vise/service_index_spec.rb | 39 +++++++++++++ gems/smithy/spec/smithy/vise/shape_spec.rb | 55 +++++++++++++++++++ gems/smithy/spec/smithy/vise_spec.rb | 55 ------------------- 29 files changed, 208 insertions(+), 473 deletions(-) delete mode 100644 gems/smithy/lib/smithy/vise/enum_shape.rb delete mode 100644 gems/smithy/lib/smithy/vise/int_enum_shape.rb delete mode 100644 gems/smithy/lib/smithy/vise/list_shape.rb delete mode 100644 gems/smithy/lib/smithy/vise/map_shape.rb delete mode 100644 gems/smithy/lib/smithy/vise/member_shape.rb delete mode 100644 gems/smithy/lib/smithy/vise/model.rb delete mode 100644 gems/smithy/lib/smithy/vise/operation_shape.rb delete mode 100644 gems/smithy/lib/smithy/vise/resource_shape.rb delete mode 100644 gems/smithy/lib/smithy/vise/service_shape.rb delete mode 100644 gems/smithy/lib/smithy/vise/structure_shape.rb delete mode 100644 gems/smithy/lib/smithy/vise/trait.rb delete mode 100644 gems/smithy/lib/smithy/vise/union_shape.rb create mode 100644 gems/smithy/spec/fixtures/vise_multi_service/model.json create mode 100644 gems/smithy/spec/fixtures/vise_multi_service/model.smithy create mode 100644 gems/smithy/spec/fixtures/vise_no_service/model.json create mode 100644 gems/smithy/spec/fixtures/vise_no_service/model.smithy create mode 100644 gems/smithy/spec/smithy/vise/operation_index_spec.rb create mode 100644 gems/smithy/spec/smithy/vise/service_index_spec.rb create mode 100644 gems/smithy/spec/smithy/vise/shape_spec.rb delete mode 100644 gems/smithy/spec/smithy/vise_spec.rb diff --git a/gems/smithy/lib/smithy.rb b/gems/smithy/lib/smithy.rb index b407c214..abc16655 100644 --- a/gems/smithy/lib/smithy.rb +++ b/gems/smithy/lib/smithy.rb @@ -23,6 +23,7 @@ class << self # Generates a Ruby artifact from a Smithy model. # @param [Plan] plan The plan to generate the artifact from. def smith(plan) + plan.welds.each { |weld| weld.preprocess(plan.model) } artifact = Smithy::Forge.forge(plan) plan.polishes.each { |polish| polish.polish(artifact) } artifact diff --git a/gems/smithy/lib/smithy/anvil/client/views/client_class.rb b/gems/smithy/lib/smithy/anvil/client/views/client_class.rb index 8d1cf2d2..23f82f0c 100644 --- a/gems/smithy/lib/smithy/anvil/client/views/client_class.rb +++ b/gems/smithy/lib/smithy/anvil/client/views/client_class.rb @@ -32,7 +32,8 @@ def gem_version end def operations - Vise::Model.operations(@model).map { |id, shape| Operation.new(id, shape) } + service = Vise::ServiceIndex.new(@model).service + Vise::OperationIndex.new(@model).for(service).map { |id, shape| Operation.new(id, shape) } end # @api private @@ -47,7 +48,7 @@ def documentation end def name - @operation.name.underscore + Vise::Shape.name(@id).underscore end end end diff --git a/gems/smithy/lib/smithy/anvil/client/views/errors.rb b/gems/smithy/lib/smithy/anvil/client/views/errors.rb index dba9ee5e..f85477eb 100644 --- a/gems/smithy/lib/smithy/anvil/client/views/errors.rb +++ b/gems/smithy/lib/smithy/anvil/client/views/errors.rb @@ -17,9 +17,8 @@ def namespace end def errors - @model - .shapes - .select { |_key, shape| shape.traits&.any? { |_id, trait| trait.id == 'smithy.api#error' } } + @model['shapes'] + .select { |_key, shape| shape['traits']&.any? { |id, _trait| id == 'smithy.api#error' } } .map { |id, structure| Error.new(id, structure) } end @@ -35,11 +34,11 @@ def documentation end def name - @structure.name + Vise::Shape.name(@id) end def member_names - @structure.members.keys.map(&:underscore) + @structure['members'].keys.map(&:underscore) end end end diff --git a/gems/smithy/lib/smithy/anvil/client/views/types.rb b/gems/smithy/lib/smithy/anvil/client/views/types.rb index e5d97abc..e86593a6 100644 --- a/gems/smithy/lib/smithy/anvil/client/views/types.rb +++ b/gems/smithy/lib/smithy/anvil/client/views/types.rb @@ -17,9 +17,8 @@ def namespace end def types - @model - .shapes - .select { |_key, shape| shape.is_a?(Vise::StructureShape) } + @model['shapes'] + .select { |_key, shape| shape['type'] == 'structure' } .map { |id, structure| Type.new(id, structure) } end @@ -35,11 +34,11 @@ def documentation end def name - @structure.name + Vise::Shape.name(@id) end def member_names - @structure.members.keys.map(&:underscore) + @structure['members'].keys.map(&:underscore) end end end diff --git a/gems/smithy/lib/smithy/plan.rb b/gems/smithy/lib/smithy/plan.rb index 7aba30dd..aa047c64 100644 --- a/gems/smithy/lib/smithy/plan.rb +++ b/gems/smithy/lib/smithy/plan.rb @@ -7,19 +7,17 @@ class Plan # @param [Symbol] type The type of code to generate, either :client, :server, or :types. # @param [Hash] options The options passed to the generator. def initialize(model, type, options = {}) + @model = model @type = type @options = options Welds.load!(self) - @welds = Welds.for(model) Polishes.load!(self) + @welds = Welds.for(model) @polishes = Polishes.for(model) - - @welds.each { |weld| weld.preprocess(model) } - @model = Vise::Model.new(model) end - # @return [Vise::Model] The API model wrapped by Vise. + # @return [Hash] The API model as a JSON hash. attr_reader :model # @return [Symbol] The type of code to generate. diff --git a/gems/smithy/lib/smithy/vise.rb b/gems/smithy/lib/smithy/vise.rb index 552d713f..ddcae06b 100644 --- a/gems/smithy/lib/smithy/vise.rb +++ b/gems/smithy/lib/smithy/vise.rb @@ -1,24 +1,9 @@ # frozen_string_literal: true +require_relative 'vise/shape' require_relative 'vise/operation_index' require_relative 'vise/service_index' -require_relative 'vise/shape' -require_relative 'vise/trait' - -require_relative 'vise/enum_shape' -require_relative 'vise/int_enum_shape' -require_relative 'vise/list_shape' -require_relative 'vise/map_shape' -require_relative 'vise/member_shape' -require_relative 'vise/operation_shape' -require_relative 'vise/resource_shape' -require_relative 'vise/service_shape' -require_relative 'vise/structure_shape' -require_relative 'vise/union_shape' - -require_relative 'vise/model' - module Smithy # A module that parses the Smithy JSON model. module Vise; end diff --git a/gems/smithy/lib/smithy/vise/enum_shape.rb b/gems/smithy/lib/smithy/vise/enum_shape.rb deleted file mode 100644 index 4318ed9c..00000000 --- a/gems/smithy/lib/smithy/vise/enum_shape.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents an enum shape from the model. - class EnumShape < Shape - # (see Shape#initialize) - def initialize(id, shape) - super - @members = build_members(shape['members']) - end - - # @return [Hash] - attr_reader :members - - private - - def build_members(members) - members.each_with_object({}) do |(id, shape), h| - h[id] = MemberShape.new(id, shape) - end - end - end - end -end diff --git a/gems/smithy/lib/smithy/vise/int_enum_shape.rb b/gems/smithy/lib/smithy/vise/int_enum_shape.rb deleted file mode 100644 index c1b9d7cc..00000000 --- a/gems/smithy/lib/smithy/vise/int_enum_shape.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents an int enum shape from the model. - class IntEnumShape < Shape - # (see Shape#initialize) - def initialize(id, shape) - super - @members = build_members(shape['members']) - end - - # @return [Hash] - attr_reader :members - - private - - def build_members(members) - members.each_with_object({}) do |(id, shape), h| - h[id] = MemberShape.new(id, shape) - end - end - end - end -end diff --git a/gems/smithy/lib/smithy/vise/list_shape.rb b/gems/smithy/lib/smithy/vise/list_shape.rb deleted file mode 100644 index 0d19ad66..00000000 --- a/gems/smithy/lib/smithy/vise/list_shape.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents a list shape from the model. - class ListShape < Shape - # (see Shape#initialize) - def initialize(id, shape) - super - @member = MemberShape.new('member', shape['member']) - end - - # @return [MemberShape] - attr_reader :member - end - end -end diff --git a/gems/smithy/lib/smithy/vise/map_shape.rb b/gems/smithy/lib/smithy/vise/map_shape.rb deleted file mode 100644 index 281ac434..00000000 --- a/gems/smithy/lib/smithy/vise/map_shape.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents a map shape from the model. - class MapShape < Shape - # (see Shape#initialize) - def initialize(id, shape) - super - @key = MemberShape.new('key', shape['key']) - @value = MemberShape.new('value', shape['value']) - end - - # @return [MemberShape] - attr_reader :key - - # @return [MemberShape] - attr_reader :value - end - end -end diff --git a/gems/smithy/lib/smithy/vise/member_shape.rb b/gems/smithy/lib/smithy/vise/member_shape.rb deleted file mode 100644 index 12df4ae4..00000000 --- a/gems/smithy/lib/smithy/vise/member_shape.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents a member shape from the model. - class MemberShape < Shape - # (see Shape#initialize) - def initialize(id, shape) - super - @traits = build_traits(shape['traits']) - end - - # @return [Hash, nil] Member shape traits - attr_reader :traits - - private - - def build_traits(traits) - return nil unless traits - - traits.each_with_object({}) { |(id, data), h| h[id] = Trait.new(id, data) } - end - end - end -end diff --git a/gems/smithy/lib/smithy/vise/model.rb b/gems/smithy/lib/smithy/vise/model.rb deleted file mode 100644 index 1029e528..00000000 --- a/gems/smithy/lib/smithy/vise/model.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents a Smithy model. - class Model - # @api private - SHAPE_CLASSES = { - 'enum' => EnumShape, - 'intEnum' => IntEnumShape, - 'list' => ListShape, - 'map' => MapShape, - 'operation' => OperationShape, - 'resource' => ResourceShape, - 'service' => ServiceShape, - 'structure' => StructureShape, - 'union' => UnionShape - }.freeze - - # @param [Hash] model The Smithy model as a JSON hash. - def initialize(model) - @version = model['smithy'] - @shapes = build_shapes(model['shapes']) - end - - # @return [String] - attr_reader :version - - # @return [Hash] - attr_reader :shapes - - # @return [ServiceShape] - def self.service(model) - ServiceIndex.new(model.shapes).service - end - - # @return [Hash] - def self.operations(model) - service = service(model) - OperationIndex.new(model.shapes).for(service) - end - - private - - def build_shapes(shapes) - shapes.each_with_object({}) do |(id, shape), h| - klass = SHAPE_CLASSES[shape['type']] || Shape - h[id] = klass.new(id, shape) - end - end - end - end -end diff --git a/gems/smithy/lib/smithy/vise/operation_index.rb b/gems/smithy/lib/smithy/vise/operation_index.rb index 83ca29e4..ba9beafd 100644 --- a/gems/smithy/lib/smithy/vise/operation_index.rb +++ b/gems/smithy/lib/smithy/vise/operation_index.rb @@ -2,14 +2,20 @@ module Smithy module Vise - # Finds all operations in a service. + # Finds all operation shapes in a service. class OperationIndex - def initialize(shapes) - @shapes = shapes + RESOURCE_LIFECYCLE_KEYS = %w[create put read update delete list].freeze + + # @param [Hash] model Model + def initialize(model) + @shapes = model['shapes'] end + # @param [Hash] service Service shape + # @return [Hash] The operations for the service. def for(service) operations = {} + _id, service = service.first parse_service_operations(service, operations) parse_service_resources(service, operations) operations.sort_by { |k, _v| k }.to_h @@ -18,14 +24,14 @@ def for(service) private def parse_service_operations(service, operations) - service.operations&.collect do |shape| + service['operations']&.collect do |shape| id = shape['target'] operations[id] = @shapes[id] end end def parse_service_resources(service, operations) - service.resources&.collect do |shape| + service['resources']&.collect do |shape| id = shape['target'] parse_resource(@shapes[id], operations) end @@ -36,30 +42,30 @@ def parse_resource(resource, operations) parse_resource_operations(resource, operations) parse_resource_collection_operations(resource, operations) - resource.resources&.collect do |shape| + resource['resources']&.collect do |shape| id = shape['target'] parse_resource(@shapes[id], operations) end end def parse_lifecycles(resource, operations) - resource.lifecycle_operations.each_value do |data| - next unless data + RESOURCE_LIFECYCLE_KEYS.each do |key| + next unless resource[key] - id = data['target'] + id = resource[key]['target'] operations[id] = @shapes[id] end end def parse_resource_operations(resource, operations) - resource.operations&.collect do |shape| + resource['operations']&.collect do |shape| id = shape['target'] operations[id] = @shapes[id] end end def parse_resource_collection_operations(resource, operations) - resource.collection_operations&.collect do |shape| + resource['collectionOperations']&.collect do |shape| id = shape['target'] operations[id] = @shapes[id] end diff --git a/gems/smithy/lib/smithy/vise/operation_shape.rb b/gems/smithy/lib/smithy/vise/operation_shape.rb deleted file mode 100644 index 074655b5..00000000 --- a/gems/smithy/lib/smithy/vise/operation_shape.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents an operation shape from the model. - class OperationShape < Shape - # (see Shape#initialize) - def initialize(id, shape) - super - @input = shape['input'] - @output = shape['output'] - @errors = shape['errors'] - end - - # @return [Hash, nil] - attr_reader :input - - # @return [Hash, nil] - attr_reader :output - - # @return [Array>, nil] - attr_reader :errors - end - end -end diff --git a/gems/smithy/lib/smithy/vise/resource_shape.rb b/gems/smithy/lib/smithy/vise/resource_shape.rb deleted file mode 100644 index 8ad2d5f9..00000000 --- a/gems/smithy/lib/smithy/vise/resource_shape.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents a resource shape from the model. - class ResourceShape < Shape - RESOURCE_LIFECYCLE_KEYS = %w[create put read update delete list].freeze - RESOURCE_OPERATION_KEYS = %w[operation collectionOperations].freeze - - # (see Shape#initialize) - def initialize(id, shape) - super - @identifiers = shape['identifiers'] - @properties = shape['properties'] - @lifecycle_operations = {} - RESOURCE_LIFECYCLE_KEYS.each do |key| - @lifecycle_operations[key] = shape[key] - end - - @operations = shape['operations'] - @collection_operations = shape['collectionOperations'] - @resources = shape['resources'] - end - - # @return [Hash, nil] - attr_reader :identifiers - - # @return [Hash, nil] - attr_reader :properties - - # @return [Hash, nil] - attr_reader :lifecycle_operations - - # @return [Array>, nil] - attr_reader :operations - - # @return [Array>, nil] - attr_reader :collection_operations - - # @return [Array>, nil] - attr_reader :resources - end - end -end diff --git a/gems/smithy/lib/smithy/vise/service_index.rb b/gems/smithy/lib/smithy/vise/service_index.rb index dd9e63c6..15b9c16e 100644 --- a/gems/smithy/lib/smithy/vise/service_index.rb +++ b/gems/smithy/lib/smithy/vise/service_index.rb @@ -4,17 +4,20 @@ module Smithy module Vise # Finds a service shape in a set of shapes. class ServiceIndex - def initialize(shapes) - @shapes = shapes + # @param [Hash] model Model + def initialize(model) + @service = find_service(model['shapes']) end - # @return [ServiceShape] The service shape for the shapes. - def service - services = @shapes.each_value.select { |v| v.is_a?(ServiceShape) } - raise 'Multiple service shapes found' if services.size > 1 + # @return [Hash] The service shape for the shapes. + attr_reader :service - service = services.first - raise 'No service shape found' if service.nil? + private + + def find_service(shapes) + service = shapes.select { |_, shape| shape['type'] == 'service' } + raise 'Multiple service shapes found' if service.size > 1 + raise 'No service shape found' if service.empty? service end diff --git a/gems/smithy/lib/smithy/vise/service_shape.rb b/gems/smithy/lib/smithy/vise/service_shape.rb deleted file mode 100644 index c0bad192..00000000 --- a/gems/smithy/lib/smithy/vise/service_shape.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents a service shape from the model. - class ServiceShape < Shape - # (see Shape#initialize) - def initialize(id, shape) - super - @version = shape['version'] - @operations = shape['operations'] - @resources = shape['resources'] - end - - # @return [String, nil] - attr_reader :version - - # @return [Array>, nil] - attr_reader :operations - - # @return [Array>, nil] - attr_reader :resources - end - end -end diff --git a/gems/smithy/lib/smithy/vise/shape.rb b/gems/smithy/lib/smithy/vise/shape.rb index 48693acb..bc92a8a9 100644 --- a/gems/smithy/lib/smithy/vise/shape.rb +++ b/gems/smithy/lib/smithy/vise/shape.rb @@ -13,55 +13,36 @@ module Vise # └──────────────────────┬───────────────────────┘ # (Absolute shape ID) class Shape - # @param [String] id Absolute shape ID - # @param [Hash] shape Shape definition - def initialize(id, shape) - @id = id - @traits = build_traits(shape['traits']) - end - - # @return [String] Absolute shape ID - attr_reader :id - - # @return [Hash, nil] Shape traits - attr_reader :traits - # Optional shape namespace + # @param [String] id Shape ID # @return [String, nil] Shape namespace - def namespace - return nil unless @id.include?('#') + def self.namespace(id) + return nil unless id.include?('#') - @id.split('#').first + id.split('#').first end - # @return [String] Relative shape ID - def relative_id - return nil if @id.empty? - - @id.split('#').last + # Relative shape ID + # @param [String] id Shape ID + # @return [String, nil] Relative shape ID + def self.relative_id(id) + id.split('#').last end - # @return [String] Shape name - def name - return nil if @id.empty? - - @id.split('#').last.split('$').first + # Shape name + # @param [String] id Shape ID + # @return [String, nil] Shape name + def self.name(id) + id.split('#').last&.split('$')&.first end # Optional member name + # @param [String] id Shape ID # @return [String, nil] Member name - def member_name - return nil unless @id.include?('$') - - @id.split('$').last - end - - private - - def build_traits(traits) - return nil unless traits + def self.member_name(id) + return nil unless id.include?('$') - traits.each_with_object({}) { |(id, data), h| h[id] = Trait.new(id, data) } + id.split('$').last end end end diff --git a/gems/smithy/lib/smithy/vise/structure_shape.rb b/gems/smithy/lib/smithy/vise/structure_shape.rb deleted file mode 100644 index 2438aab1..00000000 --- a/gems/smithy/lib/smithy/vise/structure_shape.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents a structure shape from the model. - class StructureShape < Shape - # (see Shape#initialize) - def initialize(id, shape) - super - @members = build_members(shape['members']) - end - - # @return [Hash] - attr_reader :members - - private - - def build_members(members) - members.each_with_object({}) do |(id, shape), h| - h[id] = MemberShape.new(id, shape) - end - end - end - end -end diff --git a/gems/smithy/lib/smithy/vise/trait.rb b/gems/smithy/lib/smithy/vise/trait.rb deleted file mode 100644 index 05781e55..00000000 --- a/gems/smithy/lib/smithy/vise/trait.rb +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents a trait from the model. - class Trait - def initialize(id, properties) - @id = id - @properties = properties - end - - # @return [String] - attr_reader :id - - # @return [Hash] - attr_reader :properties - end - end -end diff --git a/gems/smithy/lib/smithy/vise/union_shape.rb b/gems/smithy/lib/smithy/vise/union_shape.rb deleted file mode 100644 index 3caf3346..00000000 --- a/gems/smithy/lib/smithy/vise/union_shape.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -module Smithy - module Vise - # Represents a union shape from the model. - class UnionShape < Shape - # (see Shape#initialize) - def initialize(id, shape) - super - @members = build_members(shape['members']) - end - - # @return [Hash] - attr_reader :members - - private - - def build_members(members) - members.each_with_object({}) do |(id, shape), h| - h[id] = MemberShape.new(id, shape) - end - end - end - end -end diff --git a/gems/smithy/spec/fixtures/vise_multi_service/model.json b/gems/smithy/spec/fixtures/vise_multi_service/model.json new file mode 100644 index 00000000..b427e9ff --- /dev/null +++ b/gems/smithy/spec/fixtures/vise_multi_service/model.json @@ -0,0 +1,11 @@ +{ + "smithy": "2.0", + "shapes": { + "smithy.ruby.tests#Service1": { + "type": "service" + }, + "smithy.ruby.tests#Service2": { + "type": "service" + } + } +} diff --git a/gems/smithy/spec/fixtures/vise_multi_service/model.smithy b/gems/smithy/spec/fixtures/vise_multi_service/model.smithy new file mode 100644 index 00000000..56c5198f --- /dev/null +++ b/gems/smithy/spec/fixtures/vise_multi_service/model.smithy @@ -0,0 +1,7 @@ +$version: "2" + +namespace smithy.ruby.tests + +service Service1 {} + +service Service2 {} diff --git a/gems/smithy/spec/fixtures/vise_no_service/model.json b/gems/smithy/spec/fixtures/vise_no_service/model.json new file mode 100644 index 00000000..46240d48 --- /dev/null +++ b/gems/smithy/spec/fixtures/vise_no_service/model.json @@ -0,0 +1,4 @@ +{ + "smithy": "2.0", + "shapes": {} +} diff --git a/gems/smithy/spec/fixtures/vise_no_service/model.smithy b/gems/smithy/spec/fixtures/vise_no_service/model.smithy new file mode 100644 index 00000000..3929cdd5 --- /dev/null +++ b/gems/smithy/spec/fixtures/vise_no_service/model.smithy @@ -0,0 +1,3 @@ +$version: "2" + +namespace smithy.ruby.tests diff --git a/gems/smithy/spec/smithy/vise/operation_index_spec.rb b/gems/smithy/spec/smithy/vise/operation_index_spec.rb new file mode 100644 index 00000000..135ddbbe --- /dev/null +++ b/gems/smithy/spec/smithy/vise/operation_index_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Smithy + module Vise + describe OperationIndex do + let(:fixture) do + JSON.load_file(File.expand_path('../../fixtures/vise/model.json', __dir__)) + end + + subject { described_class.new(fixture) } + + describe '#for' do + it 'returns a complete set of operations for the service' do + service = + fixture['shapes'] + .select { |_, shape| shape['type'] == 'service' } + expected = + fixture['shapes'] + .select { |_, shape| shape['type'] == 'operation' } + .reject { |id, _| id.include?('OrphanedOperation') } + actual = subject.for(service) + expect(actual.keys).to match_array(expected.keys) + end + end + end + end +end diff --git a/gems/smithy/spec/smithy/vise/service_index_spec.rb b/gems/smithy/spec/smithy/vise/service_index_spec.rb new file mode 100644 index 00000000..558e12f8 --- /dev/null +++ b/gems/smithy/spec/smithy/vise/service_index_spec.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +module Smithy + module Vise + describe ServiceIndex do + let(:model) { JSON.load_file(fixture) } + + subject { described_class.new(model) } + + describe '#service' do + context 'one service shape' do + let(:fixture) { File.expand_path('../../fixtures/vise/model.json', __dir__) } + + it 'finds the service shape' do + expected = model['shapes'].select { |_, shape| shape['type'] == 'service' } + actual = subject.service + expect(actual.keys.first).to eq(expected.keys.first) + end + end + + context 'no service shapes' do + let(:fixture) { File.expand_path('../../fixtures/vise_no_service/model.json', __dir__) } + + it 'raises an error' do + expect { subject.service }.to raise_error('No service shape found') + end + end + + context 'multiple service shapes' do + let(:fixture) { File.expand_path('../../fixtures/vise_multi_service/model.json', __dir__) } + + it 'raises an error' do + expect { subject.service }.to raise_error('Multiple service shapes found') + end + end + end + end + end +end diff --git a/gems/smithy/spec/smithy/vise/shape_spec.rb b/gems/smithy/spec/smithy/vise/shape_spec.rb new file mode 100644 index 00000000..5f35675b --- /dev/null +++ b/gems/smithy/spec/smithy/vise/shape_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module Smithy + module Vise + describe Shape do + let(:namespace) { 'name.space' } + let(:shape_name) { 'Shape' } + let(:member_name) { 'member' } + + let(:relative_id) { "#{shape_name}$#{member_name}" } + let(:absolute_id) { "#{namespace}##{relative_id}" } + let(:namespaced_id) { "#{namespace}##{shape_name}" } + + describe '.namespace' do + it 'returns the namespace' do + expect(Shape.namespace(absolute_id)).to eq(namespace) + end + + it 'returns nil when there is no namespace' do + expect(Shape.namespace(relative_id)).to be_nil + end + end + + describe '.relative_id' do + it 'returns the relative ID' do + expect(Shape.relative_id(absolute_id)).to eq(relative_id) + end + + it 'returns nil when the ID is empty' do + expect(Shape.relative_id('')).to be_nil + end + end + + describe '.name' do + it 'returns the shape name' do + expect(Shape.name(absolute_id)).to eq(shape_name) + end + + it 'returns nil when the ID is empty' do + expect(Shape.name('')).to be_nil + end + end + + describe '.member_name' do + it 'returns the member name' do + expect(Shape.member_name(absolute_id)).to eq(member_name) + end + + it 'returns nil when there is no member name' do + expect(Shape.member_name(namespaced_id)).to be_nil + end + end + end + end +end diff --git a/gems/smithy/spec/smithy/vise_spec.rb b/gems/smithy/spec/smithy/vise_spec.rb deleted file mode 100644 index 33e5c80b..00000000 --- a/gems/smithy/spec/smithy/vise_spec.rb +++ /dev/null @@ -1,55 +0,0 @@ -# frozen_string_literal: true - -module Smithy - describe Vise do - let(:fixture) do - path = File.expand_path('../fixtures/vise/model.json', __dir__) - JSON.parse(File.read(path)) - end - - describe Vise::Model do - subject { described_class.new(fixture) } - - def expect_shape(id, shape) - expected = subject.shapes[id] - actual = Vise::Model::SHAPE_CLASSES[shape['type']] - raise "Unknown shape type: #{shape['type']}" unless actual - - expect(expected).to be_a(actual) - end - - describe '#initialize' do - it 'parses the shapes' do - expect(subject.shapes.each_value).to all(be_a(Vise::Shape)) - end - - it 'parses the shape types' do - fixture['shapes'].each do |id, shape| - expect_shape(id, shape) - end - end - end - - describe '.service' do - it 'finds the service shape' do - expected = fixture['shapes'].select { |_, shape| shape['type'] == 'service' } - actual = Vise::Model.service(subject) - expect(actual.id).to eq(expected.keys.first) - end - end - - describe '.operations' do - it 'returns a complete set of operations' do - expected = - fixture['shapes'] - .select { |_, shape| shape['type'] == 'operation' } - .reject { |id, _| id.include?('OrphanedOperation') } - actual = Vise::Model.operations(subject) - expect(actual.keys).to match_array(expected.keys) - end - end - end - - # TODO: Add more specs for subclasses - end -end