ffast 0.1.9 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +104 -1
- data/.sourcelevel.yml +2 -0
- data/.travis.yml +1 -1
- data/Fastfile +59 -3
- data/README.md +228 -130
- data/bin/console +5 -0
- data/docs/experiments.md +2 -0
- data/docs/git.md +115 -0
- data/docs/ideas.md +0 -10
- data/docs/index.md +2 -0
- data/docs/sql-support.md +253 -0
- data/docs/videos.md +5 -1
- data/docs/walkthrough.md +135 -0
- data/fast.gemspec +24 -4
- data/lib/fast/cli.rb +102 -24
- data/lib/fast/experiment.rb +1 -2
- data/lib/fast/git.rb +101 -0
- data/lib/fast/shortcut.rb +13 -11
- data/lib/fast/sql/rewriter.rb +69 -0
- data/lib/fast/sql.rb +167 -0
- data/lib/fast/version.rb +1 -1
- data/lib/fast.rb +114 -17
- data/mkdocs.yml +10 -1
- metadata +66 -15
data/lib/fast.rb
CHANGED
@@ -67,24 +67,103 @@ module Fast
|
|
67
67
|
%\d # bind extra arguments to the expression
|
68
68
|
/x.freeze
|
69
69
|
|
70
|
+
# Set some convention methods from file.
|
71
|
+
class Node < Astrolabe::Node
|
72
|
+
# @return [String] with path of the file or simply buffer name.
|
73
|
+
def buffer_name
|
74
|
+
expression.source_buffer.name
|
75
|
+
end
|
76
|
+
|
77
|
+
# @return [Parser::Source::Range] from the expression
|
78
|
+
def expression
|
79
|
+
location.expression
|
80
|
+
end
|
81
|
+
|
82
|
+
# @return [String] with the content of the #expression
|
83
|
+
def source
|
84
|
+
expression.source
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Boolean] true if a file exists with the #buffer_name
|
88
|
+
def from_file?
|
89
|
+
File.exist?(buffer_name)
|
90
|
+
end
|
91
|
+
|
92
|
+
# @return [Array<String>] with authors from the current expression range
|
93
|
+
def blame_authors
|
94
|
+
`git blame -L #{expression.first_line},#{expression.last_line} #{buffer_name}`.lines.map do |line|
|
95
|
+
line.split('(')[1].split(/\d+/).first.strip
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [String] with the first element from #blame_authors
|
100
|
+
def author
|
101
|
+
blame_authors.first
|
102
|
+
end
|
103
|
+
|
104
|
+
# Search recursively into a node and its children using a pattern.
|
105
|
+
# @param [String] pattern
|
106
|
+
# @param [Array] *args extra arguments to interpolate in the pattern.
|
107
|
+
# @return [Array<Fast::Node>>] with files and results
|
108
|
+
def search(pattern, *args)
|
109
|
+
Fast.search(pattern, self, *args)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Captures elements from search recursively
|
113
|
+
# @param [String] pattern
|
114
|
+
# @param [Array] *args extra arguments to interpolate in the pattern.
|
115
|
+
# @return [Array<Fast::Node>>] with files and results
|
116
|
+
def capture(pattern, *args)
|
117
|
+
Fast.capture(pattern, self, *args)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Custom builder allow us to set a buffer name for each Node
|
122
|
+
class Builder < Astrolabe::Builder
|
123
|
+
attr_writer :buffer_name
|
124
|
+
# Generates {Node} from the given information.
|
125
|
+
#
|
126
|
+
# @return [Node] the generated node
|
127
|
+
def n(type, children, source_map)
|
128
|
+
Node.new(type, children, location: source_map, buffer_name: @buffer_name)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
70
132
|
class << self
|
71
|
-
# @return [
|
133
|
+
# @return [Fast::Node] from the parsed content
|
72
134
|
# @example
|
73
135
|
# Fast.ast("1") # => s(:int, 1)
|
74
136
|
# Fast.ast("a.b") # => s(:send, s(:send, nil, :a), :b)
|
75
137
|
def ast(content, buffer_name: '(string)')
|
76
138
|
buffer = Parser::Source::Buffer.new(buffer_name)
|
77
139
|
buffer.source = content
|
78
|
-
Parser::CurrentRuby.new(
|
140
|
+
Parser::CurrentRuby.new(builder_for(buffer_name)).parse(buffer)
|
141
|
+
end
|
142
|
+
|
143
|
+
def builder_for(buffer_name)
|
144
|
+
builder = Builder.new
|
145
|
+
builder.buffer_name = buffer_name
|
146
|
+
builder
|
79
147
|
end
|
80
148
|
|
81
|
-
# @return [
|
149
|
+
# @return [Fast::Node] parsed from file content
|
82
150
|
# caches the content based on the filename.
|
151
|
+
# Also, it can parse SQL files.
|
83
152
|
# @example
|
84
153
|
# Fast.ast_from_file("example.rb") # => s(...)
|
85
154
|
def ast_from_file(file)
|
86
155
|
@cache ||= {}
|
87
|
-
@cache[file] ||=
|
156
|
+
@cache[file] ||=
|
157
|
+
begin
|
158
|
+
method =
|
159
|
+
if file.end_with?('.sql')
|
160
|
+
require_relative 'fast/sql' unless respond_to?(:parse_sql)
|
161
|
+
:parse_sql
|
162
|
+
else
|
163
|
+
:ast
|
164
|
+
end
|
165
|
+
Fast.public_send(method, IO.read(file), buffer_name: file)
|
166
|
+
end
|
88
167
|
end
|
89
168
|
|
90
169
|
# Verify if a given AST matches with a specific pattern
|
@@ -96,18 +175,23 @@ module Fast
|
|
96
175
|
end
|
97
176
|
|
98
177
|
# Search with pattern directly on file
|
99
|
-
# @return [Array<
|
178
|
+
# @return [Array<Fast::Node>] that matches the pattern
|
100
179
|
def search_file(pattern, file)
|
101
180
|
node = ast_from_file(file)
|
102
181
|
return [] unless node
|
103
182
|
|
104
|
-
|
183
|
+
case node
|
184
|
+
when Array
|
185
|
+
node.map { |n| search(pattern, n) }.flatten.compact
|
186
|
+
else
|
187
|
+
search pattern, node
|
188
|
+
end
|
105
189
|
end
|
106
190
|
|
107
191
|
# Search with pattern on a directory or multiple files
|
108
192
|
# @param [String] pattern
|
109
193
|
# @param [Array<String>] *locations where to search. Default is '.'
|
110
|
-
# @return [Hash<String,Array<
|
194
|
+
# @return [Hash<String,Array<Fast::Node>>] with files and results
|
111
195
|
def search_all(pattern, locations = ['.'], parallel: true, on_result: nil)
|
112
196
|
group_results(build_grouped_search(:search_file, pattern, on_result),
|
113
197
|
locations, parallel: parallel)
|
@@ -160,8 +244,12 @@ module Fast
|
|
160
244
|
def capture_file(pattern, file)
|
161
245
|
node = ast_from_file(file)
|
162
246
|
return [] unless node
|
163
|
-
|
164
|
-
|
247
|
+
case node
|
248
|
+
when Array
|
249
|
+
node.map { |n| capture(pattern, n) }.flatten.compact
|
250
|
+
else
|
251
|
+
capture pattern, node
|
252
|
+
end
|
165
253
|
end
|
166
254
|
|
167
255
|
# Search recursively into a node and its children.
|
@@ -173,9 +261,14 @@ module Fast
|
|
173
261
|
yield node, match if block_given?
|
174
262
|
match != true ? [node, match] : [node]
|
175
263
|
else
|
176
|
-
node
|
177
|
-
|
178
|
-
.
|
264
|
+
case node
|
265
|
+
when Array
|
266
|
+
node.flat_map { |child| search(pattern, child, *args) }
|
267
|
+
else
|
268
|
+
node.each_child_node
|
269
|
+
.flat_map { |child| search(pattern, child, *args) }
|
270
|
+
.compact.flatten
|
271
|
+
end
|
179
272
|
end
|
180
273
|
end
|
181
274
|
|
@@ -241,7 +334,7 @@ module Fast
|
|
241
334
|
# Useful to index abstract patterns or similar code structure.
|
242
335
|
# @see https://jonatas.github.io/fast/similarity_tutorial/
|
243
336
|
# @return [String] with an pattern to search from it.
|
244
|
-
# @param node [
|
337
|
+
# @param node [Fast::Node]
|
245
338
|
# @example
|
246
339
|
# Fast.expression_from(Fast.ast('1')) # => '(int _)'
|
247
340
|
# Fast.expression_from(Fast.ast('a = 1')) # => '(lvasgn _ (int _))'
|
@@ -250,7 +343,7 @@ module Fast
|
|
250
343
|
case node
|
251
344
|
when Parser::AST::Node
|
252
345
|
children_expression = node.children.map(&method(:expression_from)).join(' ')
|
253
|
-
"(#{node.type}#{
|
346
|
+
"(#{node.type}#{" #{children_expression}" if node.children.any?})"
|
254
347
|
when nil, 'nil'
|
255
348
|
'nil'
|
256
349
|
when Symbol, String, Numeric
|
@@ -305,14 +398,14 @@ module Fast
|
|
305
398
|
when '{' then Any.new(parse_until_peek('}'))
|
306
399
|
when '[' then All.new(parse_until_peek(']'))
|
307
400
|
when /^"/ then FindString.new(token[1..-2])
|
308
|
-
when /^#\w/ then MethodCall.new(token[1
|
309
|
-
when /^\.\w[\w\d_]+\?/ then InstanceMethodCall.new(token[1
|
401
|
+
when /^#\w/ then MethodCall.new(token[1..])
|
402
|
+
when /^\.\w[\w\d_]+\?/ then InstanceMethodCall.new(token[1..])
|
310
403
|
when '$' then Capture.new(parse)
|
311
404
|
when '!' then (@tokens.any? ? Not.new(parse) : Find.new(token))
|
312
405
|
when '?' then Maybe.new(parse)
|
313
406
|
when '^' then Parent.new(parse)
|
314
407
|
when '\\' then FindWithCapture.new(parse)
|
315
|
-
when /^%\d/ then FindFromArgument.new(token[1
|
408
|
+
when /^%\d/ then FindFromArgument.new(token[1..])
|
316
409
|
else Find.new(token)
|
317
410
|
end
|
318
411
|
end
|
@@ -367,6 +460,10 @@ module Fast
|
|
367
460
|
node.type == expression.to_sym
|
368
461
|
when String
|
369
462
|
node == expression.to_s
|
463
|
+
when TrueClass
|
464
|
+
expression == :true
|
465
|
+
when FalseClass
|
466
|
+
expression == :false
|
370
467
|
else
|
371
468
|
node == expression
|
372
469
|
end
|
data/mkdocs.yml
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
site_name: Fast
|
2
2
|
repo_url: https://github.com/jonatas/fast
|
3
3
|
edit_uri: edit/master/docs/
|
4
|
-
google_analytics: ['
|
4
|
+
google_analytics: ['G-YKZDZDNRG2', 'auto']
|
5
|
+
|
5
6
|
theme:
|
6
7
|
name: material
|
7
8
|
palette:
|
8
9
|
primary: indigo
|
9
10
|
accent: pink
|
11
|
+
logo: assets/logo.png
|
12
|
+
favicon: assets/favicon.png
|
13
|
+
extra_css:
|
14
|
+
- stylesheets/custom.css
|
15
|
+
|
10
16
|
markdown_extensions:
|
11
17
|
- admonition
|
12
18
|
- codehilite:
|
@@ -15,13 +21,16 @@ markdown_extensions:
|
|
15
21
|
permalink: true
|
16
22
|
nav:
|
17
23
|
- Introduction: index.md
|
24
|
+
- Walkthrough: walkthrough.md
|
18
25
|
- Syntax: syntax.md
|
19
26
|
- Command Line: command_line.md
|
20
27
|
- Experiments: experiments.md
|
21
28
|
- Shortcuts: shortcuts.md
|
29
|
+
- Git Integration: git.md
|
22
30
|
- Code Similarity: similarity_tutorial.md
|
23
31
|
- Pry Integration: pry-integration.md
|
24
32
|
- Editors' Integration: editors-integration.md
|
25
33
|
- Research: research.md
|
26
34
|
- Ideas: ideas.md
|
27
35
|
- Videos: videos.md
|
36
|
+
- SQL Support: sql-support.md
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffast
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jônatas Davi Paganini
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: astrolabe
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pg_query
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,6 +94,20 @@ dependencies:
|
|
80
94
|
- - ">="
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: git
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: guard
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -154,30 +182,30 @@ dependencies:
|
|
154
182
|
name: rspec
|
155
183
|
requirement: !ruby/object:Gem::Requirement
|
156
184
|
requirements:
|
157
|
-
- - "
|
185
|
+
- - ">="
|
158
186
|
- !ruby/object:Gem::Version
|
159
|
-
version: '
|
187
|
+
version: '0'
|
160
188
|
type: :development
|
161
189
|
prerelease: false
|
162
190
|
version_requirements: !ruby/object:Gem::Requirement
|
163
191
|
requirements:
|
164
|
-
- - "
|
192
|
+
- - ">="
|
165
193
|
- !ruby/object:Gem::Version
|
166
|
-
version: '
|
194
|
+
version: '0'
|
167
195
|
- !ruby/object:Gem::Dependency
|
168
196
|
name: rspec-its
|
169
197
|
requirement: !ruby/object:Gem::Requirement
|
170
198
|
requirements:
|
171
|
-
- - "
|
199
|
+
- - ">="
|
172
200
|
- !ruby/object:Gem::Version
|
173
|
-
version: '
|
201
|
+
version: '0'
|
174
202
|
type: :development
|
175
203
|
prerelease: false
|
176
204
|
version_requirements: !ruby/object:Gem::Requirement
|
177
205
|
requirements:
|
178
|
-
- - "
|
206
|
+
- - ">="
|
179
207
|
- !ruby/object:Gem::Version
|
180
|
-
version: '
|
208
|
+
version: '0'
|
181
209
|
- !ruby/object:Gem::Dependency
|
182
210
|
name: rubocop
|
183
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -247,6 +275,7 @@ files:
|
|
247
275
|
- ".projections.json"
|
248
276
|
- ".rspec"
|
249
277
|
- ".rubocop.yml"
|
278
|
+
- ".sourcelevel.yml"
|
250
279
|
- ".travis.yml"
|
251
280
|
- CODE_OF_CONDUCT.md
|
252
281
|
- Fastfile
|
@@ -263,14 +292,17 @@ files:
|
|
263
292
|
- docs/command_line.md
|
264
293
|
- docs/editors-integration.md
|
265
294
|
- docs/experiments.md
|
295
|
+
- docs/git.md
|
266
296
|
- docs/ideas.md
|
267
297
|
- docs/index.md
|
268
298
|
- docs/pry-integration.md
|
269
299
|
- docs/research.md
|
270
300
|
- docs/shortcuts.md
|
271
301
|
- docs/similarity_tutorial.md
|
302
|
+
- docs/sql-support.md
|
272
303
|
- docs/syntax.md
|
273
304
|
- docs/videos.md
|
305
|
+
- docs/walkthrough.md
|
274
306
|
- examples/build_stubbed_and_let_it_be_experiment.rb
|
275
307
|
- examples/experimental_replacement.rb
|
276
308
|
- examples/find_usage.rb
|
@@ -286,15 +318,33 @@ files:
|
|
286
318
|
- lib/fast.rb
|
287
319
|
- lib/fast/cli.rb
|
288
320
|
- lib/fast/experiment.rb
|
321
|
+
- lib/fast/git.rb
|
289
322
|
- lib/fast/rewriter.rb
|
290
323
|
- lib/fast/shortcut.rb
|
324
|
+
- lib/fast/sql.rb
|
325
|
+
- lib/fast/sql/rewriter.rb
|
291
326
|
- lib/fast/version.rb
|
292
327
|
- mkdocs.yml
|
293
328
|
homepage: https://jonatas.github.io/fast/
|
294
329
|
licenses:
|
295
330
|
- MIT
|
296
331
|
metadata: {}
|
297
|
-
post_install_message:
|
332
|
+
post_install_message: |2+
|
333
|
+
|
334
|
+
==========================================================
|
335
|
+
Yay! Thanks for installing
|
336
|
+
|
337
|
+
___ __ ___
|
338
|
+
|__ / /__` |
|
339
|
+
| /~~ .__/ |
|
340
|
+
|
341
|
+
To interactive learn about the gem in the terminal use:
|
342
|
+
|
343
|
+
fast .intro
|
344
|
+
|
345
|
+
More docs at: https://jonatas.github.io/fast/
|
346
|
+
==========================================================
|
347
|
+
|
298
348
|
rdoc_options: []
|
299
349
|
require_paths:
|
300
350
|
- lib
|
@@ -303,15 +353,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
303
353
|
requirements:
|
304
354
|
- - ">="
|
305
355
|
- !ruby/object:Gem::Version
|
306
|
-
version: '2.
|
356
|
+
version: '2.6'
|
307
357
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
308
358
|
requirements:
|
309
359
|
- - ">="
|
310
360
|
- !ruby/object:Gem::Version
|
311
361
|
version: '0'
|
312
362
|
requirements: []
|
313
|
-
rubygems_version: 3.
|
314
|
-
signing_key:
|
363
|
+
rubygems_version: 3.4.22
|
364
|
+
signing_key:
|
315
365
|
specification_version: 4
|
316
366
|
summary: 'FAST: Find by AST.'
|
317
367
|
test_files: []
|
368
|
+
...
|