trains 0.0.4 → 0.0.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/lib/trains/dto/app.rb +3 -1
- data/lib/trains/dto/callback.rb +7 -0
- data/lib/trains/dto/controller.rb +1 -1
- data/lib/trains/dto/migration.rb +5 -0
- data/lib/trains/scanner.rb +48 -59
- data/lib/trains/utils/args.rb +43 -0
- data/lib/trains/utils/migration_tailor.rb +43 -0
- data/lib/trains/version.rb +1 -1
- data/lib/trains/visitor/controller.rb +23 -3
- data/lib/trains/visitor/migration.rb +21 -5
- data/lib/trains/visitor/route.rb +7 -29
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2b1af8d7a53681c21f561432534383da1d83bf4615bc8e85bdfa6c8ce7b210aa
|
|
4
|
+
data.tar.gz: aa4798c33b271c590c5b966078eb7a6f9fd603a069842ce454cadb14de8cc08d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f6faddb254499e05f02a13def98dc7ab1f7df69d2ff694617cbd24410e2cb23266c7fd4c067cb2e4e2dd4fd7e7552f7d5ba79c995f2f951ff452150b8d800222
|
|
7
|
+
data.tar.gz: 95748dab8e2f16aed324d9c55a8d14c0eeec265361d49794bf7d81f21f6b42b8a25ba7426f719fea673efc982864ff49c745d3cdeb6888780b63a3bdf81038b9
|
data/lib/trains/dto/app.rb
CHANGED
data/lib/trains/scanner.rb
CHANGED
|
@@ -5,10 +5,9 @@ module Trains
|
|
|
5
5
|
|
|
6
6
|
def initialize(folder, options = {})
|
|
7
7
|
@root_folder = folder
|
|
8
|
-
@
|
|
9
|
-
@
|
|
10
|
-
@
|
|
11
|
-
@helpers = []
|
|
8
|
+
@models = {}
|
|
9
|
+
@controllers = {}
|
|
10
|
+
@helpers = {}
|
|
12
11
|
@dir = File.expand_path(folder)
|
|
13
12
|
@options = options
|
|
14
13
|
end
|
|
@@ -23,15 +22,13 @@ module Trains
|
|
|
23
22
|
return(
|
|
24
23
|
Result.new(
|
|
25
24
|
data: nil,
|
|
26
|
-
error: ArgumentError.new(
|
|
25
|
+
error: ArgumentError.new('Not a Rails directory')
|
|
27
26
|
)
|
|
28
27
|
)
|
|
29
28
|
end
|
|
30
29
|
|
|
31
|
-
@models =
|
|
32
|
-
@
|
|
33
|
-
@controllers = get_controllers.to_set unless @options[:controllers] ==
|
|
34
|
-
false
|
|
30
|
+
@models = generate_models unless @options[:models] == false
|
|
31
|
+
@controllers = get_controllers unless @options[:controllers] == false
|
|
35
32
|
@routes = get_routes.to_set unless @options[:routes] == false
|
|
36
33
|
# TODO: @helpers = get_helpers
|
|
37
34
|
|
|
@@ -40,7 +37,6 @@ module Trains
|
|
|
40
37
|
name: nil,
|
|
41
38
|
controllers: @controllers,
|
|
42
39
|
models: @models,
|
|
43
|
-
migrations: @migrations,
|
|
44
40
|
helpers: @helpers,
|
|
45
41
|
routes: @routes
|
|
46
42
|
)
|
|
@@ -48,51 +44,65 @@ module Trains
|
|
|
48
44
|
|
|
49
45
|
private
|
|
50
46
|
|
|
47
|
+
# Generate models from either db/schema.rb
|
|
48
|
+
# else stitch together migrations to create models
|
|
49
|
+
def generate_models
|
|
50
|
+
return get_models if File.exist?(File.join(@dir, 'db', 'schema.rb'))
|
|
51
|
+
|
|
52
|
+
migrations = get_migrations
|
|
53
|
+
Utils::MigrationTailor.stitch(migrations)
|
|
54
|
+
end
|
|
55
|
+
|
|
51
56
|
def get_routes
|
|
52
|
-
route_file = [File.join(@dir,
|
|
57
|
+
route_file = [File.join(@dir, 'config', 'routes.rb')]
|
|
53
58
|
|
|
54
59
|
routes_results = parse_util(route_file, Visitor::Route)
|
|
55
60
|
routes_results
|
|
56
61
|
.select { |result| result.error.nil? }
|
|
57
|
-
.map
|
|
62
|
+
.map(&:data)
|
|
58
63
|
.flatten
|
|
59
64
|
end
|
|
60
65
|
|
|
61
66
|
def get_models
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
result_hash = {}
|
|
68
|
+
schema_file = [File.join(@dir, 'db', 'schema.rb')]
|
|
65
69
|
models_results = parse_util(schema_file, Visitor::Schema)
|
|
70
|
+
|
|
66
71
|
models_results
|
|
67
72
|
.select { |result| result.error.nil? }
|
|
68
|
-
.map
|
|
73
|
+
.map(&:data)
|
|
69
74
|
.flatten
|
|
70
|
-
|
|
75
|
+
.each { |model| result_hash[model.name] = model }
|
|
71
76
|
|
|
72
|
-
|
|
77
|
+
result_hash
|
|
73
78
|
end
|
|
74
79
|
|
|
75
|
-
def
|
|
76
|
-
|
|
80
|
+
def get_helpers; end
|
|
81
|
+
|
|
82
|
+
def get_gemfile; end
|
|
77
83
|
|
|
78
84
|
def get_controllers
|
|
85
|
+
result_hash = {}
|
|
79
86
|
controllers =
|
|
80
|
-
Dir.glob(File.join(@dir,
|
|
81
|
-
|
|
87
|
+
Dir.glob(File.join(@dir, 'app', 'controllers', '**', '*_controller.rb'))
|
|
82
88
|
controller_results = parse_util(controllers, Visitor::Controller)
|
|
89
|
+
|
|
83
90
|
controller_results
|
|
84
91
|
.select { |result| result.error.nil? }
|
|
85
|
-
.map
|
|
92
|
+
.map(&:data)
|
|
86
93
|
.flatten
|
|
94
|
+
.each { |controller| result_hash[controller.name] = controller }
|
|
95
|
+
|
|
96
|
+
result_hash
|
|
87
97
|
end
|
|
88
98
|
|
|
89
99
|
def get_migrations
|
|
90
|
-
migrations = Dir.glob(File.join(@dir,
|
|
91
|
-
|
|
100
|
+
migrations = Dir.glob(File.join(@dir, 'db', 'migrate', '**', '*.rb'))
|
|
92
101
|
migration_results = parse_util(migrations, Visitor::Migration)
|
|
102
|
+
|
|
93
103
|
migration_results
|
|
94
104
|
.select { |result| result.error.nil? }
|
|
95
|
-
.map
|
|
105
|
+
.map(&:data)
|
|
96
106
|
end
|
|
97
107
|
|
|
98
108
|
def parse_util(file_nodes, visitor_class)
|
|
@@ -109,42 +119,21 @@ module Trains
|
|
|
109
119
|
end
|
|
110
120
|
|
|
111
121
|
Parallel.map(file_nodes) do |node|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
puts e.
|
|
122
|
-
|
|
123
|
-
Result.new(data: nil, error: e)
|
|
122
|
+
processed_source =
|
|
123
|
+
RuboCop::AST::ProcessedSource.from_file(node, RUBY_VERSION.to_f)
|
|
124
|
+
visitor = visitor_class.new
|
|
125
|
+
visitor.process(processed_source.ast)
|
|
126
|
+
|
|
127
|
+
Result.new(data: visitor.result, error: nil)
|
|
128
|
+
rescue StandardError => e
|
|
129
|
+
puts "An error occurred while parsing #{node}. Use debug option to view backtrace. Skipping file..."
|
|
130
|
+
if @options[:debug]
|
|
131
|
+
puts e.message
|
|
132
|
+
puts e.backtrace
|
|
124
133
|
end
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
134
|
|
|
128
|
-
|
|
129
|
-
path = File.join(prefix, node)
|
|
130
|
-
obj = { path: nil }
|
|
131
|
-
|
|
132
|
-
# puts "DEBUG: #{path} #{ FastIgnore.new.allowed? path }"
|
|
133
|
-
if path != @dir.to_path &&
|
|
134
|
-
FastIgnore.new.allowed?(path, directory: false) == false
|
|
135
|
-
return nil
|
|
135
|
+
Result.new(data: nil, error: e)
|
|
136
136
|
end
|
|
137
|
-
|
|
138
|
-
if Dir.exist? path
|
|
139
|
-
children = []
|
|
140
|
-
Dir.each_child path do |child|
|
|
141
|
-
child_node = get_tree(child, path)
|
|
142
|
-
children.append(child_node) unless child_node.nil?
|
|
143
|
-
end
|
|
144
|
-
obj[:children] = children
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
obj
|
|
148
137
|
end
|
|
149
138
|
end
|
|
150
139
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Trains
|
|
4
|
+
module Utils
|
|
5
|
+
# utility module to deal with parsing of arguments
|
|
6
|
+
module Args
|
|
7
|
+
def parse_args(node)
|
|
8
|
+
case node.type
|
|
9
|
+
when :hash
|
|
10
|
+
parse_hash(node)
|
|
11
|
+
else
|
|
12
|
+
parse_value(node)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def parse_hash(node)
|
|
17
|
+
options = {}
|
|
18
|
+
return options unless node.type == :hash
|
|
19
|
+
|
|
20
|
+
node.each_pair { |key, value| options[key.value] = parse_value(value) }
|
|
21
|
+
rescue StandardError => e
|
|
22
|
+
puts node.parent
|
|
23
|
+
ensure
|
|
24
|
+
return options
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def parse_value(node)
|
|
28
|
+
case node.type
|
|
29
|
+
when :hash
|
|
30
|
+
parse_hash(node)
|
|
31
|
+
when :array
|
|
32
|
+
node.values.map { |value| parse_value(value) }
|
|
33
|
+
when :send
|
|
34
|
+
if node.method_name == :redirect
|
|
35
|
+
{ redirect: node.arguments.first.value }
|
|
36
|
+
end
|
|
37
|
+
else
|
|
38
|
+
node.value
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module Trains
|
|
2
|
+
module Utils
|
|
3
|
+
module MigrationTailor
|
|
4
|
+
def self.stitch(migrations)
|
|
5
|
+
models = {}
|
|
6
|
+
|
|
7
|
+
migrations.each do |mig|
|
|
8
|
+
case mig.modifier
|
|
9
|
+
when :create_table
|
|
10
|
+
models[mig.table_name] = {}
|
|
11
|
+
models[mig.table_name] = Trains::DTO::Model.new(
|
|
12
|
+
name: mig.table_name,
|
|
13
|
+
fields: mig.fields,
|
|
14
|
+
version: mig.version
|
|
15
|
+
)
|
|
16
|
+
when :add_column
|
|
17
|
+
models[mig.table_name].fields.push(*mig.fields)
|
|
18
|
+
when :remove_column
|
|
19
|
+
column =
|
|
20
|
+
models[mig.table_name].fields.find do |field|
|
|
21
|
+
field.name == mig.fields.first.name
|
|
22
|
+
end
|
|
23
|
+
models[mig.table_name].fields.delete(column)
|
|
24
|
+
when :change_table
|
|
25
|
+
# TODO: handle renaming columns
|
|
26
|
+
when :change_column
|
|
27
|
+
# get column
|
|
28
|
+
column =
|
|
29
|
+
models[mig.table_name].fields.find do |field|
|
|
30
|
+
field.name == mig.fields.first.name
|
|
31
|
+
end
|
|
32
|
+
# replace it with new column object
|
|
33
|
+
models[mig.table_name].fields.delete(column)
|
|
34
|
+
|
|
35
|
+
models[mig.table_name].fields << mig.fields.first
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
models
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/trains/version.rb
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../dto/callback'
|
|
4
|
+
require_relative '../dto/controller'
|
|
5
|
+
require_relative '../dto/method'
|
|
3
6
|
|
|
4
7
|
module Trains
|
|
5
8
|
module Visitor
|
|
6
9
|
# Visitor that parses controllers and returns a DTO::Controller object
|
|
7
10
|
class Controller < Base
|
|
11
|
+
include Utils::Args
|
|
12
|
+
|
|
13
|
+
TRACKED_CALLBACKS = [
|
|
14
|
+
:http_basic_authenticate_with
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
8
17
|
def initialize
|
|
9
18
|
@method_list = []
|
|
10
19
|
@methods = {}
|
|
11
20
|
@class_name = nil
|
|
21
|
+
@callbacks = []
|
|
12
22
|
end
|
|
13
23
|
|
|
14
24
|
def on_class(node)
|
|
@@ -17,15 +27,25 @@ module Trains
|
|
|
17
27
|
return unless controller?(parent_class)
|
|
18
28
|
|
|
19
29
|
@class_name = class_name
|
|
30
|
+
find_callbacks(node)
|
|
20
31
|
parse_body(node.body) unless node.body.nil?
|
|
21
32
|
end
|
|
22
33
|
|
|
23
34
|
def result
|
|
24
|
-
DTO::Controller.new(name: @class_name, method_list: @method_list.uniq)
|
|
35
|
+
DTO::Controller.new(name: @class_name, method_list: @method_list.uniq, callbacks: @callbacks)
|
|
25
36
|
end
|
|
26
37
|
|
|
27
38
|
private
|
|
28
39
|
|
|
40
|
+
def find_callbacks(klass_node)
|
|
41
|
+
klass_node.each_descendant(:send) do |node|
|
|
42
|
+
if node.receiver.nil? && TRACKED_CALLBACKS.include?(node.method_name)
|
|
43
|
+
@callbacks << DTO::Callback.new(method: node.method_name,
|
|
44
|
+
arguments: node.arguments.map { |arg| parse_args(arg) })
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
29
49
|
def parse_body(body)
|
|
30
50
|
body.each_child_node do |child|
|
|
31
51
|
@method_list << parse_method(child) if child.type == :def
|
|
@@ -9,6 +9,7 @@ module Trains
|
|
|
9
9
|
|
|
10
10
|
def initialize
|
|
11
11
|
@model = nil
|
|
12
|
+
@table_modifier = nil
|
|
12
13
|
@table_name = nil
|
|
13
14
|
@is_class = false
|
|
14
15
|
@is_migration = false
|
|
@@ -30,7 +31,12 @@ module Trains
|
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
def result
|
|
33
|
-
DTO::
|
|
34
|
+
DTO::Migration.new(
|
|
35
|
+
table_name: @table_name,
|
|
36
|
+
modifier: @table_modifier,
|
|
37
|
+
fields: @fields,
|
|
38
|
+
version: @migration_version
|
|
39
|
+
)
|
|
34
40
|
end
|
|
35
41
|
|
|
36
42
|
private
|
|
@@ -50,11 +56,19 @@ module Trains
|
|
|
50
56
|
|
|
51
57
|
def process_def_node(node)
|
|
52
58
|
allowed_method_names = %i[change up down]
|
|
53
|
-
allowed_table_modifiers = %i[
|
|
59
|
+
allowed_table_modifiers = %i[
|
|
60
|
+
create_table
|
|
61
|
+
change_table
|
|
62
|
+
update_column
|
|
63
|
+
add_column
|
|
64
|
+
remove_column
|
|
65
|
+
change_column
|
|
66
|
+
]
|
|
54
67
|
block_type_modifier = false
|
|
55
68
|
|
|
56
69
|
method_name = node.method_name
|
|
57
70
|
return unless allowed_method_names.include? method_name
|
|
71
|
+
return if node.body.nil?
|
|
58
72
|
|
|
59
73
|
table_modifier =
|
|
60
74
|
if node.body.children[0] == nil
|
|
@@ -68,6 +82,8 @@ module Trains
|
|
|
68
82
|
end
|
|
69
83
|
return unless allowed_table_modifiers.include? table_modifier
|
|
70
84
|
|
|
85
|
+
@table_modifier = table_modifier
|
|
86
|
+
|
|
71
87
|
# Get the name of the table being modified
|
|
72
88
|
if block_type_modifier
|
|
73
89
|
raw_table_name =
|
|
@@ -81,8 +97,8 @@ module Trains
|
|
|
81
97
|
raw_table_name = node.body.children[2].value.to_s
|
|
82
98
|
@table_name = raw_table_name.singularize.camelize
|
|
83
99
|
|
|
84
|
-
field_name = node.body.children[3]
|
|
85
|
-
field_type = node.body.children[4]
|
|
100
|
+
field_name = node.body.children[3]&.value
|
|
101
|
+
field_type = node.body.children[4]&.value
|
|
86
102
|
@fields.append(DTO::Field.new(field_name, field_type))
|
|
87
103
|
end
|
|
88
104
|
end
|
|
@@ -95,7 +111,7 @@ module Trains
|
|
|
95
111
|
@fields.append(DTO::Field.new(:updated_at, :datetime))
|
|
96
112
|
return
|
|
97
113
|
end
|
|
98
|
-
|
|
114
|
+
|
|
99
115
|
type = node.children[1]
|
|
100
116
|
value = node.children[2].value unless node.children[2].hash_type?
|
|
101
117
|
@fields.append(DTO::Field.new(value, type))
|
data/lib/trains/visitor/route.rb
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
require_relative
|
|
1
|
+
require_relative '../dto/route'
|
|
2
2
|
|
|
3
3
|
module Trains
|
|
4
4
|
module Visitor
|
|
5
|
+
# Visitor for Parsing Rails routes
|
|
5
6
|
class Route < Base
|
|
7
|
+
include Utils::Args
|
|
8
|
+
|
|
6
9
|
def_node_matcher :route_parent?, <<~PATTERN
|
|
7
10
|
(block (send (send (send
|
|
8
11
|
(const nil? :Rails) :application) :routes) :draw)
|
|
@@ -13,7 +16,7 @@ module Trains
|
|
|
13
16
|
(send nil? %1 ...)
|
|
14
17
|
PATTERN
|
|
15
18
|
|
|
16
|
-
ALLOWED_VERBS = %i[get put post update delete resources scope]
|
|
19
|
+
ALLOWED_VERBS = %i[get put post update delete resources scope].freeze
|
|
17
20
|
|
|
18
21
|
def initialize
|
|
19
22
|
@route_list = []
|
|
@@ -25,6 +28,7 @@ module Trains
|
|
|
25
28
|
|
|
26
29
|
def on_block(node)
|
|
27
30
|
return unless route_parent?(node)
|
|
31
|
+
return if node.body.nil?
|
|
28
32
|
|
|
29
33
|
node.body.each_child_node do |child|
|
|
30
34
|
ALLOWED_VERBS.each do |verb|
|
|
@@ -45,33 +49,7 @@ module Trains
|
|
|
45
49
|
node.arguments[0].value
|
|
46
50
|
end
|
|
47
51
|
options = parse_hash(node.arguments[1])
|
|
48
|
-
DTO::Route.new(method
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def parse_hash(node)
|
|
52
|
-
options = {}
|
|
53
|
-
return options unless node.type == :hash
|
|
54
|
-
|
|
55
|
-
node.each_pair { |key, value| options[key.value] = parse_value(value) }
|
|
56
|
-
rescue StandardError => e
|
|
57
|
-
puts node.parent
|
|
58
|
-
ensure
|
|
59
|
-
return options
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def parse_value(node)
|
|
63
|
-
case node.type
|
|
64
|
-
when :hash
|
|
65
|
-
parse_hash(node)
|
|
66
|
-
when :array
|
|
67
|
-
node.values.map { |value| parse_value(value) }
|
|
68
|
-
when :send
|
|
69
|
-
if node.method_name == :redirect
|
|
70
|
-
{ redirect: node.arguments.first.value }
|
|
71
|
-
end
|
|
72
|
-
else
|
|
73
|
-
node.value
|
|
74
|
-
end
|
|
52
|
+
DTO::Route.new(method:, param:, options:)
|
|
75
53
|
end
|
|
76
54
|
end
|
|
77
55
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trains
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Syed Faraaz Ahmad
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-05-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -85,13 +85,17 @@ files:
|
|
|
85
85
|
- Rakefile
|
|
86
86
|
- lib/trains.rb
|
|
87
87
|
- lib/trains/dto/app.rb
|
|
88
|
+
- lib/trains/dto/callback.rb
|
|
88
89
|
- lib/trains/dto/controller.rb
|
|
89
90
|
- lib/trains/dto/field.rb
|
|
90
91
|
- lib/trains/dto/method.rb
|
|
92
|
+
- lib/trains/dto/migration.rb
|
|
91
93
|
- lib/trains/dto/model.rb
|
|
92
94
|
- lib/trains/dto/route.rb
|
|
93
95
|
- lib/trains/scanner.rb
|
|
96
|
+
- lib/trains/utils/args.rb
|
|
94
97
|
- lib/trains/utils/logger.rb
|
|
98
|
+
- lib/trains/utils/migration_tailor.rb
|
|
95
99
|
- lib/trains/utils/rails_dir.rb
|
|
96
100
|
- lib/trains/utils/result.rb
|
|
97
101
|
- lib/trains/version.rb
|