Module: Charming::Controller::ClassMethods

Included in:
Charming::Controller
Defined in:
lib/charming/controller/class_methods.rb

Overview

DSL for declaring controller-level event bindings and configuration: keys, commands, timers, task handlers, the auto-rendered action, layout wrapper, and focus ring. Mixed into Controller as class methods; also exposed for tests and shared base controllers.

Instance Method Summary collapse

Instance Method Details

#auto_render(action = :show) ⇒ Object

Sets the action that the controller should auto-render after a non-rendering action runs. Defaults to :show when unset.



48
49
50
# File 'lib/charming/controller/class_methods.rb', line 48

def auto_render(action = :show)
  @auto_render_action = action.to_sym
end

#auto_render_actionObject

Returns the configured auto-render action, walking the superclass chain when undefined locally.



53
54
55
56
57
58
# File 'lib/charming/controller/class_methods.rb', line 53

def auto_render_action
  return @auto_render_action if instance_variable_defined?(:@auto_render_action)
  return superclass.auto_render_action if superclass.respond_to?(:auto_render_action)

  nil
end

#command(label, action = nil, &block) ⇒ Object

Adds a CommandPalette entry with the given label. action is a method name to send on the controller, or a block to instance_exec when selected.



21
22
23
# File 'lib/charming/controller/class_methods.rb', line 21

def command(label, action = nil, &block)
  command_bindings << Components::CommandPalette::Command.new(label: label, value: block || action)
end

#command_bindingsObject

Array of registered command palette entries, inherited from superclass when undefined.



91
92
93
# File 'lib/charming/controller/class_methods.rb', line 91

def command_bindings
  @command_bindings ||= superclass.respond_to?(:command_bindings) ? superclass.command_bindings.dup : []
end

#focus_ring(*slots) ⇒ Object

Defines the named focus slots cycled by Tab/Shift+Tab traversal.



81
82
83
# File 'lib/charming/controller/class_methods.rb', line 81

def focus_ring(*slots)
  @focus_ring_slots = slots
end

#focus_ring_slotsObject

Returns the focus ring slots, inherited from superclass when undefined.



86
87
88
# File 'lib/charming/controller/class_methods.rb', line 86

def focus_ring_slots
  @focus_ring_slots ||= superclass.respond_to?(:focus_ring_slots) ? superclass.focus_ring_slots.dup : []
end

#key(name, action, scope: :content) ⇒ Object

Binds a key press to a controller action. name is the normalized key symbol (e.g., “up”, “q”, “ctrl+c”). scope is :content (default) for content-pane keys or :global for app-wide shortcuts that fire regardless of focus. Raises ArgumentError for any other scope.



12
13
14
15
16
17
# File 'lib/charming/controller/class_methods.rb', line 12

def key(name, action, scope: :content)
  normalized_scope = validate_key_scope(scope)
  key_name = Charming.key_binding_name(name)
  key_bindings[key_name] = action
  key_binding_scopes[key_name] = normalized_scope
end

#key_binding_scopesObject

Hash of key scopes paralleling ‘key_bindings` (symbol key name => :content or :global).



76
77
78
# File 'lib/charming/controller/class_methods.rb', line 76

def key_binding_scopes
  @key_binding_scopes ||= superclass.respond_to?(:key_binding_scopes) ? superclass.key_binding_scopes.dup : {}
end

#key_bindingsObject

Hash of registered key bindings (symbol key name => action method name), inherited from superclass controllers.



71
72
73
# File 'lib/charming/controller/class_methods.rb', line 71

def key_bindings
  @key_bindings ||= superclass.respond_to?(:key_bindings) ? superclass.key_bindings.dup : {}
end

#layout(layout_class = :__charming_layout_reader__) ⇒ Object

Sets or returns the controller’s layout. Pass a layout class (instantiated per request), a String/Symbol template name (resolved through Templates), or ‘false` to disable inherited layout wrapping. Called with no arguments returns the resolved layout.



63
64
65
66
67
# File 'lib/charming/controller/class_methods.rb', line 63

def layout(layout_class = :__charming_layout_reader__)
  return resolved_layout if layout_class == :__charming_layout_reader__

  @layout = layout_class
end

#on_task(name, action:) ⇒ Object

Declares a task handler for async work submitted via ‘run_task(:name)`. When the task emits a TaskEvent with the matching name, the runtime dispatches action on the controller.



35
36
37
# File 'lib/charming/controller/class_methods.rb', line 35

def on_task(name, action:)
  task_bindings[name.to_sym] = TaskBinding.new(name: name.to_sym, action: action)
end

#on_task_progress(name, action:) ⇒ Object

Declares a progress handler for a task: while ‘run_task(:name)` runs, each `progress.report(…)` dispatches action on the controller (the event is available as `event` — a TaskProgressEvent with current/total/message).



42
43
44
# File 'lib/charming/controller/class_methods.rb', line 42

def on_task_progress(name, action:)
  task_progress_bindings[name.to_sym] = TaskBinding.new(name: name.to_sym, action: action)
end

#task_bindingsObject

Hash of task name => TaskBinding, inherited from superclass when undefined.



101
102
103
# File 'lib/charming/controller/class_methods.rb', line 101

def task_bindings
  @task_bindings ||= superclass.respond_to?(:task_bindings) ? superclass.task_bindings.dup : {}
end

#task_progress_bindingsObject

Hash of task name => TaskBinding for progress handlers, inherited from superclass.



106
107
108
# File 'lib/charming/controller/class_methods.rb', line 106

def task_progress_bindings
  @task_progress_bindings ||= superclass.respond_to?(:task_progress_bindings) ? superclass.task_progress_bindings.dup : {}
end

#timer(name, every:, action:) ⇒ Object

Declares a timer that fires every every seconds and dispatches action on the controller. The runtime builds a TimerEvent and routes it to the active controller’s dispatch_timer.

Raises:

  • (ArgumentError)


27
28
29
30
31
# File 'lib/charming/controller/class_methods.rb', line 27

def timer(name, every:, action:)
  raise ArgumentError, "timer interval must be positive (got #{every.inspect})" unless every.is_a?(Numeric) && every.positive?

  timer_bindings[name.to_sym] = TimerBinding.new(name: name.to_sym, interval: every, action: action)
end

#timer_bindingsObject

Hash of timer name => TimerBinding, inherited from superclass when undefined.



96
97
98
# File 'lib/charming/controller/class_methods.rb', line 96

def timer_bindings
  @timer_bindings ||= superclass.respond_to?(:timer_bindings) ? superclass.timer_bindings.dup : {}
end