starscope 1.3.3 → 1.4.0

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: 9fb073a356694d459d2c8f52e8dd1f7b81d22103
4
- data.tar.gz: bddae56a6b270f28bd0135e355a09f5b14c16923
3
+ metadata.gz: 0034f945269abf5a562e9ac393621ef5ab6dfed0
4
+ data.tar.gz: 772a237027e861ea5a76c3e87a891fe9cc45b825
5
5
  SHA512:
6
- metadata.gz: fbe36b2c5a96dc14475b41e29d7de9344b4ea1183369a75002ecbe1e8f7bac9e37ffe8f01a108527304426fde4281a3ab8d520b750e80c5dfdc6c969475e1b1f
7
- data.tar.gz: 0a79e14ddd7de65dba9fe6246e8da1f6da1f2b5ff7f93e59f0ed4a5f9741e9d53d5c771a3b20e5870836bc7358dba6ad87e82cb9c1e2b4b55bf7b1a6c9fcc268
6
+ metadata.gz: 68a111fe637ba4a2e0307f04d5fec574bf3fca41ad9eee91cba1f1fe07cdaa36cc18ed953a29702a0dff4c4435cdb45b8b4a0ff06a1a39702aa8136bb9b04c27
7
+ data.tar.gz: fb56e7e538076c94866cd6d10b427919ed91ec50fba6f4d3692b30bbcd1e56eee004f4caba8eb64c832d8e490f67faaae3b9d3498fb951fbdb2613d662ff1327
@@ -0,0 +1,29 @@
1
+ Lint/UnusedBlockArgument:
2
+ Enabled: false
3
+
4
+ Lint/UnusedMethodArgument:
5
+ Enabled: false
6
+
7
+ Style/HashSyntax:
8
+ EnforcedStyle: hash_rockets
9
+
10
+ Metrics/AbcSize:
11
+ Enabled: false
12
+
13
+ Metrics/ClassLength:
14
+ Enabled: false
15
+
16
+ Metrics/CyclomaticComplexity:
17
+ Enabled: false
18
+
19
+ Metrics/LineLength:
20
+ Enabled: false
21
+
22
+ Metrics/MethodLength:
23
+ Enabled: false
24
+
25
+ Metrics/PerceivedComplexity:
26
+ Enabled: false
27
+
28
+ Style/Documentation:
29
+ Enabled: false
@@ -1,7 +1,21 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
- v1.3.3 (trunk)
4
+ v1.4.0 (trunk)
5
+ --------------------
6
+
7
+ New Features:
8
+ * Implement support for files with multiple nested languages (#61).
9
+ * Implement support for extracting ruby inside ERB files (#120).
10
+
11
+ Bug Fixes:
12
+ * Correctly handle the removal of language extractors (#122).
13
+
14
+ Misc:
15
+ * Preliminary use of Rubocop for more consistent code style.
16
+ * Document the fact that `!` can't be used at the beginning of table names.
17
+
18
+ v1.3.3 (2015-03-07)
5
19
  --------------------
6
20
 
7
21
  Bug Fixes:
@@ -1,10 +1,10 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- starscope (1.3.3)
4
+ starscope (1.4.0)
5
5
  backports (~> 3.6)
6
6
  oj (~> 2.9)
7
- parser (~> 2.2.0.3)
7
+ parser (~> 2.2.2)
8
8
  ruby-progressbar (~> 1.5)
9
9
 
10
10
  GEM
@@ -15,18 +15,18 @@ GEM
15
15
  coderay (1.1.0)
16
16
  metaclass (0.0.4)
17
17
  method_source (0.8.2)
18
- minitest (5.5.1)
18
+ minitest (5.7.0)
19
19
  mocha (1.1.0)
20
20
  metaclass (~> 0.0.1)
21
- oj (2.11.4)
22
- parser (2.2.0.3)
21
+ oj (2.12.9)
22
+ parser (2.2.2.5)
23
23
  ast (>= 1.1, < 3.0)
24
24
  pry (0.10.1)
25
25
  coderay (~> 1.1.0)
26
26
  method_source (~> 0.8.1)
27
27
  slop (~> 3.4)
28
28
  rake (10.4.2)
29
- ruby-progressbar (1.7.1)
29
+ ruby-progressbar (1.7.5)
30
30
  slop (3.6.0)
31
31
 
32
32
  PLATFORMS
data/README.md CHANGED
@@ -3,6 +3,7 @@ Starscope
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/starscope.svg)](http://badge.fury.io/rb/starscope)
5
5
  [![Build Status](https://travis-ci.org/eapache/starscope.svg?branch=master)](https://travis-ci.org/eapache/starscope)
6
+ [![Code of Conduct](https://img.shields.io/badge/code%20of%20conduct-active-blue.svg)](https://eapache.github.io/conduct.html)
6
7
 
7
8
  Anyone who has done much programming in C (or C++) on a Unix-based OS has come
8
9
  across the fantastic [Cscope](http://cscope.sourceforge.net/) tool. Sadly, it
@@ -46,5 +47,7 @@ More Documentation
46
47
  Other Uses
47
48
  ----------
48
49
 
49
- Starscope is a supported backend for
50
+ - Starscope is a supported backend for
50
51
  [CodeQuery](https://github.com/ruben2020/codequery).
52
+ - Starscope has been [packaged for Arch
53
+ Linux](https://aur.archlinux.org/packages/ruby-starscope/).
@@ -7,14 +7,14 @@ require 'optparse'
7
7
  require 'readline'
8
8
  require 'starscope'
9
9
 
10
- DEFAULT_DB='.starscope.db'
11
-
12
- options = {:read => true,
13
- :write => true,
14
- :update => true,
15
- :output => :normal,
16
- :export => [],
17
- :db => DEFAULT_DB,
10
+ DEFAULT_DB = '.starscope.db'
11
+
12
+ options = { :read => true,
13
+ :write => true,
14
+ :update => true,
15
+ :output => :normal,
16
+ :export => [],
17
+ :db => DEFAULT_DB
18
18
  }
19
19
 
20
20
  # Options Parsing
@@ -35,53 +35,53 @@ User Manual: https://github.com/eapache/starscope/blob/master/doc/USER_GUIDE.md
35
35
  END
36
36
 
37
37
  opts.separator "\nQueries"
38
- opts.on("-d", "--dump [TABLE]", "Dumps the DB or specified table to stdout") do |tbl|
38
+ opts.on('-d', '--dump [TABLE]', 'Dumps the DB or specified table to stdout') do |tbl|
39
39
  options[:dump] = tbl || true
40
40
  end
41
- opts.on("-l", "--line-mode", "Starts line-oriented interface") do
41
+ opts.on('-l', '--line-mode', 'Starts line-oriented interface') do
42
42
  options[:linemode] = true
43
43
  end
44
- opts.on("-q", "--query TABLE,QUERY", "Looks up QUERY in TABLE") do |query|
44
+ opts.on('-q', '--query TABLE,QUERY', 'Looks up QUERY in TABLE') do |query|
45
45
  options[:query] = query
46
46
  end
47
- opts.on("-s", "--summary", "Print a database summary to stdout") do
47
+ opts.on('-s', '--summary', 'Print a database summary to stdout') do
48
48
  options[:summary] = true
49
49
  end
50
50
 
51
51
  opts.separator "\nDatabase Management"
52
- opts.on("-e", "--export FORMAT[,PATH]", "Export in FORMAT to PATH, (see EXPORTING)") do |export|
52
+ opts.on('-e', '--export FORMAT[,PATH]', 'Export in FORMAT to PATH, (see EXPORTING)') do |export|
53
53
  options[:export] << export
54
54
  end
55
- opts.on("-f", "--file FILE", "Use FILE instead of `#{DEFAULT_DB}`") do |path|
55
+ opts.on('-f', '--file FILE', "Use FILE instead of `#{DEFAULT_DB}`") do |path|
56
56
  options[:db] = path
57
57
  end
58
- opts.on("-x", "--exclude PATTERN", "Skip files matching PATTERN") do |pattern|
58
+ opts.on('-x', '--exclude PATTERN', 'Skip files matching PATTERN') do |pattern|
59
59
  options[:exclude] ||= []
60
60
  options[:exclude] << pattern
61
61
  end
62
- opts.on("--no-read", "Don't read the DB from a file") do
62
+ opts.on('--no-read', "Don't read the DB from a file") do
63
63
  options[:read] = false
64
64
  end
65
- opts.on("--no-write", "Don't write the DB to a file") do
65
+ opts.on('--no-write', "Don't write the DB to a file") do
66
66
  options[:write] = false
67
67
  end
68
- opts.on("--no-update", "Don't update the DB") do
68
+ opts.on('--no-update', "Don't update the DB") do
69
69
  options[:update] = false
70
70
  end
71
71
 
72
72
  opts.separator "\nMisc"
73
- opts.on("-v", "--version", "Print the version number") do
73
+ opts.on('-v', '--version', 'Print the version number') do
74
74
  puts Starscope::VERSION
75
75
  exit
76
76
  end
77
- opts.on("--verbose", "Print extra status messages") do
77
+ opts.on('--verbose', 'Print extra status messages') do
78
78
  if options[:output] == :quiet
79
79
  $stderr.puts "Can't be both verbose and quiet"
80
80
  exit(1)
81
81
  end
82
82
  options[:output] = :verbose
83
83
  end
84
- opts.on("--quiet", "Print fewer messages") do
84
+ opts.on('--quiet', 'Print fewer messages') do
85
85
  if options[:output] == :verbose
86
86
  $stderr.puts "Can't be both verbose and quiet"
87
87
  exit(1)
@@ -95,19 +95,18 @@ END
95
95
  you don't specify a path, the output is written to the file '#{Starscope::Exportable::CTAGS_DEFAULT_PATH}' (for
96
96
  ctags) or '#{Starscope::Exportable::CSCOPE_DEFAULT_PATH}' (for cscope) in the current directory.
97
97
  END
98
-
99
98
  end.parse!
100
99
 
101
100
  def print_summary(db)
102
101
  tables = db.tables
103
- puts "No tables" if tables.empty?
104
- tables.sort {|a,b| a.to_s <=> b.to_s}.each do |table|
102
+ puts 'No tables' if tables.empty?
103
+ tables.sort { |a, b| a.to_s <=> b.to_s }.each do |table|
105
104
  printf("%-9s %6d records\n", table, db.records(table).length)
106
105
  end
107
106
  end
108
107
 
109
108
  def format_record(db, rec)
110
- "#{rec[:name].join " "} -- #{rec[:file]}:#{rec[:line_no]} (#{db.line_for_record(rec).strip})"
109
+ "#{rec[:name].join ' '} -- #{rec[:file]}:#{rec[:line_no]} (#{db.line_for_record(rec).strip})"
111
110
  end
112
111
 
113
112
  def run_query(db, query, separator)
@@ -130,15 +129,15 @@ def run_query(db, query, separator)
130
129
  match = match.join(separator)
131
130
 
132
131
  if match.empty?
133
- $stderr.puts "Invalid input - no query found."
132
+ $stderr.puts 'Invalid input - no query found.'
134
133
  return false
135
134
  end
136
135
  tables = (table == '*' ? db.tables : table.to_sym)
137
136
  results = db.query(tables, match, filters)
138
137
  if !results || results.empty?
139
- puts "No results found."
138
+ puts 'No results found.'
140
139
  else
141
- results.sort_by {|x| x[:name].join(' ')}.each do |rec|
140
+ results.sort_by { |x| x[:name].join(' ') }.each do |rec|
142
141
  puts format_record(db, rec)
143
142
  end
144
143
  end
@@ -149,12 +148,12 @@ rescue Starscope::DB::NoTableError
149
148
  end
150
149
 
151
150
  def dump_table(db, table)
152
- records = db.records(table).sort {|a,b|
151
+ records = db.records(table).sort do |a, b|
153
152
  a[:name][-1].to_s.downcase <=> b[:name][-1].to_s.downcase
154
- }
153
+ end
155
154
 
156
155
  puts "== Table: #{table} =="
157
- puts "No records" if records.empty?
156
+ puts 'No records' if records.empty?
158
157
 
159
158
  records.each do |record|
160
159
  puts format_record(db, record)
@@ -162,11 +161,10 @@ def dump_table(db, table)
162
161
  end
163
162
 
164
163
  def dump(db, table)
165
-
166
164
  case table
167
165
  when nil
168
- db.tables.each {|t| dump_table(db, t)}
169
- when "_meta"
166
+ db.tables.each { |t| dump_table(db, t) }
167
+ when '_meta'
170
168
  puts db.metadata
171
169
  when /^_/
172
170
  puts db.metadata(table[1..-1].to_sym)
@@ -190,7 +188,7 @@ end
190
188
  output = Starscope::Output.new(options[:output])
191
189
  db = Starscope::DB.new(output)
192
190
 
193
- db_exists = File.exists?(options[:db])
191
+ db_exists = File.exist?(options[:db])
194
192
 
195
193
  if options[:read] && db_exists
196
194
  # we consider it 'new data' if the db was upconverted from an old format
@@ -216,7 +214,7 @@ elsif !(options[:read] && db_exists)
216
214
  new_data = true
217
215
  end
218
216
 
219
- updated = db.update() if options[:update]
217
+ updated = db.update if options[:update]
220
218
  new_data ||= updated
221
219
 
222
220
  db.save(options[:db]) if options[:write] && (new_data || !db_exists)
@@ -253,29 +251,29 @@ end
253
251
  if options[:linemode]
254
252
  puts "Run your query as 'TABLE QUERY' or run '!help' for more information."
255
253
  begin
256
- while input = Readline.readline("> ", true)
254
+ while input = Readline.readline('> ', true)
257
255
  next if input.empty?
258
256
  cmd, param = input.split(' ', 2)
259
257
  if cmd[0] == '!'
260
258
  case cmd[1..-1]
261
- when "dump"
259
+ when 'dump'
262
260
  dump(db, param)
263
- when "export"
261
+ when 'export'
264
262
  if param
265
263
  export(db, param)
266
264
  else
267
- puts "!export requires an argument"
265
+ puts '!export requires an argument'
268
266
  end
269
- when "summary"
267
+ when 'summary'
270
268
  print_summary(db)
271
- when "update"
269
+ when 'update'
272
270
  changed = db.update
273
271
  db.save(options[:db]) if options[:write] && changed
274
- when "help"
272
+ when 'help'
275
273
  puts linemode_help
276
- when "version"
274
+ when 'version'
277
275
  puts Starscope::VERSION
278
- when "quit"
276
+ when 'quit'
279
277
  exit
280
278
  else
281
279
  puts "Unknown command: '#{input}', try '!help'."
@@ -16,19 +16,19 @@ on anything language-specific, they just read the internal database record
16
16
  format.
17
17
 
18
18
  For this doc, we're going to pretend to add support for a language called
19
- "MyLanguage". Create a file called `mylanguage.rb` in `lib/starscope/langs/` and
20
- drop the following template in:
19
+ "MyLanguage". Create a file called `my_language.rb` in `lib/starscope/langs/`
20
+ and drop the following template in:
21
21
 
22
22
  ```ruby
23
23
  module Starscope::Lang
24
- module Mylanguage
24
+ module MyLanguage
25
25
  VERSION = 1
26
26
 
27
27
  def self.match_file(name)
28
28
  name.end_with?(".mylang")
29
29
  end
30
30
 
31
- def self.extract(file)
31
+ def self.extract(path, contents)
32
32
  # TODO
33
33
  end
34
34
  end
@@ -36,18 +36,19 @@ end
36
36
  ```
37
37
 
38
38
  This code is pretty simple: we define a module called
39
- `Starscope::Lang::Mylanguage` and give it one constant and two public module
39
+ `Starscope::Lang::MyLanguage` and give it one constant and two public module
40
40
  methods:
41
41
  * `VERSION` is a constant integer defining the current version of the
42
42
  extractor. It should be incremented when the extractor has changed enough
43
43
  that any existing files should be re-parsed with the new version.
44
44
  * `match_file` takes the name of the file and returns a boolean if that file is
45
45
  written in MyLanguage or not. This can be as simple as checking the file
46
- extension (which the sample code does) or looking for a shell #! line, or
46
+ extension (which the sample code does) or looking for a shell `#!` line, or
47
47
  anything you want.
48
- * `extract` takes a readable file handle pointing to the file, and must parse
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.
48
+ * `extract` takes the path to the file and a string containing the contents of
49
+ the file, and must parse the text, `yield`ing records as it finds function
50
+ definitions and the like. It may also return a final hash of file-wide
51
+ metadata to store.
51
52
 
52
53
  The record requirements are pretty straight-forward:
53
54
  ```ruby
@@ -67,7 +68,7 @@ belongs (basically its type). Current tables already include:
67
68
  Try to use pre-existing tables where possible, but feel free to add more if the
68
69
  language has some weird feature that doesn't map to any of the above. You don't
69
70
  have to do anything special to create a new table, just yield the appropriate
70
- symbol.
71
+ symbol. Table names cannot begin with exclamation points (`!`).
71
72
 
72
73
  The second yielded argument is the name (string or symbol) of the token that
73
74
  you want to add: the name of the function being called, or the name of the class
@@ -85,3 +86,19 @@ And that's it! Parse your files, yield your records, and the Starscope engine
85
86
  takes care of everything else for you. If you've added support for a language
86
87
  that you think others might find useful, please contribute it (with tests!) via
87
88
  pull request.
89
+
90
+ Sublanguages and Fragments
91
+ --------------------------
92
+
93
+ Some languages (such as ERB and Markdown) include support for nesting chunks of
94
+ other languages inside. If your extractor comes across a fragment of another
95
+ language while it is parsing, it can pass that off to the correct sub-extractor
96
+ by yielding to the special `FRAGMENT` table, with the name of the language as
97
+ the name, and a `frag` argument containing the actual raw text. For example:
98
+
99
+ ```ruby
100
+ yield FRAGMENT, :Ruby, :frag => my_extracted_ruby_code, :line_no => line_no
101
+ ```
102
+
103
+ Fragments will be accumulated by the database and passed to the appropriate
104
+ extractor when the current file has been completely parsed.
@@ -1,2 +1,2 @@
1
- require "starscope/version"
2
- require "starscope/db"
1
+ require 'starscope/version'
2
+ require 'starscope/db'
@@ -5,6 +5,7 @@ require 'set'
5
5
  require 'zlib'
6
6
 
7
7
  require 'starscope/exportable'
8
+ require 'starscope/fragment_extractor'
8
9
  require 'starscope/queryable'
9
10
  require 'starscope/output'
10
11
 
@@ -19,8 +20,9 @@ Starscope::Lang.constants.each do |lang|
19
20
  LANGS[lang.to_sym] = extractor.const_get(:VERSION)
20
21
  end
21
22
 
22
- class Starscope::DB
23
+ FRAGMENT = :'!fragment'
23
24
 
25
+ class Starscope::DB
24
26
  include Starscope::Exportable
25
27
  include Starscope::Queryable
26
28
 
@@ -31,8 +33,8 @@ class Starscope::DB
31
33
 
32
34
  def initialize(output)
33
35
  @output = output
34
- @meta = {:paths => [], :files => {}, :excludes => [],
35
- :langs => LANGS, :version => Starscope::VERSION}
36
+ @meta = { :paths => [], :files => {}, :excludes => [],
37
+ :langs => LANGS, :version => Starscope::VERSION }
36
38
  @tables = {}
37
39
  end
38
40
 
@@ -63,43 +65,43 @@ class Starscope::DB
63
65
 
64
66
  def add_excludes(paths)
65
67
  @output.extra("Excluding files in paths #{paths}...")
66
- @meta[:paths] -= paths.map {|p| self.class.normalize_glob(p)}
67
- paths = paths.map {|p| self.class.normalize_fnmatch(p)}
68
+ @meta[:paths] -= paths.map { |p| self.class.normalize_glob(p) }
69
+ paths = paths.map { |p| self.class.normalize_fnmatch(p) }
68
70
  @meta[:excludes] += paths
69
71
  @meta[:excludes].uniq!
70
72
 
71
- excluded = @meta[:files].keys.select {|name| matches_exclude?(name, paths)}
73
+ excluded = @meta[:files].keys.select { |name| matches_exclude?(name, paths) }
72
74
  remove_files(excluded)
73
75
  end
74
76
 
75
77
  def add_paths(paths)
76
78
  @output.extra("Adding files in paths #{paths}...")
77
- @meta[:excludes] -= paths.map {|p| self.class.normalize_fnmatch(p)}
78
- paths = paths.map {|p| self.class.normalize_glob(p)}
79
+ @meta[:excludes] -= paths.map { |p| self.class.normalize_fnmatch(p) }
80
+ paths = paths.map { |p| self.class.normalize_glob(p) }
79
81
  @meta[:paths] += paths
80
82
  @meta[:paths].uniq!
81
- files = Dir.glob(paths).select {|f| File.file? f}
82
- files.delete_if {|f| matches_exclude?(f)}
83
+ files = Dir.glob(paths).select { |f| File.file? f }
84
+ files.delete_if { |f| matches_exclude?(f) }
83
85
  return if files.empty?
84
- @output.new_pbar("Building", files.length)
86
+ @output.new_pbar('Building', files.length)
85
87
  add_files(files)
86
88
  @output.finish_pbar
87
89
  end
88
90
 
89
91
  def update
90
- changes = @meta[:files].keys.group_by {|name| file_changed(name)}
92
+ changes = @meta[:files].keys.group_by { |name| file_changed(name) }
91
93
  changes[:modified] ||= []
92
94
  changes[:deleted] ||= []
93
95
 
94
- new_files = (Dir.glob(@meta[:paths]).select {|f| File.file? f}) - @meta[:files].keys
95
- new_files.delete_if {|f| matches_exclude?(f)}
96
+ new_files = (Dir.glob(@meta[:paths]).select { |f| File.file? f }) - @meta[:files].keys
97
+ new_files.delete_if { |f| matches_exclude?(f) }
96
98
 
97
99
  if changes[:deleted].empty? && changes[:modified].empty? && new_files.empty?
98
- @output.normal("No changes detected.")
100
+ @output.normal('No changes detected.')
99
101
  return false
100
102
  end
101
103
 
102
- @output.new_pbar("Updating", changes[:modified].length + new_files.length)
104
+ @output.new_pbar('Updating', changes[:modified].length + new_files.length)
103
105
  remove_files(changes[:deleted])
104
106
  update_files(changes[:modified])
105
107
  add_files(new_files)
@@ -113,7 +115,7 @@ class Starscope::DB
113
115
 
114
116
  file = @meta[:files][rec[:file]]
115
117
 
116
- return file[:lines][rec[:line_no]-1] if file[:lines]
118
+ return file[:lines][rec[:line_no] - 1] if file[:lines]
117
119
  end
118
120
 
119
121
  def tables
@@ -121,15 +123,15 @@ class Starscope::DB
121
123
  end
122
124
 
123
125
  def records(table)
124
- raise NoTableError if not @tables[table]
126
+ fail NoTableError unless @tables[table]
125
127
 
126
128
  @tables[table]
127
129
  end
128
130
 
129
- def metadata(key=nil)
131
+ def metadata(key = nil)
130
132
  return @meta.keys if key.nil?
131
133
 
132
- raise NoTableError unless @meta[key]
134
+ fail NoTableError unless @meta[key]
133
135
 
134
136
  @meta[key]
135
137
  end
@@ -163,10 +165,10 @@ class Starscope::DB
163
165
  when 0..2
164
166
  # Old format (pre-json), so read the directories segment then rebuild
165
167
  len = stream.gets.to_i
166
- add_paths(Marshal::load(stream.read(len)))
168
+ add_paths(Marshal.load(stream.read(len)))
167
169
  return false
168
170
  else
169
- raise UnknownDBFormatError
171
+ fail UnknownDBFormatError
170
172
  end
171
173
  rescue Oj::ParseError
172
174
  stream.rewind
@@ -174,7 +176,7 @@ class Starscope::DB
174
176
  # try reading as formated json, which is much slower, but it is sometimes
175
177
  # useful to be able to directly read your db
176
178
  objects = []
177
- Oj.load(stream) {|obj| objects << obj}
179
+ Oj.load(stream) { |obj| objects << obj }
178
180
  @meta, @tables = objects
179
181
  return true
180
182
  end
@@ -186,10 +188,10 @@ class Starscope::DB
186
188
 
187
189
  # File.fnmatch treats a "**" to match files and directories recursively
188
190
  def self.normalize_fnmatch(path)
189
- if path == "."
190
- "**"
191
+ if path == '.'
192
+ '**'
191
193
  elsif File.directory?(path)
192
- File.join(path, "**")
194
+ File.join(path, '**')
193
195
  else
194
196
  path
195
197
  end
@@ -198,17 +200,17 @@ class Starscope::DB
198
200
  # Dir.glob treats a "**" to only match directories recursively; you need
199
201
  # "**/*" to match all files recursively
200
202
  def self.normalize_glob(path)
201
- if path == "."
202
- File.join("**", "*")
203
+ if path == '.'
204
+ File.join('**', '*')
203
205
  elsif File.directory?(path)
204
- File.join(path, "**", "*")
206
+ File.join(path, '**', '*')
205
207
  else
206
208
  path
207
209
  end
208
210
  end
209
211
 
210
212
  def matches_exclude?(file, patterns = @meta[:excludes])
211
- patterns.map {|p| File.fnmatch(p, file)}.any?
213
+ patterns.map { |p| File.fnmatch(p, file) }.any?
212
214
  end
213
215
 
214
216
  def add_files(files)
@@ -226,7 +228,7 @@ class Starscope::DB
226
228
  end
227
229
  files = files.to_set
228
230
  @tables.each do |name, tbl|
229
- tbl.delete_if {|val| files.include?(val[:file])}
231
+ tbl.delete_if { |val| files.include?(val[:file]) }
230
232
  end
231
233
  end
232
234
 
@@ -236,7 +238,7 @@ class Starscope::DB
236
238
  end
237
239
 
238
240
  def parse_file(file)
239
- @meta[:files][file] = {:last_updated => File.mtime(file).to_i}
241
+ @meta[:files][file] = { :last_updated => File.mtime(file).to_i }
240
242
 
241
243
  EXTRACTORS.each do |extractor|
242
244
  begin
@@ -246,27 +248,40 @@ class Starscope::DB
246
248
  next
247
249
  end
248
250
 
249
- extract_file(extractor, file)
251
+ line_cache = File.readlines(file)
252
+ lines = Array.new(line_cache.length)
253
+ @meta[:files][file][:sublangs] = []
254
+ extract_file(extractor, file, line_cache, lines)
250
255
 
251
- return
256
+ break
252
257
  end
253
258
  end
254
259
 
255
- def extract_file(extractor, file)
256
- lines = nil
257
- line_cache = nil
258
-
259
- extractor_metadata = extractor.extract(file) do |tbl, name, args|
260
- @tables[tbl] ||= []
261
- @tables[tbl] << self.class.normalize_record(file, name, args)
262
-
263
- if args[:line_no]
264
- line_cache ||= File.readlines(file)
265
- lines ||= Array.new(line_cache.length)
266
- lines[args[:line_no]-1] = line_cache[args[:line_no]-1].chomp
260
+ def extract_file(extractor, file, line_cache, lines)
261
+ fragment_cache = {}
262
+
263
+ extractor_metadata = extractor.extract(file, File.read(file)) do |tbl, name, args|
264
+ case tbl
265
+ when FRAGMENT
266
+ fragment_cache[name] ||= []
267
+ fragment_cache[name] << args
268
+ else
269
+ @tables[tbl] ||= []
270
+ @tables[tbl] << self.class.normalize_record(file, name, args)
271
+
272
+ if args[:line_no]
273
+ line_cache ||= File.readlines(file)
274
+ lines ||= Array.new(line_cache.length)
275
+ lines[args[:line_no] - 1] = line_cache[args[:line_no] - 1].chomp
276
+ end
267
277
  end
268
278
  end
269
279
 
280
+ fragment_cache.each do |lang, frags|
281
+ extract_file(Starscope::FragmentExtractor.new(lang, frags), file, line_cache, lines)
282
+ @meta[:files][file][:sublangs] << lang
283
+ end
284
+
270
285
  @meta[:files][file][:lang] = extractor.name.split('::').last.to_sym
271
286
  @meta[:files][file][:lines] = lines
272
287
 
@@ -280,26 +295,32 @@ class Starscope::DB
280
295
 
281
296
  def file_changed(name)
282
297
  file_meta = @meta[:files][name]
283
- if !File.exists?(name) || !File.file?(name)
298
+ if !File.exist?(name) || !File.file?(name)
284
299
  :deleted
285
300
  elsif (file_meta[:last_updated] < File.mtime(name).to_i) ||
286
- (file_meta[:lang] && (@meta[:langs][file_meta[:lang]] || 0) < LANGS[file_meta[:lang]])
301
+ language_out_of_date(file_meta[:lang]) ||
302
+ (file_meta[:sublangs] || []).any? { |lang| language_out_of_date(lang) }
287
303
  :modified
288
304
  else
289
305
  :unchanged
290
306
  end
291
307
  end
292
308
 
309
+ def language_out_of_date(lang)
310
+ return false unless lang
311
+ return true unless LANGS[lang]
312
+ (@meta[:langs][lang] || 0) < LANGS[lang]
313
+ end
314
+
293
315
  def self.normalize_record(file, name, args)
294
316
  args[:file] = file
295
317
 
296
318
  if name.is_a? Array
297
- args[:name] = name.map {|x| x.to_sym}
319
+ args[:name] = name.map(&:to_sym)
298
320
  else
299
321
  args[:name] = [name.to_sym]
300
322
  end
301
323
 
302
324
  args
303
325
  end
304
-
305
326
  end