ffast 0.1.9 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
...
|