database_documenter 0.1.6 → 0.1.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 79f3c7ce476383f98904cc065f592a2bfc522507b0bb5e9777b98429f206fde1
4
- data.tar.gz: 52c6cebb47928cb00fc4a1e7f94aa6b807709970e78b3cb38529a7eff34e896c
3
+ metadata.gz: f61327bfc7acbd2f256ae2ad2c93640eb981e01a88a5fb215ed0da8eee35049b
4
+ data.tar.gz: 510687dda8d4aefa92660a767687ed19e91dc31379218f1dc91ed63348cbdc8e
5
5
  SHA512:
6
- metadata.gz: 70679fc84a3e1e0b9e143c0f642d78ed6541cb899e07d7329db83399e5e93788eab57e6dda6b32a8e5236132ff31caeed17545a9c2554ff5f9b200ab85adacf8
7
- data.tar.gz: 3fd5a31dd095a61c12c40c3c701bb683f47be404e18d6018308d3dbc956b3bff65caafd68193479ecd73bf5371d32487de2d2f4ef46f6df09ae739f1830b45de
6
+ metadata.gz: '0269e91c7cac255801c79ddcee20863da8d0b3c1c44ec197b97031dc97dccec92ee09bd9d2dd35e021e8b2fbe5a4d7abf50755e19ad2a37561ab3dd552a8afa7'
7
+ data.tar.gz: e66e7ccef12797577dd78bcd4b53cb17988fd15baddd3627cf17da9bc53d8d44f1f864e3d461c2553c10c82190ca47eb7c231b06a07fe860ed35b36a6cc2cf0b
data/.overcommit.yml ADDED
@@ -0,0 +1,37 @@
1
+ gemfile: Gemfile
2
+
3
+ PreCommit:
4
+ BundleCheck:
5
+ enabled: true
6
+
7
+ FixMe:
8
+ enabled: true
9
+ keywords: ["FIXME"]
10
+ exclude:
11
+ - .overcommit.yml
12
+
13
+ LocalPathsInGemfile:
14
+ enabled: true
15
+
16
+ RailsSchemaUpToDate:
17
+ enabled: false
18
+
19
+ RuboCop:
20
+ enabled: true
21
+ on_warn: fail
22
+
23
+ TrailingWhitespace:
24
+ enabled: true
25
+ exclude:
26
+ - "**/db/structure.sql"
27
+
28
+ YamlSyntax:
29
+ enabled: true
30
+
31
+ HardTabs:
32
+ enabled: true
33
+
34
+ PrePush:
35
+ RSpec:
36
+ enabled: true
37
+ command: ['xvfb-run', '-a', 'bundle', 'exec', 'rspec']
data/.rubocop.yml ADDED
@@ -0,0 +1,84 @@
1
+ AllCops:
2
+ DisplayCopNames: true
3
+ DisplayStyleGuide: true
4
+ TargetRubyVersion: 2.5
5
+ Exclude:
6
+ - "bin/*"
7
+ - Gemfile
8
+
9
+ Layout/SpaceAroundEqualsInParameterDefault:
10
+ EnforcedStyle: no_space
11
+
12
+ Metrics/AbcSize:
13
+ Enabled: false
14
+
15
+ Metrics/BlockLength:
16
+ Exclude:
17
+ - "spec/**/*"
18
+
19
+ Metrics/ClassLength:
20
+ Exclude:
21
+ - "spec/**/*"
22
+
23
+ Metrics/MethodLength:
24
+ Max: 30
25
+ Exclude:
26
+ - "spec/**/*"
27
+
28
+ Metrics/LineLength:
29
+ Enabled: false
30
+
31
+ Naming/MemoizedInstanceVariableName:
32
+ EnforcedStyleForLeadingUnderscores: optional
33
+
34
+ Naming/VariableNumber:
35
+ Enabled: false
36
+
37
+ Rails:
38
+ Enabled: true
39
+
40
+ Rails/ApplicationRecord:
41
+ Exclude:
42
+ - "db/migrate/**"
43
+
44
+ Rails/RefuteMethods:
45
+ Enabled: false
46
+
47
+ Rails/Validation:
48
+ Enabled: false
49
+
50
+ Style/BarePercentLiterals:
51
+ EnforcedStyle: percent_q
52
+
53
+ Style/ClassAndModuleChildren:
54
+ Enabled: false
55
+
56
+ Style/Documentation:
57
+ Enabled: false
58
+
59
+ Style/DoubleNegation:
60
+ Enabled: false
61
+
62
+ Style/EmptyMethod:
63
+ Enabled: false
64
+
65
+ Style/FrozenStringLiteralComment:
66
+ Enabled: false
67
+
68
+ Style/NumericPredicate:
69
+ Enabled: false
70
+
71
+ Style/StringLiterals:
72
+ Enabled: false
73
+
74
+ Style/TrivialAccessors:
75
+ AllowPredicates: true
76
+
77
+ Style/RescueStandardError:
78
+ Enabled: false
79
+
80
+ Rails/HasManyOrHasOneDependent:
81
+ Enabled: false
82
+
83
+ Style/NumericLiterals:
84
+ Enabled: false
data/Gemfile.lock CHANGED
@@ -1,20 +1,38 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- database_documenter (0.1.5)
4
+ database_documenter (0.1.7)
5
5
  caracal (= 1.4.1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
+ ast (2.4.0)
10
11
  caracal (1.4.1)
11
12
  nokogiri (~> 1.6)
12
13
  rubyzip (~> 1.1)
13
14
  tilt (>= 1.4)
15
+ childprocess (1.0.1)
16
+ rake (< 13.0)
17
+ coderay (1.1.2)
14
18
  diff-lcs (1.3)
19
+ iniparse (1.4.4)
20
+ jaro_winkler (1.5.3)
21
+ method_source (0.9.2)
15
22
  mini_portile2 (2.4.0)
16
23
  nokogiri (1.10.3)
17
24
  mini_portile2 (~> 2.4.0)
25
+ overcommit (0.49.0)
26
+ childprocess (>= 0.6.3, < 2.0)
27
+ iniparse (~> 1.4)
28
+ parallel (1.17.0)
29
+ parser (2.6.3.0)
30
+ ast (~> 2.4.0)
31
+ powerpack (0.1.2)
32
+ pry (0.12.2)
33
+ coderay (~> 1.1.0)
34
+ method_source (~> 0.9.0)
35
+ rainbow (3.0.0)
18
36
  rake (10.5.0)
19
37
  rspec (3.8.0)
20
38
  rspec-core (~> 3.8.0)
@@ -29,8 +47,18 @@ GEM
29
47
  diff-lcs (>= 1.2.0, < 2.0)
30
48
  rspec-support (~> 3.8.0)
31
49
  rspec-support (3.8.2)
50
+ rubocop (0.58.2)
51
+ jaro_winkler (~> 1.5.1)
52
+ parallel (~> 1.10)
53
+ parser (>= 2.5, != 2.5.1.1)
54
+ powerpack (~> 0.1)
55
+ rainbow (>= 2.2.2, < 4.0)
56
+ ruby-progressbar (~> 1.7)
57
+ unicode-display_width (~> 1.0, >= 1.0.1)
58
+ ruby-progressbar (1.10.1)
32
59
  rubyzip (1.2.3)
33
60
  tilt (2.0.9)
61
+ unicode-display_width (1.6.0)
34
62
 
35
63
  PLATFORMS
36
64
  ruby
@@ -38,8 +66,11 @@ PLATFORMS
38
66
  DEPENDENCIES
39
67
  bundler (~> 1.17)
40
68
  database_documenter!
69
+ overcommit (= 0.49.0)
70
+ pry (~> 0.12.2)
41
71
  rake (~> 10.0)
42
72
  rspec (~> 3.0)
73
+ rubocop (= 0.58.2)
43
74
 
44
75
  BUNDLED WITH
45
76
  1.17.3
data/README.md CHANGED
@@ -52,10 +52,14 @@ use [migration comments](https://github.com/pinnymz/migration_comments) gem or [
52
52
  ### Rails 5.2
53
53
  use `change_column_comment` and `change_table_comment` methods in rails 5
54
54
 
55
+ ## Contribution
56
+
57
+ - Fork & create a branch
58
+ - bundle install
59
+ - Make sure to run `overcommit --install` before working to run RuboCop before push.
60
+ - Create Pull Request.
61
+
55
62
  ## TODO
56
63
 
57
- - Add more Configurations.
58
- - Add OverCommit
59
64
  - Generate the ERD with the file.
60
- - Clean code.
61
65
  - Add test cases.
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
@@ -1,5 +1,4 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path("lib", __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require "database_documenter/version"
5
4
 
@@ -8,14 +7,14 @@ Gem::Specification.new do |spec|
8
7
  spec.version = DatabaseDocumenter::VERSION
9
8
  spec.authors = ["Ahmed Yehia"]
10
9
  spec.email = ["ruby@espace.com.eg"]
11
- spec.homepage = "https://github.com/espace/db_documenter"
10
+ spec.homepage = "https://github.com/espace/db_documenter"
12
11
 
13
- spec.summary = %q{Generate Database Documentation as a word document}
14
- spec.description = %q{Generate Database Documentation as a word document}
12
+ spec.summary = 'Generate Database Documentation as a word document'
13
+ spec.description = 'Generate Database Documentation as a word document'
15
14
 
16
15
  # Specify which files should be added to the gem when it is released.
17
16
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
18
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
19
18
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
20
19
  end
21
20
  spec.bindir = "exe"
@@ -23,7 +22,11 @@ Gem::Specification.new do |spec|
23
22
  spec.require_paths = ["lib"]
24
23
 
25
24
  spec.add_development_dependency "bundler", "~> 1.17"
25
+ spec.add_development_dependency "overcommit", "=0.49.0"
26
+ spec.add_development_dependency 'pry', '~> 0.12.2'
26
27
  spec.add_development_dependency "rake", "~> 10.0"
27
28
  spec.add_development_dependency "rspec", "~> 3.0"
29
+ spec.add_development_dependency "rubocop", "=0.58.2"
30
+
28
31
  spec.add_dependency 'caracal', '=1.4.1'
29
32
  end
@@ -6,13 +6,15 @@ require 'database_documenter/database_comment/mysql_database_comment'
6
6
  require 'database_documenter/database_comment/postgres_database_comment'
7
7
  require 'database_documenter/tables_sql'
8
8
  require 'database_documenter/column_description'
9
+ require 'database_documenter/table_data'
10
+ require 'database_documenter/exporters/export_to_word'
9
11
  require 'caracal'
10
12
  require "database_documenter/railtie" if defined?(Rails)
11
13
 
12
14
  module DatabaseDocumenter
13
15
  class Error < StandardError; end
14
16
  class << self
15
- attr_accessor :configuration
17
+ attr_writer :configuration
16
18
  end
17
19
 
18
20
  def self.configuration
@@ -1,36 +1,38 @@
1
1
  # frozen_string_literal: true
2
- module DatabaseDocumenter::ColumnDescription
3
2
 
3
+ module DatabaseDocumenter::ColumnDescription
4
4
  def self.generate(column_name, column_type, klass)
5
5
  klass_name = klass.name.demodulize.titleize
6
6
 
7
- # handle enums
8
- if klass.defined_enums.keys.include?(column_name)
9
- return generate_enum_column_description(column_name, column_type, klass_name, klass)
10
- end
7
+ # Handle enums
8
+ return generate_enum_column_description(column_name, column_type, klass_name, klass) if klass.defined_enums.key?(column_name)
11
9
 
12
- # handle assm
13
- if klass.respond_to?(:aasm) && klass.aasm.attribute_name.to_s == column_name
14
- return generate_assm_column_description(column_name, column_type, klass_name, klass)
15
- elsif klass.subclasses.select { |x| x.respond_to?(:aasm) }[0] != nil
10
+ # Handle assm
11
+ return generate_assm_column_description(column_name, column_type, klass_name, klass) if klass.respond_to?(:aasm) && klass.aasm.attribute_name.to_s == column_name
12
+
13
+ unless klass.subclasses.select { |x| x.respond_to?(:aasm) }[0].nil?
16
14
  subklass = klass.subclasses.select { |x| x.respond_to?(:aasm) }[0]
17
- if subklass.aasm.attribute_name.to_s == column_name
18
- return generate_assm_column_description(column_name, column_type, klass_name, subklass)
19
- end
15
+ return generate_assm_column_description(column_name, column_type, klass_name, subklass) if subklass.aasm.attribute_name.to_s == column_name
20
16
  end
21
17
 
22
18
  # Default
23
- if self.respond_to?("generate_#{column_type}_column_description")
19
+ generate_default_column_descrription(column_name, column_type, klass_name, klass)
20
+ end
21
+
22
+ def self.generate_default_column_descrription(column_name, column_type, klass_name, klass)
23
+ if respond_to?("generate_#{column_type}_column_description")
24
24
  send("generate_#{column_type}_column_description", column_name, column_type, klass_name)
25
25
  else
26
- self.generate_with_default_rules(column_name, column_type, klass_name, klass)
26
+ generate_with_default_rules(column_name, column_type, klass_name, klass)
27
27
  end
28
28
  end
29
29
 
30
- def self.generate_datetime_column_description(column_name, column_type, klass_name)
30
+ def self.handle_enums(column_name, column_type, klass_name, klass)
31
+ generate_enum_column_description(column_name, column_type, klass_name, klass)
32
+ end
33
+
34
+ def self.generate_datetime_column_description(column_name, _column_type, _klass_name)
31
35
  case column_name
32
- when 'remember_created_at'
33
- "Date when remember me created"
34
36
  when 'reset_password_sent_at'
35
37
  "Date when reset password sent"
36
38
  when 'current_sign_in_at'
@@ -46,7 +48,7 @@ module DatabaseDocumenter::ColumnDescription
46
48
  end
47
49
  end
48
50
 
49
- def self.generate_boolean_column_description(column_name, column_type, klass_name)
51
+ def self.generate_boolean_column_description(column_name, _column_type, klass_name)
50
52
  case column_name
51
53
  when /.*active/, /has_.*/, "canceled"
52
54
  "Is #{klass_name.titlecase.downcase} #{column_name.titlecase.downcase}"
@@ -57,10 +59,10 @@ module DatabaseDocumenter::ColumnDescription
57
59
  end
58
60
  end
59
61
 
60
- def self.generate_with_default_rules(column_name, column_type, klass_name, klass)
62
+ def self.generate_with_default_rules(column_name, _column_type, klass_name, klass)
61
63
  case column_name
62
64
  when 'type'
63
- values_hash = Hash[klass.subclasses.collect { |k| [k.name.underscore.humanize, k.name] } ]
65
+ values_hash = Hash[klass.subclasses.collect { |k| [k.name.underscore.humanize, k.name] }]
64
66
  represent_multi_value_column(column_name, klass_name, values_hash)
65
67
  when /.*_code/
66
68
  refered_table_name = column_name.scan(/(.*)_code/)[0][0]
@@ -79,27 +81,25 @@ module DatabaseDocumenter::ColumnDescription
79
81
  end
80
82
  end
81
83
 
82
- def self.generate_enum_column_description(column_name, column_type, klass_name, klass)
84
+ def self.generate_enum_column_description(column_name, _column_type, klass_name, klass)
83
85
  values_hash = klass.defined_enums[column_name]
84
86
  represent_multi_value_column(column_name, klass_name, values_hash)
85
87
  end
86
88
 
87
- def self.generate_assm_column_description(column_name, column_type, klass_name, klass)
88
- values_hash = Hash[klass.aasm.states.collect { |k| [k.name.to_s.humanize, k.name.to_s] } ]
89
+ def self.generate_assm_column_description(column_name, _column_type, klass_name, klass)
90
+ values_hash = Hash[klass.aasm.states.collect { |k| [k.name.to_s.humanize, k.name.to_s] }]
89
91
  represent_multi_value_column(column_name, klass_name, values_hash)
90
92
  end
91
93
 
92
94
  def self.represent_multi_value_column(column_name, klass_name, values_hash)
93
- broken_cell_para = Caracal::Core::Models::TableCellModel.new do |c|
94
- c.p "#{column_name.titlecase.downcase} of #{klass_name.titleize}, possible values:"
95
- values_hash.each do |k,v|
96
- if k == values_hash.keys.last
97
- c.p "[#{v}] => #{k}."
98
- else
99
- c.p "[#{v}] => #{k},"
100
- end
101
- end
95
+ description = ["#{column_name.titlecase.downcase} of #{klass_name.titleize}, possible values:"]
96
+ values_hash.each do |k, v|
97
+ description << if k == values_hash.keys.last
98
+ "[#{v}] => #{k}."
99
+ else
100
+ "[#{v}] => #{k},"
101
+ end
102
102
  end
103
- broken_cell_para
103
+ description
104
104
  end
105
105
  end
@@ -4,7 +4,7 @@ module DatabaseDocumenter
4
4
 
5
5
  def initialize
6
6
  @skipped_modules = []
7
- @hidden_values_columns = ['encrypted_password', 'current_sign_in_ip', 'remote_address', 'last_sign_in_ip']
7
+ @hidden_values_columns = %w[encrypted_password current_sign_in_ip remote_address last_sign_in_ip]
8
8
  @database_configuration = Rails.application.config.database_configuration[Rails.env]
9
9
  @footer = ''
10
10
  end
@@ -1,14 +1,14 @@
1
1
  module DatabaseDocumenter
2
2
  module DatabaseComment
3
- def self.get_comment_class(adapter = get_current_adapter)
4
- if adapter == "postgresql"
3
+ def self.get_comment_class(adapter=current_adapter)
4
+ if adapter == "postgresql"
5
5
  DatabaseDocumenter::DatabaseComment::PostgresDatabaseComment
6
6
  else
7
7
  DatabaseDocumenter::DatabaseComment::MysqlDatabaseComment
8
8
  end
9
9
  end
10
10
 
11
- def self.get_current_adapter
11
+ def self.current_adapter
12
12
  DatabaseDocumenter.configuration.database_configuration['adapter']
13
13
  end
14
14
  end
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # A base class for reading column database comments
3
- class DatabaseDocumenter::DatabaseComment::BaseDatabaseComment
4
4
 
5
- def self.read_columns_comment(table_name)
6
- raise NotImplementedError
7
- end
5
+ class DatabaseDocumenter::DatabaseComment::BaseDatabaseComment
6
+ def self.read_columns_comment(_table_name)
7
+ raise NotImplementedError
8
+ end
8
9
 
9
- def self.read_table_comment(table_name)
10
- raise NotImplementedError
11
- end
10
+ def self.read_table_comment(_table_name)
11
+ raise NotImplementedError
12
+ end
12
13
 
13
- def self.database_name
14
- Rails.application.config.database_configuration[Rails.env]['database'].freeze
15
- end
14
+ def self.database_name
15
+ Rails.application.config.database_configuration[Rails.env]['database'].freeze
16
16
  end
17
+ end
@@ -1,8 +1,6 @@
1
1
  module DatabaseDocumenter
2
2
  class DatabaseComment::MysqlDatabaseComment < DatabaseComment::BaseDatabaseComment
3
-
4
3
  def self.read_columns_comment(table_name)
5
-
6
4
  select_comment = <<-SQL
7
5
  SELECT `column_name`, `column_comment`
8
6
  FROM `information_schema`.`COLUMNS`
@@ -1,30 +1,28 @@
1
1
  module DatabaseDocumenter
2
2
  class DatabaseComment::PostgresDatabaseComment < DatabaseComment::BaseDatabaseComment
3
-
4
3
  def self.read_columns_comment(table_name)
5
-
6
4
  select_comment = <<-SQL
7
5
  SELECT
8
- cols.column_name,
9
- (
10
- SELECT
11
- pg_catalog.col_description(c.oid, cols.ordinal_position::int)
12
- FROM
13
- pg_catalog.pg_class c
14
- WHERE
15
- c.oid = (SELECT ('"' || cols.table_name || '"')::regclass::oid)
16
- AND c.relname = cols.table_name
17
- ) AS column_comment
18
- FROM
19
- information_schema.columns cols
20
- WHERE
21
- cols.table_catalog = '#{database_name}'
22
- AND cols.table_name = '#{table_name}'
23
- AND cols.table_schema = 'public';
6
+ cols.column_name,
7
+ (
8
+ SELECT
9
+ pg_catalog.col_description(c.oid, cols.ordinal_position::int)
10
+ FROM
11
+ pg_catalog.pg_class c
12
+ WHERE
13
+ c.oid = (SELECT ('"' || cols.table_name || '"')::regclass::oid)
14
+ AND c.relname = cols.table_name
15
+ ) AS column_comment
16
+ FROM
17
+ information_schema.columns cols
18
+ WHERE
19
+ cols.table_catalog = '#{database_name}'
20
+ AND cols.table_name = '#{table_name}'
21
+ AND cols.table_schema = 'public';
24
22
  SQL
25
23
 
26
- columns_comment_hash ={}
27
- ActiveRecord::Base.connection.execute(select_comment).map { |c| columns_comment_hash[c['column_name']] = c['column_comment']}
24
+ columns_comment_hash = {}
25
+ ActiveRecord::Base.connection.execute(select_comment).map { |c| columns_comment_hash[c['column_name']] = c['column_comment'] }
28
26
  columns_comment_hash
29
27
  end
30
28
 
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DatabaseDocumenter::Exporters
4
+ class ExportToWord
5
+ attr_accessor :table_data, :printed_tables, :generated_cols_count, :commented_cols_count
6
+
7
+ def initialize
8
+ self.table_data = DatabaseDocumenter::TableData.new
9
+ self.printed_tables = []
10
+ self.generated_cols_count = 0
11
+ self.commented_cols_count = 0
12
+ end
13
+
14
+ def call
15
+ load_all_models
16
+ generate_word_document
17
+ end
18
+
19
+ def load_all_models
20
+ Rails.application.eager_load!
21
+ end
22
+
23
+ def generate_word_document
24
+ Caracal::Document.save 'database.docx' do |docx|
25
+ add_word_header(docx)
26
+ add_word_footer(docx)
27
+
28
+ ActiveRecord::Base.descendants.each do |klass|
29
+ # Skip STI classes
30
+ # Skip duplicate tables in case of has_and_belongs_to_many
31
+ # Skip certain modules
32
+ next if skip_class?(klass)
33
+
34
+ printed_tables << klass.table_name
35
+
36
+ generate_table_metadata(docx, klass)
37
+ generate_table_columns(docx, klass)
38
+
39
+ docx.page
40
+ end
41
+ end
42
+ Rails.logger.info "Number of columns with generated description #{generated_cols_count}"
43
+ Rails.logger.info "Number of columns with description from comments #{commented_cols_count}"
44
+ end
45
+
46
+ def add_word_footer(docx)
47
+ docx.page_numbers true do
48
+ align 'center'
49
+ label DatabaseDocumenter.configuration.footer.to_s
50
+ end
51
+ end
52
+
53
+ def add_word_header(docx)
54
+ docx.h1 "Database Design"
55
+ docx.p "The database design specifies how the data of the software is going to be stored."
56
+ end
57
+
58
+ def skip_class?(klass)
59
+ (klass.class_name != klass.base_class.class_name) || klass.abstract_class? || (klass == ActiveAdmin::Comment) ||
60
+ (printed_tables.include? klass.table_name) || (DatabaseDocumenter.configuration.skipped_modules.include? klass.parent.name)
61
+ end
62
+
63
+ def generate_table_metadata(docx, klass)
64
+ metadata = table_data.get_meta_data(klass)
65
+ docx.p ''
66
+ docx.h2 "#{klass.table_name} schema"
67
+ docx.hr
68
+
69
+ word_table = [
70
+ ["Table Name", metadata[:name]],
71
+ ["Description", metadata[:description]],
72
+ ["Primary Key", metadata[:primary_key]],
73
+ ["SQL Code", metadata[:sql_code]]
74
+ ]
75
+
76
+ docx.table word_table, border_size: 4 do
77
+ cell_style rows[0][0], background: 'b4b4b4', bold: true, width: 2000
78
+ cell_style rows[1][0], background: 'e0e0e0', bold: true, width: 2000
79
+ cell_style rows[2][0], background: 'e0e0e0', bold: true, width: 2000
80
+ cell_style rows[3][0], background: 'e0e0e0', bold: true, width: 2000
81
+ end
82
+ end
83
+
84
+ def generate_table_columns(docx, klass)
85
+ columns_header = ["Attribute", "Description", "Type", "Example of values"]
86
+ columns = []
87
+
88
+ columns_data = table_data.get_columns_data(klass)
89
+
90
+ columns_data.each do |col|
91
+ data = [col[:name]]
92
+ if col[:description_generated]
93
+ self.generated_cols_count += 1
94
+ else
95
+ self.commented_cols_count += 1
96
+ end
97
+
98
+ broken_cell_para = Caracal::Core::Models::TableCellModel.new do |c|
99
+ col[:description].flatten.each do |s|
100
+ c.p s
101
+ end
102
+ end
103
+
104
+ data << broken_cell_para
105
+ data << col[:type]
106
+ data << col[:value]
107
+ columns << data
108
+ end
109
+ docx.page
110
+ docx.table [columns_header] + columns, border_size: 4 do
111
+ cell_style rows[0], background: 'e0e0e0', bold: true
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ class DatabaseDocumenter::TableData
4
+ attr_accessor :tables_sql, :database_comment_class
5
+
6
+ def initialize
7
+ self.database_comment_class = DatabaseDocumenter::DatabaseComment.get_comment_class
8
+ load_tables_sql_data
9
+ end
10
+
11
+ def load_tables_sql_data
12
+ self.tables_sql = DatabaseDocumenter::TablesSql.generate
13
+ end
14
+
15
+ def get_meta_data(klass)
16
+ table_comment = database_comment_class.read_table_comment(klass.table_name)
17
+
18
+ data = {}
19
+ data[:name] = klass.table_name
20
+ data[:description] = table_comment.presence || "A collection of data related to #{klass.table_name.titleize}"
21
+ data[:primary_key] = klass.primary_key
22
+ data[:sql_code] = tables_sql[klass.table_name]
23
+ data
24
+ end
25
+
26
+ def get_columns_data(klass)
27
+ sample_record = klass.first
28
+ columns_comments = database_comment_class.read_columns_comment(klass.table_name)
29
+ columns = []
30
+ klass.columns.each do |col|
31
+ column_data = get_column_data(klass, col, sample_record, columns_comments[col.name])
32
+
33
+ columns << column_data
34
+ end
35
+ columns
36
+ end
37
+
38
+ def get_column_data(klass, col, sample_record, column_comment)
39
+ column_data = { name: col.name }
40
+ column_data[:description] = []
41
+
42
+ if column_comment.present?
43
+ column_data[:description_generated] = false
44
+ column_comment.split("<br/>").each do |s|
45
+ column_data[:description] << s
46
+ end
47
+ else
48
+ column_data[:description_generated] = true
49
+ column_data[:description] << DatabaseDocumenter::ColumnDescription.generate(col.name, col.type, klass)
50
+ end
51
+
52
+ column_data[:type] = col.type
53
+
54
+ hidden_values_columns = DatabaseDocumenter.configuration.hidden_values_columns
55
+
56
+ column_data[:value] = if hidden_values_columns.include?(col.name)
57
+ 'Data is hidden/removed'
58
+ elsif sample_record.nil?
59
+ ''
60
+ elsif Rails.version.split(".")[0].to_i == 4
61
+ sample_record[col.name]
62
+ else
63
+ sample_record.send("#{col.name}_before_type_cast")
64
+ end
65
+ column_data
66
+ end
67
+ end
@@ -1,13 +1,12 @@
1
1
  # frozen_string_literal: true
2
- module DatabaseDocumenter::TablesSql
3
2
 
3
+ module DatabaseDocumenter::TablesSql
4
4
  def self.generate
5
-
6
5
  configuration = DatabaseDocumenter.configuration.database_configuration
7
6
 
8
7
  tables_sql = generate_sql_file(configuration)
9
8
 
10
- self.send("process_#{configuration['adapter']}_sql", tables_sql)
9
+ send("process_#{configuration['adapter']}_sql", tables_sql)
11
10
  end
12
11
 
13
12
  def self.generate_sql_file(configuration)
@@ -19,7 +18,7 @@ module DatabaseDocumenter::TablesSql
19
18
 
20
19
  def self.process_postgresql_sql(tables_sql)
21
20
  tables_sql_hash = {}
22
- tables_sql = tables_sql.split('--').select { |line| line.match(/CREATE TABLE/)}
21
+ tables_sql = tables_sql.split('--').select { |line| line.match(/CREATE TABLE/) }
23
22
 
24
23
  tables_sql.each do |sql_statement|
25
24
  key = sql_statement.scan(/public.(.*) \(/)[0][0]
@@ -29,7 +28,6 @@ module DatabaseDocumenter::TablesSql
29
28
  end
30
29
  end
31
30
  tables_sql_hash[key] = broken_cell_para
32
-
33
31
  end
34
32
 
35
33
  tables_sql_hash
@@ -37,7 +35,7 @@ module DatabaseDocumenter::TablesSql
37
35
 
38
36
  def self.process_mysql2_sql(tables_sql)
39
37
  tables_sql_hash = {}
40
- tables_sql = tables_sql.split(';').select { |line| line.match(/CREATE/)}
38
+ tables_sql = tables_sql.split(';').select { |line| line.match(/CREATE/) }
41
39
 
42
40
  tables_sql.each do |sql_statement|
43
41
  key = sql_statement.scan(/`(.*)`/)[0][0]
@@ -47,7 +45,6 @@ module DatabaseDocumenter::TablesSql
47
45
  end
48
46
  end
49
47
  tables_sql_hash[key] = broken_cell_para
50
-
51
48
  end
52
49
 
53
50
  tables_sql_hash
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module DatabaseDocumenter
2
- VERSION = "0.1.6"
4
+ VERSION = '0.1.7'
3
5
  end
@@ -2,95 +2,5 @@ require "bundler/setup"
2
2
  require "database_documenter"
3
3
 
4
4
  task generate_db_document: :environment do
5
- Rails.application.eager_load!
6
-
7
- tables_sql = DatabaseDocumenter::TablesSql.generate
8
-
9
- Caracal::Document.save 'database.docx' do |docx|
10
- database_comment_class = DatabaseDocumenter::DatabaseComment.get_comment_class
11
-
12
- docx.page_numbers true do
13
- align 'center'
14
- label "#{DatabaseDocumenter.configuration.footer}"
15
- end
16
-
17
- docx.h1 "Database Design"
18
- docx.p "The database design specifies how the data of the software is going to be stored."
19
-
20
- printed_tables = []
21
- generated_col_description = 0
22
- col_description_from_comments = 0
23
- ActiveRecord::Base.descendants.each do |klass|
24
- next if (klass.class_name != klass.base_class.class_name) || klass.abstract_class? || klass == ActiveAdmin::Comment # Ignore STI classes
25
-
26
- next if printed_tables.include? klass.table_name # Skip duplicate tables in case of has_and_belongs_to_many
27
-
28
- next if DatabaseDocumenter.configuration.skipped_modules.include? klass.parent.name
29
-
30
- printed_tables << klass.table_name
31
-
32
- table_comment = database_comment_class.read_table_comment(klass.table_name)
33
-
34
- docx.p ''
35
- docx.h2 "#{klass.table_name} schema"
36
- docx.hr
37
-
38
- table_name = ["Table Name", klass.table_name]
39
- description = ["Description", (table_comment.nil? || table_comment.empty?) ? "A collection of data related to #{klass.table_name.titleize}" : table_comment ]
40
- primary_key = ["Primary Key", klass.primary_key]
41
- sql_code = ["SQL Code", tables_sql[klass.table_name]]
42
-
43
- docx.table [table_name, description, primary_key, sql_code], border_size: 4 do
44
- cell_style rows[0][0], background: 'b4b4b4', bold: true, width: 2000
45
- cell_style rows[1][0], background: 'e0e0e0', bold: true, width: 2000
46
- cell_style rows[2][0], background: 'e0e0e0', bold: true, width: 2000
47
- cell_style rows[3][0], background: 'e0e0e0', bold: true, width: 2000
48
- end
49
-
50
- columns_header = ["Attribute", "Description", "Type", "Example of values"]
51
- columns = []
52
- sample_record = klass.first
53
- columns_comments = database_comment_class.read_columns_comment(klass.table_name)
54
- klass.columns.each do |col|
55
- column_data = [col.name]
56
- if columns_comments[col.name].present?
57
- col_description_from_comments +=1
58
- broken_cell_para = Caracal::Core::Models::TableCellModel.new do |c|
59
- columns_comments[col.name].split("<br/>").each do |s|
60
- c.p s
61
- end
62
- end
63
- column_data << broken_cell_para
64
- else
65
- generated_col_description +=1
66
- column_data << DatabaseDocumenter::ColumnDescription.generate(col.name, col.type, klass)
67
- end
68
-
69
- column_data << col.type
70
-
71
- hidden_values_columns = DatabaseDocumenter.configuration.hidden_values_columns
72
-
73
- if hidden_values_columns.include?(col.name)
74
- column_data << 'Data is hidden/removed'
75
- elsif sample_record.nil?
76
- column_data << ''
77
- else
78
- if Rails.version.split(".")[0].to_i == 4
79
- column_data << sample_record[col.name]
80
- else
81
- column_data << sample_record.send("#{col.name}_before_type_cast")
82
- end
83
- end
84
-
85
- columns << column_data
86
- end
87
- docx.page
88
- docx.table [columns_header] + columns, border_size: 4 do
89
- cell_style rows[0], background: 'e0e0e0', bold: true
90
- end
91
- docx.page
92
- end
93
- puts "Number of columns with generated description #{generated_col_description}"
94
- puts "Number of columns with description from comments #{col_description_from_comments}"
95
- end
5
+ DatabaseDocumenter::Exporters::ExportToWord.new.call
96
6
  end
@@ -1,9 +1,9 @@
1
1
  task :generate_dd_initializer do
2
- template_path = File.join( File.dirname(__FILE__), 'templates/database_documenter.rb').freeze
2
+ template_path = File.join(File.dirname(__FILE__), 'templates/database_documenter.rb').freeze
3
3
  initializer_path = 'config/initializers/database_documenter.rb'.freeze
4
4
  # Check if the initializer already exists
5
5
  abort("Initializer already exists") if File.file?(initializer_path)
6
6
 
7
7
  # Copy the template to the initializers dir
8
8
  FileUtils.cp(template_path, initializer_path)
9
- end
9
+ end
@@ -1,5 +1,5 @@
1
1
  DatabaseDocumenter.configure do |config|
2
- config.skipped_modules = %w(NAMESPACE)
3
- config.hidden_values_columns = %w(col1 col2)
4
- config.footer = "Generated by Company" # Footer beside the pagination
2
+ # config.skipped_modules = %w(NAMESPACE)
3
+ # config.hidden_values_columns = %w(col1 col2)
4
+ # config.footer = "Generated by Company" # Footer beside the pagination
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: database_documenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ahmed Yehia
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-07-11 00:00:00.000000000 Z
11
+ date: 2019-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,6 +24,34 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: overcommit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.49.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.49.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.12.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.12.2
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: rake
29
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +80,20 @@ dependencies:
52
80
  - - "~>"
53
81
  - !ruby/object:Gem::Version
54
82
  version: '3.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.58.2
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.58.2
55
97
  - !ruby/object:Gem::Dependency
56
98
  name: caracal
57
99
  requirement: !ruby/object:Gem::Requirement
@@ -74,7 +116,9 @@ extensions: []
74
116
  extra_rdoc_files: []
75
117
  files:
76
118
  - ".gitignore"
119
+ - ".overcommit.yml"
77
120
  - ".rspec"
121
+ - ".rubocop.yml"
78
122
  - ".travis.yml"
79
123
  - Gemfile
80
124
  - Gemfile.lock
@@ -90,7 +134,9 @@ files:
90
134
  - lib/database_documenter/database_comment/base_database_comment.rb
91
135
  - lib/database_documenter/database_comment/mysql_database_comment.rb
92
136
  - lib/database_documenter/database_comment/postgres_database_comment.rb
137
+ - lib/database_documenter/exporters/export_to_word.rb
93
138
  - lib/database_documenter/railtie.rb
139
+ - lib/database_documenter/table_data.rb
94
140
  - lib/database_documenter/tables_sql.rb
95
141
  - lib/database_documenter/version.rb
96
142
  - lib/tasks/generate_db_document.rake