ripper-tags 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ripper-tags.rb +65 -14
- data/lib/ripper-tags/data_reader.rb +21 -8
- data/lib/ripper-tags/default_formatter.rb +16 -6
- data/lib/ripper-tags/parser.rb +108 -5
- data/lib/ripper-tags/vim_formatter.rb +18 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 52c268f393b07f8fa528f4886a5c5c3d39fa712f
|
4
|
+
data.tar.gz: 7ea8519875252ee44f554ad3021d02a29e482970
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed66eb27100243fe6766f609f2ac3aa6f9f556a01f7c3f995fb663e973ef36fc7ab35e46eadf64e448ee75d133c96aa6177fa8a508548ab27fdce7268ade9ca0
|
7
|
+
data.tar.gz: 504ecdbdbb6315116d0d12d70827597c1f565fe08034d0201498ac5d878888c9e96bb7e7c750db79fd3f95798508493f1bdf9f0c00da9c07129eb3c84863aba7
|
data/lib/ripper-tags.rb
CHANGED
@@ -9,7 +9,7 @@ require 'ripper-tags/vim_formatter'
|
|
9
9
|
require 'ripper-tags/json_formatter'
|
10
10
|
|
11
11
|
module RipperTags
|
12
|
-
def self.version() "0.
|
12
|
+
def self.version() "0.4.0" end
|
13
13
|
|
14
14
|
FatalError = Class.new(RuntimeError)
|
15
15
|
|
@@ -26,11 +26,51 @@ module RipperTags
|
|
26
26
|
:files => %w[.],
|
27
27
|
:recursive => false,
|
28
28
|
:exclude => %w[.git],
|
29
|
-
:all_files => false
|
29
|
+
:all_files => false,
|
30
|
+
:fields => Set.new,
|
31
|
+
:excmd => nil,
|
32
|
+
:input_file => nil
|
33
|
+
end
|
34
|
+
|
35
|
+
class ForgivingOptionParser < OptionParser
|
36
|
+
attr_accessor :ignore_unsupported_options
|
37
|
+
|
38
|
+
def parse(argv)
|
39
|
+
argv = argv.dup
|
40
|
+
exceptions = []
|
41
|
+
remaining = []
|
42
|
+
|
43
|
+
while argv.size > 0
|
44
|
+
begin
|
45
|
+
remaining = super(argv)
|
46
|
+
break
|
47
|
+
rescue OptionParser::InvalidOption => err
|
48
|
+
argv -= err.args
|
49
|
+
exceptions << err
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if exceptions.any? && !ignore_unsupported_options
|
54
|
+
raise exceptions.first
|
55
|
+
end
|
56
|
+
|
57
|
+
remaining
|
58
|
+
end
|
30
59
|
end
|
31
60
|
|
32
61
|
def self.option_parser(options)
|
33
|
-
|
62
|
+
flags_string_to_set = lambda do |string, set|
|
63
|
+
flags = string.split("")
|
64
|
+
operation = :add
|
65
|
+
if flags[0] == "+" || flags[0] == "-"
|
66
|
+
operation = :delete if flags.shift == "-"
|
67
|
+
else
|
68
|
+
set.clear
|
69
|
+
end
|
70
|
+
flags.each { |f| set.send(operation, f) }
|
71
|
+
end
|
72
|
+
|
73
|
+
ForgivingOptionParser.new do |opts|
|
34
74
|
opts.banner = "Usage: #{opts.program_name} [options] FILES..."
|
35
75
|
opts.version = version
|
36
76
|
|
@@ -43,6 +83,9 @@ module RipperTags
|
|
43
83
|
opts.on("--tag-relative[=OPTIONAL]", "Make file paths relative to the directory of the tag file") do |value|
|
44
84
|
options.tag_relative = value != "no"
|
45
85
|
end
|
86
|
+
opts.on("-L", "--input-file=FILE", "File to read paths to process trom (use `-` for stdin)") do |file|
|
87
|
+
options.input_file = file
|
88
|
+
end
|
46
89
|
opts.on("-R", "--recursive", "Descend recursively into subdirectories") do
|
47
90
|
options.recursive = true
|
48
91
|
end
|
@@ -53,7 +96,16 @@ module RipperTags
|
|
53
96
|
options.exclude << pattern
|
54
97
|
end
|
55
98
|
end
|
56
|
-
opts.on("--
|
99
|
+
opts.on("--excmd=number", "Use EX number command to locate tags.") do |excmd|
|
100
|
+
options.excmd = excmd
|
101
|
+
end
|
102
|
+
opts.on("-n", "Equivalent to --excmd=number.") do
|
103
|
+
options.excmd = "number"
|
104
|
+
end
|
105
|
+
opts.on("--fields=+n", "Include line number information in the tag") do |flags|
|
106
|
+
flags_string_to_set.call(flags, options.fields)
|
107
|
+
end
|
108
|
+
opts.on("--all-files", "Parse all files in recursive mode (default: parse `*.rb' files)") do
|
57
109
|
options.all_files = true
|
58
110
|
end
|
59
111
|
|
@@ -66,14 +118,7 @@ module RipperTags
|
|
66
118
|
options.format = "emacs"
|
67
119
|
end
|
68
120
|
opts.on("--extra=FLAGS", "Specify extra flags for the formatter") do |flags|
|
69
|
-
flags
|
70
|
-
operation = :add
|
71
|
-
if flags[0] == "+" || flags[0] == "-"
|
72
|
-
operation = :delete if flags.shift == "-"
|
73
|
-
else
|
74
|
-
options.extra_flags.clear
|
75
|
-
end
|
76
|
-
flags.each { |f| options.extra_flags.send(operation, f) }
|
121
|
+
flags_string_to_set.call(flags, options.extra_flags)
|
77
122
|
end
|
78
123
|
|
79
124
|
opts.separator ""
|
@@ -106,6 +151,9 @@ module RipperTags
|
|
106
151
|
exit 1
|
107
152
|
end
|
108
153
|
end
|
154
|
+
opts.on_tail("--ignore-unsupported-options", "Don't fail when unsupported options given, just skip them") do
|
155
|
+
opts.ignore_unsupported_options = true
|
156
|
+
end
|
109
157
|
opts.on_tail("-v", "--version", "Print version information") do
|
110
158
|
puts opts.ver
|
111
159
|
exit
|
@@ -118,14 +166,17 @@ module RipperTags
|
|
118
166
|
def self.process_args(argv, run = method(:run))
|
119
167
|
option_parser(default_options) do |optparse, options|
|
120
168
|
file_list = optparse.parse(argv)
|
169
|
+
|
121
170
|
if !file_list.empty?
|
122
171
|
options.files = file_list
|
123
|
-
elsif !options.recursive
|
124
|
-
raise OptionParser::InvalidOption, "needs either a list of files or `-R' flag"
|
172
|
+
elsif !(options.recursive || options.input_file)
|
173
|
+
raise OptionParser::InvalidOption, "needs either a list of files, `-L`, or `-R' flag"
|
125
174
|
end
|
175
|
+
|
126
176
|
options.tag_file_name ||= options.format == 'emacs' ? './TAGS' : './tags'
|
127
177
|
options.format ||= File.basename(options.tag_file_name) == 'TAGS' ? 'emacs' : 'vim'
|
128
178
|
options.tag_relative = options.format == "emacs" if options.tag_relative.nil?
|
179
|
+
|
129
180
|
return run.call(options)
|
130
181
|
end
|
131
182
|
end
|
@@ -49,8 +49,8 @@ module RipperTags
|
|
49
49
|
file.end_with?(RUBY_EXT)
|
50
50
|
end
|
51
51
|
|
52
|
-
def include_file?(file)
|
53
|
-
(options.all_files || ruby_file?(file)) && !exclude_file?(file)
|
52
|
+
def include_file?(file, depth)
|
53
|
+
(depth == 0 || options.all_files || ruby_file?(file)) && !exclude_file?(file)
|
54
54
|
end
|
55
55
|
|
56
56
|
def resolve_file(file, depth = 0, &block)
|
@@ -66,8 +66,8 @@ module RipperTags
|
|
66
66
|
end
|
67
67
|
elsif depth > 0 || File.exist?(file)
|
68
68
|
file = clean_path(file) if depth == 0
|
69
|
-
yield file if include_file?(file)
|
70
|
-
|
69
|
+
yield file if include_file?(file, depth)
|
70
|
+
else
|
71
71
|
$stderr.puts "%s: %p: no such file or directory" % [
|
72
72
|
File.basename($0),
|
73
73
|
file
|
@@ -81,19 +81,32 @@ module RipperTags
|
|
81
81
|
|
82
82
|
def each_file(&block)
|
83
83
|
return to_enum(__method__) unless block_given?
|
84
|
-
|
84
|
+
each_input_file do |file|
|
85
85
|
resolve_file(file, &block)
|
86
86
|
end
|
87
87
|
end
|
88
|
+
|
89
|
+
def each_input_file(&block)
|
90
|
+
if options.input_file
|
91
|
+
io = options.input_file == "-" ? $stdin : File.new(options.input_file, DataReader::READ_MODE)
|
92
|
+
begin
|
93
|
+
io.each_line { |line| yield line.chomp }
|
94
|
+
ensure
|
95
|
+
io.close
|
96
|
+
end
|
97
|
+
else
|
98
|
+
options.files.each(&block)
|
99
|
+
end
|
100
|
+
end
|
88
101
|
end
|
89
102
|
|
90
103
|
class DataReader
|
91
104
|
attr_reader :options
|
92
|
-
|
105
|
+
|
106
|
+
READ_MODE = 'r:utf-8'
|
93
107
|
|
94
108
|
def initialize(options)
|
95
109
|
@options = options
|
96
|
-
@read_mode = defined?(::Encoding) ? 'r:utf-8' : 'r'
|
97
110
|
end
|
98
111
|
|
99
112
|
def file_finder
|
@@ -101,7 +114,7 @@ module RipperTags
|
|
101
114
|
end
|
102
115
|
|
103
116
|
def read_file(filename)
|
104
|
-
str = File.open(filename,
|
117
|
+
str = File.open(filename, READ_MODE) {|f| f.read }
|
105
118
|
normalize_encoding(str)
|
106
119
|
end
|
107
120
|
|
@@ -9,11 +9,15 @@ module RipperTags
|
|
9
9
|
|
10
10
|
def initialize(options)
|
11
11
|
@options = options
|
12
|
+
check_supported_flags(@options.extra_flags, supported_flags)
|
13
|
+
check_supported_flags(@options.fields, supported_fields)
|
14
|
+
end
|
12
15
|
|
13
|
-
|
14
|
-
|
16
|
+
def check_supported_flags(set, supported)
|
17
|
+
if set
|
18
|
+
unsupported = set - supported.to_set
|
15
19
|
if unsupported.any?
|
16
|
-
raise FatalError, "these
|
20
|
+
raise FatalError, "these fields are not supported in the '%s' format: %s" % [
|
17
21
|
options.format,
|
18
22
|
unsupported.to_a.join(", ")
|
19
23
|
]
|
@@ -27,6 +31,12 @@ module RipperTags
|
|
27
31
|
options.extra_flags && options.extra_flags.include?(flag)
|
28
32
|
end
|
29
33
|
|
34
|
+
def supported_fields() [] end
|
35
|
+
|
36
|
+
def field?(field)
|
37
|
+
options.fields && options.fields.include?(field)
|
38
|
+
end
|
39
|
+
|
30
40
|
def stdout?
|
31
41
|
'-' == options.tag_file_name
|
32
42
|
end
|
@@ -35,9 +45,9 @@ module RipperTags
|
|
35
45
|
if stdout?
|
36
46
|
begin
|
37
47
|
yield $stdout
|
38
|
-
|
39
|
-
|
40
|
-
|
48
|
+
rescue Errno::EINVAL
|
49
|
+
raise BrokenPipe
|
50
|
+
end
|
41
51
|
else
|
42
52
|
File.open(options.tag_file_name, 'w+') do |outfile|
|
43
53
|
yield outfile
|
data/lib/ripper-tags/parser.rb
CHANGED
@@ -71,8 +71,16 @@ class Parser < Ripper
|
|
71
71
|
"has_one", "has_many",
|
72
72
|
"belongs_to", "has_and_belongs_to_many",
|
73
73
|
"scope", "named_scope",
|
74
|
+
"public_class_method", "private_class_method",
|
75
|
+
"public", "protected", "private",
|
74
76
|
/^attr_(accessor|reader|writer)$/
|
75
77
|
on_method_add_arg([:fcall, name], args[0])
|
78
|
+
when "delegate"
|
79
|
+
on_delegate(*args[0][1..-1])
|
80
|
+
when "def_delegator", "def_instance_delegator"
|
81
|
+
on_def_delegator(*args[0][1..-1])
|
82
|
+
when "def_delegators", "def_instance_delegators"
|
83
|
+
on_def_delegators(*args[0][1..-1])
|
76
84
|
end
|
77
85
|
end
|
78
86
|
def on_bodystmt(*args)
|
@@ -95,11 +103,38 @@ class Parser < Ripper
|
|
95
103
|
end
|
96
104
|
end
|
97
105
|
|
106
|
+
def on_array(args)
|
107
|
+
if args.is_a?(Array) && args[0] == :args
|
108
|
+
args[1..-1]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def on_hash(args)
|
113
|
+
return unless args
|
114
|
+
|
115
|
+
args.select { |arg| arg.is_a?(Array) && arg[0] == :assoc }.map { |_assoc, k, _v| k }
|
116
|
+
end
|
117
|
+
|
98
118
|
undef on_tstring_content
|
99
119
|
def on_tstring_content(str)
|
100
120
|
str
|
101
121
|
end
|
102
122
|
|
123
|
+
def on_string_add(*args)
|
124
|
+
[args[1], lineno]
|
125
|
+
end
|
126
|
+
|
127
|
+
def on_string_embexpr(*)
|
128
|
+
:string_embexpr
|
129
|
+
end
|
130
|
+
def on_string_dvar(*)
|
131
|
+
:string_embexpr
|
132
|
+
end
|
133
|
+
def on_string_literal(*args)
|
134
|
+
args = args.flatten
|
135
|
+
args unless args.include?(:string_embexpr)
|
136
|
+
end
|
137
|
+
|
103
138
|
def on_xstring_add(first, arg)
|
104
139
|
arg if first.nil?
|
105
140
|
end
|
@@ -109,7 +144,7 @@ class Parser < Ripper
|
|
109
144
|
end
|
110
145
|
|
111
146
|
def on_vcall(name)
|
112
|
-
[name[0].to_sym] if name[0].to_s =~ /^(private|protected|public)$/
|
147
|
+
[name[0].to_sym] if name[0].to_s =~ /^(private|protected|public|private_class_method|public_class_method)$/
|
113
148
|
end
|
114
149
|
|
115
150
|
def on_call(lhs, op, rhs)
|
@@ -136,6 +171,18 @@ class Parser < Ripper
|
|
136
171
|
[:alias, args[1][0], args[2][0], line] if args[1] && args[2]
|
137
172
|
when "define_method"
|
138
173
|
[:def, args[1][0], line]
|
174
|
+
when "public_class_method", "private_class_method", "private", "public", "protected"
|
175
|
+
access = name.sub("_class_method", "")
|
176
|
+
|
177
|
+
if args[1][1] == 'self'
|
178
|
+
klass = 'self'
|
179
|
+
method_name = args[1][2]
|
180
|
+
else
|
181
|
+
klass = nil
|
182
|
+
method_name = args[1][1]
|
183
|
+
end
|
184
|
+
|
185
|
+
[:def_with_access, klass, method_name, access, line]
|
139
186
|
when "scope", "named_scope"
|
140
187
|
[:rails_def, :scope, args[1][0], line]
|
141
188
|
when /^attr_(accessor|reader|writer)$/
|
@@ -218,6 +265,43 @@ class Parser < Ripper
|
|
218
265
|
super
|
219
266
|
end
|
220
267
|
end
|
268
|
+
|
269
|
+
# Otherwise hashes and keyword arguments turn into a list of their keys only
|
270
|
+
def on_assoc_new(key, value)
|
271
|
+
[:assoc, key, value]
|
272
|
+
end
|
273
|
+
|
274
|
+
def on_delegate(*args)
|
275
|
+
method_names = args.select { |arg| arg.first.is_a? String }
|
276
|
+
options = args.select { |arg| arg.first.is_a?(Array) && arg.first.first == :assoc }.flatten(1)
|
277
|
+
options = Hash[options.map { |_assoc, key, val| [key.first, val.first] }]
|
278
|
+
|
279
|
+
target = options["to:"] || options["to"] # When using hashrocket syntax there is no ':'
|
280
|
+
prefix = options["prefix:"] || options["prefix"]
|
281
|
+
method_prefix = if prefix.is_a?(Array) && prefix.first == "true"
|
282
|
+
"#{target}_"
|
283
|
+
elsif prefix.is_a? String
|
284
|
+
"#{prefix}_"
|
285
|
+
else
|
286
|
+
""
|
287
|
+
end
|
288
|
+
|
289
|
+
method_names.map do |name, lineno|
|
290
|
+
[:def, "#{method_prefix}#{name}", lineno]
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def on_def_delegator(*args)
|
295
|
+
name, lineno = args.last
|
296
|
+
[:def, name, lineno]
|
297
|
+
end
|
298
|
+
|
299
|
+
def on_def_delegators(*args)
|
300
|
+
_target, *names = args
|
301
|
+
names.map do |name, lineno|
|
302
|
+
[:def, name, lineno]
|
303
|
+
end
|
304
|
+
end
|
221
305
|
end
|
222
306
|
|
223
307
|
class Visitor
|
@@ -254,7 +338,10 @@ end
|
|
254
338
|
sexp.each{ |child| process(child) }
|
255
339
|
when Symbol
|
256
340
|
name, *args = sexp
|
257
|
-
|
341
|
+
name = name.to_s
|
342
|
+
if name.index("@") != 0 && name.index("-@") != 0
|
343
|
+
__send__("on_#{name}", *args)
|
344
|
+
end
|
258
345
|
when String, nil
|
259
346
|
# nothing
|
260
347
|
end
|
@@ -297,9 +384,11 @@ end
|
|
297
384
|
on_module_or_class(:class, name, superclass, *body)
|
298
385
|
end
|
299
386
|
|
300
|
-
def on_private()
|
301
|
-
def on_protected()
|
302
|
-
def on_public()
|
387
|
+
def on_private() @current_access = 'private' end
|
388
|
+
def on_protected() @current_access = 'protected' end
|
389
|
+
def on_public() @current_access = 'public' end
|
390
|
+
def on_private_class_method() @current_access = 'private' end
|
391
|
+
def on_public_class_method() @current_access = 'public' end
|
303
392
|
|
304
393
|
# Ripper trips up on keyword arguments in pre-2.1 Ruby and supplies extra
|
305
394
|
# arguments that we just ignore here
|
@@ -320,6 +409,8 @@ end
|
|
320
409
|
namespace = namespace + parts
|
321
410
|
end
|
322
411
|
|
412
|
+
process(rhs)
|
413
|
+
|
323
414
|
emit_tag :constant, line,
|
324
415
|
:name => name,
|
325
416
|
:full_name => (namespace + [name]).join('::'),
|
@@ -354,6 +445,18 @@ end
|
|
354
445
|
:class => ns.join('::')
|
355
446
|
end
|
356
447
|
|
448
|
+
def on_def_with_access(klass, name, access, line)
|
449
|
+
ns = (@namespace.empty? ? 'Object' : @namespace.join('::'))
|
450
|
+
singleton = @is_singleton || klass == 'self'
|
451
|
+
kind = singleton ? 'singleton method' : 'method'
|
452
|
+
|
453
|
+
emit_tag kind, line,
|
454
|
+
:name => name,
|
455
|
+
:full_name => "#{ns}#{singleton ? '.' : '#'}#{name}",
|
456
|
+
:class => ns,
|
457
|
+
:access => access
|
458
|
+
end
|
459
|
+
|
357
460
|
def on_rails_def(kind, name, line)
|
358
461
|
ns = (@namespace.empty?? 'Object' : @namespace.join('::'))
|
359
462
|
|
@@ -3,6 +3,7 @@ require 'ripper-tags/default_formatter'
|
|
3
3
|
module RipperTags
|
4
4
|
class VimFormatter < DefaultFormatter
|
5
5
|
def supported_flags() ['q'] end
|
6
|
+
def supported_fields() ['n'] end
|
6
7
|
|
7
8
|
def include_qualified_names?
|
8
9
|
return @include_qualified_names if defined? @include_qualified_names
|
@@ -39,8 +40,12 @@ module RipperTags
|
|
39
40
|
const.to_s.gsub('::', '.')
|
40
41
|
end
|
41
42
|
|
42
|
-
def
|
43
|
-
|
43
|
+
def display_excmd_info(tag)
|
44
|
+
if options.excmd == "number"
|
45
|
+
"%d;\"" % tag.fetch(:line)
|
46
|
+
else
|
47
|
+
"/^%s$/;\"" % tag.fetch(:pattern).to_s.gsub('\\','\\\\\\\\').gsub('/','\\/')
|
48
|
+
end
|
44
49
|
end
|
45
50
|
|
46
51
|
def display_class(tag)
|
@@ -59,6 +64,14 @@ module RipperTags
|
|
59
64
|
end
|
60
65
|
end
|
61
66
|
|
67
|
+
def display_line_number(tag)
|
68
|
+
if field?('n') && tag[:line]
|
69
|
+
"\tline:%s" % tag[:line]
|
70
|
+
else
|
71
|
+
""
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
62
75
|
def display_kind(tag)
|
63
76
|
case tag.fetch(:kind)
|
64
77
|
when 'method' then 'f'
|
@@ -71,11 +84,12 @@ module RipperTags
|
|
71
84
|
end
|
72
85
|
|
73
86
|
def format(tag, name_field = :name)
|
74
|
-
"%s\t%s\t
|
87
|
+
"%s\t%s\t%s\t%s%s%s%s" % [
|
75
88
|
tag.fetch(name_field),
|
76
89
|
relative_path(tag),
|
77
|
-
|
90
|
+
display_excmd_info(tag),
|
78
91
|
display_kind(tag),
|
92
|
+
display_line_number(tag),
|
79
93
|
name_field == :full_name ? nil : display_class(tag),
|
80
94
|
display_inheritance(tag),
|
81
95
|
]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ripper-tags
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: fast, accurate ctags generator for ruby source code using Ripper
|
14
14
|
email:
|
@@ -40,7 +40,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
43
|
+
version: '1.9'
|
44
44
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
46
|
- - ">="
|