ffast 0.2.4 → 0.2.7
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/lib/fast/cli.rb +17 -2
- data/lib/fast/node.rb +1 -4
- data/lib/fast/prism_adapter.rb +134 -14
- data/lib/fast/version.rb +1 -1
- data/lib/fast.rb +21 -6
- metadata +17 -20
- data/.github/workflows/release.yml +0 -27
- data/.github/workflows/ruby.yml +0 -34
- data/.gitignore +0 -14
- data/.projections.json +0 -4
- data/.rspec +0 -2
- data/.rubocop.yml +0 -160
- data/.sourcelevel.yml +0 -2
- data/.travis.yml +0 -18
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -6
- data/Guardfile +0 -39
- data/Rakefile +0 -8
- data/TODO.md +0 -3
- data/fast.gemspec +0 -62
- data/ideia_blog_post.md +0 -36
- data/mkdocs.yml +0 -51
- data/requirements-docs.txt +0 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ebcc19357d7845b5494ede74a18103b84164bbf9e2de41bf3acb1e4010bdc601
|
|
4
|
+
data.tar.gz: 2bbe9b055db2b8bcc6a855addbf41a642f2c7c74f7cfe015a7e53802b1147113
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fae498867cea1a193d25b2d10f5c4b21c34ef0f70ac76b83c6db39c7966238ae2f20eb0a537f2036ead6177de36542fa08a98d7789a0724e79a7cb358f860e46
|
|
7
|
+
data.tar.gz: df003c3585970cd06cb82b639ab890d311ae25325b2361cae05d54ef594d0cb0f3043e017b69368fc15495bcc3a20ccb84f276901159542b241d816c7600e7ff
|
data/lib/fast/cli.rb
CHANGED
|
@@ -106,8 +106,23 @@ module Fast
|
|
|
106
106
|
args = args.dup
|
|
107
107
|
args = replace_args_with_shortcut(args) if shortcut_name_from(args)
|
|
108
108
|
@colorize = STDOUT.isatty
|
|
109
|
-
|
|
109
|
+
@headless = false
|
|
110
|
+
@bodyless = false
|
|
111
|
+
@captures = false
|
|
112
|
+
@parallel = false
|
|
113
|
+
@debug = false
|
|
114
|
+
@sql = false
|
|
115
|
+
@level = nil
|
|
116
|
+
@show_sexp = false
|
|
117
|
+
@help = false
|
|
118
|
+
@similar = false
|
|
119
|
+
@from_code = false
|
|
120
|
+
@show_link = false
|
|
121
|
+
@show_permalink = false
|
|
122
|
+
@files = []
|
|
123
|
+
option_parser.parse!(args)
|
|
110
124
|
@pattern, @files = extract_pattern_and_files(args)
|
|
125
|
+
puts "DEBUG: pattern=#{@pattern.inspect} files=#{@files.inspect}" if @debug
|
|
111
126
|
|
|
112
127
|
@sql ||= @files.any? && @files.all? { |file| file.end_with?('.sql') }
|
|
113
128
|
require 'fast/sql' if @sql
|
|
@@ -146,7 +161,7 @@ module Fast
|
|
|
146
161
|
@sql = true
|
|
147
162
|
end
|
|
148
163
|
|
|
149
|
-
opts.on('--captures', 'Print only captures of the patterns and skip node results') do
|
|
164
|
+
opts.on('-c', '--captures', 'Print only captures of the patterns and skip node results') do
|
|
150
165
|
@captures = true
|
|
151
166
|
end
|
|
152
167
|
|
data/lib/fast/node.rb
CHANGED
|
@@ -70,13 +70,11 @@ module Fast
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def updated(type = nil, children = nil, properties = nil)
|
|
73
|
-
|
|
73
|
+
self.class.new(
|
|
74
74
|
type || self.type,
|
|
75
75
|
children || self.children,
|
|
76
76
|
{ location: properties&.fetch(:location, loc) || loc }
|
|
77
77
|
)
|
|
78
|
-
updated_node.send(:assign_parents!)
|
|
79
|
-
updated_node
|
|
80
78
|
end
|
|
81
79
|
|
|
82
80
|
def ==(other)
|
|
@@ -159,7 +157,6 @@ module Fast
|
|
|
159
157
|
def assign_parents!
|
|
160
158
|
each_child_node do |child|
|
|
161
159
|
self.class.set_parent(child, self)
|
|
162
|
-
child.send(:assign_parents!) if child.respond_to?(:assign_parents!, true)
|
|
163
160
|
end
|
|
164
161
|
end
|
|
165
162
|
|
data/lib/fast/prism_adapter.rb
CHANGED
|
@@ -87,6 +87,12 @@ module Fast
|
|
|
87
87
|
statements.is_a?(Node) ? statements : build_node(:begin, statements, node, source, buffer_name)
|
|
88
88
|
when Prism::StatementsNode
|
|
89
89
|
adapt_statements(node, source, buffer_name)
|
|
90
|
+
when Prism::AliasMethodNode, Prism::AliasGlobalVariableNode
|
|
91
|
+
build_node(:alias, [adapt(node.new_name, source, buffer_name), adapt(node.old_name, source, buffer_name)], node, source, buffer_name)
|
|
92
|
+
when Prism::DefinedNode
|
|
93
|
+
build_node(:defined?, [adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
94
|
+
when Prism::UndefNode
|
|
95
|
+
build_node(:undef, node.names.map { |name| adapt(name, source, buffer_name) }, node, source, buffer_name)
|
|
90
96
|
when Prism::ModuleNode
|
|
91
97
|
build_node(:module, [adapt(node.constant_path, source, buffer_name), adapt(node.body, source, buffer_name)], node, source, buffer_name)
|
|
92
98
|
when Prism::ClassNode
|
|
@@ -125,12 +131,31 @@ module Fast
|
|
|
125
131
|
build_node(node.exclude_end? ? :erange : :irange, [adapt(node.left, source, buffer_name), adapt(node.right, source, buffer_name)], node, source, buffer_name)
|
|
126
132
|
when Prism::BlockArgumentNode
|
|
127
133
|
build_node(:block_pass, [adapt(node.expression, source, buffer_name)], node, source, buffer_name)
|
|
134
|
+
when Prism::ReturnNode
|
|
135
|
+
build_node(:return, node.arguments&.arguments.to_a.map { |arg| adapt(arg, source, buffer_name) }, node, source, buffer_name)
|
|
136
|
+
when Prism::NextNode
|
|
137
|
+
build_node(:next, node.arguments&.arguments.to_a.map { |arg| adapt(arg, source, buffer_name) }, node, source, buffer_name)
|
|
138
|
+
when Prism::BreakNode
|
|
139
|
+
build_node(:break, node.arguments&.arguments.to_a.map { |arg| adapt(arg, source, buffer_name) }, node, source, buffer_name)
|
|
140
|
+
when Prism::YieldNode
|
|
141
|
+
build_node(:yield, node.arguments&.arguments.to_a.map { |arg| adapt(arg, source, buffer_name) }, node, source, buffer_name)
|
|
142
|
+
when Prism::SuperNode
|
|
143
|
+
build_node(:super, node.arguments&.arguments.to_a.map { |arg| adapt(arg, source, buffer_name) }, node, source, buffer_name)
|
|
144
|
+
when Prism::ForwardingSuperNode
|
|
145
|
+
build_node(:zsuper, [], node, source, buffer_name)
|
|
146
|
+
when Prism::SplatNode
|
|
147
|
+
build_node(:splat, [adapt(node.expression, source, buffer_name)], node, source, buffer_name)
|
|
148
|
+
when Prism::AssocSplatNode
|
|
149
|
+
build_node(:kwsplat, [adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
128
150
|
when Prism::ConstantPathNode
|
|
129
151
|
build_const_path(node, source, buffer_name)
|
|
152
|
+
|
|
130
153
|
when Prism::ConstantReadNode
|
|
131
154
|
build_node(:const, [nil, node.name], node, source, buffer_name)
|
|
132
155
|
when Prism::ConstantWriteNode
|
|
133
156
|
build_node(:casgn, [nil, node.name, adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
157
|
+
when Prism::ConstantPathWriteNode
|
|
158
|
+
build_node(:casgn, [adapt(node.target, source, buffer_name), nil, adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
134
159
|
when Prism::SymbolNode
|
|
135
160
|
build_node(:sym, [node.unescaped], node, source, buffer_name)
|
|
136
161
|
when Prism::StringNode
|
|
@@ -143,6 +168,10 @@ module Fast
|
|
|
143
168
|
build_node(:dxstr, node.parts.filter_map { |part| adapt(part, source, buffer_name) }, node, source, buffer_name)
|
|
144
169
|
when Prism::InterpolatedSymbolNode
|
|
145
170
|
build_node(:dsym, node.parts.filter_map { |part| adapt(part, source, buffer_name) }, node, source, buffer_name)
|
|
171
|
+
when Prism::RegularExpressionNode
|
|
172
|
+
build_node(:regexp, [build_node(:str, [node.unescaped], node, source, buffer_name), build_node(:regopt, regexp_options(node), node, source, buffer_name)], node, source, buffer_name)
|
|
173
|
+
when Prism::InterpolatedRegularExpressionNode
|
|
174
|
+
build_node(:regexp, node.parts.filter_map { |part| adapt(part, source, buffer_name) } + [build_node(:regopt, regexp_options(node), node, source, buffer_name)], node, source, buffer_name)
|
|
146
175
|
when Prism::ArrayNode
|
|
147
176
|
build_node(:array, node.elements.map { |child| adapt(child, source, buffer_name) }, node, source, buffer_name)
|
|
148
177
|
when Prism::HashNode
|
|
@@ -153,12 +182,30 @@ module Fast
|
|
|
153
182
|
build_node(:pair, [adapt(node.key, source, buffer_name), adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
154
183
|
when Prism::SelfNode
|
|
155
184
|
build_node(:self, [], node, source, buffer_name)
|
|
185
|
+
when Prism::RedoNode
|
|
186
|
+
build_node(:redo, [], node, source, buffer_name)
|
|
187
|
+
when Prism::RetryNode
|
|
188
|
+
build_node(:retry, [], node, source, buffer_name)
|
|
189
|
+
when Prism::PreExecutionNode
|
|
190
|
+
build_node(:preexe, [adapt_statements(node.statements, source, buffer_name)], node, source, buffer_name)
|
|
191
|
+
when Prism::PostExecutionNode
|
|
192
|
+
build_node(:postexe, [adapt_statements(node.statements, source, buffer_name)], node, source, buffer_name)
|
|
193
|
+
when Prism::NumberedReferenceReadNode
|
|
194
|
+
build_node(:nth_ref, [node.number], node, source, buffer_name)
|
|
195
|
+
when Prism::BackReferenceReadNode
|
|
196
|
+
build_node(:back_ref, [node.name], node, source, buffer_name)
|
|
156
197
|
when Prism::LocalVariableReadNode
|
|
157
198
|
build_node(:lvar, [node.name], node, source, buffer_name)
|
|
199
|
+
when Prism::LocalVariableTargetNode
|
|
200
|
+
build_node(:lvasgn, [node.name], node, source, buffer_name)
|
|
158
201
|
when Prism::InstanceVariableReadNode
|
|
159
202
|
build_node(:ivar, [node.name], node, source, buffer_name)
|
|
203
|
+
when Prism::GlobalVariableReadNode
|
|
204
|
+
build_node(:gvar, [node.name], node, source, buffer_name)
|
|
160
205
|
when Prism::InstanceVariableWriteNode, Prism::InstanceVariableOrWriteNode
|
|
161
206
|
build_node(:ivasgn, [node.name, adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
207
|
+
when Prism::GlobalVariableWriteNode
|
|
208
|
+
build_node(:gvasgn, [node.name, adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
162
209
|
when Prism::LocalVariableWriteNode, Prism::LocalVariableOrWriteNode
|
|
163
210
|
build_node(:lvasgn, [node.name, adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
164
211
|
when Prism::LocalVariableOperatorWriteNode
|
|
@@ -173,33 +220,52 @@ module Fast
|
|
|
173
220
|
source,
|
|
174
221
|
buffer_name
|
|
175
222
|
)
|
|
223
|
+
when Prism::MatchWriteNode
|
|
224
|
+
build_node(:match_with_lvasgn, [adapt(node.call.receiver, source, buffer_name), adapt(node.call.arguments&.arguments&.first, source, buffer_name)], node, source, buffer_name)
|
|
225
|
+
when Prism::MatchLastLineNode
|
|
226
|
+
build_node(:match_current_line, [build_node(:regexp, [build_node(:str, [node.unescaped], node, source, buffer_name), build_node(:regopt, regexp_options(node), node, source, buffer_name)], node, source, buffer_name)], node, source, buffer_name)
|
|
176
227
|
when Prism::IntegerNode
|
|
177
228
|
build_node(:int, [node.value], node, source, buffer_name)
|
|
178
229
|
when Prism::FloatNode
|
|
179
230
|
build_node(:float, [node.value], node, source, buffer_name)
|
|
231
|
+
when Prism::RationalNode
|
|
232
|
+
build_node(:rational, [node.value], node, source, buffer_name)
|
|
233
|
+
when Prism::ImaginaryNode
|
|
234
|
+
build_node(:complex, [node.value], node, source, buffer_name)
|
|
180
235
|
when Prism::TrueNode
|
|
181
236
|
build_node(:true, [], node, source, buffer_name)
|
|
182
237
|
when Prism::FalseNode
|
|
183
238
|
build_node(:false, [], node, source, buffer_name)
|
|
184
239
|
when Prism::NilNode
|
|
185
240
|
build_node(:nil, [], node, source, buffer_name)
|
|
241
|
+
when Prism::AndNode
|
|
242
|
+
build_node(:and, [adapt(node.left, source, buffer_name), adapt(node.right, source, buffer_name)], node, source, buffer_name)
|
|
243
|
+
when Prism::OrNode
|
|
244
|
+
build_node(:or, [adapt(node.left, source, buffer_name), adapt(node.right, source, buffer_name)], node, source, buffer_name)
|
|
186
245
|
when Prism::IfNode
|
|
187
246
|
build_node(:if, [adapt(node.predicate, source, buffer_name), adapt(node.statements, source, buffer_name), adapt(node.consequent, source, buffer_name)], node, source, buffer_name)
|
|
188
247
|
when Prism::UnlessNode
|
|
189
248
|
build_node(:if, [adapt(node.predicate, source, buffer_name), adapt(node.consequent, source, buffer_name), adapt(node.statements, source, buffer_name)], node, source, buffer_name)
|
|
249
|
+
when Prism::WhileNode
|
|
250
|
+
build_node(:while, [adapt(node.predicate, source, buffer_name), adapt(node.statements, source, buffer_name)], node, source, buffer_name)
|
|
251
|
+
when Prism::UntilNode
|
|
252
|
+
build_node(:until, [adapt(node.predicate, source, buffer_name), adapt(node.statements, source, buffer_name)], node, source, buffer_name)
|
|
253
|
+
when Prism::ForNode
|
|
254
|
+
build_node(:for, [adapt(node.index, source, buffer_name), adapt(node.collection, source, buffer_name), adapt(node.statements, source, buffer_name)], node, source, buffer_name)
|
|
255
|
+
when Prism::MultiWriteNode
|
|
256
|
+
mlhs_children = node.lefts.map { |left| adapt(left, source, buffer_name) }
|
|
257
|
+
mlhs_children << adapt(node.rest, source, buffer_name) if node.rest
|
|
258
|
+
mlhs_children.concat(node.rights.map { |right| adapt(right, source, buffer_name) }) if node.respond_to?(:rights)
|
|
259
|
+
build_node(:masgn, [build_node(:mlhs, mlhs_children, node, source, buffer_name), adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
190
260
|
when Prism::RescueModifierNode
|
|
191
261
|
build_node(:rescue, [adapt(node.expression, source, buffer_name), build_node(:resbody, [nil, nil, adapt(node.rescue_expression, source, buffer_name)], node, source, buffer_name), nil], node, source, buffer_name)
|
|
192
262
|
when Prism::CaseNode
|
|
193
263
|
children = [adapt(node.predicate, source, buffer_name)]
|
|
194
264
|
children.concat(node.conditions.map { |condition| adapt(condition, source, buffer_name) })
|
|
195
|
-
|
|
196
|
-
if node.respond_to?(:else_clause)
|
|
197
|
-
node.else_clause
|
|
198
|
-
elsif node.respond_to?(:consequent)
|
|
199
|
-
node.consequent
|
|
200
|
-
end
|
|
201
|
-
children << adapt_else_clause(else_clause, source, buffer_name) if else_clause
|
|
265
|
+
children << adapt(node.consequent, source, buffer_name) if node.consequent
|
|
202
266
|
build_node(:case, children, node, source, buffer_name)
|
|
267
|
+
when Prism::HashPatternNode
|
|
268
|
+
build_node(:hash, node.elements.map { |child| adapt(child, source, buffer_name) }, node, source, buffer_name)
|
|
203
269
|
when Prism::WhenNode
|
|
204
270
|
condition =
|
|
205
271
|
if node.conditions.length == 1
|
|
@@ -210,12 +276,29 @@ module Fast
|
|
|
210
276
|
build_node(:when, [condition, adapt(node.statements, source, buffer_name)].compact, node, source, buffer_name)
|
|
211
277
|
when Prism::ElseNode
|
|
212
278
|
adapt_else_clause(node, source, buffer_name)
|
|
279
|
+
when Prism::CallOperatorWriteNode
|
|
280
|
+
operator = node.respond_to?(:binary_operator) ? node.binary_operator : node.operator
|
|
281
|
+
build_node(:op_asgn, [build_node(:send, [adapt(node.receiver, source, buffer_name), node.read_name], node, source, buffer_name), operator, adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
282
|
+
when Prism::IndexOperatorWriteNode
|
|
283
|
+
operator = node.respond_to?(:binary_operator) ? node.binary_operator : node.operator
|
|
284
|
+
build_node(:op_asgn, [build_node(:send, [adapt(node.receiver, source, buffer_name), :[]].concat(node.arguments&.arguments.to_a.map { |arg| adapt(arg, source, buffer_name) }), node, source, buffer_name), operator, adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
213
285
|
when Prism::BeginNode, Prism::EmbeddedStatementsNode
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
286
|
+
res = adapt_statements(node.statements, source, buffer_name)
|
|
287
|
+
if node.respond_to?(:rescue_clause) && node.rescue_clause
|
|
288
|
+
res = build_node(:rescue, [res].concat(adapt_rescue_clause(node.rescue_clause, source, buffer_name)).concat([adapt(node.else_clause, source, buffer_name)]), node, source, buffer_name)
|
|
289
|
+
end
|
|
290
|
+
if node.respond_to?(:ensure_clause) && node.ensure_clause
|
|
291
|
+
res = build_node(:ensure, [res, adapt(node.ensure_clause, source, buffer_name)], node, source, buffer_name)
|
|
292
|
+
end
|
|
293
|
+
res
|
|
294
|
+
when Prism::RescueNode
|
|
295
|
+
adapt_rescue_clause(node, source, buffer_name)
|
|
296
|
+
when Prism::EnsureNode
|
|
297
|
+
adapt_statements(node.statements, source, buffer_name)
|
|
217
298
|
when Prism::EmbeddedVariableNode
|
|
218
299
|
build_node(:begin, [adapt(node.variable, source, buffer_name)].compact, node, source, buffer_name)
|
|
300
|
+
when Prism::ImplicitNode
|
|
301
|
+
adapt(node.value, source, buffer_name)
|
|
219
302
|
when Prism::LambdaNode
|
|
220
303
|
build_node(:lambda, [adapt_block_parameters(node.parameters, source, buffer_name), adapt(node.body, source, buffer_name)], node, source, buffer_name)
|
|
221
304
|
else
|
|
@@ -223,6 +306,33 @@ module Fast
|
|
|
223
306
|
end
|
|
224
307
|
end
|
|
225
308
|
|
|
309
|
+
def adapt_rescue_clause(node, source, buffer_name)
|
|
310
|
+
resbodies = []
|
|
311
|
+
current = node
|
|
312
|
+
while current && current.is_a?(Prism::RescueNode)
|
|
313
|
+
exceptions = current.exceptions.map { |e| adapt(e, source, buffer_name) }
|
|
314
|
+
exceptions = build_node(:array, exceptions, current, source, buffer_name) if exceptions.any?
|
|
315
|
+
resbodies << build_node(:resbody, [exceptions, adapt(current.reference, source, buffer_name), adapt(current.statements, source, buffer_name)], current, source, buffer_name)
|
|
316
|
+
current = current.respond_to?(:subsequent) ? current.subsequent : current.consequent
|
|
317
|
+
end
|
|
318
|
+
resbodies
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def adapt_else_clause(node, source, buffer_name)
|
|
322
|
+
adapt(node&.statements, source, buffer_name)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def wrap_begin(node, source, buffer_name)
|
|
326
|
+
return nil unless node
|
|
327
|
+
|
|
328
|
+
res = adapt(node, source, buffer_name)
|
|
329
|
+
if res.is_a?(Node) && res.type == :begin
|
|
330
|
+
res
|
|
331
|
+
else
|
|
332
|
+
build_node(:begin, [nil, res], node, source, buffer_name)
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
226
336
|
def adapt_statements(node, source, buffer_name)
|
|
227
337
|
return nil unless node
|
|
228
338
|
|
|
@@ -299,8 +409,12 @@ module Fast
|
|
|
299
409
|
send_node
|
|
300
410
|
end
|
|
301
411
|
|
|
302
|
-
def
|
|
303
|
-
|
|
412
|
+
def regexp_options(node)
|
|
413
|
+
options = []
|
|
414
|
+
options << :i if node.ignore_case?
|
|
415
|
+
options << :m if node.multi_line?
|
|
416
|
+
options << :x if node.extended?
|
|
417
|
+
options
|
|
304
418
|
end
|
|
305
419
|
|
|
306
420
|
def parameter_name(node)
|
|
@@ -308,8 +422,14 @@ module Fast
|
|
|
308
422
|
end
|
|
309
423
|
|
|
310
424
|
def build_const_path(node, source, buffer_name)
|
|
311
|
-
parent =
|
|
312
|
-
|
|
425
|
+
parent =
|
|
426
|
+
if node.parent
|
|
427
|
+
adapt(node.parent, source, buffer_name)
|
|
428
|
+
elsif node.delimiter_loc
|
|
429
|
+
build_node(:cbase, [], nil, source, buffer_name)
|
|
430
|
+
end
|
|
431
|
+
name = node.respond_to?(:name) ? node.name : node.child.name
|
|
432
|
+
build_node(:const, [parent, name], node, source, buffer_name)
|
|
313
433
|
end
|
|
314
434
|
|
|
315
435
|
def build_node(type, children, prism_node, source, buffer_name)
|
data/lib/fast/version.rb
CHANGED
data/lib/fast.rb
CHANGED
|
@@ -41,6 +41,12 @@ module Fast
|
|
|
41
41
|
|
|
|
42
42
|
[\d\w_]+[=\\!\?]? # method names or numbers
|
|
43
43
|
|
|
|
44
|
+
:[^(){}\[\]\s;]+ # symbols
|
|
45
|
+
|
|
|
46
|
+
\/[^\/ \n]+\/ # regex literals
|
|
47
|
+
|
|
|
48
|
+
; # semicolons
|
|
49
|
+
|
|
|
44
50
|
\(|\) # parens `(` and `)` for tuples
|
|
45
51
|
|
|
|
46
52
|
\{|\} # curly brackets `{` and `}` for any
|
|
@@ -259,6 +265,8 @@ module Fast
|
|
|
259
265
|
# otherwise it recursively collect possible children nodes
|
|
260
266
|
# @yield node and capture if block given
|
|
261
267
|
def search(pattern, node, *args)
|
|
268
|
+
return [] if node.nil?
|
|
269
|
+
|
|
262
270
|
if (match = match?(pattern, node, *args))
|
|
263
271
|
yield node, match if block_given?
|
|
264
272
|
match != true ? [node, match] : [node]
|
|
@@ -277,6 +285,8 @@ module Fast
|
|
|
277
285
|
# Only captures from a search
|
|
278
286
|
# @return [Array<Object>] with all captured elements.
|
|
279
287
|
def capture(pattern, node)
|
|
288
|
+
return [] if node.nil?
|
|
289
|
+
|
|
280
290
|
if (match = match?(pattern, node))
|
|
281
291
|
match == true ? node : match
|
|
282
292
|
else
|
|
@@ -488,6 +498,8 @@ module Fast
|
|
|
488
498
|
when '^' then Parent.new(parse)
|
|
489
499
|
when '\\' then FindWithCapture.new(parse)
|
|
490
500
|
when /^%\d/ then FindFromArgument.new(token[1..])
|
|
501
|
+
when ';'
|
|
502
|
+
raise SyntaxError, "Semicolons are not allowed in patterns: #{token}"
|
|
491
503
|
when nil then nil
|
|
492
504
|
else Find.new(token)
|
|
493
505
|
end
|
|
@@ -548,7 +560,6 @@ module Fast
|
|
|
548
560
|
case expression
|
|
549
561
|
when Proc then expression.call(node)
|
|
550
562
|
when Find then expression.match?(node)
|
|
551
|
-
when Symbol then compare_symbol_or_head(expression, node)
|
|
552
563
|
when Enumerable
|
|
553
564
|
if expression.last == :'...' || expression.last.is_a?(Find) && expression.last.token == '...'
|
|
554
565
|
expression[0...-1].each_with_index.all? do |exp, i|
|
|
@@ -560,14 +571,16 @@ module Fast
|
|
|
560
571
|
end
|
|
561
572
|
end
|
|
562
573
|
else
|
|
563
|
-
node
|
|
574
|
+
compare_symbol_or_head(expression, node)
|
|
564
575
|
end
|
|
565
576
|
end
|
|
566
577
|
|
|
567
578
|
def compare_symbol_or_head(expression, node)
|
|
579
|
+
return true if node.nil? && (expression.nil? || expression == :nil)
|
|
580
|
+
|
|
568
581
|
case node
|
|
569
582
|
when ->(candidate) { Fast.ast_node?(candidate) }
|
|
570
|
-
node.type == expression
|
|
583
|
+
node.type == expression&.to_sym
|
|
571
584
|
when String
|
|
572
585
|
node == expression.to_s
|
|
573
586
|
when TrueClass
|
|
@@ -615,6 +628,8 @@ module Fast
|
|
|
615
628
|
case token
|
|
616
629
|
when /^\d+\.\d*/ then token.to_f
|
|
617
630
|
when /^\d+/ then token.to_i
|
|
631
|
+
when /^:/ then token[1..].to_sym
|
|
632
|
+
when /^\/.*\/$/ then Regexp.new(token[1..-2])
|
|
618
633
|
else token.to_sym
|
|
619
634
|
end
|
|
620
635
|
end
|
|
@@ -774,7 +789,7 @@ module Fast
|
|
|
774
789
|
# Fast.expression("{int float}")
|
|
775
790
|
class Any < Find
|
|
776
791
|
def match?(node)
|
|
777
|
-
token.any? { |expression| Fast.match?(expression, node) }
|
|
792
|
+
token.any? { |expression| !!Fast.match?(expression, node) }
|
|
778
793
|
end
|
|
779
794
|
|
|
780
795
|
def to_s
|
|
@@ -785,7 +800,7 @@ module Fast
|
|
|
785
800
|
# Intersect expressions. Works like a **AND** operator.
|
|
786
801
|
class All < Find
|
|
787
802
|
def match?(node)
|
|
788
|
-
token.all? { |expression| expression.match?(node) }
|
|
803
|
+
token.all? { |expression| !!expression.match?(node) }
|
|
789
804
|
end
|
|
790
805
|
|
|
791
806
|
def to_s
|
|
@@ -831,7 +846,7 @@ module Fast
|
|
|
831
846
|
def initialize(pattern, ast, *args)
|
|
832
847
|
@ast = ast
|
|
833
848
|
@expression = if pattern.is_a?(String)
|
|
834
|
-
Fast.expression(pattern)
|
|
849
|
+
Array(Fast.expression(pattern))
|
|
835
850
|
else
|
|
836
851
|
[*pattern].map(&Find.method(:new))
|
|
837
852
|
end
|
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.2.
|
|
4
|
+
version: 0.2.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jônatas Davi Paganini
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-04-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: coderay
|
|
@@ -136,6 +136,20 @@ dependencies:
|
|
|
136
136
|
- - ">="
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
138
|
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: racc
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
139
153
|
- !ruby/object:Gem::Dependency
|
|
140
154
|
name: rake
|
|
141
155
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -240,33 +254,19 @@ email:
|
|
|
240
254
|
executables:
|
|
241
255
|
- fast
|
|
242
256
|
- fast-experiment
|
|
257
|
+
- fast-mcp
|
|
243
258
|
extensions: []
|
|
244
259
|
extra_rdoc_files: []
|
|
245
260
|
files:
|
|
246
261
|
- ".agents/fast-pattern-expert/SKILL.md"
|
|
247
|
-
- ".github/workflows/release.yml"
|
|
248
|
-
- ".github/workflows/ruby.yml"
|
|
249
|
-
- ".gitignore"
|
|
250
|
-
- ".projections.json"
|
|
251
|
-
- ".rspec"
|
|
252
|
-
- ".rubocop.yml"
|
|
253
|
-
- ".sourcelevel.yml"
|
|
254
|
-
- ".travis.yml"
|
|
255
|
-
- CODE_OF_CONDUCT.md
|
|
256
262
|
- Fastfile
|
|
257
|
-
- Gemfile
|
|
258
|
-
- Guardfile
|
|
259
263
|
- LICENSE.txt
|
|
260
264
|
- README.md
|
|
261
|
-
- Rakefile
|
|
262
|
-
- TODO.md
|
|
263
265
|
- bin/console
|
|
264
266
|
- bin/fast
|
|
265
267
|
- bin/fast-experiment
|
|
266
268
|
- bin/fast-mcp
|
|
267
269
|
- bin/setup
|
|
268
|
-
- fast.gemspec
|
|
269
|
-
- ideia_blog_post.md
|
|
270
270
|
- lib/fast.rb
|
|
271
271
|
- lib/fast/cli.rb
|
|
272
272
|
- lib/fast/experiment.rb
|
|
@@ -283,8 +283,6 @@ files:
|
|
|
283
283
|
- lib/fast/sql/rewriter.rb
|
|
284
284
|
- lib/fast/summary.rb
|
|
285
285
|
- lib/fast/version.rb
|
|
286
|
-
- mkdocs.yml
|
|
287
|
-
- requirements-docs.txt
|
|
288
286
|
homepage: https://jonatas.github.io/fast/
|
|
289
287
|
licenses:
|
|
290
288
|
- MIT
|
|
@@ -308,7 +306,6 @@ post_install_message: |2+
|
|
|
308
306
|
rdoc_options: []
|
|
309
307
|
require_paths:
|
|
310
308
|
- lib
|
|
311
|
-
- experiments
|
|
312
309
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
313
310
|
requirements:
|
|
314
311
|
- - ">="
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
name: Release Gem
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- 'v*' # Triggers when a new tag like v0.2.0 is pushed
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
release:
|
|
10
|
-
name: Build and Release
|
|
11
|
-
runs-on: ubuntu-22.04
|
|
12
|
-
permissions:
|
|
13
|
-
contents: read # Required to checkout the code
|
|
14
|
-
id-token: write # Required for RubyGems Trusted Publishing
|
|
15
|
-
|
|
16
|
-
steps:
|
|
17
|
-
- name: Checkout code
|
|
18
|
-
uses: actions/checkout@v4
|
|
19
|
-
|
|
20
|
-
- name: Set up Ruby
|
|
21
|
-
uses: ruby/setup-ruby@v1
|
|
22
|
-
with:
|
|
23
|
-
ruby-version: '3.3'
|
|
24
|
-
bundler-cache: true
|
|
25
|
-
|
|
26
|
-
- name: Publish to RubyGems
|
|
27
|
-
uses: rubygems/release-gem@v1
|
data/.github/workflows/ruby.yml
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# This workflow uses actions that are not certified by GitHub.
|
|
2
|
-
# They are provided by a third-party and are governed by
|
|
3
|
-
# separate terms of service, privacy policy, and support
|
|
4
|
-
# documentation.
|
|
5
|
-
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
|
6
|
-
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
|
7
|
-
|
|
8
|
-
name: Ruby
|
|
9
|
-
|
|
10
|
-
on:
|
|
11
|
-
push:
|
|
12
|
-
branches: [ "master" ]
|
|
13
|
-
pull_request:
|
|
14
|
-
branches: [ "master" ]
|
|
15
|
-
|
|
16
|
-
permissions:
|
|
17
|
-
contents: read
|
|
18
|
-
|
|
19
|
-
jobs:
|
|
20
|
-
test:
|
|
21
|
-
runs-on: ubuntu-22.04
|
|
22
|
-
strategy:
|
|
23
|
-
matrix:
|
|
24
|
-
ruby-version: ['3.0', '3.1', '3.2', '3.3']
|
|
25
|
-
|
|
26
|
-
steps:
|
|
27
|
-
- uses: actions/checkout@v4
|
|
28
|
-
- name: Set up Ruby
|
|
29
|
-
uses: ruby/setup-ruby@v1
|
|
30
|
-
with:
|
|
31
|
-
ruby-version: ${{ matrix.ruby-version }}
|
|
32
|
-
bundler-cache: true
|
|
33
|
-
- name: Run tests
|
|
34
|
-
run: bundle exec rake
|
data/.gitignore
DELETED
data/.projections.json
DELETED
data/.rspec
DELETED
data/.rubocop.yml
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
# This is the configuration used to check the rubocop source code.
|
|
2
|
-
|
|
3
|
-
require:
|
|
4
|
-
- rubocop-rspec
|
|
5
|
-
- rubocop-performance
|
|
6
|
-
|
|
7
|
-
AllCops:
|
|
8
|
-
Exclude:
|
|
9
|
-
- 'tmp/**/*'
|
|
10
|
-
- 'examples/*'
|
|
11
|
-
TargetRubyVersion: 2.6
|
|
12
|
-
|
|
13
|
-
Layout/LineLength:
|
|
14
|
-
Enabled: false
|
|
15
|
-
|
|
16
|
-
Layout/EmptyLinesAroundAttributeAccessor:
|
|
17
|
-
Enabled: false
|
|
18
|
-
|
|
19
|
-
Layout/SpaceAroundMethodCallOperator:
|
|
20
|
-
Enabled: false
|
|
21
|
-
|
|
22
|
-
Lint/BinaryOperatorWithIdenticalOperands:
|
|
23
|
-
Enabled: true
|
|
24
|
-
|
|
25
|
-
Lint/DuplicateElsifCondition:
|
|
26
|
-
Enabled: false
|
|
27
|
-
|
|
28
|
-
Lint/DuplicateRescueException:
|
|
29
|
-
Enabled: false
|
|
30
|
-
|
|
31
|
-
Lint/EmptyConditionalBody:
|
|
32
|
-
Enabled: false
|
|
33
|
-
|
|
34
|
-
Lint/FloatComparison:
|
|
35
|
-
Enabled: false
|
|
36
|
-
|
|
37
|
-
Lint/MissingSuper:
|
|
38
|
-
Enabled: false
|
|
39
|
-
|
|
40
|
-
Lint/OutOfRangeRegexpRef:
|
|
41
|
-
Enabled: false
|
|
42
|
-
|
|
43
|
-
Lint/SelfAssignment:
|
|
44
|
-
Enabled: false
|
|
45
|
-
|
|
46
|
-
Lint/TopLevelReturnWithArgument:
|
|
47
|
-
Enabled: false
|
|
48
|
-
|
|
49
|
-
Lint/UnreachableLoop:
|
|
50
|
-
Enabled: false
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
Lint/DeprecatedOpenSSLConstant:
|
|
54
|
-
Enabled: false
|
|
55
|
-
|
|
56
|
-
Lint/MixedRegexpCaptureTypes:
|
|
57
|
-
Enabled: false
|
|
58
|
-
|
|
59
|
-
Lint/RaiseException:
|
|
60
|
-
Enabled: true
|
|
61
|
-
|
|
62
|
-
Lint/StructNewOverride:
|
|
63
|
-
Enabled: true
|
|
64
|
-
|
|
65
|
-
Style/AccessorGrouping:
|
|
66
|
-
Enabled: false
|
|
67
|
-
|
|
68
|
-
Style/ArrayCoercion:
|
|
69
|
-
Enabled: false
|
|
70
|
-
|
|
71
|
-
Style/BisectedAttrAccessor:
|
|
72
|
-
Enabled: true
|
|
73
|
-
|
|
74
|
-
Style/CaseLikeIf:
|
|
75
|
-
Enabled: true
|
|
76
|
-
|
|
77
|
-
Style/ExplicitBlockArgument:
|
|
78
|
-
Enabled: false
|
|
79
|
-
|
|
80
|
-
Style/ExponentialNotation:
|
|
81
|
-
Enabled: true
|
|
82
|
-
|
|
83
|
-
Style/GlobalStdStream:
|
|
84
|
-
Enabled: false
|
|
85
|
-
|
|
86
|
-
Style/HashAsLastArrayItem:
|
|
87
|
-
Enabled: false
|
|
88
|
-
|
|
89
|
-
Style/HashLikeCase:
|
|
90
|
-
Enabled: true
|
|
91
|
-
|
|
92
|
-
Style/OptionalBooleanParameter:
|
|
93
|
-
Enabled: true
|
|
94
|
-
|
|
95
|
-
Style/RedundantAssignment:
|
|
96
|
-
Enabled: true
|
|
97
|
-
|
|
98
|
-
Style/RedundantFetchBlock:
|
|
99
|
-
Enabled: true
|
|
100
|
-
|
|
101
|
-
Style/RedundantFileExtensionInRequire:
|
|
102
|
-
Enabled: true
|
|
103
|
-
|
|
104
|
-
Style/SingleArgumentDig:
|
|
105
|
-
Enabled: true
|
|
106
|
-
|
|
107
|
-
Style/StringConcatenation:
|
|
108
|
-
Enabled: true
|
|
109
|
-
|
|
110
|
-
Style/RedundantRegexpCharacterClass:
|
|
111
|
-
Enabled: false
|
|
112
|
-
|
|
113
|
-
Style/RedundantRegexpEscape:
|
|
114
|
-
Enabled: false
|
|
115
|
-
|
|
116
|
-
Style/SlicingWithRange:
|
|
117
|
-
Enabled: true
|
|
118
|
-
|
|
119
|
-
Metrics/BlockLength:
|
|
120
|
-
Exclude:
|
|
121
|
-
- 'spec/**/*'
|
|
122
|
-
- 'fast.gemspec'
|
|
123
|
-
|
|
124
|
-
Lint/InterpolationCheck:
|
|
125
|
-
Exclude:
|
|
126
|
-
- 'spec/**/*'
|
|
127
|
-
|
|
128
|
-
Metrics/MethodLength:
|
|
129
|
-
CountComments: false # count full line comments?
|
|
130
|
-
Max: 12
|
|
131
|
-
|
|
132
|
-
Metrics/ModuleLength:
|
|
133
|
-
Enabled: false
|
|
134
|
-
|
|
135
|
-
Layout/MultilineMethodCallIndentation:
|
|
136
|
-
EnforcedStyle: 'indented'
|
|
137
|
-
|
|
138
|
-
RSpec/NestedGroups:
|
|
139
|
-
Max: 4
|
|
140
|
-
|
|
141
|
-
RSpec/ExampleLength:
|
|
142
|
-
Max: 20
|
|
143
|
-
|
|
144
|
-
RSpec/MultipleExpectations:
|
|
145
|
-
Enabled: false
|
|
146
|
-
|
|
147
|
-
RSpec/DescribedClass:
|
|
148
|
-
Enabled: false
|
|
149
|
-
|
|
150
|
-
RSpec/ImplicitSubject:
|
|
151
|
-
Enabled: false
|
|
152
|
-
|
|
153
|
-
Style/HashEachMethods:
|
|
154
|
-
Enabled: true
|
|
155
|
-
|
|
156
|
-
Style/HashTransformKeys:
|
|
157
|
-
Enabled: true
|
|
158
|
-
|
|
159
|
-
Style/HashTransformValues:
|
|
160
|
-
Enabled: true
|
data/.sourcelevel.yml
DELETED
data/.travis.yml
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
sudo: false
|
|
2
|
-
language: ruby
|
|
3
|
-
env:
|
|
4
|
-
global:
|
|
5
|
-
- CC_TEST_REPORTER_ID=cf3977cb8c335147723d765c91877e0506ba43e56a22a0dc5b83d7fb969cf5e4
|
|
6
|
-
rvm:
|
|
7
|
-
- 2.6.3
|
|
8
|
-
before_install:
|
|
9
|
-
gem install bundler -v 2.1.4
|
|
10
|
-
before_script:
|
|
11
|
-
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
|
12
|
-
- chmod +x ./cc-test-reporter
|
|
13
|
-
- ./cc-test-reporter before-build
|
|
14
|
-
after_script:
|
|
15
|
-
- ./cc-test-reporter after-build -t simplecov --exit-code $TRAVIS_TEST_RESULT
|
|
16
|
-
script:
|
|
17
|
-
- bundle exec rubocop --fail-level warning --display-only-fail-level-offenses
|
|
18
|
-
- bundle exec rspec
|
data/CODE_OF_CONDUCT.md
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
# Contributor Covenant Code of Conduct
|
|
2
|
-
|
|
3
|
-
## Our Pledge
|
|
4
|
-
|
|
5
|
-
In the interest of fostering an open and welcoming environment, we as
|
|
6
|
-
contributors and maintainers pledge to making participation in our project and
|
|
7
|
-
our community a harassment-free experience for everyone, regardless of age, body
|
|
8
|
-
size, disability, ethnicity, gender identity and expression, level of experience,
|
|
9
|
-
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
-
orientation.
|
|
11
|
-
|
|
12
|
-
## Our Standards
|
|
13
|
-
|
|
14
|
-
Examples of behavior that contributes to creating a positive environment
|
|
15
|
-
include:
|
|
16
|
-
|
|
17
|
-
* Using welcoming and inclusive language
|
|
18
|
-
* Being respectful of differing viewpoints and experiences
|
|
19
|
-
* Gracefully accepting constructive criticism
|
|
20
|
-
* Focusing on what is best for the community
|
|
21
|
-
* Showing empathy towards other community members
|
|
22
|
-
|
|
23
|
-
Examples of unacceptable behavior by participants include:
|
|
24
|
-
|
|
25
|
-
* The use of sexualized language or imagery and unwelcome sexual attention or
|
|
26
|
-
advances
|
|
27
|
-
* Trolling, insulting/derogatory comments, and personal or political attacks
|
|
28
|
-
* Public or private harassment
|
|
29
|
-
* Publishing others' private information, such as a physical or electronic
|
|
30
|
-
address, without explicit permission
|
|
31
|
-
* Other conduct which could reasonably be considered inappropriate in a
|
|
32
|
-
professional setting
|
|
33
|
-
|
|
34
|
-
## Our Responsibilities
|
|
35
|
-
|
|
36
|
-
Project maintainers are responsible for clarifying the standards of acceptable
|
|
37
|
-
behavior and are expected to take appropriate and fair corrective action in
|
|
38
|
-
response to any instances of unacceptable behavior.
|
|
39
|
-
|
|
40
|
-
Project maintainers have the right and responsibility to remove, edit, or
|
|
41
|
-
reject comments, commits, code, wiki edits, issues, and other contributions
|
|
42
|
-
that are not aligned to this Code of Conduct, or to ban temporarily or
|
|
43
|
-
permanently any contributor for other behaviors that they deem inappropriate,
|
|
44
|
-
threatening, offensive, or harmful.
|
|
45
|
-
|
|
46
|
-
## Scope
|
|
47
|
-
|
|
48
|
-
This Code of Conduct applies both within project spaces and in public spaces
|
|
49
|
-
when an individual is representing the project or its community. Examples of
|
|
50
|
-
representing a project or community include using an official project e-mail
|
|
51
|
-
address, posting via an official social media account, or acting as an appointed
|
|
52
|
-
representative at an online or offline event. Representation of a project may be
|
|
53
|
-
further defined and clarified by project maintainers.
|
|
54
|
-
|
|
55
|
-
## Enforcement
|
|
56
|
-
|
|
57
|
-
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
58
|
-
reported by contacting the project team at jonatas.paganini@toptal.com. All
|
|
59
|
-
complaints will be reviewed and investigated and will result in a response that
|
|
60
|
-
is deemed necessary and appropriate to the circumstances. The project team is
|
|
61
|
-
obligated to maintain confidentiality with regard to the reporter of an incident.
|
|
62
|
-
Further details of specific enforcement policies may be posted separately.
|
|
63
|
-
|
|
64
|
-
Project maintainers who do not follow or enforce the Code of Conduct in good
|
|
65
|
-
faith may face temporary or permanent repercussions as determined by other
|
|
66
|
-
members of the project's leadership.
|
|
67
|
-
|
|
68
|
-
## Attribution
|
|
69
|
-
|
|
70
|
-
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
71
|
-
available at [http://contributor-covenant.org/version/1/4][version]
|
|
72
|
-
|
|
73
|
-
[homepage]: http://contributor-covenant.org
|
|
74
|
-
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
DELETED
data/Guardfile
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# A sample Guardfile
|
|
4
|
-
# More info at https://github.com/guard/guard#readme
|
|
5
|
-
|
|
6
|
-
## Uncomment and set this to only include directories you want to watch
|
|
7
|
-
# directories %w(app lib config test spec features) \
|
|
8
|
-
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
|
9
|
-
|
|
10
|
-
## Note: if you are using the `directories` clause above and you are not
|
|
11
|
-
## watching the project directory ('.'), then you will want to move
|
|
12
|
-
## the Guardfile to a watched dir and symlink it back, e.g.
|
|
13
|
-
#
|
|
14
|
-
# $ mkdir config
|
|
15
|
-
# $ mv Guardfile config/
|
|
16
|
-
# $ ln -s config/Guardfile .
|
|
17
|
-
#
|
|
18
|
-
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
|
19
|
-
|
|
20
|
-
guard 'livereload' do
|
|
21
|
-
watch(%r{lib/.+\.rb$})
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
guard :rspec, cmd: 'bundle exec rspec' do
|
|
25
|
-
require 'guard/rspec/dsl'
|
|
26
|
-
dsl = Guard::RSpec::Dsl.new(self)
|
|
27
|
-
|
|
28
|
-
# Feel free to open issues for suggestions and improvements
|
|
29
|
-
|
|
30
|
-
# RSpec files
|
|
31
|
-
rspec = dsl.rspec
|
|
32
|
-
watch(rspec.spec_helper) { rspec.spec_dir }
|
|
33
|
-
watch(rspec.spec_support) { rspec.spec_dir }
|
|
34
|
-
watch(rspec.spec_files)
|
|
35
|
-
|
|
36
|
-
# Ruby files
|
|
37
|
-
ruby = dsl.ruby
|
|
38
|
-
dsl.watch_spec_files_for(ruby.lib_files)
|
|
39
|
-
end
|
data/Rakefile
DELETED
data/TODO.md
DELETED
data/fast.gemspec
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
lib = File.expand_path('lib', __dir__)
|
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
-
require 'fast/version'
|
|
6
|
-
|
|
7
|
-
Gem::Specification.new do |spec|
|
|
8
|
-
spec.name = 'ffast'
|
|
9
|
-
spec.version = Fast::VERSION
|
|
10
|
-
spec.required_ruby_version = '>= 2.6'
|
|
11
|
-
spec.authors = ['Jônatas Davi Paganini']
|
|
12
|
-
spec.email = ['jonatasdp@gmail.com']
|
|
13
|
-
spec.homepage = 'https://jonatas.github.io/fast/'
|
|
14
|
-
|
|
15
|
-
spec.summary = 'FAST: Find by AST.'
|
|
16
|
-
spec.description = 'Allow you to search for code using node pattern syntax.'
|
|
17
|
-
spec.license = 'MIT'
|
|
18
|
-
|
|
19
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
20
|
-
f.match(%r{^(test|spec|experiments|examples|features|docs|assets|stylesheets|site)/})
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
spec.post_install_message = <<~THANKS
|
|
24
|
-
|
|
25
|
-
==========================================================
|
|
26
|
-
Yay! Thanks for installing
|
|
27
|
-
|
|
28
|
-
___ __ ___
|
|
29
|
-
|__ /\ /__` |
|
|
30
|
-
| /~~\ .__/ |
|
|
31
|
-
|
|
32
|
-
To interactive learn about the gem in the terminal use:
|
|
33
|
-
|
|
34
|
-
fast .intro
|
|
35
|
-
|
|
36
|
-
More docs at: https://jonatas.github.io/fast/
|
|
37
|
-
==========================================================
|
|
38
|
-
|
|
39
|
-
THANKS
|
|
40
|
-
|
|
41
|
-
spec.bindir = 'bin'
|
|
42
|
-
spec.executables = %w[fast fast-experiment]
|
|
43
|
-
spec.require_paths = %w[lib experiments]
|
|
44
|
-
|
|
45
|
-
spec.add_dependency 'coderay'
|
|
46
|
-
spec.add_dependency 'parallel'
|
|
47
|
-
spec.add_dependency 'pg_query'
|
|
48
|
-
|
|
49
|
-
spec.add_development_dependency 'bundler'
|
|
50
|
-
spec.add_development_dependency 'git'
|
|
51
|
-
spec.add_development_dependency 'guard'
|
|
52
|
-
spec.add_development_dependency 'guard-livereload'
|
|
53
|
-
spec.add_development_dependency 'guard-rspec'
|
|
54
|
-
spec.add_development_dependency 'pry'
|
|
55
|
-
spec.add_development_dependency 'rake'
|
|
56
|
-
spec.add_development_dependency 'rspec'
|
|
57
|
-
spec.add_development_dependency 'rspec-its'
|
|
58
|
-
spec.add_development_dependency 'rubocop'
|
|
59
|
-
spec.add_development_dependency 'rubocop-performance'
|
|
60
|
-
spec.add_development_dependency 'rubocop-rspec'
|
|
61
|
-
spec.add_development_dependency 'simplecov'
|
|
62
|
-
end
|
data/ideia_blog_post.md
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# Empowering LLM Agents with Natural Language to Fast Patterns
|
|
2
|
-
|
|
3
|
-
Today I'm excited to announce a significant set of improvements to `fast`, specifically designed to bridge the gap between human reasoning (and LLM agents) and the technical precision of Ruby AST searching.
|
|
4
|
-
|
|
5
|
-
## The Problem: AST Patterns are Hard
|
|
6
|
-
|
|
7
|
-
Searching through code using AST patterns is incredibly powerful, but constructing the right S-expression can be daunting. Whether you're a human or an AI agent, getting the syntax just right—especially for complex queries—often involves a lot of trial and error.
|
|
8
|
-
|
|
9
|
-
## The Solution: NL-to-Fast Translation
|
|
10
|
-
|
|
11
|
-
We've introduced three new tools to solve this:
|
|
12
|
-
|
|
13
|
-
1. **The `fast-pattern-expert` Skill**: A specialized Gemini CLI skill that provides deep guidance, syntax references, and few-shot examples for translating structural descriptions of Ruby code into valid `Fast` patterns.
|
|
14
|
-
2. **`validate_fast_pattern` MCP Tool**: A new tool for our Model Context Protocol (MCP) server that allows agents to verify their generated patterns before executing them.
|
|
15
|
-
3. **`--validate-pattern` CLI Flag**: A quick way for humans to check if their pattern syntax is correct, checking for balanced nesting and valid token types.
|
|
16
|
-
|
|
17
|
-
### Example in Action:
|
|
18
|
-
**Query:** "Find all classes that inherit from `BaseService` and have a `call` method."
|
|
19
|
-
**Pattern:** `[(class _ (const nil BaseService)) (def call)]`
|
|
20
|
-
|
|
21
|
-
## Robustness and Precision
|
|
22
|
-
|
|
23
|
-
We've also beefed up the core of `fast`:
|
|
24
|
-
- **Stricter Validation**: The `ExpressionParser` now tracks nesting levels and unconsumed tokens, providing helpful error messages instead of silently failing or returning partial matches.
|
|
25
|
-
- **Improved `...` Matcher**: The `...` literal now acts as a "rest-of-children" matcher when used at the end of a pattern, making it much easier to match methods with any number of arguments.
|
|
26
|
-
- **Graceful Degradation**: Multi-file scans (`.scan`) now degrade gracefully if a single file fails to parse, ensuring your reconnaissance isn't aborted by one unsupported syntax node.
|
|
27
|
-
|
|
28
|
-
## A Safer Release Workflow
|
|
29
|
-
|
|
30
|
-
On the operational side, I'm moving our gem release process to **GitHub Actions**. By releasing from a clean CI sandbox instead of my local machine, we ensure a much higher level of security and reproducibility. This move minimizes the risk of local environment contamination and provides a transparent, auditable path from source to RubyGems.
|
|
31
|
-
|
|
32
|
-
## Release 0.2.4
|
|
33
|
-
|
|
34
|
-
To celebrate these features, we are releasing version `0.2.4` today!
|
|
35
|
-
|
|
36
|
-
Happy searching!
|
data/mkdocs.yml
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
site_name: Fast
|
|
2
|
-
repo_url: https://github.com/jonatas/fast
|
|
3
|
-
edit_uri: edit/master/docs/
|
|
4
|
-
|
|
5
|
-
extra:
|
|
6
|
-
analytics:
|
|
7
|
-
provider: google
|
|
8
|
-
property: G-YKZDZDNRG2
|
|
9
|
-
|
|
10
|
-
theme:
|
|
11
|
-
name: material
|
|
12
|
-
palette:
|
|
13
|
-
primary: indigo
|
|
14
|
-
accent: pink
|
|
15
|
-
logo: assets/logo.png
|
|
16
|
-
favicon: assets/favicon.png
|
|
17
|
-
extra_css:
|
|
18
|
-
- stylesheets/custom.css
|
|
19
|
-
|
|
20
|
-
plugins:
|
|
21
|
-
- search
|
|
22
|
-
|
|
23
|
-
markdown_extensions:
|
|
24
|
-
- admonition
|
|
25
|
-
- pymdownx.details
|
|
26
|
-
- pymdownx.superfences
|
|
27
|
-
- pymdownx.tabbed:
|
|
28
|
-
alternate_style: true
|
|
29
|
-
- toc:
|
|
30
|
-
permalink: true
|
|
31
|
-
nav:
|
|
32
|
-
- Introduction: index.md
|
|
33
|
-
- Walkthrough: walkthrough.md
|
|
34
|
-
- Syntax: syntax.md
|
|
35
|
-
- Command Line: command_line.md
|
|
36
|
-
- Experiments: experiments.md
|
|
37
|
-
- Shortcuts: shortcuts.md
|
|
38
|
-
- Git Integration: git.md
|
|
39
|
-
- Fast for LLMs and Agents: agents.md
|
|
40
|
-
- MCP Server Tutorial: mcp_tutorial.md
|
|
41
|
-
- Code Similarity: similarity_tutorial.md
|
|
42
|
-
- LLM/Agent Feature TODOs: llm_features.md
|
|
43
|
-
- Pry Integration: pry-integration.md
|
|
44
|
-
- Editors' Integration: editors-integration.md
|
|
45
|
-
- Research: research.md
|
|
46
|
-
- Ideas: ideas.md
|
|
47
|
-
- Videos: videos.md
|
|
48
|
-
- SQL:
|
|
49
|
-
- Intro: sql/index.md
|
|
50
|
-
- Shortcuts: sql/shortcuts.md
|
|
51
|
-
- About: sql-support.md
|
data/requirements-docs.txt
DELETED