Class: NaslDoc::CLI::Comment

Inherits:
Object
  • Object
show all
Defined in:
lib/nasldoc/cli/comment.rb

Constant Summary collapse

@@tags =
[
  'anonparam',
  'category',
  'deprecated',
  'include',
  'nessus',
  'param',
  'remark',
  'return'
]

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(node, path) ⇒ Comment

Returns a new instance of Comment.



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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/nasldoc/cli/comment.rb', line 78

def initialize(node, path)
  # Create common attributes.
  @name = nil
  @type = nil
  @valid = false

  # Create freeform text attributes.
  @summary = nil
  @description = nil

  # Create tag attributes.
  @anonparams = {}
  @categories = []
  @deprecated = nil
  @includes = []
  @nessus = nil
  @params = {}
  @remarks = []
  @return = nil

  # Create export and function attributes.
  @function = nil

  # Create file attributes.
  @filename = nil
  @signed = nil

  # Create global attributes.
  @variables = []

  # Determine if this is a nasldoc comment.
  text = node.text.body;
  @valid = !Regexp.new("(^\s*\#{2,3}\s*$|#{trusted_regex})").match(text).nil?
  return unless @valid

  # Remember the type.
  unless node.next.nil?
    @type = node.next.class.name.gsub(/.*::/, '').downcase.to_sym
  else
    # The first comment in a file might not have a next node.
    @type = :file
  end

  # Store any other attributes we may need, since we're not keeping a
  # reference to the node.
  case @type
  when :export
    extract_function(node.function)
  when :file
    extract_file(node, path)
  when :function
    extract_function(node)
  when :global
    extract_global(node)
  else
    raise UnsupportedClassException, "The class #{node.next.class.name} is not supported."
  end

  # Parse the comment's text.
  parse(text)
end

Instance Attribute Details

#anonparamsObject

Tag attributes.



55
56
57
# File 'lib/nasldoc/cli/comment.rb', line 55

def anonparams
  @anonparams
end

#categoriesObject

Tag attributes.



55
56
57
# File 'lib/nasldoc/cli/comment.rb', line 55

def categories
  @categories
end

#deprecatedObject

Tag attributes.



55
56
57
# File 'lib/nasldoc/cli/comment.rb', line 55

def deprecated
  @deprecated
end

#descriptionObject

Freeform text attributes.



52
53
54
# File 'lib/nasldoc/cli/comment.rb', line 52

def description
  @description
end

#filenameObject

File attributes.



62
63
64
# File 'lib/nasldoc/cli/comment.rb', line 62

def filename
  @filename
end

#functionObject

Export and function attributes.



59
60
61
# File 'lib/nasldoc/cli/comment.rb', line 59

def function
  @function
end

#includesObject

Tag attributes.



55
56
57
# File 'lib/nasldoc/cli/comment.rb', line 55

def includes
  @includes
end

#nameObject (readonly)

Common attributes.



49
50
51
# File 'lib/nasldoc/cli/comment.rb', line 49

def name
  @name
end

#nessusObject

Tag attributes.



55
56
57
# File 'lib/nasldoc/cli/comment.rb', line 55

def nessus
  @nessus
end

#paramsObject

Returns the value of attribute params.



56
57
58
# File 'lib/nasldoc/cli/comment.rb', line 56

def params
  @params
end

#remarksObject

Returns the value of attribute remarks.



56
57
58
# File 'lib/nasldoc/cli/comment.rb', line 56

def remarks
  @remarks
end

#returnObject

Returns the value of attribute return.



56
57
58
# File 'lib/nasldoc/cli/comment.rb', line 56

def return
  @return
end

#signedObject

File attributes.



62
63
64
# File 'lib/nasldoc/cli/comment.rb', line 62

def signed
  @signed
end

#summaryObject

Freeform text attributes.



52
53
54
# File 'lib/nasldoc/cli/comment.rb', line 52

def summary
  @summary
end

#typeObject (readonly)

Common attributes.



49
50
51
# File 'lib/nasldoc/cli/comment.rb', line 49

def type
  @type
end

#validObject (readonly)

Common attributes.



49
50
51
# File 'lib/nasldoc/cli/comment.rb', line 49

def valid
  @valid
end

#variablesObject

Global attributes.



65
66
67
# File 'lib/nasldoc/cli/comment.rb', line 65

def variables
  @variables
end

Instance Method Details

#extract_file(node, path) ⇒ Object



288
289
290
291
292
293
294
295
296
297
298
# File 'lib/nasldoc/cli/comment.rb', line 288

def extract_file(node, path)
  # Remember the filename.
  @filename = File.basename(path)

  # Name this comment for use in error messages.
  @name = "file #@filename"

  # Determine whether the filename is signed, but don't validate the
  # signature.
  @signed = !Regexp.new(trusted_regex).match(node.text.body).nil?
end

#extract_function(node) ⇒ Object



300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/nasldoc/cli/comment.rb', line 300

def extract_function(node)
  # Remember the function name.
  fn = node.next
  @function = fn.to_s
  @fn_type = fn.fn_type

  # Name this comment for use in error messages.
  @name = "function " + fn.name.name

  # Add in all named parameters, even ones that weren't annotated.
  fn.params.each { |arg| @params[arg.name] = nil }
end

#extract_global(node) ⇒ Object



313
314
315
316
317
318
319
# File 'lib/nasldoc/cli/comment.rb', line 313

def extract_global(node)
  # Remember all the variables.
  @variables = node.next.idents.map &:name

  # Name this comment for use in error messages.
  @name = "global variable(s) #{@variables.join(', ')}"
end

#parse(text) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/nasldoc/cli/comment.rb', line 140

def parse(text)
  # Remove the trusted header.
  re_sig = Regexp.new(trusted_regex)
  text.gsub!(re_sig, '');

  # strip out empty comment lines with accidental whitespace afterwards
  text.gsub!(/^#+[ \t]+$/, '');
  # Remove the comment prefixes ('#') from the text.
  text.gsub!(/^#+/, '');

  # Parse all the paragraphs of free-form text.
  parse_paragraphs(text)

  # Parse all the tags.
  parse_tags(text)
end

#parse_paragraphs(text) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/nasldoc/cli/comment.rb', line 157

def parse_paragraphs(text)
  re_none = Regexp.new(/[^[:space:]]/)
  re_tags = Regexp.new(tags_regex)

  # Collect together a list of paragraphs.
  min = 9999
  paras = []
  text.each_line('') do |para|
    # Skip if the paragraph has a line starting with a tag, or has no
    # content.
    next unless para =~ re_none
    next if para =~ re_tags
    para.rstrip!
    paras << para

    # Determine the minimum indentation across all paragraphs.
    para.each_line do |line|
      padding = line[/^ */]
      min = [min, padding.length].min

      # No point in continuing if we hit the lower bound.
      break if min == 0
    end
  end

  # Strip the minimum number of spaces from the left.
  if min > 0
    regex = Regexp.new("^ {#{min}}")
    paras.map! { |p| p.gsub(regex, '') }
  end

  # The first paragraph is the summary.
  @summary = paras.shift

  # The following paragraphs are the description.
  @description = paras
end

#parse_tags(text) ⇒ Object



195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/nasldoc/cli/comment.rb', line 195

def parse_tags(text)
  re_name = Regexp.new("[_a-zA-Z][_a-zA-Z0-9]*")
  re_tags = Regexp.new(tags_regex)

  # Tags start a line which continues until the next tag or blank line.
  text.each_line('') do |para|
    # Skip if the paragraph it doesn't have a line starting with a tag.
    next if para !~ re_tags

    # Break the paragraphs into blocks, each starting with a tag.
    until para.empty?
      # Find the bounds of the block.
      beg = para.index(re_tags)
      break if beg.nil?
      fin = para.index(re_tags, beg + 1) || -1

      # Pull the block out of the paragraph.
      block = para[beg..fin]
      para = para[fin..-1]

      # Remove the tag from the block.
      tag = block[re_tags]
      block = block[tag.length..-1]
      next if block.nil?

      # Squash all spaces on the block, being mindful that if the block is
      # nil the tag is useless.
      block.gsub!(/[ \n\r\t]+/, ' ')
      next if block.nil?
      block.strip!
      next if block.nil?

      # Squash the tag and trim the '@' off for accessing the object's
      # attribute.
      tag.lstrip!
      attr = tag[1..-1]

      case tag
        when '@anonparam', '@param'
          # Parse the argument name.
          name = block[re_name]
          if name.nil?
            raise TagFormatException, "Failed to parse the #{tag}'s name for #@name."
          end

          block = block[name.length..-1]
          if block.nil?
            raise TagFormatException, "Failed to parse the #{tag}'s block for #@name."
          end
          block.lstrip!
          block = block.gsub(/^.*>/, "")

          # Check for previous declarations of this name.
          if @anonparams.key?(name)
            raise DuplicateTagException, "The param '#{name}' was previously declared as an @anonparam for #@name."
          end

          if @params.key?(name) and not @params[name].nil?
            raise DuplicateTagException, "The param '#{name}' was previously declared as a @param for #@name."
          end

          hash = self.send(attr + 's')
          hash[name] = block

        when '@category'
          unless @categories.empty?
            raise DuplicateTagException, "The #{tag} tag appears more than once for #@name."
          end

          @categories = block.split(/,/).map &:strip
        when '@deprecated', '@nessus', '@return'
          unless self.send(attr).nil?
            raise DuplicateTagException, "The #{tag} tag appears more than once for #@name."
          end

          self.send(attr + '=', block)
        when '@include', '@remark'
          self.send(attr + 's').push(block)
        else
          raise UnrecognizedTagException, "The #{tag} tag is not recognized in #@name."
      end
    end
  end
end

#tags_regexObject



280
281
282
# File 'lib/nasldoc/cli/comment.rb', line 280

def tags_regex
  "^\s*@(#{@@tags.join('|')})"
end

#trusted_regexObject



284
285
286
# File 'lib/nasldoc/cli/comment.rb', line 284

def trusted_regex
  "^#TRUSTED [[:xdigit:]]{1024}$"
end