k_domain 0.0.16 → 0.0.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.builders/boot.rb +40 -0
- data/.builders/generators/configuration_generator.rb +22 -0
- data/.builders/run.rb +16 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -2
- data/Guardfile +1 -0
- data/README.md +15 -0
- data/STORIES.md +35 -6
- data/lib/k_domain/config/_.rb +4 -0
- data/lib/k_domain/config/config.rb +19 -0
- data/lib/k_domain/config/configuration.rb +76 -0
- data/lib/k_domain/domain_model/load.rb +41 -0
- data/lib/k_domain/domain_model/transform.rb +27 -55
- data/lib/k_domain/domain_model/transform_steps/_.rb +8 -7
- data/lib/k_domain/domain_model/transform_steps/step.rb +27 -1
- data/lib/k_domain/domain_model/transform_steps/{step1_attach_db_schema.rb → step1_db_schema.rb} +2 -1
- data/lib/k_domain/domain_model/transform_steps/{step5_attach_dictionary.rb → step20_dictionary.rb} +7 -4
- data/lib/k_domain/domain_model/transform_steps/step2_domain_models.rb +123 -0
- data/lib/k_domain/domain_model/transform_steps/{step8_rails_resource_models.rb → step4_rails_resource_models.rb} +4 -4
- data/lib/k_domain/domain_model/transform_steps/step5_rails_resource_routes.rb +36 -0
- data/lib/k_domain/domain_model/transform_steps/step6_rails_structure_models.rb +90 -0
- data/lib/k_domain/domain_model/transform_steps/step7_rails_structure_controllers.rb +111 -0
- data/lib/k_domain/domain_model/transform_steps/step8_domain_columns.rb +99 -0
- data/lib/k_domain/rails_code_extractor/_.rb +5 -0
- data/lib/k_domain/rails_code_extractor/extract_controller.rb +61 -0
- data/lib/k_domain/rails_code_extractor/extract_model.rb +56 -6
- data/lib/k_domain/rails_code_extractor/{load_shim.rb → shim_loader.rb} +3 -5
- data/lib/k_domain/raw_db_schema/load.rb +1 -1
- data/lib/k_domain/raw_db_schema/transform.rb +28 -3
- data/lib/k_domain/schemas/_.rb +6 -3
- data/lib/k_domain/schemas/database.rb +86 -0
- data/lib/k_domain/schemas/domain/erd_file.rb +78 -77
- data/lib/k_domain/schemas/domain.rb +149 -0
- data/lib/k_domain/schemas/domain_model.rb +6 -5
- data/lib/k_domain/schemas/{domain/_.rb → domain_types.rb} +1 -8
- data/lib/k_domain/schemas/rails_resource.rb +43 -6
- data/lib/k_domain/schemas/rails_structure.rb +182 -0
- data/lib/k_domain/version.rb +1 -1
- data/lib/k_domain.rb +4 -2
- data/templates/custom/action_controller.rb +36 -0
- data/templates/custom/controller_interceptors.rb +78 -0
- data/templates/custom/model_interceptors.rb +71 -0
- data/templates/load_schema.rb +7 -0
- data/templates/rails/action_controller.rb +301 -0
- data/templates/{active_record_shims.rb → rails/active_record.rb} +42 -49
- data/templates/ruby_code_extractor/attach_class_info.rb +13 -0
- data/templates/ruby_code_extractor/behaviour_accessors.rb +39 -0
- data/templates/sample_config.rb +47 -0
- data/templates/simple/controller_interceptors.rb +2 -0
- metadata +33 -22
- data/lib/k_domain/domain_model/transform_steps/step2_attach_models.rb +0 -62
- data/lib/k_domain/domain_model/transform_steps/step3_attach_columns.rb +0 -137
- data/lib/k_domain/domain_model/transform_steps/step4_attach_erd_files.rb +0 -457
- data/lib/k_domain/domain_model/transform_steps/step9_rails_structure_models.rb +0 -33
- data/lib/k_domain/schemas/database/_.rb +0 -7
- data/lib/k_domain/schemas/database/foreign_key.rb +0 -14
- data/lib/k_domain/schemas/database/index.rb +0 -14
- data/lib/k_domain/schemas/database/schema.rb +0 -31
- data/lib/k_domain/schemas/database/table.rb +0 -32
- data/lib/k_domain/schemas/domain/domain.rb +0 -11
- data/lib/k_domain/schemas/domain/models/column.rb +0 -49
- data/lib/k_domain/schemas/domain/models/model.rb +0 -111
- data/templates/fake_module_shims.rb +0 -42
@@ -1,62 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Loop through the db_schema tables and build up a
|
4
|
-
# basic model for each table
|
5
|
-
class Step2AttachModels < KDomain::DomainModel::Step
|
6
|
-
# Map database schema to domain model
|
7
|
-
def call
|
8
|
-
raise 'ERD path not supplied' if opts[:erd_path].nil?
|
9
|
-
|
10
|
-
# Schema is re-shaped into a format designed for domain modeling
|
11
|
-
domain[:models] = database_tables.map { |table| model(table) }
|
12
|
-
end
|
13
|
-
|
14
|
-
def model(table)
|
15
|
-
table_name = table[:name].to_s
|
16
|
-
model_name = table_name.singularize
|
17
|
-
|
18
|
-
{
|
19
|
-
name: model_name,
|
20
|
-
name_plural: table_name, # need to check if this is correct as I know it is wrong for account_history_datum
|
21
|
-
table_name: table_name,
|
22
|
-
pk: primary_key(table),
|
23
|
-
erd_location: location(table_name, model_name),
|
24
|
-
statistics: {}, # Load in future step
|
25
|
-
columns: [] # Load in future step
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
def primary_key(table)
|
30
|
-
{
|
31
|
-
name: table[:primary_key],
|
32
|
-
type: table[:primary_key_type],
|
33
|
-
exist: !table[:primary_key].nil?
|
34
|
-
}
|
35
|
-
end
|
36
|
-
|
37
|
-
# Location of source code
|
38
|
-
def location(table_name, model_name)
|
39
|
-
file_normal = File.join(opts[:erd_path], "#{model_name}.rb")
|
40
|
-
file_custom = File.join(opts[:erd_path], "#{table_name}.rb")
|
41
|
-
file_exist = true
|
42
|
-
state = []
|
43
|
-
|
44
|
-
if File.exist?(file_normal)
|
45
|
-
file = file_normal
|
46
|
-
state.push(:has_ruby_model)
|
47
|
-
elsif File.exist?(file_custom)
|
48
|
-
file = file_custom
|
49
|
-
state.push(:has_ruby_model)
|
50
|
-
state.push(:nonconventional_name)
|
51
|
-
else
|
52
|
-
file = ''
|
53
|
-
file_exist = false
|
54
|
-
end
|
55
|
-
|
56
|
-
{
|
57
|
-
file: file,
|
58
|
-
exist: file_exist,
|
59
|
-
state: state # display_state: state.join(' ')
|
60
|
-
}
|
61
|
-
end
|
62
|
-
end
|
@@ -1,137 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Attach columns to models
|
4
|
-
class Step3AttachColumns < KDomain::DomainModel::Step
|
5
|
-
attr_accessor :table
|
6
|
-
attr_reader :column_name
|
7
|
-
attr_reader :column_symbol
|
8
|
-
|
9
|
-
def call
|
10
|
-
build_columns
|
11
|
-
end
|
12
|
-
|
13
|
-
def build_columns
|
14
|
-
domain_models.each do |model|
|
15
|
-
@table = find_table_for_model(model)
|
16
|
-
columns = columns(table[:columns])
|
17
|
-
columns = insert_primary_key(model, columns)
|
18
|
-
model[:columns] = columns
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def column_data(name)
|
23
|
-
@column_name = name
|
24
|
-
@column_symbol = name.to_sym
|
25
|
-
{
|
26
|
-
name: name,
|
27
|
-
name_plural: name.pluralize,
|
28
|
-
type: nil,
|
29
|
-
precision: nil,
|
30
|
-
scale: nil,
|
31
|
-
default: nil,
|
32
|
-
null: nil,
|
33
|
-
limit: nil,
|
34
|
-
array: nil
|
35
|
-
}
|
36
|
-
end
|
37
|
-
|
38
|
-
def columns(db_columns)
|
39
|
-
db_columns.map do |db_column|
|
40
|
-
column = column_data(db_column[:name]).merge(
|
41
|
-
type: check_type(db_column[:type]),
|
42
|
-
precision: db_column[:precision],
|
43
|
-
scale: db_column[:scale],
|
44
|
-
default: db_column[:default],
|
45
|
-
null: db_column[:null],
|
46
|
-
limit: db_column[:limit],
|
47
|
-
array: db_column[:array]
|
48
|
-
)
|
49
|
-
|
50
|
-
expand_column(column)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def insert_primary_key(model, columns)
|
55
|
-
return columns unless model[:pk][:exist]
|
56
|
-
|
57
|
-
column = column_data('id').merge(
|
58
|
-
type: check_type(model[:pk][:type])
|
59
|
-
)
|
60
|
-
|
61
|
-
columns.unshift(expand_column(column))
|
62
|
-
columns
|
63
|
-
end
|
64
|
-
|
65
|
-
def expand_column(column)
|
66
|
-
foreign_table = lookup_foreign_table(column_name)
|
67
|
-
is_foreign = !foreign_table.nil?
|
68
|
-
# is_foreign = foreign_key?(column_name)
|
69
|
-
structure_type = structure_type(is_foreign)
|
70
|
-
|
71
|
-
column.merge({
|
72
|
-
structure_type: structure_type,
|
73
|
-
foreign_key: is_foreign,
|
74
|
-
foreign_table: (foreign_table || '').singularize,
|
75
|
-
foreign_table_plural: (foreign_table || '').pluralize
|
76
|
-
})
|
77
|
-
end
|
78
|
-
|
79
|
-
def check_type(type)
|
80
|
-
type = type.to_sym if type.is_a?(String)
|
81
|
-
|
82
|
-
return type if %i[string integer bigint bigserial boolean float decimal datetime date hstore text jsonb].include?(type)
|
83
|
-
|
84
|
-
if type.nil?
|
85
|
-
guard('nil type detected for db_column[:type]')
|
86
|
-
|
87
|
-
return :string
|
88
|
-
end
|
89
|
-
|
90
|
-
guard("new type detected for db_column[:type] - #{type}")
|
91
|
-
|
92
|
-
camel.parse(type.to_s).downcase
|
93
|
-
end
|
94
|
-
|
95
|
-
def lookup_foreign_table(column_name)
|
96
|
-
foreign_table = find_foreign_table(table[:name], column_name)
|
97
|
-
|
98
|
-
return foreign_table if foreign_table
|
99
|
-
|
100
|
-
cn = column_name.to_s
|
101
|
-
|
102
|
-
if cn.ends_with?('_id')
|
103
|
-
table_name = column_name[0..-4]
|
104
|
-
table_name_plural = table_name.pluralize
|
105
|
-
|
106
|
-
if table_name_exist?(table_name_plural.to_s)
|
107
|
-
investigate(step: :step3_attach_columns,
|
108
|
-
location: :lookup_foreign_table,
|
109
|
-
key: column_name,
|
110
|
-
message: "#{@table[:name]}.#{column_name} => #{table_name_plural} - Relationship not found in DB, so have inferred this relationship. You may want to check that this relation is correct")
|
111
|
-
|
112
|
-
return table_name
|
113
|
-
end
|
114
|
-
|
115
|
-
investigate(step: :step3_attach_columns,
|
116
|
-
location: :lookup_foreign_table,
|
117
|
-
key: column_name,
|
118
|
-
message: "#{@table[:name]}.#{column_name} => #{table_name_plural} - Table not found for a column that looks like foreign_key")
|
119
|
-
end
|
120
|
-
|
121
|
-
nil
|
122
|
-
end
|
123
|
-
|
124
|
-
# Need some configurable data dictionary where by
|
125
|
-
# _token can be setup on a project by project basis
|
126
|
-
def structure_type(is_foreign)
|
127
|
-
return :foreign_key if is_foreign
|
128
|
-
return :primary_key if column_symbol == :id
|
129
|
-
return :timestamp if column_symbol == :created_at || column_symbol == :updated_at
|
130
|
-
return :timestamp if column_symbol == :created_at || column_symbol == :updated_at
|
131
|
-
return :deleted_at if column_symbol == :deleted_at
|
132
|
-
return :encrypted_password if column_symbol == :encrypted_password
|
133
|
-
return :token if column_name.ends_with?('_token') || column_name.ends_with?('_token_iv')
|
134
|
-
|
135
|
-
:data
|
136
|
-
end
|
137
|
-
end
|
@@ -1,457 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Attach source code found in rails model definitions to models
|
4
|
-
class Step4AttachErdFiles < KDomain::DomainModel::Step
|
5
|
-
attr_accessor :ruby_code
|
6
|
-
|
7
|
-
# NOTE: This code could be rewritten using monkey patched modules and peak
|
8
|
-
def call
|
9
|
-
domain[:erd_files] = domain_models.map { |model| load_dsl(model) }
|
10
|
-
end
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def reset_dsl
|
15
|
-
@ruby_code = nil
|
16
|
-
@dsl = nil
|
17
|
-
end
|
18
|
-
|
19
|
-
def dsl
|
20
|
-
@dsl ||= {
|
21
|
-
name: '',
|
22
|
-
name_plural: ''
|
23
|
-
}
|
24
|
-
end
|
25
|
-
|
26
|
-
def load_dsl(model)
|
27
|
-
# this should be a configuration
|
28
|
-
# print '.'
|
29
|
-
|
30
|
-
reset_dsl
|
31
|
-
|
32
|
-
dsl[:name] = model[:name]
|
33
|
-
dsl[:name_plural] = model[:name_plural]
|
34
|
-
dsl[:dsl_file] = model[:erd_location][:exist] ? model[:erd_location][:file] : ''
|
35
|
-
|
36
|
-
return dsl unless File.exist?(dsl[:dsl_file])
|
37
|
-
|
38
|
-
@ruby_code = File.read(dsl[:dsl_file])
|
39
|
-
|
40
|
-
dsl[:source] = read_dsl_source
|
41
|
-
dsl[:dsl] = build_dsl
|
42
|
-
dsl[:todo] = todo
|
43
|
-
|
44
|
-
dsl
|
45
|
-
end
|
46
|
-
|
47
|
-
def read_dsl_source
|
48
|
-
regex_split_private_public = /(?<public>.+?)(?=\bprivate\b)(?<private>.*)/m
|
49
|
-
|
50
|
-
split_code = regex_split_private_public.match(ruby_code)
|
51
|
-
|
52
|
-
public_code = nil
|
53
|
-
private_code = nil
|
54
|
-
|
55
|
-
if split_code
|
56
|
-
public_code = split_code[:public]
|
57
|
-
private_code = split_code[:private]
|
58
|
-
end
|
59
|
-
|
60
|
-
{
|
61
|
-
ruby: ruby_code,
|
62
|
-
public: public_code,
|
63
|
-
private: private_code,
|
64
|
-
all_methods: grab_methods(public_code, private_code)
|
65
|
-
}
|
66
|
-
end
|
67
|
-
|
68
|
-
def build_dsl
|
69
|
-
return if ruby_code.nil?
|
70
|
-
|
71
|
-
# need to support options as hash instead of options as string in the future
|
72
|
-
{
|
73
|
-
default_scope: grab_default_scope,
|
74
|
-
scopes: grab_scopes,
|
75
|
-
belongs_to: grab_belongs_to,
|
76
|
-
has_one: grab_has_one,
|
77
|
-
has_many: grab_has_many,
|
78
|
-
has_and_belongs_to_many: grab_has_and_belongs_to_many,
|
79
|
-
validate_on: grab_validate,
|
80
|
-
validates_on: grab_validates
|
81
|
-
}
|
82
|
-
|
83
|
-
# ^(?<spaces>\s*)(?<event_type>before_create|before_save|before_destroy|after_create|after_save|after_destroy) (:(?<name>\w*)[, ]?(?<scope>.*)|(?<scope>\{.*?\}.*$))
|
84
|
-
end
|
85
|
-
|
86
|
-
def grab_default_scope
|
87
|
-
regex = /default_scope \{(?<scope>.*?)\}/m
|
88
|
-
|
89
|
-
m = regex.match(ruby_code)
|
90
|
-
|
91
|
-
return "{ #{m[:scope].strip.gsub('\n', '')} }" if m
|
92
|
-
|
93
|
-
nil
|
94
|
-
end
|
95
|
-
|
96
|
-
def grab_scopes
|
97
|
-
entries = []
|
98
|
-
# Start from beginning of line and capture
|
99
|
-
# - number of spaces scope
|
100
|
-
# - name of scope
|
101
|
-
# - value of scope to end of line
|
102
|
-
regex = /^(?<spaces>\s*)scope :(?<name>\w*)[, ]?(?<scope>.*)/
|
103
|
-
|
104
|
-
# rubocop:disable Metrics/BlockLength
|
105
|
-
ruby_code.scan(regex) do
|
106
|
-
m = $LAST_MATCH_INFO
|
107
|
-
spaces = m[:spaces] # .delete("\n")
|
108
|
-
last_lf = spaces.rindex("\n")
|
109
|
-
spaces = last_lf ? spaces[spaces.rindex("\n") + 1..-1] : spaces
|
110
|
-
name = m[:name]
|
111
|
-
scope = m[:scope].strip
|
112
|
-
|
113
|
-
# Found a valid one liner
|
114
|
-
if scope.ends_with?('}') && (scope.scan(/{/).count == scope.scan(/}/).count)
|
115
|
-
scope = escape_single_quote(scope)
|
116
|
-
entries << { name: name, scope: scope }
|
117
|
-
else
|
118
|
-
# Have a multiline scope, lets see if it is cleanly formatted
|
119
|
-
|
120
|
-
start_anchor = "#{spaces}scope :#{name}"
|
121
|
-
end_anchor = "#{spaces}}"
|
122
|
-
|
123
|
-
# log.kv 'spaces', spaces.length
|
124
|
-
# log.kv 'name', name
|
125
|
-
# log.kv 'start_anchor', start_anchor
|
126
|
-
# log.kv 'end_anchor', end_anchor
|
127
|
-
|
128
|
-
start_index = ruby_code.index(/#{start_anchor}/)
|
129
|
-
|
130
|
-
if start_index.nil?
|
131
|
-
log.error("[#{@current_entity[:name]}] could not find [start] anchor index for [#{name}]")
|
132
|
-
else
|
133
|
-
ruby_section = ruby_code[start_index..-1]
|
134
|
-
end_index = ruby_section.index(/^#{end_anchor}/) # Add ^ start of line
|
135
|
-
if end_index.nil?
|
136
|
-
log.error("[#{@current_entity[:name]}] could not find [end] anchor index for [#{name}]")
|
137
|
-
else
|
138
|
-
scope = ruby_section[start_anchor.length + 1..end_index].strip
|
139
|
-
scope = escape_single_quote("#{scope}#{end_anchor}")
|
140
|
-
entries << { name: name, scope: scope }
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
145
|
-
entries
|
146
|
-
rescue StandardError => e
|
147
|
-
# bin ding.pry
|
148
|
-
puts e.message
|
149
|
-
end
|
150
|
-
# rubocop:enable Metrics/BlockLength
|
151
|
-
|
152
|
-
def grab_belongs_to
|
153
|
-
entries = []
|
154
|
-
|
155
|
-
# Start from beginning of line and capture
|
156
|
-
# - number of spaces before belongs_to
|
157
|
-
# - name of the belongs_to
|
158
|
-
# - value of belongs_to to end of line
|
159
|
-
regex = /^(?<spaces>\s*)belongs_to :(?<name>\w*)[, ]?(?<options>.*)/
|
160
|
-
|
161
|
-
ruby_code.scan(regex) do
|
162
|
-
m = $LAST_MATCH_INFO
|
163
|
-
|
164
|
-
# spaces = m[:spaces] # .delete("\n")
|
165
|
-
# last_lf = spaces.rindex("\n")
|
166
|
-
# spaces = last_lf ? spaces[spaces.rindex("\n") + 1..-1] : spaces
|
167
|
-
name = m[:name]
|
168
|
-
|
169
|
-
options = m[:options]
|
170
|
-
.gsub(':polymorphic => ', 'polymorphic: ')
|
171
|
-
.gsub(':class_name => ', 'class_name: ')
|
172
|
-
.gsub(':foreign_key => ', 'foreign_key: ')
|
173
|
-
.strip
|
174
|
-
|
175
|
-
options = clean_lambda(options)
|
176
|
-
|
177
|
-
entries << { name: name, options: extract_options(options), raw_options: options }
|
178
|
-
end
|
179
|
-
entries
|
180
|
-
rescue StandardError => e
|
181
|
-
# bin ding.pry
|
182
|
-
puts e.message
|
183
|
-
end
|
184
|
-
|
185
|
-
def grab_has_one
|
186
|
-
entries = []
|
187
|
-
|
188
|
-
# Start from beginning of line and capture
|
189
|
-
# - number of spaces before has_one
|
190
|
-
# - name of the has_one
|
191
|
-
# - value of has_one to end of line
|
192
|
-
regex = /^(?<spaces>\s*)has_one :(?<name>\w*)[, ]?(?<options>.*)/
|
193
|
-
|
194
|
-
ruby_code.scan(regex) do
|
195
|
-
m = $LAST_MATCH_INFO
|
196
|
-
|
197
|
-
# spaces = m[:spaces] # .delete("\n")
|
198
|
-
# last_lf = spaces.rindex("\n")
|
199
|
-
# spaces = last_lf ? spaces[spaces.rindex("\n") + 1..-1] : spaces
|
200
|
-
name = m[:name]
|
201
|
-
options = m[:options]
|
202
|
-
.strip
|
203
|
-
# .gsub(':polymorphic => ', 'polymorphic: ')
|
204
|
-
# .gsub(':class_name => ', 'class_name: ')
|
205
|
-
# .gsub(':foreign_key => ', 'foreign_key: ')
|
206
|
-
|
207
|
-
options = clean_lambda(options)
|
208
|
-
|
209
|
-
entries << { name: name, options: extract_options(options), raw_options: options }
|
210
|
-
end
|
211
|
-
entries
|
212
|
-
rescue StandardError => e
|
213
|
-
# bin ding.pry
|
214
|
-
puts e.message
|
215
|
-
end
|
216
|
-
|
217
|
-
def grab_has_many
|
218
|
-
entries = []
|
219
|
-
# Start from beginning of line and capture
|
220
|
-
# - number of spaces before has_many
|
221
|
-
# - name of the has_many
|
222
|
-
# - value of has_many to end of line
|
223
|
-
regex = /^(?<spaces>\s*)has_many :(?<name>\w*)[, ]?(?<options>.*)/
|
224
|
-
|
225
|
-
ruby_code.scan(regex) do
|
226
|
-
m = $LAST_MATCH_INFO
|
227
|
-
|
228
|
-
# spaces = m[:spaces] # .delete("\n")
|
229
|
-
# last_lf = spaces.rindex("\n")
|
230
|
-
# spaces = last_lf ? spaces[spaces.rindex("\n") + 1..-1] : spaces
|
231
|
-
name = m[:name]
|
232
|
-
options = m[:options]
|
233
|
-
.gsub(':dependent => ', 'dependent: ')
|
234
|
-
.gsub(':class_name => ', 'class_name: ')
|
235
|
-
.gsub(':foreign_key => ', 'foreign_key: ')
|
236
|
-
.gsub(':primary_key => ', 'primary_key: ')
|
237
|
-
.strip
|
238
|
-
|
239
|
-
options = clean_lambda(options)
|
240
|
-
|
241
|
-
entries << { name: name, options: extract_options(options), raw_options: options }
|
242
|
-
end
|
243
|
-
entries
|
244
|
-
rescue StandardError => e
|
245
|
-
# bin ding.pry
|
246
|
-
puts e.message
|
247
|
-
end
|
248
|
-
|
249
|
-
def grab_has_and_belongs_to_many
|
250
|
-
entries = []
|
251
|
-
# Start from beginning of line and capture
|
252
|
-
# - number of spaces before has_and_belongs_to_many
|
253
|
-
# - name of the has_and_belongs_to_many
|
254
|
-
# - value of has_and_belongs_to_many to end of line
|
255
|
-
regex = /^(?<spaces>\s*)has_and_belongs_to_many :(?<name>\w*)[, ]?(?<options>.*)/
|
256
|
-
|
257
|
-
ruby_code.scan(regex) do
|
258
|
-
m = $LAST_MATCH_INFO
|
259
|
-
|
260
|
-
# spaces = m[:spaces] # .delete("\n")
|
261
|
-
# last_lf = spaces.rindex("\n")
|
262
|
-
# spaces = last_lf ? spaces[spaces.rindex("\n") + 1..-1] : spaces
|
263
|
-
name = m[:name]
|
264
|
-
options = m[:options]
|
265
|
-
.gsub(':dependent => ', 'dependent: ')
|
266
|
-
.gsub(':class_name => ', 'class_name: ')
|
267
|
-
.gsub(':foreign_key => ', 'foreign_key: ')
|
268
|
-
.gsub(':primary_key => ', 'primary_key: ')
|
269
|
-
.strip
|
270
|
-
|
271
|
-
options = clean_lambda(options)
|
272
|
-
|
273
|
-
entries << { name: name, options: {}, raw_options: options }
|
274
|
-
end
|
275
|
-
entries
|
276
|
-
rescue StandardError => e
|
277
|
-
# bin ding.pry
|
278
|
-
puts e.message
|
279
|
-
end
|
280
|
-
|
281
|
-
def grab_validates
|
282
|
-
entries = []
|
283
|
-
# Start from beginning of line and capture
|
284
|
-
# - number of spaces before validates
|
285
|
-
# - name of the validates
|
286
|
-
# - value of validates to end of line
|
287
|
-
regex = /^(?<spaces>\s*)validates :(?<name>\w*)[, ]?(?<options>.*)/
|
288
|
-
|
289
|
-
ruby_code.scan(regex) do
|
290
|
-
m = $LAST_MATCH_INFO
|
291
|
-
|
292
|
-
# spaces = m[:spaces] # .delete("\n")
|
293
|
-
# last_lf = spaces.rindex("\n")
|
294
|
-
# spaces = last_lf ? spaces[spaces.rindex("\n") + 1..-1] : spaces
|
295
|
-
name = m[:name]
|
296
|
-
|
297
|
-
options = m[:options].strip
|
298
|
-
|
299
|
-
options = clean_lambda(options)
|
300
|
-
|
301
|
-
entries << { name: name, raw_options: options }
|
302
|
-
end
|
303
|
-
entries
|
304
|
-
rescue StandardError => e
|
305
|
-
# bin ding.pry
|
306
|
-
puts e.message
|
307
|
-
end
|
308
|
-
|
309
|
-
def grab_validate
|
310
|
-
entries = []
|
311
|
-
# Start from beginning of line and capture
|
312
|
-
# - number of spaces before validate
|
313
|
-
# - list of methods to call until to end of line
|
314
|
-
# regex = /^(?<spaces>\s*)validate :(?<name>\w*)[, ]?(?<options>.*)/
|
315
|
-
regex = /^(?<spaces>\s*)validate (?<line>:.*)/
|
316
|
-
# puts @current_entity[:name]
|
317
|
-
|
318
|
-
ruby_code.scan(regex) do
|
319
|
-
m = $LAST_MATCH_INFO
|
320
|
-
|
321
|
-
# spaces = m[:spaces] # .delete("\n")
|
322
|
-
# last_lf = spaces.rindex("\n")
|
323
|
-
# spaces = last_lf ? spaces[spaces.rindex("\n") + 1..-1] : spaces
|
324
|
-
line = m[:line]
|
325
|
-
|
326
|
-
entries << { line: line }
|
327
|
-
# puts @current_entity[:validate]
|
328
|
-
end
|
329
|
-
entries
|
330
|
-
rescue StandardError => e
|
331
|
-
# bin ding.pry
|
332
|
-
puts e.message
|
333
|
-
end
|
334
|
-
|
335
|
-
def grab_methods(public_code = ruby_code, private_code = nil)
|
336
|
-
# public_code = ruby_code_public.nil? ? ruby_code : ruby_code_public
|
337
|
-
# private_code = ruby_code_private
|
338
|
-
|
339
|
-
regex = /def (?<method>.*)/
|
340
|
-
|
341
|
-
# log.info(@current_entity[:name])
|
342
|
-
|
343
|
-
public_methods = parse_methods(:public, public_code&.scan(regex)&.flatten || [])
|
344
|
-
private_methods = parse_methods(:private, private_code&.scan(regex)&.flatten || [])
|
345
|
-
methods = (public_methods + private_methods)
|
346
|
-
|
347
|
-
class_methods = methods.select { |method| method[:class_method] == true }
|
348
|
-
|
349
|
-
all_instance = methods.select { |method| method[:class_method] == false }
|
350
|
-
instance_public = all_instance.select { |method| method[:scope] == :public }
|
351
|
-
instance_private = all_instance.select { |method| method[:scope] == :private }
|
352
|
-
|
353
|
-
{
|
354
|
-
klass: class_methods,
|
355
|
-
instance: all_instance,
|
356
|
-
instance_public: instance_public,
|
357
|
-
instance_private: instance_private
|
358
|
-
}
|
359
|
-
end
|
360
|
-
|
361
|
-
def parse_methods(scope, methods)
|
362
|
-
methods.map do |value|
|
363
|
-
class_method = value.starts_with?('self.')
|
364
|
-
name = class_method ? value[5..-1] : value
|
365
|
-
arguments = nil
|
366
|
-
arguments_index = name.index('(')
|
367
|
-
|
368
|
-
if arguments_index
|
369
|
-
arguments = name[arguments_index..-1]
|
370
|
-
name = name[0..arguments_index - 1]
|
371
|
-
end
|
372
|
-
|
373
|
-
arguments = escape_single_quote(arguments)
|
374
|
-
|
375
|
-
{
|
376
|
-
name: name,
|
377
|
-
scope: scope,
|
378
|
-
class_method: class_method,
|
379
|
-
arguments: arguments&.strip.to_s
|
380
|
-
}
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
def todo
|
385
|
-
{
|
386
|
-
after_destroy: [], # to do
|
387
|
-
before_save: [], # to do
|
388
|
-
after_save: [], # to do
|
389
|
-
before_create: [], # to do
|
390
|
-
after_create: [], # to do
|
391
|
-
enum: [], # to do
|
392
|
-
attr_encrypted: [], # to do
|
393
|
-
validates_uniqueness_of: [], # to do
|
394
|
-
validates_confirmation_of: [], # to do
|
395
|
-
attr_accessor: [], # to do
|
396
|
-
attr_reader: [], # to do
|
397
|
-
attr_writer: [] # to do
|
398
|
-
}
|
399
|
-
end
|
400
|
-
|
401
|
-
def escape_single_quote(value)
|
402
|
-
return nil if value.nil?
|
403
|
-
|
404
|
-
value.gsub("'", "\\\\'")
|
405
|
-
end
|
406
|
-
|
407
|
-
# rubocop:disable Style/EvalWithLocation, Security/Eval, Style/DocumentDynamicEvalDefinition
|
408
|
-
def extract_options(options)
|
409
|
-
eval("{ #{options} }")
|
410
|
-
rescue StandardError => e
|
411
|
-
investigate(
|
412
|
-
step: :step4_attach_erd_files_models,
|
413
|
-
location: :extract_options,
|
414
|
-
key: nil,
|
415
|
-
message: e.message
|
416
|
-
)
|
417
|
-
{}
|
418
|
-
rescue SyntaxError => e
|
419
|
-
# may be the issue is from a comment at the off the line
|
420
|
-
comment_index = options.rindex('#') - 1
|
421
|
-
|
422
|
-
if comment_index.positive?
|
423
|
-
options_minus_comment = options[0..comment_index].squish
|
424
|
-
return extract_options(options_minus_comment)
|
425
|
-
end
|
426
|
-
|
427
|
-
investigate(
|
428
|
-
step: :step4_attach_erd_files_models,
|
429
|
-
location: :extract_options,
|
430
|
-
key: nil,
|
431
|
-
message: e.message
|
432
|
-
)
|
433
|
-
{}
|
434
|
-
end
|
435
|
-
# rubocop:enable Style/EvalWithLocation, Security/Eval, Style/DocumentDynamicEvalDefinition
|
436
|
-
|
437
|
-
def clean_lambda(options)
|
438
|
-
if /^->/.match?(options)
|
439
|
-
index = options.index(/}\s*,/)
|
440
|
-
if index.nil?
|
441
|
-
if options.count('{') == options.count('}')
|
442
|
-
index = options.rindex(/}/)
|
443
|
-
options = "a_lambda: '#{escape_single_quote(options[0..index])}'"
|
444
|
-
else
|
445
|
-
log.error(options)
|
446
|
-
options = "a_lambda: '#{escape_single_quote(options)}'"
|
447
|
-
end
|
448
|
-
else
|
449
|
-
options = "a_lambda: '#{escape_single_quote(options[0..index])}', #{options[index + 2..-1]}"
|
450
|
-
end
|
451
|
-
end
|
452
|
-
options
|
453
|
-
rescue StandardError => e
|
454
|
-
# bin ding.pry
|
455
|
-
puts e.message
|
456
|
-
end
|
457
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Locate rails model files
|
4
|
-
class Step9RailsStructureModels < KDomain::DomainModel::Step
|
5
|
-
attr_accessor :ruby_code
|
6
|
-
|
7
|
-
def call
|
8
|
-
raise 'ERD path not supplied' if opts[:erd_path].nil?
|
9
|
-
|
10
|
-
self.rails_structure_models = rails_resource_models.map do |resource|
|
11
|
-
process_resource(OpenStruct.new(resource))
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def process_resource(resource)
|
18
|
-
erd_path = opts[:erd_path]
|
19
|
-
puts erd_path
|
20
|
-
@model = {
|
21
|
-
model_name: resource.model_name,
|
22
|
-
table_name: resource.table_name,
|
23
|
-
file: resource.file,
|
24
|
-
exist: resource.exist,
|
25
|
-
state: resource.state,
|
26
|
-
code: resource.exist ? File.read(resource.file) : '',
|
27
|
-
behaviours: {},
|
28
|
-
functions: {}
|
29
|
-
}
|
30
|
-
|
31
|
-
@model
|
32
|
-
end
|
33
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module KDomain
|
4
|
-
module Database
|
5
|
-
class ForeignKey < Dry::Struct
|
6
|
-
attribute :left , Types::Strict::String
|
7
|
-
attribute :right , Types::Strict::String
|
8
|
-
attribute :name? , Types::Strict::String.optional.default(nil)
|
9
|
-
attribute :on_update? , Types::Strict::String.optional.default(nil)
|
10
|
-
attribute :on_delete? , Types::Strict::String.optional.default(nil)
|
11
|
-
attribute :column? , Types::Strict::String.optional.default(nil)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|