k_domain 0.0.16 → 0.0.26
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/.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
|