-
Notifications
You must be signed in to change notification settings - Fork 10
/
Fastfile
141 lines (124 loc) · 4.12 KB
/
Fastfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# frozen_string_literal: true
# Fastfile is loaded when you start an expression with a dot.
#
# You can introduce shortcuts or methods that can be embedded during your
# command line interactions with fast.
#
# Let's say you'd like to show the version that is over the version file
version_file = Dir['lib/*/version.rb'].first
Fast.shortcut(:version, '(casgn nil VERSION (str _))', version_file)
# Show all classes that inherits Fast::Find
Fast.shortcut(:finders, '(class ... (const nil Find)', 'lib')
# You can run shortcuts appending a dot to the shortcut.
# $ fast .version
# # lib/fast/version.rb:4
# VERSION = '0.1.2'
# Simple shortcut that I used often to show how the expression parser works
Fast.shortcut(:parser, '(class (const nil ExpressionParser)', 'lib/fast.rb')
Fast.shortcut(:sql_parser, '(def parse', 'lib/fast/sql.rb')
# Use `fast .bump_version` to rewrite the version file
Fast.shortcut :bump_version do
rewrite_file('(casgn nil VERSION (str _)', version_file) do |node|
target = node.children.last.loc.expression
pieces = target.source.split('.').map(&:to_i)
pieces.reverse.each_with_index do |fragment, i|
if fragment < 9
pieces[-(i + 1)] = fragment + 1
break
else
pieces[-(i + 1)] = 0
end
end
replace(target, "'#{pieces.join('.')}'")
end
end
# List all shortcut with comments
Fast.shortcut :shortcuts do
fast_files.each do |file|
lines = File.readlines(file).map { |line| line.chomp.gsub(/\s*#/, '').strip }
result = capture_file('(send _ :shortcut $(sym _) ...)', file)
result = [result] unless result.is_a? Array
result.each do |capture|
target = capture.loc.expression
puts "fast .#{target.source[1..].ljust(30)} # #{lines[target.line - 2]}"
end
end
end
# Use to walkthrough the docs files with fast examples
# fast .intro
Fast.shortcut :intro do
ARGV << File.join(File.dirname(__FILE__), 'docs', 'walkthrough.md')
Fast.shortcuts[:walk].run
end
# Useful for `fast .walk file.md` but not required by the library.
private
def require_or_install_tty_md
require 'tty-markdown'
rescue LoadError
puts 'Installing tty-markdown gem to better engage you :)'
Gem.install('tty-markdown')
puts 'Done! Now, back to our topic \o/'
system('clear')
retry
end
# Interactive command line walkthrough
# fast .walk docs/walkthrough.md
Fast.shortcut :walk do
require_or_install_tty_md
file = ARGV.last
execute = ->(line) { system(line) }
walk = ->(line) { line.each_char { |c| sleep(0.02) and print(c) } }
File.readlines(file).each do |line|
case line
when /^fast /
walk[line]
execute[line]
when /^\$ /
walk[line]
execute[line[2..]]
when /^!{3}\s/
# Skip warnings that are only for web tutorials
else
walk[TTY::Markdown.parse(line)]
end
end
end
# Format SQL
Fast.shortcut :format_sql do
require 'fast/sql'
file = ARGV.last
method = File.exist?(file) ? :parse_sql_file : :parse_sql
ast = Fast.public_send(method, file)
ast = ast.first if ast.is_a? Array
eligible_kw = [:RESERVED_KEYWORD]
eligible_tokens = [:BY]
output = Fast::SQL.replace('_', ast) do |root|
sb = root.loc.expression.source_buffer
sb.tokens.each do |token|
if eligible_kw.include?(token.keyword_kind) || eligible_tokens.include?(token.token)
range = Parser::Source::Range.new(sb, token.start, token.end)
replace(range, range.source.upcase)
end
end
end
require 'fast/cli'
puts Fast.highlight(output, sql: true)
end
# Anonymize SQL
# fast .anonymize_sql file.sql
Fast.shortcut :anonymize_sql do
require 'fast/sql'
file = ARGV.last
method = File.exist?(file) ? :parse_sql_file : :parse_sql
ast = Fast.public_send(method, file)
memo = {}
relnames = search("(relname $_)", ast).grep(String).uniq
pattern = "{relname (sval {#{relnames.map(&:inspect).join(' ')}})}"
puts "searching with #{pattern}"
content = Fast::SQL.replace(pattern, ast) do |node|
new_name = memo[node.source.tr(%|"'|, '')] ||= "x#{memo.size}"
new_name = "'#{new_name}'" if node.type == :sval
replace(node.loc.expression, new_name)
end
puts Fast.highlight(content, sql: true)
end