From 66578bd45c20a1525e71a10e53473053bda89dd0 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Sun, 18 Oct 2026 15:41:36 +1300 Subject: [PATCH] Remove installed dependency context from version control. --- .context/agent-context/index.yaml | 13 - .context/agent-context/usage.md | 173 ------------ .context/decode/coverage.md | 325 ---------------------- .context/decode/getting-started.md | 242 ---------------- .context/decode/index.yaml | 22 -- .context/decode/ruby-documentation.md | 363 ------------------------ .context/sus/index.yaml | 21 -- .context/sus/mocking.md | 95 ------- .context/sus/shared.md | 185 ------------- .context/sus/usage.md | 380 -------------------------- agent.md | 47 ---- 11 files changed, 1866 deletions(-) delete mode 100644 .context/agent-context/index.yaml delete mode 100644 .context/agent-context/usage.md delete mode 100644 .context/decode/coverage.md delete mode 100644 .context/decode/getting-started.md delete mode 100644 .context/decode/index.yaml delete mode 100644 .context/decode/ruby-documentation.md delete mode 100644 .context/sus/index.yaml delete mode 100644 .context/sus/mocking.md delete mode 100644 .context/sus/shared.md delete mode 100644 .context/sus/usage.md delete mode 100644 agent.md diff --git a/.context/agent-context/index.yaml b/.context/agent-context/index.yaml deleted file mode 100644 index 183e4ee6..00000000 --- a/.context/agent-context/index.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -description: Install and manage context files from Ruby gems. -version: 0.1.3 -metadata: - documentation_uri: https://ioquatix.github.io/agent-context/ - funding_uri: https://github.com/sponsors/ioquatix/ - source_code_uri: https://github.com/ioquatix/agent-context.git -files: -- path: usage.md - title: Usage Guide - description: "`agent-context` is a tool that helps you discover and install contextual - information from Ruby gems for AI agents. Gems can provide additional documentation, - examples, and guidance in a `context/` ..." diff --git a/.context/agent-context/usage.md b/.context/agent-context/usage.md deleted file mode 100644 index 1d673f6d..00000000 --- a/.context/agent-context/usage.md +++ /dev/null @@ -1,173 +0,0 @@ -# Usage Guide - -## What is agent-context? - -`agent-context` is a tool that helps you discover and install contextual information from Ruby gems for AI agents. Gems can provide additional documentation, examples, and guidance in a `context/` directory. - -## Quick Commands - -```bash -# See what context is available -bake agent:context:list - -# Install all available context -bake agent:context:install - -# Install context from a specific gem -bake agent:context:install --gem async - -# See what context files a gem provides -bake agent:context:list --gem async - -# View a specific context file -bake agent:context:show --gem async --file thread-safety -``` - -## Understanding context/ vs .context/ - -**Important distinction:** -- **`context/`** (no dot) = Directory in gems that contains context files to share. -- **`.context/`** (with dot) = Directory in your project where context gets installed. - -### What happens when you install context? - -When you run `bake agent:context:install`, the tool: - -1. Scans all installed gems for `context/` directories (in the gem's root). -2. Creates a `.context/` directory in your current project. -3. Copies context files organized by gem name. - -For example: -``` -your-project/ -├── .context/ # ← Installed context (with dot) -│ ├── async/ # ← From the 'async' gem's context/ directory -│ │ ├── thread-safety.md -│ │ └── performance.md -│ └── rack/ # ← From the 'rack' gem's context/ directory -│ └── middleware.md -├── lib/ -└── Gemfile -``` - -Meanwhile, in the gems themselves: -``` -async-gem/ -├── context/ # ← Source context (no dot) -│ ├── thread-safety.md -│ └── performance.md -├── lib/ -└── async.gemspec -``` - -## Using Context (For Gem Users) - -### Why use this? - -- **Discover hidden documentation** that gems provide. -- **Get practical examples** and guidance. -- **Understand best practices** from gem authors. -- **Access migration guides** and troubleshooting tips. - -### Key Points for Users - -- Run `bake agent:context:install` to copy context to `.context/` (with dot). -- The `.context/` directory is where installed context lives in your project. -- Don't edit files in `.context/` - they get completely replaced when you reinstall. - -## Providing Context (For Gem Authors) - -### How to provide context in your gem - -#### 1. Create a `context/` directory - -In your gem's root directory, create a `context/` folder (no dot): - -``` -your-gem/ -├── context/ # ← Source context (no dot) - this is what you create -│ ├── getting-started.md -│ ├── configuration.md -│ └── troubleshooting.md -├── lib/ -└── your-gem.gemspec -``` - -**Important:** This is different from `.context/` (with dot) which is where context gets installed in user projects. - -#### 2. Add context files - -Create files with helpful information for users of your gem. Common types include: - -- **getting-started.md** - Quick start guide for using your gem. -- **configuration.md** - Configuration options and examples. -- **troubleshooting.md** - Common issues and solutions. -- **migration.md** - Migration guides between versions. -- **performance.md** - Performance tips and best practices. -- **security.md** - Security considerations. - -**Focus on the agent experience:** These files should help AI agents understand how to use your gem effectively, not document your gem's internal APIs. - -#### 3. Document your context - -Add a section to your gem's README: - -```markdown -## Context - -This gem provides additional context files that can be installed using `bake agent:context:install`. - -Available context files: -- `getting-started.md` - Quick start guide. -- `configuration.md` - Configuration options. -- `troubleshooting.md` - Common issues and solutions. -``` - -#### 4. File format and content guidelines - -Context files can be in any format, but `.md` is commonly used for documentation. The content should be: - -- **Practical** - Include real examples and working code. -- **Focused** - One topic per file. -- **Clear** - Easy to understand and follow. -- **Actionable** - Provide specific guidance and next steps. -- **Agent-focused** - Help AI agents understand how to use your gem effectively. - -### Key Points for Gem Authors - -- Create a `context/` directory (no dot) in your gem's root. -- Put helpful guides for users of your gem there. -- Focus on practical usage, not API documentation. - -## Example Context Files - -For examples of well-structured context files, see the existing files in this directory: -- `usage.md` - Shows how to use the tool (this file). -- `examples.md` - Demonstrates practical usage scenarios. - -## Key Differences from API Documentation - -Context files are NOT the same as API documentation: - -- **Context files**: Help agents accomplish tasks ("How do I configure authentication?"). -- **API documentation**: Document methods and classes ("Method `authenticate` returns Boolean"). - -Context files should answer questions like: -- "How do I get started?". -- "How do I configure this for production?". -- "What do I do when X goes wrong?". -- "How do I migrate from version Y to Z?". - -## Testing Your Context - -Before publishing, test your context files: - -1. Have an AI agent try to follow your getting-started guide. -2. Check that all code examples actually work. -3. Ensure the files are focused and don't try to cover too much. -4. Verify that they complement rather than duplicate your main documentation. - -## Summary - -- **`context/`** = source (in gems). -- **`.context/`** = destination (in your project). diff --git a/.context/decode/coverage.md b/.context/decode/coverage.md deleted file mode 100644 index c81f0e8f..00000000 --- a/.context/decode/coverage.md +++ /dev/null @@ -1,325 +0,0 @@ -# Documentation Coverage - -This guide explains how to test and monitor documentation coverage in your Ruby projects using the Decode gem's built-in bake tasks. - -## Available Bake Tasks - -The Decode gem provides several bake tasks for analyzing your codebase: - -- `bake decode:index:coverage` - Check documentation coverage. -- `bake decode:index:symbols` - List all symbols in the codebase. -- `bake decode:index:documentation` - Extract all documentation. - -## Checking Documentation Coverage - -### Basic Coverage Check - -```bash -# Check coverage for the lib directory: -bake decode:index:coverage lib - -# Check coverage for a specific directory: -bake decode:index:coverage app/models -``` - -### Understanding Coverage Output - -When you run the coverage command, you'll see output like: - -``` -15 definitions have documentation, out of 20 public definitions. - -Missing documentation for: -- MyGem::SomeClass#method_name -- MyGem::AnotherClass -- MyGem::Utility.helper_method -``` - -The coverage check: -- **Counts only public definitions** (public methods, classes, modules). -- **Reports the ratio** of documented vs total public definitions. -- **Lists missing documentation** by qualified name. -- **Fails with an error** if coverage is incomplete. - -### What Counts as "Documented" - -A definition is considered documented if it has: -- Any comment preceding it. -- Documentation pragmas (like `@parameter`, `@returns`). -- A `@namespace` pragma (for organizational modules). - -```ruby -# Represents a user in the system. -class MyClass -end - -# @namespace -module OrganizationalModule - # Contains helper functionality. -end - -# Process user data and return formatted results. -# @parameter name [String] The user's name. -# @returns [Boolean] Success status. -def process(name) - # Validation logic here: - return false if name.empty? - - # Processing logic: - true -end - -class UndocumentedClass -end -``` - -## Analyzing Symbols - -### List All Symbols - -```bash -# See the structure of your codebase -bake decode:index:symbols lib -``` - -This shows the hierarchical structure of your code: - -``` -[] -> [] -["MyGem"] -> [#] - MyGem -["MyGem", "User"] -> [#] - MyGem::User -["MyGem", "User", "initialize"] -> [#] - MyGem::User#initialize -``` - -### Extract Documentation - -```bash -# Extract all documentation from your codebase -bake decode:index:documentation lib -``` - -This outputs formatted documentation for all documented definitions: - -~~~markdown -## `MyGem::User#initialize` - -Initialize a new user with the given email address. - -## `MyGem::User#authenticate` - -Authenticate the user with a password. -Returns true if authentication is successful. -~~~ - -## Achieving 100% Coverage - -### Strategy for Complete Coverage - -1. **Document all public APIs** - ```ruby - # Represents a user management system. - class User - # @attribute [String] The user's email address. - attr_reader :email - - # Initialize a new user. - # @parameter email [String] The user's email address. - def initialize(email) - # Store the email address: - @email = email - end - end - ``` - -2. **Use @namespace for organizational modules** - ```ruby - # @namespace - module MyGem - # Contains the main functionality. - end - ``` - -3. **Document edge cases** - ```ruby - # @private - def internal_helper - # Internal implementation details. - end - ``` - -### Common Coverage Issues - -**Issue: Missing namespace documentation** -```ruby -# This module has no documentation and will show as missing coverage: -module MyGem -end - -# Solution: Add @namespace pragma: -# @namespace -module MyGem - # Provides core functionality. -end -``` - -**Issue: Undocumented methods** - -Problem: Methods without any comments will show as missing coverage: -```ruby -def process_data - # Implementation here -end -``` - -Solution: Add description and pragmas: -```ruby -# Process the input data and return results. -# @parameter data [Hash] Input data to process. -# @returns [Array] Processed results. -def process_data(data) - # Process the input: - results = data.map { |item| transform(item) } - - # Return processed results: - results -end -``` - -**Issue: Missing attr documentation** - -Problem: Attributes without documentation will show as missing coverage: -```ruby -attr_reader :name -``` - -Solution: Document with @attribute pragma: -```ruby -# @attribute [String] The user's full name. -attr_reader :name -``` - -## Integrating into CI/CD - -### GitHub Actions Example - -```yaml -name: Documentation Coverage - -on: [push, pull_request] - -jobs: - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true - - name: Check documentation coverage - run: bake decode:index:coverage lib -``` - -### Rake Task Integration - -Add to your `Rakefile`: - -```ruby -require 'decode' - -desc "Check documentation coverage" -task :doc_coverage do - system("bake decode:index:coverage lib") || exit(1) -end - -task default: [:test, :doc_coverage] -``` - -## Monitoring Coverage Over Time - -### Generate Coverage Reports - -```ruby -# Generate a coverage percentage for the specified directory. -# @parameter root [String] The root directory to analyze. -# @returns [Float] The coverage percentage. -def coverage_percentage(root) - index = Decode::Index.new - index.update(Dir.glob(File.join(root, "**/*.rb"))) - - documented = 0 - total = 0 - - index.trie.traverse do |path, node, descend| - node.values&.each do |definition| - if definition.public? - total += 1 - documented += 1 if definition.comments&.any? - end - end - descend.call if node.values.nil? - end - - (documented.to_f / total * 100).round(2) -end - -puts "Coverage: #{coverage_percentage('lib')}%" -``` - -### Exclude Patterns - -If you need to exclude certain files from coverage: - -```ruby -# Custom coverage script with exclusions. -paths = Dir.glob("lib/**/*.rb").reject do |path| - # Exclude vendor files and test files: - path.include?('vendor/') || path.end_with?('_test.rb') -end - -index = Decode::Index.new -index.update(paths) -# ... continue with coverage analysis -``` - -## Best Practices - -1. **Run coverage checks regularly** - Include in your CI pipeline -2. **Set coverage targets** - Aim for 100% coverage of public APIs -3. **Document incrementally** - Add documentation as you write code -4. **Use meaningful descriptions** - Don't just add empty comments -5. **Leverage @namespace** - For modules that only serve as containers -6. **Review coverage reports** - Use the missing documentation list to prioritize - -## Troubleshooting - -### Common Error Messages - -**"Insufficient documentation!"** -- Some public definitions are missing documentation -- Check the list of missing items and add appropriate comments - -**No output from coverage command** -- Verify the path exists: `bake decode:index:coverage lib` -- Check that Ruby files exist in the specified directory - -**Coverage shows 0/0 definitions** -- The directory might not contain any Ruby files -- Try a different path or check your file extensions - -### Debug Coverage Issues - -```bash -# First, see what symbols are being detected -bake decode:index:symbols lib - -# Then check what documentation exists -bake decode:index:documentation lib - -# Finally, run coverage to see what's missing -bake decode:index:coverage lib -``` - -This workflow helps you understand what the tool is detecting and why certain items might be missing documentation. diff --git a/.context/decode/getting-started.md b/.context/decode/getting-started.md deleted file mode 100644 index a73f8bbc..00000000 --- a/.context/decode/getting-started.md +++ /dev/null @@ -1,242 +0,0 @@ -# Getting Started with Decode - -The Decode gem provides programmatic access to Ruby code structure and metadata. It can parse Ruby files and extract definitions, comments, and documentation pragmas, enabling code analysis, documentation generation, and other programmatic manipulations of Ruby codebases. - -## Installation - -Add to your Gemfile: - -```ruby -gem 'decode' -``` - -Or install directly: - -```bash -bundle add decode -``` - -## Basic Usage - -### Analyzing a Ruby File - -```ruby -require 'decode' - -# Create a source object: -source = Decode::Source.new('lib/my_class.rb', Decode::Language::Ruby.new) - -# Extract definitions (classes, methods, etc.): -definitions = source.definitions.to_a - -definitions.each do |definition| - puts "#{definition.name}: #{definition.short_form}" -end -``` - -### Extracting Documentation - -```ruby -# Get segments (blocks of comments + code): -segments = source.segments.to_a - -segments.each do |segment| - puts "Comments: #{segment.comments.join(' ')}" - puts "Code: #{segment.code}" -end -``` - -### Checking Documentation Coverage - -```ruby -# Check which definitions have documentation: -definitions.each do |definition| - status = definition.comments.any? ? 'documented' : 'missing docs' - puts "#{definition.name}: #{status}" -end -``` - -## Working with Documentation Pragmas - -The Decode gem understands structured documentation pragmas: - -```ruby -# This will be parsed and structured: -source_code = <<~RUBY - # Represents a user in the system. - class User - # @attribute [String] The user's email address. - attr_reader :email - - # Initialize a new user. - # @parameter email [String] The user's email address. - # @parameter options [Hash] Additional options. - # @option :active [Boolean] Whether the account is active. - # @raises [ArgumentError] If email is invalid. - def initialize(email, options = {}) - # Validate the email format: - raise ArgumentError, "Invalid email" if email.empty? - - # Set instance variables: - @email = email - @active = options.fetch(:active, true) - end - end -RUBY - -# Parse and analyze: -result = Decode::Language::Ruby.new.parser.parse_source(source_code) -definitions = Decode::Language::Ruby.new.parser.definitions_for(source_code).to_a - -definitions.each do |definition| - puts "#{definition.name}: #{definition.comments.join(' ')}" -end -``` - -## Common Use Cases - -### 1. Code Analysis and Metrics - -```ruby -# Analyze a codebase and return metrics. -# @parameter file_path [String] Path to the Ruby file to analyze. -def analyze_codebase(file_path) - source = Decode::Source.new(file_path, Decode::Language::Ruby.new) - definitions = source.definitions.to_a - - # Count different definition types: - classes = definitions.count { |d| d.is_a?(Decode::Language::Ruby::Class) } - methods = definitions.count { |d| d.is_a?(Decode::Language::Ruby::Method) } - modules = definitions.count { |d| d.is_a?(Decode::Language::Ruby::Module) } - - puts "Classes: #{classes}, Methods: #{methods}, Modules: #{modules}" -end -``` - -### 2. Documentation Coverage Reports - -```ruby -# Calculate documentation coverage for a file. -# @parameter file_path [String] Path to the Ruby file to analyze. -def documentation_coverage(file_path) - source = Decode::Source.new(file_path, Decode::Language::Ruby.new) - definitions = source.definitions.to_a - - # Calculate coverage statistics: - total = definitions.count - documented = definitions.count { |d| d.comments.any? } - - puts "Coverage: #{documented}/#{total} (#{(documented.to_f / total * 100).round(1)}%)" -end -``` - -### 3. Extracting API Information - -```ruby -# Extract API information from a Ruby file. -# @parameter file_path [String] Path to the Ruby file to analyze. -def extract_api_info(file_path) - source = Decode::Source.new(file_path, Decode::Language::Ruby.new) - definitions = source.definitions.to_a - - # Get public methods only: - public_methods = definitions.select do |definition| - definition.is_a?(Decode::Language::Ruby::Method) && - definition.visibility == :public - end - - public_methods.each do |method| - puts "#{method.long_form}" - puts " Comments: #{method.comments.join(' ')}" if method.comments.any? - end -end -``` - -### 4. Code Structure Analysis - -```ruby -# Analyze the structure of Ruby files in a directory. -# @parameter directory [String] Path to the directory to analyze. -def analyze_structure(directory) - Dir.glob("#{directory}/**/*.rb").each do |file| - source = Decode::Source.new(file, Decode::Language::Ruby.new) - definitions = source.definitions.to_a - - # Find nested classes and modules: - nested = definitions.select { |d| d.parent } - - if nested.any? - puts "#{file}:" - nested.each do |definition| - puts " #{definition.qualified_name}" - end - end - end -end -``` - -### 5. Finding Undocumented Code - -```ruby -# Find undocumented code in a directory. -# @parameter directory [String] Path to the directory to analyze. -def find_undocumented(directory) - Dir.glob("#{directory}/**/*.rb").each do |file| - source = Decode::Source.new(file, Decode::Language::Ruby.new) - definitions = source.definitions.to_a - - # Filter for undocumented public definitions: - undocumented = definitions.select { |d| d.comments.empty? && d.visibility == :public } - - if undocumented.any? - puts "#{file}:" - undocumented.each do |definition| - puts " - #{definition.short_form}" - end - end - end -end -``` - -## Advanced Features - -### Using the Index - -```ruby -# Create an index for multiple files: -index = Decode::Index.new -index.update(Dir.glob("lib/**/*.rb")) - -# Search through the index: -index.trie.traverse do |path, node, descend| - if node.values - node.values.each do |definition| - puts "#{path.join('::')} - #{definition.short_form}" - end - end - descend.call -end -``` - -### Custom Language Support - -```ruby -# The decode gem is extensible: -language = Decode::Language::Generic.new("custom") -# You can implement your own parser for other languages: -``` - -## Tips for Effective Usage - -1. **Use structured pragmas** - They help tools understand your code better. -2. **Leverage programmatic access** - Build tools that analyze and manipulate code. -3. **Use @namespace** - For organizational modules to achieve complete coverage. -4. **Analyze code patterns** - Use decode to understand codebase structure. -5. **Build automation** - Use decode in CI/CD pipelines for code quality checks. - -## Next Steps - -- See [Ruby Documentation](ruby-documentation.md) for complete pragma reference. -- Check out [Documentation Coverage](coverage.md) for coverage monitoring. -- Use decode to build code analysis tools for your projects. -- Integrate decode into your development workflow and CI/CD pipelines. diff --git a/.context/decode/index.yaml b/.context/decode/index.yaml deleted file mode 100644 index d9df0844..00000000 --- a/.context/decode/index.yaml +++ /dev/null @@ -1,22 +0,0 @@ ---- -description: Code analysis for documentation generation. -version: 0.23.3 -metadata: - documentation_uri: https://ioquatix.github.io/decode/ - funding_uri: https://github.com/sponsors/ioquatix/ - source_code_uri: https://github.com/ioquatix/decode.git -files: -- path: getting-started.md - title: Getting Started with Decode - description: The Decode gem provides programmatic access to Ruby code structure - and metadata. It can parse Ruby files and extract definitions, comments, and documentation - pragmas, enabling code analysis, docume... -- path: coverage.md - title: Documentation Coverage - description: This guide explains how to test and monitor documentation coverage - in your Ruby projects using the Decode gem's built-in bake tasks. -- path: ruby-documentation.md - title: Ruby Documentation - description: This guide covers documentation practices and pragmas supported by - the Decode gem for documenting Ruby code. These pragmas provide structured documentation - that can be parsed and used to generate A... diff --git a/.context/decode/ruby-documentation.md b/.context/decode/ruby-documentation.md deleted file mode 100644 index 61f14969..00000000 --- a/.context/decode/ruby-documentation.md +++ /dev/null @@ -1,363 +0,0 @@ -# Ruby Documentation - -This guide covers documentation practices and pragmas supported by the Decode gem for documenting Ruby code. These pragmas provide structured documentation that can be parsed and used to generate API documentation and achieve complete documentation coverage. - -## Documentation Guidelines - -### Writing Style and Format - -#### Definition Documentation - -- **Full sentences**: All documentation for definitions (classes, modules, methods) should be written as complete sentences with proper grammar and punctuation. -- **Class documentation**: Documentation for classes should generally start with "Represents a ..." to clearly indicate what the class models or encapsulates. -- **Method documentation**: Should clearly describe what the method does, not how it does it. -- **Markdown format**: All documentation comments are written in Markdown format, allowing for rich formatting including lists, emphasis, code blocks, and links. - -#### Inline Code Comments - -- **Explanatory comments**: Comments within methods that explain specific lines or sections of code should end with a colon `:` to distinguish them from definition documentation. -- **Purpose**: These comments explain the reasoning behind specific implementation details. - -#### Links and Code Formatting - -- **Curly braces `{}`**: Use curly braces to create links to other methods, classes, or modules. The Decode gem uses `@index.lookup(text)` to resolve these references. - - **Absolute references**: `{Decode::Index#lookup}` - Links to a specific method in a specific class - - **Relative references**: `{lookup}` - Links to a method in the current scope or class - - **Class references**: `{User}` - Links to a class or module -- **Backticks**: Use backticks for code formatting of symbols, values, method names, and technical terms that should appear in monospace font. - - **Symbols**: `:admin`, `:user`, `:guest` - - **Values**: `true`, `false`, `nil` - - **Technical terms**: `attr_*`, `catch`/`throw` - - **Code expressions**: `**options` - -#### Examples - -```ruby -# Represents a user account in the system. -class User - # @attribute [String] The user's email address. - attr_reader :email - - # Initialize a new user account. - # @parameter email [String] The user's email address. - # @raises [ArgumentError] If email is invalid. - def initialize(email) - # Validate email format before assignment: - raise ArgumentError, "Invalid email format" unless email.match?(/\A[^@\s]+@[^@\s]+\z/) - - # Store the normalized email: - @email = email.downcase.strip - end - - # Authenticate the user with the provided password. - # @parameter password [String] The password to verify. - # @returns [Boolean] True if authentication succeeds. - def authenticate(password) - # Hash the password for comparison: - hashed = hash_password(password) - - # Compare against stored hash: - hashed == @password_hash - end - - # Deactivate the user account. - # This method sets the user's status to inactive. Use this instead of - # the deprecated {disable!} method. The account status can be checked - # using `active?` or by examining the `:active` attribute. - # @returns [Boolean] Returns `true` if deactivation was successful. - def deactivate! - @active = false - true - end -end - -# Represents a collection of users with search capabilities. -class UserCollection - # Find users matching the given criteria. - # @parameter criteria [Hash] Search parameters. - # @returns [Array(User)] Matching users. - def find(**criteria) - # Start with all users: - results = @users.dup - - # Apply each filter criterion: - criteria.each do |key, value| - results = filter_by(results, key, value) - end - - results - end -end -``` - -**Key formatting examples from above:** -- `{disable!}` - Creates a link to the `disable!` method (relative reference) -- `active?` - Formats the method name in monospace (backticks for code formatting) -- `:active` - Formats the symbol in monospace (backticks for code formatting) -- `true` - Formats the boolean value in monospace (backticks for code formatting) - -### Best Practices - -1. **Be Consistent**: Use the same format for similar types of documentation. -2. **Include Types**: Always specify types for parameters, returns, and attributes. -3. **Be Descriptive**: Provide clear, actionable descriptions. -4. **Document Exceptions**: Always document what exceptions might be raised. -5. **Use Examples**: Include usage examples when the behavior isn't obvious. -6. **Keep Updated**: Update documentation when you change the code. -7. **Use @namespace wisely**: Apply to organizational modules to achieve 100% coverage. -8. **Avoid redundancy**: For simple attributes and methods, attach descriptions directly to pragmas rather than repeating obvious information. - -#### Simple Attributes and Methods - -For extremely simple attributes and methods where the name clearly indicates the purpose, avoid redundant descriptions. Instead, attach the description directly to the `@attribute` pragma: - -```ruby -# Good - concise and clear: -# @attribute [String] The name of the parameter. -attr :name - -# @attribute [String] The type of the parameter. -attr :type - -# Avoid - redundant descriptions: -# The name of the parameter. -# @attribute [String] The parameter name. -attr :name -``` - -This approach keeps documentation concise while still providing essential type information. - -## Type Signatures - -Type signatures are used to specify the expected types of parameters, return values, and attributes in Ruby code. They help clarify the intended use of methods and improve code readability. - -### Primitive Types - -- `String`: Represents a sequence of characters. -- `Integer`: Represents whole numbers. -- `Float`: Represents decimal numbers. -- `Boolean`: Represents true or false values. -- `Symbol`: Represents a name or identifier. - -### Composite Types - -- `Array(Type)`: Represents an ordered collection of items. -- `Hash(KeyType, ValueType)`: Represents a collection of key-value pairs. -- `Interface(:method1, :method2)`: Represents a contract that a class must implement, specifying required methods. -- `Type | Nil`: Represents an optional type. - -## Supported Pragmas - -### Type and Return Value Documentation - -#### `@attribute [Type] Description.` - -Documents class attributes, instance variables, and `attr_*` declarations. Prefer to have one attribute per line for clarity. - -```ruby -# Represents a person with basic attributes. -class Person - # @attribute [String] The person's full name. - attr_reader :name - - # @attribute [Integer] The person's age in years. - attr_accessor :age - - # @attribute [Hash] Configuration settings. - attr_writer :config -end -``` - -#### `@parameter name [Type] Description.` - -Documents method parameters with their types and descriptions. - -```ruby -# @parameter x [Integer] The x coordinate. -# @parameter y [Integer] The y coordinate. -# @parameter options [Hash] Optional configuration. -def move(x, y, **options) - # ... -end -``` - -#### `@option :key [Type] Description.` - -Documents hash options (keyword arguments). - -```ruby -# @parameter user [User] The user object. -# @option :cached [Boolean] Whether to cache the result. -# @option :timeout [Integer] Request timeout in seconds. -def fetch_user_data(user, **options) - # ... -end -``` - -#### `@returns [Type] Description.` - -Documents return values. - -```ruby -# @returns [String] The formatted user name. -def full_name - "#{first_name} #{last_name}" -end - -# @returns [Array(User)] All active users. -def active_users - users.select(&:active?) -end -``` - -#### `@raises [Exception] Description.` - -Documents exceptions that may be raised. - -```ruby -# @parameter age [Integer] The person's age. -# @raises [ArgumentError] If age is negative. -# @raises [TypeError] If age is not an integer. -def set_age(age) - raise ArgumentError, "Age cannot be negative" if age < 0 - raise TypeError, "Age must be an integer" unless age.is_a?(Integer) - @age = age -end -``` - -#### `@throws [:symbol] Description.` - -Documents symbols that may be thrown (used with `catch`/`throw`). - -```ruby -# @throws [:skip] To skip processing this item. -# @throws [:retry] To retry the operation. -def process_item(item) - throw :skip if item.nil? - throw :retry if item.invalid? - # ... -end -``` - -### Block Documentation - -#### `@yields {|param| ...} Description.` - -Documents block parameters and behavior. - -```ruby -# @yields {|item| ...} Each item in the collection. -# @parameter item [Object] The current item being processed. -def each_item(&block) - items.each(&block) -end - -# @yields {|user, index| ...} User and their index. -# @parameter user [User] The current user. -# @parameter index [Integer] The user's position in the list. -def each_user_with_index(&block) - users.each_with_index(&block) -end -``` - -### Visibility and Access Control - -#### `@public` - -Explicitly marks a method as public (useful for documentation clarity). - -```ruby -# @public -def public_method - # This method is part of the public API. -end -``` - -#### `@private` - -Marks a method as private (for documentation purposes). - -```ruby -# @private -def internal_helper - # This method is for internal use only. -end -``` - -### Behavioral Documentation - -#### `@deprecated Description.` - -Marks methods as deprecated with migration guidance. - -```ruby -# @deprecated Use {new_method} instead. -def old_method - # Legacy implementation -end -``` - -#### `@asynchronous` - -Indicates that a method may yield control. - -```ruby -# @asynchronous -def fetch_data - # This method may yield control during execution. -end -``` - -### Namespace Documentation - -#### `@namespace` - -Marks a module as serving only as a namespace, achieving 100% documentation coverage without requiring detailed documentation of empty container modules. - -```ruby -# @namespace -module MyGem - # This module serves only as a namespace for organizing classes. - - class ActualImplementation - # This class contains the real functionality. - end -end -``` - -**Why use `@namespace`?** -- Achieves 100% documentation coverage without redundant documentation. -- Clearly indicates that a module is purely organizational. -- Avoids documenting modules that exist only to group related classes. -- Maintains clean, focused documentation on actual functionality. - -**When to use `@namespace`:** -- Root gem modules that only contain other classes/modules. -- Organizational modules with no methods or meaningful state. -- Modules that exist purely for constant scoping. -- Any module where documentation would add no value. - -**Note:** This pragma is treated as a form of documentation by the Decode gem, satisfying coverage requirements while keeping the codebase clean. - -## Special Pragmas for Code Structure - -### `@name custom_name` - -Overrides the default name extraction for attributes or methods. - -```ruby -# @name hostname -# @attribute [String] The server hostname. -attr_reader :server_name -``` - -### `@scope Module::Name` - -Defines scope for definitions that should be associated with a specific module. - -```ruby -# @scope Database -def connect - # This method belongs to the Database scope. -end -``` diff --git a/.context/sus/index.yaml b/.context/sus/index.yaml deleted file mode 100644 index 51214065..00000000 --- a/.context/sus/index.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -description: A fast and scalable test runner. -version: 0.33.1 -metadata: - documentation_uri: https://socketry.github.io/sus/ - funding_uri: https://github.com/sponsors/ioquatix/ - source_code_uri: https://github.com/socketry/sus.git -files: -- path: usage.md - title: Using Sus Testing Framework - description: Sus is a modern Ruby testing framework that provides a clean, BDD-style - syntax for writing tests. It's designed to be fast, simple, and expressive. -- path: mocking.md - title: Mocking - description: 'There are two types of mocking in sus: `receive` and `mock`. The `receive` - matcher is a subset of full mocking and is used to set expectations on method - calls, while `mock` can be used to replace m...' -- path: shared.md - title: Shared Test Behaviors and Fixtures - description: Sus provides shared test contexts which can be used to define common - behaviours or tests that can be reused across one or more test files. diff --git a/.context/sus/mocking.md b/.context/sus/mocking.md deleted file mode 100644 index 432bdd7c..00000000 --- a/.context/sus/mocking.md +++ /dev/null @@ -1,95 +0,0 @@ -# Mocking - -There are two types of mocking in sus: `receive` and `mock`. The `receive` matcher is a subset of full mocking and is used to set expectations on method calls, while `mock` can be used to replace method implementations or set up more complex behavior. - -Mocking non-local objects permanently changes the object's ancestors, so it should be used with care. For local objects, you can use `let` to define the object and then mock it. - -Sus does not support the concept of test doubles, but you can use `receive` and `mock` to achieve similar functionality. - -## Method Call Expectations - -The `receive(:method)` expectation is used to set up an expectation that a method will be called on an object. You can also specify arguments and return values. However, `receive` is not sequenced, meaning it does not enforce the order of method calls. If you need to enforce the order, use `mock` instead. - -```ruby -describe MyThing do - let(:my_thing) {subject.new} - - it "calls the expected method" do - expect(my_thing).to receive(:my_method) - - expect(my_thing.my_method).to be == 42 - end -end -``` - -### With Arguments - -```ruby -it "calls the method with arguments" do - expect(object).to receive(:method_name).with(arg1, arg2) - # or .with_arguments(be == [arg1, arg2]) - # or .with_options(be == {option1: value1, option2: value2}) - # or .with_block - - object.method_name(arg1, arg2) -end -``` - -### Returning Values - -```ruby -it "returns a value" do - expect(object).to receive(:method_name).and_return("expected value") - result = object.method_name - expect(result).to be == "expected value" -end -``` - -### Raising Exceptions - -```ruby -it "raises an exception" do - expect(object).to receive(:method_name).and_raise(StandardError, "error message") - - expect{object.method_name}.to raise_exception(StandardError, message: "error message") -end -``` - -### Multiple Calls - -```ruby -it "calls the method multiple times" do - expect(object).to receive(:method_name).twice.and_return("result") - # or .with_call_count(be == 2) - expect(object.method_name).to be == "result" - expect(object.method_name).to be == "result" -end -``` - -## Mock Objects - -Mock objects are used to replace method implementations or set up complex behavior. They can be used to intercept method calls, modify arguments, and control the flow of execution. They are thread-local, meaning they only affect the current thread, therefore are not suitable for use in tests that have multiple threads. - -```ruby -describe ApiClient do - let(:http_client) {Object.new} - let(:client) {ApiClient.new(http_client)} - let(:users) {["Alice", "Bob"]} - - it "makes GET requests" do - mock(http_client) do |mock| - mock.replace(:get) do |url, headers: {}| - expect(url).to be == "/api/users" - expect(headers).to be == {"accept" => "application/json"} - users.to_json - end - - # or mock.before {|...| ...} - # or mock.after {|...| ...} - # or mock.wrap(:new) {|original, ...| original.call(...)} - end - - expect(client.fetch_users).to be == users - end -end -``` diff --git a/.context/sus/shared.md b/.context/sus/shared.md deleted file mode 100644 index 701f71b5..00000000 --- a/.context/sus/shared.md +++ /dev/null @@ -1,185 +0,0 @@ -# Shared Test Behaviors and Fixtures - -## Overview - -Sus provides shared test contexts which can be used to define common behaviours or tests that can be reused across one or more test files. - -When you have common test behaviors that you want to apply to multiple test files, add them to the `fixtures/` directory. When you have common test behaviors that you want to apply to multiple implementations of the same interface, within a single test file, you can define them as shared contexts within that file. - -## Shared Fixtures - -### Directory Structure - -``` -my-gem/ -├── lib/ -│ ├── my_gem.rb -│ └── my_gem/ -│ └── my_thing.rb -├── fixtures/ -│ └── my_gem/ -│ └── a_thing.rb # Provides MyGem::AThing shared context -└── test/ - ├── my_gem.rb - └── my_gem/ - └── my_thing.rb -``` - -### Creating Shared Fixtures - -Create shared behaviors in the `fixtures/` directory using `Sus::Shared`: - -```ruby -# fixtures/my_gem/a_user.rb - -require "sus/shared" - -module MyGem - AUser = Sus::Shared("a user") do |role| - let(:user) do - { - name: "Test User", - email: "test@example.com", - role: role - } - end - - it "has a name" do - expect(user[:name]).not.to be_nil - end - - it "has a valid email" do - expect(user[:email]).to be(:include?, "@") - end - - it "has a role" do - expect(user[:role]).to be_a(String) - end - end -end -``` - -### Using Shared Fixtures - -Require and use shared fixtures in your test files: - -```ruby -# test/my_gem/user_manager.rb -require 'my_gem/a_user' - -describe MyGem::UserManager do - it_behaves_like MyGem::AUser, "manager" - # or include_context MyGem::AUser, "manager" -end -``` - -### Multiple Shared Fixtures - -You can create multiple shared fixtures for different scenarios: - -```ruby -# fixtures/my_gem/users.rb -module MyGem - module Users - AStandardUser = Sus::Shared("a standard user") do - let(:user) do - { name: "John Doe", role: "user", active: true } - end - - it "is active" do - expect(user[:active]).to be_truthy - end - end - - AnAdminUser = Sus::Shared("an admin user") do - let(:user) do - { name: "Admin User", role: "admin", active: true } - end - - it "has admin role" do - expect(user[:role]).to be == "admin" - end - end - end -end -``` - -Use specific shared fixtures: - -```ruby -# test/my_gem/authorization.rb -require 'my_gem/users' - -describe MyGem::Authorization do - with "standard user" do - # If there are no arguments, you can use `include` directly: - include MyGem::Users::AStandardUser - - it "denies admin access" do - auth = subject.new - expect(auth.can_admin?(user)).to be_falsey - end - end - - with "admin user" do - include MyGem::Users::AnAdminUser - - it "allows admin access" do - auth = subject.new - expect(auth.can_admin?(user)).to be_truthy - end - end -end -``` - -### Modules - -You can also define shared behaviors in modules and include them in your test files: - -```ruby -# fixtures/my_gem/shared_behaviors.rb -module MyGem - module SharedBehaviors - def self.included(base) - base.it "uses shared data" do - expect(shared_data).to be == "some shared data" - end - end - - def shared_data - "some shared data" - end - end -end -``` - -### Enumerating Tests - -Some tests will be run multiple times with different arguments (for example, multiple database adapters). You can use `Sus::Shared` to define these tests and then enumerate them: - -```ruby -# test/my_gem/database_adapter.rb - -require "sus/shared" - -ADatabaseAdapter = Sus::Shared("a database adapter") do |adapter| - let(:database) {adapter.new} - - it "connects to the database" do - expect(database.connect).to be_truthy - end - - it "can execute queries" do - expect(database.execute("SELECT 1")).to be == [[1]] - end -end - -# Enumerate the tests with different adapters -MyGem::DatabaseAdapters.each do |adapter| - describe "with #{adapter}", unique: adapter.name do - it_behaves_like ADatabaseAdapter, adapter - end -end -``` - -Note the use of `unique: adapter.name` to ensure each test is uniquely identified, which is useful for reporting and debugging - otherwise the same test line number would be used for all iterations, which can make it hard to identify which specific test failed. diff --git a/.context/sus/usage.md b/.context/sus/usage.md deleted file mode 100644 index d9be7578..00000000 --- a/.context/sus/usage.md +++ /dev/null @@ -1,380 +0,0 @@ -# Using Sus Testing Framework - -## Overview - -Sus is a modern Ruby testing framework that provides a clean, BDD-style syntax for writing tests. It's designed to be fast, simple, and expressive. - -## Basic Structure - -Here is an example structure for testing with Sus - the actual structure may vary based on your gem's organization, but aside from the `lib/` directory, sus expects the following structure: - -``` -my-gem/ -├── config/ -│ └── sus.rb # Sus configuration file -├── lib/ -│ ├── my_gem.rb -│ └── my_gem/ -│ └── my_thing.rb -├── fixtures/ -│ └── my_gem/ -│ └── a_thing.rb # Provides MyGem::AThing shared context -└── test/ - ├── my_gem.rb # Tests MyGem - └── my_gem/ - └── my_thing.rb # Tests MyGem::MyThing -``` - -### Configuration File - -Create `config/sus.rb`: - -```ruby -# frozen_string_literal: true - -# Use the covered gem for test coverage reporting: -require 'covered/sus' -include Covered::Sus - -def before_tests(assertions, output: self.output) - # Starts the clock and sets up the test environment: - super -end - -def after_tests(assertions, output: self.output) - # Stops the clock and prints the test results: - super -end -``` - -### Fixtures Files - -`fixtures/` gets added to the `$LOAD_PATH` automatically, so you can require files from there without needing to specify the full path. - -### Test Files - -Sus runs all Ruby files in the `test/` directory by default. But you can also create tests in any file, and run them with the `sus my_tests.rb` command. - -## Basic Syntax - -```ruby -# frozen_string_literal: true - -describe MyThing do - let(:my_thing) {subject.new} - - with "#my_method" do - it "does something" do - expect(my_thing.my_method).to be == 42 - end - end -end -``` - -### `describe` - Test Groups - -Use `describe` to group related tests: - -```ruby -describe MyThing do - # The subject will be whatever is described: - let(:my_thing) {subject.new} -end -``` - -### `it` - Individual Tests - -Use `it` to define individual test cases: - -```ruby -it "returns the expected value" do - expect(result).to be == "expected" -end -``` - -You can use `it` blocks at the top level or within `describe` or `with` blocks. - -### `with` - Context Blocks - -Use `with` to create context-specific test groups: - -```ruby -with "valid input" do - let(:input) {"valid input"} - it "succeeds" do - expect{my_thing.process(input)}.not.to raise_exception - end -end - -# Non-lazy state can be provided as keyword arguments: -with "invalid input", input: nil do - it "raises an error" do - expect{my_thing.process(input)}.to raise_exception(ArgumentError) - end -end -``` - -When testing methods, use `with` to specify the method being tested: - -```ruby -with "#my_method" do - it "results a value" do - expect(my_thing.method).to be == 42 - end -end - -with ".my_class_method" do - it "returns a value" do - expect(MyThing.class_method).to be == "class value" - end -end -``` - -### `let` - Lazy Variables - -Use `let` to define variables that are evaluated when first accessed: - -```ruby -let(:helper) {subject.new} -let(:test_data) {"test value"} - -it "uses the helper" do - expect(helper.process(test_data)).to be_truthy -end -``` - -### `before` and `after` - Setup/Teardown - -Use `before` and `after` for setup and teardown logic: - -```ruby -before do - # Setup logic. -end - -after do - # Cleanup logic. -end -``` - -Error handling in `after` allows you to perform cleanup even if the test fails with an exception (not a test failure). - -```ruby -after do |error = nil| - if error - # The state of the test is unknown, so you may want to forcefully kill processes or clean up resources. - Process.kill(:KILL, @child_pid) - else - # Normal cleanup logic. - Process.kill(:TERM, @child_pid) - end - - Process.waitpid(@child_pid) -end -``` - -### `around` - Setup/Teardown - -Use `around` for setup and teardown logic: - -```ruby -around do |&block| - # Setup logic. - super() do - # Run the test. - block.call - end -ensure - # Cleanup logic. -end -``` - -Invoking `super()` calls any parent `around` block, allowing you to chain setup and teardown logic. - -## Assertions - -### Basic Assertions - -```ruby -expect(value).to be == expected -exepct(value).to be >= 10 -expect(value).to be <= 100 -expect(value).to be > 0 -expect(value).to be < 1000 -expect(value).to be_truthy -expect(value).to be_falsey -expect(value).to be_nil -expect(value).to be_equal(another_value) -expect(value).to be_a(Class) -``` - -### Strings - -```ruby -expect(string).to be(:start_with?, "prefix") -expect(string).to be(:end_with?, "suffix") -expect(string).to be(:match?, /pattern/) -expect(string).to be(:include?, "substring") -``` - -### Ranges and Tolerance - -```ruby -expect(value).to be_within(0.1).of(5.0) -expect(value).to be_within(5).percent_of(100) -``` - -### Method Calls - -To call methods on the expected object: - -```ruby -expect(array).to be(:include?, "value") -expect(string).to be(:start_with?, "prefix") -expect(object).to be(:respond_to?, :method_name) -``` - -### Collection Assertions - -```ruby -expect(array).to have_attributes(length: be == 1) -expect(array).to have_value(be > 1) - -expect(hash).to have_keys(:key1, "key2") -expect(hash).to have_keys(key1: be == 1, "key2" => be == 2) -``` - -### Attribute Testing - -```ruby -expect(user).to have_attributes( - name: be == "John", - age: be >= 18, - email: be(:include?, "@") -) -``` - -### Exception Assertions - -```ruby -expect do - risky_operation -end.to raise_exception(RuntimeError, message: be =~ /expected error message/) -``` - -## Combining Predicates - -Predicates can be nested. - -```ruby -expect(user).to have_attributes( - name: have_attributes( - first: be == "John", - last: be == "Doe" - ), - comments: have_value(be =~ /test comment/), - created_at: be_within(1.minute).of(Time.now) -) -``` - -### Logical Combinations - -```ruby -expect(value).to (be > 10).and(be < 20) -expect(value).to be_a(String).or(be_a(Symbol), be_a(Integer)) -``` - -### Custom Predicates - -You can create custom predicates for more complex assertions: - -```ruby -def be_small_prime - (be == 2).or(be == 3, be == 5, be == 7) -end -``` - -## Block Expectations - -### Testing Blocks - -```ruby -expect{operation}.to raise_exception(Error) -expect{operation}.to have_duration(be < 1.0) -``` - -### Performance Testing - -You should generally avoid testing performance in unit tests, as it will be highly unstable and dependent on the environment. However, if you need to test performance, you can use: - -```ruby -expect{slow_operation}.to have_duration(be < 2.0) -expect{fast_operation}.to have_duration(be < 0.1) -``` - -- For less unsable performance tests, you can use the `sus-fixtures-time` gem which tries to compensate for the environment by measuring execution time. - -- For benchmarking, you can use the `sus-fixtures-benchmark` gem which measures a block of code multiple times and reports the execution time. - -## File Operations - -### Temporary Directories - -Use `Dir.mktmpdir` for isolated test environments: - -```ruby -around do |block| - Dir.mktmpdir do |root| - @root = root - block.call - end -end - -let(:test_path) {File.join(@root, "test.txt")} - -it "can create a file" do - File.write(test_path, "content") - expect(File).to be(:exist?, test_path) -end -``` - -## Test Output - -In general, tests should not produce output unless there is an error or failure. - -### Informational Output - -You can use `inform` to print informational messages during tests: - -```ruby -it "logs an informational message" do - rate = copy_data(source, destination) - inform "Copied data at #{rate}MB/s" - expect(rate).to be > 0 -end -``` - -This can be useful for debugging or providing context during test runs. - -### Console Output - -The `sus-fixtures-console` gem provides a way to surpress and capture console output during tests. If you are using code which generates console output, you can use this gem to capture it and assert on it. - -## Running Tests - -```bash -# Run all tests -bundle exec sus - -# Run specific test file -bundle exec sus test/specific_test.rb -``` - -## Best Practices - -1. **Use real objects** instead of mocks when possible. -2. **Dependency injection** for testability. -3. **Isolatae mutable state** using temporary directories. -4. **Clear test descriptions** that explain the behavior. -5. **Group tests** with `describe` (classes) and `with` for better organization. -6. **Keep tests simple** and focused on one behavior. diff --git a/agent.md b/agent.md deleted file mode 100644 index 6891da9c..00000000 --- a/agent.md +++ /dev/null @@ -1,47 +0,0 @@ -# Agent - -## Context - -This section provides links to documentation from installed packages. It is automatically generated and may be updated by running `bake agent:context:install`. - -**Important:** Before performing any code, documentation, or analysis tasks, always read and apply the full content of any relevant documentation referenced in the following sections. These context files contain authoritative standards and best practices for documentation, code style, and project-specific workflows. **Do not proceed with any actions until you have read and incorporated the guidance from relevant context files.** - -### agent-context - -Install and manage context files from Ruby gems. - -#### [Usage Guide](.context/agent-context/usage.md) - -`agent-context` is a tool that helps you discover and install contextual information from Ruby gems for AI agents. Gems can provide additional documentation, examples, and guidance in a `context/` ... - -### decode - -Code analysis for documentation generation. - -#### [Getting Started with Decode](.context/decode/getting-started.md) - -The Decode gem provides programmatic access to Ruby code structure and metadata. It can parse Ruby files and extract definitions, comments, and documentation pragmas, enabling code analysis, docume... - -#### [Documentation Coverage](.context/decode/coverage.md) - -This guide explains how to test and monitor documentation coverage in your Ruby projects using the Decode gem's built-in bake tasks. - -#### [Ruby Documentation](.context/decode/ruby-documentation.md) - -This guide covers documentation practices and pragmas supported by the Decode gem for documenting Ruby code. These pragmas provide structured documentation that can be parsed and used to generate A... - -### sus - -A fast and scalable test runner. - -#### [Using Sus Testing Framework](.context/sus/usage.md) - -Sus is a modern Ruby testing framework that provides a clean, BDD-style syntax for writing tests. It's designed to be fast, simple, and expressive. - -#### [Mocking](.context/sus/mocking.md) - -There are two types of mocking in sus: `receive` and `mock`. The `receive` matcher is a subset of full mocking and is used to set expectations on method calls, while `mock` can be used to replace m... - -#### [Shared Test Behaviors and Fixtures](.context/sus/shared.md) - -Sus provides shared test contexts which can be used to define common behaviours or tests that can be reused across one or more test files.