yard 0.8.0 → 0.8.1
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/ChangeLog +67 -1
- data/README.md +8 -2
- data/docs/WhatsNew.md +34 -0
- data/lib/yard.rb +1 -1
- data/lib/yard/autoload.rb +2 -0
- data/lib/yard/cli/list.rb +1 -1
- data/lib/yard/cli/stats.rb +5 -1
- data/lib/yard/cli/yardoc.rb +27 -1
- data/lib/yard/code_objects/macro_object.rb +1 -1
- data/lib/yard/docstring.rb +28 -2
- data/lib/yard/docstring_parser.rb +69 -40
- data/lib/yard/handlers/base.rb +1 -1
- data/lib/yard/i18n/message.rb +56 -0
- data/lib/yard/i18n/messages.rb +55 -0
- data/lib/yard/i18n/pot_generator.rb +49 -50
- data/lib/yard/tags/directives.rb +1 -1
- data/lib/yard/tags/library.rb +42 -15
- data/lib/yard/verifier.rb +2 -2
- data/spec/cli/list_spec.rb +1 -1
- data/spec/cli/stats_spec.rb +5 -5
- data/spec/cli/yardoc_spec.rb +71 -2
- data/spec/docstring_parser_spec.rb +17 -0
- data/spec/i18n/message_spec.rb +52 -0
- data/spec/i18n/messages_spec.rb +67 -0
- data/spec/i18n/pot_generator_spec.rb +45 -27
- data/spec/i18n/text_spec.rb +2 -0
- data/spec/verifier_spec.rb +20 -0
- data/templates/default/fulldoc/html/{full_list_methods.erb → full_list_method.erb} +0 -0
- data/templates/default/fulldoc/html/setup.rb +1 -1
- data/templates/default/tags/html/option.erb +3 -1
- metadata +7 -3
data/lib/yard/handlers/base.rb
CHANGED
@@ -431,7 +431,7 @@ module YARD
|
|
431
431
|
# @since 0.8.0
|
432
432
|
def register_docstring(object, docstring = statement.comments, stmt = statement)
|
433
433
|
docstring = docstring.join("\n") if Array === docstring
|
434
|
-
parser =
|
434
|
+
parser = Docstring.parser
|
435
435
|
parser.parse(docstring || "", object, self)
|
436
436
|
|
437
437
|
if object && docstring
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module YARD
|
4
|
+
module I18n
|
5
|
+
# +Message+ is a translation target message. It has message ID as
|
6
|
+
# {#id} and some properties {#locations} and {#comments}.
|
7
|
+
#
|
8
|
+
# @since 0.8.1
|
9
|
+
class Message
|
10
|
+
# @return [String] the message ID of the trnslation target message.
|
11
|
+
attr_reader :id
|
12
|
+
|
13
|
+
# @return [Set] the set of locations. Location is an array of
|
14
|
+
# path and line number where the message is appered.
|
15
|
+
attr_reader :locations
|
16
|
+
|
17
|
+
# @return [Set] the set of comments for the messages.
|
18
|
+
attr_reader :comments
|
19
|
+
|
20
|
+
# Creates a trasnlate target message for message ID +id+.
|
21
|
+
#
|
22
|
+
# @param [String] id the message ID of the translate target message.
|
23
|
+
def initialize(id)
|
24
|
+
@id = id
|
25
|
+
@locations = Set.new
|
26
|
+
@comments = Set.new
|
27
|
+
end
|
28
|
+
|
29
|
+
# Adds location information for the message.
|
30
|
+
#
|
31
|
+
# @param [String] path the path where the message appears.
|
32
|
+
# @param [Integer] line the line number where the message appears.
|
33
|
+
# @return [void]
|
34
|
+
def add_location(path, line)
|
35
|
+
@locations << [path, line]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Adds a comment for the message.
|
39
|
+
#
|
40
|
+
# @param [String] comment the comment for the message to be added.
|
41
|
+
# @return [void]
|
42
|
+
def add_comment(comment)
|
43
|
+
@comments << comment unless comment.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
# @param [Message] other the +Message+ to be compared.
|
47
|
+
# @return [Boolean] checks whether this message is equal to another.
|
48
|
+
def ==(other)
|
49
|
+
other.is_a?(self.class) and
|
50
|
+
@id == other.id and
|
51
|
+
@locations == other.locations and
|
52
|
+
@comments == other.comments
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module YARD
|
2
|
+
module I18n
|
3
|
+
# Acts as a container for {Message} objects.
|
4
|
+
#
|
5
|
+
# @since 0.8.1
|
6
|
+
class Messages
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
# Creates a new container.
|
10
|
+
def initialize
|
11
|
+
@messages = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
# Enumerates each {Message} in the container.
|
15
|
+
#
|
16
|
+
# @yieldparam [Message] message the next message object in
|
17
|
+
# the enumeration.
|
18
|
+
# @return [void]
|
19
|
+
def each(&block)
|
20
|
+
@messages.each_value(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param [String] id the message ID to perform a lookup on.
|
24
|
+
# @return [Message, nil] a registered message for the given +id+,
|
25
|
+
# or nil if no message for the ID is found.
|
26
|
+
def [](id)
|
27
|
+
@messages[id]
|
28
|
+
end
|
29
|
+
|
30
|
+
# Registers a {Message}, the mssage ID of which is +id+. If
|
31
|
+
# corresponding +Message+ is already registered, the previously
|
32
|
+
# registered object is returned.
|
33
|
+
#
|
34
|
+
# @param [String] id the ID of the message to be registered.
|
35
|
+
# @return [Message] the registered +Message+.
|
36
|
+
def register(id)
|
37
|
+
@messages[id] ||= Message.new(id)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Checks if this messages list is equal to another messages list.
|
41
|
+
#
|
42
|
+
# @param [Messages] other the container to compare.
|
43
|
+
# @return [Boolean] whether +self+ and +other+ is equivalence or not.
|
44
|
+
def ==(other)
|
45
|
+
other.is_a?(self.class) and
|
46
|
+
@messages == other.messages
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
# @return [Hash{String=>Message}] the set of message objects
|
52
|
+
attr_reader :messages
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -62,26 +62,15 @@ module YARD
|
|
62
62
|
# @see http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
|
63
63
|
# GNU gettext manual about details of PO file
|
64
64
|
class PotGenerator
|
65
|
-
# Extracted messages.
|
66
|
-
# value is properties of the translation target message. The
|
67
|
-
# properties are added to the msgid entry for the translation
|
68
|
-
# target message. The properties are +:locations+ and
|
69
|
-
# +:comments+.
|
65
|
+
# Extracted messages.
|
70
66
|
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
# appeared. Each location is prepended +:relative_base_path+
|
74
|
-
# that is passed on creating a +PotGenerator+ instance.
|
75
|
-
#
|
76
|
-
# +:comments+ is an array of comment. All comments are added to
|
77
|
-
# the msgid entry for the translation target message.
|
78
|
-
#
|
79
|
-
# @api private
|
80
|
-
# @return [Hash{String => Hash{:locations => Array<Array[String, Integer]>, :comments => Array<String>}}]
|
67
|
+
# @return [Messages]
|
68
|
+
# @since 0.8.1
|
81
69
|
attr_reader :messages
|
82
70
|
|
83
71
|
# Creates a POT generator that uses +relative_base_path+ to
|
84
|
-
# generate locations for a msgid.
|
72
|
+
# generate locations for a msgid. +relative_base_path+ is
|
73
|
+
# prepended to all locations.
|
85
74
|
#
|
86
75
|
# @param [String] relative_base_path a relative working
|
87
76
|
# directory path from a directory path that has created .pot
|
@@ -89,7 +78,7 @@ module YARD
|
|
89
78
|
def initialize(relative_base_path)
|
90
79
|
@relative_base_path = relative_base_path
|
91
80
|
@extracted_objects = {}
|
92
|
-
@messages =
|
81
|
+
@messages = Messages.new
|
93
82
|
end
|
94
83
|
|
95
84
|
# Parses {CodeObjects::Base} objects and stores extracted msgids
|
@@ -118,17 +107,27 @@ module YARD
|
|
118
107
|
|
119
108
|
# Generates POT from +@messages+.
|
120
109
|
#
|
110
|
+
# One PO file entry is generated from a +Message+ in
|
111
|
+
# +@messages+.
|
112
|
+
#
|
113
|
+
# Locations of the +Message+ are used to generate the reference
|
114
|
+
# line that is started with "#: ". +relative_base_path+ passed
|
115
|
+
# when the generater is created is prepended to each path in location.
|
116
|
+
#
|
117
|
+
# Comments of the +Message+ are used to generate the
|
118
|
+
# translater-comment line that is started with "# ".
|
119
|
+
#
|
121
120
|
# @return [String] POT format string
|
122
121
|
def generate
|
123
122
|
pot = header
|
124
|
-
sorted_messages = @messages.sort_by do |message
|
125
|
-
sorted_locations =
|
123
|
+
sorted_messages = @messages.sort_by do |message|
|
124
|
+
sorted_locations = message.locations.sort_by do |location|
|
126
125
|
location
|
127
126
|
end
|
128
127
|
sorted_locations.first || []
|
129
128
|
end
|
130
|
-
sorted_messages.each do |message
|
131
|
-
generate_message(pot, message
|
129
|
+
sorted_messages.each do |message|
|
130
|
+
generate_message(pot, message)
|
132
131
|
end
|
133
132
|
pot
|
134
133
|
end
|
@@ -158,30 +157,30 @@ msgstr ""
|
|
158
157
|
EOH
|
159
158
|
end
|
160
159
|
|
161
|
-
def generate_message(pot, message
|
162
|
-
|
160
|
+
def generate_message(pot, message)
|
161
|
+
message.comments.sort.each do |comment|
|
163
162
|
pot << "# #{comment}\n" unless comment.empty?
|
164
163
|
end
|
165
|
-
|
164
|
+
message.locations.sort.each do |path, line|
|
166
165
|
pot << "#: #{@relative_base_path}/#{path}:#{line}\n"
|
167
166
|
end
|
168
|
-
|
169
|
-
|
170
|
-
pot << "msgid \"#{
|
167
|
+
escaped_message_id = escape_message_id(message.id)
|
168
|
+
escaped_message_id = escaped_message_id.gsub(/\n/, "\\\\n\"\n\"")
|
169
|
+
pot << "msgid \"#{escaped_message_id}\"\n"
|
171
170
|
pot << "msgstr \"\"\n"
|
172
171
|
pot << "\n"
|
173
172
|
pot
|
174
173
|
end
|
175
174
|
|
176
|
-
def
|
177
|
-
|
175
|
+
def escape_message_id(message_id)
|
176
|
+
message_id.gsub(/(\\|")/) do
|
178
177
|
special_character = $1
|
179
178
|
"\\#{special_character}"
|
180
179
|
end
|
181
180
|
end
|
182
181
|
|
183
|
-
def
|
184
|
-
@messages
|
182
|
+
def register_message(id)
|
183
|
+
@messages.register(id)
|
185
184
|
end
|
186
185
|
|
187
186
|
def extract_documents(object)
|
@@ -196,11 +195,11 @@ EOH
|
|
196
195
|
end
|
197
196
|
|
198
197
|
if object.group
|
199
|
-
message =
|
198
|
+
message = register_message(object.group)
|
200
199
|
object.files.each do |path, line|
|
201
|
-
message
|
200
|
+
message.add_location(path, line)
|
202
201
|
end
|
203
|
-
message
|
202
|
+
message.add_comment(object.path) unless object.path.empty?
|
204
203
|
end
|
205
204
|
|
206
205
|
docstring = object.docstring
|
@@ -210,11 +209,11 @@ EOH
|
|
210
209
|
case type
|
211
210
|
when :paragraph
|
212
211
|
paragraph, line_no = *args
|
213
|
-
message =
|
212
|
+
message = register_message(paragraph.rstrip)
|
214
213
|
object.files.each do |path, line|
|
215
|
-
message
|
214
|
+
message.add_location(path, (docstring.line || line) + line_no)
|
216
215
|
end
|
217
|
-
message
|
216
|
+
message.add_comment(object.path) unless object.path.empty?
|
218
217
|
else
|
219
218
|
raise "should not reach here: unexpected type: #{type}"
|
220
219
|
end
|
@@ -234,26 +233,26 @@ EOH
|
|
234
233
|
return if tag.name.nil?
|
235
234
|
return if tag.name.is_a?(String) and tag.name.empty?
|
236
235
|
key = "tag|#{tag.tag_name}|#{tag.name}"
|
237
|
-
message =
|
238
|
-
tag.object.files.each do |
|
239
|
-
message
|
236
|
+
message = register_message(key)
|
237
|
+
tag.object.files.each do |path, line|
|
238
|
+
message.add_location(path, line)
|
240
239
|
end
|
241
240
|
tag_label = "@#{tag.tag_name}"
|
242
241
|
tag_label << " [#{tag.types.join(', ')}]" if tag.types
|
243
|
-
message
|
242
|
+
message.add_comment(tag_label)
|
244
243
|
end
|
245
244
|
|
246
245
|
def extract_tag_text(tag)
|
247
246
|
return if tag.text.nil?
|
248
247
|
return if tag.text.empty?
|
249
|
-
message =
|
250
|
-
tag.object.files.each do |
|
251
|
-
message
|
248
|
+
message = register_message(tag.text)
|
249
|
+
tag.object.files.each do |path, line|
|
250
|
+
message.add_location(path, line)
|
252
251
|
end
|
253
252
|
tag_label = "@#{tag.tag_name}"
|
254
253
|
tag_label << " [#{tag.types.join(', ')}]" if tag.types
|
255
254
|
tag_label << " #{tag.name}" if tag.name
|
256
|
-
message
|
255
|
+
message.add_comment(tag_label)
|
257
256
|
end
|
258
257
|
|
259
258
|
def extract_paragraphs(file)
|
@@ -263,13 +262,13 @@ EOH
|
|
263
262
|
case type
|
264
263
|
when :attribute
|
265
264
|
name, value, line_no = *args
|
266
|
-
message =
|
267
|
-
message
|
268
|
-
message
|
265
|
+
message = register_message(value)
|
266
|
+
message.add_location(file.filename, line_no)
|
267
|
+
message.add_comment(name)
|
269
268
|
when :paragraph
|
270
269
|
paragraph, line_no = *args
|
271
|
-
message =
|
272
|
-
message
|
270
|
+
message = register_message(paragraph.rstrip)
|
271
|
+
message.add_location(file.filename, line_no)
|
273
272
|
else
|
274
273
|
raise "should not reach here: unexpected type: #{type}"
|
275
274
|
end
|
data/lib/yard/tags/directives.rb
CHANGED
@@ -386,7 +386,7 @@ module YARD
|
|
386
386
|
return if tag.text.empty?
|
387
387
|
handler = parser.handler
|
388
388
|
object = parser.object
|
389
|
-
self.parser =
|
389
|
+
self.parser = parser.class.new(parser.library)
|
390
390
|
parser.parse(tag.text, object, handler)
|
391
391
|
end
|
392
392
|
|
data/lib/yard/tags/library.rb
CHANGED
@@ -57,16 +57,17 @@ module YARD
|
|
57
57
|
# @see Directive
|
58
58
|
class Library
|
59
59
|
class << self
|
60
|
+
# @return [SymbolHash{Symbol=>String}] the map of tag names and their
|
61
|
+
# respective display labels.
|
60
62
|
attr_reader :labels
|
61
63
|
|
64
|
+
# @!attribute instance
|
65
|
+
# @return [Library] the main Library instance object.
|
62
66
|
def instance
|
63
67
|
@instance ||= new
|
64
68
|
end
|
65
69
|
|
66
|
-
|
67
|
-
@default_factory ||= DefaultFactory.new
|
68
|
-
end
|
69
|
-
|
70
|
+
# @!attribute default_factory
|
70
71
|
# Replace the factory object responsible for parsing tags by setting
|
71
72
|
# this to an object (or class) that responds to +parse_TAGNAME+ methods
|
72
73
|
# where +TAGNAME+ is the name of the tag.
|
@@ -80,6 +81,10 @@ module YARD
|
|
80
81
|
# @param [Class, Object] factory the factory that parses all tags
|
81
82
|
#
|
82
83
|
# @see DefaultFactory
|
84
|
+
def default_factory
|
85
|
+
@default_factory ||= DefaultFactory.new
|
86
|
+
end
|
87
|
+
|
83
88
|
def default_factory=(factory)
|
84
89
|
@default_factory = factory.is_a?(Class) ? factory.new : factory
|
85
90
|
end
|
@@ -256,19 +261,32 @@ module YARD
|
|
256
261
|
self.factory = factory
|
257
262
|
end
|
258
263
|
|
264
|
+
# @param [#to_s] tag_name the name of the tag to look for
|
265
|
+
# @return [Boolean] whether a tag by the given name is registered in
|
266
|
+
# the library.
|
259
267
|
def has_tag?(tag_name)
|
260
268
|
tag_name && respond_to?(self.class.tag_method_name(tag_name))
|
261
269
|
end
|
262
270
|
|
271
|
+
# Creates a new {Tag} object with a given tag name and data
|
272
|
+
# @return [Tag] the newly created tag object
|
263
273
|
def tag_create(tag_name, tag_buf)
|
264
274
|
send(self.class.tag_method_name(tag_name), tag_buf)
|
265
275
|
end
|
266
276
|
|
277
|
+
# @param [#to_s] tag_name the name of the tag to look for
|
278
|
+
# @return [Boolean] whether a directive by the given name is registered in
|
279
|
+
# the library.
|
267
280
|
def has_directive?(tag_name)
|
268
281
|
tag_name && respond_to?(self.class.directive_method_name(tag_name))
|
269
282
|
end
|
270
283
|
|
271
|
-
#
|
284
|
+
# Creates a new directive with tag information and a docstring parser
|
285
|
+
# object.
|
286
|
+
# @param [String] tag_name the name of the tag
|
287
|
+
# @param [String] tag_buf the tag data
|
288
|
+
# @param [DocstringParser] parser the parser object parsing the docstring
|
289
|
+
# @return [Directive] the newly created directive
|
272
290
|
def directive_create(tag_name, tag_buf, parser)
|
273
291
|
meth = self.class.factory_method_for(tag_name)
|
274
292
|
tag = send_to_factory(tag_name, meth, tag_buf)
|
@@ -277,9 +295,10 @@ module YARD
|
|
277
295
|
end
|
278
296
|
|
279
297
|
# @!macro yard.tag.transitive
|
280
|
-
# @note This tag is *transitive*. If
|
298
|
+
# @note This tag is *transitive*. If it is applied on a
|
281
299
|
# namespace (module or class), it will automatically be
|
282
|
-
# applied to all children objects of that namespace
|
300
|
+
# applied to all children objects of that namespace unless
|
301
|
+
# it is redefined on the child object.
|
283
302
|
|
284
303
|
# Marks a class/module/method as abstract with optional
|
285
304
|
# implementor information.
|
@@ -425,23 +444,31 @@ module YARD
|
|
425
444
|
# def load_page(url) end
|
426
445
|
define_tag "Parameters", :param, :with_types_and_name
|
427
446
|
|
428
|
-
#
|
429
|
-
#
|
430
|
-
#
|
431
|
-
#
|
432
|
-
#
|
433
|
-
#
|
447
|
+
# Declares that the _logical_ visibility of an object is private.
|
448
|
+
# In other words, it specifies that this method should be marked
|
449
|
+
# private but cannot due to Ruby's visibility restrictions. This
|
450
|
+
# exists for classes, modules and constants that do not obey Ruby's
|
451
|
+
# visibility rules. For instance, an inner class might be considered
|
452
|
+
# "private", though Ruby would make no such distinction.
|
453
|
+
#
|
454
|
+
# This tag is meant to be used in conjunction with the +--no-private+
|
455
|
+
# command-line option, and is required to actually remove these objects
|
456
|
+
# from documentation output. See {file:README.md} for more information on
|
457
|
+
# switches.
|
458
|
+
#
|
459
|
+
# If you simply want to set the API visibility of a method, you should
|
460
|
+
# look at the {tag:api} tag instead.
|
434
461
|
#
|
435
462
|
# @note This method is not recommended for hiding undocumented or
|
436
463
|
# "unimportant" methods. This tag should only be used to mark objects
|
437
464
|
# private when Ruby visibility rules cannot do so. In Ruby 1.9.3, you
|
438
465
|
# can use +private_constant+ to declare constants (like classes or
|
439
466
|
# modules) as private, and should be used instead of +@private+.
|
440
|
-
# @
|
441
|
-
# that namespace are also marked private.
|
467
|
+
# @macro yard.tag.transitive
|
442
468
|
# @example
|
443
469
|
# # @private
|
444
470
|
# class InteralImplementation; end
|
471
|
+
# @see tag:api
|
445
472
|
# @yard.signature
|
446
473
|
define_tag "Private", :private
|
447
474
|
|
data/lib/yard/verifier.rb
CHANGED
@@ -140,8 +140,8 @@ module YARD
|
|
140
140
|
#
|
141
141
|
# @return [String] the parsed expression
|
142
142
|
def parse_expression(expr)
|
143
|
-
expr = expr.gsub(/@@(\w+)/, 'object.tags("\1")')
|
144
|
-
expr = expr.gsub(/@(\w+)/, 'object.tag("\1")')
|
143
|
+
expr = expr.gsub(/@@(?:(\w+)|\{([\w\.]+)\})/, 'object.tags("\1\2")')
|
144
|
+
expr = expr.gsub(/@(?:(\w+)|\{([\w\.]+)\})/, 'object.tag("\1\2")')
|
145
145
|
expr
|
146
146
|
end
|
147
147
|
end
|