lagoon 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +229 -0
- data/Rakefile +8 -0
- data/exe/lagoon +8 -0
- data/lib/lagoon/cli.rb +112 -0
- data/lib/lagoon/configuration.rb +20 -0
- data/lib/lagoon/diagram/base.rb +38 -0
- data/lib/lagoon/diagram/controller_diagram.rb +31 -0
- data/lib/lagoon/diagram/er_diagram.rb +31 -0
- data/lib/lagoon/diagram/model_diagram.rb +31 -0
- data/lib/lagoon/parser/controller_parser.rb +94 -0
- data/lib/lagoon/parser/model_parser.rb +161 -0
- data/lib/lagoon/parser/schema_parser.rb +114 -0
- data/lib/lagoon/railtie.rb +11 -0
- data/lib/lagoon/renderer/base_renderer.rb +45 -0
- data/lib/lagoon/renderer/class_diagram_renderer.rb +91 -0
- data/lib/lagoon/renderer/er_diagram_renderer.rb +108 -0
- data/lib/lagoon/version.rb +5 -0
- data/lib/lagoon.rb +51 -0
- data/lib/tasks/lagoon.rake +39 -0
- metadata +94 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/string"
|
|
4
|
+
|
|
5
|
+
module Lagoon
|
|
6
|
+
module Parser
|
|
7
|
+
class ModelParser
|
|
8
|
+
attr_reader :options, :config
|
|
9
|
+
|
|
10
|
+
def initialize(options = {})
|
|
11
|
+
@options = options
|
|
12
|
+
@config = Lagoon.configuration
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def parse
|
|
16
|
+
models = load_models
|
|
17
|
+
classes = []
|
|
18
|
+
relationships = []
|
|
19
|
+
|
|
20
|
+
models.each do |model|
|
|
21
|
+
next if excluded?(model)
|
|
22
|
+
|
|
23
|
+
classes << parse_model(model)
|
|
24
|
+
relationships.concat(extract_associations(model))
|
|
25
|
+
relationships.concat(extract_inheritance(model)) if config.include_inheritance
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
classes: classes,
|
|
30
|
+
relationships: relationships
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def load_models
|
|
37
|
+
# Railsアプリケーションの全モデルをロード
|
|
38
|
+
return [] unless defined?(Rails)
|
|
39
|
+
|
|
40
|
+
Rails.application.eager_load!
|
|
41
|
+
ActiveRecord::Base.descendants.reject(&:abstract_class?)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def excluded?(model)
|
|
45
|
+
model_name = model.name
|
|
46
|
+
config.exclude_models.include?(model_name)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def parse_model(model)
|
|
50
|
+
{
|
|
51
|
+
name: model.name,
|
|
52
|
+
abstract: model.abstract_class?,
|
|
53
|
+
attributes: config.show_attributes ? extract_columns(model) : [],
|
|
54
|
+
methods: config.show_methods ? extract_methods(model) : []
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def extract_columns(model)
|
|
59
|
+
return [] unless model.table_exists?
|
|
60
|
+
|
|
61
|
+
columns = if options[:all_columns]
|
|
62
|
+
model.columns
|
|
63
|
+
else
|
|
64
|
+
model.columns.reject { |col| magic_field?(col.name) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
columns.map do |column|
|
|
68
|
+
{
|
|
69
|
+
name: column.name,
|
|
70
|
+
type: column.type,
|
|
71
|
+
visibility: "+"
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def magic_field?(field_name)
|
|
77
|
+
# マジックフィールド(created_at, updated_at等)を判定
|
|
78
|
+
return false if options[:all_columns]
|
|
79
|
+
|
|
80
|
+
%w[id created_at updated_at].include?(field_name)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def extract_methods(_model)
|
|
84
|
+
# publicメソッドを抽出(必要に応じて実装)
|
|
85
|
+
[]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def extract_associations(model)
|
|
89
|
+
associations = []
|
|
90
|
+
|
|
91
|
+
model.reflect_on_all_associations.each do |assoc|
|
|
92
|
+
next if assoc.options[:through] && options[:hide_through]
|
|
93
|
+
|
|
94
|
+
associations << build_association(model, assoc)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
associations.compact
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def build_association(model, assoc)
|
|
101
|
+
case assoc.macro
|
|
102
|
+
when :belongs_to
|
|
103
|
+
return nil unless options[:show_belongs_to]
|
|
104
|
+
|
|
105
|
+
{
|
|
106
|
+
source: model.name,
|
|
107
|
+
target: assoc.class_name,
|
|
108
|
+
type: :association,
|
|
109
|
+
label: "belongs_to #{assoc.name}",
|
|
110
|
+
source_cardinality: "1",
|
|
111
|
+
target_cardinality: "0..1"
|
|
112
|
+
}
|
|
113
|
+
when :has_one
|
|
114
|
+
{
|
|
115
|
+
source: model.name,
|
|
116
|
+
target: assoc.class_name,
|
|
117
|
+
type: :association,
|
|
118
|
+
label: "has_one #{assoc.name}",
|
|
119
|
+
source_cardinality: "1",
|
|
120
|
+
target_cardinality: "0..1"
|
|
121
|
+
}
|
|
122
|
+
when :has_many
|
|
123
|
+
{
|
|
124
|
+
source: model.name,
|
|
125
|
+
target: assoc.class_name,
|
|
126
|
+
type: :association,
|
|
127
|
+
label: "has_many #{assoc.name}",
|
|
128
|
+
source_cardinality: "1",
|
|
129
|
+
target_cardinality: "*"
|
|
130
|
+
}
|
|
131
|
+
when :has_and_belongs_to_many
|
|
132
|
+
{
|
|
133
|
+
source: model.name,
|
|
134
|
+
target: assoc.class_name,
|
|
135
|
+
type: :association,
|
|
136
|
+
label: "has_and_belongs_to_many #{assoc.name}",
|
|
137
|
+
source_cardinality: "*",
|
|
138
|
+
target_cardinality: "*"
|
|
139
|
+
}
|
|
140
|
+
end
|
|
141
|
+
rescue NameError
|
|
142
|
+
# アソシエーション先のクラスが見つからない場合はスキップ
|
|
143
|
+
nil
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def extract_inheritance(model)
|
|
147
|
+
return [] if model.superclass == ActiveRecord::Base
|
|
148
|
+
return [] if model.superclass.abstract_class?
|
|
149
|
+
|
|
150
|
+
[{
|
|
151
|
+
source: model.superclass.name,
|
|
152
|
+
target: model.name,
|
|
153
|
+
type: :inheritance,
|
|
154
|
+
label: nil
|
|
155
|
+
}]
|
|
156
|
+
rescue StandardError
|
|
157
|
+
[]
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/core_ext/string"
|
|
4
|
+
|
|
5
|
+
module Lagoon
|
|
6
|
+
module Parser
|
|
7
|
+
class SchemaParser
|
|
8
|
+
attr_reader :options, :config
|
|
9
|
+
|
|
10
|
+
def initialize(options = {})
|
|
11
|
+
@options = options
|
|
12
|
+
@config = Lagoon.configuration
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def parse
|
|
16
|
+
tables = load_schema
|
|
17
|
+
entities = []
|
|
18
|
+
relationships = []
|
|
19
|
+
|
|
20
|
+
tables.each do |table_name, columns|
|
|
21
|
+
next if excluded?(table_name)
|
|
22
|
+
|
|
23
|
+
entity = parse_table(table_name, columns)
|
|
24
|
+
entities << entity
|
|
25
|
+
relationships.concat(extract_foreign_keys(table_name, columns))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
{
|
|
29
|
+
entities: entities,
|
|
30
|
+
relationships: relationships
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def load_schema
|
|
37
|
+
return {} unless defined?(ActiveRecord)
|
|
38
|
+
|
|
39
|
+
connection = ActiveRecord::Base.connection
|
|
40
|
+
tables_hash = {}
|
|
41
|
+
|
|
42
|
+
connection.tables.each do |table_name|
|
|
43
|
+
next if internal_table?(table_name)
|
|
44
|
+
|
|
45
|
+
columns = connection.columns(table_name)
|
|
46
|
+
tables_hash[table_name] = columns
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
tables_hash
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def internal_table?(table_name)
|
|
53
|
+
# Railsの内部テーブルをスキップ
|
|
54
|
+
%w[schema_migrations ar_internal_metadata].include?(table_name)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def excluded?(_table_name)
|
|
58
|
+
false # 必要に応じて除外ロジックを追加
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def parse_table(table_name, columns)
|
|
62
|
+
{
|
|
63
|
+
name: table_name,
|
|
64
|
+
attributes: columns.map { |col| parse_column(col) }
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def parse_column(column)
|
|
69
|
+
{
|
|
70
|
+
name: column.name,
|
|
71
|
+
type: column.type,
|
|
72
|
+
primary_key: column.name == "id",
|
|
73
|
+
foreign_key: foreign_key?(column.name),
|
|
74
|
+
unique: false # 必要に応じて実装
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def foreign_key?(column_name)
|
|
79
|
+
column_name.end_with?("_id")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def extract_foreign_keys(table_name, columns)
|
|
83
|
+
relationships = []
|
|
84
|
+
|
|
85
|
+
columns.each do |column|
|
|
86
|
+
next unless foreign_key?(column.name)
|
|
87
|
+
|
|
88
|
+
# column_nameから参照先テーブルを推測 (例: user_id -> users)
|
|
89
|
+
target_table = infer_target_table(column.name)
|
|
90
|
+
next unless target_table
|
|
91
|
+
|
|
92
|
+
relationships << {
|
|
93
|
+
source: table_name,
|
|
94
|
+
target: target_table,
|
|
95
|
+
label: "has many",
|
|
96
|
+
source_cardinality: "||",
|
|
97
|
+
target_cardinality: "}o",
|
|
98
|
+
identifying: true
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
relationships
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def infer_target_table(foreign_key_name)
|
|
106
|
+
# user_id -> users のように推測
|
|
107
|
+
base_name = foreign_key_name.sub(/_id$/, "")
|
|
108
|
+
base_name.pluralize
|
|
109
|
+
rescue StandardError
|
|
110
|
+
nil
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lagoon
|
|
4
|
+
module Renderer
|
|
5
|
+
class BaseRenderer
|
|
6
|
+
attr_reader :direction
|
|
7
|
+
|
|
8
|
+
def initialize(direction: "TB")
|
|
9
|
+
@direction = direction
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def render(parsed_data)
|
|
13
|
+
raise NotImplementedError, "Subclasses must implement #render"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
protected
|
|
17
|
+
|
|
18
|
+
def escape_class_name(name)
|
|
19
|
+
# Mermaidで特殊文字を含むクラス名をエスケープ
|
|
20
|
+
if name.match?(/[^a-zA-Z0-9_]/)
|
|
21
|
+
"`#{name}`"
|
|
22
|
+
else
|
|
23
|
+
name
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def type_to_mermaid(type)
|
|
28
|
+
# Ruby/Rails型をMermaid表記に変換
|
|
29
|
+
case type.to_s
|
|
30
|
+
when /integer/i then "Integer"
|
|
31
|
+
when /string/i then "String"
|
|
32
|
+
when /text/i then "Text"
|
|
33
|
+
when /boolean/i then "Boolean"
|
|
34
|
+
when /datetime/i then "DateTime"
|
|
35
|
+
when /date/i then "Date"
|
|
36
|
+
when /time/i then "Time"
|
|
37
|
+
when /decimal/i then "Decimal"
|
|
38
|
+
when /float/i then "Float"
|
|
39
|
+
when /json/i then "JSON"
|
|
40
|
+
else type.to_s.capitalize
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lagoon
|
|
4
|
+
module Renderer
|
|
5
|
+
class ClassDiagramRenderer < BaseRenderer
|
|
6
|
+
def render(parsed_data)
|
|
7
|
+
output = ["classDiagram"]
|
|
8
|
+
output << " direction #{@direction}"
|
|
9
|
+
output << ""
|
|
10
|
+
|
|
11
|
+
# クラス定義を追加
|
|
12
|
+
parsed_data[:classes].each do |klass|
|
|
13
|
+
output << render_class(klass)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
output << ""
|
|
17
|
+
|
|
18
|
+
# 関係性を追加
|
|
19
|
+
parsed_data[:relationships].each do |rel|
|
|
20
|
+
output << render_relationship(rel)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
output.join("\n")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def render_class(klass)
|
|
29
|
+
lines = []
|
|
30
|
+
class_name = escape_class_name(klass[:name])
|
|
31
|
+
|
|
32
|
+
lines << " class #{class_name} {"
|
|
33
|
+
lines << " <<abstract>>" if klass[:abstract]
|
|
34
|
+
|
|
35
|
+
# 属性を追加
|
|
36
|
+
if klass[:attributes]&.any?
|
|
37
|
+
klass[:attributes].each do |attr|
|
|
38
|
+
visibility = attr[:visibility] || "+"
|
|
39
|
+
type = type_to_mermaid(attr[:type])
|
|
40
|
+
lines << " #{visibility}#{type} #{attr[:name]}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# メソッドを追加
|
|
45
|
+
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}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
lines << " }"
|
|
54
|
+
lines << ""
|
|
55
|
+
lines.join("\n")
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def render_relationship(rel)
|
|
59
|
+
source = escape_class_name(rel[:source])
|
|
60
|
+
target = escape_class_name(rel[:target])
|
|
61
|
+
type = rel[:type]
|
|
62
|
+
label = rel[:label]
|
|
63
|
+
source_cardinality = rel[:source_cardinality]
|
|
64
|
+
target_cardinality = rel[:target_cardinality]
|
|
65
|
+
|
|
66
|
+
arrow = case type
|
|
67
|
+
when :inheritance
|
|
68
|
+
"<|--"
|
|
69
|
+
when :composition
|
|
70
|
+
"*--"
|
|
71
|
+
when :aggregation
|
|
72
|
+
"o--"
|
|
73
|
+
when :association
|
|
74
|
+
"-->"
|
|
75
|
+
when :dependency
|
|
76
|
+
"..>"
|
|
77
|
+
else
|
|
78
|
+
"--"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
line = " #{source}"
|
|
82
|
+
line += " \"#{source_cardinality}\"" if source_cardinality
|
|
83
|
+
line += " #{arrow} "
|
|
84
|
+
line += "\"#{target_cardinality}\" " if target_cardinality
|
|
85
|
+
line += target
|
|
86
|
+
line += " : #{label}" if label
|
|
87
|
+
line
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lagoon
|
|
4
|
+
module Renderer
|
|
5
|
+
class ErDiagramRenderer < BaseRenderer
|
|
6
|
+
def render(parsed_data)
|
|
7
|
+
output = ["erDiagram"]
|
|
8
|
+
|
|
9
|
+
# リレーションシップを先に追加
|
|
10
|
+
if parsed_data[:relationships]&.any?
|
|
11
|
+
parsed_data[:relationships].each do |rel|
|
|
12
|
+
output << render_relationship(rel)
|
|
13
|
+
end
|
|
14
|
+
output << ""
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# エンティティ定義を追加
|
|
18
|
+
parsed_data[:entities].each do |entity|
|
|
19
|
+
output << render_entity(entity)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
output.join("\n")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def render_entity(entity)
|
|
28
|
+
lines = []
|
|
29
|
+
entity_name = entity[:name].upcase
|
|
30
|
+
|
|
31
|
+
lines << " #{entity_name} {"
|
|
32
|
+
entity[:attributes].each do |attr|
|
|
33
|
+
type = type_to_er_type(attr[:type])
|
|
34
|
+
constraints = []
|
|
35
|
+
constraints << "PK" if attr[:primary_key]
|
|
36
|
+
constraints << "FK" if attr[:foreign_key]
|
|
37
|
+
constraints << "UK" if attr[:unique]
|
|
38
|
+
|
|
39
|
+
line = " #{type} #{attr[:name]}"
|
|
40
|
+
line += " #{constraints.join(" ")}" if constraints.any?
|
|
41
|
+
lines << line
|
|
42
|
+
end
|
|
43
|
+
lines << " }"
|
|
44
|
+
lines << ""
|
|
45
|
+
|
|
46
|
+
lines.join("\n")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def render_relationship(rel)
|
|
50
|
+
source = rel[:source].upcase
|
|
51
|
+
target = rel[:target].upcase
|
|
52
|
+
label = rel[:label]
|
|
53
|
+
|
|
54
|
+
# カーディナリティを決定
|
|
55
|
+
source_card = cardinality_symbol(rel[:source_cardinality])
|
|
56
|
+
target_card = cardinality_symbol(rel[:target_cardinality])
|
|
57
|
+
|
|
58
|
+
# 関係の種類(識別 or 非識別)
|
|
59
|
+
line_type = rel[:identifying] ? "--" : ".."
|
|
60
|
+
|
|
61
|
+
" #{source} #{source_card}#{line_type}#{target_card} #{target} : \"#{label}\""
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
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"
|
|
74
|
+
else
|
|
75
|
+
"||" # デフォルト
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def type_to_er_type(type)
|
|
80
|
+
# Ruby/Rails型をERダイアグラム用の型に変換
|
|
81
|
+
case type.to_s.downcase
|
|
82
|
+
when /integer/, /bigint/
|
|
83
|
+
"int"
|
|
84
|
+
when /string/, /varchar/
|
|
85
|
+
"string"
|
|
86
|
+
when /text/
|
|
87
|
+
"text"
|
|
88
|
+
when /boolean/
|
|
89
|
+
"boolean"
|
|
90
|
+
when /datetime/, /timestamp/
|
|
91
|
+
"datetime"
|
|
92
|
+
when /date/
|
|
93
|
+
"date"
|
|
94
|
+
when /time/
|
|
95
|
+
"time"
|
|
96
|
+
when /decimal/, /numeric/
|
|
97
|
+
"decimal"
|
|
98
|
+
when /float/, /double/
|
|
99
|
+
"float"
|
|
100
|
+
when /json/, /jsonb/
|
|
101
|
+
"json"
|
|
102
|
+
else
|
|
103
|
+
type.to_s.downcase
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
data/lib/lagoon.rb
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
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)
|
|
16
|
+
|
|
17
|
+
module Lagoon
|
|
18
|
+
class Error < StandardError; end
|
|
19
|
+
|
|
20
|
+
class << self
|
|
21
|
+
attr_writer :configuration
|
|
22
|
+
|
|
23
|
+
def configuration
|
|
24
|
+
@configuration ||= Configuration.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def configure
|
|
28
|
+
yield(configuration)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def generate_model_diagram(options = {})
|
|
32
|
+
Diagram::ModelDiagram.new(options).generate
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def generate_controller_diagram(options = {})
|
|
36
|
+
Diagram::ControllerDiagram.new(options).generate
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def generate_er_diagram(options = {})
|
|
40
|
+
Diagram::ErDiagram.new(options).generate
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def generate_all(options = {})
|
|
44
|
+
{
|
|
45
|
+
models: generate_model_diagram(options),
|
|
46
|
+
controllers: generate_controller_diagram(options),
|
|
47
|
+
er: generate_er_diagram(options)
|
|
48
|
+
}
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :mermaid do
|
|
4
|
+
desc "Generate all Mermaid diagrams"
|
|
5
|
+
task all: :environment do
|
|
6
|
+
results = Lagoon.generate_all
|
|
7
|
+
puts "All diagrams generated:"
|
|
8
|
+
puts " Models: #{results[:models]}"
|
|
9
|
+
puts " Controllers: #{results[:controllers]}"
|
|
10
|
+
puts " ER: #{results[:er]}"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
desc "Generate Mermaid model diagram"
|
|
14
|
+
task models: :environment do
|
|
15
|
+
output_file = Lagoon.generate_model_diagram
|
|
16
|
+
puts "Model diagram generated: #{output_file}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
desc "Generate Mermaid controller diagram"
|
|
20
|
+
task controllers: :environment do
|
|
21
|
+
output_file = Lagoon.generate_controller_diagram
|
|
22
|
+
puts "Controller diagram generated: #{output_file}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc "Generate Mermaid ER diagram"
|
|
26
|
+
task er: :environment do
|
|
27
|
+
output_file = Lagoon.generate_er_diagram
|
|
28
|
+
puts "ER diagram generated: #{output_file}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
desc "Generate brief diagrams (no attributes/methods)"
|
|
32
|
+
task brief: :environment do
|
|
33
|
+
results = Lagoon.generate_all(brief: true)
|
|
34
|
+
puts "Brief diagrams generated:"
|
|
35
|
+
puts " Models: #{results[:models]}"
|
|
36
|
+
puts " Controllers: #{results[:controllers]}"
|
|
37
|
+
puts " ER: #{results[:er]}"
|
|
38
|
+
end
|
|
39
|
+
end
|