starscope 1.2.0 → 1.3.0.pre.rc1

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: 63556d4e16d22bf281211c311fa2ca379b7ec631
4
- data.tar.gz: c48c940ea99cd383e0aa6f90a19b0cc2f9df6d96
3
+ metadata.gz: c09fb48ea12174fc241fc799d5eb948da2a44582
4
+ data.tar.gz: c56e8c9fc177ecc94d7dbd77b15af4a130b2c65f
5
5
  SHA512:
6
- metadata.gz: ad88485b560c0b4f56aa48c76b7b42451d1e91e9f72ff65689207db6ffc1b85cc2c84966399965f4cdf08489d9f5f771bcefda1bc2f61dd83be38f59564f3346
7
- data.tar.gz: e03b09376ac960ea2316e5436a9963af358862cebaf51bee7565607bd06b4f60c89df4e5bc5e4802345cd3f7d43f282eac321b853327de8c2ca2959b059dfb8a
6
+ metadata.gz: 715d7b4ff92b00c9a9e8feee0acd4e6a198215c66b142796a5c90f5eac7f66eafdf4890fd1314d323a62c00f1bbc65f3ad3a64d57f5942c6326952e47361b34c
7
+ data.tar.gz: ab315bcf74d0b42dc7420c8ee18a30fbc17b66a1a6e8259cfa93d19953d1a462de597fda4895ae3c10cf7bac762d27b546ac95ea2925c565aaf873d466920521
data/.travis.yml CHANGED
@@ -4,4 +4,4 @@ rvm:
4
4
  - 1.8.7
5
5
  - 1.9.3
6
6
  - 2.0.0
7
- - 2.1.1
7
+ - 2.1.5
data/CHANGELOG.md CHANGED
@@ -1,7 +1,21 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
- v1.2.0 (trunk)
4
+ v1.3.0 (trunk)
5
+ --------------------
6
+
7
+ New Features:
8
+ * Give `*` as the table name in order to query all tables at once (#58).
9
+ * Specify filters for your queries for example `lang:ruby,calls,new` (#24).
10
+ * Ruby: Recognize variables and symbols outside of assignments, available in
11
+ the new `reads` and `sym` tables (#102).
12
+ * Cscope: export 'unmarked' or generic cscope tokens, providing a much richer
13
+ integration with cscope's "find this C symbol" (#60).
14
+
15
+ Bug Fixes:
16
+ * Simplify query logic to match user expectations (#91)
17
+
18
+ v1.2.0 (2014-09-02)
5
19
  --------------------
6
20
 
7
21
  Improvements:
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- starscope (1.2.0)
4
+ starscope (1.3.0.pre.rc1)
5
+ backports (~> 3.6)
5
6
  oj (~> 2.9)
6
7
  parser (~> 2.1)
7
8
  ruby-progressbar (~> 1.5)
@@ -10,23 +11,24 @@ GEM
10
11
  remote: https://rubygems.org/
11
12
  specs:
12
13
  ast (2.0.0)
14
+ backports (3.6.4)
13
15
  coderay (1.1.0)
14
16
  metaclass (0.0.4)
15
17
  method_source (0.8.2)
16
- minitest (5.4.0)
18
+ minitest (5.5.0)
17
19
  mocha (1.1.0)
18
20
  metaclass (~> 0.0.1)
19
- oj (2.9.9)
20
- parser (2.1.9)
21
+ oj (2.11.1)
22
+ parser (2.2.0.1)
21
23
  ast (>= 1.1, < 3.0)
22
24
  slop (~> 3.4, >= 3.4.5)
23
- pry (0.10.0)
25
+ pry (0.10.1)
24
26
  coderay (~> 1.1.0)
25
27
  method_source (~> 0.8.1)
26
28
  slop (~> 3.4)
27
- rake (10.3.2)
28
- ruby-progressbar (1.5.1)
29
- slop (3.5.0)
29
+ rake (10.4.2)
30
+ ruby-progressbar (1.7.1)
31
+ slop (3.6.0)
30
32
 
31
33
  PLATFORMS
32
34
  ruby
data/README.md CHANGED
@@ -9,7 +9,7 @@ across the fantastic [Cscope](http://cscope.sourceforge.net/) tool. Sadly, it
9
9
  only works for C (and sort of works for C++).
10
10
 
11
11
  Starscope is a similar tool for [Ruby](https://www.ruby-lang.org/) and
12
- [Golang](http://golang.org/), with a design intended to make it easy to add
12
+ [Golang](https://golang.org/), with a design intended to make it easy to add
13
13
  [support for other languages](doc/LANGUAGE_SUPPORT.md) within the same framework
14
14
  (thus the name Starscope, i.e. \*scope).
15
15
 
data/bin/starscope CHANGED
@@ -92,8 +92,8 @@ END
92
92
  opts.separator <<END
93
93
  \nEXPORTING
94
94
  At the moment two export formats are supported: 'ctags' and 'cscope'. If
95
- you don't specify a path, the output is written to the file '#{Starscope::Export::CTAGS_DEFAULT_PATH}' (for
96
- ctags) or '#{Starscope::Export::CSCOPE_DEFAULT_PATH}' (for cscope) in the current directory.
95
+ you don't specify a path, the output is written to the file '#{Starscope::Exportable::CTAGS_DEFAULT_PATH}' (for
96
+ ctags) or '#{Starscope::Exportable::CSCOPE_DEFAULT_PATH}' (for cscope) in the current directory.
97
97
  END
98
98
 
99
99
  end.parse!
@@ -110,12 +110,31 @@ def format_record(db, rec)
110
110
  "#{rec[:name].join " "} -- #{rec[:file]}:#{rec[:line_no]} (#{db.line_for_record(rec).strip})"
111
111
  end
112
112
 
113
- def run_query(db, table, value)
114
- if !value
113
+ def run_query(db, query, separator)
114
+ table = nil
115
+ match = []
116
+ filters = {}
117
+ query.split(separator).each do |tok|
118
+ unless table.nil?
119
+ match << tok
120
+ next
121
+ end
122
+
123
+ k, v = tok.split(':', 2)
124
+ if v.nil?
125
+ table = tok
126
+ else
127
+ filters[k.to_sym] = v
128
+ end
129
+ end
130
+ match = match.join(separator)
131
+
132
+ if !match
115
133
  $stderr.puts "Invalid input - no query found."
116
134
  return false
117
135
  end
118
- results = db.query(table.to_sym, value)
136
+ tables = (table == '*' ? db.tables : table.to_sym)
137
+ results = db.query(tables, match, filters)
119
138
  if !results || results.empty?
120
139
  puts "No results found."
121
140
  else
@@ -164,7 +183,7 @@ end
164
183
  def export(db, param)
165
184
  format, path = param.split(',', 2)
166
185
  db.export(format.to_sym, path)
167
- rescue Starscope::Export::UnknownExportFormatError
186
+ rescue Starscope::Exportable::UnknownExportFormatError
168
187
  $stderr.puts "Unrecognized export format \"#{format}\""
169
188
  end
170
189
 
@@ -203,10 +222,7 @@ db.save(options[:db]) if options[:write] && (new_data || !db_exists)
203
222
 
204
223
  options[:export].each { |target| export(db, target) }
205
224
 
206
- if options[:query]
207
- table, query = options[:query].split(',', 2)
208
- run_query(db, table, query)
209
- end
225
+ run_query(db, options[:query], ',') if options[:query]
210
226
 
211
227
  print_summary(db) if options[:summary]
212
228
 
@@ -264,7 +280,7 @@ if options[:linemode]
264
280
  puts "Unknown command: '#{input}', try '!help'."
265
281
  end
266
282
  else
267
- success = run_query(db, cmd, param)
283
+ success = run_query(db, input, ' ')
268
284
  puts "Try '!help'." unless success
269
285
  end
270
286
  end
@@ -5,7 +5,7 @@ Already Supported
5
5
  -----------------
6
6
 
7
7
  * [Ruby](https://www.ruby-lang.org/)
8
- * [Golang](http://golang.org/)
8
+ * [Golang](https://golang.org/)
9
9
 
10
10
  How to Add Another Language
11
11
  ---------------------------
@@ -47,6 +47,7 @@ methods:
47
47
  anything you want.
48
48
  * `extract` takes a readable file handle pointing to the file, and must parse
49
49
  the file, `yield`ing records as it finds function definitions and the like.
50
+ It may also return a final hash of file-wide metadata to store.
50
51
 
51
52
  The record requirements are pretty straight-forward:
52
53
  ```ruby
@@ -60,6 +61,8 @@ belongs (basically its type). Current tables already include:
60
61
  * `assigns` for variable assignment
61
62
  * `requires` for required files in Ruby
62
63
  * `imports` for imported packages in Golang
64
+ * `reads` for reading of variables, constants etc. (e.g. use in an expression)
65
+ * `sym` for Ruby symbols
63
66
 
64
67
  Try to use pre-existing tables where possible, but feel free to add more if the
65
68
  language has some weird feature that doesn't map to any of the above. You don't
data/doc/USER_GUIDE.md CHANGED
@@ -20,7 +20,7 @@ across the fantastic [Cscope](http://cscope.sourceforge.net/) tool. Sadly, it
20
20
  only works for C (and sort of works for C++).
21
21
 
22
22
  Starscope is a similar tool for [Ruby](https://www.ruby-lang.org/) and
23
- [Golang](http://golang.org/), with a design intended to make it easy to add
23
+ [Golang](https://golang.org/), with a design intended to make it easy to add
24
24
  [support for other languages](LANGUAGE_SUPPORT.md) within the same framework
25
25
  (thus the name Starscope, i.e. \*scope).
26
26
 
@@ -110,11 +110,12 @@ Queries
110
110
  -------
111
111
 
112
112
  To query the starscope database, pass the `-q` or `--query` flag with an
113
- argument in the following format: `TABLE,QUERY`. For example, `-q calls,new`
114
- would list all callers of `new` and `-q defs,bar` would list places that define
115
- a method or class named `bar`. See the [language support
113
+ argument in the following format: `[FILTERS,]TABLE,QUERY`. For example,
114
+ `-q calls,new` would list all callers of `new` and `-q defs,bar` would list
115
+ places that define a method or class named `bar`. See the [language support
116
116
  documentation](LANGUAGE_SUPPORT.md) for a list of the most common tables, or use
117
- the `--summary` flag to list all the tables in the current database.
117
+ the `--summary` flag to list all the tables in the current database. Pass `*` as
118
+ the table name to query all tables.
118
119
 
119
120
  You can also search for scoped names such as `MyClass.new`. To do this, you must
120
121
  specify the scope with `::`, even if the language or instance you are searching
@@ -124,6 +125,11 @@ Queries using regular expressions are generally supported, and will be tried
124
125
  against both the base name and the fully-qualified name (again using `::` as the
125
126
  scope separator).
126
127
 
128
+ You can optionally filter records based on their metadata prior to the actual
129
+ query, by prefixing comma-separated `KEY:VALUE` pairs to the query string. A
130
+ common use of this is to restrict a query to files of a given language, for
131
+ example with `-q lang:ruby,calls,new`.
132
+
127
133
  Exporting
128
134
  ---------
129
135
 
@@ -148,9 +154,9 @@ Line-Mode
148
154
 
149
155
  Specifying `-l` or `--line-mode` places you into line-oriented mode, letting you
150
156
  run multiple queries without reloading the database each time. In line mode,
151
- input is normally a query of the form `TABLE QUERY`, or a special command
152
- starting with a `!`. Recognized special commands generally map to non-line-mode
153
- options:
157
+ input is normally a query of the form `[FILTERS ]TABLE QUERY`, or a special
158
+ command starting with a `!`. Recognized special commands generally map to
159
+ non-line-mode options:
154
160
  * `!dump [TABLE]` - same as the `--dump` flag
155
161
  * `!export FORMAT[,PATH]` - same as the `--export` flag
156
162
  * `!summary` - same as the `--summary` flag
data/lib/starscope/db.rb CHANGED
@@ -1,26 +1,28 @@
1
+ require 'backports'
1
2
  require 'date'
2
3
  require 'oj'
3
4
  require 'set'
4
5
  require 'zlib'
5
6
 
6
- require 'starscope/export'
7
- require 'starscope/matcher'
7
+ require 'starscope/exportable'
8
+ require 'starscope/queryable'
8
9
  require 'starscope/output'
9
10
 
10
11
  # dynamically load all our language extractors
11
12
  LANGS = {}
12
13
  EXTRACTORS = []
13
- Dir.glob("#{File.dirname(__FILE__)}/langs/*.rb").each do |path|
14
- require path
15
- lang = /(\w+)\.rb$/.match(path)[1].capitalize
16
- mod_name = "Starscope::Lang::#{lang}"
17
- EXTRACTORS << eval(mod_name)
18
- LANGS[lang.to_sym] = eval("#{mod_name}::VERSION")
14
+ Dir.glob("#{File.dirname(__FILE__)}/langs/*.rb").each { |path| require path }
15
+
16
+ Starscope::Lang.constants.each do |lang|
17
+ extractor = Starscope::Lang.const_get(lang)
18
+ EXTRACTORS << extractor
19
+ LANGS[lang.to_sym] = extractor.const_get(:VERSION)
19
20
  end
20
21
 
21
22
  class Starscope::DB
22
23
 
23
- include Starscope::Export
24
+ include Starscope::Exportable
25
+ include Starscope::Queryable
24
26
 
25
27
  DB_FORMAT = 5
26
28
 
@@ -105,12 +107,6 @@ class Starscope::DB
105
107
  true
106
108
  end
107
109
 
108
- def query(table, value)
109
- raise NoTableError if not @tables[table]
110
- input = @tables[table]
111
- Starscope::Matcher.new(value, input).query()
112
- end
113
-
114
110
  def line_for_record(rec)
115
111
  return rec[:line] if rec[:line]
116
112
 
@@ -242,27 +238,45 @@ class Starscope::DB
242
238
  @meta[:files][file] = {:last_updated => File.mtime(file).to_i}
243
239
 
244
240
  EXTRACTORS.each do |extractor|
245
- next if not extractor.match_file file
246
-
247
- lines = nil
248
- line_cache = nil
249
- extractor.extract file do |tbl, name, args|
250
- @tables[tbl] ||= []
251
- @tables[tbl] << self.class.normalize_record(file, name, args)
252
-
253
- if args[:line_no]
254
- line_cache ||= File.readlines(file)
255
- lines ||= Array.new(line_cache.length)
256
- lines[args[:line_no]-1] = line_cache[args[:line_no]-1].chomp
257
- end
241
+ begin
242
+ next unless extractor.match_file file
243
+ rescue => e
244
+ @output.normal("#{extractor} raised #{e} while matching #{file}")
245
+ next
258
246
  end
259
247
 
260
- @meta[:files][file][:lang] = extractor.name.split('::').last.to_sym
261
- @meta[:files][file][:lines] = lines
248
+ extract_file(extractor, file)
249
+
262
250
  return
263
251
  end
264
252
  end
265
253
 
254
+ def extract_file(extractor, file)
255
+ lines = nil
256
+ line_cache = nil
257
+
258
+ extractor_metadata = extractor.extract(file) do |tbl, name, args|
259
+ @tables[tbl] ||= []
260
+ @tables[tbl] << self.class.normalize_record(file, name, args)
261
+
262
+ if args[:line_no]
263
+ line_cache ||= File.readlines(file)
264
+ lines ||= Array.new(line_cache.length)
265
+ lines[args[:line_no]-1] = line_cache[args[:line_no]-1].chomp
266
+ end
267
+ end
268
+
269
+ @meta[:files][file][:lang] = extractor.name.split('::').last.to_sym
270
+ @meta[:files][file][:lines] = lines
271
+
272
+ if extractor_metadata.is_a? Hash
273
+ @meta[:files][file] = extractor_metadata.merge!(@meta[:files][file])
274
+ end
275
+
276
+ rescue => e
277
+ @output.normal("#{extractor} raised #{e} while extracting #{file}")
278
+ end
279
+
266
280
  def file_changed(name)
267
281
  file_meta = @meta[:files][name]
268
282
  if !File.exists?(name) || !File.file?(name)
@@ -1,4 +1,4 @@
1
- module Starscope::Export
1
+ module Starscope::Exportable
2
2
 
3
3
  CTAGS_DEFAULT_PATH='tags'
4
4
  CSCOPE_DEFAULT_PATH='cscope.out'
@@ -95,11 +95,7 @@ END
95
95
  end
96
96
  end
97
97
 
98
- buf << CSCOPE_GLOBAL_HACK_STOP if record[:type] == :func && record[:tbl] == :defs
99
- buf << cscope_plaintext(line, prev, offset) << "\n"
100
- buf << cscope_mark(record[:tbl], record) << record[:key] << "\n"
101
- buf << CSCOPE_GLOBAL_HACK_START if record[:type] == :func && record[:tbl] == :end
102
-
98
+ buf << cscope_output(line, prev, offset, record)
103
99
  prev = offset + record[:key].length
104
100
 
105
101
  end
@@ -151,7 +147,7 @@ END
151
147
  # keep scanning if our current index doesn't actually match the key, or if
152
148
  # either the preceeding or succeeding character is a word character
153
149
  # (meaning we've accidentally matched the middle of some other token)
154
- while !index.nil? &&
150
+ while index &&
155
151
  ((line[index, key.length] != key) ||
156
152
  (index > 0 && line[index-1] =~ /\w/) ||
157
153
  (index+key.length < line.length && line[index+key.length] =~ /\w/))
@@ -176,6 +172,37 @@ END
176
172
  return toks.sort
177
173
  end
178
174
 
175
+ def cscope_output(line, prev, offset, record)
176
+ buf = ""
177
+ buf << CSCOPE_GLOBAL_HACK_STOP if record[:type] == :func && record[:tbl] == :defs
178
+
179
+ tokens = record[:name][0...-1].map {|x| x.to_s.sub(/\W+$/, '')}.select {|x| !x.empty?}.join("|")
180
+ if !tokens.empty?
181
+ # output previous components of the name (ie the Foo in Foo::bar) as unmarked symbols
182
+ rxp = Regexp.new("\\W(#{tokens})\\W")
183
+ index = line.index(rxp, prev)
184
+
185
+ while index
186
+ tok = rxp.match(line[index..-1])[1]
187
+ index += 1
188
+ break if index+tok.length > offset
189
+ buf << cscope_plaintext(line, prev, index) << "\n"
190
+ buf << "#{tok}\n"
191
+ prev = index + tok.length
192
+ index = line.index(rxp, prev)
193
+ end
194
+ end
195
+
196
+ buf << cscope_plaintext(line, prev, offset) << "\n"
197
+ buf << cscope_mark(record) << record[:key] << "\n"
198
+
199
+ buf << CSCOPE_GLOBAL_HACK_START if record[:type] == :func && record[:tbl] == :end
200
+ buf
201
+ rescue ArgumentError
202
+ # invalid utf-8 byte sequence in the line, oh well
203
+ line
204
+ end
205
+
179
206
  def cscope_plaintext(line, start, stop)
180
207
  ret = line.slice(start, stop-start)
181
208
  ret.lstrip! if start == 0
@@ -186,8 +213,8 @@ END
186
213
  line
187
214
  end
188
215
 
189
- def cscope_mark(tbl, rec)
190
- case tbl
216
+ def cscope_mark(rec)
217
+ case rec[:tbl]
191
218
  when :end
192
219
  case rec[:type]
193
220
  when :func
@@ -8,20 +8,14 @@ module Starscope::Lang
8
8
  return true if name.end_with?(".rb")
9
9
  File.open(name) do |f|
10
10
  head = f.read(2)
11
- return false if head.nil? or not head.start_with?("#!")
11
+ return false if head.nil? || !head.start_with?("#!")
12
12
  return f.readline.include?("ruby")
13
13
  end
14
- rescue ArgumentError # may occur if file is binary (invalid UTF)
15
- false
16
14
  end
17
15
 
18
16
  def self.extract(file, &block)
19
- begin
20
- ast = Parser::CurrentRuby.parse_file(file)
21
- rescue
22
- else
23
- extract_tree(ast, [], &block) if not ast.nil?
24
- end
17
+ ast = Parser::CurrentRuby.parse_file(file)
18
+ extract_tree(ast, [], &block) unless ast.nil?
25
19
  end
26
20
 
27
21
  private
@@ -72,12 +66,22 @@ module Starscope::Lang
72
66
  yield :end, :end, :line_no => loc.end.line, :type => node.type, :col => loc.end.column
73
67
 
74
68
  when :casgn
75
- fqn = scoped_name(node, scope)
76
- yield :assigns, fqn, :line_no => loc.line, :col => loc.name.column
77
- yield :defs, fqn, :line_no => loc.line, :col => loc.name.column
69
+ name = scoped_name(node, scope)
70
+ yield :assigns, name, :line_no => loc.line, :col => loc.name.column
71
+ yield :defs, name, :line_no => loc.line, :col => loc.name.column
78
72
 
79
73
  when :lvasgn, :ivasgn, :cvasgn, :gvasgn
80
74
  yield :assigns, scope + [node.children[0]], :line_no => loc.line, :col => loc.name.column
75
+
76
+ when :const
77
+ name = scoped_name(node, scope)
78
+ yield :reads, name, :line_no => loc.line, :col => loc.name.column
79
+
80
+ when :lvar, :ivar, :cvar, :gvar
81
+ yield :reads, scope + [node.children[0]], :line_no => loc.line, :col => loc.expression.column
82
+
83
+ when :sym
84
+ yield :sym, [node.children[0]], :line_no => loc.line, :col => loc.expression.column
81
85
  end
82
86
  end
83
87
 
@@ -1,44 +1,24 @@
1
- class Starscope::Matcher
1
+ module Starscope
2
+ class Matcher
3
+ MATCH_TYPES = [:literal_match, :regexp_match]
2
4
 
3
- MATCH_TYPES = [:full_match, :simple_match, :simple_regexp, :full_regexp]
5
+ def initialize(query)
6
+ @query = query
4
7
 
5
- def initialize(query, input)
6
- @query = query
7
- @input = input
8
- @regexp = Regexp.new(query, Regexp::IGNORECASE)
9
- rescue RegexpError
10
- # not a regex, oh well
11
- end
12
-
13
- def match(record)
14
- name = record[:name].map {|x| x.to_s}
15
- fullname = name.join('::')
16
-
17
- case
18
- when fullname == @query
19
- :full_match
20
- when name[-1] == @query
21
- :simple_match
22
- when @regexp
23
- if @regexp.match(name[-1])
24
- :simple_regexp
25
- elsif @regexp.match(fullname)
26
- :full_regexp
8
+ begin
9
+ @regexp = Regexp.new(@query, Regexp::IGNORECASE)
10
+ rescue RegexpError
11
+ # not a regex, oh well
27
12
  end
28
13
  end
29
- end
30
-
31
- def query
32
- return [] if @input.empty?
33
14
 
34
- results = @input.group_by {|x| match(x)}
35
-
36
- MATCH_TYPES.each do |type|
37
- next if results[type].nil? or results[type].empty?
38
- return results[type]
39
- end
40
-
41
- return []
15
+ def match(input)
16
+ case
17
+ when input.end_with?(@query)
18
+ :literal_match
19
+ when @regexp && @regexp.match(input)
20
+ :regexp_match
21
+ end
22
+ end
42
23
  end
43
-
44
24
  end
@@ -0,0 +1,47 @@
1
+ require 'starscope/matcher'
2
+
3
+ module Starscope::Queryable
4
+
5
+ def query(tables, value, filters={})
6
+ tables = [tables] if tables.is_a?(Symbol)
7
+ tables.each { |t| raise NoTableError, "Table '#{t}' not found" unless @tables[t] }
8
+ input = Enumerator.new do |y|
9
+ tables.each do |t|
10
+ @tables[t].each do |elem|
11
+ y << elem
12
+ end
13
+ end
14
+ end
15
+
16
+ run_query(value, input, filters)
17
+ end
18
+
19
+ private
20
+
21
+ def run_query(query, input, filters)
22
+ query = Starscope::Matcher.new(query)
23
+ filters.each {|k,v| filters[k] = Starscope::Matcher.new(v)}
24
+
25
+ results = input.select {|x| filter(x, filters)}.group_by {|x| match(x, query)}
26
+
27
+ Starscope::Matcher::MATCH_TYPES.each do |type|
28
+ next if results[type].nil? || results[type].empty?
29
+ return results[type]
30
+ end
31
+
32
+ []
33
+ end
34
+
35
+ def filter(record, filters)
36
+ filters.all? do |key, filter|
37
+ target = record[key] || (@meta[:files][record[:file]] || {})[key]
38
+ target && filter.match(target.to_s)
39
+ end
40
+ end
41
+
42
+ def match(record, query)
43
+ name = record[:name].map {|x| x.to_s}.join('::')
44
+
45
+ query.match(name)
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module Starscope
2
- VERSION = "1.2.0"
2
+ VERSION = "1.3.0-rc1"
3
3
  end
data/starscope.gemspec CHANGED
@@ -18,6 +18,7 @@ Gem::Specification.new do |gem|
18
18
  gem.add_dependency 'oj', '~> 2.9'
19
19
  gem.add_dependency 'parser', '~> 2.1'
20
20
  gem.add_dependency 'ruby-progressbar', '~> 1.5'
21
+ gem.add_dependency 'backports', '~> 3.6'
21
22
  gem.add_development_dependency 'bundler', '~> 1.5'
22
23
  gem.add_development_dependency 'rake'
23
24
  gem.add_development_dependency 'pry'
@@ -17,7 +17,7 @@ describe "starscope executable script" do
17
17
 
18
18
  it "must produce a valid database summary" do
19
19
  lines = `#{EXTRACT} -s`.lines.to_a
20
- lines.length.must_equal 6
20
+ lines.length.must_equal 8
21
21
  end
22
22
 
23
23
  it "must produce a valid database dump" do
@@ -30,6 +30,14 @@ describe "starscope executable script" do
30
30
  `#{EXTRACT} -q calls,add_file`.each_line do |line|
31
31
  line.split[0..2].must_equal ["Starscope", "DB", "add_file"]
32
32
  end
33
+
34
+ `#{EXTRACT} -q lang:ruby,calls,add_file`.each_line do |line|
35
+ line.split[0..2].must_equal ["Starscope", "DB", "add_file"]
36
+ end
37
+
38
+ `#{EXTRACT} -q lang:go,calls,add_file`.each_line do |line|
39
+ line.must_equal "No results found.\n"
40
+ end
33
41
  end
34
42
 
35
43
  it "must correctly export to cscope" do
@@ -43,7 +51,7 @@ describe "starscope executable script" do
43
51
  end
44
52
  end
45
53
 
46
- it "Must correctly export to ctags" do
54
+ it "must correctly export to ctags" do
47
55
  file = Tempfile.new('starscope_test')
48
56
  begin
49
57
  `#{EXTRACT} -e ctags,#{file.path()}`
data/test/unit/db_test.rb CHANGED
@@ -113,6 +113,13 @@ describe Starscope::DB do
113
113
  @db.query(:calls, "add_file").length.must_equal 3
114
114
  end
115
115
 
116
+ it "must run queries on multiple tables" do
117
+ @db.add_paths([FIXTURES])
118
+ ret = @db.query([:calls, :defs], "foo")
119
+ ret.length.must_equal 1
120
+ ret.first[:name].last.must_equal :foo
121
+ end
122
+
116
123
  it "must symbolize compound name" do
117
124
  rec = Starscope::DB.normalize_record(:foo, ["a", :b], {})
118
125
  rec[:name].must_equal [:a, :b]
@@ -123,6 +130,18 @@ describe Starscope::DB do
123
130
  rec[:name].must_equal [:a]
124
131
  end
125
132
 
133
+ it "must store extractor metadata returned from the `extract` call" do
134
+ extractor = mock('extractor')
135
+ extractor.expects(:match_file).with(GOLANG_SAMPLE).returns(true)
136
+ extractor.expects(:extract).with(GOLANG_SAMPLE).returns({:a => 1})
137
+ extractor.expects(:name).returns('Foo')
138
+ EXTRACTORS.stubs(:each).yields(extractor)
139
+
140
+ @db.add_paths([GOLANG_SAMPLE])
141
+
142
+ @db.metadata(:files)[GOLANG_SAMPLE][:a].must_equal 1
143
+ end
144
+
126
145
  private
127
146
 
128
147
  def validate(db)
@@ -1,6 +1,6 @@
1
1
  require File.expand_path('../../test_helper', __FILE__)
2
2
 
3
- describe Starscope::Export do
3
+ describe Starscope::Exportable do
4
4
 
5
5
  before do
6
6
  @db = Starscope::DB.new(Starscope::Output.new(:quiet))
@@ -0,0 +1,62 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ describe Starscope::Queryable do
4
+
5
+ SAMPLE_RECORDS = [
6
+ {:name => [:"[abc"], :foo => "baz"},
7
+ {:name => [:"not a match"], :foo => "bar", :x => "y"},
8
+ {:name => [:a, :b, :c, :d], :file => :somefile},
9
+ ]
10
+
11
+ class MockQuerable
12
+ include Starscope::Queryable
13
+ def initialize
14
+ @tables = {
15
+ :mytable => SAMPLE_RECORDS,
16
+ :empty_table => []
17
+ }
18
+ @meta = {
19
+ :files => {
20
+ :somefile => {
21
+ :lang => :ruby
22
+ }
23
+ }
24
+ }
25
+ end
26
+ end
27
+
28
+ before do
29
+ @mock = MockQuerable.new
30
+ end
31
+
32
+ it "must handle empty input" do
33
+ @mock.query(:empty_table, "foo").must_be_empty
34
+ end
35
+
36
+ it "must handle scoped queries" do
37
+ @mock.query(:mytable, "a::b::").must_equal [SAMPLE_RECORDS[2]]
38
+ end
39
+
40
+ it "must handle regex queries" do
41
+ @mock.query(:mytable, "a[bc]{2}").must_equal [SAMPLE_RECORDS[0]]
42
+
43
+ @mock.query(:mytable, "a.*d").must_equal [SAMPLE_RECORDS[2]]
44
+ end
45
+
46
+ it "must handle malformed regexes" do
47
+ @mock.query(:mytable, "[abc").must_equal [SAMPLE_RECORDS[0]]
48
+ end
49
+
50
+ it "must handle simple filters" do
51
+ @mock.query(:mytable, ".*", :foo => "bar").must_equal [SAMPLE_RECORDS[1]]
52
+ end
53
+
54
+ it "must handle multiple filters" do
55
+ @mock.query(:mytable, ".*", :foo => "bar", :x => "y").must_equal [SAMPLE_RECORDS[1]]
56
+ @mock.query(:mytable, ".*", :foo => "bar", :x => "nope").must_be_empty
57
+ end
58
+
59
+ it "must handle filters on file properties" do
60
+ @mock.query(:mytable, ".*", :lang => "ruby").must_equal [SAMPLE_RECORDS[2]]
61
+ end
62
+ end
metadata CHANGED
@@ -1,125 +1,139 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: starscope
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0.pre.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Huus
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-02 00:00:00.000000000 Z
11
+ date: 2015-01-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2.9'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.9'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: parser
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '2.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: ruby-progressbar
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.5'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: backports
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.6'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.6'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - ~>
73
+ - - "~>"
60
74
  - !ruby/object:Gem::Version
61
75
  version: '1.5'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - ~>
80
+ - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '1.5'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - '>='
87
+ - - ">="
74
88
  - !ruby/object:Gem::Version
75
89
  version: '0'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - '>='
94
+ - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: pry
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
- - - '>='
101
+ - - ">="
88
102
  - !ruby/object:Gem::Version
89
103
  version: '0'
90
104
  type: :development
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
- - - '>='
108
+ - - ">="
95
109
  - !ruby/object:Gem::Version
96
110
  version: '0'
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: minitest
99
113
  requirement: !ruby/object:Gem::Requirement
100
114
  requirements:
101
- - - '>='
115
+ - - ">="
102
116
  - !ruby/object:Gem::Version
103
117
  version: '0'
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
- - - '>='
122
+ - - ">="
109
123
  - !ruby/object:Gem::Version
110
124
  version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: mocha
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
- - - '>='
129
+ - - ">="
116
130
  - !ruby/object:Gem::Version
117
131
  version: '0'
118
132
  type: :development
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
- - - '>='
136
+ - - ">="
123
137
  - !ruby/object:Gem::Version
124
138
  version: '0'
125
139
  description: A tool like the venerable cscope, but for ruby, golang and other languages
@@ -129,8 +143,8 @@ executables:
129
143
  extensions: []
130
144
  extra_rdoc_files: []
131
145
  files:
132
- - .gitignore
133
- - .travis.yml
146
+ - ".gitignore"
147
+ - ".travis.yml"
134
148
  - CHANGELOG.md
135
149
  - Gemfile
136
150
  - Gemfile.lock
@@ -143,12 +157,13 @@ files:
143
157
  - doc/USER_GUIDE.md
144
158
  - lib/starscope.rb
145
159
  - lib/starscope/db.rb
146
- - lib/starscope/export.rb
160
+ - lib/starscope/exportable.rb
147
161
  - lib/starscope/langs/coffeescript.rb
148
162
  - lib/starscope/langs/go.rb
149
163
  - lib/starscope/langs/ruby.rb
150
164
  - lib/starscope/matcher.rb
151
165
  - lib/starscope/output.rb
166
+ - lib/starscope/queryable.rb
152
167
  - lib/starscope/version.rb
153
168
  - starscope.gemspec
154
169
  - test/fixtures/db_added_files.json
@@ -163,11 +178,11 @@ files:
163
178
  - test/functional/starscope_test.rb
164
179
  - test/test_helper.rb
165
180
  - test/unit/db_test.rb
166
- - test/unit/export_test.rb
181
+ - test/unit/exportable_test.rb
167
182
  - test/unit/langs/golang_test.rb
168
183
  - test/unit/langs/ruby_test.rb
169
- - test/unit/matcher_test.rb
170
184
  - test/unit/output_test.rb
185
+ - test/unit/queryable_test.rb
171
186
  homepage: https://github.com/eapache/starscope
172
187
  licenses:
173
188
  - MIT
@@ -178,17 +193,17 @@ require_paths:
178
193
  - lib
179
194
  required_ruby_version: !ruby/object:Gem::Requirement
180
195
  requirements:
181
- - - '>='
196
+ - - ">="
182
197
  - !ruby/object:Gem::Version
183
198
  version: 1.8.7
184
199
  required_rubygems_version: !ruby/object:Gem::Requirement
185
200
  requirements:
186
- - - '>='
201
+ - - ">"
187
202
  - !ruby/object:Gem::Version
188
- version: '0'
203
+ version: 1.3.1
189
204
  requirements: []
190
205
  rubyforge_project:
191
- rubygems_version: 2.0.14
206
+ rubygems_version: 2.2.2
192
207
  signing_key:
193
208
  specification_version: 4
194
209
  summary: A code indexer and analyzer
@@ -205,8 +220,8 @@ test_files:
205
220
  - test/functional/starscope_test.rb
206
221
  - test/test_helper.rb
207
222
  - test/unit/db_test.rb
208
- - test/unit/export_test.rb
223
+ - test/unit/exportable_test.rb
209
224
  - test/unit/langs/golang_test.rb
210
225
  - test/unit/langs/ruby_test.rb
211
- - test/unit/matcher_test.rb
212
226
  - test/unit/output_test.rb
227
+ - test/unit/queryable_test.rb
@@ -1,34 +0,0 @@
1
- require File.expand_path('../../test_helper', __FILE__)
2
-
3
- describe Starscope::Matcher do
4
-
5
- SAMPLE_RECORDS = [
6
- {:name => [:"[abc"]},
7
- {:name => [:"not a match"]},
8
- {:name => [:a, :b, :c, :d]},
9
- ]
10
-
11
- it "must handle empty input" do
12
- matcher = Starscope::Matcher.new("foo", [])
13
- matcher.query.must_be_empty
14
- end
15
-
16
- it "must handle scoped queries" do
17
- matcher = Starscope::Matcher.new("a::b::", SAMPLE_RECORDS)
18
- matcher.query.must_equal [SAMPLE_RECORDS[2]]
19
- end
20
-
21
- it "must handle regex queries" do
22
- matcher = Starscope::Matcher.new("a[bc]{2}", SAMPLE_RECORDS)
23
- matcher.query.must_equal [SAMPLE_RECORDS[0]]
24
-
25
- matcher = Starscope::Matcher.new("a.*d", SAMPLE_RECORDS)
26
- matcher.query.must_equal [SAMPLE_RECORDS[2]]
27
- end
28
-
29
- it "must handle malformed regexes" do
30
- matcher = Starscope::Matcher.new("[abc", SAMPLE_RECORDS)
31
- matcher.query.must_equal [SAMPLE_RECORDS[0]]
32
- end
33
-
34
- end