belt 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9236fac00b7efcb43f17c02fb347626f768cf7dd5d6c1d2162470176043cdfde
4
- data.tar.gz: d7998c44bfcdfa42eb4d22acca3fabf62e0005753b355f4112bbdff108682527
3
+ metadata.gz: 6527c1a9570ed74381b685347d178f0e20db869d39791c06b5685a45ba94c4dd
4
+ data.tar.gz: b60a0994c0646820e74eaf8d81918b4b52b95b570f9fc9ca3d74994b36bbfc6b
5
5
  SHA512:
6
- metadata.gz: 3ec40527e1d14fe89e8e5f3dc412e803354630126d40e9bed1a8c1dc32703ecd5a1fbffec1690ff0262ee2d1ece1895751441fc554f2cc38b86cb1d36e8b4ea8
7
- data.tar.gz: 3eaff9879994c9d2b7c3eb6b454a833bc4ae433bd544ac0c8fa3578045de96263a2871915b60d8707eaed8b512e497c88125554b45068d597d19d612a6b87209
6
+ metadata.gz: eb607dbfcc355a2b79dc82b3117f9e10937f32b9449cf6d3861685130f63271207d9b94992d1d86a5f49396acc0d7756f485b6c0db24d3aa70d738d95601fb6e
7
+ data.tar.gz: 1aa7b6eee506bc68947a8eaacc3cf773cb4929207831d21b9fac098bcf82de3a6062918faa0244bce389d4d5f680d4508f49a6e2c5a36dc843a82ad1d2164393
checksums.yaml.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -34,6 +34,8 @@ my-app/
34
34
  │ ├── routes.tf.rb # Belt provider route definitions
35
35
  │ └── schema.tf.rb # DynamoDB table schemas
36
36
  ├── lambda/
37
+ │ ├── config/
38
+ │ │ └── environment.rb # App boot file (used by console + Lambda)
37
39
  │ ├── controllers/
38
40
  │ │ └── posts_controller.rb
39
41
  │ ├── models/
@@ -41,6 +43,7 @@ my-app/
41
43
  │ ├── lib/
42
44
  │ │ └── routes.rb
43
45
  │ └── api.rb # Lambda entry point
46
+ ├── .irbrc # Console customization (optional)
44
47
  ├── Gemfile
45
48
  └── Gemfile.lock
46
49
  ```
@@ -229,6 +232,22 @@ Belt::Observability::Metrics.track_event("OrderCreated", model: "Order")
229
232
 
230
233
  Belt includes a command-line interface for project management.
231
234
 
235
+ ### `belt console` (alias: `belt c`)
236
+
237
+ Start an interactive Ruby console with your app loaded. Belt uses convention over configuration:
238
+
239
+ 1. Loads `lambda/config/environment.rb` (your app's boot file — AWS setup, models, libs)
240
+ 2. Starts IRB with `reload!` available
241
+ 3. Reads `.irbrc` from the project root (console-specific customization)
242
+
243
+ ```bash
244
+ belt console # uses BELT_ENV or defaults to 'dev'
245
+ belt c prod # specify environment explicitly
246
+ belt c dev02 --run "Customer.first" # runner mode (execute and exit)
247
+ ```
248
+
249
+ A production safety prompt is shown when the environment is `prod`.
250
+
232
251
  ### `belt routes`
233
252
 
234
253
  Display route definitions from your `infrastructure/routes.tf.rb`. This is the primary way to inspect what endpoints your app exposes.
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ module Belt
6
+ module CLI
7
+ class ConsoleCommand
8
+ def self.run(args)
9
+ new(args).run
10
+ end
11
+
12
+ def initialize(args)
13
+ @args = args
14
+ @options = {}
15
+ parse_options
16
+ end
17
+
18
+ def run
19
+ ENV['BUNDLE_GEMFILE'] ||= File.join(Belt.root, 'Gemfile')
20
+
21
+ unless File.exist?(ENV['BUNDLE_GEMFILE'])
22
+ abort "Error: No Gemfile found at #{ENV['BUNDLE_GEMFILE']}. Are you in a Belt project?"
23
+ end
24
+
25
+ @environment = @args.first || ENV['BELT_ENV'] || 'dev'
26
+ ENV['ENVIRONMENT'] = @environment
27
+
28
+ if @options[:run]
29
+ exec_runner(@options[:run])
30
+ else
31
+ exec_console
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def parse_options
38
+ OptionParser.new do |opts|
39
+ opts.banner = 'Usage: belt console [environment] [options]'
40
+ opts.on('--run COMMAND', 'Execute a command and exit') { |cmd| @options[:run] = cmd }
41
+ opts.on('-h', '--help', 'Show this help') do
42
+ puts opts
43
+ exit
44
+ end
45
+ end.parse!(@args)
46
+ end
47
+
48
+ def exec_console
49
+ production_guard!
50
+ boot_app
51
+ puts banner
52
+ ARGV.clear
53
+ require 'irb'
54
+ IRB.start
55
+ end
56
+
57
+ def exec_runner(command)
58
+ boot_app
59
+ result = eval(command) # rubocop:disable Security/Eval
60
+ puts format_result(result)
61
+ rescue StandardError => e
62
+ abort "Error: #{e.class}: #{e.message}\n#{e.backtrace.first(5).join("\n")}"
63
+ end
64
+
65
+ def boot_app
66
+ require 'bundler/setup'
67
+
68
+ environment_file = File.join(Belt.root, 'lambda', 'config', 'environment.rb')
69
+ if File.exist?(environment_file)
70
+ load environment_file
71
+ else
72
+ require 'belt'
73
+ load_dir('lib')
74
+ load_dir('models')
75
+ end
76
+
77
+ define_reload!
78
+ end
79
+
80
+ def load_dir(subdir)
81
+ dir = File.join(Belt.root, 'lambda', subdir)
82
+ Dir.glob(File.join(dir, '**', '*.rb')).each { |f| require f } if Dir.exist?(dir)
83
+ end
84
+
85
+ def define_reload!
86
+ root = Belt.root
87
+ Kernel.define_method(:reload!) do
88
+ %w[lib models].each do |subdir|
89
+ dir = File.join(root, 'lambda', subdir)
90
+ Dir.glob(File.join(dir, '**', '*.rb')).each { |f| load f } if Dir.exist?(dir)
91
+ end
92
+ puts '♻️ Reloaded'
93
+ end
94
+ end
95
+
96
+ def production_guard!
97
+ return unless @environment == 'prod'
98
+
99
+ $stdout.write "\n⚠️ WARNING: You are entering the PRODUCTION console!\nType 'yes' to continue: "
100
+ response = $stdin.gets&.chomp
101
+ abort "\n❌ Cancelled." unless response&.downcase == 'yes'
102
+ puts "\n✅ Entering production console...\n"
103
+ end
104
+
105
+ def banner
106
+ <<~BANNER
107
+
108
+ Belt Console (#{@environment})
109
+ Type 'reload!' to reload code.
110
+
111
+ BANNER
112
+ end
113
+
114
+ def format_result(result)
115
+ require 'json'
116
+ if result.respond_to?(:to_h)
117
+ JSON.pretty_generate(result.to_h)
118
+ elsif result.respond_to?(:map) && result.respond_to?(:first) && result.first.respond_to?(:to_h)
119
+ JSON.pretty_generate(result.map(&:to_h))
120
+ elsif result.nil?
121
+ 'nil'
122
+ else
123
+ result.inspect
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
@@ -71,6 +71,7 @@ module Belt
71
71
  #{@app_name}/lambda/models
72
72
  #{@app_name}/lambda/models/concerns
73
73
  #{@app_name}/lambda/lib/routes
74
+ #{@app_name}/lambda/config
74
75
  #{@app_name}/lambda/spec
75
76
  #{@app_name}/infrastructure
76
77
  ]
@@ -80,8 +81,8 @@ module Belt
80
81
  {
81
82
  'Gemfile.erb' => "#{@app_name}/Gemfile",
82
83
  'Rakefile.erb' => "#{@app_name}/Rakefile",
83
- 'lambda/Gemfile.erb' => "#{@app_name}/lambda/Gemfile",
84
84
  'lambda/api.rb.erb' => "#{@app_name}/lambda/#{@app_name}.rb",
85
+ 'lambda/config/environment.rb.erb' => "#{@app_name}/lambda/config/environment.rb",
85
86
  'lambda/models/application_record.rb.erb' => "#{@app_name}/lambda/models/application_record.rb",
86
87
  'lambda/models/concerns/timestampable.rb.erb' => "#{@app_name}/lambda/models/concerns/timestampable.rb",
87
88
  'lambda/controllers/application_controller.rb.erb' =>
@@ -16,13 +16,7 @@ module Belt
16
16
 
17
17
  return non_param.map { |s| s.gsub('-', '_') }.join('/') if route.resource? && nested_resource?(segments)
18
18
 
19
- if route.resource?
20
- non_param.first.gsub('-', '_')
21
- elsif non_param.length == 1 && segments.length == 1
22
- route.lambda.to_s == gateway.name.to_s ? gateway.name.to_s : route.lambda.to_s
23
- else
24
- non_param.first.gsub('-', '_')
25
- end
19
+ non_param.first.gsub('-', '_')
26
20
  end
27
21
 
28
22
  def infer_action(route, _gateway)
data/lib/belt/cli.rb CHANGED
@@ -13,6 +13,7 @@ require_relative 'cli/setup_command'
13
13
  require_relative 'cli/terraform_command'
14
14
  require_relative 'cli/routes_command'
15
15
  require_relative 'cli/tasks_command'
16
+ require_relative 'cli/console_command'
16
17
 
17
18
  module Belt
18
19
  module CLI
@@ -20,6 +21,7 @@ module Belt
20
21
  'new' => Belt::CLI::NewCommand,
21
22
  %w[generate g] => Belt::CLI::GenerateCommand,
22
23
  'routes' => Belt::CLI::RoutesCommand,
24
+ %w[console c] => Belt::CLI::ConsoleCommand,
23
25
  %w[tasks --tasks -T] => Belt::CLI::TasksCommand,
24
26
  'setup' => Belt::CLI::SetupCommand,
25
27
  'deploy' => lambda { |args|
@@ -79,6 +81,8 @@ module Belt
79
81
  generate views <resource> [fields...] Generate React pages for REST actions
80
82
  generate environment <name> Create a new environment
81
83
  routes [-g PATTERN] [-f json] Show route definitions
84
+ console Start an interactive console (IRB)
85
+ c Alias for console
82
86
  tasks [-g PATTERN] [-a] List available rake tasks
83
87
  -T [-g PATTERN] [-a] Alias for tasks
84
88
  setup state Create/select S3 state bucket
data/lib/belt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Belt
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.2'
5
5
  end
@@ -2,4 +2,6 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
+ gem 'activeitem'
5
6
  gem 'belt'
7
+ gem 'lambda_loadout'
@@ -1,13 +1,13 @@
1
1
  /.bundle
2
2
  /vendor/bundle
3
3
  *.gem
4
- Gemfile.lock
5
4
 
6
5
  # Terraform
7
6
  .terraform/
8
7
  *.tfstate
9
8
  *.tfstate.backup
10
9
  .terraform.lock.hcl
10
+ *.tfvars
11
11
 
12
12
  # Lambda build artifacts
13
13
  /lambda/vendor/
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Boot the application. Used by `belt console` and Lambda at runtime.
4
+
5
+ require 'belt'
6
+ require 'activeitem'
7
+
8
+ ENV['APP_NAME'] ||= '<%= @app_name %>'
9
+ ENV['AWS_REGION'] ||= 'us-east-1'
10
+
11
+ ActiveItem.configure do |config|
12
+ config.table_prefix = ENV['APP_NAME']
13
+ config.environment = ENV['ENVIRONMENT']
14
+ end
15
+
16
+ # Load lib and models
17
+ Dir[File.join(__dir__, '..', 'lib', '**', '*.rb')].sort.each { |f| require f }
18
+ Dir[File.join(__dir__, '..', 'models', '**', '*.rb')].sort.each { |f| require f }
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: belt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stowzilla
@@ -83,6 +83,7 @@ files:
83
83
  - lib/belt/cli.rb
84
84
  - lib/belt/cli/app_detection.rb
85
85
  - lib/belt/cli/bucket_security.rb
86
+ - lib/belt/cli/console_command.rb
86
87
  - lib/belt/cli/env_resolver.rb
87
88
  - lib/belt/cli/environment_command.rb
88
89
  - lib/belt/cli/frontend_command.rb
@@ -131,8 +132,8 @@ files:
131
132
  - lib/templates/new_app/gitignore.erb
132
133
  - lib/templates/new_app/infrastructure/routes.tf.rb.erb
133
134
  - lib/templates/new_app/infrastructure/schema.tf.rb.erb
134
- - lib/templates/new_app/lambda/Gemfile.erb
135
135
  - lib/templates/new_app/lambda/api.rb.erb
136
+ - lib/templates/new_app/lambda/config/environment.rb.erb
136
137
  - lib/templates/new_app/lambda/controllers/application_controller.rb.erb
137
138
  - lib/templates/new_app/lambda/lib/routes/routes.rb.erb
138
139
  - lib/templates/new_app/lambda/models/application_record.rb.erb
metadata.gz.sig CHANGED
Binary file
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source 'https://rubygems.org'
4
-
5
- gem 'activeitem'
6
- gem 'belt'
7
- gem 'lambda_loadout'