Skip to content

Repository files navigation

Stroma

A foundation for building modular, extensible DSLs in Ruby.

Gem versionRelease DateDownloadsRuby version

💡 Why Stroma?

Building modular DSLs shouldn't require reinventing the wheel. Stroma provides a structured approach for library authors to compose DSL modules with:

  • 🔌 Module Registration - Register DSL modules at boot time, compose them into a unified interface
  • 🧱 Structured Composition - Include all registered modules automatically via single DSL entry point
  • 🏛️ Inheritance Safe - Per-class state isolation with automatic deep copying
  • 🪝 Extension Hooks - Optional before/after hooks for user customization
  • ⚙️ Extension Settings - Three-level hierarchical storage for extension configuration
  • 🔒 Thread Safe - Immutable registry after finalization, safe concurrent reads

🧬 Concept

Stroma is a foundation for library authors building DSL-driven frameworks (service objects, form objects, decorators, etc.).

Core lifecycle:

  1. Define - Create a Matrix with DSL modules at boot time
  2. Include - Classes include the matrix's DSL to gain all modules
  3. Extend (optional) - Add cross-cutting logic via before/after hooks

🚀 Quick Start

Installation

spec.add_dependency"stroma",">= 0.4"

Define your library's DSL

moduleMyLibSTROMA=Stroma::Matrix.define(:my_lib)doregister:inputs,MyLib::Inputs::DSLregister:actions,MyLib::Actions::DSLendprivate_constant:STROMAend

Create base class

moduleMyLibclassBaseincludeSTROMA.dslendend

Usage

Create an intermediate class with lifecycle hooks:

classApplicationService < MyLib::Base# Add lifecycle hooks (optional)extensionsdobefore:actions,ApplicationService::Extensions::Rollbackable::DSLendend

Build services that inherit extension functionality:

classUserService < ApplicationService# DSL method from Rollbackable extensionon_rollback(...)input:email,type: Stringmake:create_userprivatedefcreate_user# implementationendend

Extensions allow you to add cross-cutting concerns like transactions, authorization, and rollback support. See extension examples for implementation details.

🧩 Building Extensions

Extensions are standard Ruby modules that hook into the DSL lifecycle. Stroma places them at the correct position in the method chain, so super naturally flows through all registered extensions.

Define an extension

moduleAuthorizationdefself.included(base)base.extend(ClassMethods)base.include(InstanceMethods)endmoduleClassMethodsdefauthorize_with(method_name)stroma.settings[:actions][:authorization][:method_name]=method_nameendendmoduleInstanceMethodsdefcall(...)method_name=self.class.stroma.settings[:actions][:authorization][:method_name]send(method_name)ifmethod_namesuperendendend

ClassMethods provides the class-level DSL. InstanceMethods overrides the orchestrator method defined by your library (here call) and delegates via super. Split them into separate files as the extension grows.

Register the extension

classApplicationService < MyLib::Baseextensionsdobefore:actions,Authorizationendend

before places the module so its call executes before the :actions entry. Use after for post-processing. Multiple modules in one call: before :actions, ModA, ModB.

Use in a service

classUserService < ApplicationServiceauthorize_with:check_permissionsinput:email,type: Stringmake:create_userprivatedefcheck_permissions# authorization logicenddefcreate_user# runs only after check_permissions passesendend

Settings and hooks are deep-copied on inheritance — each subclass has independent configuration.

💎 Projects Using Stroma

  • Servactory — Service objects framework for Ruby applications

🤝 Contributing

We welcome contributions! Check out our Contributing Guide to get started.

Ways to contribute:

  • 🐛 Report bugs and issues
  • 💡 Suggest new features
  • 📝 Improve documentation
  • 🧪 Add test cases
  • 🔧 Submit pull requests

🙏 Acknowledgments

Special thanks to all our contributors!

📄 License

Stroma is available as open source under the terms of the MIT License.

About

A foundation for building modular, extensible DSLs in Ruby

Topics

Resources

Code of conduct

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages