Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest

strategy:
matrix: { ruby: ['3.2', '3.3', '3.4'] }
matrix: { ruby: ['3.2', '3.3', '3.4', '4.0'] }

steps:
- name: Check out code
Expand Down
35 changes: 23 additions & 12 deletions lib/victor/cli/commands/render.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require 'filewatcher'
require 'listen'

module Victor
module CLI
Expand Down Expand Up @@ -56,25 +56,36 @@ def generate
end

def watch
say "Watching #{ruby_file} for changes"
file_watcher.watch do |changes|
changes.each_value do |event|
yield unless event == :deleted
end
l = listener do |modified, added, _removed|
changes = modified + added
yield unless changes.empty?
end
l.start
sleep
end

def watch_and_generate
watch do
generate
rescue => e
say! "ru`#{e.class}`\n#{e.message}"
say "Watching #{ruby_file} for changes"
safe_generate
begin
watch { safe_generate }
rescue Interrupt
say "\nGoodbye"
end
end

def file_watcher
@file_watcher ||= Filewatcher.new(ruby_file, immediate: true)
def safe_generate
generate
rescue => e
say! "ru`#{e.class}`\n#{e.message}"
end

def listener(&)
Listen.to(ruby_dir, force_polling: true, latency: 3, only: ruby_glob, &)
end

def ruby_dir = @ruby_dir ||= File.dirname(ruby_file)
def ruby_glob = @ruby_glob ||= /\A#{Regexp.escape(File.basename(ruby_file))}\z/
end
end
end
Expand Down
3 changes: 3 additions & 0 deletions spec/approvals/cli/render/watch-interrupt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Watching spec/fixtures/render/pacman_dsl.rb for changes

Goodbye
46 changes: 35 additions & 11 deletions spec/victor-cli/commands/render_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
describe Commands::Render do
let(:ruby_file) { 'spec/fixtures/render/pacman_dsl.rb' }
let(:filewatcher) { Filewatcher.new 'path' }
let(:listener) { double(:listener, start: nil) }

context 'without arguments' do
it 'shows short usage' do
Expand Down Expand Up @@ -29,29 +29,53 @@
end

context 'with RUBY_FILE --watch' do
it 'generates immediately and on change' do
allow(Filewatcher).to receive(:new).and_return(filewatcher)
expect(filewatcher).to receive(:watch) do |_watcher, &block|
changes = { 'some-path' => :updated }
block.call changes
end
it 'generates immediately and watches for changes' do
expect(Listen).to receive(:to).and_return(listener)
expect(listener).to receive(:start)
allow(subject).to receive(:sleep)

expect { subject.execute %W[render #{ruby_file} --watch] }
.to output_approval('cli/render/watch')
end

it 'yields only when changes are present' do
expect(subject).to receive(:listener)
.and_yield([], [], [])
.and_yield(['changed'], [], [])
.and_return(listener)
expect(listener).to receive(:start)
allow(subject).to receive(:sleep)

count = 0
subject.send(:watch) { count += 1 }
expect(count).to eq 1
end

context 'when the script contains an error' do
it 'shows it gracefully and continues to watch' do
expect(subject).to receive(:watch) do |_watcher, &block|
allow(subject).to receive(:generate).and_raise('Intentional error')
changes = { 'some-path' => :updated }
block.call changes
call_count = 0
allow(subject).to receive(:generate) do
call_count += 1
raise 'Intentional error' if call_count == 2
end
expect(subject).to receive(:watch) do |&block|
block.call
end

expect { subject.execute %W[render #{ruby_file} --watch] }
.to output_approval('cli/render/watch-error').to_stderr
end
end

context 'when interrupted' do
it 'shows a friendly message' do
allow(subject).to receive(:safe_generate)
allow(subject).to receive(:watch).and_raise(Interrupt)

expect { subject.execute %W[render #{ruby_file} --watch] }
.to output_approval('cli/render/watch-interrupt')
end
end
end

context 'with RUBY_FILE --save SVG_FILE' do
Expand Down
8 changes: 2 additions & 6 deletions victor-cli.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,15 @@ Gem::Specification.new do |s|

s.add_dependency 'colsole', '~> 1.0'
s.add_dependency 'css_parser', '~> 1.7'
s.add_dependency 'filewatcher', '~> 2.0'
s.add_dependency 'listen', '~> 3.9'
s.add_dependency 'logger', '~> 1.7' # required by lietsn
s.add_dependency 'mister_bin', '~> 0.7'
s.add_dependency 'nokogiri', '~> 1.10'
s.add_dependency 'pretty_trace', '~> 0.3'
s.add_dependency 'requires', '~> 1.0'
s.add_dependency 'rufo', '~> 0.12'
s.add_dependency 'victor', '~> 0.4'

# FIXME: Remove when resolved.
# This is a sub-dependency of filewatcher which does not bundle logger.
# ref: https://github.com/filewatcher/filewatcher/pull/272
s.add_dependency 'logger', '~> 1.6'

s.metadata = {
'bug_tracker_uri' => 'https://github.com/DannyBen/victor-cli/issues',
'changelog_uri' => 'https://github.com/DannyBen/victor-cli/blob/master/CHANGELOG.md',
Expand Down