Skills-4-SE function-class-generator
Generate complete, production-ready functions and classes from formal specifications, design descriptions, type signatures, or natural language requirements. Use this skill when implementing APIs from specifications, creating data structures from schemas, building classes from UML diagrams, generating code from contracts, or translating design documents into code. Supports multiple programming languages and follows language-specific best practices.
git clone https://github.com/ArabelaTso/Skills-4-SE
T=$(mktemp -d) && git clone --depth=1 https://github.com/ArabelaTso/Skills-4-SE "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/function-class-generator" ~/.claude/skills/arabelatso-skills-4-se-function-class-generator && rm -rf "$T"
skills/function-class-generator/SKILL.mdFunction/Class Generator
Transform formal specifications, design descriptions, and requirements into complete, well-structured, production-ready code. Generates functions, classes, interfaces, and data structures with proper error handling, documentation, and tests.
Core Capabilities
1. Specification Parsing
Understand specifications from multiple sources:
- Type signatures - Function signatures with input/output types
- Formal specifications - Pre/postconditions, invariants, contracts
- API documentation - OpenAPI, Swagger, JSON Schema
- UML diagrams - Class diagrams, sequence diagrams
- Natural language - Requirements and design descriptions
- Interface definitions - Protocol buffers, GraphQL schemas
2. Code Generation
Create complete implementations:
- Functions - Standalone functions with logic and validation
- Classes - Full class definitions with methods and properties
- Interfaces/Protocols - Abstract definitions and contracts
- Data structures - Custom types, enums, unions
- Error handling - Exceptions, error types, validation
- Documentation - Docstrings, comments, type hints
3. Best Practices Integration
Apply language-specific patterns:
- Naming conventions - Follow language standards
- Type safety - Use static typing where available
- Error handling - Appropriate exception handling
- Documentation - Clear docstrings and comments
- Testing - Generate unit tests alongside code
- SOLID principles - Single responsibility, open/closed, etc.
4. Validation and Testing
Ensure correctness:
- Type checking - Verify type correctness
- Contract validation - Check pre/postconditions
- Unit tests - Generate test cases
- Edge cases - Handle boundaries and exceptions
- Examples - Provide usage examples
Code Generation Workflow
Step 1: Parse Specification
Extract key information:
From type signature:
# Specification def calculate_discount(price: float, percentage: float) -> float: """Calculate discounted price.""" pass
Extract:
- Function name:
calculate_discount - Parameters:
(float),price
(float)percentage - Return type:
float - Purpose: Calculate discounted price
From formal specification:
Function: binary_search Inputs: sorted_array: List[int], target: int Output: int (index of target, or -1 if not found) Preconditions: - sorted_array is sorted in ascending order - sorted_array is not empty Postconditions: - If result >= 0: sorted_array[result] == target - If result == -1: target not in sorted_array
Step 2: Design Implementation
Plan the structure:
Identify:
- Main logic flow
- Edge cases to handle
- Validation needed
- Error conditions
- Helper functions required
For binary_search example:
- Main logic: Binary search algorithm
- Edge cases: Empty array, single element, target at boundaries
- Validation: Array must be sorted, index bounds
- Errors: Invalid input types, empty array
- Helpers: None needed (self-contained)
Step 3: Generate Code
Create complete implementation:
Generated code:
def binary_search(sorted_array: list[int], target: int) -> int: """ Search for target in sorted array using binary search. Args: sorted_array: List of integers sorted in ascending order target: Integer value to search for Returns: Index of target if found, -1 otherwise Raises: ValueError: If sorted_array is empty TypeError: If inputs are not of correct type Examples: >>> binary_search([1, 2, 3, 4, 5], 3) 2 >>> binary_search([1, 2, 3, 4, 5], 6) -1 Time Complexity: O(log n) Space Complexity: O(1) """ if not isinstance(sorted_array, list): raise TypeError("sorted_array must be a list") if not isinstance(target, int): raise TypeError("target must be an integer") if not sorted_array: raise ValueError("sorted_array cannot be empty") left, right = 0, len(sorted_array) - 1 while left <= right: mid = left + (right - left) // 2 # Avoid overflow if sorted_array[mid] == target: return mid elif sorted_array[mid] < target: left = mid + 1 else: right = mid - 1 return -1
Step 4: Add Documentation
Include comprehensive documentation:
Elements:
- Docstring with description
- Parameter descriptions
- Return value description
- Exceptions raised
- Usage examples
- Complexity analysis
- Precondition/postcondition notes
Step 5: Generate Tests
Create validation tests:
import pytest def test_binary_search_found(): """Test finding an element in the middle.""" assert binary_search([1, 2, 3, 4, 5], 3) == 2 def test_binary_search_not_found(): """Test element not in array.""" assert binary_search([1, 2, 3, 4, 5], 6) == -1 def test_binary_search_first_element(): """Test finding first element.""" assert binary_search([1, 2, 3, 4, 5], 1) == 0 def test_binary_search_last_element(): """Test finding last element.""" assert binary_search([1, 2, 3, 4, 5], 5) == 4 def test_binary_search_single_element_found(): """Test single-element array with target present.""" assert binary_search([1], 1) == 0 def test_binary_search_single_element_not_found(): """Test single-element array with target absent.""" assert binary_search([1], 2) == -1 def test_binary_search_empty_array(): """Test that empty array raises ValueError.""" with pytest.raises(ValueError, match="cannot be empty"): binary_search([], 1) def test_binary_search_invalid_array_type(): """Test that invalid array type raises TypeError.""" with pytest.raises(TypeError, match="must be a list"): binary_search("not a list", 1) def test_binary_search_invalid_target_type(): """Test that invalid target type raises TypeError.""" with pytest.raises(TypeError, match="must be an integer"): binary_search([1, 2, 3], "not an int")
Generation Patterns
Pattern 1: Function from Type Signature
Specification:
function calculateArea(width: number, height: number): number
Generated implementation:
/** * Calculate the area of a rectangle. * * @param width - Width of the rectangle (must be positive) * @param height - Height of the rectangle (must be positive) * @returns The calculated area (width * height) * @throws {Error} If width or height is not positive * * @example * ```typescript * calculateArea(5, 10) // returns 50 * calculateArea(2.5, 4) // returns 10 * ``` */ function calculateArea(width: number, height: number): number { if (width <= 0) { throw new Error('Width must be positive'); } if (height <= 0) { throw new Error('Height must be positive'); } return width * height; }
Generated tests:
import { describe, it, expect } from '@jest/globals'; describe('calculateArea', () => { it('should calculate area correctly', () => { expect(calculateArea(5, 10)).toBe(50); expect(calculateArea(2.5, 4)).toBe(10); }); it('should handle decimal values', () => { expect(calculateArea(3.5, 2.5)).toBeCloseTo(8.75); }); it('should throw error for zero width', () => { expect(() => calculateArea(0, 10)).toThrow('Width must be positive'); }); it('should throw error for negative width', () => { expect(() => calculateArea(-5, 10)).toThrow('Width must be positive'); }); it('should throw error for zero height', () => { expect(() => calculateArea(10, 0)).toThrow('Height must be positive'); }); it('should throw error for negative height', () => { expect(() => calculateArea(10, -5)).toThrow('Height must be positive'); }); });
Pattern 2: Class from Specification
Specification:
Class: BankAccount Purpose: Manage a bank account with deposits and withdrawals Attributes: - account_number: string (unique identifier) - balance: decimal (current balance, must be >= 0) - owner_name: string Methods: - deposit(amount): Add money to account Precondition: amount > 0 Postcondition: balance increased by amount - withdraw(amount): Remove money from account Precondition: amount > 0 and amount <= balance Postcondition: balance decreased by amount - get_balance(): Return current balance Postcondition: returns balance >= 0 Invariants: - balance must always be >= 0 - account_number is immutable
Generated implementation:
from decimal import Decimal from typing import Final class InsufficientFundsError(Exception): """Raised when withdrawal amount exceeds account balance.""" pass class InvalidAmountError(Exception): """Raised when transaction amount is invalid.""" pass class BankAccount: """ Manage a bank account with deposits and withdrawals. Invariants: - Balance is always >= 0 - Account number is immutable once set Attributes: account_number: Unique account identifier (immutable) balance: Current account balance (non-negative) owner_name: Name of account owner """ def __init__(self, account_number: str, owner_name: str, initial_balance: Decimal = Decimal('0')): """ Initialize a new bank account. Args: account_number: Unique account identifier owner_name: Name of account owner initial_balance: Starting balance (default: 0) Raises: ValueError: If account_number or owner_name is empty InvalidAmountError: If initial_balance is negative """ if not account_number: raise ValueError("Account number cannot be empty") if not owner_name: raise ValueError("Owner name cannot be empty") if initial_balance < 0: raise InvalidAmountError("Initial balance cannot be negative") self._account_number: Final[str] = account_number self._balance: Decimal = initial_balance self.owner_name: str = owner_name @property def account_number(self) -> str: """Get account number (immutable).""" return self._account_number @property def balance(self) -> Decimal: """Get current account balance.""" return self._balance def deposit(self, amount: Decimal) -> None: """ Add money to the account. Args: amount: Amount to deposit (must be positive) Raises: InvalidAmountError: If amount is not positive Postcondition: Balance increases by amount """ if amount <= 0: raise InvalidAmountError("Deposit amount must be positive") self._balance += amount def withdraw(self, amount: Decimal) -> None: """ Remove money from the account. Args: amount: Amount to withdraw (must be positive and <= balance) Raises: InvalidAmountError: If amount is not positive InsufficientFundsError: If amount exceeds current balance Postcondition: Balance decreases by amount """ if amount <= 0: raise InvalidAmountError("Withdrawal amount must be positive") if amount > self._balance: raise InsufficientFundsError( f"Insufficient funds: balance={self._balance}, requested={amount}" ) self._balance -= amount def get_balance(self) -> Decimal: """ Return current account balance. Returns: Current balance (always >= 0) """ return self._balance def __repr__(self) -> str: """Return string representation of account.""" return f"BankAccount(account_number={self._account_number!r}, balance={self._balance}, owner={self.owner_name!r})"
Generated tests:
import pytest from decimal import Decimal class TestBankAccount: """Test suite for BankAccount class.""" def test_init_valid(self): """Test creating account with valid parameters.""" account = BankAccount("12345", "John Doe", Decimal('100')) assert account.account_number == "12345" assert account.balance == Decimal('100') assert account.owner_name == "John Doe" def test_init_default_balance(self): """Test creating account with default zero balance.""" account = BankAccount("12345", "John Doe") assert account.balance == Decimal('0') def test_init_invalid_account_number(self): """Test that empty account number raises ValueError.""" with pytest.raises(ValueError, match="Account number cannot be empty"): BankAccount("", "John Doe") def test_init_invalid_owner_name(self): """Test that empty owner name raises ValueError.""" with pytest.raises(ValueError, match="Owner name cannot be empty"): BankAccount("12345", "") def test_init_negative_balance(self): """Test that negative initial balance raises InvalidAmountError.""" with pytest.raises(InvalidAmountError, match="cannot be negative"): BankAccount("12345", "John Doe", Decimal('-10')) def test_account_number_immutable(self): """Test that account number cannot be changed.""" account = BankAccount("12345", "John Doe") with pytest.raises(AttributeError): account.account_number = "67890" def test_deposit_valid(self): """Test depositing positive amount.""" account = BankAccount("12345", "John Doe", Decimal('100')) account.deposit(Decimal('50')) assert account.balance == Decimal('150') def test_deposit_zero(self): """Test that depositing zero raises InvalidAmountError.""" account = BankAccount("12345", "John Doe") with pytest.raises(InvalidAmountError, match="must be positive"): account.deposit(Decimal('0')) def test_deposit_negative(self): """Test that depositing negative amount raises InvalidAmountError.""" account = BankAccount("12345", "John Doe") with pytest.raises(InvalidAmountError, match="must be positive"): account.deposit(Decimal('-10')) def test_withdraw_valid(self): """Test withdrawing valid amount.""" account = BankAccount("12345", "John Doe", Decimal('100')) account.withdraw(Decimal('30')) assert account.balance == Decimal('70') def test_withdraw_entire_balance(self): """Test withdrawing entire balance.""" account = BankAccount("12345", "John Doe", Decimal('100')) account.withdraw(Decimal('100')) assert account.balance == Decimal('0') def test_withdraw_insufficient_funds(self): """Test that withdrawing more than balance raises InsufficientFundsError.""" account = BankAccount("12345", "John Doe", Decimal('100')) with pytest.raises(InsufficientFundsError, match="Insufficient funds"): account.withdraw(Decimal('150')) def test_withdraw_zero(self): """Test that withdrawing zero raises InvalidAmountError.""" account = BankAccount("12345", "John Doe", Decimal('100')) with pytest.raises(InvalidAmountError, match="must be positive"): account.withdraw(Decimal('0')) def test_withdraw_negative(self): """Test that withdrawing negative amount raises InvalidAmountError.""" account = BankAccount("12345", "John Doe", Decimal('100')) with pytest.raises(InvalidAmountError, match="must be positive"): account.withdraw(Decimal('-10')) def test_get_balance(self): """Test getting account balance.""" account = BankAccount("12345", "John Doe", Decimal('100')) assert account.get_balance() == Decimal('100') assert account.get_balance() >= 0 # Invariant check def test_multiple_transactions(self): """Test sequence of deposits and withdrawals.""" account = BankAccount("12345", "John Doe", Decimal('100')) account.deposit(Decimal('50')) # 150 account.withdraw(Decimal('30')) # 120 account.deposit(Decimal('10')) # 130 account.withdraw(Decimal('80')) # 50 assert account.balance == Decimal('50') def test_repr(self): """Test string representation.""" account = BankAccount("12345", "John Doe", Decimal('100')) repr_str = repr(account) assert "12345" in repr_str assert "John Doe" in repr_str assert "100" in repr_str
Pattern 3: Interface from API Specification
Specification (OpenAPI):
paths: /users/{userId}: get: summary: Get user by ID parameters: - name: userId in: path required: true schema: type: integer responses: '200': description: User found content: application/json: schema: $ref: '#/components/schemas/User' '404': description: User not found
Generated implementation (Python with FastAPI):
from fastapi import FastAPI, HTTPException, Path from pydantic import BaseModel from typing import Optional app = FastAPI() class User(BaseModel): """User model.""" id: int name: str email: str created_at: str class Config: json_schema_extra = { "example": { "id": 1, "name": "John Doe", "email": "john@example.com", "created_at": "2024-01-01T00:00:00Z" } } # Mock database users_db: dict[int, User] = { 1: User(id=1, name="John Doe", email="john@example.com", created_at="2024-01-01T00:00:00Z") } @app.get( "/users/{userId}", response_model=User, summary="Get user by ID", responses={ 200: {"description": "User found"}, 404: {"description": "User not found"} } ) async def get_user( userId: int = Path(..., description="User ID", ge=1) ) -> User: """ Retrieve a user by their ID. Args: userId: Unique user identifier (must be >= 1) Returns: User object with id, name, email, and created_at Raises: HTTPException: 404 if user not found """ user = users_db.get(userId) if user is None: raise HTTPException(status_code=404, detail=f"User {userId} not found") return user
Generated tests:
from fastapi.testclient import TestClient import pytest client = TestClient(app) def test_get_user_success(): """Test retrieving existing user.""" response = client.get("/users/1") assert response.status_code == 200 data = response.json() assert data["id"] == 1 assert data["name"] == "John Doe" assert data["email"] == "john@example.com" def test_get_user_not_found(): """Test retrieving non-existent user.""" response = client.get("/users/999") assert response.status_code == 404 assert "not found" in response.json()["detail"].lower() def test_get_user_invalid_id(): """Test with invalid user ID.""" response = client.get("/users/0") assert response.status_code == 422 # Validation error def test_get_user_negative_id(): """Test with negative user ID.""" response = client.get("/users/-1") assert response.status_code == 422 # Validation error
Pattern 4: Data Structure from Schema
Specification (JSON Schema):
{ "type": "object", "title": "Product", "required": ["id", "name", "price"], "properties": { "id": { "type": "integer", "minimum": 1 }, "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "price": { "type": "number", "minimum": 0 }, "category": { "type": "string", "enum": ["electronics", "clothing", "food", "other"] }, "inStock": { "type": "boolean", "default": true } } }
Generated implementation (TypeScript):
/** * Product category enumeration. */ export enum ProductCategory { Electronics = 'electronics', Clothing = 'clothing', Food = 'food', Other = 'other' } /** * Product data structure. */ export interface Product { /** Unique product identifier (must be >= 1) */ id: number; /** Product name (1-100 characters) */ name: string; /** Product price (must be >= 0) */ price: number; /** Product category (optional) */ category?: ProductCategory; /** Whether product is in stock (default: true) */ inStock?: boolean; } /** * Validate a product object. * * @param product - Product object to validate * @throws {Error} If validation fails */ export function validateProduct(product: Product): void { if (product.id < 1) { throw new Error('Product ID must be at least 1'); } if (product.name.length < 1 || product.name.length > 100) { throw new Error('Product name must be 1-100 characters'); } if (product.price < 0) { throw new Error('Product price must be non-negative'); } if (product.category !== undefined && !Object.values(ProductCategory).includes(product.category)) { throw new Error(`Invalid category: ${product.category}`); } } /** * Create a product with validation. * * @param data - Product data * @returns Validated product object * @throws {Error} If validation fails */ export function createProduct(data: Product): Product { const product: Product = { id: data.id, name: data.name, price: data.price, category: data.category, inStock: data.inStock ?? true }; validateProduct(product); return product; }
Generated tests:
import { describe, it, expect } from '@jest/globals'; import { Product, ProductCategory, validateProduct, createProduct } from './product'; describe('Product validation', () => { const validProduct: Product = { id: 1, name: 'Test Product', price: 10.99, category: ProductCategory.Electronics, inStock: true }; describe('validateProduct', () => { it('should accept valid product', () => { expect(() => validateProduct(validProduct)).not.toThrow(); }); it('should reject product with invalid ID', () => { const invalid = { ...validProduct, id: 0 }; expect(() => validateProduct(invalid)).toThrow('ID must be at least 1'); }); it('should reject product with empty name', () => { const invalid = { ...validProduct, name: '' }; expect(() => validateProduct(invalid)).toThrow('name must be 1-100 characters'); }); it('should reject product with too long name', () => { const invalid = { ...validProduct, name: 'a'.repeat(101) }; expect(() => validateProduct(invalid)).toThrow('name must be 1-100 characters'); }); it('should reject product with negative price', () => { const invalid = { ...validProduct, price: -1 }; expect(() => validateProduct(invalid)).toThrow('price must be non-negative'); }); it('should accept product with zero price', () => { const valid = { ...validProduct, price: 0 }; expect(() => validateProduct(valid)).not.toThrow(); }); it('should accept product without category', () => { const valid = { ...validProduct, category: undefined }; expect(() => validateProduct(valid)).not.toThrow(); }); }); describe('createProduct', () => { it('should create product with all fields', () => { const product = createProduct(validProduct); expect(product).toEqual(validProduct); }); it('should set default inStock to true', () => { const data = { ...validProduct, inStock: undefined }; const product = createProduct(data); expect(product.inStock).toBe(true); }); it('should respect explicit inStock value', () => { const data = { ...validProduct, inStock: false }; const product = createProduct(data); expect(product.inStock).toBe(false); }); it('should throw on invalid data', () => { const invalid = { ...validProduct, id: -1 }; expect(() => createProduct(invalid)).toThrow(); }); }); });
Language-Specific Templates
Python
- Use type hints (PEP 484)
- Docstrings (Google or NumPy style)
- Property decorators for getters
- Raise appropriate exceptions
- Follow PEP 8 naming
TypeScript/JavaScript
- Use interfaces for contracts
- JSDoc comments
- Readonly for immutability
- Async/await for promises
- camelCase naming
Java
- Use interfaces and abstract classes
- Javadoc comments
- Getters/setters
- Checked exceptions
- camelCase naming
Rust
- Use traits for interfaces
- Rustdoc comments
- Result type for errors
- Ownership patterns
- snake_case naming
Best Practices
- Start with specifications - Fully understand requirements before coding
- Include validation - Check preconditions and invariants
- Handle errors explicitly - Don't ignore edge cases
- Document thoroughly - Explain what, why, and how
- Generate tests - Tests validate the implementation
- Follow conventions - Use language idioms and patterns
- Keep it simple - Don't over-engineer
- Make it immutable - When appropriate, prevent mutation
- Use types - Leverage type systems for safety
- Provide examples - Show how to use the code
Common Patterns
- Factory pattern - For complex object creation
- Builder pattern - For objects with many parameters
- Strategy pattern - For interchangeable algorithms
- Template method - For invariant algorithms with variant steps
- Dependency injection - For testability and flexibility