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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.builders/boot.rb +40 -0
  3. data/.builders/generators/configuration_generator.rb +22 -0
  4. data/.builders/run.rb +16 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +1 -2
  7. data/Guardfile +1 -0
  8. data/README.md +15 -0
  9. data/STORIES.md +35 -6
  10. data/lib/k_domain/config/_.rb +4 -0
  11. data/lib/k_domain/config/config.rb +19 -0
  12. data/lib/k_domain/config/configuration.rb +76 -0
  13. data/lib/k_domain/domain_model/load.rb +41 -0
  14. data/lib/k_domain/domain_model/transform.rb +27 -55
  15. data/lib/k_domain/domain_model/transform_steps/_.rb +8 -7
  16. data/lib/k_domain/domain_model/transform_steps/step.rb +27 -1
  17. data/lib/k_domain/domain_model/transform_steps/{step1_attach_db_schema.rb → step1_db_schema.rb} +2 -1
  18. data/lib/k_domain/domain_model/transform_steps/{step5_attach_dictionary.rb → step20_dictionary.rb} +7 -4
  19. data/lib/k_domain/domain_model/transform_steps/step2_domain_models.rb +123 -0
  20. data/lib/k_domain/domain_model/transform_steps/{step8_rails_resource_models.rb → step4_rails_resource_models.rb} +4 -4
  21. data/lib/k_domain/domain_model/transform_steps/step5_rails_resource_routes.rb +36 -0
  22. data/lib/k_domain/domain_model/transform_steps/step6_rails_structure_models.rb +90 -0
  23. data/lib/k_domain/domain_model/transform_steps/step7_rails_structure_controllers.rb +111 -0
  24. data/lib/k_domain/domain_model/transform_steps/step8_domain_columns.rb +99 -0
  25. data/lib/k_domain/rails_code_extractor/_.rb +5 -0
  26. data/lib/k_domain/rails_code_extractor/extract_controller.rb +61 -0
  27. data/lib/k_domain/rails_code_extractor/extract_model.rb +56 -6
  28. data/lib/k_domain/rails_code_extractor/{load_shim.rb → shim_loader.rb} +3 -5
  29. data/lib/k_domain/raw_db_schema/load.rb +1 -1
  30. data/lib/k_domain/raw_db_schema/transform.rb +28 -3
  31. data/lib/k_domain/schemas/_.rb +6 -3
  32. data/lib/k_domain/schemas/database.rb +86 -0
  33. data/lib/k_domain/schemas/domain/erd_file.rb +78 -77
  34. data/lib/k_domain/schemas/domain.rb +149 -0
  35. data/lib/k_domain/schemas/domain_model.rb +6 -5
  36. data/lib/k_domain/schemas/{domain/_.rb → domain_types.rb} +1 -8
  37. data/lib/k_domain/schemas/rails_resource.rb +43 -6
  38. data/lib/k_domain/schemas/rails_structure.rb +182 -0
  39. data/lib/k_domain/version.rb +1 -1
  40. data/lib/k_domain.rb +4 -2
  41. data/templates/custom/action_controller.rb +36 -0
  42. data/templates/custom/controller_interceptors.rb +78 -0
  43. data/templates/custom/model_interceptors.rb +71 -0
  44. data/templates/load_schema.rb +7 -0
  45. data/templates/rails/action_controller.rb +301 -0
  46. data/templates/{active_record_shims.rb → rails/active_record.rb} +42 -49
  47. data/templates/ruby_code_extractor/attach_class_info.rb +13 -0
  48. data/templates/ruby_code_extractor/behaviour_accessors.rb +39 -0
  49. data/templates/sample_config.rb +47 -0
  50. data/templates/simple/controller_interceptors.rb +2 -0
  51. metadata +33 -22
  52. data/lib/k_domain/domain_model/transform_steps/step2_attach_models.rb +0 -62
  53. data/lib/k_domain/domain_model/transform_steps/step3_attach_columns.rb +0 -137
  54. data/lib/k_domain/domain_model/transform_steps/step4_attach_erd_files.rb +0 -457
  55. data/lib/k_domain/domain_model/transform_steps/step9_rails_structure_models.rb +0 -33
  56. data/lib/k_domain/schemas/database/_.rb +0 -7
  57. data/lib/k_domain/schemas/database/foreign_key.rb +0 -14
  58. data/lib/k_domain/schemas/database/index.rb +0 -14
  59. data/lib/k_domain/schemas/database/schema.rb +0 -31
  60. data/lib/k_domain/schemas/database/table.rb +0 -32
  61. data/lib/k_domain/schemas/domain/domain.rb +0 -11
  62. data/lib/k_domain/schemas/domain/models/column.rb +0 -49
  63. data/lib/k_domain/schemas/domain/models/model.rb +0 -111
  64. data/templates/fake_module_shims.rb +0 -42
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Schema is re-shaped into a format designed for domain modeling
4
+ class Step2DomainModels < KDomain::DomainModel::Step
5
+ # Map database schema to domain model
6
+ def call
7
+ raise 'Rails model path not supplied' if opts[:model_path].nil?
8
+
9
+ domain[:models] = database_tables.map { |table| model(table) }
10
+ end
11
+
12
+ def model(table)
13
+ table_name = table[:name].to_s
14
+ model_name = table_name.singularize
15
+
16
+ model = {
17
+ name: model_name,
18
+ name_plural: table_name, # need to check if this is correct as I know it is wrong for account_history_datum
19
+ table_name: table_name,
20
+ pk: primary_key(table),
21
+ file: nil # will be set in step8_domain_columns
22
+ }
23
+
24
+ attach_columns(model)
25
+ end
26
+
27
+ def primary_key(table)
28
+ {
29
+ name: table[:primary_key],
30
+ type: table[:primary_key_type],
31
+ exist: !table[:primary_key].nil?
32
+ }
33
+ end
34
+
35
+ def attach_columns(model)
36
+ table = find_table_for_model(model)
37
+ columns = columns(table[:columns])
38
+ columns = insert_primary_key(model, columns)
39
+ model[:columns] = columns
40
+ model
41
+ end
42
+
43
+ def columns(db_columns)
44
+ db_columns.map do |db_column|
45
+ column_data(db_column[:name]).merge(
46
+ type: check_type(db_column[:type]),
47
+ precision: db_column[:precision],
48
+ scale: db_column[:scale],
49
+ default: db_column[:default],
50
+ null: db_column[:null],
51
+ limit: db_column[:limit],
52
+ array: db_column[:array]
53
+ )
54
+ end
55
+ end
56
+
57
+ def insert_primary_key(model, columns)
58
+ return columns unless model[:pk][:exist]
59
+
60
+ column = column_data('id').merge(
61
+ type: check_type(model[:pk][:type])
62
+ )
63
+
64
+ columns.unshift(column)
65
+ columns
66
+ end
67
+
68
+ def check_type(type)
69
+ type = type.to_sym if type.is_a?(String)
70
+
71
+ return type if %i[string integer bigint bigserial boolean float decimal datetime date hstore text jsonb].include?(type)
72
+
73
+ if type.nil?
74
+ guard('nil type detected for db_column[:type]')
75
+
76
+ return :string
77
+ end
78
+
79
+ guard("new type detected for db_column[:type] - #{type}")
80
+
81
+ camel.parse(type.to_s).downcase
82
+ end
83
+
84
+ def column_data(name)
85
+ {
86
+ name: name,
87
+ name_plural: name.pluralize,
88
+ type: nil,
89
+ precision: nil,
90
+ scale: nil,
91
+ default: nil,
92
+ null: nil,
93
+ limit: nil,
94
+ array: nil
95
+ }
96
+ end
97
+
98
+ # # Location of source code
99
+ # def location(table_name, model_name)
100
+ # file_normal = File.join(opts[:model_path], "#{model_name}.rb")
101
+ # file_custom = File.join(opts[:model_path], "#{table_name}.rb")
102
+ # file_exist = true
103
+ # state = []
104
+
105
+ # if File.exist?(file_normal)
106
+ # file = file_normal
107
+ # state.push(:has_ruby_model)
108
+ # elsif File.exist?(file_custom)
109
+ # file = file_custom
110
+ # state.push(:has_ruby_model)
111
+ # state.push(:nonconventional_name)
112
+ # else
113
+ # file = ''
114
+ # file_exist = false
115
+ # end
116
+
117
+ # {
118
+ # file: file,
119
+ # exist: file_exist,
120
+ # state: state
121
+ # }
122
+ # end
123
+ end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Locate rails model files
4
- class Step8RailsResourceModels < KDomain::DomainModel::Step
4
+ class Step4RailsResourceModels < KDomain::DomainModel::Step
5
5
  attr_accessor :ruby_code
6
6
 
7
7
  def call
8
- raise 'ERD path not supplied' if opts[:erd_path].nil?
8
+ raise 'Model path not supplied' if opts[:model_path].nil?
9
9
 
10
10
  self.rails_resource_models = domain_models.map do |model|
11
11
  locate_rails_model(model[:name], model[:table_name])
@@ -15,8 +15,8 @@ class Step8RailsResourceModels < KDomain::DomainModel::Step
15
15
  private
16
16
 
17
17
  def locate_rails_model(model_name, table_name)
18
- file_normal = File.join(opts[:erd_path], "#{model_name}.rb")
19
- file_custom = File.join(opts[:erd_path], "#{table_name}.rb")
18
+ file_normal = File.join(opts[:model_path], "#{model_name}.rb")
19
+ file_custom = File.join(opts[:model_path], "#{table_name}.rb")
20
20
  file_exist = true
21
21
  state = []
22
22
 
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Locate rails model files
4
+ class Step5RailsResourceRoutes < KDomain::DomainModel::Step
5
+ def call
6
+ return warning('Routes .json file not supplied') if opts[:route_path].nil?
7
+ return warning('Routes .json file not found') unless File.exist?(opts[:route_path])
8
+
9
+ warning('Controller path not supplied. Routes will be loaded but not paired with a controller') if opts[:controller_path].nil?
10
+
11
+ self.rails_resource_routes = load_routes(opts[:route_path], opts[:controller_path])
12
+ end
13
+
14
+ private
15
+
16
+ def load_routes(route_path, controller_path)
17
+ json = File.read(route_path)
18
+ root = JSON.parse(json, symbolize_names: true)
19
+ routes = root[:routes]
20
+
21
+ routes.map { |route| map_route(route, controller_path) }
22
+ end
23
+
24
+ def map_route(route, controller_path)
25
+ return route.merge({ file: '', exist: false }) if controller_path.nil?
26
+
27
+ controller_file = File.join(controller_path, route[:controller_file])
28
+
29
+ route.merge(
30
+ {
31
+ file: controller_file,
32
+ exist: File.exist?(controller_file)
33
+ }
34
+ )
35
+ end
36
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Locate rails model files
4
+ class Step6RailsStructureModels < KDomain::DomainModel::Step
5
+ def call
6
+ raise 'Rails model path not supplied' unless opts[:model_path]
7
+
8
+ # THIS IS NOT WORKING YET
9
+ self.rails_structure_models = rails_resource_models.map do |resource|
10
+ process_resource(OpenStruct.new(resource))
11
+ end
12
+
13
+ attach_behavior_and_functions
14
+ end
15
+
16
+ private
17
+
18
+ def process_resource(resource)
19
+ {
20
+ model_name: resource.model_name,
21
+ table_name: resource.table_name,
22
+ file: resource.file,
23
+ exist: resource.exist,
24
+ state: resource.state,
25
+ code: resource.exist ? File.read(resource.file) : '',
26
+ behaviours: {},
27
+ functions: {}
28
+ }
29
+
30
+ # return @model unless resource.exist
31
+
32
+ # @model[:behaviours] = extract_behavior(resource.file)
33
+ # @model[:functions] = extract_functions(resource.file)
34
+
35
+ # @model
36
+ end
37
+
38
+ def attach_behavior_and_functions
39
+ rails_structure_models.select { |model| model[:exist] }.each do |model|
40
+ model[:behaviours] = extract_behavior(model[:file])
41
+ klass_name = model[:behaviours][:class_name]
42
+ model[:functions] = extract_functions(klass_name)
43
+ end
44
+ end
45
+
46
+ def extract_behavior(file)
47
+ extractor.extract(file)
48
+ extractor.model
49
+ end
50
+
51
+ def extract_functions(klass_name)
52
+ klass = klass_type(klass_name)
53
+
54
+ return {} if klass.nil?
55
+
56
+ Peeky.api.build_class_info(klass.new).to_h
57
+ rescue StandardError => e
58
+ log.exception(e)
59
+ end
60
+
61
+ def klass_type(klass_name)
62
+ Module.const_get(klass_name.classify)
63
+ rescue NameError
64
+ puts ''
65
+ puts klass_name
66
+ puts klass_name.classify
67
+ puts klass_name.pluralize
68
+ puts 'Trying the pluralized version: '
69
+ Module.const_get(klass_name.pluralize)
70
+ end
71
+
72
+ def extractor
73
+ @extractor ||= KDomain::RailsCodeExtractor::ExtractModel.new(shim_loader)
74
+ end
75
+
76
+ def shim_loader
77
+ return opts[:shim_loader] if !opts[:shim_loader].nil? && opts[:shim_loader].is_a?(KDomain::RailsCodeExtractor::ShimLoader)
78
+
79
+ shim_loader = KDomain::RailsCodeExtractor::ShimLoader.new
80
+ # Shims to attach generic class_info writers
81
+ shim_loader.register(:attach_class_info , KDomain::Gem.resource('templates/ruby_code_extractor/attach_class_info.rb'))
82
+ shim_loader.register(:behaviour_accessors , KDomain::Gem.resource('templates/ruby_code_extractor/behaviour_accessors.rb'))
83
+
84
+ # Shims to support standard active_record DSL methods
85
+ shim_loader.register(:active_record , KDomain::Gem.resource('templates/rails/active_record.rb'))
86
+
87
+ # Shims to support application specific [module, class, method] implementations for suppression and exception avoidance
88
+ shim_loader
89
+ end
90
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Locate rails controller files
4
+ class Step7RailsStructureControllers < KDomain::DomainModel::Step
5
+ attr_accessor :controllers
6
+
7
+ def call
8
+ raise 'Rails controller path not supplied' unless opts[:controller_path]
9
+
10
+ @controllers = {}
11
+
12
+ rails_resource_routes.map do |route|
13
+ process_route(OpenStruct.new(route))
14
+ end
15
+
16
+ self.rails_structure_controllers = controllers.keys.map { |key| controllers[key] }
17
+
18
+ attach_behavior_and_functions
19
+ end
20
+
21
+ private
22
+
23
+ def process_route(route)
24
+ if new_controller?(route)
25
+ new_controller(route)
26
+ else
27
+ controller = @controllers[route[:controller_file]]
28
+ controller[:actions] << new_action(route)
29
+ end
30
+ end
31
+
32
+ def new_controller?(route)
33
+ !controllers.key?(route[:controller_file])
34
+ end
35
+
36
+ def new_controller(route)
37
+ controllers[route[:controller_file]] = {
38
+ name: route[:controller_name],
39
+ path: route[:controller_path],
40
+ namespace: route[:controller_namespace],
41
+ file: route[:controller_file],
42
+ exist: route[:controller_exist],
43
+ full_file: route[:file],
44
+ behaviours: {},
45
+ functions: {},
46
+ actions: [new_action(route)]
47
+ }
48
+ end
49
+
50
+ def new_action(route)
51
+ {
52
+ route_name: route[:name],
53
+ action: route[:action],
54
+ uri_path: route[:uri_path],
55
+ mime_match: route[:mime_match],
56
+ verbs: route[:verbs]
57
+ }
58
+ end
59
+
60
+ def attach_behavior_and_functions
61
+ rails_structure_controllers.select { |controller| controller[:exist] }.each do |controller|
62
+ unless File.exist?(controller[:full_file])
63
+ log.error 'Controller apparently exists but no file found, this means that you need re-run rake routes'
64
+ puts controller[:full_file]
65
+ next
66
+ end
67
+ controller[:behaviours] = extract_behavior(controller[:full_file])
68
+ klass_name = controller[:behaviours][:class_name]
69
+ controller[:functions] = extract_functions(klass_name, controller[:full_file])
70
+ end
71
+ end
72
+
73
+ def extract_behavior(file)
74
+ # puts file
75
+ extractor.extract(file)
76
+ extractor.controller
77
+ end
78
+
79
+ def extractor
80
+ @extractor ||= KDomain::RailsCodeExtractor::ExtractController.new(shim_loader)
81
+ end
82
+
83
+ def shim_loader
84
+ return opts[:shim_loader] if !opts[:shim_loader].nil? && opts[:shim_loader].is_a?(KDomain::RailsCodeExtractor::ShimLoader)
85
+
86
+ shim_loader = KDomain::RailsCodeExtractor::ShimLoader.new
87
+ # Shims to attach generic class_info writers
88
+ shim_loader.register(:attach_class_info , KDomain::Gem.resource('templates/ruby_code_extractor/attach_class_info.rb'))
89
+ shim_loader.register(:behaviour_accessors , KDomain::Gem.resource('templates/ruby_code_extractor/behaviour_accessors.rb'))
90
+
91
+ # Shims to support stand rails controller DSL methods
92
+ shim_loader.register(:action_controller , KDomain::Gem.resource('templates/rails/action_controller.rb'))
93
+
94
+ # Shims to support application specific [module, class, method] implementations for suppression and exception avoidance
95
+ # shim_loader.register(:app_action_controller , KDomain::Gem.resource('templates/advanced/action_controller.rb'))
96
+ # shim_loader.register(:app_controller_interceptors , KDomain::Gem.resource('templates/advanced/controller_interceptors.rb'))
97
+ shim_loader
98
+ end
99
+
100
+ def extract_functions(klass_name, controller_file)
101
+ klass = Module.const_get(klass_name.classify)
102
+
103
+ class_info = Peeky.api.build_class_info(klass.new)
104
+
105
+ class_info.to_h
106
+ rescue StandardError => e
107
+ log.kv 'controller_file', controller_file
108
+ log.exception(e, style: :short)
109
+ {}
110
+ end
111
+ end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ # columns to models
4
+ class Step8DomainColumns < KDomain::DomainModel::Step
5
+ attr_reader :domain_model
6
+ attr_reader :domain_column
7
+ attr_reader :rails_model
8
+ attr_reader :column_name
9
+ attr_reader :column_symbol
10
+
11
+ def call
12
+ @debug = true
13
+ enrich_columns
14
+ end
15
+
16
+ def enrich_columns
17
+ # .select {|m| m[:name] == 'app_user'}
18
+ domain_models.each do |model|
19
+ @domain_model = enrich_model(model)
20
+ # this will be nil if there is no rails model code
21
+
22
+ # log.warn domain_model[:name]
23
+ domain_model[:columns].each do |column|
24
+ @domain_column = column
25
+ @column_name = column[:name]
26
+ @column_symbol = column[:name].to_sym
27
+
28
+ column[:structure_type] = structure_type
29
+ end
30
+ end
31
+ end
32
+
33
+ def enrich_model(model)
34
+ # NOTE: THIS MAY GET MOVED TO DomainModel::Load#enrichment
35
+ @rails_model = find_rails_structure_models(model[:name])
36
+
37
+ model[:file] = @rails_model[:file]
38
+
39
+ log.error "Rails model not found for: #{model[:name]}" unless @rails_model
40
+
41
+ model
42
+ end
43
+
44
+ # Need some configurable data dictionary where by
45
+ # _token can be setup on a project by project basis
46
+ def structure_type
47
+ return :primary_key if domain_model[:pk][:name] == column_name
48
+ return :foreign_key if foreign_relationship?
49
+ return :foreign_type if column_symbol == :context_type || column_symbol == :element_type
50
+
51
+ return :timestamp if column_symbol == :created_at || column_symbol == :updated_at
52
+ return :deleted_at if column_symbol == :deleted_at
53
+ return :encrypted_password if column_symbol == :encrypted_password
54
+ return :token if column_name.ends_with?('_token') || column_name.ends_with?('_token_iv')
55
+
56
+ :data
57
+ end
58
+
59
+ def foreign_relationship?
60
+ return false if rails_model.nil? || rails_model[:behaviours].nil? || rails_model[:behaviours][:belongs_to].nil?
61
+
62
+ column_name = domain_column[:name].to_sym
63
+ rails_model[:behaviours][:belongs_to].any? { |belong| belong[:opts][:foreign_key].to_sym == column_name }
64
+ end
65
+
66
+ # def attach_relationships
67
+ # domain_column[:relationships] = []
68
+ # return if rails_model.nil? || rails_model[:behaviours].nil? || rails_model[:behaviours][:belongs_to].nil?
69
+
70
+ # column_name = domain_column[:name].to_sym
71
+
72
+ # attach_column_relationships(column_name)
73
+ # end
74
+
75
+ # def select_belongs_to(column_name)
76
+ # rails_model[:behaviours][:belongs_to].select { |belong| belong[:opts][:foreign_key].to_sym == column_name.to_sym }
77
+ # end
78
+
79
+ # # this just maps basic relationship information,
80
+ # # to go deeper you really need to use the Rails Model Behaviours
81
+ # def attach_column_relationships(column_name)
82
+ # select_belongs_to(column_name).each do |belongs_to|
83
+ # domain_column[:relationships] << map_belongs_to(belongs_to)
84
+ # end
85
+ # end
86
+
87
+ # def map_belongs_to(belongs_to)
88
+ # @domain_column[:structure_type] = :foreign_key
89
+ # # result = {
90
+ # # type: :belongs_to,
91
+ # # name: belongs_to[:name],
92
+ # # foreign_key: belongs_to.dig(:opts, :foreign_key) || @domain_column[:name],
93
+ # # }
94
+
95
+ # # result[:primary_key] = belongs_to.dig(:opts, :primary_key) if belongs_to.dig(:opts, :primary_key)
96
+ # # result[:class_name] = belongs_to.dig(:opts, :class_name) if belongs_to.dig(:opts, :class_name)
97
+ # result
98
+ # end
99
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './shim_loader'
4
+ require_relative './extract_model'
5
+ require_relative './extract_controller'
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Takes a Rails controller and extracts DSL behaviours and custom functions (instance, class and private methods)
4
+ module KDomain
5
+ module RailsCodeExtractor
6
+ class ExtractController
7
+ include KLog::Logging
8
+
9
+ attr_reader :shims_loaded
10
+ attr_reader :controller
11
+
12
+ def initialize(load_shim)
13
+ @load_shim = load_shim
14
+ @shims_loaded = false
15
+ end
16
+
17
+ def extract(file)
18
+ load_shims unless shims_loaded
19
+
20
+ ActionController.class_info = nil
21
+ # KDomain::RailsCodeExtractor.reset
22
+
23
+ load_retry(file, 10, nil)
24
+ rescue StandardError => e
25
+ log.exception(e)
26
+ end
27
+
28
+ private
29
+
30
+ def load_shims
31
+ @load_shim.call
32
+ @shims_loaded = true
33
+ end
34
+
35
+ # rubocop:disable Security/Eval,Style/EvalWithLocation,Style/DocumentDynamicEvalDefinition,Metrics/AbcSize
36
+ def load_retry(file, times, last_error)
37
+ return if times.negative?
38
+
39
+ # puts file
40
+ load(file)
41
+
42
+ @controller = ActionController::Base.class_info
43
+ # @controller = KDomain::RailsCodeExtractor.class_info
44
+
45
+ # get_method_info(File.base_name(file))
46
+ rescue StandardError => e
47
+ log.kv 'times', times
48
+ # puts e.message
49
+ if e.is_a?(NameError) && e.message != last_error&.message
50
+ log.kv('add module', e.name)
51
+ log.kv 'file', file
52
+ eval("module #{e.name}; end")
53
+ return load_retry(file, times - 1, e)
54
+ end
55
+ log.kv 'file', file
56
+ log.exception(e, style: :short, method_info: method(__callee__))
57
+ end
58
+ # rubocop:enable Security/Eval,Style/EvalWithLocation,Style/DocumentDynamicEvalDefinition,Metrics/AbcSize
59
+ end
60
+ end
61
+ end
@@ -6,16 +6,66 @@ module KDomain
6
6
  class ExtractModel
7
7
  include KLog::Logging
8
8
 
9
- attr_reader :source_file
10
- attr_reader :data
9
+ attr_reader :shims_loaded
10
+ attr_reader :models
11
+ attr_reader :model
11
12
 
12
- def initialize(source_file)
13
- @source_file = source_file
13
+ def initialize(load_shim)
14
+ @load_shim = load_shim
15
+ @shims_loaded = false
16
+ @models = []
14
17
  end
15
18
 
16
- def call
17
- log.kv 'source_file', source_file
19
+ def extract(file)
20
+ load_shims unless shims_loaded
21
+
22
+ ActiveRecord.class_info = nil
23
+
24
+ load_retry(file, 10, nil)
25
+ rescue StandardError => e
26
+ log.exception(e)
27
+ end
28
+
29
+ private
30
+
31
+ def load_shims
32
+ @load_shim.call
33
+ @shims_loaded = true
34
+ end
35
+
36
+ # rubocop:disable Security/Eval,Style/EvalWithLocation,Style/DocumentDynamicEvalDefinition,Metrics/AbcSize
37
+ def load_retry(file, times, last_error)
38
+ return if times.negative?
39
+
40
+ load(file)
41
+
42
+ @model = ActiveRecord.class_info
43
+
44
+ if @model.nil?
45
+ # puts ''
46
+ # puts file
47
+ # puts 'class probably has no DSL methods'
48
+ @model = {
49
+ class_name: File.basename(file, File.extname(file)).classify
50
+ }
51
+ end
52
+
53
+ @models << @model
54
+
55
+ # get_method_info(File.base_name(file))
56
+ rescue StandardError => e
57
+ log.kv 'times', times
58
+ # puts e.message
59
+ if e.is_a?(NameError) && e.message != last_error&.message
60
+ log.kv('add module', e.name)
61
+ log.kv 'file', file
62
+ eval("module #{e.name}; end")
63
+ return load_retry(file, times - 1, e)
64
+ end
65
+ log.kv 'file', file
66
+ log.exception(e, style: :short, method_info: method(__callee__))
18
67
  end
68
+ # rubocop:enable Security/Eval,Style/EvalWithLocation,Style/DocumentDynamicEvalDefinition,Metrics/AbcSize
19
69
  end
20
70
  end
21
71
  end
@@ -8,20 +8,18 @@
8
8
  # 2. Inject fake module/classes that would otherwise break code loading with various exceptions
9
9
  module KDomain
10
10
  module RailsCodeExtractor
11
- class LoadShim
11
+ class ShimLoader
12
12
  include KLog::Logging
13
13
 
14
14
  attr_reader :shim_files
15
15
 
16
- attr_reader :dsl_shim_file
17
- attr_reader :fake_module_file
18
-
19
16
  def initialize
20
17
  @shim_files = []
21
18
  end
22
19
 
23
20
  def call
24
- log.kv 'preload', preload
21
+ # puts shim_files.map { |sf| sf[:file] }
22
+ shim_files.select { |sf| sf[:exist] }.each { |sf| require sf[:file] }
25
23
  end
26
24
 
27
25
  def register(name, file)
@@ -22,7 +22,7 @@ module KDomain
22
22
  json = File.read(source_file)
23
23
  @raw_data = KUtil.data.json_parse(json, as: :hash_symbolized)
24
24
 
25
- @data = KDomain::Database::Schema.new(@raw_data)
25
+ @data = KDomain::Schemas::Database.new(@raw_data)
26
26
  end
27
27
 
28
28
  def to_h