ripper-tags 0.3.5 → 0.4.0

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.
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
  - - ">="