commento 0.1.0 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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: