Class: Docks::Parsers::Base

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/docks/parsers/base_parser.rb

Direct Known Subclasses

CSS, CoffeeScript, JavaScript, Sass

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeBase

Returns a new instance of Base.



11
12
13
14
# File 'lib/docks/parsers/base_parser.rb', line 11

def initialize
  @comment_pattern = /#/
  setup_regexes
end

Instance Attribute Details

#comment_line_patternObject

Returns the value of attribute comment_line_pattern.



6
7
8
# File 'lib/docks/parsers/base_parser.rb', line 6

def comment_line_pattern
  @comment_line_pattern
end

#comment_patternObject

Returns the value of attribute comment_pattern.



6
7
8
# File 'lib/docks/parsers/base_parser.rb', line 6

def comment_pattern
  @comment_pattern
end

#pattern_block_extractorObject

Returns the value of attribute pattern_block_extractor.



6
7
8
# File 'lib/docks/parsers/base_parser.rb', line 6

def pattern_block_extractor
  @pattern_block_extractor
end

#symbol_block_extractorObject

Returns the value of attribute symbol_block_extractor.



6
7
8
# File 'lib/docks/parsers/base_parser.rb', line 6

def symbol_block_extractor
  @symbol_block_extractor
end

Instance Method Details

#parse(file) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/docks/parsers/base_parser.rb', line 16

def parse(file)
  symbols = []
  file_contents, file_given = if File.exists?(file)
    [File.read(file).gsub(/\r\n?/, "\n"), true]
  else
    [file, false]
  end

  # Get rid of the page block and, in the process, add the page block
  # to the set of parse results.
  lines_from_pattern_block = 0
  file_contents.sub!(@pattern_block_extractor) do |page_comment_block|
    start_line_number = $`.lines.count + 1
    lines_from_pattern_block = page_comment_block.lines.count
    page_comment_block.sub!(/#{@comment_pattern}\*\s*/, '')

    index = page_comment_block.index(/^\s*(?:#{@first_non_code_line_pattern}|#{@comment_pattern}\*$)/m)
    parseable_block, replacement = page_comment_block, ""

    if index
      index -= 1
      parseable_block = page_comment_block[0...index]
      replacement = page_comment_block[index..-1]
      lines_from_pattern_block -= replacement.lines.count
    end

    symbol = parse_comment_block(parseable_block)
    symbol.source = OpenStruct.new(file: file, language_code: Languages.extension_for_file(file), line_number: start_line_number) if file_given
    symbols << symbol

    replacement
  end

  # Scan through each symbols comment block and add it to the list of parsed symbols.
  last_match_position = 0
  while (match = file_contents.match(@symbol_block_extractor, last_match_position))
    symbol_details = symbol_details_from_first_line(match[:first_line])
    symbol = Containers.container_for(symbol_details[:symbol_type]).new(symbol_details)
    parse_comment_block(match[:comments], symbol)

    symbol.source = OpenStruct.new(file: file, language_code: Languages.extension_for_file(file), line_number: lines_from_pattern_block + match.pre_match.lines.count + match[0].lines.count) if file_given
    symbols << symbol

    last_match_position = match.offset(0).last
  end

  symbols
end

#parse_comment_block(comment_block, symbol = Containers::Symbol.new) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/docks/parsers/base_parser.rb', line 65

def parse_comment_block(comment_block, symbol = Containers::Symbol.new)
  if @tag_pattern.nil?
    supported_tags = Tags.supported_parseable_tags.sort! { |a, b| b.length <=> a.length }
    @tag_pattern = /(?:\s*@(?<tag>#{supported_tags.join("|")}) ?)?(?<text>.*)/
  end

  last_tag = nil

  comment_block.sub(/#{@comment_pattern}\*\s*/, '').gsub(@comment_line_pattern, "").strip.split("\n").each do |comment_line|
    line_details = comment_line.match(@tag_pattern)
    next if line_details.nil? || line_details[:text].nil?

    tag, text = line_details[:tag], line_details[:text]

    if tag.nil?
      if last_tag.nil?
        # No tag and no previous tag — must be description
        symbol[Tags::Description] ||= []
        symbol[Tags::Description] << text
      else
        # No tag, but has a previous tag — bundle with last tag. As discussed below,
        # multiple_allowed tags will be represented by an array of arrays, so append
        # this line to the last array within the main array. Otherwise, just append
        # the text to the main array.
        (symbol[last_tag].first.kind_of?(Array) ? symbol[last_tag].last : symbol[last_tag]) << text
      end
    else
      # New tag declaration
      tag = tag.to_sym
      tag_handler = Tags.tag_for(tag)
      multiline = tag_handler.multiline?
      last_tag = multiline ? tag : nil

      # If multiple tags are allowed, each one (the tag declaration, plus the following lines)
      # should be in an array inside the main array for that tag. Otherwise, the array
      # for the tag should only contain strings. If only one of that tag is available per tag,
      # overwrite the existing content. Non-multiline comments are always as minimally-Array-ed
      # as possible (if only one is allowed per file, the tag value will be the line. Otherwise,
      # it is added to a single-dimensional array).
      if tag_handler.multiple_allowed?
        symbol[tag] ||= []
        symbol[tag] << (multiline ? [text] : text)
      else
        symbol[tag] = multiline ? [text] : text
      end
    end
  end

  symbol
end