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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b7f252249e97f4fc155fc6fc24a0e1bd15a76b16
4
- data.tar.gz: 988fad9d5795bffab282f8725698c4399b79b324
3
+ metadata.gz: 52c268f393b07f8fa528f4886a5c5c3d39fa712f
4
+ data.tar.gz: 7ea8519875252ee44f554ad3021d02a29e482970
5
5
  SHA512:
6
- metadata.gz: feacc50ba4dee2e08023a4a2a0c1fa7bdb66b71952999ea3f11118fd0d97e5efb8004200e1939b03d71ea039d86a0763b4ad7fdebb85254130b3156ce0e4cdfe
7
- data.tar.gz: 43eda4fcf9d254eaf133ea2ee3db1475925ae37c016db3c5cd4c7ff1a145be7fbd06d2ce6061ac84028e7ce0508214d6c48b72a8da60db3ff7bf5d8ce5fdfeb4
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.3.5" end
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
- OptionParser.new do |opts|
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("--all-files", "Parse all files as ruby files, not just `*.rb' ones") do
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 = flags.split("")
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
- elsif
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
- options.files.each do |file|
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
- attr_accessor :read_mode
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, read_mode) {|f| f.read }
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
- if @options.extra_flags
14
- unsupported = @options.extra_flags - supported_flags.to_set
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 flags are not supported in the '%s' format: %s" % [
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
- rescue Errno::EINVAL
39
- raise BrokenPipe
40
- end
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
@@ -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
- __send__("on_#{name}", *args) unless name.to_s.index("@") == 0
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() @current_access = 'private' end
301
- def on_protected() @current_access = 'protected' end
302
- def on_public() @current_access = 'public' end
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 display_pattern(tag)
43
- tag.fetch(:pattern).to_s.gsub('\\','\\\\\\\\').gsub('/','\\/')
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/^%s$/;\"\t%s%s%s" % [
87
+ "%s\t%s\t%s\t%s%s%s%s" % [
75
88
  tag.fetch(name_field),
76
89
  relative_path(tag),
77
- display_pattern(tag),
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.3.5
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-07-24 00:00:00.000000000 Z
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: '0'
43
+ version: '1.9'
44
44
  required_rubygems_version: !ruby/object:Gem::Requirement
45
45
  requirements:
46
46
  - - ">="