ripper-tags 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +5 -0
- data/README.md +57 -0
- data/Rakefile +6 -0
- data/bin/ripper-tags +76 -0
- data/lib/tag_ripper.rb +241 -0
- data/ripper-tags.gemspec +21 -0
- data/test/test_ripper_tags.rb +76 -0
- metadata +85 -0
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
## ripper-tags
|
2
|
+
|
3
|
+
fast, accurate ctags generator for ruby source code using Ripper
|
4
|
+
|
5
|
+
### usage (bin)
|
6
|
+
|
7
|
+
```
|
8
|
+
$ ripper-tags /usr/lib/ruby/1.8/timeout.rb
|
9
|
+
30 module Timeout
|
10
|
+
35 class Timeout::Error < Interrupt
|
11
|
+
37 class Timeout::ExitException < Exception
|
12
|
+
40 const Timeout::THIS_FILE
|
13
|
+
41 const Timeout::CALLER_OFFSET
|
14
|
+
52 def Timeout#timeout
|
15
|
+
100 def Object#timeout
|
16
|
+
108 const TimeoutError
|
17
|
+
|
18
|
+
$ ripper-tags --debug /usr/lib/ruby/1.8/timeout.rb
|
19
|
+
[[:module,
|
20
|
+
["Timeout", 30],
|
21
|
+
[[:class, ["Error", 35], ["Interrupt", 35], []],
|
22
|
+
[:class, ["ExitException", 37], ["Exception", 37], []],
|
23
|
+
[:assign, "THIS_FILE", 40],
|
24
|
+
[:assign, "CALLER_OFFSET", 41],
|
25
|
+
[:def, "timeout", 52]]],
|
26
|
+
[:def, "timeout", 100],
|
27
|
+
[:assign, "TimeoutError", 108]]
|
28
|
+
|
29
|
+
$ ripper-tags --vim /usr/lib/ruby/1.8/timeout.rb
|
30
|
+
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
31
|
+
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
32
|
+
CALLER_OFFSET /usr/lib/ruby/1.8/timeout.rb /^ CALLER_OFFSET = ((c = caller[0]) && THIS_FILE =~ c) ? 1 : 0$/;" C class:Timeout
|
33
|
+
Error /usr/lib/ruby/1.8/timeout.rb /^ class Error < Interrupt$/;" c class:Timeout inherits:Interrupt
|
34
|
+
ExitException /usr/lib/ruby/1.8/timeout.rb /^ class ExitException < ::Exception # :nodoc:$/;" c class:Timeout inherits:Exception
|
35
|
+
THIS_FILE /usr/lib/ruby/1.8/timeout.rb /^ THIS_FILE = \/\\A#{Regexp.quote(__FILE__)}:\/o$/;" C class:Timeout
|
36
|
+
Timeout /usr/lib/ruby/1.8/timeout.rb /^module Timeout$/;" m
|
37
|
+
TimeoutError /usr/lib/ruby/1.8/timeout.rb /^TimeoutError = Timeout::Error # :nodoc:$/;" C class:
|
38
|
+
timeout /usr/lib/ruby/1.8/timeout.rb /^def timeout(n, e = nil, &block) # :nodoc:$/;" f class:Object
|
39
|
+
timeout /usr/lib/ruby/1.8/timeout.rb /^ def timeout(sec, klass = nil)$/;" f class:Timeout
|
40
|
+
|
41
|
+
$ ripper-tags --json /usr/lib/ruby/1.8/timeout.rb
|
42
|
+
{"full_name":"Timeout","name":"Timeout","kind":"module","line":30,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":"module Timeout"}
|
43
|
+
{"full_name":"Timeout::Error","name":"Error","class":"Timeout","inherits":"Interrupt","kind":"class","line":35,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" class Error < Interrupt"}
|
44
|
+
{"full_name":"Timeout::ExitException","name":"ExitException","class":"Timeout","inherits":"Exception","kind":"class","line":37,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" class ExitException < ::Exception # :nodoc:"}
|
45
|
+
{"name":"THIS_FILE","full_name":"Timeout::THIS_FILE","class":"Timeout","kind":"constant","line":40,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" THIS_FILE = /\\A#{Regexp.quote(__FILE__)}:/o"}
|
46
|
+
{"name":"CALLER_OFFSET","full_name":"Timeout::CALLER_OFFSET","class":"Timeout","kind":"constant","line":41,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" CALLER_OFFSET = ((c = caller[0]) && THIS_FILE =~ c) ? 1 : 0"}
|
47
|
+
{"name":"timeout","full_name":"Timeout#timeout","class":"Timeout","kind":"method","line":52,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":" def timeout(sec, klass = nil)"}
|
48
|
+
{"name":"timeout","full_name":"Object#timeout","class":"Object","kind":"method","line":100,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":"def timeout(n, e = nil, &block) # :nodoc:"}
|
49
|
+
{"name":"TimeoutError","full_name":"TimeoutError","class":"","kind":"constant","line":108,"language":"Ruby","path":"/usr/lib/ruby/1.8/timeout.rb","pattern":"TimeoutError = Timeout::Error # :nodoc:"}
|
50
|
+
```
|
51
|
+
|
52
|
+
### usage (api)
|
53
|
+
|
54
|
+
``` ruby
|
55
|
+
require 'tag_ripper'
|
56
|
+
tags = TagRipper.extract("def abc() end", "mycode.rb")
|
57
|
+
```
|
data/Rakefile
ADDED
data/bin/ripper-tags
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'tag_ripper'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
if ARGV.delete('--json')
|
7
|
+
require 'yajl'
|
8
|
+
json = true
|
9
|
+
end
|
10
|
+
if ARGV.delete('--debug')
|
11
|
+
debug = true
|
12
|
+
end
|
13
|
+
if ARGV.delete('--vim')
|
14
|
+
vim = true
|
15
|
+
all_tags = []
|
16
|
+
end
|
17
|
+
|
18
|
+
ARGV.each do |file|
|
19
|
+
begin
|
20
|
+
data = File.read(file)
|
21
|
+
sexp = TagRipper.new(data, file).parse
|
22
|
+
v = TagRipper::Visitor.new(sexp, file, data)
|
23
|
+
|
24
|
+
if debug
|
25
|
+
pp sexp
|
26
|
+
elsif json
|
27
|
+
v.tags.each do |tag|
|
28
|
+
puts Yajl.dump(tag)
|
29
|
+
end
|
30
|
+
elsif vim
|
31
|
+
all_tags += v.tags
|
32
|
+
else
|
33
|
+
v.tags.each do |tag|
|
34
|
+
kind = case tag[:kind]
|
35
|
+
when /method$/ then 'def'
|
36
|
+
when /^const/ then 'const'
|
37
|
+
else tag[:kind]
|
38
|
+
end
|
39
|
+
if kind == 'class' && tag[:inherits]
|
40
|
+
suffix = " < #{tag[:inherits]}"
|
41
|
+
else
|
42
|
+
suffix = ''
|
43
|
+
end
|
44
|
+
|
45
|
+
puts "#{tag[:line].to_s.rjust(5)} #{kind.to_s.rjust(6)} #{tag[:full_name]}#{suffix}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
rescue Exception => e
|
49
|
+
STDERR.puts [e, file].inspect
|
50
|
+
raise e
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
if vim
|
55
|
+
puts <<-EOC
|
56
|
+
!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;" to lines/
|
57
|
+
!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/
|
58
|
+
EOC
|
59
|
+
|
60
|
+
all_tags.sort_by!{ |t| t[:name] }
|
61
|
+
all_tags.each do |tag|
|
62
|
+
kwargs = ''
|
63
|
+
kwargs << "\tclass:#{tag[:class].gsub('::','.')}" if tag[:class]
|
64
|
+
kwargs << "\tinherits:#{tag[:inherits].gsub('::','.')}" if tag[:inherits]
|
65
|
+
|
66
|
+
kind = case tag[:kind]
|
67
|
+
when 'method' then 'f'
|
68
|
+
when 'singleton method' then 'F'
|
69
|
+
when 'constant' then 'C'
|
70
|
+
else tag[:kind].slice(0,1)
|
71
|
+
end
|
72
|
+
|
73
|
+
code = tag[:pattern].gsub('\\','\\\\\\\\').gsub('/','\\/')
|
74
|
+
puts "%s\t%s\t/^%s$/;\"\t%c%s" % [tag[:name], tag[:path], code, kind, kwargs]
|
75
|
+
end
|
76
|
+
end
|
data/lib/tag_ripper.rb
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
require 'ripper'
|
2
|
+
|
3
|
+
class TagRipper < Ripper
|
4
|
+
def self.extract(data, file='(eval)')
|
5
|
+
sexp = new(data, file).parse
|
6
|
+
Visitor.new(sexp, file, data).tags
|
7
|
+
end
|
8
|
+
|
9
|
+
SCANNER_EVENTS.each do |event|
|
10
|
+
module_eval(<<-End, __FILE__, __LINE__ + 1)
|
11
|
+
def on_#{event}(tok)
|
12
|
+
[tok, lineno]
|
13
|
+
end
|
14
|
+
End
|
15
|
+
end
|
16
|
+
|
17
|
+
def on_stmts_add(first, *rest)
|
18
|
+
(first || []) + rest.compact
|
19
|
+
end
|
20
|
+
|
21
|
+
def on_module(name, body)
|
22
|
+
[:module, name, *body.compact]
|
23
|
+
end
|
24
|
+
def on_class(name, superclass, body)
|
25
|
+
superclass.flatten!(1) if superclass
|
26
|
+
[:class, name, superclass, *body.compact]
|
27
|
+
end
|
28
|
+
def on_def(method, args, body)
|
29
|
+
[:def, *method]
|
30
|
+
end
|
31
|
+
def on_defs(receiver, op, method, args, body)
|
32
|
+
receiver.flatten!(1) if receiver
|
33
|
+
[:defs, receiver && receiver[0], *method]
|
34
|
+
end
|
35
|
+
def on_alias(lhs, rhs)
|
36
|
+
[:alias, lhs[0], rhs[0], rhs[1]]
|
37
|
+
end
|
38
|
+
def on_assign(lhs, rhs)
|
39
|
+
return if lhs.nil?
|
40
|
+
return if lhs[0] == :field
|
41
|
+
return if lhs[0] == :aref_field
|
42
|
+
[:assign, *lhs.flatten(1)]
|
43
|
+
end
|
44
|
+
def on_sclass(name, body)
|
45
|
+
[:sclass, name && name.flatten(1), *body.compact]
|
46
|
+
end
|
47
|
+
def on_field(lhs, op, rhs)
|
48
|
+
[:field, lhs && lhs[0], rhs[0], rhs[1]]
|
49
|
+
end
|
50
|
+
def on_aref_field(*args)
|
51
|
+
[:aref_field, *args]
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_const_path_ref(a, b)
|
55
|
+
a.flatten!(1)
|
56
|
+
[[a && a[0], b[0]].join('::'), b[1]]
|
57
|
+
end
|
58
|
+
|
59
|
+
def on_binary(*args)
|
60
|
+
end
|
61
|
+
|
62
|
+
def on_command(name, *args)
|
63
|
+
# if name =~ /^(attr_|alias)/
|
64
|
+
# [name.to_sym, *args]
|
65
|
+
# end
|
66
|
+
end
|
67
|
+
def on_bodystmt(*args)
|
68
|
+
args
|
69
|
+
end
|
70
|
+
def on_if(condition, success, failure)
|
71
|
+
ret = [success, failure].flatten(1).compact
|
72
|
+
ret.any?? ret : nil
|
73
|
+
end
|
74
|
+
|
75
|
+
def on_unless_mod(condition, success)
|
76
|
+
nil
|
77
|
+
end
|
78
|
+
alias on_if_mod on_unless_mod
|
79
|
+
|
80
|
+
def on_var_ref(*args)
|
81
|
+
on_vcall(*args) || args
|
82
|
+
end
|
83
|
+
|
84
|
+
def on_vcall(name)
|
85
|
+
[name[0].to_sym] if name[0].to_s =~ /private|protected|public$/
|
86
|
+
end
|
87
|
+
|
88
|
+
def on_call(lhs, op, rhs)
|
89
|
+
[:call, lhs && lhs[0], rhs && rhs[0], rhs[1]]
|
90
|
+
end
|
91
|
+
|
92
|
+
def on_do_block(*args)
|
93
|
+
args
|
94
|
+
end
|
95
|
+
|
96
|
+
def on_method_add_block(method, body)
|
97
|
+
return unless method and body
|
98
|
+
if method[2] == 'class_eval'
|
99
|
+
[:class_eval, [method[1], method[3]], body.last]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class Visitor
|
104
|
+
attr_reader :tags
|
105
|
+
|
106
|
+
def initialize(sexp, path, data)
|
107
|
+
@path = path
|
108
|
+
@lines = data.split("\n")
|
109
|
+
@namespace = []
|
110
|
+
@tags = []
|
111
|
+
|
112
|
+
process(sexp)
|
113
|
+
end
|
114
|
+
|
115
|
+
def emit_tag(kind, line, opts={})
|
116
|
+
@tags << opts.merge(
|
117
|
+
:kind => kind.to_s,
|
118
|
+
:line => line,
|
119
|
+
:language => 'Ruby',
|
120
|
+
:path => @path,
|
121
|
+
:pattern => @lines[line-1].chomp,
|
122
|
+
:access => @current_access
|
123
|
+
).delete_if{ |k,v| v.nil? }
|
124
|
+
end
|
125
|
+
|
126
|
+
def process(sexp)
|
127
|
+
return unless sexp
|
128
|
+
return if Symbol === sexp
|
129
|
+
|
130
|
+
case sexp[0]
|
131
|
+
when Array
|
132
|
+
sexp.each{ |child| process(child) }
|
133
|
+
when Symbol
|
134
|
+
name, *args = sexp
|
135
|
+
__send__("on_#{name}", *args)
|
136
|
+
when String, nil
|
137
|
+
# nothing
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def on_module_or_class(kind, name, superclass, body)
|
142
|
+
name, line = *name
|
143
|
+
@namespace << name
|
144
|
+
|
145
|
+
prev_access = @current_access
|
146
|
+
@current_access = nil
|
147
|
+
|
148
|
+
if superclass
|
149
|
+
superclass_name = superclass[0] == :call ?
|
150
|
+
superclass[1] :
|
151
|
+
superclass[0]
|
152
|
+
end
|
153
|
+
full_name = @namespace.join('::')
|
154
|
+
parts = full_name.split('::')
|
155
|
+
class_name = parts.pop
|
156
|
+
|
157
|
+
emit_tag kind, line,
|
158
|
+
:full_name => full_name,
|
159
|
+
:name => class_name,
|
160
|
+
:class => parts.any? && parts.join('::') || nil,
|
161
|
+
:inherits => superclass_name
|
162
|
+
|
163
|
+
process(body)
|
164
|
+
ensure
|
165
|
+
@current_access = prev_access
|
166
|
+
@namespace.pop
|
167
|
+
end
|
168
|
+
|
169
|
+
def on_module(name, body)
|
170
|
+
on_module_or_class(:module, name, nil, body)
|
171
|
+
end
|
172
|
+
|
173
|
+
def on_class(name, superclass, body)
|
174
|
+
on_module_or_class(:class, name, superclass, body)
|
175
|
+
end
|
176
|
+
|
177
|
+
def on_private() @current_access = 'private' end
|
178
|
+
def on_protected() @current_access = 'protected' end
|
179
|
+
def on_public() @current_access = 'public' end
|
180
|
+
|
181
|
+
def on_assign(name, line)
|
182
|
+
return unless name =~ /^[A-Z]/
|
183
|
+
|
184
|
+
emit_tag :constant, line,
|
185
|
+
:name => name,
|
186
|
+
:full_name => (@namespace + [name]).join('::'),
|
187
|
+
:class => @namespace.join('::')
|
188
|
+
end
|
189
|
+
|
190
|
+
def on_alias(name, other, line)
|
191
|
+
ns = (@namespace.empty?? 'Object' : @namespace.join('::'))
|
192
|
+
|
193
|
+
emit_tag :alias, line,
|
194
|
+
:name => name,
|
195
|
+
:inherits => other,
|
196
|
+
:full_name => "#{ns}#{@is_singleton ? '.' : '#'}#{name}",
|
197
|
+
:class => ns
|
198
|
+
end
|
199
|
+
|
200
|
+
def on_def(name, line)
|
201
|
+
kind = @is_singleton ? 'singleton method' : 'method'
|
202
|
+
ns = (@namespace.empty?? 'Object' : @namespace.join('::'))
|
203
|
+
|
204
|
+
emit_tag kind, line,
|
205
|
+
:name => name,
|
206
|
+
:full_name => "#{ns}#{@is_singleton ? '.' : '#'}#{name}",
|
207
|
+
:class => ns
|
208
|
+
end
|
209
|
+
|
210
|
+
def on_defs(klass, name, line)
|
211
|
+
ns = (@namespace + [klass != 'self' ? klass : nil]).compact
|
212
|
+
emit_tag 'singleton method', line,
|
213
|
+
:name => name,
|
214
|
+
:full_name => ns.join('::') + ".#{name}",
|
215
|
+
:class => ns.join('::')
|
216
|
+
end
|
217
|
+
|
218
|
+
def on_sclass(name, body)
|
219
|
+
name, line = *name
|
220
|
+
@namespace << name unless name == 'self'
|
221
|
+
prev_is_singleton, @is_singleton = @is_singleton, true
|
222
|
+
process(body)
|
223
|
+
ensure
|
224
|
+
@namespace.pop unless name == 'self'
|
225
|
+
@is_singleton = prev_is_singleton
|
226
|
+
end
|
227
|
+
|
228
|
+
def on_class_eval(name, body)
|
229
|
+
name, line = *name
|
230
|
+
@namespace << name
|
231
|
+
process(body)
|
232
|
+
ensure
|
233
|
+
@namespace.pop
|
234
|
+
end
|
235
|
+
|
236
|
+
def on_call(*args)
|
237
|
+
end
|
238
|
+
alias on_aref_field on_call
|
239
|
+
alias on_field on_call
|
240
|
+
end
|
241
|
+
end
|
data/ripper-tags.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'ripper-tags'
|
3
|
+
s.version = '0.1.0'
|
4
|
+
|
5
|
+
s.summary = 'ctags generator for ruby code'
|
6
|
+
s.description = 'fast, accurate ctags generator for ruby source code using Ripper'
|
7
|
+
|
8
|
+
s.homepage = 'http://github.com/tmm1/ripper-tags'
|
9
|
+
s.has_rdoc = false
|
10
|
+
|
11
|
+
s.authors = ['Aman Gupta']
|
12
|
+
s.email = ['aman@tmm1.net']
|
13
|
+
|
14
|
+
s.add_dependency 'yajl-ruby'
|
15
|
+
|
16
|
+
s.require_paths = ['lib']
|
17
|
+
s.bindir = 'bin'
|
18
|
+
s.executables << 'ripper-tags'
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require File.expand_path('../../lib/tag_ripper', __FILE__)
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TagRipperTest < Test::Unit::TestCase
|
5
|
+
def test_extract_basics
|
6
|
+
tags = TagRipper.extract(<<-EOC)
|
7
|
+
Const1 = 123
|
8
|
+
def gmethod
|
9
|
+
end
|
10
|
+
module M
|
11
|
+
class C
|
12
|
+
Const2 = 456
|
13
|
+
def imethod
|
14
|
+
end
|
15
|
+
alias imethod_alias imethod
|
16
|
+
def self.cmethod
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
class M::C
|
21
|
+
def imethod2
|
22
|
+
end
|
23
|
+
def self.cmethod2
|
24
|
+
end
|
25
|
+
class << self
|
26
|
+
def cmethod3
|
27
|
+
end
|
28
|
+
alias cmethod_alias cmethod3
|
29
|
+
end
|
30
|
+
end
|
31
|
+
M::C.class_eval do
|
32
|
+
def imethod3
|
33
|
+
end
|
34
|
+
def self.cmethod4
|
35
|
+
end
|
36
|
+
end
|
37
|
+
EOC
|
38
|
+
|
39
|
+
assert_equal %w[
|
40
|
+
Const1
|
41
|
+
Object#gmethod
|
42
|
+
M
|
43
|
+
M::C
|
44
|
+
M::C::Const2
|
45
|
+
M::C#imethod
|
46
|
+
M::C#imethod_alias
|
47
|
+
M::C.cmethod
|
48
|
+
M::C
|
49
|
+
M::C#imethod2
|
50
|
+
M::C.cmethod2
|
51
|
+
M::C.cmethod3
|
52
|
+
M::C.cmethod_alias
|
53
|
+
M::C#imethod3
|
54
|
+
M::C.cmethod4
|
55
|
+
], tags.map{ |t| t[:full_name] }
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_extract_access
|
59
|
+
tags = TagRipper.extract(<<-EOC)
|
60
|
+
class Test
|
61
|
+
def abc() end
|
62
|
+
private
|
63
|
+
def def() end
|
64
|
+
protected
|
65
|
+
def ghi() end
|
66
|
+
public
|
67
|
+
def jkl() end
|
68
|
+
end
|
69
|
+
EOC
|
70
|
+
|
71
|
+
assert_equal nil, tags.find{ |t| t[:name] == 'abc' }[:access]
|
72
|
+
assert_equal 'private', tags.find{ |t| t[:name] == 'def' }[:access]
|
73
|
+
assert_equal 'protected', tags.find{ |t| t[:name] == 'ghi' }[:access]
|
74
|
+
assert_equal 'public', tags.find{ |t| t[:name] == 'jkl' }[:access]
|
75
|
+
end
|
76
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ripper-tags
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Aman Gupta
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2013-01-01 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: yajl-ruby
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
description: fast, accurate ctags generator for ruby source code using Ripper
|
35
|
+
email:
|
36
|
+
- aman@tmm1.net
|
37
|
+
executables:
|
38
|
+
- ripper-tags
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- Gemfile
|
45
|
+
- README.md
|
46
|
+
- Rakefile
|
47
|
+
- bin/ripper-tags
|
48
|
+
- lib/tag_ripper.rb
|
49
|
+
- ripper-tags.gemspec
|
50
|
+
- test/test_ripper_tags.rb
|
51
|
+
homepage: http://github.com/tmm1/ripper-tags
|
52
|
+
licenses: []
|
53
|
+
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 3
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.8.24
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: ctags generator for ruby code
|
84
|
+
test_files: []
|
85
|
+
|