Module: LineDetector

Defined in:
lib/version.rb,
lib/line-detector.rb

Overview

LineDetector - line ending detector

Defined Under Namespace

Classes: Report

Constant Summary collapse

VERSION =
'0.4'
EOL_CHARACTERS =
[
  "\r",
  "\n",
  "\v",
  "\f",
  "\u2028",
  "\u2029",
  "\u0085"
]
EOL2NAME =
{
  "\r\n" => :crlf,
  "\n\r" => :lfcr,
  "\n" => :lf,
  "\r" => :cr,
  "\v" => :vt,
  "\f" => :ff,
  "\u2028" => :ls,
  "\u2029" => :ps,
  "\u0085" => :nel
}
NAME2EOL =
EOL2NAME.invert

Class Method Summary collapse

Class Method Details

.detect_final_eol_of_file(filename) ⇒ Object

Detect presence of final end of line in a file

Assumes file is a text file.



101
102
103
# File 'lib/line-detector.rb', line 101

def self.detect_final_eol_of_file(filename)
  detect_final_eol_of_text(open(filename).read)
end

.detect_final_eol_of_text(text) ⇒ Object

Detects presence of final end of line in arbitrary text

“abcndefn” => true “abcrndefrn” => true “abcndef” => false “abcrndefr” => false “abcdef” => false “” => false



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/line-detector.rb', line 69

def self.detect_final_eol_of_text(text)
  line_ending = detect_line_ending_of_text(text)

  if line_ending == :none
    false
  elsif line_ending == :mix
    false
  else
    eol = NAME2EOL[line_ending] || :unknown

    if eol == :unknown
      false
    else
      text.end_with?(NAME2EOL[line_ending])
    end
  end
end

.detect_line_ending_of_file(filename) ⇒ Object

Detect line ending format of a file

Assumes file is a text file.



92
93
94
# File 'lib/line-detector.rb', line 92

def self.detect_line_ending_of_file(filename)
  detect_line_ending_of_text(open(filename).read)
end

.detect_line_ending_of_text(text) ⇒ Object

Detect line ending format of arbitrary text

If text uses multiple line ending formats, Returns :mix.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/line-detector.rb', line 39

def self.detect_line_ending_of_text(text)
  line_endings = text.split(/[^#{EOL_CHARACTERS.join('')}]/)
    .reject { |ending| ending == '' }
    .map { |ending| ending.gsub(/(.+?)(\1)+/m, '\1') }
    .uniq

  len = line_endings.length

  if len == 0
    :none
  elsif len == 1
    EOL2NAME[line_endings.first] || :unknown
  else
    :mix
  end
# Handle String#split errors on binary data
rescue ArgumentError
  :unknown
end

.lines(text) ⇒ Object

A more capable version of String#lines, that handles some of the more obscure line ending formats.

If line ending format cannot be determined, returns :unknown.



151
152
153
154
155
156
157
158
159
160
161
# File 'lib/line-detector.rb', line 151

def self.lines(text)
  line_ending = detect_line_ending_of_text(text)

  if line_ending == :unknown
    line_ending
  elsif line_ending == :none
    [text]
  else
    text.split(NAME2EOL[line_ending])
  end
end

.report_of_file(filename) ⇒ Object

Detect presence of final end of line in a file

Assumes file is a text file.



140
141
142
# File 'lib/line-detector.rb', line 140

def self.report_of_file(filename)
  report_of_text(open(filename).read)
end

.report_of_text(text) ⇒ Object

Report line ending and presence of final line ending of arbitrary text



128
129
130
131
132
133
# File 'lib/line-detector.rb', line 128

def self.report_of_text(text)
  Report.new(
    detect_line_ending_of_text(text),
    detect_final_eol_of_text(text)
  )
end