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.

@@ -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 = DocstringParser.new
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. Key is a translation target message and
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
- # +:locations+ is an array of location. Location is an array of
72
- # path and line number of the translation target message is
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, options|
125
- sorted_locations = (options[:locations] || []).sort_by do |location|
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, options|
131
- generate_message(pot, message, options)
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, options)
162
- options[:comments].compact.uniq.each do |comment|
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
- options[:locations].uniq.each do |path, line|
164
+ message.locations.sort.each do |path, line|
166
165
  pot << "#: #{@relative_base_path}/#{path}:#{line}\n"
167
166
  end
168
- escaped_message = escape_message(message)
169
- escaped_message = escaped_message.gsub(/\n/, "\\\\n\"\n\"")
170
- pot << "msgid \"#{escaped_message}\"\n"
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 escape_message(message)
177
- message.gsub(/(\\|")/) do
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 add_message(text)
184
- @messages[text] ||= {:locations => [], :comments => []}
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 = add_message(object.group)
198
+ message = register_message(object.group)
200
199
  object.files.each do |path, line|
201
- message[:locations] << [path, line]
200
+ message.add_location(path, line)
202
201
  end
203
- message[:comments] << object.path unless object.path.empty?
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 = add_message(paragraph.rstrip)
212
+ message = register_message(paragraph.rstrip)
214
213
  object.files.each do |path, line|
215
- message[:locations] << [path, (docstring.line || line) + line_no]
214
+ message.add_location(path, (docstring.line || line) + line_no)
216
215
  end
217
- message[:comments] << object.path unless object.path.empty?
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 = add_message(key)
238
- tag.object.files.each do |file|
239
- message[:locations] << file
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[:comments] << tag_label
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 = add_message(tag.text)
250
- tag.object.files.each do |file|
251
- message[:locations] << file
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[:comments] << tag_label
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 = add_message(value)
267
- message[:locations] << [file.filename, line_no]
268
- message[:comments] << name
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 = add_message(paragraph.rstrip)
272
- message[:locations] << [file.filename, line_no]
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
@@ -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 = DocstringParser.new(parser.library)
389
+ self.parser = parser.class.new(parser.library)
390
390
  parser.parse(tag.text, object, handler)
391
391
  end
392
392
 
@@ -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
- def default_factory
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
- # @return [Directive]
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 this tag is applied on a
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
- # Defines an object as private. This exists for classes,
429
- # modules and constants that do not obey Ruby's visibility rules. For
430
- # instance, an inner class might be considered "private", though Ruby
431
- # would make no such distinction. By declaring the @private tag, the
432
- # class can be hidden from documentation by using the +--no-private+
433
- # command-line switch to yardoc (see {file:README.md}).
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
- # @note If +@private+ is applied to a class or module, all methods within
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
 
@@ -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