Class: Servactory::TestKit::Rspec::Matchers::Base::AttributeMatcher

Inherits:
Object
  • Object
show all
Includes:
RSpec::Matchers::Composable, SubmatcherRegistry
Defined in:
lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb

Overview

Base class for RSpec matchers that validate Servactory attribute definitions.

## Purpose

AttributeMatcher provides the foundation for testing service attribute definitions (inputs, internals, outputs) in Servactory services. It implements the RSpec matcher protocol with fluent API for chaining validation rules.

## Usage

Subclasses define specific attribute type matchers:

“‘ruby class HaveServiceInputMatcher < Base::AttributeMatcher

for_attribute_type :input

register_submatcher :required,
                    class_name: "Input::RequiredSubmatcher",
                    mutually_exclusive_with: [:optional]

end “‘

In RSpec tests:

“‘ruby expect(MyService).to have_service_input(:name)

.type(String)
.required
.inclusion(%w[admin user])

“‘

## Architecture

Works with:

  • SubmatcherRegistry - provides DSL for registering submatchers

  • SubmatcherContext - carries context data to submatchers

  • Submatcher - base class for individual validation rules

## Features

  • **Fluent API** - chain methods for readable test assertions

  • **Dynamic Chain Methods** - generated from submatcher registry

  • **Mutual Exclusivity** - conflicting options replace each other

  • Composable - works with RSpec’s compound matchers

  • **Block Expectations** - supports ‘expect { }.to` syntax

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from SubmatcherRegistry

included

Constructor Details

#initialize(described_class, attribute_name) ⇒ AttributeMatcher

Creates a new attribute matcher instance.

Parameters:

  • described_class (Class)

    The Servactory service class to test

  • attribute_name (Symbol)

    The name of the attribute to validate



83
84
85
86
87
88
89
90
91
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 83

def initialize(described_class, attribute_name)
  @described_class = described_class
  @attribute_name = attribute_name
  @submatchers = []
  @option_types = nil
  @last_submatcher = nil

  build_chain_methods_from_registry
end

Class Attribute Details

.attribute_typeSymbol (readonly)

Returns The attribute type this matcher validates (:input, :internal, :output).

Returns:

  • (Symbol)

    The attribute type this matcher validates (:input, :internal, :output)



59
60
61
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 59

def attribute_type
  @attribute_type
end

Instance Attribute Details

#attribute_nameSymbol (readonly)

Returns The name of the attribute being validated.

Returns:

  • (Symbol)

    The name of the attribute being validated



74
75
76
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 74

def attribute_name
  @attribute_name
end

#described_classClass (readonly)

Returns The Servactory service class being tested.

Returns:

  • (Class)

    The Servactory service class being tested



71
72
73
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 71

def described_class
  @described_class
end

#option_typesArray? (readonly)

Returns Type classes passed to the types chain method.

Returns:

  • (Array, nil)

    Type classes passed to the types chain method



77
78
79
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 77

def option_types
  @option_types
end

Class Method Details

.for_attribute_type(type) ⇒ void

This method returns an undefined value.

Sets the attribute type for this matcher class.

Parameters:

  • type (Symbol)

    The attribute type (:input, :internal, :output)



65
66
67
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 65

def for_attribute_type(type)
  @attribute_type = type
end

Instance Method Details

#descriptionString

Builds a human-readable description of what this matcher validates.

Returns:

  • (String)

    Description including attribute name and all submatcher descriptions



114
115
116
117
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 114

def description
  submatcher_descriptions = submatchers.map(&:description).join(", ")
  "#{attribute_name} with #{submatcher_descriptions}"
end

#failure_messageString

Builds the failure message when the matcher does not pass.

Returns:

  • (String)

    Explanation of what was expected and what was missing



122
123
124
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 122

def failure_message
  "Expected #{expectation}, which #{missing_options}"
end

#failure_message_when_negatedString

Builds the failure message for negated expectations.

Returns:

  • (String)

    Explanation for negated expectation failure



129
130
131
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 129

def failure_message_when_negated
  "Did not expect #{expectation} with specified options"
end

#matches?(subject) ⇒ Boolean

Checks if all submatchers pass for the given subject.

Parameters:

  • subject (Object)

    The RSpec subject (typically nil for service class matchers)

Returns:

  • (Boolean)

    True if all submatchers pass, false otherwise



106
107
108
109
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 106

def matches?(subject)
  @subject = subject
  failing_submatchers.empty?
end

#supports_block_expectations?Boolean

Indicates this matcher supports block expectations.

Required by RSpec for matchers used with ‘expect { }.to` syntax.

Returns:

  • (Boolean)

    Always returns true



98
99
100
# File 'lib/servactory/test_kit/rspec/matchers/base/attribute_matcher.rb', line 98

def supports_block_expectations?
  true
end