ripper-tags 0.1.1 → 0.1.2
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 +15 -0
- data/.gitignore +3 -0
- data/Gemfile +1 -1
- data/LICENSE +21 -0
- data/README.md +15 -45
- data/bin/ripper-tags +8 -93
- data/lib/ripper-tags/data_reader.rb +125 -0
- data/lib/ripper-tags/default_formatter.rb +67 -0
- data/lib/ripper-tags/emacs_formatter.rb +69 -0
- data/lib/ripper-tags/json_formatter.rb +10 -0
- data/lib/{tag_ripper.rb → ripper-tags/parser.rb} +141 -13
- data/lib/ripper-tags/vim_formatter.rb +74 -0
- data/lib/ripper-tags.rb +120 -0
- data/ripper-tags.gemspec +3 -1
- data/test/fixtures/_git/hooks/hook.rb +0 -0
- data/test/fixtures/encoding.rb +4 -0
- data/test/fixtures/non-script.txt +0 -0
- data/test/fixtures/very/deep/script.rb +0 -0
- data/test/fixtures/very/inter.rb +0 -0
- data/test/test_cli.rb +84 -0
- data/test/test_data_reader.rb +80 -0
- data/test/test_formatters.rb +120 -0
- data/test/test_ripper_tags.rb +218 -3
- metadata +55 -57
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'ripper'
|
2
2
|
|
3
|
-
|
3
|
+
module RipperTags
|
4
|
+
|
5
|
+
class Parser < Ripper
|
4
6
|
def self.extract(data, file='(eval)')
|
5
7
|
sexp = new(data, file).parse
|
6
8
|
Visitor.new(sexp, file, data).tags
|
@@ -33,13 +35,14 @@ class TagRipper < Ripper
|
|
33
35
|
[:defs, receiver && receiver[0], *method]
|
34
36
|
end
|
35
37
|
def on_alias(lhs, rhs)
|
36
|
-
[:alias, lhs[0], rhs[0], rhs[1]]
|
38
|
+
[:alias, lhs[0], rhs[0], rhs[1]] if lhs && rhs
|
37
39
|
end
|
38
40
|
def on_assign(lhs, rhs)
|
39
41
|
return if lhs.nil?
|
40
42
|
return if lhs[0] == :field
|
41
43
|
return if lhs[0] == :aref_field
|
42
|
-
|
44
|
+
lhs, line = lhs
|
45
|
+
[:assign, lhs, rhs, line]
|
43
46
|
end
|
44
47
|
def on_sclass(name, body)
|
45
48
|
[:sclass, name && name.flatten(1), *body.compact]
|
@@ -52,6 +55,7 @@ class TagRipper < Ripper
|
|
52
55
|
end
|
53
56
|
|
54
57
|
def on_const_path_ref(a, b)
|
58
|
+
return if a.nil? || b.nil?
|
55
59
|
a.flatten!(1)
|
56
60
|
[[a && a[0], b[0]].join('::'), b[1]]
|
57
61
|
end
|
@@ -61,9 +65,14 @@ class TagRipper < Ripper
|
|
61
65
|
end
|
62
66
|
|
63
67
|
def on_command(name, *args)
|
64
|
-
|
65
|
-
|
66
|
-
|
68
|
+
case name[0]
|
69
|
+
when "define_method", "alias_method",
|
70
|
+
"has_one", "has_many",
|
71
|
+
"belongs_to", "has_and_belongs_to_many",
|
72
|
+
"scope", "named_scope",
|
73
|
+
/^attr_(accessor|reader|writer)$/
|
74
|
+
on_method_add_arg([:fcall, name], args[0])
|
75
|
+
end
|
67
76
|
end
|
68
77
|
def on_bodystmt(*args)
|
69
78
|
args
|
@@ -78,6 +87,20 @@ class TagRipper < Ripper
|
|
78
87
|
end
|
79
88
|
alias on_if_mod on_unless_mod
|
80
89
|
|
90
|
+
def on_dyna_symbol(*args)
|
91
|
+
if args.length == 1 && args[0]
|
92
|
+
[args[0], lineno]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def on_tstring_content(str)
|
97
|
+
str
|
98
|
+
end
|
99
|
+
|
100
|
+
def on_xstring_add(first, arg)
|
101
|
+
arg if first.nil?
|
102
|
+
end
|
103
|
+
|
81
104
|
def on_var_ref(*args)
|
82
105
|
on_vcall(*args) || args
|
83
106
|
end
|
@@ -87,7 +110,84 @@ class TagRipper < Ripper
|
|
87
110
|
end
|
88
111
|
|
89
112
|
def on_call(lhs, op, rhs)
|
90
|
-
|
113
|
+
return unless lhs && rhs
|
114
|
+
arg = block = nil
|
115
|
+
[:call, lhs[0], rhs[0], arg, block]
|
116
|
+
end
|
117
|
+
|
118
|
+
def on_method_add_arg(call, args)
|
119
|
+
call_name = call && call[0]
|
120
|
+
first_arg = args && :args == args[0] && args[1]
|
121
|
+
|
122
|
+
if :call == call_name && first_arg
|
123
|
+
if args.length == 2
|
124
|
+
# augment call if a single argument was used
|
125
|
+
call = call.dup
|
126
|
+
call[3] = args[1]
|
127
|
+
end
|
128
|
+
call
|
129
|
+
elsif :fcall == call_name && first_arg
|
130
|
+
name, line = call[1]
|
131
|
+
case name
|
132
|
+
when "alias_method"
|
133
|
+
[:alias, args[1][0], args[2][0], line] if args[1] && args[2]
|
134
|
+
when "define_method"
|
135
|
+
[:def, args[1][0], line]
|
136
|
+
when "scope", "named_scope"
|
137
|
+
[:rails_def, :scope, args[1][0], line]
|
138
|
+
when /^attr_(accessor|reader|writer)$/
|
139
|
+
gen_reader = $1 != 'writer'
|
140
|
+
gen_writer = $1 != 'reader'
|
141
|
+
args[1..-1].inject([]) do |gen, arg|
|
142
|
+
gen << [:def, arg[0], line] if gen_reader
|
143
|
+
gen << [:def, "#{arg[0]}=", line] if gen_writer
|
144
|
+
gen
|
145
|
+
end
|
146
|
+
when "has_many", "has_and_belongs_to_many"
|
147
|
+
a = args[1][0]
|
148
|
+
kind = name.to_sym
|
149
|
+
gen = []
|
150
|
+
gen << [:rails_def, kind, a, line]
|
151
|
+
gen << [:rails_def, kind, "#{a}=", line]
|
152
|
+
if (sing = a.chomp('s')) != a
|
153
|
+
# poor man's singularize
|
154
|
+
gen << [:rails_def, kind, "#{sing}_ids", line]
|
155
|
+
gen << [:rails_def, kind, "#{sing}_ids=", line]
|
156
|
+
end
|
157
|
+
gen
|
158
|
+
when "belongs_to", "has_one"
|
159
|
+
a = args[1][0]
|
160
|
+
kind = name.to_sym
|
161
|
+
%W[ #{a} #{a}= build_#{a} create_#{a} create_#{a}! ].inject([]) do |gen, ident|
|
162
|
+
gen << [:rails_def, kind, ident, line]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
else
|
166
|
+
super
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
# handle `Class.new arg` call without parens
|
171
|
+
def on_command_call(*args)
|
172
|
+
if args.last && :args == args.last[0]
|
173
|
+
args_add = args.pop
|
174
|
+
call = on_call(*args)
|
175
|
+
on_method_add_arg(call, args_add)
|
176
|
+
else
|
177
|
+
super
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def on_fcall(*args)
|
182
|
+
[:fcall, *args]
|
183
|
+
end
|
184
|
+
|
185
|
+
def on_args_add(sub, arg)
|
186
|
+
if sub
|
187
|
+
sub + [arg]
|
188
|
+
else
|
189
|
+
[:args, arg].compact
|
190
|
+
end
|
91
191
|
end
|
92
192
|
|
93
193
|
def on_do_block(*args)
|
@@ -95,14 +195,22 @@ class TagRipper < Ripper
|
|
95
195
|
end
|
96
196
|
|
97
197
|
def on_method_add_block(method, body)
|
98
|
-
return unless method
|
99
|
-
if method[2]
|
198
|
+
return unless method
|
199
|
+
if %w[class_eval module_eval].include?(method[2]) && body
|
100
200
|
[:class_eval, [
|
101
201
|
method[1].is_a?(Array) ? method[1][0] : method[1],
|
102
202
|
method[3]
|
103
203
|
], body.last]
|
204
|
+
elsif :call == method[0] && body
|
205
|
+
# augment the `Class.new/Struct.new` call with associated block
|
206
|
+
call = method.dup
|
207
|
+
call[4] = body.last
|
208
|
+
call
|
209
|
+
else
|
210
|
+
super
|
104
211
|
end
|
105
212
|
end
|
213
|
+
end
|
106
214
|
|
107
215
|
class Visitor
|
108
216
|
attr_reader :tags
|
@@ -117,14 +225,14 @@ class TagRipper < Ripper
|
|
117
225
|
end
|
118
226
|
|
119
227
|
def emit_tag(kind, line, opts={})
|
120
|
-
@tags <<
|
228
|
+
@tags << {
|
121
229
|
:kind => kind.to_s,
|
122
230
|
:line => line,
|
123
231
|
:language => 'Ruby',
|
124
232
|
:path => @path,
|
125
233
|
:pattern => @lines[line-1].chomp,
|
126
234
|
:access => @current_access
|
127
|
-
).delete_if{ |k,v| v.nil? }
|
235
|
+
}.update(opts).delete_if{ |k,v| v.nil? }
|
128
236
|
end
|
129
237
|
|
130
238
|
def process(sexp)
|
@@ -153,6 +261,7 @@ class TagRipper < Ripper
|
|
153
261
|
superclass_name = superclass[0] == :call ?
|
154
262
|
superclass[1] :
|
155
263
|
superclass[0]
|
264
|
+
superclass_name = nil unless superclass_name =~ /^[A-Z]/
|
156
265
|
end
|
157
266
|
full_name = @namespace.join('::')
|
158
267
|
parts = full_name.split('::')
|
@@ -170,7 +279,7 @@ class TagRipper < Ripper
|
|
170
279
|
@namespace.pop
|
171
280
|
end
|
172
281
|
|
173
|
-
def on_module(name, body)
|
282
|
+
def on_module(name, body = nil)
|
174
283
|
on_module_or_class(:module, name, nil, body)
|
175
284
|
end
|
176
285
|
|
@@ -182,9 +291,16 @@ class TagRipper < Ripper
|
|
182
291
|
def on_protected() @current_access = 'protected' end
|
183
292
|
def on_public() @current_access = 'public' end
|
184
293
|
|
185
|
-
def on_assign(name, line)
|
294
|
+
def on_assign(name, rhs, line)
|
186
295
|
return unless name =~ /^[A-Z]/
|
187
296
|
|
297
|
+
if rhs && :call == rhs[0] && rhs[1] && "#{rhs[1][0]}.#{rhs[2]}" =~ /^(Class|Module|Struct)\.new$/
|
298
|
+
kind = $1 == 'Module' ? :module : :class
|
299
|
+
superclass = $1 == 'Class' ? rhs[3] : nil
|
300
|
+
superclass.flatten! if superclass
|
301
|
+
return on_module_or_class(kind, [name, line], superclass, rhs[4])
|
302
|
+
end
|
303
|
+
|
188
304
|
emit_tag :constant, line,
|
189
305
|
:name => name,
|
190
306
|
:full_name => (@namespace + [name]).join('::'),
|
@@ -219,6 +335,16 @@ class TagRipper < Ripper
|
|
219
335
|
:class => ns.join('::')
|
220
336
|
end
|
221
337
|
|
338
|
+
def on_rails_def(kind, name, line)
|
339
|
+
ns = (@namespace.empty?? 'Object' : @namespace.join('::'))
|
340
|
+
|
341
|
+
emit_tag kind, line,
|
342
|
+
:language => 'Rails',
|
343
|
+
:name => name,
|
344
|
+
:full_name => "#{ns}.#{name}",
|
345
|
+
:class => ns
|
346
|
+
end
|
347
|
+
|
222
348
|
def on_sclass(name, body)
|
223
349
|
name, line = *name
|
224
350
|
@namespace << name unless name == 'self'
|
@@ -241,5 +367,7 @@ class TagRipper < Ripper
|
|
241
367
|
end
|
242
368
|
alias on_aref_field on_call
|
243
369
|
alias on_field on_call
|
370
|
+
alias on_fcall on_call
|
371
|
+
alias on_args on_call
|
244
372
|
end
|
245
373
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'ripper-tags/default_formatter'
|
2
|
+
|
3
|
+
module RipperTags
|
4
|
+
class VimFormatter < DefaultFormatter
|
5
|
+
def header
|
6
|
+
<<-EOC
|
7
|
+
!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;" to lines/
|
8
|
+
!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/
|
9
|
+
EOC
|
10
|
+
end
|
11
|
+
|
12
|
+
# prepend header and sort lines before closing output
|
13
|
+
def with_output
|
14
|
+
super do |out|
|
15
|
+
out.puts header
|
16
|
+
@queued_write = []
|
17
|
+
yield out
|
18
|
+
@queued_write.sort.each do |line|
|
19
|
+
out.puts(line)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def write(tag, out)
|
25
|
+
@queued_write << format(tag)
|
26
|
+
end
|
27
|
+
|
28
|
+
def display_constant(const)
|
29
|
+
const.to_s.gsub('::', '.')
|
30
|
+
end
|
31
|
+
|
32
|
+
def display_pattern(tag)
|
33
|
+
tag.fetch(:pattern).to_s.gsub('\\','\\\\\\\\').gsub('/','\\/')
|
34
|
+
end
|
35
|
+
|
36
|
+
def display_class(tag)
|
37
|
+
if tag[:class]
|
38
|
+
"\tclass:%s" % display_constant(tag[:class])
|
39
|
+
else
|
40
|
+
""
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def display_inheritance(tag)
|
45
|
+
if tag[:inherits] && 'class' == tag[:kind]
|
46
|
+
"\tinherits:%s" % display_constant(tag[:inherits])
|
47
|
+
else
|
48
|
+
""
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def display_kind(tag)
|
53
|
+
case tag.fetch(:kind)
|
54
|
+
when 'method' then 'f'
|
55
|
+
when 'singleton method' then 'F'
|
56
|
+
when 'constant' then 'C'
|
57
|
+
when 'scope', 'belongs_to', 'has_one', 'has_many', 'has_and_belongs_to_many'
|
58
|
+
'F'
|
59
|
+
else tag[:kind].slice(0,1)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def format(tag)
|
64
|
+
"%s\t%s\t/^%s$/;\"\t%s%s%s" % [
|
65
|
+
tag.fetch(:name),
|
66
|
+
relative_path(tag),
|
67
|
+
display_pattern(tag),
|
68
|
+
display_kind(tag),
|
69
|
+
display_class(tag),
|
70
|
+
display_inheritance(tag),
|
71
|
+
]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/ripper-tags.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'ripper-tags/parser'
|
4
|
+
require 'ripper-tags/data_reader'
|
5
|
+
require 'ripper-tags/default_formatter'
|
6
|
+
require 'ripper-tags/emacs_formatter'
|
7
|
+
require 'ripper-tags/vim_formatter'
|
8
|
+
require 'ripper-tags/json_formatter'
|
9
|
+
|
10
|
+
module RipperTags
|
11
|
+
def self.version() "0.1.2" end
|
12
|
+
|
13
|
+
def self.default_options
|
14
|
+
OpenStruct.new \
|
15
|
+
:format => nil,
|
16
|
+
:tag_file_name => "./tags",
|
17
|
+
:tag_relative => nil,
|
18
|
+
:debug => false,
|
19
|
+
:verbose_debug => false,
|
20
|
+
:verbose => false,
|
21
|
+
:force => false,
|
22
|
+
:files => %w[.],
|
23
|
+
:recursive => false,
|
24
|
+
:exclude => %w[.git],
|
25
|
+
:all_files => false
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.option_parser(options)
|
29
|
+
OptionParser.new do |opts|
|
30
|
+
opts.banner = "Usage: #{opts.program_name} [options] FILES..."
|
31
|
+
opts.version = version
|
32
|
+
|
33
|
+
opts.separator ""
|
34
|
+
|
35
|
+
opts.on("-f", "--tag-file (FILE|-)", "File to write tags to (default: `#{options.tag_file_name}')",
|
36
|
+
'"-" outputs to standard output') do |fname|
|
37
|
+
options.tag_file_name = fname
|
38
|
+
end
|
39
|
+
opts.on("--tag-relative", "Make file paths relative to the directory of the tag file") do
|
40
|
+
options.tag_relative = true
|
41
|
+
end
|
42
|
+
opts.on("-R", "--recursive", "Descend recursively into subdirectories") do
|
43
|
+
options.recursive = true
|
44
|
+
end
|
45
|
+
opts.on("--exclude PATTERN", "Exclude a file, directory or pattern") do |pattern|
|
46
|
+
if pattern.empty?
|
47
|
+
options.exclude.clear
|
48
|
+
else
|
49
|
+
options.exclude << pattern
|
50
|
+
end
|
51
|
+
end
|
52
|
+
opts.on("--all-files", "Parse all files as ruby files, not just `*.rb' ones") do
|
53
|
+
options.all_files = true
|
54
|
+
end
|
55
|
+
|
56
|
+
opts.separator " "
|
57
|
+
|
58
|
+
opts.on("--format (emacs|json|custom)", "Set output format (default: vim)") do |fmt|
|
59
|
+
options.format = fmt
|
60
|
+
end
|
61
|
+
opts.on("-e", "--emacs", "Output Emacs format (default if `--tag-file' is `TAGS')") do
|
62
|
+
options.format = "emacs"
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.separator ""
|
66
|
+
|
67
|
+
opts.on_tail("-d", "--debug", "Output parse tree") do
|
68
|
+
options.debug = true
|
69
|
+
end
|
70
|
+
opts.on_tail("--debug-verbose", "Output parse tree verbosely") do
|
71
|
+
options.verbose_debug = true
|
72
|
+
end
|
73
|
+
opts.on_tail("-V", "--verbose", "Print additional information on stderr") do
|
74
|
+
options.verbose = true
|
75
|
+
end
|
76
|
+
opts.on_tail("--force", "Skip files with parsing errors") do
|
77
|
+
options.force = true
|
78
|
+
end
|
79
|
+
opts.on_tail("-v", "--version", "Print version information") do
|
80
|
+
puts opts.ver
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
|
84
|
+
yield(opts, options) if block_given?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.process_args(argv, run = method(:run))
|
89
|
+
option_parser(default_options) do |optparse, options|
|
90
|
+
file_list = optparse.parse(argv)
|
91
|
+
if !file_list.empty? then options.files = file_list
|
92
|
+
elsif !options.recursive then abort(optparse.banner)
|
93
|
+
end
|
94
|
+
options.format ||= File.basename(options.tag_file_name) == "TAGS" ? "emacs" : "vim"
|
95
|
+
options.tag_relative = options.format == "emacs" if options.tag_relative.nil?
|
96
|
+
return run.call(options)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.formatter_for(options)
|
101
|
+
options.formatter ||
|
102
|
+
case options.format
|
103
|
+
when "vim" then RipperTags::VimFormatter
|
104
|
+
when "emacs" then RipperTags::EmacsFormatter
|
105
|
+
when "json" then RipperTags::JSONFormatter
|
106
|
+
when "custom" then RipperTags::DefaultFormatter
|
107
|
+
else raise ArgumentError, "unknown format: #{options.format.inspect}"
|
108
|
+
end.new(options)
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.run(options)
|
112
|
+
reader = RipperTags::DataReader.new(options)
|
113
|
+
formatter = formatter_for(options)
|
114
|
+
formatter.with_output do |out|
|
115
|
+
reader.each_tag do |tag|
|
116
|
+
formatter.write(tag, out)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/ripper-tags.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'ripper-tags'
|
3
|
-
s.version = '0.1.
|
3
|
+
s.version = '0.1.2'
|
4
4
|
|
5
5
|
s.summary = 'ctags generator for ruby code'
|
6
6
|
s.description = 'fast, accurate ctags generator for ruby source code using Ripper'
|
@@ -17,5 +17,7 @@ Gem::Specification.new do |s|
|
|
17
17
|
s.bindir = 'bin'
|
18
18
|
s.executables << 'ripper-tags'
|
19
19
|
|
20
|
+
s.license = 'MIT'
|
21
|
+
|
20
22
|
s.files = `git ls-files`.split("\n")
|
21
23
|
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/test/test_cli.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'stringio'
|
3
|
+
require 'ripper-tags'
|
4
|
+
|
5
|
+
class CliTest < Test::Unit::TestCase
|
6
|
+
def process_args(argv)
|
7
|
+
RipperTags.process_args(argv, lambda {|o| o})
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_empty_args
|
11
|
+
err = assert_raise(SystemExit) do
|
12
|
+
with_program_name('ripper-tags') do
|
13
|
+
capture_stderr do
|
14
|
+
RipperTags.process_args([])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
assert_equal "Usage: ripper-tags [options] FILES...", err.message
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_invalid_option
|
22
|
+
err = assert_raise(OptionParser::InvalidOption) do
|
23
|
+
RipperTags.process_args(%[--moo])
|
24
|
+
end
|
25
|
+
assert_equal "invalid option: --moo", err.message
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_recurse_defaults_to_current_dir
|
29
|
+
options = process_args(%w[-R])
|
30
|
+
assert_equal true, options.recursive
|
31
|
+
assert_equal %w[.], options.files
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_exclude_add_patterns
|
35
|
+
options = process_args(%w[-R --exclude vendor --exclude=bundle/*])
|
36
|
+
assert_equal %w[.git vendor bundle/*], options.exclude
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_exclude_clear
|
40
|
+
options = process_args(%w[-R --exclude=])
|
41
|
+
assert_equal [], options.exclude
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_TAGS_triggers_to_emacs_format
|
45
|
+
options = process_args(%w[-f ./TAGS script.rb])
|
46
|
+
assert_equal './TAGS', options.tag_file_name
|
47
|
+
assert_equal 'emacs', options.format
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_tag_relative_off_by_default
|
51
|
+
options = process_args(%w[ -R ])
|
52
|
+
assert_equal false, options.tag_relative
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_tag_relative_on
|
56
|
+
options = process_args(%w[ -R --tag-relative ])
|
57
|
+
assert_equal true, options.tag_relative
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_tag_relative_on_for_emacs
|
61
|
+
options = process_args(%w[ -R -e ])
|
62
|
+
assert_equal true, options.tag_relative
|
63
|
+
end
|
64
|
+
|
65
|
+
def with_program_name(name)
|
66
|
+
old_name = $0
|
67
|
+
$0 = name
|
68
|
+
begin
|
69
|
+
yield
|
70
|
+
ensure
|
71
|
+
$0 = old_name
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def capture_stderr
|
76
|
+
old_stderr = $stderr
|
77
|
+
$stderr = StringIO.new
|
78
|
+
begin
|
79
|
+
yield
|
80
|
+
ensure
|
81
|
+
$stderr = old_stderr
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'ripper-tags/data_reader'
|
4
|
+
|
5
|
+
class DataReaderTest < Test::Unit::TestCase
|
6
|
+
FIXTURES = File.expand_path('../fixtures', __FILE__)
|
7
|
+
|
8
|
+
def fixture(path)
|
9
|
+
File.join(FIXTURES, path)
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_files(*files)
|
13
|
+
opts = files.last.is_a?(Hash) ? files.pop : {}
|
14
|
+
options = OpenStruct.new({:files => files, :recursive => true}.merge(opts))
|
15
|
+
finder = RipperTags::FileFinder.new(options)
|
16
|
+
finder.each_file.map {|f| f.sub("#{FIXTURES}/", '') }
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_encoding
|
20
|
+
with_default_encoding('utf-8') do
|
21
|
+
options = OpenStruct.new(:files => [fixture('encoding.rb')])
|
22
|
+
reader = RipperTags::DataReader.new(options)
|
23
|
+
tags = reader.each_tag.to_a
|
24
|
+
assert_equal 'Object#encoding', tags[0][:full_name]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_encoding_non_utf8_default
|
29
|
+
with_default_encoding('us-ascii') do
|
30
|
+
options = OpenStruct.new(:files => [fixture('encoding.rb')])
|
31
|
+
reader = RipperTags::DataReader.new(options)
|
32
|
+
tags = reader.each_tag.to_a
|
33
|
+
assert_equal 'Object#encoding', tags[0][:full_name]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_file_finder
|
38
|
+
files = find_files(fixture(''), :exclude => %w[_git])
|
39
|
+
expected = %w[
|
40
|
+
encoding.rb
|
41
|
+
very/deep/script.rb
|
42
|
+
very/inter.rb
|
43
|
+
]
|
44
|
+
assert_equal expected, files
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_file_finder_no_exclude
|
48
|
+
files = find_files(fixture(''), :exclude => [])
|
49
|
+
assert files.include?('_git/hooks/hook.rb'), files.inspect
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_file_finder_exclude
|
53
|
+
files = find_files(fixture(''), :exclude => %w[_git very])
|
54
|
+
expected = %w[ encoding.rb ]
|
55
|
+
assert_equal expected, files
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_file_finder_exclude_glob
|
59
|
+
files = find_files(fixture(''), :exclude => %w[_git very/deep/*])
|
60
|
+
expected = %w[
|
61
|
+
encoding.rb
|
62
|
+
very/inter.rb
|
63
|
+
]
|
64
|
+
assert_equal expected, files
|
65
|
+
end
|
66
|
+
|
67
|
+
def with_default_encoding(name)
|
68
|
+
if defined?(Encoding)
|
69
|
+
old_default = Encoding.default_external
|
70
|
+
Encoding.default_external = name
|
71
|
+
begin
|
72
|
+
yield
|
73
|
+
ensure
|
74
|
+
Encoding.default_external = old_default
|
75
|
+
end
|
76
|
+
else
|
77
|
+
yield
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|