schema_doctor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bb30a32516182031828f9be6b2f30a5496d5322ba77f7a4e17aa8655e2ef8596
4
+ data.tar.gz: 40a59308e3e55209061d7995c393ff45071352ee168af12ea09387edf07fcff2
5
+ SHA512:
6
+ metadata.gz: f7cd15084b68dd5b4c7993f5346344f01c2de301f2061ee7230267f2bf738a31b93611924a8532807ae25df8524e44f087d305116c988a6ed78d37ca0ebf2fb3
7
+ data.tar.gz: de186a77d0f1afec160804205a521784919a75f92452558baa8453eebfceebd34cef33fa190519872d4c2a0fdfed0a54f5ebe8bf79c025c0b44a85da45cd9fde
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.standard.yml ADDED
@@ -0,0 +1,3 @@
1
+ # For available configuration options, see:
2
+ # https://github.com/standardrb/standard
3
+ ruby_version: 3.0
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.0.X]
4
+
5
+ - Debug releases
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2024 @lni_T
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # SchemaDoctor
2
+
3
+ TBD
4
+
5
+ ## Installation
6
+
7
+ TBD
8
+
9
+ ## Usage
10
+
11
+ TBD
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "standard/rake"
9
+
10
+ task default: %i[spec standard]
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record"
4
+
5
+ module SchemaDoctor
6
+ class Analyzer
7
+ attr_reader :schema_file
8
+
9
+ def initialize
10
+ @schema_file = SchemaFile.new
11
+ end
12
+
13
+ def analyze_schema
14
+ existing_schema = schema_file.load
15
+
16
+ puts "== Analyzing model schema..."
17
+ new_schema = model_schema(existing_schema || {})
18
+
19
+ puts "== Exporting Specification files..."
20
+ schema_file.dump(new_schema)
21
+ end
22
+
23
+ def model_schema(schema = {})
24
+ models.each do |model|
25
+ next if model.table_name.blank?
26
+
27
+ puts "Processing #{model.name}..."
28
+ schema[model.name] =
29
+ {
30
+ name: model.name,
31
+ table_name: model.table_name,
32
+ table_comment: connection.table_comment(model.table_name),
33
+ extra_comment: schema.dig(model.name, :extra_comment),
34
+ columns: columns(model, schema.dig(model.name, :columns) || {}),
35
+ indexes: indexes(model)
36
+ }
37
+ rescue ActiveRecord::TableNotSpecified
38
+ nil
39
+ end
40
+
41
+ schema
42
+ end
43
+
44
+ private
45
+
46
+ def connection
47
+ @connection ||= ActiveRecord::Base.connection
48
+ end
49
+
50
+ def models
51
+ return @models if @models
52
+
53
+ Rails.application.eager_load! if defined?(Rails)
54
+ @models = ActiveRecord::Base.descendants.sort_by!(&:name)
55
+ end
56
+
57
+ def columns(model, columns = {})
58
+ model.columns.each do |column|
59
+ columns[column.name] =
60
+ {
61
+ name: column.name,
62
+ type: column.type,
63
+ sql_type: column.sql_type,
64
+ default: column.default,
65
+ null: column.null,
66
+ limit: column.limit,
67
+ precision: column.precision,
68
+ scale: column.scale,
69
+ column_comment: column.comment,
70
+ extra_comment: columns.dig(column.name, :extra_comment)
71
+ }
72
+ end
73
+ columns
74
+ end
75
+
76
+ def indexes(model)
77
+ connection.indexes(model.table_name).each_with_object({}) do |index, hash|
78
+ hash[index.name] = {
79
+ name: index.name,
80
+ columns: index.columns,
81
+ unique: index.unique,
82
+ using: index.using
83
+ }
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "asciidoctor"
4
+
5
+ module SchemaDoctor
6
+ class Exporter
7
+ attr_reader :schema_file
8
+
9
+ def initialize
10
+ @schema_file = SchemaFile.new
11
+ end
12
+
13
+ def export_adoc
14
+ puts "== Loading model specifications..."
15
+ specs = schema_file.load
16
+
17
+ puts "== Exporting adoc file..."
18
+ # TODO: Use template
19
+ File.open(adoc_path, "w") do |f|
20
+ f.puts <<~TEXT
21
+ = Rails Model Specification
22
+ :toc: left
23
+ :toclevels: 1
24
+ :toc-title: Table of Contents
25
+ :linkattrs:
26
+
27
+ TEXT
28
+
29
+ specs.each_value do |model|
30
+ f.puts <<~TEXT
31
+ == #{model[:name]}
32
+ * Table name: #{model[:table_name]}
33
+ * Comment: #{model[:table_comment]}
34
+ #{model[:extra_comment]}
35
+
36
+ === Columns
37
+ [cols="1,1,1,1,1,1,1,1,2"]
38
+ |===
39
+ |name|type|sql_type|default|null|limit|precision|scale|comment
40
+
41
+ TEXT
42
+
43
+ # Output columns schema
44
+ model[:columns].each_value do |column|
45
+ column[:column_comment] = column[:column_comment].to_s + column.delete(:extra_comment).to_s
46
+ col_str = column.values.map do |v|
47
+ escaped = v.to_s.gsub("|", "{vbar}") # "|" is table delimiter in asciidoc
48
+ "|#{escaped}\n"
49
+ end.join
50
+
51
+ f.puts <<~TEXT
52
+ #{col_str}
53
+ TEXT
54
+ end
55
+ f.puts "|==="
56
+
57
+ # Output indexes schema
58
+ f.puts <<~TEXT
59
+
60
+ === Indexes
61
+ TEXT
62
+ if model[:indexes].present?
63
+ f.puts <<~TEXT
64
+ [cols="2,2,1,1"]
65
+ |===
66
+ |name|columns|unique|using
67
+
68
+ TEXT
69
+
70
+ model[:indexes].each_value do |index|
71
+ index_str = index.values.map do |v|
72
+ escaped = v.to_s.gsub("|", "{vbar}") # "|" is table delimiter in asciidoc
73
+ "|#{escaped}\n"
74
+ end.join
75
+
76
+ f.puts <<~TEXT
77
+ #{index_str}
78
+ TEXT
79
+ end
80
+
81
+ f.puts "|==="
82
+ else
83
+ f.puts <<~TEXT
84
+ None
85
+
86
+ TEXT
87
+ end
88
+ end
89
+ end
90
+ puts "Done! => #{adoc_path}"
91
+ end
92
+
93
+ def convert_adoc_to_html
94
+ puts "== Converting to html..."
95
+ Asciidoctor.convert_file adoc_path, to_file: html_path, standalone: true, safe: :server
96
+ puts "Done! => #{html_path}"
97
+ end
98
+
99
+ private
100
+
101
+ def export_dir
102
+ "docs/models" # TODO: Configurable
103
+ end
104
+
105
+ def adoc_path
106
+ "#{export_dir}/models.adoc" # TODO: Configurable
107
+ end
108
+
109
+ def html_path
110
+ "#{export_dir}/index.html" # TODO: Configurable
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,7 @@
1
+ module SchemaDoctor
2
+ class Railtie < ::Rails::Railtie
3
+ rake_tasks do
4
+ load File.join(File.dirname(__FILE__), "tasks/schemadoc.rake")
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ module SchemaDoctor
6
+ class SchemaFile
7
+ def load
8
+ return unless Dir.exist?(schema_dir)
9
+
10
+ # Load schema specification files and merge them into a single hash
11
+ Dir.glob("#{schema_dir}/*").inject({}) do |hash, file|
12
+ hash.merge(YAML.load_file(file))
13
+ end
14
+ end
15
+
16
+ def dump(specs)
17
+ # Output specification files for each model
18
+ FileUtils.mkdir_p(schema_dir)
19
+ specs.each do |name, spec|
20
+ File.open("#{schema_dir}/#{name}.yml", "w") do |f|
21
+ YAML.dump({name => spec}, f)
22
+ end
23
+ end
24
+ end
25
+
26
+ def delete
27
+ FileUtils.rm_rf(schema_dir)
28
+ end
29
+
30
+ private
31
+
32
+ def export_dir
33
+ "docs/models" # TODO: Configurable
34
+ end
35
+
36
+ def schema_dir
37
+ "#{export_dir}/specs" # TODO: Configurable
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :schema do
4
+ desc "Analyze schema and Export yml files"
5
+ task analyze: :environment do
6
+ SchemaDoctor::Analyzer.new.analyze_schema
7
+ end
8
+
9
+ desc "Export schema documentation"
10
+ task export: :environment do
11
+ exporter = SchemaDoctor::Exporter.new
12
+ exporter.export_adoc
13
+ exporter.convert_adoc_to_html
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SchemaDoctor
4
+ VERSION = "0.0.1"
5
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "schema_doctor/version"
4
+ require_relative "schema_doctor/schema_file"
5
+ require_relative "schema_doctor/analyzer"
6
+ require_relative "schema_doctor/exporter"
7
+ require_relative "schema_doctor/railtie"
8
+
9
+ module SchemaDoctor
10
+ class Error < StandardError; end
11
+ end
@@ -0,0 +1,4 @@
1
+ module SchemaDoctor
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schema_doctor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - lni_T
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-07-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: railties
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '7.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '7.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: asciidoctor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ description:
56
+ email:
57
+ - developer.lni@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".rspec"
63
+ - ".standard.yml"
64
+ - CHANGELOG.md
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/schema_doctor.rb
69
+ - lib/schema_doctor/analyzer.rb
70
+ - lib/schema_doctor/exporter.rb
71
+ - lib/schema_doctor/railtie.rb
72
+ - lib/schema_doctor/schema_file.rb
73
+ - lib/schema_doctor/tasks/schemadoc.rake
74
+ - lib/schema_doctor/version.rb
75
+ - sig/schema_doctor.rbs
76
+ homepage: https://github.com/lnit/schema_doctor
77
+ licenses:
78
+ - MIT
79
+ metadata:
80
+ changelog_uri: https://github.com/lnit/schema_doctor/blob/master/CHANGELOG.md
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 3.0.0
90
+ required_rubygems_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: '0'
95
+ requirements: []
96
+ rubygems_version: 3.5.9
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Automatic database documentation tool.
100
+ test_files: []