Class: Everywhere::Framework
- Inherits:
-
Object
- Object
- Everywhere::Framework
- Defined in:
- lib/everywhere/framework.rb
Overview
Framework adapters keep both the CLI (dev/build) and the packaged runtime (boot) framework-agnostic. Each adapter owns two sides of one framework:
CLI side — dev_command / precompile_* / cleanup_command (build.rb, dev.rb)
runtime side — prepare_runtime_env / boot! (boot.rb, inside the binary)
Rails keeps its own boot path (Rails::Command server, multi-db prepare_all). Sinatra and Hanami are plain Rack apps and share RackFramework's boot: load config.ru, prepare the database, serve it under Puma bound to localhost.
Defined Under Namespace
Classes: Hanami, RackFramework, Rails, Sinatra
Constant Summary collapse
- GEMFILE_NAMES =
Bundler reads either name, and
gem "rails"/gem("rails")are the same line to it. Anchored at the start of the line so a commented-out gem — the usual reason a Gemfile still mentions one — doesn't count as detection. %w[Gemfile gems.rb].freeze
Instance Attribute Summary collapse
-
#root ⇒ Object
readonly
Returns the value of attribute root.
Class Method Summary collapse
- .detect(root = Dir.pwd) ⇒ Object
- .gemfile_mentions?(root, gem_name) ⇒ Boolean
- .hanami?(root) ⇒ Boolean
- .rails?(root) ⇒ Boolean
-
.read_source(path) ⇒ Object
Gemfiles are UTF-8, but the process may be running under LANG=C, where File.read tags the bytes as US-ASCII and any accented comment makes the match raise instead of answering.
- .sinatra?(root) ⇒ Boolean
Instance Method Summary collapse
-
#boot!(port:) ⇒ Object
Load the app, prepare its database, and start the server bound to 127.0.0.1:port.
-
#boot_stub ⇒ Object
The native_boot.rb entry point
every installwrites. -
#env_exports ⇒ Object
Env each framework needs set before the app loads, beyond NATIVE_PACKAGED.
-
#initialize(root) ⇒ Framework
constructor
A new instance of Framework.
-
#load_rack_app ⇒ Object
Build the Rack app from config.ru.
-
#precompile? ⇒ Boolean
Whether the build must run anything against the app's bundle on the HOST Ruby (asset precompile).
-
#prepare_runtime_env ⇒ Object
Set framework-specific env before the app loads.
- #render_boot_stub(env, setup_line) ⇒ Object
-
#serve_rack(app, port:) ⇒ Object
Serve a Rack app under Puma on localhost.
Constructor Details
Instance Attribute Details
#root ⇒ Object (readonly)
Returns the value of attribute root.
55 56 57 |
# File 'lib/everywhere/framework.rb', line 55 def root @root end |
Class Method Details
.detect(root = Dir.pwd) ⇒ Object
14 15 16 17 18 19 20 |
# File 'lib/everywhere/framework.rb', line 14 def self.detect(root = Dir.pwd) return Rails.new(root) if rails?(root) return Hanami.new(root) if hanami?(root) return Sinatra.new(root) if sinatra?(root) raise Error, "No supported framework detected in #{root} (looked for Rails, Hanami, Sinatra)" end |
.gemfile_mentions?(root, gem_name) ⇒ Boolean
40 41 42 43 44 45 46 |
# File 'lib/everywhere/framework.rb', line 40 def self.gemfile_mentions?(root, gem_name) pattern = /^\s*gem[\s(]+["']#{Regexp.escape(gem_name)}/ GEMFILE_NAMES.any? do |name| path = File.join(root, name) File.exist?(path) && read_source(path).match?(pattern) end end |
.hanami?(root) ⇒ Boolean
27 28 29 |
# File 'lib/everywhere/framework.rb', line 27 def self.hanami?(root) File.exist?(File.join(root, "config", "app.rb")) && gemfile_mentions?(root, "hanami") end |
.rails?(root) ⇒ Boolean
22 23 24 25 |
# File 'lib/everywhere/framework.rb', line 22 def self.rails?(root) File.exist?(File.join(root, "config", "application.rb")) && gemfile_mentions?(root, "rails") end |
.read_source(path) ⇒ Object
Gemfiles are UTF-8, but the process may be running under LANG=C, where File.read tags the bytes as US-ASCII and any accented comment makes the match raise instead of answering.
51 52 53 |
# File 'lib/everywhere/framework.rb', line 51 def self.read_source(path) File.read(path, encoding: "UTF-8").scrub end |
Instance Method Details
#boot!(port:) ⇒ Object
Load the app, prepare its database, and start the server bound to 127.0.0.1:port. Blocks. Implemented per framework.
68 69 70 |
# File 'lib/everywhere/framework.rb', line 68 def boot!(port:) raise NotImplementedError, "#{name} has no packaged boot path yet" end |
#boot_stub ⇒ Object
The native_boot.rb entry point every install writes. Frameworks differ
in which env they set and how the bundle is loaded before the gem.
84 85 86 |
# File 'lib/everywhere/framework.rb', line 84 def boot_stub render_boot_stub(env_exports, "require \"bundler/setup\"") end |
#env_exports ⇒ Object
Env each framework needs set before the app loads, beyond NATIVE_PACKAGED.
89 |
# File 'lib/everywhere/framework.rb', line 89 def env_exports = {} |
#load_rack_app ⇒ Object
Build the Rack app from config.ru. Rack 3 returns the app; Rack 2 returned [app, options].
74 75 76 77 78 |
# File 'lib/everywhere/framework.rb', line 74 def load_rack_app require "rack" built = ::Rack::Builder.parse_file(File.join(root, "config.ru")) built.is_a?(Array) ? built.first : built end |
#precompile? ⇒ Boolean
Whether the build must run anything against the app's bundle on the HOST Ruby (asset precompile). Sinatra's no-op precompile opts out.
93 |
# File 'lib/everywhere/framework.rb', line 93 def precompile? = precompile_command != "true" |
#prepare_runtime_env ⇒ Object
Set framework-specific env before the app loads. Called by Boot.
64 |
# File 'lib/everywhere/framework.rb', line 64 def prepare_runtime_env; end |
#render_boot_stub(env, setup_line) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/everywhere/framework.rb', line 95 def render_boot_stub(env, setup_line) exports = ({ "NATIVE_PACKAGED" => "1" }.merge(env)) .map { |k, v| "ENV[#{k.inspect}] ||= #{v.inspect}" }.join("\n") <<~RUBY #!/usr/bin/env ruby # frozen_string_literal: true # RubyEverywhere packaged-app entry point (generated by `every install`). # Keep this thin: the real boot lives in the ruby_everywhere gem. #{exports} #{setup_line} require "ruby_everywhere" Everywhere.boot!(root: __dir__) RUBY end |
#serve_rack(app, port:) ⇒ Object
Serve a Rack app under Puma on localhost. Keep-alives are disabled: WebKit (the webview) reuses connections Puma has already closed, which shows up as intermittent "network connection was lost" asset failures.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/everywhere/framework.rb', line 116 def serve_rack(app, port:) require "puma" require "puma/configuration" require "puma/launcher" configuration = ::Puma::Configuration.new do |c| c.bind "tcp://127.0.0.1:#{port}" c.app app c.environment ENV.fetch("RACK_ENV", "production") c.workers 0 c.threads 1, 5 c.enable_keep_alives false if c.respond_to?(:enable_keep_alives) end ::Puma::Launcher.new(configuration).run end |