rspec-core 3.3.2 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.document +1 -1
- data/.yardopts +1 -1
- data/Changelog.md +69 -0
- data/{License.txt → LICENSE.md} +6 -5
- data/README.md +18 -3
- data/lib/rspec/core/bisect/example_minimizer.rb +78 -39
- data/lib/rspec/core/configuration.rb +87 -25
- data/lib/rspec/core/configuration_options.rb +1 -1
- data/lib/rspec/core/example.rb +54 -7
- data/lib/rspec/core/example_group.rb +28 -8
- data/lib/rspec/core/example_status_persister.rb +16 -16
- data/lib/rspec/core/formatters.rb +1 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +44 -15
- data/lib/rspec/core/formatters/exception_presenter.rb +146 -59
- data/lib/rspec/core/formatters/helpers.rb +1 -1
- data/lib/rspec/core/formatters/html_formatter.rb +2 -2
- data/lib/rspec/core/formatters/html_printer.rb +2 -3
- data/lib/rspec/core/formatters/html_snippet_extractor.rb +116 -0
- data/lib/rspec/core/formatters/protocol.rb +9 -0
- data/lib/rspec/core/formatters/snippet_extractor.rb +124 -97
- data/lib/rspec/core/hooks.rb +2 -2
- data/lib/rspec/core/memoized_helpers.rb +2 -2
- data/lib/rspec/core/metadata.rb +3 -2
- data/lib/rspec/core/metadata_filter.rb +11 -6
- data/lib/rspec/core/notifications.rb +3 -2
- data/lib/rspec/core/option_parser.rb +22 -4
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +2 -2
- data/lib/rspec/core/rake_task.rb +12 -3
- data/lib/rspec/core/reporter.rb +18 -2
- data/lib/rspec/core/ruby_project.rb +1 -1
- data/lib/rspec/core/shared_example_group.rb +2 -0
- data/lib/rspec/core/source.rb +76 -0
- data/lib/rspec/core/source/location.rb +13 -0
- data/lib/rspec/core/source/node.rb +93 -0
- data/lib/rspec/core/source/syntax_highlighter.rb +71 -0
- data/lib/rspec/core/source/token.rb +43 -0
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +25 -6
- metadata +12 -9
- metadata.gz.sig +0 -0
- data/lib/rspec/core/bisect/subset_enumerator.rb +0 -39
- data/lib/rspec/core/mutex.rb +0 -63
- data/lib/rspec/core/reentrant_mutex.rb +0 -52
data/lib/rspec/core/metadata.rb
CHANGED
@@ -147,12 +147,13 @@ module RSpec
|
|
147
147
|
end
|
148
148
|
|
149
149
|
relative_file_path = Metadata.relative_path(file_path)
|
150
|
+
absolute_file_path = File.expand_path(relative_file_path)
|
150
151
|
metadata[:file_path] = relative_file_path
|
151
152
|
metadata[:line_number] = line_number.to_i
|
152
153
|
metadata[:location] = "#{relative_file_path}:#{line_number}"
|
153
|
-
metadata[:absolute_file_path] =
|
154
|
+
metadata[:absolute_file_path] = absolute_file_path
|
154
155
|
metadata[:rerun_file_path] ||= relative_file_path
|
155
|
-
metadata[:scoped_id] = build_scoped_id_for(
|
156
|
+
metadata[:scoped_id] = build_scoped_id_for(absolute_file_path)
|
156
157
|
end
|
157
158
|
|
158
159
|
def file_path_and_line_number_from(backtrace)
|
@@ -15,22 +15,19 @@ module RSpec
|
|
15
15
|
# @private
|
16
16
|
def filter_applies?(key, value, metadata)
|
17
17
|
silence_metadata_example_group_deprecations do
|
18
|
-
return filter_applies_to_any_value?(key, value, metadata) if Array === metadata[key] && !(Proc === value)
|
19
18
|
return location_filter_applies?(value, metadata) if key == :locations
|
20
19
|
return id_filter_applies?(value, metadata) if key == :ids
|
21
20
|
return filters_apply?(key, value, metadata) if Hash === value
|
22
21
|
|
23
22
|
return false unless metadata.key?(key)
|
23
|
+
return true if TrueClass === value && !!metadata[key]
|
24
|
+
return filter_applies_to_any_value?(key, value, metadata) if Array === metadata[key] && !(Proc === value)
|
24
25
|
|
25
26
|
case value
|
26
27
|
when Regexp
|
27
28
|
metadata[key] =~ value
|
28
29
|
when Proc
|
29
|
-
|
30
|
-
when 0 then value.call
|
31
|
-
when 2 then value.call(metadata[key], metadata)
|
32
|
-
else value.call(metadata[key])
|
33
|
-
end
|
30
|
+
proc_filter_applies?(key, value, metadata)
|
34
31
|
else
|
35
32
|
metadata[key].to_s == value.to_s
|
36
33
|
end
|
@@ -61,6 +58,14 @@ module RSpec
|
|
61
58
|
!(relevant_line_numbers(metadata) & preceding_declaration_lines).empty?
|
62
59
|
end
|
63
60
|
|
61
|
+
def proc_filter_applies?(key, proc, metadata)
|
62
|
+
case proc.arity
|
63
|
+
when 0 then proc.call
|
64
|
+
when 2 then proc.call(metadata[key], metadata)
|
65
|
+
else proc.call(metadata[key])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
64
69
|
def relevant_line_numbers(metadata)
|
65
70
|
Metadata.ascend(metadata).map { |meta| meta[:line_number] }
|
66
71
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
RSpec::Support.require_rspec_core "formatters/exception_presenter"
|
2
2
|
RSpec::Support.require_rspec_core "formatters/helpers"
|
3
3
|
RSpec::Support.require_rspec_core "shell_escape"
|
4
|
-
RSpec::Support.require_rspec_support "encoded_string"
|
5
4
|
|
6
5
|
module RSpec::Core
|
7
6
|
# Notifications are value objects passed to formatters to provide them
|
@@ -10,6 +9,7 @@ module RSpec::Core
|
|
10
9
|
# @private
|
11
10
|
module NullColorizer
|
12
11
|
module_function
|
12
|
+
|
13
13
|
def wrap(line, _code_or_symbol)
|
14
14
|
line
|
15
15
|
end
|
@@ -281,7 +281,8 @@ module RSpec::Core
|
|
281
281
|
# @attr pending_examples [Array<RSpec::Core::Example>] the pending examples
|
282
282
|
# @attr load_time [Float] the number of seconds taken to boot RSpec
|
283
283
|
# and load the spec files
|
284
|
-
SummaryNotification = Struct.new(:duration, :examples, :failed_examples,
|
284
|
+
SummaryNotification = Struct.new(:duration, :examples, :failed_examples,
|
285
|
+
:pending_examples, :load_time)
|
285
286
|
class SummaryNotification
|
286
287
|
# @api
|
287
288
|
# @return [Fixnum] the number of examples run
|
@@ -34,6 +34,8 @@ module RSpec::Core
|
|
34
34
|
private
|
35
35
|
|
36
36
|
# rubocop:disable MethodLength
|
37
|
+
# rubocop:disable Metrics/AbcSize
|
38
|
+
# rubocop:disable CyclomaticComplexity
|
37
39
|
def parser(options)
|
38
40
|
OptionParser.new do |parser|
|
39
41
|
parser.banner = "Usage: rspec [options] [files or directories]\n\n"
|
@@ -69,7 +71,18 @@ module RSpec::Core
|
|
69
71
|
bisect_and_exit(argument)
|
70
72
|
end
|
71
73
|
|
72
|
-
parser.on('--[no-]fail-fast', 'Abort the run
|
74
|
+
parser.on('--[no-]fail-fast[=COUNT]', 'Abort the run after a certain number of failures (1 by default).') do |argument|
|
75
|
+
if argument == true
|
76
|
+
value = 1
|
77
|
+
elsif argument == false || argument == 0
|
78
|
+
value = false
|
79
|
+
else
|
80
|
+
begin
|
81
|
+
value = Integer(argument)
|
82
|
+
rescue ArgumentError
|
83
|
+
RSpec.warning "Expected an integer value for `--fail-fast`, got: #{argument.inspect}", :call_site => nil
|
84
|
+
end
|
85
|
+
end
|
73
86
|
set_fail_fast(options, value)
|
74
87
|
end
|
75
88
|
|
@@ -174,12 +187,16 @@ FILTERING
|
|
174
187
|
parser.on("--next-failure", "Apply `--only-failures` and abort after one failure.",
|
175
188
|
" (Equivalent to `--only-failures --fail-fast --order defined`)") do
|
176
189
|
configure_only_failures(options)
|
177
|
-
set_fail_fast(options,
|
190
|
+
set_fail_fast(options, 1)
|
178
191
|
options[:order] ||= 'defined'
|
179
192
|
end
|
180
193
|
|
181
194
|
parser.on('-P', '--pattern PATTERN', 'Load files matching pattern (default: "spec/**/*_spec.rb").') do |o|
|
182
|
-
options[:pattern]
|
195
|
+
if options[:pattern]
|
196
|
+
options[:pattern] += ',' + o
|
197
|
+
else
|
198
|
+
options[:pattern] = o
|
199
|
+
end
|
183
200
|
end
|
184
201
|
|
185
202
|
parser.on('--exclude-pattern PATTERN',
|
@@ -246,10 +263,11 @@ FILTERING
|
|
246
263
|
raise OptionParser::InvalidOption.new
|
247
264
|
end
|
248
265
|
end
|
249
|
-
|
250
266
|
end
|
251
267
|
end
|
268
|
+
# rubocop:enable Metrics/AbcSize
|
252
269
|
# rubocop:enable MethodLength
|
270
|
+
# rubocop:enable CyclomaticComplexity
|
253
271
|
|
254
272
|
def add_tag_filter(options, filter_type, tag_name, value=true)
|
255
273
|
(options[filter_type] ||= {})[tag_name] = value
|
@@ -57,9 +57,9 @@ RSpec.configure do |config|
|
|
57
57
|
|
58
58
|
# Limits the available syntax to the non-monkey patched syntax that is
|
59
59
|
# recommended. For more details, see:
|
60
|
-
# - http://
|
60
|
+
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
61
61
|
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
62
|
-
# - http://
|
62
|
+
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
63
63
|
config.disable_monkey_patching!
|
64
64
|
|
65
65
|
# This setting enables warnings. It's recommended, but in some cases may
|
data/lib/rspec/core/rake_task.rb
CHANGED
@@ -1,7 +1,16 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/tasklib'
|
3
|
-
require 'rspec/support
|
4
|
-
|
3
|
+
require 'rspec/support'
|
4
|
+
|
5
|
+
RSpec::Support.require_rspec_support "ruby_features"
|
6
|
+
|
7
|
+
# :nocov:
|
8
|
+
unless RSpec::Support.respond_to?(:require_rspec_core)
|
9
|
+
RSpec::Support.define_optimized_require_for_rspec(:core) { |f| require_relative "../#{f}" }
|
10
|
+
end
|
11
|
+
# :nocov:
|
12
|
+
|
13
|
+
RSpec::Support.require_rspec_core "shell_escape"
|
5
14
|
|
6
15
|
module RSpec
|
7
16
|
module Core
|
@@ -91,7 +100,7 @@ module RSpec
|
|
91
100
|
|
92
101
|
def file_inclusion_specification
|
93
102
|
if ENV['SPEC']
|
94
|
-
FileList[
|
103
|
+
FileList[ENV['SPEC']].sort
|
95
104
|
elsif String === pattern && !File.exist?(pattern)
|
96
105
|
"--pattern #{escape pattern}"
|
97
106
|
else
|
data/lib/rspec/core/reporter.rb
CHANGED
@@ -8,7 +8,7 @@ module RSpec::Core
|
|
8
8
|
:close, :deprecation, :deprecation_summary, :dump_failures, :dump_pending,
|
9
9
|
:dump_profile, :dump_summary, :example_failed, :example_group_finished,
|
10
10
|
:example_group_started, :example_passed, :example_pending, :example_started,
|
11
|
-
:message, :seed, :start, :start_dump, :stop
|
11
|
+
:message, :seed, :start, :start_dump, :stop, :example_finished
|
12
12
|
])
|
13
13
|
|
14
14
|
def initialize(configuration)
|
@@ -124,6 +124,11 @@ module RSpec::Core
|
|
124
124
|
notify :example_started, Notifications::ExampleNotification.for(example)
|
125
125
|
end
|
126
126
|
|
127
|
+
# @private
|
128
|
+
def example_finished(example)
|
129
|
+
notify :example_finished, Notifications::ExampleNotification.for(example)
|
130
|
+
end
|
131
|
+
|
127
132
|
# @private
|
128
133
|
def example_passed(example)
|
129
134
|
notify :example_passed, Notifications::ExampleNotification.for(example)
|
@@ -192,6 +197,17 @@ module RSpec::Core
|
|
192
197
|
exit!(exit_status)
|
193
198
|
end
|
194
199
|
|
200
|
+
# @private
|
201
|
+
def fail_fast_limit_met?
|
202
|
+
return false unless (fail_fast = @configuration.fail_fast)
|
203
|
+
|
204
|
+
if fail_fast == true
|
205
|
+
@failed_examples.any?
|
206
|
+
else
|
207
|
+
fail_fast <= @failed_examples.size
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
195
211
|
private
|
196
212
|
|
197
213
|
def close
|
@@ -201,7 +217,7 @@ module RSpec::Core
|
|
201
217
|
def mute_profile_output?
|
202
218
|
# Don't print out profiled info if there are failures and `--fail-fast` is
|
203
219
|
# used, it just clutters the output.
|
204
|
-
!@configuration.profile_examples? ||
|
220
|
+
!@configuration.profile_examples? || fail_fast_limit_met?
|
205
221
|
end
|
206
222
|
|
207
223
|
def seed_used?
|
@@ -96,6 +96,7 @@ module RSpec
|
|
96
96
|
# Shared examples top level DSL.
|
97
97
|
module TopLevelDSL
|
98
98
|
# @private
|
99
|
+
# rubocop:disable Lint/NestedMethodDefinition
|
99
100
|
def self.definitions
|
100
101
|
proc do
|
101
102
|
def shared_examples(name, *args, &block)
|
@@ -105,6 +106,7 @@ module RSpec
|
|
105
106
|
alias shared_examples_for shared_examples
|
106
107
|
end
|
107
108
|
end
|
109
|
+
# rubocop:enable Lint/NestedMethodDefinition
|
108
110
|
|
109
111
|
# @private
|
110
112
|
def self.exposed_globally?
|
@@ -0,0 +1,76 @@
|
|
1
|
+
RSpec::Support.require_rspec_core 'source/node'
|
2
|
+
RSpec::Support.require_rspec_core 'source/syntax_highlighter'
|
3
|
+
RSpec::Support.require_rspec_core 'source/token'
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
module Core
|
7
|
+
# @private
|
8
|
+
# Represents a Ruby source file and provides access to AST and tokens.
|
9
|
+
class Source
|
10
|
+
attr_reader :source, :path
|
11
|
+
|
12
|
+
def self.from_file(path)
|
13
|
+
source = File.read(path)
|
14
|
+
new(source, path)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(source_string, path=nil)
|
18
|
+
@source = source_string
|
19
|
+
@path = path ? File.expand_path(path) : '(string)'
|
20
|
+
end
|
21
|
+
|
22
|
+
def lines
|
23
|
+
@lines ||= source.split("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def ast
|
27
|
+
@ast ||= begin
|
28
|
+
require 'ripper'
|
29
|
+
sexp = Ripper.sexp(source)
|
30
|
+
raise SyntaxError unless sexp
|
31
|
+
Node.new(sexp)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def tokens
|
36
|
+
@tokens ||= begin
|
37
|
+
require 'ripper'
|
38
|
+
tokens = Ripper.lex(source)
|
39
|
+
Token.tokens_from_ripper_tokens(tokens)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def nodes_by_line_number
|
44
|
+
@nodes_by_line_number ||= begin
|
45
|
+
nodes_by_line_number = ast.select(&:location).group_by { |node| node.location.line }
|
46
|
+
Hash.new { |hash, key| hash[key] = [] }.merge(nodes_by_line_number)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def tokens_by_line_number
|
51
|
+
@tokens_by_line_number ||= begin
|
52
|
+
nodes_by_line_number = tokens.group_by { |token| token.location.line }
|
53
|
+
Hash.new { |hash, key| hash[key] = [] }.merge(nodes_by_line_number)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
"#<#{self.class} #{path}>"
|
59
|
+
end
|
60
|
+
|
61
|
+
# @private
|
62
|
+
class Cache
|
63
|
+
attr_reader :syntax_highlighter
|
64
|
+
|
65
|
+
def initialize(configuration)
|
66
|
+
@sources_by_path = {}
|
67
|
+
@syntax_highlighter = SyntaxHighlighter.new(configuration)
|
68
|
+
end
|
69
|
+
|
70
|
+
def source_from_file(path)
|
71
|
+
@sources_by_path[path] ||= Source.from_file(path)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
class Source
|
4
|
+
# @private
|
5
|
+
# Represents a source location of node or token.
|
6
|
+
Location = Struct.new(:line, :column) do
|
7
|
+
def self.location?(array)
|
8
|
+
array.is_a?(Array) && array.size == 2 && array.all? { |e| e.is_a?(Integer) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
RSpec::Support.require_rspec_core "source/location"
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Core
|
5
|
+
class Source
|
6
|
+
# @private
|
7
|
+
# A wrapper for Ripper AST node which is generated with `Ripper.sexp`.
|
8
|
+
class Node
|
9
|
+
include Enumerable
|
10
|
+
|
11
|
+
attr_reader :sexp, :parent
|
12
|
+
|
13
|
+
def self.sexp?(array)
|
14
|
+
array.is_a?(Array) && array.first.is_a?(Symbol)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(ripper_sexp, parent=nil)
|
18
|
+
@sexp = ripper_sexp.freeze
|
19
|
+
@parent = parent
|
20
|
+
end
|
21
|
+
|
22
|
+
def type
|
23
|
+
sexp[0]
|
24
|
+
end
|
25
|
+
|
26
|
+
def args
|
27
|
+
@args ||= raw_args.map do |raw_arg|
|
28
|
+
if Node.sexp?(raw_arg)
|
29
|
+
Node.new(raw_arg, self)
|
30
|
+
elsif Location.location?(raw_arg)
|
31
|
+
Location.new(*raw_arg)
|
32
|
+
elsif raw_arg.is_a?(Array)
|
33
|
+
GroupNode.new(raw_arg, self)
|
34
|
+
else
|
35
|
+
raw_arg
|
36
|
+
end
|
37
|
+
end.freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
def children
|
41
|
+
@children ||= args.select { |arg| arg.is_a?(Node) }.freeze
|
42
|
+
end
|
43
|
+
|
44
|
+
def location
|
45
|
+
@location ||= args.find { |arg| arg.is_a?(Location) }
|
46
|
+
end
|
47
|
+
|
48
|
+
def each(&block)
|
49
|
+
return to_enum(__method__) unless block_given?
|
50
|
+
|
51
|
+
yield self
|
52
|
+
|
53
|
+
children.each do |child|
|
54
|
+
child.each(&block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def each_ancestor
|
59
|
+
return to_enum(__method__) unless block_given?
|
60
|
+
|
61
|
+
current_node = self
|
62
|
+
|
63
|
+
while (current_node = current_node.parent)
|
64
|
+
yield current_node
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def inspect
|
69
|
+
"#<#{self.class} #{type}>"
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def raw_args
|
75
|
+
sexp[1..-1] || []
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# @private
|
80
|
+
class GroupNode < Node
|
81
|
+
def type
|
82
|
+
:group
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def raw_args
|
88
|
+
sexp
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
class Source
|
4
|
+
# @private
|
5
|
+
# Provides terminal syntax highlighting of code snippets
|
6
|
+
# when coderay is available.
|
7
|
+
class SyntaxHighlighter
|
8
|
+
def initialize(configuration)
|
9
|
+
@configuration = configuration
|
10
|
+
end
|
11
|
+
|
12
|
+
def highlight(lines)
|
13
|
+
implementation.highlight_syntax(lines)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
if RSpec::Support::OS.windows?
|
19
|
+
# :nocov:
|
20
|
+
def implementation
|
21
|
+
WindowsImplementation
|
22
|
+
end
|
23
|
+
# :nocov:
|
24
|
+
else
|
25
|
+
def implementation
|
26
|
+
return color_enabled_implementation if @configuration.color_enabled?
|
27
|
+
NoSyntaxHighlightingImplementation
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def color_enabled_implementation
|
32
|
+
@color_enabled_implementation ||= begin
|
33
|
+
::Kernel.require 'coderay'
|
34
|
+
CodeRayImplementation
|
35
|
+
rescue LoadError
|
36
|
+
NoSyntaxHighlightingImplementation
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @private
|
41
|
+
module CodeRayImplementation
|
42
|
+
RESET_CODE = "\e[0m"
|
43
|
+
|
44
|
+
def self.highlight_syntax(lines)
|
45
|
+
highlighted = begin
|
46
|
+
CodeRay.encode(lines.join("\n"), :ruby, :terminal)
|
47
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue
|
48
|
+
return lines
|
49
|
+
end
|
50
|
+
|
51
|
+
highlighted.split("\n").map do |line|
|
52
|
+
line.sub(/\S/) { |char| char.insert(0, RESET_CODE) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @private
|
58
|
+
module NoSyntaxHighlightingImplementation
|
59
|
+
def self.highlight_syntax(lines)
|
60
|
+
lines
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# @private
|
65
|
+
# Not sure why, but our code above (and/or coderay itself) does not work
|
66
|
+
# on Windows, so we disable the feature on Windows.
|
67
|
+
WindowsImplementation = NoSyntaxHighlightingImplementation
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|