lagoon 0.1.0 → 0.2.0

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +39 -0
  3. data/CHANGELOG.md +14 -2
  4. data/README.md +111 -146
  5. data/Rakefile +17 -3
  6. data/exe/lagoon +3 -3
  7. data/gemfiles/adapters.gemfile +15 -0
  8. data/gemfiles/rails_6.1.gemfile +23 -0
  9. data/gemfiles/rails_7.0.gemfile +23 -0
  10. data/gemfiles/rails_7.1.gemfile +23 -0
  11. data/gemfiles/rails_7.2.gemfile +23 -0
  12. data/gemfiles/rails_8.0.gemfile +23 -0
  13. data/gemfiles/rails_8.1.gemfile +23 -0
  14. data/lib/lagoon/analyzer/action_controller_analyzer.rb +76 -0
  15. data/lib/lagoon/analyzer/active_record_analyzer.rb +202 -0
  16. data/lib/lagoon/analyzer/ast/controller_scope_collector.rb +104 -0
  17. data/lib/lagoon/analyzer/ast/method_reference_visitor.rb +170 -0
  18. data/lib/lagoon/analyzer/ast_model_reference_analyzer.rb +44 -0
  19. data/lib/lagoon/analyzer/database_schema_analyzer.rb +83 -0
  20. data/lib/lagoon/cli.rb +109 -80
  21. data/lib/lagoon/configuration.rb +42 -6
  22. data/lib/lagoon/diagram/base.rb +48 -8
  23. data/lib/lagoon/diagram/controller_diagram.rb +10 -16
  24. data/lib/lagoon/diagram/controller_model_diagram.rb +28 -0
  25. data/lib/lagoon/diagram/er_diagram.rb +10 -16
  26. data/lib/lagoon/diagram/model_diagram.rb +13 -16
  27. data/lib/lagoon/errors.rb +9 -0
  28. data/lib/lagoon/options.rb +182 -0
  29. data/lib/lagoon/parser/application_class_filter.rb +47 -0
  30. data/lib/lagoon/parser/controller_model_parser.rb +196 -0
  31. data/lib/lagoon/parser/controller_parser.rb +37 -54
  32. data/lib/lagoon/parser/model_parser.rb +57 -112
  33. data/lib/lagoon/parser/schema_parser.rb +120 -67
  34. data/lib/lagoon/railtie.rb +1 -1
  35. data/lib/lagoon/renderer/base_renderer.rb +49 -19
  36. data/lib/lagoon/renderer/class_diagram_renderer.rb +37 -31
  37. data/lib/lagoon/renderer/controller_model_er_renderer.rb +47 -0
  38. data/lib/lagoon/renderer/er_diagram_renderer.rb +43 -42
  39. data/lib/lagoon/result.rb +22 -0
  40. data/lib/lagoon/version.rb +1 -1
  41. data/lib/lagoon.rb +70 -21
  42. data/lib/tasks/lagoon.rake +15 -7
  43. data/sig/lagoon.rbs +107 -0
  44. metadata +57 -7
@@ -3,61 +3,63 @@
3
3
  module Lagoon
4
4
  module Renderer
5
5
  class ClassDiagramRenderer < BaseRenderer
6
+ def initialize(direction: 'TB', show_types: true)
7
+ super(direction: direction)
8
+ @show_types = show_types
9
+ end
10
+
6
11
  def render(parsed_data)
7
- output = ["classDiagram"]
12
+ output = ['classDiagram']
8
13
  output << " direction #{@direction}"
9
- output << ""
14
+ output << ''
10
15
 
11
- # クラス定義を追加
12
- parsed_data[:classes].each do |klass|
16
+ classes = parsed_data.fetch(:classes, []).select { |klass| klass[:name] }
17
+ classes.sort_by { |klass| klass[:name].to_s }.each do |klass|
13
18
  output << render_class(klass)
19
+ output << ''
14
20
  end
15
21
 
16
- output << ""
17
-
18
- # 関係性を追加
19
- parsed_data[:relationships].each do |rel|
22
+ relationships = parsed_data.fetch(:relationships, []).select { |rel| rel[:source] && rel[:target] }
23
+ relationships.sort_by { |rel| relationship_sort_key(rel) }.each do |rel|
20
24
  output << render_relationship(rel)
21
25
  end
22
26
 
23
- output.join("\n")
27
+ output.join("\n").rstrip
24
28
  end
25
29
 
26
30
  private
27
31
 
28
32
  def render_class(klass)
29
33
  lines = []
30
- class_name = escape_class_name(klass[:name])
34
+ class_name = aliased_identifier(klass[:name])
31
35
 
32
36
  lines << " class #{class_name} {"
33
- lines << " <<abstract>>" if klass[:abstract]
37
+ lines << ' <<abstract>>' if klass[:abstract]
34
38
 
35
- # 属性を追加
36
39
  if klass[:attributes]&.any?
37
- klass[:attributes].each do |attr|
38
- visibility = attr[:visibility] || "+"
40
+ klass[:attributes].sort_by { |attr| attr[:name].to_s }.each do |attr|
41
+ visibility = attr[:visibility] || '+'
39
42
  type = type_to_mermaid(attr[:type])
40
- lines << " #{visibility}#{type} #{attr[:name]}"
43
+ prefix = @show_types ? "#{type} " : ''
44
+ lines << " #{visibility}#{prefix}#{escape_member(attr[:name])}"
41
45
  end
42
46
  end
43
47
 
44
- # メソッドを追加
45
48
  if klass[:methods]&.any?
46
- klass[:methods].each do |method|
47
- visibility = method[:visibility] || "+"
48
- return_type = method[:return_type] ? " #{type_to_mermaid(method[:return_type])}" : ""
49
- lines << " #{visibility}#{method[:name]}()#{return_type}"
49
+ klass[:methods].sort_by { |method| [method[:visibility].to_s, method[:name].to_s] }.each do |method|
50
+ visibility = method[:visibility] || '+'
51
+ return_type = method[:return_type] ? " #{type_to_mermaid(method[:return_type])}" : ''
52
+ lines << " #{visibility}#{escape_member(method[:name])}()#{return_type}"
50
53
  end
51
54
  end
52
55
 
53
- lines << " }"
54
- lines << ""
56
+ lines << ' }'
55
57
  lines.join("\n")
56
58
  end
57
59
 
58
60
  def render_relationship(rel)
59
- source = escape_class_name(rel[:source])
60
- target = escape_class_name(rel[:target])
61
+ source = safe_identifier(rel[:source])
62
+ target = safe_identifier(rel[:target])
61
63
  type = rel[:type]
62
64
  label = rel[:label]
63
65
  source_cardinality = rel[:source_cardinality]
@@ -65,17 +67,17 @@ module Lagoon
65
67
 
66
68
  arrow = case type
67
69
  when :inheritance
68
- "<|--"
70
+ '<|--'
69
71
  when :composition
70
- "*--"
72
+ '*--'
71
73
  when :aggregation
72
- "o--"
74
+ 'o--'
73
75
  when :association
74
- "-->"
76
+ '-->'
75
77
  when :dependency
76
- "..>"
78
+ '..>'
77
79
  else
78
- "--"
80
+ '--'
79
81
  end
80
82
 
81
83
  line = " #{source}"
@@ -83,9 +85,13 @@ module Lagoon
83
85
  line += " #{arrow} "
84
86
  line += "\"#{target_cardinality}\" " if target_cardinality
85
87
  line += target
86
- line += " : #{label}" if label
88
+ line += " : #{escape_label(label)}" if label && !label.to_s.empty?
87
89
  line
88
90
  end
91
+
92
+ def relationship_sort_key(relationship)
93
+ %i[source target type label].map { |key| relationship[key].to_s }
94
+ end
89
95
  end
90
96
  end
91
97
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lagoon
4
+ module Renderer
5
+ class ControllerModelErRenderer < BaseRenderer
6
+ def initialize(options = {})
7
+ super(direction: options[:direction] || 'TB')
8
+ @show_actions = options.fetch(:show_actions, true)
9
+ end
10
+
11
+ def render(parsed_data)
12
+ output = ['classDiagram', " direction #{@direction}", '']
13
+
14
+ relationships = parsed_data[:relationships] || []
15
+ return output.join("\n").rstrip if relationships.empty?
16
+
17
+ render_classes(output, relationships)
18
+ output << ''
19
+
20
+ relationships.sort_by { |rel| [rel[:controller].to_s, rel[:model].to_s] }.each do |rel|
21
+ output << render_relationship(rel)
22
+ end
23
+
24
+ output.join("\n").rstrip
25
+ end
26
+
27
+ private
28
+
29
+ def render_relationship(rel)
30
+ controller = safe_identifier(rel[:controller])
31
+ model = safe_identifier(rel[:model])
32
+ actions = rel[:actions] || []
33
+ label = @show_actions && actions.any? ? " : #{escape_label(actions.sort.join(', '))}" : ''
34
+
35
+ " #{controller} ..> #{model}#{label}"
36
+ end
37
+
38
+ def render_classes(output, relationships)
39
+ controllers = relationships.filter_map { |rel| rel[:controller] }.uniq.sort
40
+ models = relationships.filter_map { |rel| rel[:model] }.uniq.sort
41
+
42
+ controllers.each { |name| output << " class #{aliased_identifier(name)}" }
43
+ models.each { |name| output << " class #{aliased_identifier(name)}" }
44
+ end
45
+ end
46
+ end
47
+ end
@@ -4,101 +4,102 @@ module Lagoon
4
4
  module Renderer
5
5
  class ErDiagramRenderer < BaseRenderer
6
6
  def render(parsed_data)
7
- output = ["erDiagram"]
7
+ output = ['erDiagram']
8
8
 
9
- # リレーションシップを先に追加
10
9
  if parsed_data[:relationships]&.any?
11
- parsed_data[:relationships].each do |rel|
10
+ parsed_data[:relationships].sort_by { |rel| relationship_sort_key(rel) }.each do |rel|
12
11
  output << render_relationship(rel)
13
12
  end
14
- output << ""
13
+ output << ''
15
14
  end
16
15
 
17
- # エンティティ定義を追加
18
- parsed_data[:entities].each do |entity|
16
+ parsed_data.fetch(:entities, []).sort_by { |entity| entity[:name].to_s }.each do |entity|
19
17
  output << render_entity(entity)
20
18
  end
21
19
 
22
- output.join("\n")
20
+ output.join("\n").rstrip
23
21
  end
24
22
 
25
23
  private
26
24
 
27
25
  def render_entity(entity)
28
26
  lines = []
29
- entity_name = entity[:name].upcase
27
+ entity_name = aliased_identifier(entity[:name], uppercase: true)
30
28
 
31
29
  lines << " #{entity_name} {"
32
- entity[:attributes].each do |attr|
30
+ entity.fetch(:attributes, []).sort_by { |attr| attr[:name].to_s }.each do |attr|
33
31
  type = type_to_er_type(attr[:type])
34
32
  constraints = []
35
- constraints << "PK" if attr[:primary_key]
36
- constraints << "FK" if attr[:foreign_key]
37
- constraints << "UK" if attr[:unique]
33
+ constraints << 'PK' if attr[:primary_key]
34
+ constraints << 'FK' if attr[:foreign_key]
35
+ constraints << 'UK' if attr[:unique]
38
36
 
39
- line = " #{type} #{attr[:name]}"
40
- line += " #{constraints.join(" ")}" if constraints.any?
37
+ line = " #{safe_identifier(type)} #{safe_identifier(attr[:name])}"
38
+ line += " #{constraints.join(',')}" if constraints.any?
39
+ line += " #{mermaid_string(attr[:name])}" if safe_identifier(attr[:name]) != attr[:name].to_s
41
40
  lines << line
42
41
  end
43
- lines << " }"
44
- lines << ""
42
+ lines << ' }'
43
+ lines << ''
45
44
 
46
45
  lines.join("\n")
47
46
  end
48
47
 
49
48
  def render_relationship(rel)
50
- source = rel[:source].upcase
51
- target = rel[:target].upcase
49
+ source = safe_identifier(rel[:source], uppercase: true)
50
+ target = safe_identifier(rel[:target], uppercase: true)
52
51
  label = rel[:label]
53
52
 
54
- # カーディナリティを決定
55
53
  source_card = cardinality_symbol(rel[:source_cardinality])
56
54
  target_card = cardinality_symbol(rel[:target_cardinality])
57
55
 
58
- # 関係の種類(識別 or 非識別)
59
- line_type = rel[:identifying] ? "--" : ".."
56
+ line_type = rel[:identifying] ? '--' : '..'
60
57
 
61
- " #{source} #{source_card}#{line_type}#{target_card} #{target} : \"#{label}\""
58
+ " #{source} #{source_card}#{line_type}#{target_card} #{target} : #{mermaid_string(label)}"
62
59
  end
63
60
 
64
61
  def cardinality_symbol(cardinality)
65
- case cardinality
66
- when "1", "one"
67
- "||"
68
- when "0..1", "zero_or_one"
69
- "|o"
70
- when "1..*", "one_or_more"
71
- "}|"
72
- when "*", "0..*", "zero_or_more", "many"
73
- "}o"
62
+ case cardinality&.to_sym
63
+ when :one
64
+ '||'
65
+ when :zero_or_one
66
+ 'o|'
67
+ when :one_or_more
68
+ '}|'
69
+ when :zero_or_many
70
+ 'o{'
74
71
  else
75
- "||" # デフォルト
72
+ raise ConfigurationError, "Unknown ER cardinality: #{cardinality.inspect}"
76
73
  end
77
74
  end
78
75
 
76
+ def relationship_sort_key(relationship)
77
+ %i[source target label].map { |key| relationship[key].to_s }
78
+ end
79
+
79
80
  def type_to_er_type(type)
80
81
  # Ruby/Rails型をERダイアグラム用の型に変換
81
82
  case type.to_s.downcase
82
83
  when /integer/, /bigint/
83
- "int"
84
+ 'int'
84
85
  when /string/, /varchar/
85
- "string"
86
+ 'string'
86
87
  when /text/
87
- "text"
88
+ 'text'
88
89
  when /boolean/
89
- "boolean"
90
+ 'boolean'
90
91
  when /datetime/, /timestamp/
91
- "datetime"
92
+ 'datetime'
92
93
  when /date/
93
- "date"
94
+ 'date'
94
95
  when /time/
95
- "time"
96
+ 'time'
96
97
  when /decimal/, /numeric/
97
- "decimal"
98
+ 'decimal'
98
99
  when /float/, /double/
99
- "float"
100
+ 'float'
100
101
  when /json/, /jsonb/
101
- "json"
102
+ 'json'
102
103
  else
103
104
  type.to_s.downcase
104
105
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lagoon
4
+ Result = Data.define(:path, :content, :warnings, :counts) do
5
+ def initialize(path:, content:, warnings: [], counts: {})
6
+ super(
7
+ path: path.to_s.freeze,
8
+ content: content.to_s.freeze,
9
+ warnings: warnings.map(&:to_s).freeze,
10
+ counts: counts.transform_keys(&:to_sym).freeze
11
+ )
12
+ end
13
+
14
+ def to_s
15
+ path
16
+ end
17
+
18
+ def to_path
19
+ path
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lagoon
4
- VERSION = "0.1.0"
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/lagoon.rb CHANGED
@@ -1,22 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "lagoon/version"
4
- require_relative "lagoon/configuration"
5
- require_relative "lagoon/diagram/base"
6
- require_relative "lagoon/diagram/model_diagram"
7
- require_relative "lagoon/diagram/controller_diagram"
8
- require_relative "lagoon/diagram/er_diagram"
9
- require_relative "lagoon/parser/model_parser"
10
- require_relative "lagoon/parser/controller_parser"
11
- require_relative "lagoon/parser/schema_parser"
12
- require_relative "lagoon/renderer/base_renderer"
13
- require_relative "lagoon/renderer/class_diagram_renderer"
14
- require_relative "lagoon/renderer/er_diagram_renderer"
15
- require_relative "lagoon/railtie" if defined?(Rails::Railtie)
3
+ require 'logger'
4
+ require 'active_support'
5
+ require_relative 'lagoon/version'
6
+ require_relative 'lagoon/errors'
7
+ require_relative 'lagoon/result'
8
+ require_relative 'lagoon/configuration'
9
+ require_relative 'lagoon/options'
10
+ require_relative 'lagoon/diagram/base'
11
+ require_relative 'lagoon/diagram/model_diagram'
12
+ require_relative 'lagoon/diagram/controller_diagram'
13
+ require_relative 'lagoon/diagram/er_diagram'
14
+ require_relative 'lagoon/diagram/controller_model_diagram'
15
+ require_relative 'lagoon/analyzer/active_record_analyzer'
16
+ require_relative 'lagoon/analyzer/action_controller_analyzer'
17
+ require_relative 'lagoon/analyzer/database_schema_analyzer'
18
+ require_relative 'lagoon/parser/application_class_filter'
19
+ require_relative 'lagoon/parser/model_parser'
20
+ require_relative 'lagoon/parser/controller_parser'
21
+ require_relative 'lagoon/parser/schema_parser'
22
+ require_relative 'lagoon/parser/controller_model_parser'
23
+ require_relative 'lagoon/renderer/base_renderer'
24
+ require_relative 'lagoon/renderer/class_diagram_renderer'
25
+ require_relative 'lagoon/renderer/er_diagram_renderer'
26
+ require_relative 'lagoon/renderer/controller_model_er_renderer'
27
+ require_relative 'lagoon/railtie' if defined?(Rails::Railtie)
16
28
 
17
29
  module Lagoon
18
- class Error < StandardError; end
19
-
20
30
  class << self
21
31
  attr_writer :configuration
22
32
 
@@ -28,24 +38,63 @@ module Lagoon
28
38
  yield(configuration)
29
39
  end
30
40
 
41
+ def reset_configuration!
42
+ @configuration = Configuration.new
43
+ end
44
+
31
45
  def generate_model_diagram(options = {})
32
- Diagram::ModelDiagram.new(options).generate
46
+ Diagram::ModelDiagram.new(options, configuration: configuration.dup).generate
33
47
  end
34
48
 
35
49
  def generate_controller_diagram(options = {})
36
- Diagram::ControllerDiagram.new(options).generate
50
+ Diagram::ControllerDiagram.new(options, configuration: configuration.dup).generate
37
51
  end
38
52
 
39
53
  def generate_er_diagram(options = {})
40
- Diagram::ErDiagram.new(options).generate
54
+ Diagram::ErDiagram.new(options, configuration: configuration.dup).generate
55
+ end
56
+
57
+ def generate_controller_model_diagram(options = {})
58
+ Diagram::ControllerModelDiagram.new(options, configuration: configuration.dup).generate
41
59
  end
42
60
 
43
61
  def generate_all(options = {})
62
+ raw_options = options.to_h.transform_keys(&:to_sym)
63
+ validate_all_options!(raw_options)
64
+ eager_load_application!
65
+ output_dir = raw_options.delete(:output)
66
+
44
67
  {
45
- models: generate_model_diagram(options),
46
- controllers: generate_controller_diagram(options),
47
- er: generate_er_diagram(options)
68
+ models: generate_model_diagram(options_for(:model, raw_options, output_dir, 'models.mermaid')),
69
+ controllers: generate_controller_diagram(
70
+ options_for(:controller, raw_options, output_dir, 'controllers.mermaid')
71
+ ),
72
+ er: generate_er_diagram(options_for(:er, raw_options, output_dir, 'er_diagram.mermaid')),
73
+ controller_models: generate_controller_model_diagram(
74
+ options_for(:controller_model, raw_options, output_dir, 'controller_models.mermaid')
75
+ )
48
76
  }
49
77
  end
78
+
79
+ private
80
+
81
+ def eager_load_application!
82
+ Rails.application.eager_load! if defined?(Rails) && Rails.respond_to?(:application)
83
+ end
84
+
85
+ def validate_all_options!(options)
86
+ allowed = Options::KEYS.values.flatten.uniq + [:output]
87
+ unknown = options.keys - allowed
88
+ return if unknown.empty?
89
+
90
+ raise ConfigurationError, "Unknown all option(s): #{unknown.sort.join(', ')}"
91
+ end
92
+
93
+ def options_for(kind, options, output_dir, filename)
94
+ selected = options.slice(*Options.allowed_keys(kind))
95
+ selected[:eager_load] = false
96
+ selected[:output] = File.join(output_dir.to_s, filename) if output_dir
97
+ selected
98
+ end
50
99
  end
51
100
  end
@@ -1,39 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  namespace :mermaid do
4
- desc "Generate all Mermaid diagrams"
4
+ desc 'Generate all Mermaid diagrams'
5
5
  task all: :environment do
6
6
  results = Lagoon.generate_all
7
- puts "All diagrams generated:"
7
+ puts 'All diagrams generated:'
8
8
  puts " Models: #{results[:models]}"
9
9
  puts " Controllers: #{results[:controllers]}"
10
10
  puts " ER: #{results[:er]}"
11
+ puts " Controller-Models: #{results[:controller_models]}"
11
12
  end
12
13
 
13
- desc "Generate Mermaid model diagram"
14
+ desc 'Generate Mermaid model diagram'
14
15
  task models: :environment do
15
16
  output_file = Lagoon.generate_model_diagram
16
17
  puts "Model diagram generated: #{output_file}"
17
18
  end
18
19
 
19
- desc "Generate Mermaid controller diagram"
20
+ desc 'Generate Mermaid controller diagram'
20
21
  task controllers: :environment do
21
22
  output_file = Lagoon.generate_controller_diagram
22
23
  puts "Controller diagram generated: #{output_file}"
23
24
  end
24
25
 
25
- desc "Generate Mermaid ER diagram"
26
+ desc 'Generate Mermaid ER diagram'
26
27
  task er: :environment do
27
28
  output_file = Lagoon.generate_er_diagram
28
29
  puts "ER diagram generated: #{output_file}"
29
30
  end
30
31
 
31
- desc "Generate brief diagrams (no attributes/methods)"
32
+ desc 'Generate controller-model relationship diagram'
33
+ task controller_models: :environment do
34
+ output_file = Lagoon.generate_controller_model_diagram
35
+ puts "Controller-model diagram generated: #{output_file}"
36
+ end
37
+
38
+ desc 'Generate brief diagrams (no attributes/methods)'
32
39
  task brief: :environment do
33
40
  results = Lagoon.generate_all(brief: true)
34
- puts "Brief diagrams generated:"
41
+ puts 'Brief diagrams generated:'
35
42
  puts " Models: #{results[:models]}"
36
43
  puts " Controllers: #{results[:controllers]}"
37
44
  puts " ER: #{results[:er]}"
45
+ puts " Controller-Models: #{results[:controller_models]}"
38
46
  end
39
47
  end
data/sig/lagoon.rbs ADDED
@@ -0,0 +1,107 @@
1
+ module Lagoon
2
+ VERSION: String
3
+
4
+ type option_key = Symbol | String
5
+ type options_hash = Hash[option_key, untyped]
6
+ type counts_hash = Hash[Symbol, Integer]
7
+
8
+ class Error < StandardError
9
+ end
10
+
11
+ class ConfigurationError < Error
12
+ end
13
+
14
+ class RailsLoadError < Error
15
+ end
16
+
17
+ class ParseError < Error
18
+ end
19
+
20
+ class OutputError < Error
21
+ end
22
+
23
+ class Configuration
24
+ DIRECTIONS: Array[String]
25
+
26
+ attr_accessor show_attributes: bool
27
+ attr_accessor show_methods: bool
28
+ attr_accessor include_inheritance: bool
29
+ attr_accessor exclude_models: Array[String]
30
+ attr_accessor exclude_controllers: Array[String]
31
+ attr_accessor exclude_tables: Array[String]
32
+ attr_accessor internal_tables: Array[String]
33
+ attr_accessor include_framework_bases: bool
34
+ attr_accessor strict: bool
35
+ attr_accessor helper_models: Hash[String, String]
36
+ attr_reader output_dir: String
37
+ attr_reader diagram_direction: String
38
+
39
+ def initialize: () -> void
40
+ def output_dir=: (String value) -> String
41
+ def diagram_direction=: (String value) -> String
42
+ def self.validate_direction!: (String | Symbol value) -> String
43
+ def initialize_copy: (Configuration original) -> void
44
+ end
45
+
46
+ class Options
47
+ include Enumerable[[Symbol, untyped]]
48
+
49
+ COMMON_KEYS: Array[Symbol]
50
+ KEYS: Hash[Symbol, Array[Symbol]]
51
+
52
+ attr_reader kind: Symbol
53
+
54
+ def self.for: (Symbol kind, ?options_hash? raw_options, ?config: Configuration, **untyped keyword_options) -> Options
55
+ def self.allowed_keys: (Symbol kind) -> Array[Symbol]
56
+ def initialize: (Symbol kind, ?options_hash raw_options, ?config: Configuration) -> void
57
+ def []: (option_key key) -> untyped
58
+ def fetch: (option_key key, *untyped defaults) { (Symbol) -> untyped } -> untyped
59
+ | (option_key key, *untyped defaults) -> untyped
60
+ def key?: (option_key key) -> bool
61
+ def each: () { ([Symbol, untyped]) -> void } -> Options
62
+ def to_h: () -> Hash[Symbol, untyped]
63
+ end
64
+
65
+ class Result
66
+ attr_reader path: String
67
+ attr_reader content: String
68
+ attr_reader warnings: Array[String]
69
+ attr_reader counts: counts_hash
70
+
71
+ def initialize: (path: String, content: String, ?warnings: Array[String], ?counts: counts_hash) -> void
72
+ def to_s: () -> String
73
+ def to_path: () -> String
74
+ end
75
+
76
+ def self.configuration: () -> Configuration
77
+ def self.configuration=: (Configuration configuration) -> Configuration
78
+ def self.configure: () { (Configuration) -> untyped } -> untyped
79
+ def self.reset_configuration!: () -> Configuration
80
+ def self.generate_model_diagram: (?options_hash options) -> Result
81
+ def self.generate_controller_diagram: (?options_hash options) -> Result
82
+ def self.generate_er_diagram: (?options_hash options) -> Result
83
+ def self.generate_controller_model_diagram: (?options_hash options) -> Result
84
+ def self.generate_all: (?options_hash options) -> Hash[Symbol, Result]
85
+
86
+ module Diagram
87
+ class Base
88
+ attr_reader options: Options
89
+ attr_reader config: Configuration
90
+
91
+ def initialize: (?options_hash? options, ?configuration: Configuration, **untyped keyword_options) -> void
92
+ def generate: () -> Result
93
+ end
94
+
95
+ class ModelDiagram < Base
96
+ end
97
+
98
+ class ControllerDiagram < Base
99
+ end
100
+
101
+ class ErDiagram < Base
102
+ end
103
+
104
+ class ControllerModelDiagram < Base
105
+ end
106
+ end
107
+ end