Class: Everywhere::Config

Inherits:
Object
  • Object
show all
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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data, root) ⇒ Config

Returns a new instance of Config.



29
30
31
32
# File 'lib/everywhere/config.rb', line 29

def initialize(data, root)
  @data = data
  @root = root
end

Instance Attribute Details

#rootObject (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_colorObject



116
117
118
# File 'lib/everywhere/config.rb', line 116

def background_color
  normalize_color(appearance["background_color"])
end

#buildObject

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_rubyObject

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_pathObject



72
73
74
75
# File 'lib/everywhere/config.rb', line 72

def entry_path
  path = app["entry_path"] || "/"
  path.start_with?("/") ? path : "/#{path}"
end

#iconObject

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.expand_path(explicit, root)
  else
    default = File.join(root, "icon.png")
    File.exist?(default) ? default : nil
  end
end

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.



123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/everywhere/config.rb', line 123

def menu
  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

#modeObject

"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.expand_path(root)).split(/[-_]/).map(&:capitalize).join(" ")
end

#permissionsObject

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 permissions = Array(build["permissions"])

#remote?Boolean

Returns:

  • (Boolean)


106
# File 'lib/everywhere/config.rb', line 106

def remote? = mode == "remote"

#remote_urlObject



108
109
110
# File 'lib/everywhere/config.rb', line 108

def remote_url
  @data.dig("remote", "url")&.chomp("/")
end

#splashObject

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.expand_path(path, root) if path
end

#targetsObject

Build targets (os-arch strings) — the CI matrix, expressed once.



98
# File 'lib/everywhere/config.rb', line 98

def targets = Array(build["targets"])

#tint_colorObject



112
113
114
# File 'lib/everywhere/config.rb', line 112

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).



164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/everywhere/config.rb', line 164

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" => (menu unless menu.empty?),
    "tray" => (tray unless tray.empty?)
  }.compact
end

#to_shell_json(target: nil) ⇒ Object



179
180
181
182
# File 'lib/everywhere/config.rb', line 179

def to_shell_json(target: nil)
  require "json"
  JSON.generate(to_shell_hash(target: target))
end

#trayObject

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


147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/everywhere/config.rb', line 147

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

#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