regolith 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE +21 -0
- data/README.md +210 -0
- data/bin/regolith +5 -0
- data/lib/regolith/cli.rb +435 -0
- data/lib/regolith/regolith_association.rb +74 -0
- data/lib/regolith/regolith_record.rb +140 -0
- data/lib/regolith/service_client.rb +68 -0
- data/lib/regolith/version.rb +4 -0
- data/lib/regolith.rb +51 -0
- data/regolith.gemspec +37 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ab1bb3625f09d797596ad621a52eea0c1db33939cf262c4030807a4b37301172
|
4
|
+
data.tar.gz: 699de873f98dd3416e38feaa9a3af4377ad8810c7db1329122a55bc0898792f5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bc39ef600c9cc6e1890ac561076ed67c36d07ae03700f715b1c1b94056b520b4a8bb076802c99bad1613f8c987c31d797c48db7943dcc7471bfde8407d5ac4b7
|
7
|
+
data.tar.gz: 4469ecbd5381b6b6019b8ecc5e1051a6da78b19526e9641872b17d95bae2bc866dfe953735359a95501ae3dc272bb02e33ffc8c9f5977fcb638f52787eb5d0fc
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
## [0.1.0] - 2025-07-30
|
6
|
+
|
7
|
+
### Added
|
8
|
+
- Initial Regolith framework release
|
9
|
+
- CLI for creating and managing microservices
|
10
|
+
- Cross-service ActiveRecord-style associations
|
11
|
+
- Docker Compose orchestration
|
12
|
+
- Rails API service generation
|
13
|
+
- Service discovery and registry
|
14
|
+
- Working observatory example application
|
15
|
+
|
16
|
+
### Features
|
17
|
+
- `regolith new <app>` - Create new distributed applications
|
18
|
+
- `regolith generate service <name>` - Generate Rails API services
|
19
|
+
- `regolith server` - Start all services with Docker
|
20
|
+
- `regolith console <service>` - Open Rails console for any service
|
21
|
+
- Zero-configuration service discovery
|
22
|
+
- Hot reload development environment
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 Regolith Framework
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,210 @@
|
|
1
|
+
# Regolith
|
2
|
+
|
3
|
+
**Rails for Distributed Systems**
|
4
|
+
|
5
|
+
Regolith brings the elegance and developer experience of Rails to microservices architecture. Write cross-service associations like `user.orders.create!` and let Regolith handle the distributed complexity.
|
6
|
+
|
7
|
+
[](https://badge.fury.io/rb/regolith)
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
9
|
+
|
10
|
+
## ✨ Features
|
11
|
+
|
12
|
+
- **Zero-config service discovery** - Services find each other automatically
|
13
|
+
- **ActiveRecord-style cross-service associations** - `user.orders.create!` works across services
|
14
|
+
- **Docker orchestration built-in** - One command starts your entire stack
|
15
|
+
- **Rails API scaffolding** - Generate production-ready services in seconds
|
16
|
+
- **Hot reload development** - Code changes reflect immediately in running containers
|
17
|
+
- **Rails console access** - Debug any service with `regolith console users`
|
18
|
+
|
19
|
+
## 🚀 Quick Start
|
20
|
+
|
21
|
+
### Installation
|
22
|
+
|
23
|
+
```bash
|
24
|
+
gem install regolith
|
25
|
+
Create your first distributed app
|
26
|
+
bash# Create new app
|
27
|
+
regolith new my-app
|
28
|
+
cd my-app
|
29
|
+
|
30
|
+
# Generate microservices
|
31
|
+
regolith generate service users
|
32
|
+
regolith generate service orders
|
33
|
+
|
34
|
+
# Start everything
|
35
|
+
regolith server
|
36
|
+
Your services are now running:
|
37
|
+
|
38
|
+
👥 users_service at http://localhost:3001
|
39
|
+
📦 orders_service at http://localhost:3002
|
40
|
+
🗄️ PostgreSQL at localhost:5432
|
41
|
+
|
42
|
+
🌟 Cross-Service Magic
|
43
|
+
Define relationships that span services:
|
44
|
+
ruby# users_service/app/models/user.rb
|
45
|
+
class User < Regolith::RegolithRecord
|
46
|
+
service :users
|
47
|
+
has_many :orders, service: :orders
|
48
|
+
end
|
49
|
+
|
50
|
+
# orders_service/app/models/order.rb
|
51
|
+
class Order < Regolith::RegolithRecord
|
52
|
+
service :orders
|
53
|
+
belongs_to :user, service: :users
|
54
|
+
end
|
55
|
+
Use them naturally:
|
56
|
+
ruby# In users_service Rails console
|
57
|
+
user = User.create!(name: "Alice", email: "alice@example.com")
|
58
|
+
user.orders.create!(product: "iPhone", amount: 999)
|
59
|
+
|
60
|
+
# In orders_service Rails console
|
61
|
+
order = Order.find(1)
|
62
|
+
order.user.name # "Alice" - fetched from users_service!
|
63
|
+
📁 Project Structure
|
64
|
+
my-app/
|
65
|
+
├── docker-compose.yml # Orchestration config
|
66
|
+
├── config/
|
67
|
+
│ └── regolith.yml # Service registry
|
68
|
+
├── services/
|
69
|
+
│ ├── users_service/ # Rails API app
|
70
|
+
│ └── orders_service/ # Rails API app
|
71
|
+
└── Makefile # Convenience commands
|
72
|
+
🛠️ CLI Commands
|
73
|
+
CommandPurposeregolith new <app>Create new Regolith applicationregolith generate service <name>Generate new microserviceregolith serverStart all services with Docker Composeregolith console <service>Open Rails console for serviceregolith versionShow version information
|
74
|
+
🏗️ How It Works
|
75
|
+
Service Discovery
|
76
|
+
Services are registered in config/regolith.yml:
|
77
|
+
yamlname: my-app
|
78
|
+
services:
|
79
|
+
users:
|
80
|
+
port: 3001
|
81
|
+
root: ./services/users_service
|
82
|
+
orders:
|
83
|
+
port: 3002
|
84
|
+
root: ./services/orders_service
|
85
|
+
Inter-Service Communication
|
86
|
+
The Regolith::RegolithRecord class extends ActiveModel with HTTP-based service calls:
|
87
|
+
rubyclass User < Regolith::RegolithRecord
|
88
|
+
service :users
|
89
|
+
has_many :orders, service: :orders
|
90
|
+
end
|
91
|
+
When you call user.orders.create!(), Regolith:
|
92
|
+
|
93
|
+
Identifies the target service (:orders)
|
94
|
+
Makes HTTP POST to orders_service/orders
|
95
|
+
Includes the foreign key (user_id)
|
96
|
+
Returns the created object
|
97
|
+
|
98
|
+
Docker Integration
|
99
|
+
Each service gets its own container with:
|
100
|
+
|
101
|
+
Hot reload via volume mounts
|
102
|
+
Shared PostgreSQL database
|
103
|
+
Inter-service networking
|
104
|
+
Environment-based configuration
|
105
|
+
|
106
|
+
🧪 Development Workflow
|
107
|
+
bash# Start all services
|
108
|
+
regolith server
|
109
|
+
|
110
|
+
# Open Rails console for any service
|
111
|
+
regolith console users
|
112
|
+
|
113
|
+
# Test cross-service relationships
|
114
|
+
User.first.orders.create!(product: "Laptop", amount: 1200)
|
115
|
+
|
116
|
+
# Check logs
|
117
|
+
docker-compose logs -f users
|
118
|
+
|
119
|
+
# Add new service
|
120
|
+
regolith generate service analytics
|
121
|
+
📦 Example: E-commerce Platform
|
122
|
+
bash# Create the platform
|
123
|
+
regolith new ecommerce
|
124
|
+
cd ecommerce
|
125
|
+
|
126
|
+
# Generate services
|
127
|
+
regolith generate service users
|
128
|
+
regolith generate service products
|
129
|
+
regolith generate service orders
|
130
|
+
regolith generate service payments
|
131
|
+
|
132
|
+
# Start everything
|
133
|
+
regolith server
|
134
|
+
ruby# Define cross-service relationships
|
135
|
+
class User < Regolith::RegolithRecord
|
136
|
+
service :users
|
137
|
+
has_many :orders, service: :orders
|
138
|
+
end
|
139
|
+
|
140
|
+
class Order < Regolith::RegolithRecord
|
141
|
+
service :orders
|
142
|
+
belongs_to :user, service: :users
|
143
|
+
belongs_to :product, service: :products
|
144
|
+
has_one :payment, service: :payments
|
145
|
+
end
|
146
|
+
|
147
|
+
# Use like Rails
|
148
|
+
user = User.create!(name: "Bob", email: "bob@shop.com")
|
149
|
+
product = Product.create!(name: "MacBook", price: 2000)
|
150
|
+
order = user.orders.create!(product: product)
|
151
|
+
order.create_payment!(amount: 2000, method: "credit_card")
|
152
|
+
🔧 Configuration
|
153
|
+
Custom Service Configuration
|
154
|
+
ruby# config/initializers/regolith.rb
|
155
|
+
Regolith.configure do |config|
|
156
|
+
config.timeout = 30
|
157
|
+
config.retry_attempts = 3
|
158
|
+
end
|
159
|
+
Environment Variables
|
160
|
+
VariablePurposeREGOLITH_SERVICE_NAMECurrent service identifierREGOLITH_SERVICE_PORTService port mappingDATABASE_URLShared database connection
|
161
|
+
Production Deployment
|
162
|
+
For production, replace Docker Compose with:
|
163
|
+
|
164
|
+
Container orchestration: Kubernetes, ECS, or similar
|
165
|
+
Service mesh: Istio, Linkerd for advanced networking
|
166
|
+
Service discovery: Consul, etcd for dynamic registration
|
167
|
+
Load balancing: nginx, HAProxy for traffic distribution
|
168
|
+
Monitoring: Prometheus, Grafana for observability
|
169
|
+
|
170
|
+
📚 Examples
|
171
|
+
Working Observatory App
|
172
|
+
The repository includes a complete example in observatory/:
|
173
|
+
|
174
|
+
telescope_service - User management
|
175
|
+
records_service - Observation tracking
|
176
|
+
Full cross-service associations
|
177
|
+
Docker orchestration
|
178
|
+
|
179
|
+
More Examples
|
180
|
+
|
181
|
+
E-commerce Platform - Multi-service shopping platform
|
182
|
+
Social Network - Users, posts, and comments across services
|
183
|
+
Blog Platform - Authors, articles, and analytics services
|
184
|
+
|
185
|
+
🤝 Contributing
|
186
|
+
We love contributions! See CONTRIBUTING.md for guidelines.
|
187
|
+
|
188
|
+
Fork the repository
|
189
|
+
Create feature branch (git checkout -b feature/amazing-feature)
|
190
|
+
Commit changes (git commit -m 'Add amazing feature')
|
191
|
+
Push to branch (git push origin feature/amazing-feature)
|
192
|
+
Open Pull Request
|
193
|
+
|
194
|
+
🐛 Issues & Support
|
195
|
+
|
196
|
+
Bug reports: GitHub Issues
|
197
|
+
Feature requests: GitHub Discussions
|
198
|
+
Documentation: GitHub Wiki
|
199
|
+
|
200
|
+
📄 License
|
201
|
+
MIT License - see LICENSE for details.
|
202
|
+
🙏 Acknowledgments
|
203
|
+
|
204
|
+
Inspired by the elegance of Ruby on Rails
|
205
|
+
Built for the modern microservices era
|
206
|
+
Designed to make distributed systems feel human
|
207
|
+
|
208
|
+
|
209
|
+
Regolith: Because microservices shouldn't be micro-management.
|
210
|
+
Built with ❤️ for developers who want to focus on features, not infrastructure.
|
data/bin/regolith
ADDED
data/lib/regolith/cli.rb
ADDED
@@ -0,0 +1,435 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'yaml'
|
3
|
+
require 'erb'
|
4
|
+
require 'timeout'
|
5
|
+
require 'rubygems'
|
6
|
+
|
7
|
+
module Regolith
|
8
|
+
class CLI
|
9
|
+
def initialize(args)
|
10
|
+
@args = args
|
11
|
+
@command = args[0]
|
12
|
+
@subcommand = args[1]
|
13
|
+
@name = args[2]
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
case @command
|
18
|
+
when 'new'
|
19
|
+
create_new_app(@subcommand)
|
20
|
+
when 'generate'
|
21
|
+
generate_resource(@subcommand, @name)
|
22
|
+
when 'server'
|
23
|
+
start_server
|
24
|
+
when 'console'
|
25
|
+
open_console(@subcommand)
|
26
|
+
when 'version'
|
27
|
+
puts "Regolith #{Regolith::VERSION}"
|
28
|
+
else
|
29
|
+
show_help
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def create_new_app(app_name)
|
36
|
+
unless app_name
|
37
|
+
puts "❌ Error: App name required"
|
38
|
+
puts "Usage: regolith new <app_name>"
|
39
|
+
exit 1
|
40
|
+
end
|
41
|
+
|
42
|
+
puts "🏗 Creating Regolith app '#{app_name}'..."
|
43
|
+
|
44
|
+
FileUtils.mkdir_p(app_name)
|
45
|
+
Dir.chdir(app_name) do
|
46
|
+
create_app_structure(app_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
puts "✅ Created Regolith app '#{app_name}'"
|
50
|
+
puts "→ Next: cd #{app_name} && regolith generate service <service_name>"
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_app_structure(app_name)
|
54
|
+
FileUtils.mkdir_p(['config', 'services', '.bin'])
|
55
|
+
|
56
|
+
regolith_config = {
|
57
|
+
'name' => app_name,
|
58
|
+
'version' => '0.1.0',
|
59
|
+
'services' => {},
|
60
|
+
'infrastructure' => {
|
61
|
+
'database' => {
|
62
|
+
'type' => 'postgresql',
|
63
|
+
'port' => 5432
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
File.write('config/regolith.yml', YAML.dump(regolith_config))
|
69
|
+
File.write('docker-compose.yml', generate_docker_compose(app_name))
|
70
|
+
File.write('Makefile', generate_makefile)
|
71
|
+
File.write('.bin/regolith', generate_regolith_shim)
|
72
|
+
FileUtils.chmod(0755, '.bin/regolith')
|
73
|
+
end
|
74
|
+
|
75
|
+
def generate_resource(resource_type, resource_name)
|
76
|
+
unless resource_type == 'service' && resource_name
|
77
|
+
puts "❌ Error: Invalid generate command"
|
78
|
+
puts "Usage: regolith generate service <service_name>"
|
79
|
+
exit 1
|
80
|
+
end
|
81
|
+
|
82
|
+
generate_service(resource_name)
|
83
|
+
end
|
84
|
+
|
85
|
+
def generate_service(service_name)
|
86
|
+
puts "🔧 Creating service '#{service_name}'..."
|
87
|
+
config = load_regolith_config
|
88
|
+
port = 3001 + (config['services']&.size || 0)
|
89
|
+
service_dir = "services/#{service_name}_service"
|
90
|
+
|
91
|
+
puts " → Generating Rails API app..."
|
92
|
+
|
93
|
+
cmd = [
|
94
|
+
"rails", "new", service_dir,
|
95
|
+
"--api",
|
96
|
+
"--skip-active-storage",
|
97
|
+
"--skip-action-mailbox",
|
98
|
+
"--skip-action-cable",
|
99
|
+
"--skip-bundle",
|
100
|
+
"--quiet"
|
101
|
+
]
|
102
|
+
|
103
|
+
puts "Running: #{cmd.join(' ')}"
|
104
|
+
|
105
|
+
begin
|
106
|
+
Timeout.timeout(180) do
|
107
|
+
success = system(*cmd)
|
108
|
+
unless success
|
109
|
+
puts "❌ rails new failed with exit code #{$?.exitstatus}"
|
110
|
+
exit 1
|
111
|
+
end
|
112
|
+
end
|
113
|
+
rescue Timeout::Error
|
114
|
+
puts "⏱️ rails new timed out after 3 minutes"
|
115
|
+
puts "Try running manually: #{cmd.join(' ')}"
|
116
|
+
exit 1
|
117
|
+
end
|
118
|
+
|
119
|
+
puts "🔧 Overwriting Gemfile to remove sqlite3 and other defaults..."
|
120
|
+
ruby_version = `ruby -e 'print RUBY_VERSION'`.strip
|
121
|
+
ruby_major_minor = ruby_version.split('.')[0..1].join('.')
|
122
|
+
|
123
|
+
custom_gemfile = <<~GEMFILE
|
124
|
+
source "https://rubygems.org"
|
125
|
+
ruby "~> #{ruby_major_minor}.0"
|
126
|
+
gem "rails", "~> 7.2.2.1"
|
127
|
+
gem "pg", "~> 1.5"
|
128
|
+
gem "puma", ">= 5.0"
|
129
|
+
gem "rack-cors"
|
130
|
+
|
131
|
+
group :development, :test do
|
132
|
+
gem "debug", platforms: %i[ mri mswin mswin64 mingw x64_mingw ], require: "debug/prelude"
|
133
|
+
gem "brakeman", require: false
|
134
|
+
gem "rubocop-rails-omakase", require: false
|
135
|
+
end
|
136
|
+
|
137
|
+
gem "regolith", path: "vendor/regolith"
|
138
|
+
GEMFILE
|
139
|
+
|
140
|
+
File.write("#{service_dir}/Gemfile", custom_gemfile)
|
141
|
+
|
142
|
+
vendor_dir = File.join(service_dir, "vendor")
|
143
|
+
regolith_vendor_dir = File.join(vendor_dir, "regolith")
|
144
|
+
FileUtils.mkdir_p(vendor_dir)
|
145
|
+
source_dir = File.expand_path("../..", __dir__)
|
146
|
+
FileUtils.cp_r(source_dir, regolith_vendor_dir)
|
147
|
+
Dir.glob(File.join(regolith_vendor_dir, "regolith-*")).each { |nested_dir| FileUtils.rm_rf(nested_dir) }
|
148
|
+
|
149
|
+
gemspec_path = File.join(regolith_vendor_dir, "regolith.gemspec")
|
150
|
+
File.write(gemspec_path, generate_regolith_gemspec) unless File.exist?(gemspec_path)
|
151
|
+
|
152
|
+
puts "📦 Vendored Regolith gem into #{regolith_vendor_dir}"
|
153
|
+
|
154
|
+
puts " → Running bundle install..."
|
155
|
+
Dir.chdir(service_dir) do
|
156
|
+
unless system("bundle install")
|
157
|
+
puts "❌ bundle install failed"
|
158
|
+
puts "→ You may be missing system libraries like libyaml-dev libsqlite3-dev build-essential pkg-config"
|
159
|
+
puts "→ Try: sudo apt install -y libyaml-dev libsqlite3-dev build-essential pkg-config"
|
160
|
+
exit 1
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
patch_rails_app(service_dir, service_name, port)
|
165
|
+
|
166
|
+
config['services'][service_name] = {
|
167
|
+
'port' => port,
|
168
|
+
'root' => "./#{service_dir}"
|
169
|
+
}
|
170
|
+
save_regolith_config(config)
|
171
|
+
update_docker_compose(config)
|
172
|
+
|
173
|
+
puts "✅ Created service '#{service_name}'"
|
174
|
+
puts "🚀 Service running on port #{port}"
|
175
|
+
puts "→ Next: regolith generate service <another_service> or regolith server"
|
176
|
+
end
|
177
|
+
|
178
|
+
def patch_rails_app(service_dir, service_name, port)
|
179
|
+
initializer_dir = "#{service_dir}/config/initializers"
|
180
|
+
FileUtils.mkdir_p(initializer_dir)
|
181
|
+
File.write("#{initializer_dir}/regolith.rb", generate_regolith_initializer(service_name))
|
182
|
+
File.write("#{service_dir}/Dockerfile", generate_dockerfile)
|
183
|
+
|
184
|
+
app_rb_path = "#{service_dir}/config/application.rb"
|
185
|
+
app_rb_content = File.read(app_rb_path)
|
186
|
+
|
187
|
+
# Ensure Regolith config block is inserted safely
|
188
|
+
insert_block = <<~RUBY
|
189
|
+
|
190
|
+
# Regolith configuration
|
191
|
+
config.middleware.insert_before 0, Rack::Cors do
|
192
|
+
allow do
|
193
|
+
origins '*'
|
194
|
+
resource '*', headers: :any, methods: [:get, :post, :put, :patch, :delete, :options, :head]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
config.regolith_service_name = '#{service_name}'
|
199
|
+
config.regolith_service_port = #{port}
|
200
|
+
RUBY
|
201
|
+
|
202
|
+
app_rb_lines = app_rb_content.lines
|
203
|
+
target_index = app_rb_lines.index { |line| line =~ /^\s*class Application < Rails::Application/ }
|
204
|
+
|
205
|
+
if target_index
|
206
|
+
insertion_point = app_rb_lines.index { |line| line.strip == 'end' && app_rb_lines.index(line) > target_index }
|
207
|
+
if insertion_point
|
208
|
+
app_rb_lines.insert(insertion_point, insert_block)
|
209
|
+
File.write(app_rb_path, app_rb_lines.join)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Clean up boot.rb again just in case
|
214
|
+
boot_path = "#{service_dir}/config/boot.rb"
|
215
|
+
if File.exist?(boot_path)
|
216
|
+
clean_boot_rb = <<~RUBY
|
217
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
218
|
+
require "bundler/setup" # Set up gems listed in the Gemfile.
|
219
|
+
RUBY
|
220
|
+
File.write(boot_path, clean_boot_rb)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
def start_server
|
226
|
+
unless File.exist?('docker-compose.yml')
|
227
|
+
puts "❌ Error: Not in a Regolith app directory"
|
228
|
+
exit 1
|
229
|
+
end
|
230
|
+
|
231
|
+
puts "🚀 Starting Regolith services..."
|
232
|
+
config = load_regolith_config
|
233
|
+
|
234
|
+
config['services'].each do |name, service|
|
235
|
+
puts "🚀 #{name}_service running at http://localhost:#{service['port']}"
|
236
|
+
end
|
237
|
+
|
238
|
+
puts "🏭 Service registry loaded from config/regolith.yml"
|
239
|
+
puts ""
|
240
|
+
|
241
|
+
exec("docker-compose up --build")
|
242
|
+
end
|
243
|
+
|
244
|
+
def open_console(service_name)
|
245
|
+
unless service_name
|
246
|
+
puts "❌ Error: Service name required"
|
247
|
+
puts "Usage: regolith console <service_name>"
|
248
|
+
exit 1
|
249
|
+
end
|
250
|
+
|
251
|
+
config = load_regolith_config
|
252
|
+
unless config['services'][service_name]
|
253
|
+
puts "❌ Error: Service '#{service_name}' not found"
|
254
|
+
exit 1
|
255
|
+
end
|
256
|
+
|
257
|
+
puts "🧪 Opening Rails console for #{service_name}_service..."
|
258
|
+
exec("docker-compose exec #{service_name} rails console")
|
259
|
+
end
|
260
|
+
|
261
|
+
def load_regolith_config
|
262
|
+
return { 'services' => {} } unless File.exist?('config/regolith.yml')
|
263
|
+
config = YAML.load_file('config/regolith.yml') || {}
|
264
|
+
config['services'] ||= {}
|
265
|
+
config
|
266
|
+
end
|
267
|
+
|
268
|
+
def save_regolith_config(config)
|
269
|
+
FileUtils.mkdir_p('config')
|
270
|
+
File.write('config/regolith.yml', YAML.dump(config))
|
271
|
+
end
|
272
|
+
|
273
|
+
def update_docker_compose(config)
|
274
|
+
docker_compose = generate_docker_compose(config['name'], config['services'])
|
275
|
+
File.write('docker-compose.yml', docker_compose)
|
276
|
+
end
|
277
|
+
|
278
|
+
def generate_docker_compose(app_name, services = {})
|
279
|
+
template = <<~YAML
|
280
|
+
version: '3.8'
|
281
|
+
|
282
|
+
services:
|
283
|
+
db:
|
284
|
+
image: postgres:14
|
285
|
+
environment:
|
286
|
+
POSTGRES_DB: #{app_name}_development
|
287
|
+
POSTGRES_USER: postgres
|
288
|
+
POSTGRES_PASSWORD: password
|
289
|
+
ports:
|
290
|
+
- "5432:5432"
|
291
|
+
volumes:
|
292
|
+
- postgres_data:/var/lib/postgresql/data
|
293
|
+
|
294
|
+
<% services.each do |name, service| %>
|
295
|
+
<%= name %>:
|
296
|
+
build: <%= service['root'] %>
|
297
|
+
ports:
|
298
|
+
- "<%= service['port'] %>:3000"
|
299
|
+
depends_on:
|
300
|
+
- db
|
301
|
+
environment:
|
302
|
+
DATABASE_URL: postgres://postgres:password@db:5432/<%= app_name %>_development
|
303
|
+
REGOLITH_SERVICE_NAME: <%= name %>
|
304
|
+
REGOLITH_SERVICE_PORT: <%= service['port'] %>
|
305
|
+
volumes:
|
306
|
+
- <%= service['root'] %>:/app
|
307
|
+
command: bash -c "rm -f tmp/pids/server.pid && bundle install && rails server -b 0.0.0.0"
|
308
|
+
<% end %>
|
309
|
+
|
310
|
+
volumes:
|
311
|
+
postgres_data:
|
312
|
+
YAML
|
313
|
+
|
314
|
+
ERB.new(template).result(binding)
|
315
|
+
end
|
316
|
+
|
317
|
+
def generate_dockerfile
|
318
|
+
<<~DOCKERFILE
|
319
|
+
FROM ruby:3.1
|
320
|
+
|
321
|
+
WORKDIR /app
|
322
|
+
|
323
|
+
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client libyaml-dev libsqlite3-dev build-essential pkg-config
|
324
|
+
|
325
|
+
COPY . .
|
326
|
+
|
327
|
+
RUN bundle install
|
328
|
+
|
329
|
+
EXPOSE 3000
|
330
|
+
|
331
|
+
CMD ["rails", "server", "-b", "0.0.0.0"]
|
332
|
+
DOCKERFILE
|
333
|
+
end
|
334
|
+
|
335
|
+
def generate_regolith_initializer(service_name)
|
336
|
+
<<~RUBY
|
337
|
+
# Regolith service configuration
|
338
|
+
Rails.application.configure do
|
339
|
+
config.regolith = OpenStruct.new(
|
340
|
+
service_name: '#{service_name}',
|
341
|
+
service_registry: Rails.root.join('../../config/regolith.yml')
|
342
|
+
)
|
343
|
+
end
|
344
|
+
|
345
|
+
if File.exist?(Rails.application.config.regolith.service_registry)
|
346
|
+
REGOLITH_SERVICES = YAML.load_file(Rails.application.config.regolith.service_registry)['services'] || {}
|
347
|
+
else
|
348
|
+
REGOLITH_SERVICES = {}
|
349
|
+
end
|
350
|
+
RUBY
|
351
|
+
end
|
352
|
+
|
353
|
+
def generate_makefile
|
354
|
+
<<~MAKEFILE
|
355
|
+
.PHONY: server console build clean
|
356
|
+
|
357
|
+
server:
|
358
|
+
regolith server
|
359
|
+
|
360
|
+
console:
|
361
|
+
regolith console
|
362
|
+
|
363
|
+
build:
|
364
|
+
docker-compose build
|
365
|
+
|
366
|
+
clean:
|
367
|
+
docker-compose down -v
|
368
|
+
docker system prune -f
|
369
|
+
MAKEFILE
|
370
|
+
end
|
371
|
+
|
372
|
+
def generate_regolith_shim
|
373
|
+
<<~RUBY
|
374
|
+
#!/usr/bin/env ruby
|
375
|
+
exec("regolith", *ARGV)
|
376
|
+
RUBY
|
377
|
+
end
|
378
|
+
|
379
|
+
def generate_regolith_gemspec
|
380
|
+
<<~GEMSPEC
|
381
|
+
# -*- encoding: utf-8 -*-
|
382
|
+
lib = File.expand_path('../lib', __FILE__)
|
383
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
384
|
+
require 'regolith/version'
|
385
|
+
|
386
|
+
Gem::Specification.new do |gem|
|
387
|
+
gem.name = "regolith"
|
388
|
+
gem.version = Regolith::VERSION
|
389
|
+
gem.authors = ["Regolith Team"]
|
390
|
+
gem.email = ["team@regolith.dev"]
|
391
|
+
gem.description = %q{Microservices framework for Ruby}
|
392
|
+
gem.summary = %q{Build microservices with Ruby and Rails}
|
393
|
+
gem.homepage = "https://github.com/regolith/regolith"
|
394
|
+
|
395
|
+
gem.files = Dir['lib/**/*'] + ['README.md']
|
396
|
+
gem.executables = ['regolith']
|
397
|
+
gem.test_files = []
|
398
|
+
gem.require_paths = ["lib"]
|
399
|
+
|
400
|
+
gem.add_dependency "rails", ">= 7.0"
|
401
|
+
gem.add_dependency "rack-cors"
|
402
|
+
end
|
403
|
+
GEMSPEC
|
404
|
+
end
|
405
|
+
|
406
|
+
def show_help
|
407
|
+
puts <<~HELP
|
408
|
+
Regolith #{Regolith::VERSION} - Microservices framework
|
409
|
+
|
410
|
+
USAGE:
|
411
|
+
regolith <command> [options]
|
412
|
+
|
413
|
+
COMMANDS:
|
414
|
+
new <app_name> Create a new Regolith application
|
415
|
+
generate service <name> Generate a new microservice
|
416
|
+
server Start all services with Docker Compose
|
417
|
+
console <service_name> Open Rails console for a service
|
418
|
+
version Show version information
|
419
|
+
|
420
|
+
EXAMPLES:
|
421
|
+
regolith new observatory
|
422
|
+
regolith generate service telescope
|
423
|
+
regolith generate service records
|
424
|
+
regolith server
|
425
|
+
regolith console telescope
|
426
|
+
|
427
|
+
Get started:
|
428
|
+
regolith new myapp
|
429
|
+
cd myapp
|
430
|
+
regolith generate service users
|
431
|
+
regolith server
|
432
|
+
HELP
|
433
|
+
end
|
434
|
+
end
|
435
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# lib/regolith/regolith_association.rb
|
2
|
+
module Regolith
|
3
|
+
class RegolithAssociation
|
4
|
+
def initialize(parent_record, association_name, service, type, foreign_key_value = nil)
|
5
|
+
@parent_record = parent_record
|
6
|
+
@association_name = association_name
|
7
|
+
@service = service
|
8
|
+
@type = type
|
9
|
+
@foreign_key_value = foreign_key_value
|
10
|
+
@loaded_records = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def create!(attributes = {})
|
14
|
+
case @type
|
15
|
+
when :has_many
|
16
|
+
# For has_many, set the foreign key to parent's id
|
17
|
+
foreign_key = "#{@parent_record.class.name.underscore}_id"
|
18
|
+
attributes[foreign_key] = @parent_record.id
|
19
|
+
|
20
|
+
# Create in the target service
|
21
|
+
target_class = @association_name.to_s.singularize.camelize.constantize
|
22
|
+
target_class.create(attributes)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def first
|
27
|
+
case @type
|
28
|
+
when :belongs_to
|
29
|
+
target_class = @association_name.to_s.camelize.constantize
|
30
|
+
target_class.find(@foreign_key_value)
|
31
|
+
when :has_many
|
32
|
+
all.first
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def all
|
37
|
+
load_records unless @loaded_records
|
38
|
+
@loaded_records
|
39
|
+
end
|
40
|
+
|
41
|
+
def method_missing(method_name, *args, &block)
|
42
|
+
all.send(method_name, *args, &block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def respond_to_missing?(method_name, include_private = false)
|
46
|
+
all.respond_to?(method_name, include_private) || super
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def load_records
|
52
|
+
case @type
|
53
|
+
when :has_many
|
54
|
+
# Query the target service for records that belong to this parent
|
55
|
+
foreign_key = "#{@parent_record.class.name.underscore}_id"
|
56
|
+
target_service = @service
|
57
|
+
resource_name = @association_name.to_s
|
58
|
+
|
59
|
+
response = ServiceClient.get(
|
60
|
+
target_service,
|
61
|
+
"#{resource_name}?#{foreign_key}=#{@parent_record.id}"
|
62
|
+
)
|
63
|
+
|
64
|
+
if response.code == '200'
|
65
|
+
data = JSON.parse(response.body)
|
66
|
+
target_class = @association_name.to_s.singularize.camelize.constantize
|
67
|
+
@loaded_records = data.map { |attrs| target_class.new(attrs) }
|
68
|
+
else
|
69
|
+
@loaded_records = []
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# lib/regolith/regolith_record.rb
|
2
|
+
module Regolith
|
3
|
+
class RegolithRecord
|
4
|
+
include ActiveModel::Model
|
5
|
+
include ActiveModel::Attributes
|
6
|
+
include ActiveModel::Serialization
|
7
|
+
|
8
|
+
class_attribute :service_name, :resource_name, :primary_key
|
9
|
+
self.primary_key = :id
|
10
|
+
|
11
|
+
def self.inherited(subclass)
|
12
|
+
super
|
13
|
+
# Auto-detect service from class name or allow explicit setting
|
14
|
+
subclass.resource_name = subclass.name.underscore
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.service(service_name)
|
18
|
+
self.service_name = service_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.has_many(association_name, options = {})
|
22
|
+
service = options[:service]
|
23
|
+
|
24
|
+
define_method(association_name) do
|
25
|
+
RegolithAssociation.new(
|
26
|
+
self,
|
27
|
+
association_name,
|
28
|
+
service,
|
29
|
+
:has_many
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.belongs_to(association_name, options = {})
|
35
|
+
service = options[:service]
|
36
|
+
foreign_key = options[:foreign_key] || "#{association_name}_id"
|
37
|
+
|
38
|
+
# Add the foreign key attribute
|
39
|
+
attribute foreign_key, :integer
|
40
|
+
|
41
|
+
define_method(association_name) do
|
42
|
+
foreign_key_value = send(foreign_key)
|
43
|
+
return nil unless foreign_key_value
|
44
|
+
|
45
|
+
RegolithAssociation.new(
|
46
|
+
self,
|
47
|
+
association_name,
|
48
|
+
service,
|
49
|
+
:belongs_to,
|
50
|
+
foreign_key_value
|
51
|
+
).first
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.find(id)
|
56
|
+
response = ServiceClient.get(service_name, "#{resource_name}/#{id}")
|
57
|
+
if response.code == '200'
|
58
|
+
new(JSON.parse(response.body))
|
59
|
+
else
|
60
|
+
raise ActiveRecord::RecordNotFound, "Couldn't find #{name} with 'id'=#{id}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.all
|
65
|
+
response = ServiceClient.get(service_name, resource_name)
|
66
|
+
if response.code == '200'
|
67
|
+
JSON.parse(response.body).map { |attrs| new(attrs) }
|
68
|
+
else
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.create(attributes = {})
|
74
|
+
instance = new(attributes)
|
75
|
+
instance.save
|
76
|
+
instance
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.create!(attributes = {})
|
80
|
+
instance = create(attributes)
|
81
|
+
raise "Record invalid" unless instance.persisted?
|
82
|
+
instance
|
83
|
+
end
|
84
|
+
|
85
|
+
def save
|
86
|
+
if persisted?
|
87
|
+
update
|
88
|
+
else
|
89
|
+
create
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def create
|
94
|
+
response = ServiceClient.post(
|
95
|
+
self.class.service_name,
|
96
|
+
self.class.resource_name,
|
97
|
+
attributes.to_json
|
98
|
+
)
|
99
|
+
|
100
|
+
if response.code.to_i.between?(200, 299)
|
101
|
+
data = JSON.parse(response.body)
|
102
|
+
data.each { |key, value| send("#{key}=", value) if respond_to?("#{key}=") }
|
103
|
+
true
|
104
|
+
else
|
105
|
+
false
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def update
|
110
|
+
response = ServiceClient.put(
|
111
|
+
self.class.service_name,
|
112
|
+
"#{self.class.resource_name}/#{id}",
|
113
|
+
attributes.to_json
|
114
|
+
)
|
115
|
+
|
116
|
+
response.code.to_i.between?(200, 299)
|
117
|
+
end
|
118
|
+
|
119
|
+
def destroy
|
120
|
+
response = ServiceClient.delete(
|
121
|
+
self.class.service_name,
|
122
|
+
"#{self.class.resource_name}/#{id}"
|
123
|
+
)
|
124
|
+
|
125
|
+
response.code.to_i.between?(200, 299)
|
126
|
+
end
|
127
|
+
|
128
|
+
def persisted?
|
129
|
+
id.present?
|
130
|
+
end
|
131
|
+
|
132
|
+
def id
|
133
|
+
send(self.class.primary_key) if respond_to?(self.class.primary_key)
|
134
|
+
end
|
135
|
+
|
136
|
+
def id=(value)
|
137
|
+
send("#{self.class.primary_key}=", value) if respond_to?("#{self.class.primary_key}=")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# lib/regolith/service_client.rb
|
2
|
+
module Regolith
|
3
|
+
class ServiceClient
|
4
|
+
class << self
|
5
|
+
def get(service_name, path)
|
6
|
+
make_request(service_name, :get, path)
|
7
|
+
end
|
8
|
+
|
9
|
+
def post(service_name, path, body = nil)
|
10
|
+
make_request(service_name, :post, path, body)
|
11
|
+
end
|
12
|
+
|
13
|
+
def put(service_name, path, body = nil)
|
14
|
+
make_request(service_name, :put, path, body)
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete(service_name, path)
|
18
|
+
make_request(service_name, :delete, path)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def make_request(service_name, method, path, body = nil)
|
24
|
+
service_config = Regolith.service_registry[service_name.to_s]
|
25
|
+
|
26
|
+
unless service_config
|
27
|
+
raise "Service '#{service_name}' not found in registry"
|
28
|
+
end
|
29
|
+
|
30
|
+
# In Docker Compose, services can be reached by service name
|
31
|
+
# In development, use localhost with the mapped port
|
32
|
+
host = in_docker? ? service_name.to_s : 'localhost'
|
33
|
+
port = in_docker? ? 3000 : service_config['port']
|
34
|
+
|
35
|
+
uri = URI("http://#{host}:#{port}/#{path}")
|
36
|
+
|
37
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
38
|
+
http.read_timeout = Regolith.configuration.timeout
|
39
|
+
|
40
|
+
case method
|
41
|
+
when :get
|
42
|
+
request = Net::HTTP::Get.new(uri)
|
43
|
+
when :post
|
44
|
+
request = Net::HTTP::Post.new(uri)
|
45
|
+
request.body = body if body
|
46
|
+
request['Content-Type'] = 'application/json'
|
47
|
+
when :put
|
48
|
+
request = Net::HTTP::Put.new(uri)
|
49
|
+
request.body = body if body
|
50
|
+
request['Content-Type'] = 'application/json'
|
51
|
+
when :delete
|
52
|
+
request = Net::HTTP::Delete.new(uri)
|
53
|
+
end
|
54
|
+
|
55
|
+
begin
|
56
|
+
http.request(request)
|
57
|
+
rescue => e
|
58
|
+
# Return a mock response for connection errors
|
59
|
+
OpenStruct.new(code: '500', body: { error: e.message }.to_json)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def in_docker?
|
64
|
+
File.exist?('/.dockerenv') || ENV['REGOLITH_SERVICE_NAME'].present?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/regolith.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# lib/regolith.rb
|
2
|
+
require 'active_support/all'
|
3
|
+
require 'active_model'
|
4
|
+
require 'net/http'
|
5
|
+
require 'json'
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
require_relative 'regolith/version'
|
9
|
+
require_relative 'regolith/service_client'
|
10
|
+
require_relative 'regolith/regolith_association'
|
11
|
+
require_relative 'regolith/regolith_record'
|
12
|
+
require_relative 'regolith/cli'
|
13
|
+
|
14
|
+
module Regolith
|
15
|
+
class << self
|
16
|
+
def configure
|
17
|
+
yield(configuration)
|
18
|
+
end
|
19
|
+
|
20
|
+
def configuration
|
21
|
+
@configuration ||= Configuration.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def service_registry
|
25
|
+
@service_registry ||= load_service_registry
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def load_service_registry
|
31
|
+
if defined?(Rails) && Rails.application.config.respond_to?(:regolith)
|
32
|
+
registry_path = Rails.application.config.regolith.service_registry
|
33
|
+
if File.exist?(registry_path)
|
34
|
+
YAML.load_file(registry_path)['services'] || {}
|
35
|
+
else
|
36
|
+
{}
|
37
|
+
end
|
38
|
+
else
|
39
|
+
defined?(REGOLITH_SERVICES) ? REGOLITH_SERVICES : {}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Configuration
|
45
|
+
attr_accessor :service_name, :service_port, :timeout
|
46
|
+
|
47
|
+
def initialize
|
48
|
+
@timeout = 30
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/regolith.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# regolith.gemspec
|
2
|
+
require_relative 'lib/regolith/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "regolith"
|
6
|
+
spec.version = Regolith::VERSION
|
7
|
+
spec.authors = ["Regolith Team"]
|
8
|
+
spec.email = ["team@regolith.dev"]
|
9
|
+
|
10
|
+
spec.summary = "Rails for distributed systems"
|
11
|
+
spec.description = "Regolith provides seamless inter-service communication and orchestration for Ruby microservices"
|
12
|
+
spec.homepage = "https://github.com/regolith/regolith"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.required_ruby_version = ">= 2.7.0"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/regolith/regolith"
|
19
|
+
spec.metadata["changelog_uri"] = "https://github.com/regolith/regolith/CHANGELOG.md"
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
23
|
+
Dir['lib/**/*', 'bin/*', '*.md', '*.txt', 'LICENSE*', 'regolith.gemspec']
|
24
|
+
end
|
25
|
+
|
26
|
+
spec.bindir = "bin"
|
27
|
+
spec.executables = ["regolith"]
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
|
30
|
+
# Dependencies
|
31
|
+
spec.add_dependency "activesupport", ">= 6.0"
|
32
|
+
spec.add_dependency "activemodel", ">= 6.0"
|
33
|
+
|
34
|
+
# Development dependencies
|
35
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
36
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: regolith
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Regolith Team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2025-07-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activemodel
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '6.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '6.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '13.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '13.0'
|
69
|
+
description: Regolith provides seamless inter-service communication and orchestration
|
70
|
+
for Ruby microservices
|
71
|
+
email:
|
72
|
+
- team@regolith.dev
|
73
|
+
executables:
|
74
|
+
- regolith
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- CHANGELOG.md
|
79
|
+
- LICENSE
|
80
|
+
- README.md
|
81
|
+
- bin/regolith
|
82
|
+
- lib/regolith.rb
|
83
|
+
- lib/regolith/cli.rb
|
84
|
+
- lib/regolith/regolith_association.rb
|
85
|
+
- lib/regolith/regolith_record.rb
|
86
|
+
- lib/regolith/service_client.rb
|
87
|
+
- lib/regolith/version.rb
|
88
|
+
- regolith.gemspec
|
89
|
+
homepage: https://github.com/regolith/regolith
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata:
|
93
|
+
homepage_uri: https://github.com/regolith/regolith
|
94
|
+
source_code_uri: https://github.com/regolith/regolith
|
95
|
+
changelog_uri: https://github.com/regolith/regolith/CHANGELOG.md
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 2.7.0
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubygems_version: 3.3.15
|
112
|
+
signing_key:
|
113
|
+
specification_version: 4
|
114
|
+
summary: Rails for distributed systems
|
115
|
+
test_files: []
|