ruby_header_parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyHeaderParser
4
+ # function definition in header file
5
+ class FunctionDefinition
6
+ # @!attribute name
7
+ # @return [String]
8
+ attr_accessor :name
9
+
10
+ # @!attribute definition
11
+ # @return [String]
12
+ attr_accessor :definition
13
+
14
+ # @!attribute typeref
15
+ # @return [TyperefDefinition]
16
+ attr_accessor :typeref
17
+
18
+ # @!attribute args
19
+ # @return [Array<ArgumentDefinition>]
20
+ attr_accessor :args
21
+
22
+ # @param name [String]
23
+ # @param definition [String]
24
+ # @param typeref [TyperefDefinition]
25
+ # @param args [Array<ArgumentDefinition>]
26
+ def initialize(name:, definition:, typeref:, args:)
27
+ @name = name
28
+ @definition = definition
29
+ @typeref = typeref
30
+ @args = args
31
+ end
32
+
33
+ # @param other [FunctionDefinition]
34
+ # @return [Boolean]
35
+ def ==(other)
36
+ other.is_a?(FunctionDefinition) && name == other.name && definition == other.definition &&
37
+ typeref == other.typeref && args == other.args
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,376 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyHeaderParser
4
+ # parse `ruby.h` using `ctags`
5
+ class Parser # rubocop:disable Metrics/ClassLength
6
+ # @!attribute [r] header_file
7
+ # @return [String]
8
+ attr_reader :header_file
9
+
10
+ # @!attribute [r] include_paths
11
+ # @return [Array<String>]
12
+ attr_reader :include_paths
13
+
14
+ # @!attribute [r] dist_preprocessed_header_file
15
+ # @return [String]
16
+ attr_reader :dist_preprocessed_header_file
17
+
18
+ # @!attribute [r] data
19
+ # @return [RubyHeaderParser::Config]
20
+ attr_reader :config
21
+
22
+ DEFAULT_HEADER_FILE = "#{RbConfig::CONFIG["rubyhdrdir"]}/ruby.h".freeze
23
+
24
+ DEFAULT_INCLUDE_PATHS = [
25
+ RbConfig::CONFIG["rubyarchhdrdir"],
26
+ RbConfig::CONFIG["rubyhdrdir"],
27
+ ].freeze
28
+
29
+ # @param header_file [String] Path to `ruby.h`
30
+ # @param include_paths [Array<String>]
31
+ # @param dist_preprocessed_header_file [String,nil] Destination path to the output of preprocessed ruby.h.
32
+ # (default: `"#{Dir.tmpdir}/ruby_preprocessed.h"`)
33
+ # @param config_file [String,nil] Path to config file (default: `config/default.yml`)
34
+ #
35
+ # @note `dist_preprocessed_header_file` is used as the output destination for temporary files when the parser
36
+ # is executed
37
+ #
38
+ # @note See [CONFIG.md](../file.CONFIG.html) for config file details
39
+ def initialize(dist_preprocessed_header_file: nil, header_file: DEFAULT_HEADER_FILE,
40
+ include_paths: DEFAULT_INCLUDE_PATHS, config_file: nil)
41
+ @header_file = header_file
42
+ @include_paths = include_paths
43
+ @dist_preprocessed_header_file = dist_preprocessed_header_file || File.join(Dir.tmpdir, "ruby_preprocessed.h")
44
+
45
+ config_file ||= File.expand_path("../../config/default.yml", __dir__.to_s)
46
+ @config = Config.new(config_file)
47
+ end
48
+
49
+ # @return [Array<RubyHeaderParser::FunctionDefinition>]
50
+ def extract_function_definitions
51
+ __extract_function_definitions(c_kinds: "p", kind: "p", is_parse_multiline_definition: true)
52
+ end
53
+
54
+ # @return [Array<RubyHeaderParser::FunctionDefinition>]
55
+ def extract_static_inline_function_definitions
56
+ __extract_function_definitions(c_kinds: "+p-d", kind: "f", is_parse_multiline_definition: false)
57
+ end
58
+
59
+ # @return [Array<RubyHeaderParser::StructDefinition>]
60
+ def extract_struct_definitions
61
+ stdout = execute_ctags("--c-kinds=s --fields=+n")
62
+
63
+ stdout.each_line.with_object([]) do |line, definitions|
64
+ parts = line.split("\t")
65
+
66
+ struct_name = parts[0]
67
+ next unless config.should_generate_struct?(struct_name)
68
+
69
+ definitions << StructDefinition.new(
70
+ name: struct_name,
71
+ )
72
+ end
73
+ end
74
+
75
+ # @return [Array<RubyHeaderParser::TyperefDefinition>]
76
+ def extract_type_definitions
77
+ stdout = execute_ctags("--c-kinds=t --fields=+n")
78
+
79
+ stdout.each_line.with_object([]) do |line, definitions|
80
+ parts = line.split("\t")
81
+
82
+ type_name = parts[0]
83
+
84
+ next unless config.should_generate_type?(type_name)
85
+
86
+ definitions << TypeDefinition.new(
87
+ name: type_name,
88
+ )
89
+ end.uniq(&:name)
90
+ end
91
+
92
+ # @return [Array<RubyHeaderParser::EnumDefinition>]
93
+ def extract_enum_definitions
94
+ stdout = execute_ctags("--c-kinds=e --fields=+n")
95
+
96
+ name_to_definitions =
97
+ stdout.each_line.with_object({}) do |line, hash|
98
+ parts = line.split("\t")
99
+
100
+ enum_name = Util.find_field(parts, "enum")
101
+ next unless enum_name
102
+
103
+ value = parts[0]
104
+
105
+ next unless config.should_generate_enum?(enum_name)
106
+
107
+ hash[enum_name] ||= EnumDefinition.new(name: enum_name)
108
+ hash[enum_name].values << value
109
+ end
110
+
111
+ name_to_definitions.values
112
+ end
113
+
114
+ private
115
+
116
+ # @param c_kinds [String]
117
+ # @param kind [String]
118
+ # @param is_parse_multiline_definition [Boolean]
119
+ # @return [Array<RubyHeaderParser::FunctionDefinition>]
120
+ def __extract_function_definitions(c_kinds:, kind:, is_parse_multiline_definition:)
121
+ stdout = execute_ctags("--c-kinds=#{c_kinds} --fields=+nS --extras=+q")
122
+
123
+ stdout.each_line.map do |line|
124
+ generate_function_definition_from_line(line:, kind:, is_parse_multiline_definition:)
125
+ end.compact.uniq(&:name)
126
+ end
127
+
128
+ # @param line [String]
129
+ # @param kind [String]
130
+ # @param is_parse_multiline_definition [Boolean]
131
+ #
132
+ # @return [RubyHeaderParser::FunctionDefinition, nil]
133
+ def generate_function_definition_from_line(line:, kind:, is_parse_multiline_definition:)
134
+ parts = line.split("\t")
135
+
136
+ function_name = parts[0]
137
+ filepath = parts[1]
138
+
139
+ return nil unless config.should_generate_function?(function_name)
140
+
141
+ return nil unless parts[3] == kind
142
+
143
+ line_num = Util.find_field(parts, "line").to_i
144
+ definition = parse_function_definition(filepath:, pattern: parts[2], line_num:, is_parse_multiline_definition:)
145
+
146
+ args = parse_definition_args(function_name, Util.find_field(parts, "signature"))
147
+
148
+ # Exclude functions with variable-length arguments
149
+ return nil if args&.last&.type == "..."
150
+
151
+ typeref_field = Util.find_field(parts, "typeref:typename")
152
+
153
+ FunctionDefinition.new(
154
+ definition:,
155
+ name: function_name,
156
+ typeref: create_typeref(definition:, function_name:, typeref_field:, filepath:, line_num:),
157
+ args:,
158
+ )
159
+ end
160
+
161
+ # @param args [String]
162
+ # @return [String]
163
+ def execute_ctags(args = "")
164
+ unless File.exist?(dist_preprocessed_header_file)
165
+ include_args = include_paths.map { |path| "-I #{path}" }.join(" ")
166
+ system("gcc -E #{include_args} #{header_file} -o #{dist_preprocessed_header_file}", exception: true)
167
+ end
168
+
169
+ `ctags --languages=C --language-force=C #{args} -f - #{dist_preprocessed_header_file}`
170
+ end
171
+
172
+ # @param file [String]
173
+ # @param line_num [Integer]
174
+ def read_definition_from_header_file(file, line_num)
175
+ definition = +""
176
+
177
+ File.open(file, "r") do |f|
178
+ f.each_with_index do |line, index|
179
+ if index + 1 >= line_num
180
+ definition << line.strip
181
+ return definition if definition.end_with?(");")
182
+ end
183
+ end
184
+ end
185
+ ""
186
+ end
187
+
188
+ # @param filepath [String]
189
+ # @param pattern [String]
190
+ # @param line_num [Integer]
191
+ # @param is_parse_multiline_definition [Boolean]
192
+ # @return [String]
193
+ def parse_function_definition(filepath:, pattern:, line_num:, is_parse_multiline_definition:)
194
+ definition =
195
+ if pattern.end_with?("$/;\"")
196
+ pattern.delete_prefix("/^").delete_suffix("$/;\"")
197
+ elsif is_parse_multiline_definition
198
+ read_definition_from_header_file(filepath, line_num)
199
+ else
200
+ pattern.delete_prefix("/^")
201
+ end
202
+
203
+ definition.strip.delete_suffix(";")
204
+ end
205
+
206
+ # @param function_name [String]
207
+ # @param signature [String,nil]
208
+ # @return [Array<RubyHeaderParser::ArgumentDefinition>]
209
+ def parse_definition_args(function_name, signature)
210
+ return [] unless signature
211
+
212
+ signature = signature.strip.delete_prefix("(").delete_suffix(")")
213
+ return [] if signature.match?(/^void$/i)
214
+
215
+ args = Util.split_signature(signature)
216
+
217
+ arg_pos = 0
218
+ args.map do |arg|
219
+ arg_pos += 1
220
+ generate_argument_definition(function_name:, arg:, arg_pos:)
221
+ end
222
+ end
223
+
224
+ # @param definition [String]
225
+ # @param function_name [String]
226
+ # @param typeref_field [String,nil]
227
+ # @param filepath [String]
228
+ # @param line_num [Integer]
229
+ # @return [RubyHeaderParser::TyperefDefinition]
230
+ def create_typeref(definition:, function_name:, typeref_field:, filepath:, line_num:)
231
+ typeref_type = parse_typeref_type(definition:, function_name:, typeref_field:, filepath:, line_num:)
232
+
233
+ typeref_pointer = nil
234
+ if typeref_type.match?(/\*+$/)
235
+ typeref_type = typeref_type.gsub(/\*+$/, "").strip
236
+ typeref_pointer = config.function_self_pointer_hint(function_name)
237
+ end
238
+
239
+ TyperefDefinition.new(type: typeref_type, pointer: typeref_pointer)
240
+ end
241
+
242
+ # @param definition [String]
243
+ # @param function_name [String]
244
+ # @param typeref_field [String,nil]
245
+ # @param filepath [String]
246
+ # @param line_num [Integer]
247
+ # @return [String]
248
+ def parse_typeref_type(definition:, function_name:, typeref_field:, filepath:, line_num:)
249
+ typeref_type =
250
+ if typeref_field
251
+ typeref_field.gsub(/[A-Z_]+\s*\(\(.*\)\)/, "")
252
+ else
253
+ # parse typeref in definition
254
+ type = definition[0...definition.index(function_name)] || ""
255
+ type.gsub("char *", "char*").strip
256
+ end
257
+
258
+ typeref_type = Util.sanitize_type(typeref_type)
259
+ return typeref_type unless typeref_type.empty?
260
+
261
+ # Check prev line
262
+ line = read_file_line(filepath:, line_num: line_num - 1)
263
+ return Util.sanitize_type(line) if line
264
+
265
+ ""
266
+ end
267
+
268
+ # @param filepath [String]
269
+ # @param line_num [Integer]
270
+ def read_file_line(filepath:, line_num:)
271
+ return nil if line_num < 1
272
+
273
+ lines = File.open(filepath, "rb") { |f| f.readlines(chomp: true) }
274
+ lines[line_num - 1]
275
+ end
276
+
277
+ # @param function_name [String]
278
+ # @param arg [String]
279
+ # @param arg_pos [Integer]
280
+ #
281
+ # @return [ArgumentDefinition]
282
+ def generate_argument_definition(function_name:, arg:, arg_pos:)
283
+ parts = arg.split
284
+
285
+ if parts.count < 2
286
+ return ArgumentDefinition.new(
287
+ type: parts[0],
288
+ name: "arg#{arg_pos}",
289
+ pointer: nil,
290
+ )
291
+ end
292
+
293
+ loop do
294
+ pointer_index = parts.index("*")
295
+ break unless pointer_index
296
+
297
+ parts[pointer_index - 1] << "*"
298
+ parts.delete_at(pointer_index)
299
+ end
300
+
301
+ type, pointer, length = analyze_argument_type(function_name:, arg_pos:, parts:)
302
+
303
+ ArgumentDefinition.new(
304
+ name: parts[-1],
305
+ type:,
306
+ pointer:,
307
+ length:,
308
+ )
309
+ end
310
+
311
+ # @param function_name [String]
312
+ # @param arg_pos [Integer]
313
+ # @param parts [Array<String>]
314
+ #
315
+ # @return [Array<String, Symbol, Integer>]
316
+ # - type [String]
317
+ # - pointer [Symbol]
318
+ # - length [Integer]
319
+ def analyze_argument_type(function_name:, arg_pos:, parts:)
320
+ pointer, length = prepare_argument_parts(arg_pos:, parts:)
321
+ type = parts[0...-1] || []
322
+ original_type = Util.sanitize_type(type.join(" "))
323
+
324
+ case original_type
325
+ when /\*+$/
326
+ type = original_type.gsub(/\*+$/, "").strip
327
+ pointer = config.function_arg_pointer_hint(function_name:, pos: arg_pos)
328
+
329
+ when /^void\s*/, /\(.*\)/
330
+ # function pointer (e.g. void *(*func)(void *)) is treated as `void*`
331
+ type = "void"
332
+ pointer = config.function_arg_pointer_hint(function_name:, pos: arg_pos)
333
+
334
+ else
335
+ type = original_type
336
+ end
337
+
338
+ length = pointer_length(original_type) if pointer == :sref
339
+
340
+ [type, pointer, length]
341
+ end
342
+
343
+ # @param arg_pos [Integer]
344
+ # @param parts [Array<String>]
345
+ #
346
+ # @return [Array<Symbol, Integer>]
347
+ # - pointer [Symbol,nil]
348
+ # - length [Integer]
349
+ def prepare_argument_parts(parts:, arg_pos:)
350
+ if parts[-1] =~ /\[([0-9]+)?\]$/
351
+ parts[-1].gsub!(/\[([0-9]+)?\]$/, "")
352
+ length = ::Regexp.last_match(1).to_i
353
+
354
+ unless parts[-1] =~ /^[0-9a-zA-Z_]+$/
355
+ # last elements isn't dummy argument
356
+ parts << "arg#{arg_pos}"
357
+ end
358
+
359
+ return [:array, length]
360
+ end
361
+
362
+ unless parts[-1] =~ /^[0-9a-zA-Z_]+$/
363
+ # last elements isn't dummy argument
364
+ parts << "arg#{arg_pos}"
365
+ end
366
+
367
+ [nil, 0]
368
+ end
369
+
370
+ # @param type [String]
371
+ def pointer_length(type)
372
+ type =~ /(\*+)$/
373
+ ::Regexp.last_match(1)&.length || 0
374
+ end
375
+ end
376
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyHeaderParser
4
+ # struct definition in header file
5
+ class StructDefinition
6
+ # @!attribute name
7
+ # @return [String]
8
+ attr_accessor :name
9
+
10
+ # @param name [String]
11
+ def initialize(name:)
12
+ @name = name
13
+ end
14
+
15
+ # @param other [StructDefinition]
16
+ # @return [Boolean]
17
+ def ==(other)
18
+ other.is_a?(StructDefinition) && name == other.name
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyHeaderParser
4
+ # type definition in header file
5
+ class TypeDefinition
6
+ # @!attribute name
7
+ # @return [String]
8
+ attr_accessor :name
9
+
10
+ # @param name [String]
11
+ def initialize(name:)
12
+ @name = name
13
+ end
14
+
15
+ # @param other [TypeDefinition]
16
+ # @return [Boolean]
17
+ def ==(other)
18
+ other.is_a?(TypeDefinition) && name == other.name
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyHeaderParser
4
+ # typeref definition for {RubyHeaderParser::FunctionDefinition}
5
+ class TyperefDefinition
6
+ # @!attribute type
7
+ # @return [String]
8
+ attr_accessor :type
9
+
10
+ # @!attribute pointer
11
+ # @return [Symbol,nil] :ref, :raw
12
+ attr_accessor :pointer
13
+
14
+ # @param type [String]
15
+ # @param pointer [Symbol,nil] :ref, :raw
16
+ def initialize(type:, pointer: nil)
17
+ @type = type
18
+ @pointer = pointer
19
+ end
20
+
21
+ # @return [Boolean]
22
+ def pointer?
23
+ !!pointer
24
+ end
25
+
26
+ # @param other [TyperefDefinition]
27
+ # @return [Boolean]
28
+ def ==(other)
29
+ other.is_a?(TyperefDefinition) && type == other.type && pointer == other.pointer
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyHeaderParser
4
+ # util methods
5
+ module Util
6
+ # @param array [Array<String>]
7
+ # @param field_name [String]
8
+ # @return [String,nil]
9
+ def self.find_field(array, field_name)
10
+ array.each do |element|
11
+ return element.delete_prefix("#{field_name}:").strip if element.start_with?("#{field_name}:")
12
+ end
13
+
14
+ nil
15
+ end
16
+
17
+ # @param signature [String]
18
+ # @return [Array<String>]
19
+ def self.split_signature(signature)
20
+ signature.scan(/[^,]+\([^()]*\)|[^,]+/).flatten.map(&:strip)
21
+ end
22
+
23
+ # @param type [String]
24
+ # @return [String]
25
+ def self.sanitize_type(type)
26
+ type.gsub(/(enum|volatile|const|struct|static\s+inline)\s+/i, "").gsub("const*", "").strip
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyHeaderParser
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+ require "tmpdir"
5
+
6
+ require_relative "ruby_header_parser/version"
7
+
8
+ # Parser for ruby.h
9
+ module RubyHeaderParser
10
+ class Error < StandardError; end
11
+
12
+ autoload :ArgumentDefinition, "ruby_header_parser/argument_definition"
13
+ autoload :Config, "ruby_header_parser/config"
14
+ autoload :EnumDefinition, "ruby_header_parser/enum_definition"
15
+ autoload :FunctionDefinition, "ruby_header_parser/function_definition"
16
+ autoload :Parser, "ruby_header_parser/parser"
17
+ autoload :StructDefinition, "ruby_header_parser/struct_definition"
18
+ autoload :TypeDefinition, "ruby_header_parser/type_definition"
19
+ autoload :TyperefDefinition, "ruby_header_parser/typeref_definition"
20
+ autoload :Util, "ruby_header_parser/util"
21
+ end
@@ -0,0 +1,116 @@
1
+ ---
2
+ path: ".gem_rbs_collection"
3
+ gems:
4
+ - name: ast
5
+ version: '2.4'
6
+ source:
7
+ type: git
8
+ name: ruby/gem_rbs_collection
9
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
10
+ remote: https://github.com/ruby/gem_rbs_collection.git
11
+ repo_dir: gems
12
+ - name: binding_of_caller
13
+ version: '1.0'
14
+ source:
15
+ type: git
16
+ name: ruby/gem_rbs_collection
17
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
18
+ remote: https://github.com/ruby/gem_rbs_collection.git
19
+ repo_dir: gems
20
+ - name: dbm
21
+ version: '0'
22
+ source:
23
+ type: stdlib
24
+ - name: diff-lcs
25
+ version: '1.5'
26
+ source:
27
+ type: git
28
+ name: ruby/gem_rbs_collection
29
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
30
+ remote: https://github.com/ruby/gem_rbs_collection.git
31
+ repo_dir: gems
32
+ - name: fileutils
33
+ version: '0'
34
+ source:
35
+ type: stdlib
36
+ - name: json
37
+ version: '0'
38
+ source:
39
+ type: stdlib
40
+ - name: parallel
41
+ version: '1.20'
42
+ source:
43
+ type: git
44
+ name: ruby/gem_rbs_collection
45
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
46
+ remote: https://github.com/ruby/gem_rbs_collection.git
47
+ repo_dir: gems
48
+ - name: parser
49
+ version: '3.2'
50
+ source:
51
+ type: git
52
+ name: ruby/gem_rbs_collection
53
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
54
+ remote: https://github.com/ruby/gem_rbs_collection.git
55
+ repo_dir: gems
56
+ - name: pstore
57
+ version: '0'
58
+ source:
59
+ type: stdlib
60
+ - name: psych
61
+ version: '0'
62
+ source:
63
+ type: stdlib
64
+ - name: rainbow
65
+ version: '3.0'
66
+ source:
67
+ type: git
68
+ name: ruby/gem_rbs_collection
69
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
70
+ remote: https://github.com/ruby/gem_rbs_collection.git
71
+ repo_dir: gems
72
+ - name: rake
73
+ version: '13.0'
74
+ source:
75
+ type: git
76
+ name: ruby/gem_rbs_collection
77
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
78
+ remote: https://github.com/ruby/gem_rbs_collection.git
79
+ repo_dir: gems
80
+ - name: regexp_parser
81
+ version: '2.8'
82
+ source:
83
+ type: git
84
+ name: ruby/gem_rbs_collection
85
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
86
+ remote: https://github.com/ruby/gem_rbs_collection.git
87
+ repo_dir: gems
88
+ - name: rspec-parameterized-core
89
+ version: 1.0.1
90
+ source:
91
+ type: rubygems
92
+ - name: rspec-parameterized-table_syntax
93
+ version: 1.0.1
94
+ source:
95
+ type: rubygems
96
+ - name: rubocop
97
+ version: '1.57'
98
+ source:
99
+ type: git
100
+ name: ruby/gem_rbs_collection
101
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
102
+ remote: https://github.com/ruby/gem_rbs_collection.git
103
+ repo_dir: gems
104
+ - name: rubocop-ast
105
+ version: '1.30'
106
+ source:
107
+ type: git
108
+ name: ruby/gem_rbs_collection
109
+ revision: 704f7e6b395fca717cc25c562598ca86015ed545
110
+ remote: https://github.com/ruby/gem_rbs_collection.git
111
+ repo_dir: gems
112
+ - name: yaml
113
+ version: '0'
114
+ source:
115
+ type: stdlib
116
+ gemfile_lock_path: Gemfile.lock
@@ -0,0 +1,26 @@
1
+ # Download sources
2
+ sources:
3
+ - type: git
4
+ name: ruby/gem_rbs_collection
5
+ remote: https://github.com/ruby/gem_rbs_collection.git
6
+ revision: main
7
+ repo_dir: gems
8
+
9
+ # You can specify local directories as sources also.
10
+ # - type: local
11
+ # path: path/to/your/local/repository
12
+
13
+ # A directory to install the downloaded RBSs
14
+ path: .gem_rbs_collection
15
+
16
+ gems:
17
+ - name: rbs
18
+ ignore: true
19
+ - name: steep
20
+ ignore: true
21
+ - name: yard
22
+ ignore: true
23
+ - name: ruby_header_parser
24
+ ignore: true
25
+
26
+ - name: yaml