yard 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of yard might be problematic. Click here for more details.
- data/LICENSE.txt +22 -0
- data/README.pdf +0 -0
- data/bin/yardoc +73 -0
- data/bin/yri +4 -0
- data/lib/code_object.rb +340 -0
- data/lib/formatter.rb +78 -0
- data/lib/handlers/all_handlers.rb +2 -0
- data/lib/handlers/attribute_handler.rb +46 -0
- data/lib/handlers/class_handler.rb +29 -0
- data/lib/handlers/class_variable_handler.rb +9 -0
- data/lib/handlers/code_object_handler.rb +104 -0
- data/lib/handlers/constant_handler.rb +11 -0
- data/lib/handlers/exception_handler.rb +20 -0
- data/lib/handlers/method_handler.rb +27 -0
- data/lib/handlers/mixin_handler.rb +9 -0
- data/lib/handlers/module_handler.rb +9 -0
- data/lib/handlers/visibility_handler.rb +7 -0
- data/lib/handlers/yield_handler.rb +31 -0
- data/lib/namespace.rb +98 -0
- data/lib/quick_doc.rb +104 -0
- data/lib/ruby_lex.rb +1318 -0
- data/lib/source_parser.rb +246 -0
- data/lib/tag_library.rb +162 -0
- data/lib/tag_type.rb +155 -0
- data/lib/yard.rb +3 -0
- data/templates/html_formatter.erb +455 -0
- data/test/fixtures/docstring.txt +23 -0
- data/test/fixtures/docstring2.txt +4 -0
- data/test/test_code_object.rb +66 -0
- data/test/test_namespace.rb +10 -0
- metadata +78 -0
@@ -0,0 +1,246 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require File.dirname(__FILE__) + '/ruby_lex'
|
3
|
+
require File.dirname(__FILE__) + '/namespace'
|
4
|
+
require File.dirname(__FILE__) + '/code_object'
|
5
|
+
require File.dirname(__FILE__) + '/handlers/all_handlers'
|
6
|
+
|
7
|
+
module YARD
|
8
|
+
##
|
9
|
+
# Responsible for parsing a source file into the namespace
|
10
|
+
class SourceParser
|
11
|
+
attr_reader :file
|
12
|
+
|
13
|
+
def self.parse(content)
|
14
|
+
new.parse(content)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.parse_string(content)
|
18
|
+
new.parse(StringIO.new(content))
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :current_namespace
|
22
|
+
|
23
|
+
def initialize
|
24
|
+
@current_namespace = NameStruct.new(Namespace.root)
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Creates a new SourceParser that parses a file and returns
|
29
|
+
# analysis information about it.
|
30
|
+
#
|
31
|
+
# @param [String, TokenList, StatementList] content the source file to parse
|
32
|
+
def parse(content = __FILE__)
|
33
|
+
case content
|
34
|
+
when String
|
35
|
+
@file = content
|
36
|
+
statements = StatementList.new(IO.read(content))
|
37
|
+
when TokenList
|
38
|
+
statements = StatementList.new(content)
|
39
|
+
when StatementList
|
40
|
+
statements = content
|
41
|
+
else
|
42
|
+
if content.respond_to? :read
|
43
|
+
statements = StatementList.new(content.read)
|
44
|
+
else
|
45
|
+
raise ArgumentError, "Invalid argument for SourceParser::parse: #{content.inspect}:#{content.class}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
top_level_parse(statements)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def top_level_parse(statements)
|
54
|
+
statements.each do |stmt|
|
55
|
+
find_handlers(stmt).each do |handler|
|
56
|
+
handler.new(self, stmt).process
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_handlers(stmt)
|
62
|
+
CodeObjectHandler.subclasses.find_all {|sub| sub.handles? stmt.tokens }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class StatementList < Array
|
67
|
+
include RubyToken
|
68
|
+
|
69
|
+
# The following list of tokens will require a block to be opened
|
70
|
+
# if used at the beginning of a statement.
|
71
|
+
@@open_block_tokens = [TkCLASS, TkDEF, TkMODULE, TkUNTIL,
|
72
|
+
TkIF, TkUNLESS, TkWHILE, TkFOR, TkCASE]
|
73
|
+
|
74
|
+
##
|
75
|
+
# Creates a new statement list
|
76
|
+
#
|
77
|
+
# @param [TokenList, String] content the tokens to create the list from
|
78
|
+
def initialize(content)
|
79
|
+
if content.is_a? TokenList
|
80
|
+
@tokens = content
|
81
|
+
elsif content.is_a? String
|
82
|
+
parse_tokens(content)
|
83
|
+
else
|
84
|
+
raise ArgumentError, "Invalid content for StatementList: #{content.inspect}:#{content.class}"
|
85
|
+
end
|
86
|
+
|
87
|
+
parse_statements
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
def parse_tokens(content)
|
92
|
+
@tokens = TokenList.new
|
93
|
+
lex = RubyLex.new(content)
|
94
|
+
while tk = lex.token do @tokens << tk end
|
95
|
+
end
|
96
|
+
|
97
|
+
def parse_statements
|
98
|
+
while stmt = next_statement do self << stmt end
|
99
|
+
end
|
100
|
+
|
101
|
+
# MUST REFACTOR THIS CODE
|
102
|
+
# WARNING WARNING WARNING WARNING
|
103
|
+
# MUST REFACTOR THIS CODE |
|
104
|
+
# OR CHILDREN WILL DIE V
|
105
|
+
# WARNING WARNING WARNING WARNING
|
106
|
+
# THIS IS MEANT TO BE UGLY.
|
107
|
+
def next_statement
|
108
|
+
statement, block, comments = TokenList.new, nil, nil
|
109
|
+
stmt_number, level = 0, 0
|
110
|
+
new_statement, open_block = true, false
|
111
|
+
last_tk, before_last_tk = nil, nil
|
112
|
+
open_parens = 0
|
113
|
+
|
114
|
+
while tk = @tokens.shift
|
115
|
+
#p tk.class
|
116
|
+
open_parens += 1 if [TkLPAREN, TkLBRACK].include? tk.class
|
117
|
+
open_parens -= 1 if [TkRPAREN, TkRBRACK].include?(tk.class) if open_parens > 0
|
118
|
+
|
119
|
+
# raise block.to_s + " TOKEN #{tk.inspect}" if open_parens < 0
|
120
|
+
|
121
|
+
# Get the initial comments
|
122
|
+
if statement.empty?
|
123
|
+
# Two new-lines in a row will destroy any comment blocks
|
124
|
+
if tk.class == TkCOMMENT && last_tk.class == TkNL &&
|
125
|
+
(before_last_tk && (before_last_tk.class == TkNL || before_last_tk.class == TkSPACE))
|
126
|
+
comments = nil
|
127
|
+
elsif tk.class == TkCOMMENT
|
128
|
+
# Remove the "#" and up to 1 space before the text
|
129
|
+
# Since, of course, the convention is to have "# text"
|
130
|
+
# and not "#text", which I deem ugly (you heard it here first)
|
131
|
+
comments ||= []
|
132
|
+
comments << (tk.text[/^#+\s{0,1}(\s*[^\s#].+)/, 1] || "")
|
133
|
+
comments.pop if comments.size == 1 && comments.first =~ /^\s*$/
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Ignore any initial comments or whitespace
|
138
|
+
unless statement.empty? && [TkSPACE, TkNL, TkCOMMENT].include?(tk.class)
|
139
|
+
# Decrease if end or '}' is seen
|
140
|
+
level -= 1 if [TkEND, TkRBRACE].include?(tk.class)
|
141
|
+
|
142
|
+
# If the level is greater than 0, add the code to the block text
|
143
|
+
# otherwise it's part of the statement text
|
144
|
+
if stmt_number > 0
|
145
|
+
block ||= TokenList.new
|
146
|
+
block << tk
|
147
|
+
elsif stmt_number == 0 && tk.class != TkNL && tk.class != TkCOMMENT
|
148
|
+
statement << tk
|
149
|
+
end
|
150
|
+
|
151
|
+
# puts "#{tk.line_no} #{level} #{tk} \t#{tk.text} #{tk.lex_state}"
|
152
|
+
|
153
|
+
# Increase level if we have a 'do' or block opening
|
154
|
+
if tk.class == TkLBRACE
|
155
|
+
level += 1
|
156
|
+
elsif [TkDO, TkfLBRACE, TkBEGIN].include?(tk.class)
|
157
|
+
#p "#{tk.line_no} #{level} #{tk} \t#{tk.text} #{tk.lex_state}"
|
158
|
+
level += 1
|
159
|
+
open_block = false # Cancel our wish to open a block for the if, we're doing it now
|
160
|
+
end
|
161
|
+
|
162
|
+
# Vouch to open a block when this statement would otherwise end
|
163
|
+
open_block = true if (new_statement || (last_tk && last_tk.lex_state == EXPR_BEG)) && @@open_block_tokens.include?(tk.class)
|
164
|
+
|
165
|
+
# Check if this token creates a new statement or not
|
166
|
+
#puts "#{open_parens} open brackets for: #{statement.to_s}"
|
167
|
+
if open_parens == 0 && ([TkSEMICOLON, TkNL, TkEND_OF_SCRIPT].include?(tk.class) ||
|
168
|
+
(statement.first.class == TkDEF && tk.class == TkRPAREN))
|
169
|
+
# Make sure we don't have any running expressions
|
170
|
+
# This includes things like
|
171
|
+
#
|
172
|
+
# class <
|
173
|
+
# Foo
|
174
|
+
#
|
175
|
+
# if a ||
|
176
|
+
# b
|
177
|
+
if [EXPR_END, EXPR_ARG].include? last_tk.lex_state
|
178
|
+
stmt_number += 1
|
179
|
+
new_statement = true
|
180
|
+
#p "NEW STATEMENT #{statement.to_s}"
|
181
|
+
|
182
|
+
# The statement started with a if/while/begin, so we must go to the next level now
|
183
|
+
if open_block
|
184
|
+
open_block = false
|
185
|
+
level += 1
|
186
|
+
end
|
187
|
+
end
|
188
|
+
elsif tk.class != TkSPACE
|
189
|
+
new_statement = false
|
190
|
+
end
|
191
|
+
|
192
|
+
# Else keyword is kind of weird
|
193
|
+
if tk.is_a? RubyToken::TkELSE
|
194
|
+
new_statement = true
|
195
|
+
stmt_number += 1
|
196
|
+
open_block = false
|
197
|
+
end
|
198
|
+
|
199
|
+
# We're done if we've ended a statement and we're at level 0
|
200
|
+
break if new_statement && level == 0
|
201
|
+
end
|
202
|
+
|
203
|
+
before_last_tk = last_tk
|
204
|
+
last_tk = tk # Save last token
|
205
|
+
end
|
206
|
+
|
207
|
+
# Return the code block with starting token and initial comments
|
208
|
+
# If there is no code in the block, return nil
|
209
|
+
comments = comments.compact if comments
|
210
|
+
statement.empty? ? nil : Statement.new(statement, block, comments)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
class TokenList < Array
|
215
|
+
def to_s
|
216
|
+
collect {|t| t.text }.join
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
class Statement
|
221
|
+
attr_reader :tokens, :comments, :block
|
222
|
+
|
223
|
+
def initialize(tokens, block = nil, comments = nil)
|
224
|
+
@tokens = clean_tokens(tokens)
|
225
|
+
@block = block
|
226
|
+
@comments = comments
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
def clean_tokens(tokens)
|
231
|
+
last_tk = nil
|
232
|
+
tokens.reject do |tk|
|
233
|
+
tk.is_a?(RubyToken::TkNL) ||
|
234
|
+
(last_tk.is_a?(RubyToken::TkSPACE) &&
|
235
|
+
last_tk.class == tk.class) && last_tk = tk
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
class NameStruct
|
241
|
+
attr_accessor :object, :attributes
|
242
|
+
def initialize(object)
|
243
|
+
@object, @attributes = object, { :visibility => :public, :scope => :instance }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
data/lib/tag_library.rb
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
module YARD
|
2
|
+
##
|
3
|
+
# Holds all the registered meta tags. If you want to extend YARD and add
|
4
|
+
# a new meta tag, you can do it in one of two ways.
|
5
|
+
#
|
6
|
+
# == Method #1
|
7
|
+
# Write your own +tagname_tag+ method that takes the raw text as a parameter.
|
8
|
+
# Example:
|
9
|
+
# def mytag_tag(text)
|
10
|
+
# Tag.parse_tag("mytag", text)
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# This will allow you to use @mytag TEXT to add meta data to classes through
|
14
|
+
# the docstring. {Tag} has a few convenience factory methods to create
|
15
|
+
#
|
16
|
+
# == Method #2
|
17
|
+
# Use {TagLibrary::define_tag!} to define a new tag by passing the tag name
|
18
|
+
# and the factory method to use when creating the tag. These definitions will
|
19
|
+
# be auto expanded into ruby code similar to what is shown in method #1. If you
|
20
|
+
# do not provide a factory method to use, it will default to {Tag::parse_tag}
|
21
|
+
# Example:
|
22
|
+
# define_tag! :param, :with_types_and_name
|
23
|
+
# define_tag! :author
|
24
|
+
#
|
25
|
+
# The first line will expand to the code:
|
26
|
+
# def param_tag(text) Tag.parse_tag_with_types_and_name(text) end
|
27
|
+
#
|
28
|
+
# The second line will expand to:
|
29
|
+
# def author_tag(text) Tag.parse_tag(text) end
|
30
|
+
#
|
31
|
+
# @see TagLibrary::define_tag!
|
32
|
+
module TagLibrary
|
33
|
+
class << self
|
34
|
+
##
|
35
|
+
# Convenience method to define a new tag using one of {Tag}'s factory methods, or the
|
36
|
+
# regular {Tag::parse_tag} factory method if none is supplied.
|
37
|
+
#
|
38
|
+
# @param tag the tag name to create
|
39
|
+
# @param meth the {Tag} factory method to call when creating the tag
|
40
|
+
def self.define_tag!(tag, meth = "")
|
41
|
+
meth = meth.to_s
|
42
|
+
send_name = meth.empty? ? "" : "_" + meth
|
43
|
+
class_eval "def #{tag}_tag(text) Tag.parse_tag#{send_name}(#{tag.inspect}, text) end"
|
44
|
+
end
|
45
|
+
|
46
|
+
define_tag! :param, :with_types_and_name
|
47
|
+
define_tag! :yieldparam, :with_types_and_name
|
48
|
+
define_tag! :yield
|
49
|
+
define_tag! :return, :with_types
|
50
|
+
define_tag! :deprecated
|
51
|
+
define_tag! :author
|
52
|
+
define_tag! :raise, :with_name
|
53
|
+
define_tag! :see
|
54
|
+
define_tag! :since
|
55
|
+
define_tag! :version
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Tag
|
60
|
+
attr_reader :tag_name, :text, :types, :name
|
61
|
+
|
62
|
+
class << self
|
63
|
+
##
|
64
|
+
# Parses tag text and creates a new tag with descriptive text
|
65
|
+
#
|
66
|
+
# @param tag_name the name of the tag to parse
|
67
|
+
# @param [String] text the raw tag text
|
68
|
+
# @return [Tag] a tag object with the tag_name and text values filled
|
69
|
+
def parse_tag(tag_name, text)
|
70
|
+
new(tag_name, text)
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Parses tag text and creates a new tag with a key name and descriptive text
|
75
|
+
#
|
76
|
+
# @param tag_name the name of the tag to parse
|
77
|
+
# @param [String] text the raw tag text
|
78
|
+
# @return [Tag] a tag object with the tag_name, name and text values filled
|
79
|
+
def parse_tag_with_name(tag_name, text)
|
80
|
+
name, text = *extract_name_from_text(text)
|
81
|
+
new(tag_name, text, nil, name)
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Parses tag text and creates a new tag with formally declared types and
|
86
|
+
# descriptive text
|
87
|
+
#
|
88
|
+
# @param tag_name the name of the tag to parse
|
89
|
+
# @param [String] text the raw tag text
|
90
|
+
# @return [Tag] a tag object with the tag_name, types and text values filled
|
91
|
+
def parse_tag_with_types(tag_name, text)
|
92
|
+
types, text = *extract_types_from_text(text)
|
93
|
+
new(tag_name, text, types)
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Parses tag text and creates a new tag with formally declared types, a key
|
98
|
+
# name and descriptive text
|
99
|
+
#
|
100
|
+
# @param tag_name the name of the tag to parse
|
101
|
+
# @param [String] text the raw tag text
|
102
|
+
# @return [Tag] a tag object with the tag_name, name, types and text values filled
|
103
|
+
def parse_tag_with_types_and_name(tag_name, text)
|
104
|
+
types, text = *extract_types_from_text(text)
|
105
|
+
name, text = *extract_name_from_text(text)
|
106
|
+
new(tag_name, text, types, name)
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Extracts the name from raw tag text returning the name and remaining value
|
111
|
+
#
|
112
|
+
# @param [String] text the raw tag text
|
113
|
+
# @return [Array] an array holding the name as the first element and the
|
114
|
+
# value as the second element
|
115
|
+
def extract_name_from_text(text)
|
116
|
+
text.strip.split(" ", 2)
|
117
|
+
end
|
118
|
+
|
119
|
+
##
|
120
|
+
# Extracts the type signatures from the raw tag text
|
121
|
+
#
|
122
|
+
# @param [String] text the raw tag text
|
123
|
+
# @return [Array] an array holding the value as the first element and
|
124
|
+
# the array of types as the second element
|
125
|
+
def extract_types_from_text(text)
|
126
|
+
types, text = [], text.strip
|
127
|
+
if text =~ /^\s*\[(.+?)\]\s*(.*)/
|
128
|
+
text, types = $2, $1.split(",").collect {|e| e.strip }
|
129
|
+
end
|
130
|
+
[types, text]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
##
|
135
|
+
# Creates a new tag object with a tag name and text. Optionally, formally declared types
|
136
|
+
# and a key name can be specified.
|
137
|
+
#
|
138
|
+
# Types are mainly for meta tags that rely on type information, such as +param+, +return+, etc.
|
139
|
+
#
|
140
|
+
# Key names are for tags that declare meta data for a specific key or name, such as +param+,
|
141
|
+
# +raise+, etc.
|
142
|
+
#
|
143
|
+
# @param tag_name the tag name to create the tag for
|
144
|
+
# @param [String] text the descriptive text for this tag
|
145
|
+
# @param [Array<String>] types optional type list of formally declared types
|
146
|
+
# for the tag
|
147
|
+
# @param [String] name optional key name which the tag refers to
|
148
|
+
def initialize(tag_name, text, types = nil, name = nil)
|
149
|
+
@tag_name, @text, @types, @name = tag_name.to_s, text, types, name
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
# Convenience method to access the first type specified. This should mainly
|
154
|
+
# be used for tags that only specify one type.
|
155
|
+
#
|
156
|
+
# @see #types
|
157
|
+
# @return (String) the first of the list of specified types
|
158
|
+
def type
|
159
|
+
types.first
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
data/lib/tag_type.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
module YARD
|
2
|
+
##
|
3
|
+
# Represents a tag and its respective tag name and value.
|
4
|
+
#
|
5
|
+
# @abstract Override this class to using the class name format of
|
6
|
+
# 'tagnameTag' to add a new tag to the registered tag library
|
7
|
+
class BaseTag
|
8
|
+
class << self
|
9
|
+
##
|
10
|
+
# Returns the tag name that the class responds to. If the class name
|
11
|
+
# does not accurately represent the tag name, this method should be overrided
|
12
|
+
# by subclasses to return the correct tag name.
|
13
|
+
#
|
14
|
+
# @return [String] the tag name the class represents
|
15
|
+
def tag_name
|
16
|
+
@tag_name ||= self.to_s.split("::").last.gsub(/^Base.+|Tag$/, '').downcase
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Return all valid tags in the tag library
|
21
|
+
#
|
22
|
+
# @return [Array<String>] a list of valid tags that are registered
|
23
|
+
# as being handled
|
24
|
+
def tag_library
|
25
|
+
@@tag_library || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# @override
|
30
|
+
def inherited(subclass)
|
31
|
+
@@tag_library ||= {}
|
32
|
+
@@tag_library[subclass.tag_name] = subclass unless subclass.tag_name.empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Parses tag text from a doc string and returns a new tag
|
37
|
+
def parse_tag(text)
|
38
|
+
new(text)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
## All tags have an optional field for text data
|
43
|
+
attr_reader :text
|
44
|
+
|
45
|
+
def initialize(text)
|
46
|
+
@text = text
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# @see BaseTag::tag_name
|
51
|
+
def tag_name
|
52
|
+
self.class.tag_name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Similar to the {BaseTag}, this class allows for a tag to
|
58
|
+
# formally specify type data if it depends on a specific object type.
|
59
|
+
#
|
60
|
+
class BaseTypeTag < BaseTag
|
61
|
+
##
|
62
|
+
# Attribute reader for all specified types
|
63
|
+
#
|
64
|
+
# @return [String] the object types that the tag formally specifies
|
65
|
+
attr_reader :types
|
66
|
+
|
67
|
+
##
|
68
|
+
# Extracts the type signatures from the raw tag text
|
69
|
+
#
|
70
|
+
# @param [String] text the raw tag text
|
71
|
+
# @return [Array] an array holding the value as the first element and
|
72
|
+
# the array of types as the second element
|
73
|
+
def self.extract_types_and_text(text)
|
74
|
+
types, value = [], text.strip
|
75
|
+
if text =~ /^\s*\[(.+?)\]\s*(.*)/
|
76
|
+
value = $2
|
77
|
+
types = $1.split(",").collect {|e| e.strip }
|
78
|
+
end
|
79
|
+
[value, types]
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Extracts the name from raw tag text returning the name and remaining value
|
84
|
+
#
|
85
|
+
# @param [String] text the raw tag text
|
86
|
+
# @return [Array] an array holding the name as the first element and the
|
87
|
+
# value as the second element
|
88
|
+
def self.extract_name_and_text(text)
|
89
|
+
text.strip.split(" ", 2)
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Create a new object with formally specified types
|
94
|
+
#
|
95
|
+
# @param [String] text the text data
|
96
|
+
# @param [Array<String>] types the types that are formally specified
|
97
|
+
# by the tag.
|
98
|
+
def initialize(text, types = [])
|
99
|
+
super(text)
|
100
|
+
@types = types || []
|
101
|
+
end
|
102
|
+
|
103
|
+
##
|
104
|
+
# Convenience method to access the first type specified. This should mainly
|
105
|
+
# be used for tags that only specify one type.
|
106
|
+
#
|
107
|
+
# @return (String) the first of the list of specified types
|
108
|
+
def type
|
109
|
+
types.first
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class ParamTag < BaseTypeTag
|
114
|
+
attr_reader :name
|
115
|
+
|
116
|
+
##
|
117
|
+
# Parses a typed tag's value section and returns a new {ParamTag} object
|
118
|
+
#
|
119
|
+
# @param [String] text the raw tag value to parse type specifications from
|
120
|
+
# @return [ParamTag] the new typed tag object with the type values
|
121
|
+
# parsed from raw text
|
122
|
+
def self.parse_tag(text)
|
123
|
+
desc, types = *extract_types_and_text(text)
|
124
|
+
name, desc = *extract_name_and_text(desc)
|
125
|
+
new(name, desc, types)
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Create a new +param+ tag with a description and declared types
|
130
|
+
#
|
131
|
+
# @param [String] name the parameter name specified by the tag
|
132
|
+
# @param [String] text a description of the parameter
|
133
|
+
# @param [Array<String>] types the optional types that the parameter accepts
|
134
|
+
def initialize(name, text, types = [])
|
135
|
+
super(text, types)
|
136
|
+
@name = name
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class ReturnTag < BaseTypeTag
|
141
|
+
def self.parse_tag(text)
|
142
|
+
new *extract_types_and_text(text)
|
143
|
+
end
|
144
|
+
|
145
|
+
def initialize(text, types = []) super end
|
146
|
+
end
|
147
|
+
|
148
|
+
class DeprecatedTag < BaseTag
|
149
|
+
def initialize(text) super end
|
150
|
+
end
|
151
|
+
|
152
|
+
class AuthorTag < BaseTag
|
153
|
+
def initialize(text) super end
|
154
|
+
end
|
155
|
+
end
|