Class: Taski::Progress::Layout::Base
- Inherits:
-
Execution::TaskObserver
- Object
- Execution::TaskObserver
- Taski::Progress::Layout::Base
- Defined in:
- lib/taski/progress/layout/base.rb
Overview
Base class for layout implementations. Layouts are responsible for:
- Receiving events from ExecutionFacade (Observer pattern)
- Managing task state tracking
- Rendering templates using Liquid
- Handling screen output
Observer Interface ===
| ExecutionFacade Event | Observer Method | Theme Method |
|---|---|---|
| notify_ready | on_ready | (pulls root_task, output_capture) |
| notify_start | on_start | execution_start |
| notify_stop | on_stop | execution_complete/fail |
| notify_task_updated | on_task_updated | task_start/success/fail/skip/clean_* |
| notify_group_started | on_group_started | group_start |
| notify_group_completed | on_group_completed | group_success/fail |
Direct Known Subclasses
Instance Attribute Summary collapse
-
#spinner_index ⇒ Object
readonly
Returns the value of attribute spinner_index.
Attributes inherited from Execution::TaskObserver
Instance Method Summary collapse
-
#initialize(output: $stderr, theme: nil) ⇒ Base
constructor
A new instance of Base.
-
#on_group_completed(task_class, group_name, phase:, timestamp:) ⇒ Object
Event 6: Group completed within a task.
-
#on_group_started(task_class, group_name, phase:, timestamp:) ⇒ Object
Event 5: Group started within a task.
-
#on_ready ⇒ Object
Event 1: Facade is ready (root task set, output capture available).
-
#on_start ⇒ Object
Event 2: Start progress display.
-
#on_stop ⇒ Object
Event 3: Stop progress display.
-
#on_task_updated(task_class, previous_state:, current_state:, phase:, timestamp:) ⇒ Object
Event 4: Task state transition.
-
#queue_message(text) ⇒ Object
Queue a message to be displayed after progress display stops Thread-safe for concurrent task execution.
-
#render_template_string(template_string, state: nil, task: nil, execution: nil, **variables) ⇒ String
Render a Liquid template string with the given variables.
-
#start_spinner_timer ⇒ Object
Start the spinner animation timer.
-
#stop_spinner_timer ⇒ Object
Stop the spinner animation timer.
-
#task_registered?(task_class) ⇒ Boolean
Check if a task is registered.
-
#task_state(task_class) ⇒ Symbol?
Get the current state of a task.
Constructor Details
#initialize(output: $stderr, theme: nil) ⇒ Base
Returns a new instance of Base.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/taski/progress/layout/base.rb', line 34 def initialize(output: $stderr, theme: nil) @output = output @context = nil @theme = theme || Theme::Default.new @theme_drop = ThemeDrop.new(@theme) @liquid_environment = build_liquid_environment @monitor = Monitor.new @tasks = {} @nest_level = 0 @start_time = nil @root_task_class = nil @output_capture = nil @message_queue = [] @group_start_times = {} @spinner_index = 0 @spinner_timer = nil @spinner_running = false @active = false end |
Instance Attribute Details
#spinner_index ⇒ Object (readonly)
Returns the value of attribute spinner_index.
32 33 34 |
# File 'lib/taski/progress/layout/base.rb', line 32 def spinner_index @spinner_index end |
Instance Method Details
#on_group_completed(task_class, group_name, phase:, timestamp:) ⇒ Object
Event 6: Group completed within a task.
133 134 135 136 137 138 139 |
# File 'lib/taski/progress/layout/base.rb', line 133 def on_group_completed(task_class, group_name, phase:, timestamp:) @monitor.synchronize do started_at = @group_start_times.delete([task_class, group_name]) duration = started_at ? (( - started_at) * 1000).round : nil handle_group_completed(task_class, group_name, phase, duration) end end |
#on_group_started(task_class, group_name, phase:, timestamp:) ⇒ Object
Event 5: Group started within a task.
121 122 123 124 125 126 |
# File 'lib/taski/progress/layout/base.rb', line 121 def on_group_started(task_class, group_name, phase:, timestamp:) @monitor.synchronize do @group_start_times[[task_class, group_name]] = handle_group_started(task_class, group_name, phase) end end |
#on_ready ⇒ Object
Event 1: Facade is ready (root task set, output capture available). Pulls root_task_class and output_capture from context. Only sets root_task_class once (prevents nested executor overwrite).
59 60 61 62 63 64 65 66 |
# File 'lib/taski/progress/layout/base.rb', line 59 def on_ready @monitor.synchronize do return if @root_task_class @root_task_class = @context&.root_task_class @output_capture = @context&.output_capture handle_ready end end |
#on_start ⇒ Object
Event 2: Start progress display. Increments nest level for nested executor support.
70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/taski/progress/layout/base.rb', line 70 def on_start should_start = false @monitor.synchronize do @nest_level += 1 return if @nest_level > 1 return unless should_activate? @start_time = Time.now @active = true should_start = true end handle_start if should_start end |
#on_stop ⇒ Object
Event 3: Stop progress display. Only finalizes when nest level reaches 0 and layout was actually activated.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/taski/progress/layout/base.rb', line 86 def on_stop should_stop = false was_active = false @monitor.synchronize do @nest_level -= 1 if @nest_level > 0 return unless @nest_level == 0 was_active = @active @active = false should_stop = true end return unless should_stop handle_stop if was_active end |
#on_task_updated(task_class, previous_state:, current_state:, phase:, timestamp:) ⇒ Object
Event 4: Task state transition.
108 109 110 111 112 113 114 |
# File 'lib/taski/progress/layout/base.rb', line 108 def on_task_updated(task_class, previous_state:, current_state:, phase:, timestamp:) @monitor.synchronize do progress = @tasks[task_class] ||= new_task_progress apply_state_transition(progress, current_state, phase, ) handle_task_update(task_class, current_state, phase) end end |
#queue_message(text) ⇒ Object
Queue a message to be displayed after progress display stops Thread-safe for concurrent task execution
160 161 162 |
# File 'lib/taski/progress/layout/base.rb', line 160 def (text) @monitor.synchronize { @message_queue << text } end |
#render_template_string(template_string, state: nil, task: nil, execution: nil, **variables) ⇒ String
Render a Liquid template string with the given variables. Uses scoped Liquid environment with ColorFilter and SpinnerTag.
172 173 174 175 176 177 |
# File 'lib/taski/progress/layout/base.rb', line 172 def render_template_string(template_string, state: nil, task: nil, execution: nil, **variables) context_vars = build_context_vars(task:, execution:, **variables) template = Liquid::Template.parse(template_string, environment: @liquid_environment) template.assigns["state"] = state template.render(context_vars) end |
#start_spinner_timer ⇒ Object
Start the spinner animation timer. Increments spinner_index at the template's spinner_interval.
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/taski/progress/layout/base.rb', line 181 def start_spinner_timer @monitor.synchronize do return if @spinner_running @spinner_running = true end @spinner_timer = Thread.new do loop do running = @monitor.synchronize { @spinner_running } break unless running sleep @theme.spinner_interval @monitor.synchronize do @spinner_index = (@spinner_index + 1) % @theme.spinner_frames.size end end end end |
#stop_spinner_timer ⇒ Object
Stop the spinner animation timer.
200 201 202 203 204 |
# File 'lib/taski/progress/layout/base.rb', line 200 def stop_spinner_timer @monitor.synchronize { @spinner_running = false } @spinner_timer&.join @spinner_timer = nil end |
#task_registered?(task_class) ⇒ Boolean
Check if a task is registered
144 145 146 |
# File 'lib/taski/progress/layout/base.rb', line 144 def task_registered?(task_class) @monitor.synchronize { @tasks.key?(task_class) } end |
#task_state(task_class) ⇒ Symbol?
Get the current state of a task
151 152 153 154 155 |
# File 'lib/taski/progress/layout/base.rb', line 151 def task_state(task_class) p = @monitor.synchronize { @tasks[task_class] } return nil unless p p[:clean_state] || p[:run_state] end |