ripper-tags 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|