Skip to content

Commit cad536a

Browse files
authored
Merge pull request #28 from e2/rework-logging
Use a logger for better output control
2 parents ae7fa8a + f72e5b0 commit cad536a

File tree

8 files changed

+169
-39
lines changed

8 files changed

+169
-39
lines changed

lib/ruby_dep/logger.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,40 @@
1+
require 'logger'
2+
13
module RubyDep
4+
def self.logger
5+
@logger ||= stderr_logger
6+
end
7+
8+
def self.logger=(new_logger)
9+
@logger = new_logger.nil? ? NullLogger.new : new_logger
10+
end
11+
12+
def self.stderr_logger
13+
::Logger.new(STDERR).tap do |logger|
14+
logger.formatter = proc { |_,_,_,msg| "#{msg}\n" }
15+
end
16+
end
17+
18+
# Shamelessly stolen from https://github.com/karafka/null-logger
19+
class NullLogger
20+
LOG_LEVELS = %w(unknown fatal error warn info debug).freeze
21+
22+
def respond_to_missing?(method_name, include_private = false)
23+
LOG_LEVELS.include?(method_name.to_s) || super
24+
end
25+
26+
def method_missing(method_name, *args, &block)
27+
LOG_LEVELS.include?(method_name.to_s) ? nil : super
28+
end
29+
end
30+
31+
# TODO: not used, but kept for the sake of SemVer
32+
# TODO: remove in next major version
233
class Logger
334
def initialize(device, prefix)
435
@device = device
536
@prefix = prefix
37+
::RubyDep.logger.warn("The RubyDep::Logger class is deprecated")
638
end
739

840
def warning(msg)

lib/ruby_dep/warning.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ class Warning
2727

2828
def initialize
2929
@version = RubyVersion.new(RUBY_VERSION, RUBY_ENGINE)
30-
@logger = Logger.new(STDERR, PREFIX)
3130
end
3231

3332
def show_warnings
@@ -53,9 +52,11 @@ def status
5352
end
5453

5554
def warn_ruby(msg)
56-
@logger.warning(msg)
57-
@logger.notice(recommendation)
58-
@logger.notice(NOTICE_HOW_TO_DISABLE)
55+
RubyDep.logger.tap do |logger|
56+
logger.warn(PREFIX + msg)
57+
logger.info(PREFIX + recommendation)
58+
logger.info(PREFIX + NOTICE_HOW_TO_DISABLE)
59+
end
5960
end
6061

6162
def recommendation
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require 'ruby_dep/warning'
2+
3+
# Monkey patch so warning happens on every tested Ruby version
4+
module RubyDep
5+
class RubyVersion
6+
def status
7+
:insecure
8+
end
9+
end
10+
end
11+
12+
RubyDep.logger = nil
13+
RubyDep::Warning.new.show_warnings
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require 'ruby_dep/warning'
2+
3+
# Monkey patch so warning happens on every tested Ruby version
4+
module RubyDep
5+
class RubyVersion
6+
def status
7+
:insecure
8+
end
9+
end
10+
end
11+
12+
RubyDep.logger = Logger.new(STDOUT).tap do |logger|
13+
logger.formatter = proc do |severity,_,_,msg|
14+
"#{severity};"
15+
end
16+
end
17+
RubyDep::Warning.new.show_warnings

spec/acceptance/warnings_spec.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,25 @@ def run_isolated(cmd)
6565
end
6666
end
6767
end
68+
69+
context 'when a logger is set manually' do
70+
context 'with logger instance' do
71+
let!(:spec) { 'stdout_logger.rb' }
72+
let(:code) do
73+
"o=`#{subcmd}`;"\
74+
"expected = \"WARN;INFO;INFO;\";" \
75+
"raise \"Unexpected output: \#{o.inspect}\" unless o == expected"
76+
end
77+
it 'uses the given logger' do
78+
run_isolated(cmd)
79+
end
80+
end
81+
82+
context 'with nil' do
83+
let!(:spec) { 'nil_logger.rb' }
84+
it 'produces no output' do
85+
run_isolated(cmd)
86+
end
87+
end
88+
end
6889
end

spec/lib/ruby_dep/logger_spec.rb

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,69 @@
11
require 'ruby_dep/logger'
22

3-
RSpec.describe RubyDep::Logger do
4-
let(:device) { instance_double(IO) }
5-
6-
describe '#warning' do
7-
context 'with a prefix' do
8-
subject { described_class.new(device, 'foo: ') }
9-
it 'outputs message with prefix' do
10-
expect(device).to receive(:puts).with('foo: bar')
11-
subject.warning('bar')
3+
RSpec.describe RubyDep do
4+
around do |example|
5+
example.run
6+
RubyDep.instance_variable_set(:@logger, nil)
7+
end
8+
9+
let(:stderr_logger) { instance_double(Logger, 'stderr logger') }
10+
let(:null_logger) { instance_double(RubyDep::NullLogger, 'null logger') }
11+
12+
let(:string_io) { instance_double(StringIO) }
13+
14+
before do
15+
allow(StringIO).to receive(:new).and_return(string_io)
16+
allow(RubyDep::NullLogger).to receive(:new).and_return(null_logger)
17+
allow(Logger).to receive(:new).with(STDERR).and_return(stderr_logger)
18+
end
19+
20+
describe '.logger' do
21+
context 'when not set yet' do
22+
before do
23+
allow(stderr_logger).to receive(:formatter=)
24+
end
25+
26+
it 'returns stderr_logger' do
27+
expect(described_class.logger).to be(stderr_logger)
28+
end
29+
30+
it 'sets up a simple formatter' do
31+
expect(stderr_logger).to receive(:formatter=) do |callback|
32+
expect( callback.call('a', 'b', 'c', 'd')).to eq("d\n")
33+
end
34+
described_class.logger
35+
end
36+
37+
context 'when reset to nil' do
38+
before { described_class.logger = nil }
39+
40+
it 'returns null logger' do
41+
expect(described_class.logger).to be(null_logger)
42+
end
43+
end
44+
45+
context 'when set to a logger' do
46+
let(:logger) { instance_double(Logger) }
47+
before { described_class.logger = logger }
48+
49+
it 'returns given logger' do
50+
expect(described_class.logger).to be(logger)
51+
end
1252
end
1353
end
14-
end
1554

16-
describe '#notice' do
17-
context 'with a prefix' do
18-
subject { described_class.new(device, 'foo: ') }
19-
it 'outputs message with prefix' do
20-
expect(device).to receive(:puts).with('foo: bar')
21-
subject.notice('bar')
55+
context 'when already set' do
56+
context 'with a custom logger' do
57+
let(:logger) { instance_double(Logger) }
58+
before { described_class.logger = logger }
59+
60+
context 'when reset' do
61+
before { described_class.logger = nil }
62+
63+
it 'outputs to null logger' do
64+
expect(described_class.logger).to be(null_logger)
65+
end
66+
end
2267
end
2368
end
2469
end

spec/lib/ruby_dep/travis/ruby_version_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
require 'ruby_dep/travis'
2+
13
RSpec.describe RubyDep::Travis::RubyVersion do
24
subject { described_class.new(travis_version_string) }
35

spec/lib/ruby_dep/warning_spec.rb

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
require 'ruby_dep/warning'
22

33
RSpec.describe RubyDep::Warning do
4-
let(:logger) { instance_double(RubyDep::Logger) }
4+
let(:logger) { instance_double(Logger) }
55

66
let(:outdated_ruby) { instance_double(RubyDep::RubyVersion) }
77
let(:up_to_date_ruby) { instance_double(RubyDep::RubyVersion) }
@@ -11,10 +11,9 @@
1111
let(:untracked_engine_ruby) { instance_double(RubyDep::RubyVersion) }
1212

1313
before do
14-
allow(RubyDep::Logger).to receive(:new)
15-
.with(STDERR, 'RubyDep: WARNING: ').and_return(logger)
16-
allow(logger).to receive(:warning)
17-
allow(logger).to receive(:notice)
14+
allow(RubyDep).to receive(:logger).and_return(logger)
15+
allow(logger).to receive(:warn)
16+
allow(logger).to receive(:info)
1817

1918
allow(RubyDep::RubyVersion).to receive(:new)
2019
.with(RUBY_VERSION, RUBY_ENGINE).and_return(ruby_version)
@@ -74,8 +73,8 @@ def rquote(str)
7473
context 'with any outdated Ruby' do
7574
let(:ruby_version) { outdated_ruby }
7675
it 'does not show anything' do
77-
expect(logger).to_not have_received(:warning)
78-
expect(logger).to_not have_received(:notice)
76+
expect(logger).to_not have_received(:warn)
77+
expect(logger).to_not have_received(:info)
7978
end
8079
end
8180
end
@@ -91,8 +90,8 @@ def rquote(str)
9190
context 'with any outdated Ruby' do
9291
let(:ruby_version) { outdated_ruby }
9392
it 'does not show anything' do
94-
expect(logger).to_not have_received(:warning)
95-
expect(logger).to_not have_received(:notice)
93+
expect(logger).to_not have_received(:warn)
94+
expect(logger).to_not have_received(:info)
9695
end
9796
end
9897
end
@@ -102,61 +101,61 @@ def rquote(str)
102101
context 'with an up-to-date Ruby' do
103102
let(:ruby_version) { up_to_date_ruby }
104103
it 'does not show anything' do
105-
expect(logger).to_not have_received(:warning)
106-
expect(logger).to_not have_received(:notice)
104+
expect(logger).to_not have_received(:warn)
105+
expect(logger).to_not have_received(:info)
107106
end
108107
end
109108

110109
context 'with a secure but buggy Ruby' do
111110
let(:ruby_version) { buggy_ruby }
112111
it 'shows warning about bugs' do
113-
expect(logger).to have_received(:warning).with(
112+
expect(logger).to have_received(:warn).with(
114113
%r{Your Ruby is outdated\/buggy.})
115114
end
116115

117116
it 'shows recommended action' do
118117
expected = rquote(
119118
'Your Ruby is: 2.2.4 (buggy). Recommendation: upgrade to'\
120119
' 2.2.5 or 2.3.1')
121-
expect(logger).to have_received(:notice).with(expected)
120+
expect(logger).to have_received(:info).with(expected)
122121
end
123122
end
124123

125124
context 'with an insecure Ruby' do
126125
let(:ruby_version) { insecure_ruby }
127126
it 'shows warning about vulnerability' do
128-
expect(logger).to have_received(:warning).with(
127+
expect(logger).to have_received(:warn).with(
129128
/Your Ruby has security vulnerabilities!/)
130129
end
131130

132131
it 'shows recommended action' do
133132
expected = rquote(
134133
'Your Ruby is: 2.2.3 (insecure). Recommendation:'\
135134
' upgrade to 2.2.5 or 2.3.1. (Or, at least to 2.2.4 or 2.3.0)')
136-
expect(logger).to have_received(:notice).with(expected)
135+
expect(logger).to have_received(:info).with(expected)
137136
end
138137
end
139138

140139
context 'with an unsupported Ruby' do
141140
let(:ruby_version) { unsupported_ruby }
142141
it 'shows warning about vulnerability' do
143-
expect(logger).to have_received(:warning).with(
142+
expect(logger).to have_received(:warn).with(
144143
/Your Ruby has security vulnerabilities!/)
145144
end
146145

147146
it 'shows recommended action' do
148147
expected = rquote(
149148
'Your Ruby is: 1.9.3 (insecure). Recommendation: upgrade to 2.2.5'\
150149
' or 2.3.1. (Or, at least to 2.1.9 or 2.2.4 or 2.3.0)')
151-
expect(logger).to have_received(:notice).with(expected)
150+
expect(logger).to have_received(:info).with(expected)
152151
end
153152
end
154153

155154
context 'with an untracked ruby engine' do
156155
context 'when the Ruby is not listed' do
157156
let(:ruby_version) { untracked_engine_ruby }
158157
it 'shows warning about lack of support' do
159-
expect(logger).to have_received(:warning).with(
158+
expect(logger).to have_received(:warn).with(
160159
/Your Ruby may not be supported./)
161160
end
162161

@@ -165,7 +164,7 @@ def rquote(str)
165164
"Your Ruby is: 1.2.3 'ironruby' (unrecognized). If you need"\
166165
' this version supported, please open an issue at'\
167166
' http://github.com/e2/ruby_dep')
168-
expect(logger).to have_received(:notice).with(expected)
167+
expect(logger).to have_received(:info).with(expected)
169168
end
170169
end
171170
end

0 commit comments

Comments
 (0)