Class: Kss::CommentParser

Inherits:
Object
  • Object
show all
Defined in:
lib/kss/comment_parser.rb

Overview

Public: Takes a file path of a text file and extracts comments from it. Currently accepts two formats:

// Single line style. /* Multi-line style. */

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file_path_or_string_input, options = {}) ⇒ CommentParser

Public: Initializes a new comment parser object. Does not parse on initialization.

file_path_or_string_input - The location of the file to parse as a String, or the String itself. options - Optional options hash.

:preserve_whitespace - Preserve the whitespace before/after comment
                       markers (default:false).


66
67
68
69
70
71
72
73
74
75
76
# File 'lib/kss/comment_parser.rb', line 66

def initialize(file_path_or_string_input, options={})
  @options = options
  @options[:preserve_whitespace] = false if @options[:preserve_whitespace].nil?
  if File.exists?(file_path_or_string_input)
    @file_path = file_path_or_string_input
  else
    @string_input = file_path_or_string_input
  end
  @blocks = []
  @parsed = false
end

Class Method Details

.end_multi_line_comment?(line) ⇒ Boolean

Public: Is this the end of a multi-line comment? /* This style */

line - A String of one line of text.

Returns a boolean.

Returns:

  • (Boolean)


32
33
34
35
# File 'lib/kss/comment_parser.rb', line 32

def self.end_multi_line_comment?(line)
  return false if self.single_line_comment?(line)
  !!(line =~ /.*\*\//)
end

.parse_multi_line(line) ⇒ Object

Public: Remove comment identifiers for multi-line comments.

line - A String of one line of text.

Returns a String.



52
53
54
55
56
# File 'lib/kss/comment_parser.rb', line 52

def self.parse_multi_line(line)
  cleaned = line.to_s.sub(/\s*\/\*/, '')
  cleaned = cleaned.sub(/\*\//, '')
  cleaned.rstrip
end

.parse_single_line(line) ⇒ Object

Public: Removes comment identifiers for single-line comments.

line - A String of one line of text.

Returns a String.



42
43
44
45
# File 'lib/kss/comment_parser.rb', line 42

def self.parse_single_line(line)
  cleaned = line.to_s.sub(/\s*\/\//, '')
  cleaned.rstrip
end

.single_line_comment?(line) ⇒ Boolean

Public: Is this a single-line comment? // This style

line - A String of one line of text.

Returns a boolean.

Returns:

  • (Boolean)


14
15
16
# File 'lib/kss/comment_parser.rb', line 14

def self.single_line_comment?(line)
  !!(line =~ /^\s*\/\//)
end

.start_multi_line_comment?(line) ⇒ Boolean

Public: Is this the start of a multi-line comment? /* This style */

line - A String of one line of text.

Returns a boolean.

Returns:

  • (Boolean)


23
24
25
# File 'lib/kss/comment_parser.rb', line 23

def self.start_multi_line_comment?(line)
  !!(line =~ /^\s*\/\*/)
end

Instance Method Details

#blocksObject

Public: The different sections of parsed comment text. A section is either a multi-line comment block’s content, or consecutive lines of single-line comments.

Returns an Array of parsed comment Strings.



83
84
85
# File 'lib/kss/comment_parser.rb', line 83

def blocks
  @parsed ? @blocks : parse_blocks
end

#normalize(text_block) ⇒ Object

Normalizes the comment block to ignore any consistent preceding whitespace. Consistent means the same amount of whitespace on every line of the comment block. Also strips any whitespace at the start and end of the whole block.

Returns a String of normalized text.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/kss/comment_parser.rb', line 151

def normalize(text_block)
  return text_block if @options[:preserve_whitespace]

  # Strip out any preceding [whitespace]* that occur on every line. Not
  # the smartest, but I wonder if I care.
  text_block = text_block.gsub(/^(\s*\*+)/, '')

  # Strip consistent indenting by measuring first line's whitespace
  indent_size = nil
  unindented = text_block.split("\n").collect do |line|
    preceding_whitespace = line.scan(/^\s*/)[0].to_s.size
    indent_size = preceding_whitespace if indent_size.nil?
    if line == ""
      ""
    elsif indent_size <= preceding_whitespace && indent_size > 0
      line.slice(indent_size, line.length - 1)
    else
      line
    end
  end.join("\n")

  unindented.strip
end

#parse_blocksObject

Parse the file or string for comment blocks and populate them into @blocks.

Returns an Array of parsed comment Strings.



90
91
92
93
94
95
96
97
98
99
100
# File 'lib/kss/comment_parser.rb', line 90

def parse_blocks
  if !@file_path.nil?
    # the input is an existing file
    File.open @file_path do |file|
      parse_blocks_input(file)
    end
  else
    # @file_path is nil, we then expect the input to be a String
    parse_blocks_input(@string_input)
  end
end

#parse_blocks_input(input) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/kss/comment_parser.rb', line 102

def parse_blocks_input(input)
  current_block = nil
  inside_single_line_block = false
  inside_multi_line_block  = false

  input.each_line do |line|
    # Parse single-line style
    if self.class.single_line_comment?(line)
      parsed = self.class.parse_single_line line
      if inside_single_line_block
        current_block += "\n#{parsed}"
      else
        current_block = parsed.to_s
        inside_single_line_block = true
      end
    end

    # Parse multi-lines tyle
    if self.class.start_multi_line_comment?(line) || inside_multi_line_block
      parsed = self.class.parse_multi_line line
      if inside_multi_line_block
        current_block += "\n#{parsed}"
      else
        current_block = parsed
        inside_multi_line_block = true
      end
    end

    # End a multi-line block if detected
    inside_multi_line_block = false if self.class.end_multi_line_comment?(line)

    # Store the current block if we're done
    unless self.class.single_line_comment?(line) || inside_multi_line_block
      @blocks << normalize(current_block) unless current_block.nil?

      inside_single_line_block = false
      current_block = nil
    end
  end
  @parsed = true
  @blocks
end