ffast 0.2.3 → 0.2.6
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/.agents/fast-pattern-expert/SKILL.md +71 -0
- data/Fastfile +4 -4
- data/README.md +14 -14
- data/fast.gemspec +4 -3
- data/lib/fast/cli.rb +48 -14
- data/lib/fast/mcp_server.rb +24 -0
- data/lib/fast/prism_adapter.rb +23 -6
- data/lib/fast/scan.rb +7 -3
- data/lib/fast/summary.rb +6 -1
- data/lib/fast/version.rb +1 -1
- data/lib/fast.rb +80 -21
- metadata +4 -17
- 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/Gemfile +0 -6
- data/Guardfile +0 -39
- data/Rakefile +0 -8
- data/TODO.md +0 -3
- 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: 95125c92ee4201a508f422f041be2a63aebe3a92a19ca303d85b1be98ab6f1e0
|
|
4
|
+
data.tar.gz: 137a7d81790b9f51aaeea271d4d803b6b33a158f7f4b9f4c8a007a23131e6f05
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9b1cb25bf21ef812530856cd778b8d875df7498bc9aaa6576c215964c75dc189131f8fdb539b18eec54b8c44fc3033099b74d457135f77feeff6d5f1ebb34405
|
|
7
|
+
data.tar.gz: 256b3549dd55c412ad1a5d2d84b7d284f4fb94f10096f56a02391ae4e67f4e40894ad1816ab997f7dd08b99b36aa90b9eb68ce3101fa8bba0fb0ba7185329761
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Skill: Fast Pattern Expert
|
|
2
|
+
|
|
3
|
+
You are an expert in constructing and translating natural language queries into `Fast` AST patterns for Ruby.
|
|
4
|
+
|
|
5
|
+
## Core Expertise
|
|
6
|
+
- Translating structural descriptions of Ruby code into S-expression based AST patterns.
|
|
7
|
+
- Understanding the Ruby AST (Prism/Parser based).
|
|
8
|
+
- Navigating and searching codebases semantically using `Fast`.
|
|
9
|
+
|
|
10
|
+
## Syntax Reference
|
|
11
|
+
- `(node_type ...)` : Search for a node of a specific type.
|
|
12
|
+
- `_` : Matches any non-nil node/value.
|
|
13
|
+
- `nil` : Matches exactly `nil`.
|
|
14
|
+
- `...` : When last in a list, matches zero or more remaining children. Elsewhere, matches a node with children.
|
|
15
|
+
- `^` : Navigate to the parent node.
|
|
16
|
+
- `$` : Capture the matched node or value.
|
|
17
|
+
- `{type1 type2}` : Union (OR) - matches if any internal expression matches.
|
|
18
|
+
- `[expr1 expr2]` : Intersection (AND) - matches only if all internal expressions match.
|
|
19
|
+
- `!expr` : Negation (NOT) - matches if the expression does not match.
|
|
20
|
+
- `?expr` : Maybe - matches if the node is nil or matches the expression.
|
|
21
|
+
- `\1`, `\2` : Backreference to previous captures.
|
|
22
|
+
- `#custom_method` : Call a custom Ruby method for validation.
|
|
23
|
+
- `.instance_method?` : Call an instance method on the node for validation (e.g., `.odd?`).
|
|
24
|
+
|
|
25
|
+
## Common Ruby AST Nodes
|
|
26
|
+
- `(def name (args) body)` : Method definition.
|
|
27
|
+
- `(defs receiver name (args) body)` : Singleton method definition.
|
|
28
|
+
- `(send receiver method_name args...)` : Method call.
|
|
29
|
+
- `(class name superclass body)` : Class definition.
|
|
30
|
+
- `(module name body)` : Module definition.
|
|
31
|
+
- `(const scope name)` : Constant reference (scope is nil for top-level).
|
|
32
|
+
- `(casgn scope name value)` : Constant assignment.
|
|
33
|
+
- `(lvar name)` : Local variable read.
|
|
34
|
+
- `(lvasgn name value)` : Local variable assignment.
|
|
35
|
+
- `(ivar name)` : Instance variable read.
|
|
36
|
+
- `(ivasgn name value)` : Instance variable assignment.
|
|
37
|
+
- `(hash (pair key value)...)` : Hash literal.
|
|
38
|
+
- `(array elements...)` : Array literal.
|
|
39
|
+
|
|
40
|
+
## Translation Examples
|
|
41
|
+
|
|
42
|
+
### Methods
|
|
43
|
+
- "Find all methods named 'process'" -> `(def process)`
|
|
44
|
+
- "Find methods with at least 3 arguments" -> `(def _ (args _ _ _ ...))`
|
|
45
|
+
- "Find singleton methods (self.method)" -> `(defs ...)`
|
|
46
|
+
- "Find methods that call 'super'" -> `(def _ _ (send nil :super ...))`
|
|
47
|
+
|
|
48
|
+
### Classes & Modules
|
|
49
|
+
- "Find classes inheriting from ApplicationController" -> `(class _ (const nil ApplicationController))`
|
|
50
|
+
- "Find classes defined inside the 'User' namespace" -> `(class (const (const nil User) _) ...)`
|
|
51
|
+
- "Find modules that include 'Enumerable'" -> `(module _ (begin < (send nil include (const nil Enumerable)) ...))`
|
|
52
|
+
|
|
53
|
+
### Method Calls
|
|
54
|
+
- "Find all calls to 'User.find'" -> `(send (const nil User) find ...)`
|
|
55
|
+
- "Find calls to 'where' with a hash argument" -> `(send _ where (hash ...))`
|
|
56
|
+
- "Find calls to 'exit' or 'abort'" -> `(send nil {exit abort} ...)`
|
|
57
|
+
|
|
58
|
+
### Variables & Constants
|
|
59
|
+
- "Find where the 'DEBUG' constant is assigned" -> `(casgn nil DEBUG)`
|
|
60
|
+
- "Find all uses of instance variable '@user'" -> `(ivar @user)`
|
|
61
|
+
- "Find assignments to '@user'" -> `(ivasgn @user)`
|
|
62
|
+
|
|
63
|
+
## Strategy for Complex Queries
|
|
64
|
+
1. **Identify the anchor node**: What is the primary structure? (e.g., a method definition, a specific call).
|
|
65
|
+
2. **Describe children**: What must be true about its arguments or body?
|
|
66
|
+
3. **Use Union/Intersection**: Combine multiple constraints using `{}` or `[]`.
|
|
67
|
+
4. **Capture if needed**: Use `$` if you only want a specific part of the match.
|
|
68
|
+
5. **Validate**: Always use `validate_fast_pattern` if available to check syntax.
|
|
69
|
+
|
|
70
|
+
## AST Triage
|
|
71
|
+
If you are unsure of the AST structure for a piece of code, use `Fast.ast("your code snippet")` or `Fast.ast_from_file` to see the s-expression representation. This is the most reliable way to build a pattern.
|
data/Fastfile
CHANGED
|
@@ -15,7 +15,7 @@ version_file = Dir['lib/*/version.rb'].first
|
|
|
15
15
|
Fast.shortcut(:version, '(casgn nil VERSION (str _))', version_file)
|
|
16
16
|
|
|
17
17
|
# Show all classes that inherits Fast::Find
|
|
18
|
-
Fast.shortcut(:finders, '(class ... (const nil Find)', 'lib')
|
|
18
|
+
Fast.shortcut(:finders, '(class ... (const nil Find))', 'lib')
|
|
19
19
|
|
|
20
20
|
# You can run shortcuts appending a dot to the shortcut.
|
|
21
21
|
# $ fast .version
|
|
@@ -23,13 +23,13 @@ Fast.shortcut(:finders, '(class ... (const nil Find)', 'lib')
|
|
|
23
23
|
# VERSION = '0.1.2'
|
|
24
24
|
|
|
25
25
|
# Simple shortcut that I used often to show how the expression parser works
|
|
26
|
-
Fast.shortcut(:parser, '(class (const nil ExpressionParser)', 'lib/fast.rb')
|
|
27
|
-
Fast.shortcut(:sql_parser, '(def parse', 'lib/fast/sql.rb')
|
|
26
|
+
Fast.shortcut(:parser, '(class (const nil ExpressionParser))', 'lib/fast.rb')
|
|
27
|
+
Fast.shortcut(:sql_parser, '(def parse ...)', 'lib/fast/sql.rb')
|
|
28
28
|
|
|
29
29
|
# Use `fast .bump_version` to rewrite the version file
|
|
30
30
|
Fast.shortcut :bump_version do
|
|
31
31
|
new_version = nil
|
|
32
|
-
rewrite_file('(casgn nil VERSION (str _)', version_file) do |node|
|
|
32
|
+
rewrite_file('(casgn nil VERSION (str _))', version_file) do |node|
|
|
33
33
|
target = node.children.last.loc.expression
|
|
34
34
|
pieces = target.source.split('.').map(&:to_i)
|
|
35
35
|
pieces.reverse.each_with_index do |fragment, i|
|
data/README.md
CHANGED
|
@@ -12,20 +12,6 @@ the code was written without an AST.
|
|
|
12
12
|
|
|
13
13
|
Check out the official documentation: https://jonatas.github.io/fast.
|
|
14
14
|
|
|
15
|
-
## Documentation locally
|
|
16
|
-
|
|
17
|
-
The documentation site is built with MkDocs Material and a few Markdown
|
|
18
|
-
extensions. To run it locally:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
python3 -m venv .venv
|
|
22
|
-
source .venv/bin/activate
|
|
23
|
-
python3 -m pip install -r requirements-docs.txt
|
|
24
|
-
mkdocs serve
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Then open `http://127.0.0.1:8000`.
|
|
28
|
-
|
|
29
15
|
## Token Syntax for `find` in AST
|
|
30
16
|
|
|
31
17
|
The current version of Fast covers the following token elements:
|
|
@@ -694,6 +680,20 @@ code("a = 1") # => s(:lvasgn, s(:int, 1))
|
|
|
694
680
|
|
|
695
681
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
696
682
|
|
|
683
|
+
## Documentation locally
|
|
684
|
+
|
|
685
|
+
The documentation site is built with MkDocs Material and a few Markdown
|
|
686
|
+
extensions. To run it locally:
|
|
687
|
+
|
|
688
|
+
```bash
|
|
689
|
+
python3 -m venv .venv
|
|
690
|
+
source .venv/bin/activate
|
|
691
|
+
python3 -m pip install -r requirements-docs.txt
|
|
692
|
+
mkdocs serve
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
Then open `http://127.0.0.1:8000`.
|
|
696
|
+
|
|
697
697
|
## Contributing
|
|
698
698
|
|
|
699
699
|
Bug reports and pull requests are welcome on GitHub at https://github.com/jonatas/fast. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
data/fast.gemspec
CHANGED
|
@@ -17,7 +17,8 @@ Gem::Specification.new do |spec|
|
|
|
17
17
|
spec.license = 'MIT'
|
|
18
18
|
|
|
19
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)/})
|
|
20
|
+
f.match(%r{^(test|spec|experiments|examples|features|docs|assets|stylesheets|site)/}) ||
|
|
21
|
+
f.match(%r{^(\.git|\.github|\.travis|\.sourcelevel|\.rubocop|\.projections|\.rspec|Gemfile|Rakefile|Guardfile|mkdocs|requirements-docs|TODO|ideia_blog_post)})
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
spec.post_install_message = <<~THANKS
|
|
@@ -39,8 +40,8 @@ Gem::Specification.new do |spec|
|
|
|
39
40
|
THANKS
|
|
40
41
|
|
|
41
42
|
spec.bindir = 'bin'
|
|
42
|
-
spec.executables = %w[fast fast-experiment]
|
|
43
|
-
spec.require_paths = %w[lib
|
|
43
|
+
spec.executables = %w[fast fast-experiment fast-mcp]
|
|
44
|
+
spec.require_paths = %w[lib]
|
|
44
45
|
|
|
45
46
|
spec.add_dependency 'coderay'
|
|
46
47
|
spec.add_dependency 'parallel'
|
data/lib/fast/cli.rb
CHANGED
|
@@ -12,6 +12,12 @@ require 'ostruct'
|
|
|
12
12
|
# It defines #report and #highlight functions that can be used to pretty print
|
|
13
13
|
# code and results from the search.
|
|
14
14
|
module Fast
|
|
15
|
+
module SymbolExtension
|
|
16
|
+
def loc
|
|
17
|
+
OpenStruct.new(expression: OpenStruct.new(line: 0))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
15
21
|
module_function
|
|
16
22
|
|
|
17
23
|
# Highligh some source code based on the node.
|
|
@@ -20,19 +26,19 @@ module Fast
|
|
|
20
26
|
# @param colorize [Boolean] skips `CodeRay` processing when false.
|
|
21
27
|
# @param level [Integer] defines the max depth to print the AST.
|
|
22
28
|
def highlight(node, show_sexp: false, colorize: true, sql: false, level: nil)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
else
|
|
28
|
-
wrap_source_range(node).source
|
|
29
|
-
end
|
|
30
|
-
elsif show_sexp && level && Fast.ast_node?(node)
|
|
31
|
-
Fast.fold_ast(node, level: level).to_s
|
|
32
|
-
elsif show_sexp
|
|
33
|
-
node.to_s
|
|
29
|
+
output =
|
|
30
|
+
if node.respond_to?(:loc) && !show_sexp
|
|
31
|
+
if level
|
|
32
|
+
Fast.fold_source(node, level: level)
|
|
34
33
|
else
|
|
35
|
-
node
|
|
34
|
+
wrap_source_range(node).source
|
|
35
|
+
end
|
|
36
|
+
elsif show_sexp && level && Fast.ast_node?(node)
|
|
37
|
+
Fast.fold_ast(node, level: level).to_s
|
|
38
|
+
elsif show_sexp
|
|
39
|
+
node.to_s
|
|
40
|
+
else
|
|
41
|
+
node.to_s
|
|
36
42
|
end
|
|
37
43
|
return output unless colorize
|
|
38
44
|
|
|
@@ -78,6 +84,9 @@ module Fast
|
|
|
78
84
|
# Fast.report(result, file: 'file.rb')
|
|
79
85
|
def report(result, show_link: false, show_permalink: false, show_sexp: false, file: nil, headless: false, bodyless: false, colorize: true, level: nil) # rubocop:disable Metrics/ParameterLists
|
|
80
86
|
if file
|
|
87
|
+
if result.is_a?(Symbol) && !result.respond_to?(:loc)
|
|
88
|
+
result.extend(SymbolExtension)
|
|
89
|
+
end
|
|
81
90
|
line = result.loc.expression.line if Fast.ast_node?(result) && result.respond_to?(:loc)
|
|
82
91
|
if show_link
|
|
83
92
|
puts(result.link)
|
|
@@ -97,8 +106,23 @@ module Fast
|
|
|
97
106
|
args = args.dup
|
|
98
107
|
args = replace_args_with_shortcut(args) if shortcut_name_from(args)
|
|
99
108
|
@colorize = STDOUT.isatty
|
|
100
|
-
|
|
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)
|
|
101
124
|
@pattern, @files = extract_pattern_and_files(args)
|
|
125
|
+
puts "DEBUG: pattern=#{@pattern.inspect} files=#{@files.inspect}" if @debug
|
|
102
126
|
|
|
103
127
|
@sql ||= @files.any? && @files.all? { |file| file.end_with?('.sql') }
|
|
104
128
|
require 'fast/sql' if @sql
|
|
@@ -137,7 +161,7 @@ module Fast
|
|
|
137
161
|
@sql = true
|
|
138
162
|
end
|
|
139
163
|
|
|
140
|
-
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
|
|
141
165
|
@captures = true
|
|
142
166
|
end
|
|
143
167
|
|
|
@@ -166,6 +190,16 @@ module Fast
|
|
|
166
190
|
@from_code = true
|
|
167
191
|
end
|
|
168
192
|
|
|
193
|
+
opts.on('--validate-pattern PATTERN', 'Validate a node pattern') do |pattern|
|
|
194
|
+
begin
|
|
195
|
+
Fast.expression(pattern)
|
|
196
|
+
puts "Pattern is valid."
|
|
197
|
+
rescue StandardError => e
|
|
198
|
+
puts "Invalid pattern: #{e.message}"
|
|
199
|
+
end
|
|
200
|
+
exit
|
|
201
|
+
end
|
|
202
|
+
|
|
169
203
|
opts.on_tail('--version', 'Show version') do
|
|
170
204
|
puts Fast::VERSION
|
|
171
205
|
exit
|
data/lib/fast/mcp_server.rb
CHANGED
|
@@ -10,6 +10,17 @@ module Fast
|
|
|
10
10
|
# Implements the Model Context Protocol (MCP) server over STDIO.
|
|
11
11
|
class McpServer
|
|
12
12
|
TOOLS = [
|
|
13
|
+
{
|
|
14
|
+
name: 'validate_fast_pattern',
|
|
15
|
+
description: 'Validate a Fast AST pattern. Returns true if valid, or a specific syntax error message if invalid.',
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
pattern: { type: 'string', description: 'Fast AST pattern to validate.' }
|
|
20
|
+
},
|
|
21
|
+
required: ['pattern']
|
|
22
|
+
}
|
|
23
|
+
},
|
|
13
24
|
{
|
|
14
25
|
name: 'search_ruby_ast',
|
|
15
26
|
description: 'Search Ruby files using a Fast AST pattern. Returns file, line range, and source. Use show_ast=true only when you need the s-expression.',
|
|
@@ -146,8 +157,14 @@ module Fast
|
|
|
146
157
|
args = params['arguments'] || {}
|
|
147
158
|
show_ast = args['show_ast'] || false
|
|
148
159
|
|
|
160
|
+
if args['pattern'] && !args['pattern'].start_with?('(', '{', '[') && !args['pattern'].match?(/^[a-z_]+$/)
|
|
161
|
+
raise "Invalid Fast AST pattern: '#{args['pattern']}'. Did you mean to use an s-expression like '(#{args['pattern']})'?"
|
|
162
|
+
end
|
|
163
|
+
|
|
149
164
|
result =
|
|
150
165
|
case tool_name
|
|
166
|
+
when 'validate_fast_pattern'
|
|
167
|
+
execute_validate_pattern(args['pattern'])
|
|
151
168
|
when 'search_ruby_ast'
|
|
152
169
|
execute_search(args['pattern'], args['paths'], show_ast: show_ast)
|
|
153
170
|
when 'ruby_method_source'
|
|
@@ -170,6 +187,13 @@ module Fast
|
|
|
170
187
|
write_error(id, -32603, 'Tool execution failed', e.message)
|
|
171
188
|
end
|
|
172
189
|
|
|
190
|
+
def execute_validate_pattern(pattern)
|
|
191
|
+
Fast.expression(pattern)
|
|
192
|
+
{ valid: true }
|
|
193
|
+
rescue StandardError => e
|
|
194
|
+
{ valid: false, error: e.message }
|
|
195
|
+
end
|
|
196
|
+
|
|
173
197
|
def execute_search(pattern, paths, show_ast: false)
|
|
174
198
|
results = []
|
|
175
199
|
on_result = ->(file, matches) do
|
data/lib/fast/prism_adapter.rb
CHANGED
|
@@ -135,8 +135,12 @@ module Fast
|
|
|
135
135
|
build_node(:sym, [node.unescaped], node, source, buffer_name)
|
|
136
136
|
when Prism::StringNode
|
|
137
137
|
build_node(:str, [node.unescaped], node, source, buffer_name)
|
|
138
|
+
when Prism::XStringNode
|
|
139
|
+
build_node(:xstr, [node.unescaped], node, source, buffer_name)
|
|
138
140
|
when Prism::InterpolatedStringNode
|
|
139
141
|
build_node(:dstr, node.parts.filter_map { |part| adapt(part, source, buffer_name) }, node, source, buffer_name)
|
|
142
|
+
when Prism::InterpolatedXStringNode
|
|
143
|
+
build_node(:dxstr, node.parts.filter_map { |part| adapt(part, source, buffer_name) }, node, source, buffer_name)
|
|
140
144
|
when Prism::InterpolatedSymbolNode
|
|
141
145
|
build_node(:dsym, node.parts.filter_map { |part| adapt(part, source, buffer_name) }, node, source, buffer_name)
|
|
142
146
|
when Prism::ArrayNode
|
|
@@ -183,6 +187,8 @@ module Fast
|
|
|
183
187
|
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)
|
|
184
188
|
when Prism::UnlessNode
|
|
185
189
|
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)
|
|
190
|
+
when Prism::RescueModifierNode
|
|
191
|
+
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)
|
|
186
192
|
when Prism::CaseNode
|
|
187
193
|
children = [adapt(node.predicate, source, buffer_name)]
|
|
188
194
|
children.concat(node.conditions.map { |condition| adapt(condition, source, buffer_name) })
|
|
@@ -231,10 +237,10 @@ module Fast
|
|
|
231
237
|
return build_node(:args, [], nil, source, buffer_name) unless node
|
|
232
238
|
|
|
233
239
|
children = []
|
|
234
|
-
children.concat(node.requireds.map { |child|
|
|
235
|
-
children.concat(node.optionals.map { |child| build_node(:optarg, [child
|
|
240
|
+
children.concat(node.requireds.map { |child| adapt_required_parameter(child, source, buffer_name) }) if node.respond_to?(:requireds)
|
|
241
|
+
children.concat(node.optionals.map { |child| build_node(:optarg, [parameter_name(child), adapt(child.value, source, buffer_name)], child, source, buffer_name) }) if node.respond_to?(:optionals)
|
|
236
242
|
children << build_node(:restarg, [parameter_name(node.rest)], node.rest, source, buffer_name) if node.respond_to?(:rest) && node.rest
|
|
237
|
-
children.concat(node.posts.map { |child|
|
|
243
|
+
children.concat(node.posts.map { |child| adapt_required_parameter(child, source, buffer_name) }) if node.respond_to?(:posts)
|
|
238
244
|
children.concat(node.keywords.map { |child| adapt_keyword_parameter(child, source, buffer_name) }) if node.respond_to?(:keywords)
|
|
239
245
|
children << build_node(:kwrestarg, [parameter_name(node.keyword_rest)], node.keyword_rest, source, buffer_name) if node.respond_to?(:keyword_rest) && node.keyword_rest
|
|
240
246
|
children << build_node(:blockarg, [parameter_name(node.block)], node.block, source, buffer_name) if node.respond_to?(:block) && node.block
|
|
@@ -248,14 +254,25 @@ module Fast
|
|
|
248
254
|
adapt_parameters(params, source, buffer_name)
|
|
249
255
|
end
|
|
250
256
|
|
|
257
|
+
def adapt_required_parameter(child, source, buffer_name)
|
|
258
|
+
if child.is_a?(Prism::MultiTargetNode)
|
|
259
|
+
mlhs_children = child.lefts.map { |c| adapt_required_parameter(c, source, buffer_name) }
|
|
260
|
+
mlhs_children << build_node(:restarg, [parameter_name(child.rest)], child.rest, source, buffer_name) if child.respond_to?(:rest) && child.rest
|
|
261
|
+
mlhs_children.concat(child.rights.map { |c| adapt_required_parameter(c, source, buffer_name) }) if child.respond_to?(:rights)
|
|
262
|
+
build_node(:mlhs, mlhs_children, child, source, buffer_name)
|
|
263
|
+
else
|
|
264
|
+
build_node(:arg, [parameter_name(child)], child, source, buffer_name)
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
251
268
|
def adapt_keyword_parameter(node, source, buffer_name)
|
|
252
269
|
case node
|
|
253
270
|
when Prism::RequiredKeywordParameterNode
|
|
254
|
-
build_node(:kwarg, [node
|
|
271
|
+
build_node(:kwarg, [parameter_name(node)], node, source, buffer_name)
|
|
255
272
|
when Prism::OptionalKeywordParameterNode
|
|
256
|
-
build_node(:kwoptarg, [node
|
|
273
|
+
build_node(:kwoptarg, [parameter_name(node), adapt(node.value, source, buffer_name)], node, source, buffer_name)
|
|
257
274
|
else
|
|
258
|
-
build_node(:arg, [node
|
|
275
|
+
build_node(:arg, [parameter_name(node)], node, source, buffer_name)
|
|
259
276
|
end
|
|
260
277
|
end
|
|
261
278
|
|
data/lib/fast/scan.rb
CHANGED
|
@@ -25,10 +25,14 @@ module Fast
|
|
|
25
25
|
def scan
|
|
26
26
|
files = Fast.ruby_files_from(*@locations)
|
|
27
27
|
grouped = files.each_with_object(Hash.new { |hash, key| hash[key] = [] }) do |file, memo|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
begin
|
|
29
|
+
entries = flatten_entries(Fast.summary(IO.read(file), file: file, command_name: @command_name).outline)
|
|
30
|
+
next if entries.empty?
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
memo[classify(file, entries)] << [file, entries]
|
|
33
|
+
rescue StandardError => e
|
|
34
|
+
warn "Error scanning #{file}: #{e.message}" if Fast.debugging
|
|
35
|
+
end
|
|
32
36
|
end
|
|
33
37
|
|
|
34
38
|
print_grouped(grouped)
|
data/lib/fast/summary.rb
CHANGED
|
@@ -21,7 +21,12 @@ module Fast
|
|
|
21
21
|
if unsupported_template?
|
|
22
22
|
nil
|
|
23
23
|
elsif code_or_ast.is_a?(String)
|
|
24
|
-
|
|
24
|
+
begin
|
|
25
|
+
Fast.parse_ruby(code_or_ast, buffer_name: file || '(string)')
|
|
26
|
+
rescue StandardError => e
|
|
27
|
+
warn "Error parsing #{file || 'source'}: #{e.message}" if Fast.debugging
|
|
28
|
+
nil
|
|
29
|
+
end
|
|
25
30
|
else
|
|
26
31
|
code_or_ast
|
|
27
32
|
end
|
data/lib/fast/version.rb
CHANGED
data/lib/fast.rb
CHANGED
|
@@ -220,12 +220,24 @@ module Fast
|
|
|
220
220
|
# @return [Hash[String, Array]] with files and results
|
|
221
221
|
def group_results(group_files, locations, parallel: true)
|
|
222
222
|
files = ruby_files_from(*locations)
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
223
|
+
results =
|
|
224
|
+
if parallel
|
|
225
|
+
require 'parallel' unless defined?(Parallel)
|
|
226
|
+
Parallel.map(files) do |file|
|
|
227
|
+
group_files.call(file)
|
|
228
|
+
rescue StandardError => e
|
|
229
|
+
warn "Error processing #{file}: #{e.message}" if Fast.debugging
|
|
230
|
+
nil
|
|
231
|
+
end
|
|
232
|
+
else
|
|
233
|
+
files.map do |file|
|
|
234
|
+
group_files.call(file)
|
|
235
|
+
rescue StandardError => e
|
|
236
|
+
warn "Error processing #{file}: #{e.message}" if Fast.debugging
|
|
237
|
+
nil
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
results.compact.inject(&:merge!) || {}
|
|
229
241
|
end
|
|
230
242
|
|
|
231
243
|
# Capture elements from searches in files. Keep in mind you need to use `$`
|
|
@@ -275,7 +287,11 @@ module Fast
|
|
|
275
287
|
end
|
|
276
288
|
|
|
277
289
|
def expression(string)
|
|
278
|
-
ExpressionParser.new(string)
|
|
290
|
+
parser = ExpressionParser.new(string)
|
|
291
|
+
res = parser.parse
|
|
292
|
+
raise SyntaxError, parser.error_message if parser.tokens_left?
|
|
293
|
+
|
|
294
|
+
res
|
|
279
295
|
end
|
|
280
296
|
|
|
281
297
|
attr_accessor :debugging
|
|
@@ -444,6 +460,7 @@ module Fast
|
|
|
444
460
|
# @param expression [String]
|
|
445
461
|
def initialize(expression)
|
|
446
462
|
@tokens = expression.scan TOKENIZER
|
|
463
|
+
@nesting = []
|
|
447
464
|
end
|
|
448
465
|
|
|
449
466
|
# rubocop:disable Metrics/CyclomaticComplexity
|
|
@@ -451,22 +468,43 @@ module Fast
|
|
|
451
468
|
# rubocop:disable Metrics/MethodLength
|
|
452
469
|
def parse
|
|
453
470
|
case (token = next_token)
|
|
454
|
-
when '('
|
|
455
|
-
|
|
456
|
-
|
|
471
|
+
when '('
|
|
472
|
+
@nesting << ')'
|
|
473
|
+
parse_until_peek(')')
|
|
474
|
+
when '{'
|
|
475
|
+
@nesting << '}'
|
|
476
|
+
Any.new(parse_until_peek('}'))
|
|
477
|
+
when '['
|
|
478
|
+
@nesting << ']'
|
|
479
|
+
All.new(parse_until_peek(']'))
|
|
480
|
+
when ')', '}', ']'
|
|
481
|
+
raise SyntaxError, "Unexpected token: #{token}"
|
|
457
482
|
when /^"/ then FindString.new(token[1..-2])
|
|
458
483
|
when /^#\w/ then MethodCall.new(token[1..])
|
|
459
484
|
when /^\.\w[\w\d_]+\?/ then InstanceMethodCall.new(token[1..])
|
|
460
485
|
when '$' then Capture.new(parse)
|
|
461
|
-
when '!' then (@tokens.any? ? Not.new(parse) : Find.new(token))
|
|
486
|
+
when '!' then (@tokens.any? && !closing_token?(@tokens.first) ? Not.new(parse) : Find.new(token))
|
|
462
487
|
when '?' then Maybe.new(parse)
|
|
463
488
|
when '^' then Parent.new(parse)
|
|
464
489
|
when '\\' then FindWithCapture.new(parse)
|
|
465
490
|
when /^%\d/ then FindFromArgument.new(token[1..])
|
|
491
|
+
when nil then nil
|
|
466
492
|
else Find.new(token)
|
|
467
493
|
end
|
|
468
494
|
end
|
|
469
495
|
|
|
496
|
+
def tokens_left?
|
|
497
|
+
@tokens.any? || @nesting.any?
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
def error_message
|
|
501
|
+
if @tokens.any?
|
|
502
|
+
"Unconsumed tokens after parsing: #{@tokens.join(' ')}"
|
|
503
|
+
elsif @nesting.any?
|
|
504
|
+
"Unclosed nesting: expected #{@nesting.reverse.join(', ')}"
|
|
505
|
+
end
|
|
506
|
+
end
|
|
507
|
+
|
|
470
508
|
# rubocop:enable Metrics/CyclomaticComplexity
|
|
471
509
|
# rubocop:enable Metrics/AbcSize
|
|
472
510
|
# rubocop:enable Metrics/MethodLength
|
|
@@ -477,10 +515,19 @@ module Fast
|
|
|
477
515
|
@tokens.shift
|
|
478
516
|
end
|
|
479
517
|
|
|
518
|
+
def closing_token?(token)
|
|
519
|
+
[')', '}', ']'].include?(token)
|
|
520
|
+
end
|
|
521
|
+
|
|
480
522
|
def parse_until_peek(token)
|
|
481
523
|
list = []
|
|
482
524
|
list << parse until @tokens.empty? || @tokens.first == token
|
|
483
|
-
next_token
|
|
525
|
+
last = next_token
|
|
526
|
+
if last == token
|
|
527
|
+
@nesting.pop
|
|
528
|
+
else
|
|
529
|
+
raise SyntaxError, "Expected #{token} but got #{last || 'end of string'}"
|
|
530
|
+
end
|
|
484
531
|
list
|
|
485
532
|
end
|
|
486
533
|
end
|
|
@@ -501,10 +548,15 @@ module Fast
|
|
|
501
548
|
case expression
|
|
502
549
|
when Proc then expression.call(node)
|
|
503
550
|
when Find then expression.match?(node)
|
|
504
|
-
when Symbol then compare_symbol_or_head(expression, node)
|
|
505
551
|
when Enumerable
|
|
506
|
-
expression.
|
|
507
|
-
|
|
552
|
+
if expression.last == :'...' || expression.last.is_a?(Find) && expression.last.token == '...'
|
|
553
|
+
expression[0...-1].each_with_index.all? do |exp, i|
|
|
554
|
+
match_recursive(exp, i.zero? ? node : node.children[i - 1])
|
|
555
|
+
end
|
|
556
|
+
else
|
|
557
|
+
expression.each_with_index.all? do |exp, i|
|
|
558
|
+
match_recursive(exp, i.zero? ? node : node.children[i - 1])
|
|
559
|
+
end
|
|
508
560
|
end
|
|
509
561
|
else
|
|
510
562
|
node == expression
|
|
@@ -721,7 +773,7 @@ module Fast
|
|
|
721
773
|
# Fast.expression("{int float}")
|
|
722
774
|
class Any < Find
|
|
723
775
|
def match?(node)
|
|
724
|
-
token.any? { |expression| Fast.match?(expression, node) }
|
|
776
|
+
token.any? { |expression| !!Fast.match?(expression, node) }
|
|
725
777
|
end
|
|
726
778
|
|
|
727
779
|
def to_s
|
|
@@ -732,7 +784,7 @@ module Fast
|
|
|
732
784
|
# Intersect expressions. Works like a **AND** operator.
|
|
733
785
|
class All < Find
|
|
734
786
|
def match?(node)
|
|
735
|
-
token.all? { |expression| expression.match?(node) }
|
|
787
|
+
token.all? { |expression| !!expression.match?(node) }
|
|
736
788
|
end
|
|
737
789
|
|
|
738
790
|
def to_s
|
|
@@ -798,10 +850,17 @@ module Fast
|
|
|
798
850
|
|
|
799
851
|
# @return [true] if all children matches with tail
|
|
800
852
|
def match_tail?(tail, child)
|
|
801
|
-
tail.
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
853
|
+
if tail.last.is_a?(Find) && tail.last.token == '...'
|
|
854
|
+
tail[0...-1].each_with_index.all? do |token, i|
|
|
855
|
+
prepare_token(token)
|
|
856
|
+
token.is_a?(Array) ? match?(token, child[i]) : token.match?(child[i])
|
|
857
|
+
end && find_captures
|
|
858
|
+
else
|
|
859
|
+
tail.each_with_index.all? do |token, i|
|
|
860
|
+
prepare_token(token)
|
|
861
|
+
token.is_a?(Array) ? match?(token, child[i]) : token.match?(child[i])
|
|
862
|
+
end && find_captures
|
|
863
|
+
end
|
|
805
864
|
end
|
|
806
865
|
|
|
807
866
|
# Look recursively into @param expression to check if the expression is have
|
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.6
|
|
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-03-
|
|
11
|
+
date: 2026-03-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: coderay
|
|
@@ -240,25 +240,15 @@ email:
|
|
|
240
240
|
executables:
|
|
241
241
|
- fast
|
|
242
242
|
- fast-experiment
|
|
243
|
+
- fast-mcp
|
|
243
244
|
extensions: []
|
|
244
245
|
extra_rdoc_files: []
|
|
245
246
|
files:
|
|
246
|
-
- ".
|
|
247
|
-
- ".github/workflows/ruby.yml"
|
|
248
|
-
- ".gitignore"
|
|
249
|
-
- ".projections.json"
|
|
250
|
-
- ".rspec"
|
|
251
|
-
- ".rubocop.yml"
|
|
252
|
-
- ".sourcelevel.yml"
|
|
253
|
-
- ".travis.yml"
|
|
247
|
+
- ".agents/fast-pattern-expert/SKILL.md"
|
|
254
248
|
- CODE_OF_CONDUCT.md
|
|
255
249
|
- Fastfile
|
|
256
|
-
- Gemfile
|
|
257
|
-
- Guardfile
|
|
258
250
|
- LICENSE.txt
|
|
259
251
|
- README.md
|
|
260
|
-
- Rakefile
|
|
261
|
-
- TODO.md
|
|
262
252
|
- bin/console
|
|
263
253
|
- bin/fast
|
|
264
254
|
- bin/fast-experiment
|
|
@@ -281,8 +271,6 @@ files:
|
|
|
281
271
|
- lib/fast/sql/rewriter.rb
|
|
282
272
|
- lib/fast/summary.rb
|
|
283
273
|
- lib/fast/version.rb
|
|
284
|
-
- mkdocs.yml
|
|
285
|
-
- requirements-docs.txt
|
|
286
274
|
homepage: https://jonatas.github.io/fast/
|
|
287
275
|
licenses:
|
|
288
276
|
- MIT
|
|
@@ -306,7 +294,6 @@ post_install_message: |2+
|
|
|
306
294
|
rdoc_options: []
|
|
307
295
|
require_paths:
|
|
308
296
|
- lib
|
|
309
|
-
- experiments
|
|
310
297
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
311
298
|
requirements:
|
|
312
299
|
- - ">="
|
|
@@ -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/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/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