boxwerk 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/example/Gemfile.lock DELETED
@@ -1,66 +0,0 @@
1
- PATH
2
- remote: ..
3
- specs:
4
- boxwerk (0.1.0)
5
- irb (~> 1.16)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- bigdecimal (4.0.1)
11
- concurrent-ruby (1.3.6)
12
- date (3.5.1)
13
- erb (6.0.1)
14
- i18n (1.14.8)
15
- concurrent-ruby (~> 1.0)
16
- io-console (0.8.2)
17
- irb (1.16.0)
18
- pp (>= 0.6.0)
19
- rdoc (>= 4.0.0)
20
- reline (>= 0.4.2)
21
- money (7.0.0)
22
- bigdecimal
23
- i18n (~> 1.9)
24
- pp (0.6.3)
25
- prettyprint
26
- prettyprint (0.2.0)
27
- psych (5.3.1)
28
- date
29
- stringio
30
- rdoc (7.0.3)
31
- erb
32
- psych (>= 4.0.0)
33
- tsort
34
- reline (0.6.3)
35
- io-console (~> 0.5)
36
- stringio (3.2.0)
37
- tsort (0.2.0)
38
-
39
- PLATFORMS
40
- arm64-darwin-25
41
- ruby
42
-
43
- DEPENDENCIES
44
- boxwerk!
45
- money
46
-
47
- CHECKSUMS
48
- bigdecimal (4.0.1) sha256=8b07d3d065a9f921c80ceaea7c9d4ae596697295b584c296fe599dd0ad01c4a7
49
- boxwerk (0.1.0)
50
- concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab
51
- date (3.5.1) sha256=750d06384d7b9c15d562c76291407d89e368dda4d4fff957eb94962d325a0dc0
52
- erb (6.0.1) sha256=28ecdd99c5472aebd5674d6061e3c6b0a45c049578b071e5a52c2a7f13c197e5
53
- i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5
54
- io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
55
- irb (1.16.0) sha256=2abe56c9ac947cdcb2f150572904ba798c1e93c890c256f8429981a7675b0806
56
- money (7.0.0) sha256=6de776ee00aced8b9a435d3aac25ce8c600566625809b3d69bbe0c319e941dd5
57
- pp (0.6.3) sha256=2951d514450b93ccfeb1df7d021cae0da16e0a7f95ee1e2273719669d0ab9df6
58
- prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193
59
- psych (5.3.1) sha256=eb7a57cef10c9d70173ff74e739d843ac3b2c019a003de48447b2963d81b1974
60
- rdoc (7.0.3) sha256=dfe3d0981d19b7bba71d9dbaeb57c9f4e3a7a4103162148a559c4fc687ea81f9
61
- reline (0.6.3) sha256=1198b04973565b36ec0f11542ab3f5cfeeec34823f4e54cebde90968092b1835
62
- stringio (3.2.0) sha256=c37cb2e58b4ffbd33fe5cd948c05934af997b36e0b6ca6fdf43afa234cf222e1
63
- tsort (0.2.0) sha256=9650a793f6859a43b6641671278f79cfead60ac714148aabe4e3f0060480089f
64
-
65
- BUNDLED WITH
66
- 4.0.3
data/example/README.md DELETED
@@ -1,130 +0,0 @@
1
- # Boxwerk Example Application
2
-
3
- This directory contains a complete example of a Boxwerk application demonstrating strict package isolation and dependency management.
4
-
5
- ## Architecture
6
-
7
- ```
8
- example/
9
- ├── Gemfile # Gem dependencies (money gem)
10
- ├── package.yml # Root package (imports finance)
11
- ├── app.rb # Application entry point
12
- └── packages/
13
- ├── finance/
14
- │ ├── package.yml # Exports Invoice, TaxCalculator; imports util
15
- │ └── lib/
16
- │ ├── invoice.rb
17
- │ └── tax_calculator.rb
18
- └── util/
19
- ├── package.yml # Exports Calculator, Geometry
20
- └── lib/
21
- ├── calculator.rb
22
- └── geometry.rb
23
- ```
24
-
25
- ## Dependency Graph
26
-
27
- ```
28
- util (isolated box)
29
- └── Calculator, Geometry
30
-
31
- finance (isolated box)
32
- ├── imports: util (Calculator renamed to UtilCalculator)
33
- └── Invoice, TaxCalculator
34
-
35
- root (isolated box)
36
- ├── imports: finance
37
- └── Finance::Invoice, Finance::TaxCalculator available
38
- ```
39
-
40
- ## Running the Example
41
-
42
- ```bash
43
- cd example
44
- RUBY_BOX=1 boxwerk run app.rb
45
- ```
46
-
47
- **Architecture:**
48
- - Root box: Contains gems (including money gem) and Boxwerk runtime
49
- - Util box: Contains Calculator and Geometry classes
50
- - Finance box: Contains Invoice and TaxCalculator (imports Calculator from Util box as UtilCalculator)
51
- - Root package box: Runs app.rb (imports from Finance box)
52
-
53
- **Important:** ALL packages (including root) run in isolated boxes. The main Ruby process only contains gems and the Boxwerk runtime.
54
-
55
- ### Interactive Console
56
-
57
- You can also start an IRB console in the root package context:
58
-
59
- ```bash
60
- cd example
61
- RUBY_BOX=1 boxwerk console
62
- ```
63
-
64
- This gives you an interactive session with all imports available (e.g., `Finance::Invoice`).
65
-
66
- ## What This Demonstrates
67
-
68
- ### ✓ Strict Isolation
69
- - `Finance::Invoice` and `Finance::TaxCalculator` are accessible (explicit import)
70
- - `Calculator` and `Geometry` are NOT accessible (transitive dependency - not imported)
71
- - `UtilCalculator` is NOT accessible (only available in Finance package's box)
72
- - `Invoice` at top level is NOT accessible (must use `Finance::` namespace)
73
-
74
- ### ✓ Namespace Control
75
- - Finance package exports are grouped under `Finance::` module
76
- - Import strategies control how dependencies are wired
77
-
78
- ### ✓ Selective Rename Strategy
79
- - Finance imports `Calculator` from util and renames it to `UtilCalculator`
80
- - This demonstrates the selective rename import strategy
81
-
82
- ### ✓ Transitive Dependency Blocking
83
- - Root imports Finance
84
- - Finance imports Util
85
- - Root cannot access Util classes (no transitive access)
86
-
87
- ### ✓ Gem Access
88
- - Money gem is globally accessible in all packages
89
- - Gems from Gemfile are auto-required and available everywhere
90
-
91
- ### ✓ Clean API Surface
92
- - Each package explicitly declares exports
93
- - Consumers only see what's exported
94
- - Internal implementation details remain hidden
95
-
96
- ## Package Configuration
97
-
98
- ### Root Package (`package.yml`)
99
-
100
- ```yaml
101
- imports:
102
- - packages/finance # Default namespace strategy
103
- ```
104
-
105
- ### Finance Package (`packages/finance/package.yml`)
106
-
107
- ```yaml
108
- exports:
109
- - Invoice
110
- - TaxCalculator
111
-
112
- imports:
113
- # Import Calculator from util and rename it to UtilCalculator
114
- - packages/util:
115
- Calculator: UtilCalculator
116
- ```
117
-
118
- ### Util Package (`packages/util/package.yml`)
119
-
120
- ```yaml
121
- exports:
122
- - Calculator
123
- - Geometry
124
- ```
125
-
126
- ## Requirements
127
-
128
- - Ruby 4.0+ with `Ruby::Box` support
129
- - `RUBY_BOX=1` environment variable must be set
130
- - Boxwerk gem installed or loaded from `../lib`
data/example/app.rb DELETED
@@ -1,101 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Example Boxwerk Application
4
- # Run with: RUBY_BOX=1 boxwerk app.rb
5
-
6
- puts '=' * 70
7
- puts 'Boxwerk Application'
8
- puts '=' * 70
9
- puts ''
10
-
11
- puts 'Creating invoice...'
12
- invoice = Finance::Invoice.new(tax_rate: 0.15)
13
- invoice.add_item('Web Development', 200_000) # $2000.00 in cents
14
- invoice.add_item('Design Work', 150_000) # $1500.00 in cents
15
- invoice.add_item('Consulting', 80_000) # $800.00 in cents
16
-
17
- data = invoice.to_h
18
-
19
- puts "\nInvoice Details:"
20
- data[:items].each_with_index do |item, i|
21
- amount_dollars = item[:amount] / 100.0
22
- puts " #{i + 1}. #{item[:description]}: $#{format('%.2f', amount_dollars)}"
23
- end
24
- puts ''
25
- puts " Subtotal: $#{format('%.2f', data[:subtotal] / 100.0)}"
26
- puts " Tax (15%): $#{format('%.2f', data[:tax] / 100.0)}"
27
- puts " Total: $#{format('%.2f', data[:total] / 100.0)}"
28
- puts ''
29
-
30
- puts 'Testing isolation...'
31
- # Finance::Invoice should be available
32
- begin
33
- test_invoice = Finance::Invoice.new
34
- puts ' ✓ Finance::Invoice accessible'
35
- rescue NameError => e
36
- puts " ✗ Finance::Invoice not accessible: #{e.message}"
37
- end
38
-
39
- # Finance::TaxCalculator should be available
40
- begin
41
- Finance::TaxCalculator
42
- puts ' ✓ Finance::TaxCalculator accessible'
43
- rescue NameError => e
44
- puts " ✗ Finance::TaxCalculator not accessible: #{e.message}"
45
- end
46
-
47
- # UtilCalculator should NOT be available (transitive dependency)
48
- begin
49
- UtilCalculator.add(1, 2)
50
- puts ' ✗ ERROR: UtilCalculator leaked from transitive dependency!'
51
- rescue NameError
52
- puts ' ✓ UtilCalculator not accessible (correct isolation)'
53
- end
54
-
55
- # Invoice should NOT be at top level (only in Finance namespace)
56
- begin
57
- Invoice.new
58
- puts ' ✗ ERROR: Invoice available at top level!'
59
- rescue NameError
60
- puts ' ✓ Invoice only accessible via Finance namespace'
61
- end
62
-
63
- # Calculator should NOT be available (transitive dependency from util package)
64
- begin
65
- Calculator.add(1, 2)
66
- puts ' ✗ ERROR: Calculator leaked from transitive dependency!'
67
- rescue NameError
68
- puts ' ✓ Calculator not accessible (correct isolation)'
69
- end
70
-
71
- # Geometry should NOT be available (transitive dependency from util package)
72
- begin
73
- Geometry.circle_area(5)
74
- puts ' ✗ ERROR: Geometry leaked from transitive dependency!'
75
- rescue NameError
76
- puts ' ✓ Geometry not accessible (correct isolation)'
77
- end
78
-
79
- # Money gem SHOULD be accessible (gems are global, not isolated)
80
- begin
81
- test_money = Money.new(100, 'USD')
82
- puts ' ✓ Money gem accessible (gems are global)'
83
- rescue NameError => e
84
- puts " ✗ ERROR: Money gem not accessible: #{e.message}"
85
- end
86
-
87
- puts ''
88
- puts '=' * 70
89
- puts '✓ Application completed successfully'
90
- puts '=' * 70
91
- puts ''
92
- puts 'Boxwerk CLI setup process:'
93
- puts ' 1. `boxwerk run app.rb` found root package.yml'
94
- puts ' 2. Built dependency graph (util → finance → root)'
95
- puts ' 3. Validated no circular dependencies'
96
- puts ' 4. Booted packages in topological order (all in isolated boxes)'
97
- puts ' 5. Executed app.rb in root package box with Finance imported'
98
- puts ''
99
- puts 'Key difference: ALL packages (including root) run in isolated boxes.'
100
- puts 'The main Ruby process only contains gems and the Boxwerk runtime.'
101
- puts ''
data/example/package.yml DELETED
@@ -1,6 +0,0 @@
1
- # Main Application Package
2
-
3
- imports:
4
- # Finance has multiple exports (Invoice, TaxCalculator)
5
- # so this creates a Finance module containing both
6
- - packages/finance
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Invoice represents a financial invoice with line items and tax calculation
4
- # Uses the Money gem for precise currency handling
5
- class Invoice
6
- attr_reader :items, :tax_rate
7
-
8
- def initialize(tax_rate: TaxCalculator::STANDARD_RATE)
9
- @items = []
10
- @tax_rate = tax_rate
11
- end
12
-
13
- def add_item(description, amount_cents)
14
- @items << {
15
- description: description,
16
- amount: Money.new(amount_cents, 'USD'),
17
- }
18
- self
19
- end
20
-
21
- def subtotal
22
- @items.reduce(Money.new(0, 'USD')) { |sum, item| sum + item[:amount] }
23
- end
24
-
25
- def tax
26
- (subtotal * tax_rate).round
27
- end
28
-
29
- def total
30
- subtotal + tax
31
- end
32
-
33
- def to_h
34
- {
35
- items:
36
- @items.map do |item|
37
- { description: item[:description], amount: item[:amount].cents }
38
- end,
39
- subtotal: subtotal.cents,
40
- tax_rate: tax_rate,
41
- tax: tax.cents,
42
- total: total.cents,
43
- }
44
- end
45
-
46
- def self.quick_invoice(amount_cents, tax_rate: TaxCalculator::STANDARD_RATE)
47
- invoice = new(tax_rate: tax_rate)
48
- invoice.add_item('Service', amount_cents)
49
- invoice
50
- end
51
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # TaxCalculator provides tax calculation utilities
4
- # Uses the imported Util package for calculations
5
- class TaxCalculator
6
- STANDARD_RATE = 0.10 # 10%
7
- LUXURY_RATE = 0.20 # 20%
8
-
9
- def self.calculate_tax(amount, rate = STANDARD_RATE)
10
- # Use UtilCalculator from selective import
11
- UtilCalculator.multiply(amount, rate)
12
- end
13
-
14
- def self.calculate_total(amount, rate = STANDARD_RATE)
15
- tax = calculate_tax(amount, rate)
16
- # Use UtilCalculator.add from selective import
17
- UtilCalculator.add(amount, tax)
18
- end
19
-
20
- def self.reverse_calculate(total_with_tax, rate = STANDARD_RATE)
21
- # Calculate original amount from total including tax
22
- # Formula: original = total / (1 + rate)
23
- divisor = UtilCalculator.add(1, rate)
24
- UtilCalculator.divide(total_with_tax, divisor)
25
- end
26
- end
@@ -1,10 +0,0 @@
1
- # Finance Package
2
-
3
- exports:
4
- - Invoice
5
- - TaxCalculator
6
-
7
- imports:
8
- # Import Calculator from util and rename it to UtilCalculator
9
- - packages/util:
10
- Calculator: UtilCalculator
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Calculator provides basic arithmetic operations
4
- class Calculator
5
- def self.add(a, b)
6
- a + b
7
- end
8
-
9
- def self.subtract(a, b)
10
- a - b
11
- end
12
-
13
- def self.multiply(a, b)
14
- a * b
15
- end
16
-
17
- def self.divide(a, b)
18
- raise ArgumentError, 'Cannot divide by zero' if b.zero?
19
- a.to_f / b
20
- end
21
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Geometry provides geometric calculations
4
- class Geometry
5
- PI = 3.14159265359
6
-
7
- def self.circle_area(radius)
8
- PI * radius * radius
9
- end
10
-
11
- def self.circle_circumference(radius)
12
- 2 * PI * radius
13
- end
14
-
15
- def self.rectangle_area(width, height)
16
- width * height
17
- end
18
-
19
- def self.rectangle_perimeter(width, height)
20
- 2 * (width + height)
21
- end
22
-
23
- def self.triangle_area(base, height)
24
- (base * height) / 2.0
25
- end
26
- end
@@ -1,5 +0,0 @@
1
- # Util Package
2
-
3
- exports:
4
- - Calculator
5
- - Geometry
data/sig/boxwerk.rbs DELETED
@@ -1,4 +0,0 @@
1
- module Boxwerk
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end