commento 0.1.0 → 0.1.2

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: f2558be497fdf71eca0c553371dc0fb09fdb348a04bc930289ad3696a571a4fa
4
- data.tar.gz: c4e41098d7c6ffcff077d5c18545e7c0d03fcb33b3b1273bb4cfac0406cabf38
3
+ metadata.gz: a3088eb93d7f0b937169a65a8c95efc36eecb202be76a6cd7c98ec5adc5b945e
4
+ data.tar.gz: d1ce5f3eaad3ccc2fead78cecde406a20067f4304364948f09027d66ff26b789
5
5
  SHA512:
6
- metadata.gz: f93c37134940512adbe7fd03600d7aeb0f4af032b9196c55bc5d011a310138c5f2fbefc4b8962abd9aa7cbc88ab41156cff8121eb80142df91e057146c60f779
7
- data.tar.gz: c66a4d0f5e6a626982a3842d743b712fe7023fd3303369426a9f911d4b4c3fbb7ebd00712b02de70f192857b4aa5adb0573bf7a782f4aa054ce3946c90e33da6
6
+ metadata.gz: 47cd00bf0babcd8ab1c10db8d3edcd4be3330e99c5233b4241fe9552f5a65df96d6494349cc60530781f6d41cead7e05b74c76e7fccff191c9e02de4d78a2031
7
+ data.tar.gz: 3d7dbf40b8b2783a32dd86208b32e452d142b3d13b3e4ce5e9325472d5e04343d4f594b707aa8454eca2adf014b7e59fbb3f8dc9a72a42d557377f3c2d0d4783
data/README.md CHANGED
@@ -32,16 +32,42 @@ end
32
32
 
33
33
  ### Models
34
34
 
35
- Update you application model
35
+ Update your application model
36
+
36
37
  ```ruby
37
38
  class ApplicationRecord < ActiveRecord::Base
38
39
  include Commento::Helpers
39
40
  end
40
41
  ```
41
42
 
43
+ ## Generating reports
44
+
45
+ You can generate different types of reports
46
+
47
+ ```ruby
48
+ Commento::Reports::Html.new.create_report
49
+ ```
50
+
42
51
  ## Usage
43
52
 
44
- Commento provides helpers for models for setting and getting table's column comments.
53
+ Commento provides helpers for models for setting and getting comments.
54
+
55
+ ### Set table's comment
56
+
57
+ ```ruby
58
+ User.set_table_comment('Users table')
59
+ ```
60
+
61
+ or reset comment by skiping value
62
+ ```ruby
63
+ User.set_table_comment
64
+ ```
65
+
66
+ ### Read table's column comment
67
+
68
+ ```ruby
69
+ User.get_table_comment
70
+ ```
45
71
 
46
72
  ### Set table's column comment
47
73
 
@@ -15,6 +15,19 @@ module Commento
15
15
  @name = options.fetch(:name, :active_record)
16
16
  end
17
17
 
18
+ # Public: Sets comment for table.
19
+ def set_table_comment(table_name, value)
20
+ sql = "COMMENT ON TABLE #{table_name} IS "
21
+ sql += value ? "'#{value}'" : 'NULL'
22
+ execute(sql)
23
+ end
24
+
25
+ # Public: Returns comment for table.
26
+ def table_comment(table_name)
27
+ table_data = execute(tables_comments_sql).to_a.find { |data| data['table_name'] == table_name }
28
+ table_data.present? ? table_data['obj_description'] : nil
29
+ end
30
+
18
31
  # Public: Sets comment for table's column.
19
32
  def set_column_comment(table_name, column_name, value)
20
33
  sql = "COMMENT ON COLUMN #{table_name}.#{column_name} IS "
@@ -23,27 +36,72 @@ module Commento
23
36
  end
24
37
 
25
38
  # Public: Returns comment for table's column.
26
- def get_column_comment(table_name, column_name)
27
- sql = <<-SQL.squish
39
+ def column_comment(table_name, column_name)
40
+ sql = columns_comments_sql(table_name)
41
+ column_data = execute(sql).to_a.find { |data| data['column_name'].to_sym == column_name }
42
+ column_data.present? ? column_data['col_description'] : nil
43
+ end
44
+
45
+ # Public: Returns comments for tables and columns.
46
+ def comments_for_database
47
+ execute(tables_comments_sql).to_a.filter_map do |table_data|
48
+ next if configuration.skip_table_names.include?(table_data['table_name'])
49
+
50
+ parse_data(table_data)
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def parse_data(table_data)
57
+ {
58
+ table_name: table_data['table_name'],
59
+ table_comment: table_data['obj_description'],
60
+ columns: execute(columns_comments_sql(table_data['table_name'])).to_a.filter_map do |column_data|
61
+ next if configuration.skip_column_names.include?(column_data['column_name'])
62
+
63
+ {
64
+ column_name: column_data['column_name'],
65
+ column_comment: column_data['col_description']
66
+ }
67
+ end
68
+ }
69
+ end
70
+
71
+ def tables_comments_sql
72
+ <<-SQL.squish
73
+ SELECT
74
+ tables.table_name,
75
+ pg_catalog.obj_description(pgc.oid, 'pg_class')
76
+ FROM information_schema.tables tables
77
+ INNER JOIN pg_catalog.pg_class pgc ON tables.table_name = pgc.relname
78
+ WHERE
79
+ tables.table_type='BASE TABLE' AND
80
+ tables.table_schema='public'
81
+ SQL
82
+ end
83
+
84
+ def columns_comments_sql(table_name)
85
+ <<-SQL.squish
28
86
  SELECT
29
87
  cols.column_name,
30
- pg_catalog.col_description(c.oid, cols.ordinal_position::int)
31
- FROM pg_catalog.pg_class c, information_schema.columns cols
88
+ pg_catalog.col_description(pgc.oid, cols.ordinal_position::int)
89
+ FROM pg_catalog.pg_class pgc, information_schema.columns cols
32
90
  WHERE
33
91
  cols.table_catalog = '#{Rails.configuration.database_configuration[Rails.env]["database"]}' AND
34
92
  cols.table_schema = 'public' AND
35
93
  cols.table_name = '#{table_name}' AND
36
- cols.table_name = c.relname
94
+ cols.table_name = pgc.relname
37
95
  SQL
38
- column_data = execute(sql).to_a.find { |column| column['column_name'].to_sym == column_name }
39
- column_data.presence ? column_data['col_description'] : nil
40
96
  end
41
97
 
42
- private
43
-
44
98
  def execute(sql)
45
99
  ::ActiveRecord::Base.connection.execute(sql)
46
100
  end
101
+
102
+ def configuration
103
+ Commento.configuration
104
+ end
47
105
  end
48
106
  end
49
107
  end
@@ -2,10 +2,14 @@
2
2
 
3
3
  module Commento
4
4
  class Configuration
5
- attr_accessor :adapter
5
+ attr_accessor :adapter, :include_folders, :exclude_folders, :skip_table_names, :skip_column_names
6
6
 
7
7
  def initialize
8
8
  @adapter = nil
9
+ @include_folders = %w[app lib]
10
+ @exclude_folders = ['app/assets']
11
+ @skip_table_names = %w[ar_internal_metadata schema_migrations]
12
+ @skip_column_names = %w[id uuid created_at updated_at]
9
13
  end
10
14
  end
11
15
  end
data/lib/commento/dsl.rb CHANGED
@@ -11,14 +11,29 @@ module Commento
11
11
  @adapter = adapter
12
12
  end
13
13
 
14
+ # Public: Sets comment for table.
15
+ def set_table_comment(table_name, value)
16
+ adapter.set_table_comment(table_name, value)
17
+ end
18
+
19
+ # Public: Returns comment for table.
20
+ def table_comment(table_name)
21
+ adapter.table_comment(table_name)
22
+ end
23
+
14
24
  # Public: Sets comment for table's column.
15
25
  def set_column_comment(table_name, column_name, value)
16
26
  adapter.set_column_comment(table_name, column_name, value)
17
27
  end
18
28
 
19
29
  # Public: Returns comment for table's column.
20
- def get_column_comment(table_name, column_name)
21
- adapter.get_column_comment(table_name, column_name)
30
+ def column_comment(table_name, column_name)
31
+ adapter.column_comment(table_name, column_name)
32
+ end
33
+
34
+ # Public: Returns comments for tables and columns.
35
+ def comments_for_database
36
+ adapter.comments_for_database
22
37
  end
23
38
  end
24
39
  end
@@ -9,12 +9,20 @@ module Commento
9
9
  end
10
10
 
11
11
  module ClassMethods
12
+ def set_table_comment(value=nil)
13
+ instance.set_table_comment(table_name, value)
14
+ end
15
+
16
+ def table_comment
17
+ instance.table_comment(table_name)
18
+ end
19
+
12
20
  def set_column_comment(column_name, value=nil)
13
21
  instance.set_column_comment(table_name, column_name, value)
14
22
  end
15
23
 
16
- def get_column_comment(column_name)
17
- instance.get_column_comment(table_name, column_name)
24
+ def column_comment(column_name)
25
+ instance.column_comment(table_name, column_name)
18
26
  end
19
27
 
20
28
  def instance
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Commento
4
+ class Report
5
+ COMMENTO_FOLDER_NAME = 'commento'
6
+
7
+ def initialize(data_collect_service: Commento::Services::DataCollect)
8
+ @data_collect_service = data_collect_service.new
9
+ end
10
+
11
+ def create_report
12
+ @commento_data = @data_collect_service.call
13
+ FileUtils.mkdir_p(COMMENTO_FOLDER_NAME)
14
+ File.write(
15
+ "#{COMMENTO_FOLDER_NAME}/#{file_name}",
16
+ main_template.gsub('%tables_placeholder%', tables_placeholder)
17
+ )
18
+ end
19
+
20
+ private
21
+
22
+ def tables_placeholder
23
+ database_comments.map do |table_data|
24
+ table_template
25
+ .gsub('%table_name%', table_data[:table_name])
26
+ .gsub('%table_comment%', table_data[:table_comment].presence || '')
27
+ .gsub('%columns_placeholder%', columns_placeholder(table_data[:table_name], table_data[:columns]))
28
+ end.join
29
+ end
30
+
31
+ def columns_placeholder(table_name, columns)
32
+ columns.map do |column_data|
33
+ full_column_name = "#{table_name}.#{column_data[:column_name]}"
34
+ column_template
35
+ .gsub('%column_name%', full_column_name)
36
+ .gsub('%column_comment%', column_data[:column_comment].presence || '')
37
+ .gsub('%data_placeholder%', data_placeholder(full_column_name))
38
+ end.join
39
+ end
40
+
41
+ def data_placeholder(full_column_name)
42
+ return '' if @commento_data[full_column_name].blank?
43
+
44
+ @commento_data[full_column_name].map do |filename|
45
+ data_template.gsub('%commento_data%', filename)
46
+ end.join
47
+ end
48
+
49
+ def database_comments
50
+ adapter.comments_for_database
51
+ end
52
+
53
+ def main_template
54
+ raise NotImplementedError
55
+ end
56
+
57
+ def table_template
58
+ raise NotImplementedError
59
+ end
60
+
61
+ def column_template
62
+ raise NotImplementedError
63
+ end
64
+
65
+ def data_template
66
+ raise NotImplementedError
67
+ end
68
+
69
+ def file_name
70
+ raise NotImplementedError
71
+ end
72
+
73
+ def adapter
74
+ Commento.adapter
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Commento
4
+ module Reports
5
+ class Html < Commento::Report
6
+ private
7
+
8
+ def main_template
9
+ [
10
+ '<!DOCTYPE html>',
11
+ '<html>',
12
+ ' <head>',
13
+ " #{styles}",
14
+ ' <meta charset="utf-8" />',
15
+ ' </head>',
16
+ ' <body>',
17
+ '%tables_placeholder%',
18
+ ' </body>',
19
+ '</html>'
20
+ ].join("\n")
21
+ end
22
+
23
+ def table_template
24
+ [
25
+ " <div class='table'>",
26
+ " <div class='table-header'>",
27
+ ' <h3>%table_name%</h3>',
28
+ ' <p>%table_comment%</p>',
29
+ ' </div>',
30
+ " <div class='table-body'>",
31
+ '%columns_placeholder%',
32
+ ' </div>',
33
+ " </div>\n"
34
+ ].join("\n")
35
+ end
36
+
37
+ def column_template
38
+ [
39
+ " <div class='column-body'>",
40
+ ' <p>%column_name%: %column_comment%</p>',
41
+ " <div class='column-data'>",
42
+ '%data_placeholder%',
43
+ ' </div>',
44
+ " </div>\n"
45
+ ].join("\n")
46
+ end
47
+
48
+ def data_template
49
+ ' <span>%commento_data%</span>'
50
+ end
51
+
52
+ def file_name
53
+ 'index.html'
54
+ end
55
+
56
+ def styles
57
+ [
58
+ '<style>',
59
+ 'h3 { margin: 0 0 .25rem }',
60
+ 'p { margin: 0 0 .5rem }',
61
+ '.table { padding: 0 .5rem; margin-bottom: 1rem }',
62
+ '.table-header { border-bottom: 1px solid #ddd; margin-bottom: .5rem }',
63
+ '.table-header h3 { padding: .25rem; background: #bbb }',
64
+ '.table-header p { padding: .25rem; margin: 0 }',
65
+ '.table-body { padding: 0 .25rem }',
66
+ '.column-body { margin-bottom: .5rem; }',
67
+ '.column-body p { margin: 0 }',
68
+ '.column-data { display: flex; flex-direction: column; margin: .5rem 0 }',
69
+ '.column-data span { font-style: italic; padding-left: 1rem }',
70
+ '</style>'
71
+ ].join
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Commento
4
+ module Services
5
+ class DataCollect
6
+ COMMENTO_MATCH_REGEXP = /^[ \t]*# commento:.+$/.freeze
7
+
8
+ # @data contains data with next format
9
+ # {
10
+ # 'fantasy_sports.points' => [
11
+ # 'app/services/some_service.rb:11'
12
+ # ]
13
+ # }
14
+ # key - table_name.column_name
15
+ # values - lines of files where these columns are changed in the code
16
+ def initialize
17
+ @data = {}
18
+ end
19
+
20
+ def call
21
+ configuration.include_folders.each { |include_folder| iterate_folder(include_folder) }
22
+ @data
23
+ end
24
+
25
+ private
26
+
27
+ def iterate_folder(include_folder)
28
+ Dir.glob("#{include_folder}/**/*.rb").each do |filename|
29
+ next if exclude_folders.include?(filename.split('/')[0..-2].join('/'))
30
+
31
+ File.open(filename) { |lines| iterate_filelines(lines, filename) }
32
+ end
33
+ end
34
+
35
+ def iterate_filelines(lines, filename)
36
+ lines.each.with_index(1) do |line, index|
37
+ next unless COMMENTO_MATCH_REGEXP.match?(line)
38
+
39
+ field = line.strip.split('# commento: ')[-1]
40
+ @data[field] ||= []
41
+ @data[field] << "#{filename}:#{index}"
42
+ end
43
+ end
44
+
45
+ def exclude_folders
46
+ @exclude_folders ||= configuration.exclude_folders
47
+ end
48
+
49
+ def configuration
50
+ Commento.configuration
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Commento
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.2'
5
5
  end
data/lib/commento.rb CHANGED
@@ -6,17 +6,20 @@ require 'commento/version'
6
6
  require 'commento/configuration'
7
7
  require 'commento/dsl'
8
8
  require 'commento/helpers'
9
+ require 'commento/report'
10
+ require 'commento/reports/html'
11
+ require 'commento/services/data_collect'
9
12
 
10
13
  module Commento
11
14
  extend self
12
15
  extend Forwardable
13
16
 
14
- # Public: Given an adapter returns a handy DSL to all the commentp goodness.
17
+ # Public: Given an adapter returns a handy DSL to all the commento goodness.
15
18
  def new(adapter)
16
19
  DSL.new(adapter)
17
20
  end
18
21
 
19
- # Public: Configure commentp.
22
+ # Public: Configure commento.
20
23
  #
21
24
  # Commento.configure do |config|
22
25
  # config.adapter = Commento::Adapters::ActiveRecord.new
@@ -31,7 +34,7 @@ module Commento
31
34
  @configuration ||= Configuration.new
32
35
  end
33
36
 
34
- # Public: Default per thread commentp instance if configured.
37
+ # Public: Default per thread commento instance if configured.
35
38
  # Returns Commento::DSL instance.
36
39
  def instance
37
40
  Thread.current[:commento_instance] ||= new(configuration.adapter)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: commento
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bogdanov Anton
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-08-01 00:00:00.000000000 Z
11
+ date: 2023-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -80,6 +80,9 @@ files:
80
80
  - lib/commento/configuration.rb
81
81
  - lib/commento/dsl.rb
82
82
  - lib/commento/helpers.rb
83
+ - lib/commento/report.rb
84
+ - lib/commento/reports/html.rb
85
+ - lib/commento/services/data_collect.rb
83
86
  - lib/commento/version.rb
84
87
  homepage: https://github.com/kortirso/commento
85
88
  licenses: