Class: Charming::Application
- Inherits:
-
Object
- Object
- Charming::Application
- Defined in:
- lib/charming/application.rb
Overview
Application is a lightweight, Rails-inspired application base for building terminal-based apps. It provides routing (via a DSL), session storage, and task execution for managing async operations.
Constant Summary collapse
- LOGGER_READER =
Object.new.freeze
- THEME_READER =
Object.new.freeze
Instance Attribute Summary collapse
-
#logger ⇒ Object
Returns the value of attribute logger.
-
#session ⇒ Object
readonly
Returns the value of attribute session.
-
#task_executor ⇒ Object
Returns the value of attribute task_executor.
Class Method Summary collapse
-
.default_theme(name = THEME_READER) ⇒ Object
Returns the default theme name, or sets it when name is given.
-
.logger(value = LOGGER_READER) ⇒ Object
Returns or sets the app logger.
-
.namespace ⇒ Object
Derives the module namespace from the class name — e.g., Admin::HomeController yields “Admin”.
-
.persist_session(to:) ⇒ Object
Opts into session persistence: the session hash is serialized as JSON to to when the app quits and reloaded on boot.
-
.root(path = THEME_READER) ⇒ Object
Returns the app’s filesystem root, used to resolve relative theme and template paths.
-
.routes(&block) ⇒ Object
Registers or returns the app’s Router.
-
.session_path ⇒ Object
The configured session file path, walking the superclass chain.
-
.theme(name, from: nil, built_in: nil, extends: nil, overrides: nil) ⇒ Object
Registers a named theme.
-
.theme_for(name = nil) ⇒ Object
Resolves a theme by name (or the default theme when name is nil).
-
.themes ⇒ Object
Hash of all registered themes keyed by symbol, including those inherited from superclasses.
Instance Method Summary collapse
-
#initialize ⇒ Application
constructor
Initializes the session hash for per-request state storage, restoring a previously persisted session when ‘persist_session` is configured.
-
#routes ⇒ Object
Delegates to the class-level Router, providing instance access to route definitions.
-
#save_session ⇒ Object
Serializes the session to the configured ‘persist_session` path.
- #theme ⇒ Object
- #use_theme(name) ⇒ Object
Constructor Details
#initialize ⇒ Application
Initializes the session hash for per-request state storage, restoring a previously persisted session when ‘persist_session` is configured.
134 135 136 137 |
# File 'lib/charming/application.rb', line 134 def initialize @logger = self.class.logger @session = load_session end |
Instance Attribute Details
#logger ⇒ Object
Returns the value of attribute logger.
129 130 131 |
# File 'lib/charming/application.rb', line 129 def logger @logger end |
#session ⇒ Object (readonly)
Returns the value of attribute session.
130 131 132 |
# File 'lib/charming/application.rb', line 130 def session @session end |
#task_executor ⇒ Object
Returns the value of attribute task_executor.
129 130 131 |
# File 'lib/charming/application.rb', line 129 def task_executor @task_executor end |
Class Method Details
.default_theme(name = THEME_READER) ⇒ Object
Returns the default theme name, or sets it when name is given. When unset, falls back to the first registered theme. Used by ‘theme_for` when no name is provided.
79 80 81 82 83 |
# File 'lib/charming/application.rb', line 79 def default_theme(name = THEME_READER) return @default_theme || themes.keys.first if name == THEME_READER @default_theme = name.to_sym end |
.logger(value = LOGGER_READER) ⇒ Object
Returns or sets the app logger. Defaults to a null-device logger so app and framework code can safely call logging methods without writing into the terminal UI.
31 32 33 34 35 |
# File 'lib/charming/application.rb', line 31 def logger(value = LOGGER_READER) return configured_logger if value == LOGGER_READER @logger = value end |
.namespace ⇒ Object
Derives the module namespace from the class name — e.g., Admin::HomeController yields “Admin”. Mirrors Rails’ engine-style namespacing.
25 26 27 |
# File 'lib/charming/application.rb', line 25 def namespace ActiveSupport::Inflector.deconstantize(name.to_s) end |
.persist_session(to:) ⇒ Object
Opts into session persistence: the session hash is serialized as JSON to to when the app quits and reloaded on boot. Only JSON-safe values survive the round-trip (hash keys come back as symbols); non-serializable entries (state objects, procs) are skipped with a warning in the log.
98 99 100 |
# File 'lib/charming/application.rb', line 98 def persist_session(to:) @session_path = to end |
.root(path = THEME_READER) ⇒ Object
Returns the app’s filesystem root, used to resolve relative theme and template paths. Pass path to set it; without arguments it returns the current value (or nil if unset).
39 40 41 42 43 |
# File 'lib/charming/application.rb', line 39 def root(path = THEME_READER) return @root if path == THEME_READER @root = File.(path) end |
.routes(&block) ⇒ Object
Registers or returns the app’s Router. Accepts an optional block to define routes via DSL (screen, root). Lazily initializes a new Router per namespace.
17 18 19 20 21 |
# File 'lib/charming/application.rb', line 17 def routes(&block) @routes ||= Router.new(namespace: namespace) @routes.draw(&block) if block @routes end |
.session_path ⇒ Object
The configured session file path, walking the superclass chain. Nil when persistence is not enabled.
104 105 106 107 108 109 |
# File 'lib/charming/application.rb', line 104 def session_path return @session_path if instance_variable_defined?(:@session_path) return superclass.session_path if superclass.respond_to?(:session_path) nil end |
.theme(name, from: nil, built_in: nil, extends: nil, overrides: nil) ⇒ Object
Registers a named theme. Provide one of:
-
from: — path to a JSON theme file relative to the app root
-
built_in: — name of a bundled theme (“phosphor”, “catppuccin-mocha”, “catppuccin-latte”, “gruvbox-dark”, “nord”, “tokyonight”)
-
extends: — name of an already-registered theme to derive from, with overrides: (token name → style spec) merged on top:
theme :dark, built_in: "tokyonight" theme :high_contrast, extends: :dark, overrides: {text: {foreground: "#ffffff"}}
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/charming/application.rb', line 54 def theme(name, from: nil, built_in: nil, extends: nil, overrides: nil) sources = [from, built_in, extends].compact raise ArgumentError, "theme expects from:, built_in:, or extends:" if sources.empty? raise ArgumentError, "theme expects only one of from:, built_in:, or extends:" if sources.length > 1 raise ArgumentError, "overrides: requires extends:" if overrides && !extends themes[name.to_sym] = if extends parent = themes.fetch(extends.to_sym) do raise ArgumentError, "unknown parent theme: #{extends.inspect} (register it before extending)" end parent.merge(overrides || {}) elsif built_in UI::Theme.load_builtin(built_in) else UI::Theme.load_file(resolve_theme_path(from)) end end |
.theme_for(name = nil) ⇒ Object
Resolves a theme by name (or the default theme when name is nil). Returns the default built-in theme if no name is given and no default is registered.
87 88 89 90 91 92 |
# File 'lib/charming/application.rb', line 87 def theme_for(name = nil) theme_name = name || default_theme return UI::Theme.default unless theme_name themes.fetch(theme_name.to_sym) end |
.themes ⇒ Object
Hash of all registered themes keyed by symbol, including those inherited from superclasses.
73 74 75 |
# File 'lib/charming/application.rb', line 73 def themes @themes ||= superclass.respond_to?(:themes) ? superclass.themes.dup : {} end |
Instance Method Details
#routes ⇒ Object
Delegates to the class-level Router, providing instance access to route definitions.
153 154 155 |
# File 'lib/charming/application.rb', line 153 def routes self.class.routes end |
#save_session ⇒ Object
Serializes the session to the configured ‘persist_session` path. Entries that don’t survive a JSON round-trip (state objects, procs, focus scopes) are skipped. No-op when persistence isn’t configured. Called by the Runtime on exit.
142 143 144 145 146 147 148 149 150 |
# File 'lib/charming/application.rb', line 142 def save_session path = self.class.session_path return unless path FileUtils.mkdir_p(File.dirname(path)) File.write(path, JSON.generate(serializable_session)) rescue => e logger.warn("session not saved: #{e.class}: #{e.}") end |
#theme ⇒ Object
157 158 159 |
# File 'lib/charming/application.rb', line 157 def theme self.class.theme_for(session[:theme]) end |
#use_theme(name) ⇒ Object
161 162 163 164 |
# File 'lib/charming/application.rb', line 161 def use_theme(name) self.class.theme_for(name) session[:theme] = name.to_sym end |