ghazel-ffi-clang 0.2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +21 -0
  5. data/Gemfile +4 -0
  6. data/README.md +74 -0
  7. data/Rakefile +12 -0
  8. data/ext/rakefile.rb +12 -0
  9. data/ext/teapot.rb +16 -0
  10. data/ffi-clang.gemspec +26 -0
  11. data/lib/ffi/clang.rb +54 -0
  12. data/lib/ffi/clang/comment.rb +278 -0
  13. data/lib/ffi/clang/cursor.rb +378 -0
  14. data/lib/ffi/clang/diagnostic.rb +113 -0
  15. data/lib/ffi/clang/file.rb +69 -0
  16. data/lib/ffi/clang/index.rb +71 -0
  17. data/lib/ffi/clang/lib.rb +73 -0
  18. data/lib/ffi/clang/lib/comment.rb +117 -0
  19. data/lib/ffi/clang/lib/cursor.rb +353 -0
  20. data/lib/ffi/clang/lib/diagnostic.rb +87 -0
  21. data/lib/ffi/clang/lib/file.rb +57 -0
  22. data/lib/ffi/clang/lib/index.rb +34 -0
  23. data/lib/ffi/clang/lib/source_location.rb +53 -0
  24. data/lib/ffi/clang/lib/source_range.rb +46 -0
  25. data/lib/ffi/clang/lib/string.rb +45 -0
  26. data/lib/ffi/clang/lib/token.rb +58 -0
  27. data/lib/ffi/clang/lib/translation_unit.rb +106 -0
  28. data/lib/ffi/clang/lib/type.rb +154 -0
  29. data/lib/ffi/clang/lib/utils.rb +29 -0
  30. data/lib/ffi/clang/source_location.rb +149 -0
  31. data/lib/ffi/clang/source_range.rb +61 -0
  32. data/lib/ffi/clang/token.rb +95 -0
  33. data/lib/ffi/clang/translation_unit.rb +142 -0
  34. data/lib/ffi/clang/type.rb +135 -0
  35. data/lib/ffi/clang/unsaved_file.rb +49 -0
  36. data/lib/ffi/clang/utils.rb +58 -0
  37. data/lib/ffi/clang/version.rb +26 -0
  38. data/spec/clang/comment_spec.rb +470 -0
  39. data/spec/clang/cursor_spec.rb +709 -0
  40. data/spec/clang/diagnostic_spec.rb +89 -0
  41. data/spec/clang/file_spec.rb +84 -0
  42. data/spec/clang/index_spec.rb +70 -0
  43. data/spec/clang/source_location_spec.rb +140 -0
  44. data/spec/clang/source_range_spec.rb +76 -0
  45. data/spec/clang/token_spec.rb +83 -0
  46. data/spec/clang/translation_unit_spec.rb +214 -0
  47. data/spec/clang/type_spec.rb +289 -0
  48. data/spec/clang/utils_spec.rb +61 -0
  49. data/spec/fixtures/a.c +7 -0
  50. data/spec/fixtures/canonical.c +5 -0
  51. data/spec/fixtures/docs.c +1 -0
  52. data/spec/fixtures/docs.cc +1 -0
  53. data/spec/fixtures/docs.h +54 -0
  54. data/spec/fixtures/list.c +11 -0
  55. data/spec/fixtures/location1.c +7 -0
  56. data/spec/fixtures/simple.c +3 -0
  57. data/spec/fixtures/test.cxx +62 -0
  58. data/spec/spec_helper.rb +64 -0
  59. metadata +180 -0
@@ -0,0 +1,142 @@
1
+ # Copyright, 2010-2012 by Jari Bakken.
2
+ # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
3
+ # Copyright, 2014, by Masahiro Sano.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ require 'ffi/clang/lib/translation_unit'
24
+ require 'ffi/clang/cursor'
25
+ require 'ffi/clang/file'
26
+ require 'ffi/clang/token'
27
+
28
+ module FFI
29
+ module Clang
30
+ class TranslationUnit < AutoPointer
31
+ def initialize(pointer, index)
32
+ super pointer
33
+ @index = index
34
+ end
35
+
36
+ def self.release(pointer)
37
+ Lib.dispose_translation_unit(pointer)
38
+ end
39
+
40
+ def self.default_editing_translation_unit_options
41
+ bitmask = Lib.default_editing_translation_unit_options
42
+ Lib.opts_from Lib::TranslationUnitFlags, bitmask
43
+ end
44
+
45
+ def default_save_options
46
+ bitmask = Lib.default_save_options(self)
47
+ Lib.opts_from Lib::SaveTranslationUnitFlags, bitmask
48
+ end
49
+
50
+ def save(filename, opts = {})
51
+ ret = Lib.save_translation_unit(self, filename, 0)
52
+ sym = Lib::SaveError[ret]
53
+ raise Error, "unknown return values: #{ret} #{sym.inspect}" unless sym
54
+ raise Error, "save error: #{sym.inspect}, filename: #{filename}" if sym != :none
55
+ end
56
+
57
+ def default_reparse_options
58
+ bitmask = Lib.default_save_options(self)
59
+ Lib.opts_from Lib::ReparseFlags, bitmask
60
+ end
61
+
62
+ def reparse(unsaved = [], opts = {})
63
+ unsaved_files = UnsavedFile.unsaved_pointer_from(unsaved)
64
+ if Lib.reparse_translation_unit(self, unsaved.size, unsaved_files, 0) != 0
65
+ raise Error, "reparse error"
66
+ end
67
+ end
68
+
69
+ def diagnostics
70
+ n = Lib.get_num_diagnostics(self)
71
+
72
+ n.times.map do |i|
73
+ Diagnostic.new(self, Lib.get_diagnostic(self, i))
74
+ end
75
+ end
76
+
77
+ def cursor(location = nil)
78
+ if location.nil?
79
+ Cursor.new Lib.get_translation_unit_cursor(self), self
80
+ else
81
+ Cursor.new Lib.get_cursor(self, location.location), self
82
+ end
83
+ end
84
+
85
+ def location(file, line, column)
86
+ ExpansionLocation.new Lib.get_location(self, file, line, column)
87
+ end
88
+
89
+ def location_offset(file, offset)
90
+ ExpansionLocation.new Lib.get_location_offset(self, file, offset)
91
+ end
92
+
93
+ def file(file_name)
94
+ File.new(Lib.get_file(self, file_name), self)
95
+ end
96
+
97
+ def spelling
98
+ Lib.get_translation_unit_spelling(self)
99
+ end
100
+
101
+ def resource_usage
102
+ FFI::Clang::TranslationUnit::ResourceUsage.new Lib.resource_usage(self)
103
+ end
104
+
105
+ def tokenize(range)
106
+ token_ptr = MemoryPointer.new :pointer
107
+ uint_ptr = MemoryPointer.new :uint
108
+ Lib.tokenize(self, range.range, token_ptr, uint_ptr)
109
+ Tokens.new(token_ptr.get_pointer(0), uint_ptr.get_uint(0), self)
110
+ end
111
+
112
+ class ResourceUsage < AutoPointer
113
+ def initialize(resource_usage)
114
+ # CXResourceUsage is returned by value and should be freed explicitly.
115
+ # Get FFI::pointer of the data so that the data is handled by AutoPointer.
116
+ pointer = FFI::Pointer.new(resource_usage.to_ptr)
117
+ super(pointer)
118
+ @resource_usage = resource_usage
119
+ end
120
+
121
+ def self.release(pointer)
122
+ # clang_disposeCXTUResourceUsage requires value type, so create it by pointer
123
+ Lib.dispose_resource_usage(Lib::CXTUResourceUsage.new(pointer))
124
+ end
125
+
126
+ def self.name(kind)
127
+ Lib.resource_usage_name(kind)
128
+ end
129
+
130
+ def entries
131
+ ary = []
132
+ ptr = @resource_usage[:entries]
133
+ @resource_usage[:numEntries].times {
134
+ ary << Lib::CXTUResourceUsageEntry.new(ptr)
135
+ ptr += Lib::CXTUResourceUsageEntry.size
136
+ }
137
+ ary
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,135 @@
1
+ # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ # Copyright, 2014, by Masahiro Sano.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ require 'ffi/clang/cursor'
23
+
24
+ module FFI
25
+ module Clang
26
+ class Type
27
+ attr_reader :type
28
+
29
+ def initialize(type, translation_unit)
30
+ @type = type
31
+ @translation_unit = translation_unit
32
+ end
33
+
34
+ def kind
35
+ @type[:kind]
36
+ end
37
+
38
+ def kind_spelling
39
+ Lib.extract_string Lib.get_type_kind_spelling @type[:kind]
40
+ end
41
+
42
+ def spelling
43
+ Lib.extract_string Lib.get_type_spelling(@type)
44
+ end
45
+
46
+ def variadic?
47
+ Lib.is_function_type_variadic(@type) != 0
48
+ end
49
+
50
+ def pod?
51
+ Lib.is_pod_type(@type) != 0
52
+ end
53
+
54
+ def num_arg_types
55
+ Lib.get_num_arg_types(@type)
56
+ end
57
+
58
+ def pointee
59
+ Type.new Lib.get_pointee_type(@type), @translation_unit
60
+ end
61
+
62
+ def canonical
63
+ Type.new Lib.get_canonical_type(@type), @translation_unit
64
+ end
65
+
66
+ def class_type
67
+ Type.new Lib.type_get_class_type(@type), @translation_unit
68
+ end
69
+
70
+ def const_qualified?
71
+ Lib.is_const_qualified_type(@type) != 0
72
+ end
73
+
74
+ def volatile_qualified?
75
+ Lib.is_volatile_qualified_type(@type) != 0
76
+ end
77
+
78
+ def restrict_qualified?
79
+ Lib.is_restrict_qualified_type(@type) != 0
80
+ end
81
+
82
+ def arg_type(i)
83
+ Type.new Lib.get_arg_type(@type, i), @translation_unit
84
+ end
85
+
86
+ def result_type
87
+ Type.new Lib.get_result_type(@type), @translation_unit
88
+ end
89
+
90
+ def element_type
91
+ Type.new Lib.get_element_type(@type), @translation_unit
92
+ end
93
+
94
+ def num_elements
95
+ Lib.get_num_elements(@type)
96
+ end
97
+
98
+ def array_element_type
99
+ Type.new Lib.get_array_element_type(@type), @translation_unit
100
+ end
101
+
102
+ def array_size
103
+ Lib.get_array_size(@type)
104
+ end
105
+
106
+ def alignof
107
+ Lib.type_get_align_of(@type)
108
+ end
109
+
110
+ def sizeof
111
+ Lib.type_get_size_of(@type)
112
+ end
113
+
114
+ def offsetof(field)
115
+ Lib.type_get_offset_of(@type, field)
116
+ end
117
+
118
+ def ref_qualifier
119
+ Lib.type_get_cxx_ref_qualifier(@type)
120
+ end
121
+
122
+ def calling_conv
123
+ Lib.get_fuction_type_calling_conv(@type)
124
+ end
125
+
126
+ def declaration
127
+ Cursor.new Lib.get_type_declaration(@type), @translation_unit
128
+ end
129
+
130
+ def ==(other)
131
+ Lib.equal_types(@type, other.type) != 0
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,49 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright, 2013, by Carlos Martín Nieto <cmn@dwim.me.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ module FFI
23
+ module Clang
24
+ class UnsavedFile
25
+ def initialize(filename, contents)
26
+ @filename = filename
27
+ @contents = contents
28
+ end
29
+
30
+ attr_accessor :filename, :contents
31
+
32
+
33
+ def self.unsaved_pointer_from(unsaved)
34
+ return nil if unsaved.length == 0
35
+
36
+ vec = MemoryPointer.new(Lib::CXUnsavedFile, unsaved.length)
37
+
38
+ unsaved.each_with_index do |file, i|
39
+ uf = Lib::CXUnsavedFile.new(vec + i * Lib::CXUnsavedFile.size)
40
+ uf[:filename] = MemoryPointer.from_string(file.filename)
41
+ uf[:contents] = MemoryPointer.from_string(file.contents)
42
+ uf[:length] = file.contents.length
43
+ end
44
+
45
+ vec
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,58 @@
1
+ # Copyright, 2014 by Masahiro Sano.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require 'ffi/clang/lib/utils'
22
+ require 'ffi/clang/lib/string'
23
+
24
+ module FFI
25
+ module Clang
26
+ class Utils
27
+ def self.clang_version_string
28
+ Lib.extract_string Lib.get_clang_version
29
+ end
30
+
31
+ def self.clang_version
32
+ version = clang_version_string
33
+ version.match(/based on LLVM (\d+\.\d+)/).values_at(1).first
34
+ end
35
+
36
+ def self.clang_version_symbol
37
+ version = "clang_" + clang_version.tr('.', '_')
38
+ version.intern
39
+ end
40
+
41
+ def self.clang_major_version
42
+ version = clang_version_string
43
+ version.match(/based on LLVM (\d+)\./).values_at(1).first.to_i
44
+ end
45
+
46
+ def self.clang_minor_version
47
+ version = clang_version_string
48
+ version.match(/based on LLVM \d+\.(\d+)/).values_at(1).first.to_i
49
+ end
50
+
51
+ def self.satisfy_version?(min_version, max_version = nil)
52
+ Gem::Version.create(self.clang_version) >= Gem::Version.create(min_version) and
53
+ (max_version.nil? or
54
+ Gem::Version.create(self.clang_version) <= Gem::Version.create(max_version))
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright, 2010-2012 by Jari Bakken.
2
+ # Copyright, 2013, by Samuel G. D. Williams. <http://www.codeotaku.com>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ module FFI
23
+ module Clang
24
+ VERSION = "0.2.0.1"
25
+ end
26
+ end
@@ -0,0 +1,470 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright, 2013, by Carlos Martín Nieto <cmn@dwim.me>
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+
22
+ require 'spec_helper'
23
+
24
+ describe Comment do
25
+ let(:cursor) { Index.new.parse_translation_unit(fixture_path("docs.cc")).cursor }
26
+ let (:comment) { find_first(cursor, :cursor_function).comment }
27
+
28
+ it "can be obtained from a cursor" do
29
+ comment.should be_kind_of(Comment)
30
+ comment.should be_kind_of(FullComment)
31
+ comment.kind.should equal(:comment_full)
32
+ end
33
+
34
+ it "can parse the brief description" do
35
+ para = comment.child
36
+ para.kind.should equal(:comment_paragraph)
37
+ para.should be_kind_of(ParagraphComment)
38
+ text = para.child
39
+ text.kind.should equal(:comment_text)
40
+ text.should be_kind_of(TextComment)
41
+ text.text.strip.should eq("Short explanation")
42
+ end
43
+
44
+ it "can parse the longer description" do
45
+ para = comment.child(1)
46
+ para.kind.should equal(:comment_paragraph)
47
+ para.num_children.should equal(2)
48
+ text = para.child
49
+
50
+ lines = (0..para.num_children-1).map do |i|
51
+ para.child(i).text
52
+ end
53
+
54
+ lines.should eq([" This is a longer explanation",
55
+ " that spans multiple lines"])
56
+ end
57
+
58
+ it "has working helpers" do
59
+ comment.num_children.should equal(8)
60
+
61
+ para = comment.child(1)
62
+ para.text.should eq(" This is a longer explanation\n that spans multiple lines")
63
+ end
64
+
65
+ it "understands params" do
66
+ [['input', " some input\n "], ['flags', " some flags\n "]].each_with_index do |v, child_idx|
67
+ param = comment.child(3 + child_idx)
68
+ param.should be_kind_of(ParamCommandComment)
69
+
70
+ param.valid_index?.should == true
71
+ param.index.should equal(child_idx)
72
+ param.name.should eq(v[0])
73
+ param.child.text.should eq v[1]
74
+ param.comment.should eq v[1]
75
+ end
76
+ end
77
+
78
+ describe "#whitespace?" do
79
+ it "checks the comment is whitespace" do
80
+ expect(comment.child.whitespace?).to be_false
81
+ end
82
+ end
83
+
84
+ describe "#has_trailing_newline?" do
85
+ it "checks the content has a traling newline" do
86
+ expect(comment.child.has_trailing_newline?).to be_false
87
+ end
88
+ end
89
+
90
+ context 'comment_null' do
91
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
92
+ child.kind == :cursor_function and child.spelling == 'no_comment_function' } }
93
+ let(:comment) { comment_cursor.comment }
94
+
95
+ it "is null comment" do
96
+ expect(comment).to be_kind_of(Comment)
97
+ expect(comment.kind).to eq(:comment_null)
98
+ expect(comment.text).to eq('')
99
+ end
100
+ end
101
+
102
+ context 'unknown comment type' do
103
+ let(:comment) { 'foobar' }
104
+ it "raises NotImplementedError" do
105
+ expect(Lib).to receive(:comment_get_kind).with(comment).and_return(:xxx_yyy_zzzz)
106
+ expect{Comment.build_from(comment)}.to raise_error(NotImplementedError)
107
+ end
108
+ end
109
+
110
+ describe HTMLStartTagComment do
111
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
112
+ child.kind == :cursor_function and child.spelling == 'b_function' } }
113
+ let(:comment) { comment_cursor.comment }
114
+ let(:paragraph) { comment_cursor.comment.child }
115
+ let(:html_start_tag_comments) { paragraph.children.select{|c| c.kind == :comment_html_start_tag} }
116
+
117
+ it "can be obtained from cursor" do
118
+ expect(comment).to be_kind_of(FullComment)
119
+ expect(comment.kind).to equal(:comment_full)
120
+ expect(paragraph).to be_kind_of(ParagraphComment)
121
+ expect(html_start_tag_comments.first).to be_kind_of(HTMLStartTagComment)
122
+ expect(html_start_tag_comments.size).to eq(2)
123
+ end
124
+
125
+ describe "#tag" do
126
+ it "returns HTML tag name" do
127
+ expect(html_start_tag_comments[0].tag).to eq('br')
128
+ expect(html_start_tag_comments[1].tag).to eq('a')
129
+ end
130
+
131
+ it "is alias method of #name" do
132
+ expect(html_start_tag_comments[0].name).to eq('br')
133
+ expect(html_start_tag_comments[1].name).to eq('a')
134
+ end
135
+ end
136
+
137
+ describe "#text" do
138
+ it "returns HTML tag as string", from_3_4: true do
139
+ expect(html_start_tag_comments[0].text.strip).to eq('<br/>')
140
+ expect(html_start_tag_comments[1].text.strip).to eq('<a href="http://example.org/">')
141
+ end
142
+
143
+ it "returuns empty string", upto_3_3: true do
144
+ expect(html_start_tag_comments[0].text.strip).to eq('')
145
+ expect(html_start_tag_comments[1].text.strip).to eq('')
146
+ end
147
+ end
148
+
149
+ describe "#self_closing?" do
150
+ it "checks the tag is self-closing" do
151
+ expect(html_start_tag_comments[0].self_closing?).to be_true
152
+ expect(html_start_tag_comments[1].self_closing?).to be_false
153
+ end
154
+ end
155
+
156
+ describe "#num_attrs" do
157
+ it "returns the number of attributes" do
158
+ expect(html_start_tag_comments[0].num_attrs).to eq(0)
159
+ expect(html_start_tag_comments[1].num_attrs).to eq(1)
160
+ end
161
+ end
162
+
163
+ describe "#attrs" do
164
+ it "returns attributes as Array of Hash" do
165
+ expect(html_start_tag_comments[0].attrs).to eq([])
166
+ expect(html_start_tag_comments[1].attrs).to eq([{name: 'href', value: 'http://example.org/'}])
167
+ end
168
+ end
169
+ end
170
+
171
+ describe HTMLEndTagComment do
172
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
173
+ child.kind == :cursor_function and child.spelling == 'b_function' } }
174
+ let(:comment) { comment_cursor.comment }
175
+ let(:paragraph) { comment_cursor.comment.child }
176
+ let(:html_end_tag_comment) { paragraph.children.select{|c| c.kind == :comment_html_end_tag}.first }
177
+
178
+ it "can be obtained from cursor" do
179
+ expect(comment).to be_kind_of(FullComment)
180
+ expect(comment.kind).to equal(:comment_full)
181
+ expect(paragraph).to be_kind_of(ParagraphComment)
182
+ expect(html_end_tag_comment).to be_kind_of(HTMLEndTagComment)
183
+ end
184
+
185
+ describe "#tag" do
186
+ it "returns HTML tag name" do
187
+ expect(html_end_tag_comment.tag).to eq('a')
188
+ end
189
+
190
+ it "is alias method of #name" do
191
+ expect(html_end_tag_comment.name).to eq('a')
192
+ end
193
+ end
194
+
195
+ describe "#text" do
196
+ it "returns HTML tag as string", from_3_4: true do
197
+ expect(html_end_tag_comment.text.strip).to eq('</a>')
198
+ end
199
+
200
+ it "returuns empty string", upto_3_3: true do
201
+ expect(html_end_tag_comment.text.strip).to eq('')
202
+ end
203
+ end
204
+ end
205
+
206
+ describe FullComment do
207
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
208
+ child.kind == :cursor_function and child.spelling == 'f_function' } }
209
+ let(:comment) { comment_cursor.comment }
210
+
211
+ it "can be obtained from cursor" do
212
+ expect(comment).to be_kind_of(FullComment)
213
+ expect(comment.kind).to equal(:comment_full)
214
+ end
215
+
216
+ describe "#to_html" do
217
+ it "converts a given full parsed comment to an HTML fragment", from_3_4: true do
218
+ expect(comment.to_html).to be_kind_of(String)
219
+ expect(comment.to_html).to eq('<p class="para-brief"> this is a function.</p>')
220
+ end
221
+
222
+ it "converts a given full parsed comment to an HTML fragment", upto_3_3: true do
223
+ expect(comment.to_html).to be_kind_of(String)
224
+ expect(comment.to_html).to eq('<p class="para-brief"> this is a function. </p>')
225
+ end
226
+ end
227
+
228
+ describe "#to_xml" do
229
+ it "converts a given full parsed comment to an XML document" do
230
+ expect(comment.to_xml).to be_kind_of(String)
231
+ end
232
+ end
233
+ end
234
+
235
+ describe BlockCommandComment do
236
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
237
+ child.kind == :cursor_function and child.spelling == 'f_function' } }
238
+ let(:comment) { comment_cursor.comment }
239
+ let(:block_cmd_comment) { comment.children.select{|c| c.kind == :comment_block_command}.first }
240
+
241
+ it "can be obtained from cursor" do
242
+ expect(comment).to be_kind_of(FullComment)
243
+ expect(comment.kind).to equal(:comment_full)
244
+ expect(block_cmd_comment).to be_kind_of(BlockCommandComment)
245
+ expect(block_cmd_comment.child).to be_kind_of(ParagraphComment)
246
+ end
247
+
248
+ describe "#name" do
249
+ it "returns the name of the block command" do
250
+ expect(block_cmd_comment.name).to eq("brief")
251
+ end
252
+ end
253
+
254
+ describe "#paragraph" do
255
+ it "returns the paragraph" do
256
+ expect(block_cmd_comment.paragraph).to be_kind_of(ParagraphComment)
257
+ end
258
+ end
259
+
260
+ describe "#num_args" do
261
+ it "returns the number of word-like arguments" do
262
+ expect(block_cmd_comment.num_args).to eq(0)
263
+ end
264
+ end
265
+
266
+ describe "#args" do
267
+ it "returns word-like arguments" do
268
+ expect(block_cmd_comment.args).to be_kind_of(Array)
269
+ expect(block_cmd_comment.args).to eq([])
270
+ end
271
+
272
+ #TODO: needs tests with comments which have arguments
273
+ end
274
+
275
+ describe "#text" do
276
+ it "returns readble text that includes children's comments" do
277
+ expect(block_cmd_comment.text).to be_kind_of(String)
278
+ expect(block_cmd_comment.text.strip).to eq('this is a function.')
279
+ end
280
+
281
+ it "is a alias method of #comment" do
282
+ expect(block_cmd_comment.comment).to eq(block_cmd_comment.text)
283
+ end
284
+ end
285
+ end
286
+
287
+ describe InlineCommandComment do
288
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
289
+ child.kind == :cursor_function and child.spelling == 'd_function' } }
290
+ let(:comment) { comment_cursor.comment }
291
+ let(:inline_command_comments) { comment.child.children.select{|c| c.kind == :comment_inline_command} }
292
+
293
+ it "can be obtained from cursor" do
294
+ expect(comment).to be_kind_of(FullComment)
295
+ expect(comment.kind).to equal(:comment_full)
296
+ expect(comment.child).to be_kind_of(ParagraphComment)
297
+ expect(inline_command_comments.size).to eq(2)
298
+ end
299
+
300
+ describe "#name" do
301
+ it "returns the name of the inline command" do
302
+ expect(inline_command_comments[0].name).to eq("em")
303
+ expect(inline_command_comments[1].name).to eq("b")
304
+ end
305
+ end
306
+
307
+ describe "#render_kind" do
308
+ it "returns the most appropriate rendering mode" do
309
+ expect(inline_command_comments[0].render_kind).to eq(:emphasized)
310
+ expect(inline_command_comments[1].render_kind).to eq(:bold)
311
+ end
312
+ end
313
+
314
+ describe "#num_args" do
315
+ it "returns number of command arguments" do
316
+ expect(inline_command_comments[0].num_args).to eq(1)
317
+ expect(inline_command_comments[1].num_args).to eq(1)
318
+ end
319
+ end
320
+
321
+ describe "#args" do
322
+ it "returns arguments as Array" do
323
+ expect(inline_command_comments[0].args).to eq(["foo"])
324
+ expect(inline_command_comments[1].args).to eq(["bar"])
325
+ end
326
+ end
327
+
328
+ describe "#text" do
329
+ it "returns readble text" do
330
+ expect(inline_command_comments[0].text.strip).to eq("foo")
331
+ expect(inline_command_comments[1].text.strip).to eq("bar")
332
+ end
333
+ end
334
+ end
335
+
336
+ describe VerbatimBlockCommandComment do
337
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
338
+ child.kind == :cursor_function and child.spelling == 'e_function' } }
339
+ let(:comment) { comment_cursor.comment }
340
+ let(:verb_block_cmd_comment) { comment.children.select{|c| c.kind == :comment_verbatim_block_command}.first }
341
+
342
+ it "can be obtained from cursor" do
343
+ expect(comment).to be_kind_of(FullComment)
344
+ expect(comment.kind).to equal(:comment_full)
345
+ expect(verb_block_cmd_comment).to be_kind_of(VerbatimBlockCommandComment)
346
+ end
347
+
348
+ describe "#text" do
349
+ it "returns readble text" do
350
+ expect(verb_block_cmd_comment.text).to eq(" foo bar\n baz")
351
+ end
352
+ end
353
+ end
354
+
355
+ describe VerbatimBlockLineComment do
356
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
357
+ child.kind == :cursor_function and child.spelling == 'e_function' } }
358
+ let(:comment) { comment_cursor.comment }
359
+ let(:verb_block_cmd_comment) { comment.children.select{|c| c.kind == :comment_verbatim_block_command}.first }
360
+ let(:verb_block_line_comments) { verb_block_cmd_comment.children }
361
+
362
+ it "can be obtained from cursor" do
363
+ expect(comment).to be_kind_of(FullComment)
364
+ expect(comment.kind).to equal(:comment_full)
365
+ expect(verb_block_cmd_comment).to be_kind_of(VerbatimBlockCommandComment)
366
+ expect(verb_block_line_comments.first).to be_kind_of(VerbatimBlockLineComment)
367
+ expect(verb_block_line_comments.size).to eq(2)
368
+ end
369
+
370
+ describe "#text" do
371
+ it "returns readble text" do
372
+ expect(verb_block_line_comments[0].text.strip).to eq("foo bar")
373
+ expect(verb_block_line_comments[1].text.strip).to eq("baz")
374
+ end
375
+ end
376
+ end
377
+
378
+ describe VerbatimLine do
379
+ # TODO: how to generate this comment?
380
+ end
381
+
382
+ describe ParamCommandComment do
383
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
384
+ child.kind == :cursor_function and child.spelling == 'a_function' } }
385
+ let(:comment) { comment_cursor.comment }
386
+ let(:param_cmd_comments) { comment.children.select{|c| c.kind == :comment_param_command} }
387
+
388
+ it "can be obtained from cursor" do
389
+ expect(comment).to be_kind_of(FullComment)
390
+ expect(comment.kind).to equal(:comment_full)
391
+ expect(param_cmd_comments.first).to be_kind_of(ParamCommandComment)
392
+ expect(param_cmd_comments.size).to eq(4)
393
+ end
394
+
395
+ describe "#text" do
396
+ it "returns readble text" do
397
+ expect(param_cmd_comments[0].text.strip).to eq("some input")
398
+ expect(param_cmd_comments[1].text.strip).to eq("some flags")
399
+ end
400
+ end
401
+
402
+ describe "#direction_explicit?" do
403
+ it "checks the direction is specified explicitly" do
404
+ expect(param_cmd_comments[0].direction_explicit?).to be_true
405
+ expect(param_cmd_comments[3].direction_explicit?).to be_false
406
+ end
407
+ end
408
+
409
+ describe "#direction" do
410
+ it "returns parameter passing direction" do
411
+ expect(param_cmd_comments[0].direction).to eq(:pass_direction_in)
412
+ expect(param_cmd_comments[1].direction).to eq(:pass_direction_out)
413
+ expect(param_cmd_comments[2].direction).to eq(:pass_direction_inout)
414
+ expect(param_cmd_comments[3].direction).to eq(:pass_direction_in)
415
+ end
416
+ end
417
+ end
418
+
419
+ describe TParamCommandComment do
420
+ let(:comment_cursor) { find_matching(cursor) { |child, parent|
421
+ child.kind == :cursor_function_template and child.spelling == 'c_function' } }
422
+ let(:comment) { comment_cursor.comment }
423
+ let(:tparam_cmd_comments) { comment.children.select{|c| c.kind == :comment_tparam_command} }
424
+
425
+ it "can be obtained from cursor" do
426
+ expect(comment).to be_kind_of(FullComment)
427
+ expect(comment.kind).to equal(:comment_full)
428
+ expect(tparam_cmd_comments.first).to be_kind_of(TParamCommandComment)
429
+ expect(tparam_cmd_comments.size).to eq(3)
430
+ end
431
+
432
+ describe "#text" do
433
+ it "returns readble text" do
434
+ expect(tparam_cmd_comments[0].text.strip).to eq("some type of foo")
435
+ expect(tparam_cmd_comments[1].text.strip).to eq("some type of bar")
436
+ end
437
+ end
438
+
439
+ describe "#name" do
440
+ it "returns template parameter name" do
441
+ expect(tparam_cmd_comments[0].name).to eq("T1")
442
+ expect(tparam_cmd_comments[1].name).to eq("T2")
443
+ expect(tparam_cmd_comments[2].name).to eq("T3")
444
+ end
445
+ end
446
+
447
+ describe "#valid_position?" do
448
+ it "checks this parameter has valid position" do
449
+ expect(tparam_cmd_comments[0].valid_position?).to be_true
450
+ end
451
+ end
452
+
453
+ describe "#depth" do
454
+ it "returns nesting depth of this parameter" do
455
+ expect(tparam_cmd_comments[0].depth).to eq(1)
456
+ expect(tparam_cmd_comments[1].depth).to eq(2)
457
+ expect(tparam_cmd_comments[2].depth).to eq(1)
458
+ end
459
+ end
460
+
461
+ describe "#index" do
462
+ it "returns index of the parameter at the given nesting depth" do
463
+ expect(tparam_cmd_comments[0].index(0)).to eq(0)
464
+ expect(tparam_cmd_comments[1].index(0)).to eq(1)
465
+ expect(tparam_cmd_comments[1].index(1)).to eq(0)
466
+ expect(tparam_cmd_comments[2].index(0)).to eq(1)
467
+ end
468
+ end
469
+ end
470
+ end