Class: Everywhere::Config
- Inherits:
-
Object
- Object
- Everywhere::Config
- Defined in:
- lib/everywhere/config.rb
Overview
Loads config/everywhere.yml:
app:
name: My Really Awesome App
entry_path: /dashboard # initial url on app launch
appearance:
tint_color: "#CC342D" # a hex string...
background_color: # ...or split by system theme
light: "#FAF9F7"
dark: "#1C1B1A"
Colors always normalize to { "light" => ..., "dark" => ... }.
Constant Summary collapse
- FILE =
File.join("config", "everywhere.yml")
Instance Attribute Summary collapse
-
#root ⇒ Object
readonly
Returns the value of attribute root.
Class Method Summary collapse
- .load(root = Dir.pwd) ⇒ Object
-
.os_of(target) ⇒ Object
Every target (os-arch string) resolves to a single platform (its os), and a platform may override the app-level identity/version keys — see
platforms:below.
Instance Method Summary collapse
- #background_color ⇒ Object
-
#build ⇒ Object
The
build:section — durable build knobs that were onceevery buildflags (ruby, targets, permissions). -
#build_ruby ⇒ Object
Ruby version to package.
-
#bundle_id(target: nil) ⇒ Object
Reverse-DNS identifier: macOS bundle id, and the name of the per-user app-data directory on every platform.
- #entry_path ⇒ Object
-
#icon ⇒ Object
App icon source: a PNG (ideally square, 1024px+).
-
#initialize(data, root) ⇒ Config
constructor
A new instance of Config.
-
#menu ⇒ Object
Custom native menu items (macOS app menu).
-
#mode ⇒ Object
"local" — the app is tebako-pressed and runs on-device (default) "remote" — thin shell around an already-deployed app: no press, no sidecar.
- #name(target: nil) ⇒ Object
-
#permissions ⇒ Object
OS-integration permissions the app declares.
- #remote? ⇒ Boolean
- #remote_url ⇒ Object
-
#splash ⇒ Object
Optional custom splash page (HTML file, path relative to the app root).
-
#targets ⇒ Object
Build targets (os-arch strings) — the CI matrix, expressed once.
- #tint_color ⇒ Object
-
#to_shell_hash(target: nil) ⇒ Object
The subset the shell needs, shipped as JSON (env var in dev, Resources/everywhere.json inside a bundled .app).
- #to_shell_json(target: nil) ⇒ Object
-
#tray ⇒ Object
System tray: same entry shape as
menu:plusaction: quit | show. -
#updates ⇒ Object
The
updates:section — self-hosted auto-updates. -
#updates_auto ⇒ Object
off — never check; check — check + notify (default); download — also fetch/verify in the background; install — silent auto-update.
- #updates_channel ⇒ Object
- #updates_interval ⇒ Object
- #updates_public_key ⇒ Object
- #updates_s3 ⇒ Object
-
#updates_shell_hash ⇒ Object
The client subset for the shell; nil (and thus absent from everywhere.json) until both url and public_key are configured — an unsigned update feed is not a thing.
- #updates_url ⇒ Object
-
#version(target: nil) ⇒ Object
Marketing/display version of the app (CFBundleShortVersionString, and the
versionrecorded in the build receipt).
Constructor Details
Instance Attribute Details
#root ⇒ Object (readonly)
Returns the value of attribute root.
27 28 29 |
# File 'lib/everywhere/config.rb', line 27 def root @root end |
Class Method Details
.load(root = Dir.pwd) ⇒ Object
21 22 23 24 25 |
# File 'lib/everywhere/config.rb', line 21 def self.load(root = Dir.pwd) path = File.join(root, FILE) data = File.exist?(path) ? YAML.safe_load_file(path, aliases: true) || {} : {} new(data, root) end |
.os_of(target) ⇒ Object
Every target (os-arch string) resolves to a single platform (its os), and
a platform may override the app-level identity/version keys — see
platforms: below. Pass target: to any of these accessors to apply the
matching override; omit it for the shared app-level value.
38 |
# File 'lib/everywhere/config.rb', line 38 def self.os_of(target) = target.to_s.split("-", 2).first |
Instance Method Details
#background_color ⇒ Object
152 153 154 |
# File 'lib/everywhere/config.rb', line 152 def background_color normalize_color(appearance["background_color"]) end |
#build ⇒ Object
The build: section — durable build knobs that were once every build
flags (ruby, targets, permissions). CLI flags still override per-run.
See platform/docs/build-engine.md §2.
88 |
# File 'lib/everywhere/config.rb', line 88 def build = @data.fetch("build", nil) || {} |
#build_ruby ⇒ Object
Ruby version to package. nil here means "let the CLI decide its default".
91 |
# File 'lib/everywhere/config.rb', line 91 def build_ruby = build["ruby"] |
#bundle_id(target: nil) ⇒ Object
Reverse-DNS identifier: macOS bundle id, and the name of the per-user
app-data directory on every platform. Set it explicitly and never change
it — renaming moves users' data. A platform may override it (e.g. the App
Store often wants com.example.app.ios).
48 49 50 51 |
# File 'lib/everywhere/config.rb', line 48 def bundle_id(target: nil) resolved(target)["bundle_id"] || "com.rubyeverywhere.#{name(target: target).downcase.gsub(/[^a-z0-9]+/, "-").gsub(/\A-|-\z/, "")}" end |
#entry_path ⇒ Object
72 73 74 75 |
# File 'lib/everywhere/config.rb', line 72 def entry_path path = app["entry_path"] || "/" path.start_with?("/") ? path : "/#{path}" end |
#icon ⇒ Object
App icon source: a PNG (ideally square, 1024px+). Explicit app.icon
path relative to the app root, or icon.png at the root by convention.
55 56 57 58 59 60 61 62 |
# File 'lib/everywhere/config.rb', line 55 def icon if (explicit = app["icon"]) File.(explicit, root) else default = File.join(root, "icon.png") File.exist?(default) ? default : nil end end |
#menu ⇒ Object
Custom native menu items (macOS app menu). Each entry: label + path (+ optional accelerator), or "separator". Clicks arrive in the page as "everywhere:menu" events and navigate via Turbo.
159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/everywhere/config.rb', line 159 def entries = @data["menu"] return [] unless entries.is_a?(Array) entries.filter_map do |item| if item == "separator" || (item.is_a?(Hash) && item["separator"]) { "separator" => true } elsif item.is_a?(Hash) && item["label"] && item["path"] { "label" => item["label"], "path" => item["path"], "accelerator" => item["accelerator"] }.compact end end end |
#mode ⇒ Object
"local" — the app is tebako-pressed and runs on-device (default) "remote" — thin shell around an already-deployed app: no press, no sidecar
102 103 104 |
# File 'lib/everywhere/config.rb', line 102 def mode app["mode"] || (remote_url ? "remote" : "local") end |
#name(target: nil) ⇒ Object
40 41 42 |
# File 'lib/everywhere/config.rb', line 40 def name(target: nil) resolved(target)["name"] || File.basename(File.(root)).split(/[-_]/).map(&:capitalize).join(" ") end |
#permissions ⇒ Object
OS-integration permissions the app declares. Recorded in the receipt and (later) used to generate the shell's capabilities.
95 |
# File 'lib/everywhere/config.rb', line 95 def = Array(build["permissions"]) |
#remote? ⇒ Boolean
106 |
# File 'lib/everywhere/config.rb', line 106 def remote? = mode == "remote" |
#remote_url ⇒ Object
108 109 110 |
# File 'lib/everywhere/config.rb', line 108 def remote_url @data.dig("remote", "url")&.chomp("/") end |
#splash ⇒ Object
Optional custom splash page (HTML file, path relative to the app root). Shown while the packaged server boots; the shell injects window.EVERYWHERE_CONFIG so it can use the app's name and colors.
67 68 69 70 |
# File 'lib/everywhere/config.rb', line 67 def splash path = app["splash"] File.(path, root) if path end |
#targets ⇒ Object
Build targets (os-arch strings) — the CI matrix, expressed once.
98 |
# File 'lib/everywhere/config.rb', line 98 def targets = Array(build["targets"]) |
#tint_color ⇒ Object
148 149 150 |
# File 'lib/everywhere/config.rb', line 148 def tint_color normalize_color(appearance["tint_color"]) end |
#to_shell_hash(target: nil) ⇒ Object
The subset the shell needs, shipped as JSON (env var in dev,
Resources/everywhere.json inside a bundled .app). Pass target: so the
packaged config reflects the platform being built (its bundle id / name).
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/everywhere/config.rb', line 200 def to_shell_hash(target: nil) { "name" => name(target: target), "bundle_id" => bundle_id(target: target), "version" => version(target: target), "mode" => mode, "remote_url" => remote_url, "entry_path" => entry_path, "tint_color" => tint_color, "background_color" => background_color, "menu" => ( unless .empty?), "tray" => (tray unless tray.empty?), "updates" => updates_shell_hash }.compact end |
#to_shell_json(target: nil) ⇒ Object
216 217 218 219 |
# File 'lib/everywhere/config.rb', line 216 def to_shell_json(target: nil) require "json" JSON.generate(to_shell_hash(target: target)) end |
#tray ⇒ Object
System tray: same entry shape as menu: plus action: quit | show.
tray:
- label: "Open My App"
action: show
- label: "New Note"
path: /notes/new
- separator
- label: Quit
action: quit
183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/everywhere/config.rb', line 183 def tray entries = @data["tray"] return [] unless entries.is_a?(Array) entries.filter_map do |item| if item == "separator" || (item.is_a?(Hash) && item["separator"]) { "separator" => true } elsif item.is_a?(Hash) && item["label"] && (item["path"] || item["action"]) { "label" => item["label"], "path" => item["path"], "action" => item["action"] }.compact end end end |
#updates ⇒ Object
The updates: section — self-hosted auto-updates. Two halves:
a client half (url/channel/public_key/auto/interval) that ships to the
shell, and a publish-side s3: half that NEVER leaves the dev machine.
channel here is a release channel (stable/beta) — not the receipt's
distribution_channel (direct vs app stores).
117 |
# File 'lib/everywhere/config.rb', line 117 def updates = @data.fetch("updates", nil) || {} |
#updates_auto ⇒ Object
off — never check; check — check + notify (default); download — also fetch/verify in the background; install — silent auto-update.
129 |
# File 'lib/everywhere/config.rb', line 129 def updates_auto = updates["auto"] || "check" |
#updates_channel ⇒ Object
121 |
# File 'lib/everywhere/config.rb', line 121 def updates_channel = updates["channel"] || "stable" |
#updates_interval ⇒ Object
131 |
# File 'lib/everywhere/config.rb', line 131 def updates_interval = [(updates["interval"] || 21_600).to_i, 300].max |
#updates_public_key ⇒ Object
125 |
# File 'lib/everywhere/config.rb', line 125 def updates_public_key = updates["public_key"] |
#updates_s3 ⇒ Object
119 |
# File 'lib/everywhere/config.rb', line 119 def updates_s3 = updates.fetch("s3", nil) || {} |
#updates_shell_hash ⇒ Object
The client subset for the shell; nil (and thus absent from everywhere.json) until both url and public_key are configured — an unsigned update feed is not a thing.
136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/everywhere/config.rb', line 136 def updates_shell_hash return nil unless updates_url && updates_public_key { "url" => updates_url, "channel" => updates_channel, "public_key" => updates_public_key, "auto" => updates_auto, "interval" => updates_interval } end |
#updates_url ⇒ Object
123 |
# File 'lib/everywhere/config.rb', line 123 def updates_url = updates["url"]&.chomp("/") |
#version(target: nil) ⇒ Object
Marketing/display version of the app (CFBundleShortVersionString, and the
version recorded in the build receipt). One shared app.version is the
default for every target; a platform may override it when a store forces a
different number. Defaults conservatively.
81 82 83 |
# File 'lib/everywhere/config.rb', line 81 def version(target: nil) resolved(target)["version"] || "0.1.0" end |