yard 0.7.4 → 0.7.5

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.

Files changed (47) hide show
  1. data/ChangeLog +162 -0
  2. data/README.md +20 -3
  3. data/docs/Glossary.md +2 -2
  4. data/docs/Overview.md +1 -1
  5. data/lib/yard.rb +1 -1
  6. data/lib/yard/cli/yardoc.rb +1 -0
  7. data/lib/yard/code_objects/base.rb +7 -0
  8. data/lib/yard/handlers/ruby/legacy/method_handler.rb +3 -1
  9. data/lib/yard/handlers/ruby/macro_handler_methods.rb +2 -1
  10. data/lib/yard/handlers/ruby/method_handler.rb +3 -1
  11. data/lib/yard/parser/c_parser.rb +48 -52
  12. data/lib/yard/parser/ruby/ruby_parser.rb +13 -1
  13. data/lib/yard/registry_store.rb +1 -1
  14. data/lib/yard/server/commands/library_command.rb +2 -1
  15. data/lib/yard/server/doc_server_helper.rb +3 -3
  16. data/lib/yard/server/doc_server_serializer.rb +9 -9
  17. data/lib/yard/server/rack_adapter.rb +1 -0
  18. data/lib/yard/server/router.rb +2 -0
  19. data/lib/yard/server/templates/doc_server/library_list/html/contents.erb +1 -1
  20. data/lib/yard/server/templates/doc_server/search/html/search.erb +1 -2
  21. data/lib/yard/server/webrick_adapter.rb +1 -0
  22. data/lib/yard/templates/helpers/html_helper.rb +48 -22
  23. data/spec/cli/yardoc_spec.rb +17 -0
  24. data/spec/code_objects/base_spec.rb +1 -1
  25. data/spec/handlers/examples/method_handler_001.rb.txt +4 -0
  26. data/spec/handlers/macro_handler_spec.rb +9 -0
  27. data/spec/handlers/method_handler_spec.rb +7 -0
  28. data/spec/parser/c_parser_spec.rb +134 -9
  29. data/spec/parser/ruby/ruby_parser_spec.rb +17 -1
  30. data/spec/registry_spec.rb +1 -0
  31. data/spec/registry_store_spec.rb +2 -2
  32. data/spec/server/doc_server_helper_spec.rb +51 -0
  33. data/spec/server/doc_server_serializer_spec.rb +10 -23
  34. data/spec/server/rack_adapter_spec.rb +2 -0
  35. data/spec/server/router_spec.rb +8 -1
  36. data/spec/templates/class_spec.rb +2 -1
  37. data/spec/templates/examples/module001.html +1 -1
  38. data/spec/templates/examples/module003.html +186 -0
  39. data/spec/templates/helpers/html_helper_spec.rb +57 -31
  40. data/spec/templates/module_spec.rb +22 -0
  41. data/spec/templates/tag_spec.rb +12 -0
  42. data/templates/default/fulldoc/html/js/full_list.js +6 -0
  43. data/templates/default/module/html/inherited_attributes.erb +6 -9
  44. data/templates/default/module/html/inherited_constants.erb +8 -8
  45. data/templates/default/module/setup.rb +22 -0
  46. data/templates/default/tags/setup.rb +4 -0
  47. metadata +4 -2
@@ -256,6 +256,7 @@ module YARD
256
256
  undef on_bare_assoc_hash
257
257
  undef on_assoclist_from_args
258
258
  undef on_aref
259
+ undef on_aref_field
259
260
  undef on_lbracket
260
261
  undef on_rbracket
261
262
  undef on_qwords_new
@@ -309,12 +310,19 @@ module YARD
309
310
  end
310
311
 
311
312
  def on_aref(*args)
313
+ @map[:lbracket].pop
312
314
  ll, lc = *@map[:aref].pop
313
315
  sr = args.first.source_range.first..lc
314
316
  lr = args.first.line_range.first..ll
315
317
  AstNode.new(:aref, args, :char => sr, :line => lr)
316
318
  end
317
-
319
+
320
+ def on_aref_field(*args)
321
+ @map[:lbracket].pop
322
+ AstNode.new(:aref_field, args,
323
+ :listline => lineno..lineno, :listchar => charno...charno)
324
+ end
325
+
318
326
  def on_array(other)
319
327
  node = AstNode.node_class_for(:array).new(:array, [other])
320
328
  map = @map[MAPPINGS[node.type]]
@@ -323,6 +331,10 @@ module YARD
323
331
  node.source_range = Range.new(sstart, @ns_charno - 1)
324
332
  node.line_range = Range.new(lstart, lineno)
325
333
  else
334
+ sstart = other.source_range.begin
335
+ lstart = other.line_range.begin
336
+ node.source_range = Range.new(sstart, @ns_charno - 1)
337
+ node.line_range = Range.new(lstart, lineno)
326
338
  node.source_range = other.source_range
327
339
  node.line_range = other.line_range
328
340
  end
@@ -139,7 +139,7 @@ module YARD
139
139
  destroy unless merge
140
140
 
141
141
  sdb = Registry.single_object_db
142
- if sdb == true || (sdb == nil && keys.size < 3000)
142
+ if sdb == true || sdb == nil
143
143
  @serializer.serialize(@store)
144
144
  else
145
145
  values(false).each do |object|
@@ -31,7 +31,7 @@ module YARD
31
31
 
32
32
  def initialize(opts = {})
33
33
  super
34
- self.serializer = DocServerSerializer.new(self)
34
+ self.serializer = DocServerSerializer.new
35
35
  end
36
36
 
37
37
  def call(request)
@@ -69,6 +69,7 @@ module YARD
69
69
  else
70
70
  yardoc.parse_arguments
71
71
  end
72
+ yardoc.send(:verify_markup_options)
72
73
  yardoc.options.delete(:serializer)
73
74
  options.update(yardoc.options.to_hash)
74
75
  end
@@ -10,9 +10,8 @@ module YARD
10
10
  def url_for(obj, anchor = nil, relative = false)
11
11
  return '' if obj.nil?
12
12
  return "/#{obj}" if String === obj
13
- super(obj, anchor, false)
13
+ File.join('', base_path(router.docs_prefix), super(obj, anchor, false))
14
14
  end
15
-
16
15
  # Modifies {Templates::Helpers::HtmlHelper#url_for_file} to return a URL instead
17
16
  # of a disk location.
18
17
  # @param (see Templates::Helpers::HtmlHelper#url_for_file)
@@ -30,7 +29,8 @@ module YARD
30
29
  # @param [String] path the path prefix for a base path URI
31
30
  # @return [String] the base URI for a library with an extra +path+ prefix
32
31
  def base_path(path)
33
- path + (@single_library ? '' : "/#{@library}")
32
+ libname = router.request.version_supplied ? @library.to_s : @library.name
33
+ path + (@single_library ? '' : "/#{libname}")
34
34
  end
35
35
 
36
36
  # @return [Router] convenience method for accessing the router
@@ -7,24 +7,24 @@ module YARD
7
7
  class DocServerSerializer < Serializers::FileSystemSerializer
8
8
  include WEBrick::HTTPUtils
9
9
 
10
- def initialize(command)
11
- super(:command => command, :extension => '')
10
+ def initialize(command = nil)
11
+ super(:basepath => '', :extension => '')
12
12
  end
13
13
 
14
14
  def serialized_path(object)
15
- path = case object
15
+ case object
16
16
  when CodeObjects::RootObject
17
17
  "toplevel"
18
18
  when CodeObjects::MethodObject
19
- return escape_path(serialized_path(object.namespace) + (object.scope == :instance ? ":" : ".") + object.name.to_s)
19
+ serialized_path(object.namespace) +
20
+ (object.scope == :instance ? ":" : ".") + escape(object.name.to_s)
20
21
  when CodeObjects::ConstantObject, CodeObjects::ClassVariableObject
21
- return escape_path(serialized_path(object.namespace)) + "##{object.name}-#{object.type}"
22
+ serialized_path(object.namespace) + "##{object.name}-#{object.type}"
23
+ when CodeObjects::ExtraFileObject
24
+ super(object).gsub(/^file./, 'file/')
22
25
  else
23
- object.path.gsub('::', '/')
26
+ super(object)
24
27
  end
25
- command = options[:command]
26
- library_path = command.single_library ? '' : '/' + command.library.to_s
27
- return escape_path(File.join('', command.adapter.router.docs_prefix, library_path, path))
28
28
  end
29
29
  end
30
30
  end
@@ -78,6 +78,7 @@ end
78
78
 
79
79
  # @private
80
80
  class Rack::Request
81
+ attr_accessor :version_supplied
81
82
  alias query params
82
83
  def xhr?; (env['HTTP_X_REQUESTED_WITH'] || "").downcase == "xmlhttprequest" end
83
84
  end
@@ -80,8 +80,10 @@ module YARD
80
80
  if libs = adapter.libraries[paths.first]
81
81
  paths.shift
82
82
  if library = libs.find {|l| l.version == paths.first }
83
+ request.version_supplied = true if request
83
84
  paths.shift
84
85
  else # use the last lib in the list
86
+ request.version_supplied = false if request
85
87
  library = libs.last
86
88
  end
87
89
  end
@@ -3,7 +3,7 @@
3
3
  <li class="r<%= @row = @row == 1 ? 2 : 1 %>">
4
4
  <% library_versions = library_versions.dup %>
5
5
  <% first_lib = library_versions.pop %>
6
- <a href="/<%= router.docs_prefix %>/<%= first_lib %>/frames"><%= name %></a>
6
+ <a href="/<%= router.docs_prefix %>/<%= first_lib.name %>/frames"><%= name %></a>
7
7
  <% if first_lib.version %>
8
8
  <small>(<%= first_lib.version %><% if library_versions.size > 0 %>,
9
9
  <%= library_versions.reverse.map {|lib| "<a href=\"/#{router.docs_prefix}/#{lib}/frames\">#{lib.version}</a>" }.join(', ') %><% end %>)</small>
@@ -7,8 +7,7 @@
7
7
  <% name = result.type == :method ? result.name(true).to_s : result.name.to_s %>
8
8
  <% path = name.gsub(/(#{Regexp.quote @query})/i, '<strong>\1</strong>') %>
9
9
  <li class="r<%= n %>">
10
- <a href="<%= serializer.serialized_path(result) %>"
11
- title="<%= result.path %>"><%= path %></a>
10
+ <a href="<%= url_for(result) %>" title="<%= result.path %>"><%= path %></a>
12
11
  <% if !result.namespace.root? %>
13
12
  <small>(<%= result.namespace.path %>)</small>
14
13
  <% end %>
@@ -38,5 +38,6 @@ end
38
38
 
39
39
  # @private
40
40
  class WEBrick::HTTPRequest
41
+ attr_accessor :version_supplied
41
42
  def xhr?; (self['X-Requested-With'] || "").downcase == 'xmlhttprequest' end
42
43
  end
@@ -44,14 +44,9 @@ module YARD
44
44
  html = html.encode(:invalid => :replace, :replace => '?')
45
45
  end
46
46
  html = resolve_links(html)
47
- html = html.gsub(/<pre\s*(?:lang="(.+?)")?>(?:\s*<code>)?(.+?)(?:<\/code>\s*)?<\/pre>/m) do
48
- language = $1
49
- string = $2
50
-
51
- string = html_syntax_highlight(CGI.unescapeHTML(string), language) unless options[:no_highlight]
52
- classes = ['code', language].compact.join(' ')
53
- %Q{<pre class="#{classes}">#{string}</pre>}
54
- end unless [:text, :none, :pre].include?(markup)
47
+ unless [:text, :none, :pre].include?(markup)
48
+ html = parse_codeblocks(html)
49
+ end
55
50
  html
56
51
  end
57
52
 
@@ -128,11 +123,11 @@ module YARD
128
123
  def html_markup_html(text)
129
124
  text
130
125
  end
131
-
126
+
132
127
  # Highlights Ruby source. Similar to {#html_syntax_highlight}, but
133
128
  # this method is meant to be called from {#htmlify} when markup is
134
129
  # set to "ruby".
135
- #
130
+ #
136
131
  # @param [String] source the Ruby source
137
132
  # @return [String] the highlighted HTML
138
133
  # @since 0.7.0
@@ -153,21 +148,15 @@ module YARD
153
148
  # +html_syntax_highlight_TYPE+ in this class.
154
149
  #
155
150
  # @param [String] source the source code to highlight
156
- # @param [Symbol] type the language type (:ruby, :plain, etc). Use
151
+ # @param [Symbol, String] type the language type (:ruby, :plain, etc). Use
157
152
  # :plain for no syntax highlighting.
158
153
  # @return [String] the highlighted source
159
154
  def html_syntax_highlight(source, type = nil)
160
155
  return "" unless source
161
156
  return h(source) if options[:no_highlight]
162
157
 
163
- type ||= object.source_type || :ruby
164
-
165
- # handle !!!LANG prefix to send to html_syntax_highlight_LANG
166
- if source =~ /\A(?:[ \t]*\r?\n)?[ \t]*!!!([\w.+-]+)[ \t]*\r?\n/
167
- type, source = $1, $'
168
- source = $'
169
- end
170
-
158
+ new_type, source = parse_lang_for_codeblock(source)
159
+ type ||= new_type || :ruby
171
160
  meth = "html_syntax_highlight_#{type}"
172
161
  respond_to?(meth) ? send(meth, source) : h(source)
173
162
  end
@@ -201,12 +190,12 @@ module YARD
201
190
  next(match[1..-1]) if escape
202
191
 
203
192
  next(match) if name[0,1] == '|'
204
-
193
+
205
194
  if name == '<a' && title =~ /href=["'](.+?)["'].*>.*<\/a>\s*(.*)\Z/
206
195
  name, title = $1, $2
207
196
  title = nil if title.empty?
208
197
  end
209
-
198
+
210
199
  if object.is_a?(String)
211
200
  object
212
201
  else
@@ -235,7 +224,7 @@ module YARD
235
224
  return title || file.title unless serializer
236
225
  link_url(url_for_file(file, anchor), title || file.title)
237
226
  end
238
-
227
+
239
228
  # (see BaseHelper#link_include_file)
240
229
  def link_include_file(file)
241
230
  unless file.is_a?(CodeObjects::ExtraFileObject)
@@ -514,6 +503,43 @@ module YARD
514
503
  end
515
504
  meth
516
505
  end
506
+
507
+ # Parses !!!lang out of codeblock, returning the codeblock language
508
+ # followed by the source code.
509
+ #
510
+ # @param [String] source the source code whose language to determine
511
+ # @return [Array(String, String)] the language, if any, and the
512
+ # remaining source
513
+ # @since 0.7.5
514
+ def parse_lang_for_codeblock(source)
515
+ type = nil
516
+ if source =~ /\A(?:[ \t]*\r?\n)?[ \t]*!!!([\w.+-]+)[ \t]*\r?\n/
517
+ type, source = $1, $'
518
+ end
519
+
520
+ [type, source]
521
+ end
522
+
523
+ # Parses code blocks out of html and performs syntax highlighting
524
+ # on code inside of the blocks.
525
+ #
526
+ # @param [String] html the html to search for code in
527
+ # @return [String] highlighted html
528
+ # @see #html_syntax_highlight
529
+ def parse_codeblocks(html)
530
+ html.gsub(/<pre\s*(?:lang="(.+?)")?>(?:\s*<code\s*(?:class="(.+?)")?\s*>)?(.+?)(?:<\/code>\s*)?<\/pre>/m) do
531
+ string = $3
532
+ # handle !!!LANG prefix to send to html_syntax_highlight_LANG
533
+ language, _ = parse_lang_for_codeblock(string)
534
+ language ||= $1 || $2 || object.source_type
535
+
536
+ unless options[:no_highlight]
537
+ string = html_syntax_highlight(CGI.unescapeHTML(string), language)
538
+ end
539
+ classes = ['code', language].compact.join(' ')
540
+ %Q{<pre class="#{classes}"><code>#{string}</code></pre>}
541
+ end
542
+ end
517
543
  end
518
544
  end
519
545
  end
@@ -269,6 +269,23 @@ describe YARD::CLI::Yardoc do
269
269
  @yardoc.run *%w( --asset foo:bar )
270
270
  @yardoc.assets.should == {'foo' => 'bar'}
271
271
  end
272
+
273
+ it "should not put from inside of to/ if from is a directory" do
274
+ begin
275
+ from = 'tmp_foo'
276
+ to = 'tmp_bar'
277
+ full_to = File.join(File.dirname(__FILE__), to)
278
+ FileUtils.mkdir_p(from)
279
+ @yardoc.options[:serializer].basepath = File.dirname(__FILE__)
280
+ @yardoc.run("--asset", "#{from}:#{to}")
281
+ @yardoc.run("--asset", "#{from}:#{to}")
282
+ File.directory?(full_to).should be_true
283
+ File.directory?(File.join(full_to, 'tmp_foo')).should be_false
284
+ ensure
285
+ FileUtils.rm_rf(from)
286
+ FileUtils.rm_rf(full_to)
287
+ end
288
+ end
272
289
  end
273
290
  end
274
291
 
@@ -298,7 +298,7 @@ describe YARD::CodeObjects::Base do
298
298
  it "should allow extra docstring after (see Path)" do
299
299
  ClassObject.new(:root, :AnotherObject) {|x| x.docstring = "FOO" }
300
300
  o = ClassObject.new(:root, :Me)
301
- o.docstring = "(see AnotherObject)\n\nEXTRA\n@api private"
301
+ o.docstring = Docstring.new("(see AnotherObject)\n\nEXTRA\n@api private", o)
302
302
  o.docstring.should == "FOO\n\nEXTRA"
303
303
  o.docstring.should have_tag(:api)
304
304
  end
@@ -69,6 +69,10 @@ end
69
69
  # @return [NotBoolean, nil]
70
70
  def boolean3?; end
71
71
 
72
+ # @overload rainy?
73
+ # @return whether today is the rainy day.
74
+ def rainy?; end
75
+
72
76
  attr_writer :attr_name
73
77
  def attr_name; end
74
78
 
@@ -154,4 +154,13 @@ describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}MacroHandler"
154
154
  obj.should_not be_nil
155
155
  obj.signature.should == 'def beep(a, b, c)'
156
156
  end
157
+
158
+ it "should not detect implicit macros with invalid method names" do
159
+ undoc_error <<-eof
160
+ ##
161
+ # IMPLICIT METHOD THAT SHOULD
162
+ # NOT BE DETECTED
163
+ dsl_method '/foo/bar'
164
+ eof
165
+ end
157
166
  end
@@ -106,6 +106,13 @@ describe "YARD::Handlers::Ruby::#{LEGACY_PARSER ? "Legacy::" : ""}MethodHandler"
106
106
  meth.tag(:return).types.should == ['NotBoolean', 'nil']
107
107
  end
108
108
 
109
+ it "should not change return type for method ending in ? with return types set by @overload" do
110
+ meth = P('Foo#rainy?')
111
+ meth.should have_tag(:overload)
112
+ meth.tag(:overload).should have_tag(:return)
113
+ meth.should_not have_tag(:return)
114
+ end
115
+
109
116
  it "should add method writer to existing attribute" do
110
117
  Registry.at('Foo#attr_name').should be_reader
111
118
  Registry.at('Foo#attr_name=').should be_writer
@@ -5,18 +5,23 @@ class YARD::Parser::CParser; def ensure_loaded!(a, b=1) a end end
5
5
 
6
6
  describe YARD::Parser::CParser do
7
7
  describe '#parse' do
8
- before(:all) do
9
- file = File.join(File.dirname(__FILE__), 'examples', 'array.c.txt')
10
- @parser = Parser::CParser.new(IO.read(file))
11
- @parser.parse
8
+ def parse(src = @contents)
9
+ YARD::Registry.clear
10
+ Parser::CParser.new(src).parse
12
11
  end
13
12
 
14
- def parse
15
- Registry.clear
16
- Parser::CParser.new(@contents).parse
13
+ def parse_init(src = @contents)
14
+ YARD::Registry.clear
15
+ Parser::CParser.new("void Init_Foo() {\n#{src}\n}").parse
17
16
  end
18
17
 
19
18
  describe 'Array class' do
19
+ before(:all) do
20
+ file = File.join(File.dirname(__FILE__), 'examples', 'array.c.txt')
21
+ @parser = Parser::CParser.new(IO.read(file))
22
+ @parser.parse
23
+ end
24
+
20
25
  it "should parse Array class" do
21
26
  obj = YARD::Registry.at('Array')
22
27
  obj.should_not be_nil
@@ -72,6 +77,49 @@ describe YARD::Parser::CParser do
72
77
  end
73
78
  end
74
79
 
80
+ describe 'Handling namespace parsing' do
81
+ it 'should track variable names defined under namespaces' do
82
+ @contents = <<-eof
83
+ void Init_Foo(void) {
84
+ mFoo = rb_define_module("Foo");
85
+ cBar = rb_define_class_under(mFoo, "Bar", rb_cObject);
86
+ rb_define_method(cBar, "foo", foo, 1);
87
+ }
88
+ eof
89
+ parse
90
+ Registry.at('Foo::Bar').should_not be_nil
91
+ Registry.at('Foo::Bar#foo').should_not be_nil
92
+ end
93
+
94
+ it 'should track variable names defined under namespaces' do
95
+ @contents = <<-eof
96
+ void Init_Foo(void) {
97
+ mFoo = rb_define_module("Foo");
98
+ cBar = rb_define_class_under(mFoo, "Bar", rb_cObject);
99
+ mBaz = rb_define_module_under(cBar, "Baz");
100
+ rb_define_method(mBaz, "foo", foo, 1);
101
+ }
102
+ eof
103
+ parse
104
+ Registry.at('Foo::Bar::Baz').should_not be_nil
105
+ Registry.at('Foo::Bar::Baz#foo').should_not be_nil
106
+ end
107
+
108
+ it "should handle rb_path2class() calls" do
109
+ @contents = <<-eof
110
+ void Init_Foo(void) {
111
+ somePath = rb_path2class("Foo::Bar::Baz")
112
+ mFoo = rb_define_module("Foo");
113
+ cBar = rb_define_class_under(mFoo, "Bar", rb_cObject);
114
+ mBaz = rb_define_module_under(cBar, "Baz");
115
+ rb_define_method(somePath, "foo", foo, 1);
116
+ }
117
+ eof
118
+ parse
119
+ Registry.at('Foo::Bar::Baz#foo').should_not be_nil
120
+ end
121
+ end
122
+
75
123
  describe 'Defining methods with source in other files' do
76
124
  it "should look in another file for method" do
77
125
  File.should_receive(:read).at_least(1).times.with('file.c').and_return(<<-eof)
@@ -134,7 +182,7 @@ describe YARD::Parser::CParser do
134
182
  void Init_Foo() {
135
183
  rb_cFoo = rb_define_class("Foo", rb_cObject);
136
184
  #{commented ? '/*' : ''}
137
- rb_define_attr(rb_cFoo, "foo", foo, #{read}, #{write});
185
+ rb_define_attr(rb_cFoo, "foo", #{read}, #{write});
138
186
  #{commented ? '*/' : ''}
139
187
  }
140
188
  eof
@@ -166,6 +214,67 @@ describe YARD::Parser::CParser do
166
214
  end
167
215
  end
168
216
 
217
+ describe 'Defining constants' do
218
+ it "should register constants" do
219
+ parse_init <<-eof
220
+ mFoo = rb_define_module("Foo");
221
+ rb_define_const(mFoo, "FOO", ID2SYM(100));
222
+ eof
223
+ Registry.at('Foo::FOO').type.should == :constant
224
+ end
225
+
226
+ it "should look for override comments" do
227
+ parse <<-eof
228
+ /* Document-const: FOO
229
+ * Foo bar!
230
+ */
231
+
232
+ void Init_Foo() {
233
+ mFoo = rb_define_module("Foo");
234
+ rb_define_const(mFoo, "FOO", ID2SYM(100));
235
+ }
236
+ eof
237
+ foo = Registry.at('Foo::FOO')
238
+ foo.type.should == :constant
239
+ foo.docstring.should == 'Foo bar!'
240
+ foo.value.should == 'ID2SYM(100)'
241
+ foo.file.should == '(stdin)'
242
+ end
243
+
244
+ it "should use comment attached to declaration as fallback" do
245
+ parse_init <<-eof
246
+ mFoo = rb_define_module("Foo");
247
+ /* foobar! */
248
+ rb_define_const(mFoo, "FOO", ID2SYM(100));
249
+ eof
250
+ foo = Registry.at('Foo::FOO')
251
+ foo.value.should == 'ID2SYM(100)'
252
+ foo.docstring.should == 'foobar!'
253
+ end
254
+
255
+ it "should allow the form VALUE: DOCSTRING to document value" do
256
+ parse_init <<-eof
257
+ mFoo = rb_define_module("Foo");
258
+ /* 100: foobar! */
259
+ rb_define_const(mFoo, "FOO", ID2SYM(100));
260
+ eof
261
+ foo = Registry.at('Foo::FOO')
262
+ foo.value.should == '100'
263
+ foo.docstring.should == 'foobar!'
264
+ end
265
+
266
+ it "should allow escaping of backslashes in VALUE: DOCSTRING syntax" do
267
+ parse_init <<-eof
268
+ mFoo = rb_define_module("Foo");
269
+ /* 100\\:x\\:y: foobar:x! */
270
+ rb_define_const(mFoo, "FOO", ID2SYM(100));
271
+ eof
272
+ foo = Registry.at('Foo::FOO')
273
+ foo.value.should == '100:x:y'
274
+ foo.docstring.should == 'foobar:x!'
275
+ end
276
+ end
277
+
169
278
  describe 'Defining aliases' do
170
279
  before do
171
280
  Registry.clear
@@ -186,6 +295,22 @@ describe YARD::Parser::CParser do
186
295
  Registry.at('Foo#bar').should be_is_alias
187
296
  Registry.at('Foo#bar').docstring.should == 'FOO'
188
297
  end
298
+
299
+ it "should allow defining of aliases (rb_define_alias) of attributes" do
300
+ @contents = <<-eof
301
+ /* FOO */
302
+ VALUE foo(VALUE x) { int value = x; }
303
+ void Init_Foo() {
304
+ rb_cFoo = rb_define_class("Foo", rb_cObject);
305
+ rb_define_attr(rb_cFoo, "foo", 1, 0);
306
+ rb_define_alias(rb_cFoo, "foo?", "foo");
307
+ }
308
+ eof
309
+ parse
310
+
311
+ Registry.at('Foo#foo').should be_reader
312
+ Registry.at('Foo#foo?').should be_is_alias
313
+ end
189
314
  end
190
315
  end
191
316
 
@@ -228,4 +353,4 @@ describe YARD::Parser::CParser do
228
353
  neg_self.source.should be_nil
229
354
  end
230
355
  end
231
- end
356
+ end