Class: Plushie::DevServer

Inherits:
Object
  • Object
show all
Defined in:
lib/plushie/dev_server.rb

Overview

File watcher and hot-reloader for development mode.

Watches lib/ (configurable) for .rb file changes, debounces rapid saves, and triggers a re-render in the runtime. The model state is preserved across reloads: only the view is re-evaluated.

Requires the +listen+ gem (optional dependency, not in gemspec). Install it in your Gemfile for development:

gem "listen", group: :development

Examples:

Plushie.run(MyApp, dev: true)

Manual control

dev = DevServer.new(event_queue: runtime_queue, dirs: ["lib/"])
dev.start
dev.stop

Instance Method Summary collapse

Constructor Details

#initialize(event_queue:, dirs: nil, debounce_ms: 100) ⇒ DevServer

Returns a new instance of DevServer.

Parameters:

  • event_queue (Thread::Queue)

    runtime event queue for :force_rerender

  • dirs (Array<String>) (defaults to: nil)

    directories to watch (default: ["lib/"])

  • debounce_ms (Integer) (defaults to: 100)

    debounce window in milliseconds (default: 100)



27
28
29
30
31
32
33
34
35
36
# File 'lib/plushie/dev_server.rb', line 27

def initialize(event_queue:, dirs: nil, debounce_ms: 100)
  @event_queue = event_queue
  @dirs = dirs || ["lib/"]
  @debounce_ms = debounce_ms
  @listener = nil
  @debounce_timer = nil
  @debounce_mutex = Mutex.new
  @running = false
  @logger = Logger.new($stderr, level: :info, progname: "plushie-dev")
end

Instance Method Details

#running?Boolean

Whether the dev server is actively watching.

Returns:

  • (Boolean)


40
41
42
# File 'lib/plushie/dev_server.rb', line 40

def running?
  @running
end

#startObject

Start watching for file changes.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/plushie/dev_server.rb', line 45

def start
  begin
    require "listen"
  rescue LoadError
    @logger.warn("plushie dev: `listen` gem not found. Add it to your Gemfile for hot reload.")
    return
  end

  @listener = Listen.to(*@dirs, only: /\.rb$/) do |modified, added, _removed|
    files = (modified + added).uniq
    schedule_reload(files) unless files.empty?
  end

  begin
    @listener.start
    @running = true
    @logger.info("plushie dev: watching #{@dirs.join(", ")} for changes")
  rescue => e
    @logger.error("plushie dev: file watcher failed to start: #{e.class}: #{e.message}")
    @listener = nil
  end
end

#stopObject

Stop watching and clean up all resources.

Kills the debounce timer thread, stops the file listener, and resets internal state. Safe to call multiple times.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/plushie/dev_server.rb', line 72

def stop
  @running = false

  @debounce_mutex.synchronize do
    @debounce_timer&.kill
    @debounce_timer = nil
  end

  return unless @listener

  begin
    @listener.stop
  rescue => e
    @logger.warn("plushie dev: error stopping file watcher: #{e.class}: #{e.message}")
  end
  @listener = nil
end