Skip to content

Minimal

The smallest working app with Carton boundaries, with no gems or Bundler. Then see Exports for Hashes, callables, and an explicit adapter for legacy Ruby. Source on GitHub.

main.rb # imports billing and math
billing.rb # the billing Carton's Entrypoint: export Billing
billing/invoice.rb # inside the billing Carton
billing/tax.rb # inside too; imports math
math.rb # a Carton of one file: export MathTools

main.rb imports two Cartons and uses only their Public Surfaces:

main.rb
require 'carton'
# Carton boundary: billing.rb plus everything in billing/ load in their own
# Box, and only billing's Export comes back.
Billing = import_relative 'billing'
puts "Invoice total: #{Billing.invoice(40).total}"
# Carton boundary: billing imports math too, so this Shared Import returns the
# same MathTools module.
MathTools = import_relative 'math'
puts "10% of 40: #{MathTools.percent(40, 10)} (math #{MathTools::VERSION})"

billing.rb is the Entrypoint. It loads its own files with require_relative, all inside the billing Carton Box, hides Billing::Tax with private_constant, and exports Billing:

billing.rb
# The billing Carton: this Entrypoint plus everything in billing/. Its own
# files load with require_relative, inside this Carton's one Box.
require_relative 'billing/invoice'
require_relative 'billing/tax'
module Billing
# Internal: Ruby's own visibility hides it from Importers.
private_constant :Tax
def self.invoice(subtotal) = Invoice.new(subtotal, Tax.on(subtotal))
end
# Export: importing billing returns this module.
export Billing

Its Interior is the billing/ directory beside it:

billing/invoice.rb
# Inside the billing Carton, so it can only be loaded by billing.rb.
module Billing
Invoice = Struct.new(:subtotal, :tax) { def total = subtotal + tax }
end

billing/tax.rb imports math, another Carton, across a boundary. The app imports math too, so that import is a Shared Import and both get the same Export:

billing/tax.rb
# Carton boundary: math is another Carton, and billing sees only its Export.
MathTools = import_relative '../math'
module Billing
module Tax
RATE = 10
def self.on(amount) = MathTools.percent(amount, RATE)
end
end
math.rb
# A Carton of one file: math.rb, with no math/ directory beside it.
module MathTools
VERSION = '1.0'
def self.percent(amount, rate) = (amount * rate / 100.0).round(2)
end
# Export: importing math returns this module.
export MathTools
RUBY_BOX=1 ruby examples/minimal/main.rb

See Tooling for boundary checks, generated RBS, and Steep in a separate app.