model_probe 1.0.7 → 1.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 +5 -5
- data/Gemfile +2 -0
- data/Gemfile.lock +46 -5
- data/LICENSE.txt +2 -2
- data/README.md +72 -138
- data/Rakefile +2 -0
- data/lib/model_probe/color.rb +18 -11
- data/lib/model_probe/railtie.rb +2 -0
- data/lib/model_probe/templates/fixture.yml.erb +4 -0
- data/lib/model_probe/templates/model.rb.erb +36 -0
- data/lib/model_probe/version.rb +3 -1
- data/lib/model_probe.rb +180 -78
- data/lib/tasks/model_probe.rake +2 -0
- data/model_probe.gemspec +17 -0
- data/tags +106 -0
- metadata +27 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: dfbbaa56b645ab7e076623397e7af297d5113ffd6820b31e0e16468f648c9653
|
4
|
+
data.tar.gz: 42b742bd32a1f2a8fda04e7ea1b32425b14d0c58ebc63ee2543b208883f3f379
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f84ec45449d885f167fd3ca1b6e784b03ffd4e2ace226f1868dd162e817a9223a578456eb11e86be9532a57a0e36aa6d3d848a6b88a68aed0df3a74073419ebe
|
7
|
+
data.tar.gz: ffbd50414995be1cb831677959db557ffcb4bffacb46d0ed6f2a742d1e3154bcadfaac740a43d41964fcf6e8d7165b4f3b2364572cee0ead09ca48e0ee0c0ee3
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,19 +1,60 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
model_probe (1.0
|
4
|
+
model_probe (1.1.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
|
9
|
+
ast (2.4.2)
|
10
|
+
json (2.6.3)
|
11
|
+
language_server-protocol (3.17.0.3)
|
12
|
+
lint_roller (1.0.0)
|
13
|
+
magic_frozen_string_literal (1.2.0)
|
14
|
+
parallel (1.23.0)
|
15
|
+
parser (3.2.2.1)
|
16
|
+
ast (~> 2.4.1)
|
17
|
+
rainbow (3.1.1)
|
18
|
+
regexp_parser (2.8.0)
|
19
|
+
rexml (3.2.5)
|
20
|
+
rubocop (1.50.2)
|
21
|
+
json (~> 2.3)
|
22
|
+
parallel (~> 1.10)
|
23
|
+
parser (>= 3.2.0.0)
|
24
|
+
rainbow (>= 2.2.2, < 4.0)
|
25
|
+
regexp_parser (>= 1.8, < 3.0)
|
26
|
+
rexml (>= 3.2.5, < 4.0)
|
27
|
+
rubocop-ast (>= 1.28.0, < 2.0)
|
28
|
+
ruby-progressbar (~> 1.7)
|
29
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
30
|
+
rubocop-ast (1.28.1)
|
31
|
+
parser (>= 3.2.1.0)
|
32
|
+
rubocop-performance (1.16.0)
|
33
|
+
rubocop (>= 1.7.0, < 2.0)
|
34
|
+
rubocop-ast (>= 0.4.0)
|
35
|
+
ruby-progressbar (1.13.0)
|
36
|
+
standard (1.28.2)
|
37
|
+
language_server-protocol (~> 3.17.0.2)
|
38
|
+
lint_roller (~> 1.0)
|
39
|
+
rubocop (~> 1.50.2)
|
40
|
+
standard-custom (~> 1.0.0)
|
41
|
+
standard-performance (~> 1.0.1)
|
42
|
+
standard-custom (1.0.0)
|
43
|
+
lint_roller (~> 1.0)
|
44
|
+
standard-performance (1.0.1)
|
45
|
+
lint_roller (~> 1.0)
|
46
|
+
rubocop-performance (~> 1.16.0)
|
47
|
+
standardrb (1.0.1)
|
48
|
+
standard
|
49
|
+
unicode-display_width (2.4.2)
|
10
50
|
|
11
51
|
PLATFORMS
|
12
|
-
|
52
|
+
arm64-darwin-22
|
13
53
|
|
14
54
|
DEPENDENCIES
|
55
|
+
magic_frozen_string_literal
|
15
56
|
model_probe!
|
16
|
-
|
57
|
+
standardrb
|
17
58
|
|
18
59
|
BUNDLED WITH
|
19
|
-
|
60
|
+
2.4.10
|
data/LICENSE.txt
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c)
|
1
|
+
Copyright (c) 2023 Nathan Hopkins
|
2
2
|
|
3
3
|
MIT License
|
4
4
|
|
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,140 +1,74 @@
|
|
1
1
|
# ModelProbe
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
```
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
# unlock_token string....character varying NULL
|
76
|
-
# updated_at datetime..timestamp without time zone
|
77
|
-
```
|
78
|
-
|
79
|
-
```sh
|
80
|
-
rails model_probe:print_fixture[User]
|
81
|
-
|
82
|
-
# ---
|
83
|
-
# user:
|
84
|
-
# confirmation_sent_at: value
|
85
|
-
# confirmation_token: value
|
86
|
-
# confirmed_at: value
|
87
|
-
# current_sign_in_at: value
|
88
|
-
# current_sign_in_ip: value
|
89
|
-
# email: ''
|
90
|
-
# encrypted_password: ''
|
91
|
-
# failed_attempts: '0'
|
92
|
-
# last_sign_in_at: value
|
93
|
-
# last_sign_in_ip: value
|
94
|
-
# locked_at: value
|
95
|
-
# payment_platform: value
|
96
|
-
# payment_platform_id: value
|
97
|
-
# phone_number_id: value
|
98
|
-
# reset_password_sent_at: value
|
99
|
-
# reset_password_token: value
|
100
|
-
# sign_in_count: '0'
|
101
|
-
# unconfirmed_email: value
|
102
|
-
# unlock_token: value
|
103
|
-
```
|
104
|
-
|
105
|
-
```sh
|
106
|
-
rails model_probe:print_model[User]
|
107
|
-
|
108
|
-
# class User < ApplicationRecord
|
109
|
-
# # extends ...................................................................
|
110
|
-
# # includes ..................................................................
|
111
|
-
#
|
112
|
-
# # relationships .............................................................
|
113
|
-
# belongs_to :payment_platform
|
114
|
-
# belongs_to :phone_number
|
115
|
-
#
|
116
|
-
# # validations ...............................................................
|
117
|
-
# validates :created_at, presence: true
|
118
|
-
# validates :encrypted_password, presence: true
|
119
|
-
# validates :failed_attempts, presence: true
|
120
|
-
# validates :phone_number_id, presence: true
|
121
|
-
# validates :sign_in_count, presence: true
|
122
|
-
# validates :updated_at, presence: true
|
123
|
-
#
|
124
|
-
# # callbacks .................................................................
|
125
|
-
# # scopes ....................................................................
|
126
|
-
# # additional config (i.e. accepts_nested_attribute_for etc...) ..............
|
127
|
-
#
|
128
|
-
# # class methods .............................................................
|
129
|
-
# class << self
|
130
|
-
# end
|
131
|
-
#
|
132
|
-
# # public instance methods ...................................................
|
133
|
-
#
|
134
|
-
# # protected instance methods ................................................
|
135
|
-
# protected
|
136
|
-
#
|
137
|
-
# # private instance methods ..................................................
|
138
|
-
# private
|
139
|
-
# end
|
140
|
-
```
|
3
|
+
## ActiveRecord schema visualization and model organization made easy 🙌
|
4
|
+
|
5
|
+
Colorized table info for columns, types, nullables, indexes...
|
6
|
+
and the actual DDL used by the database to create the table.
|
7
|
+
_All this and more with ModelProbe!_
|
8
|
+
|
9
|
+
1. Get a clear picture of your model's underlying schema with beautiful and informative schema introspection.
|
10
|
+
1. Generate model class definitions with a well organized, logical structure.
|
11
|
+
1. Create sensible text fixture stubs.
|
12
|
+
|
13
|
+
<!-- Tocer[start]: Auto-generated, don't remove. -->
|
14
|
+
|
15
|
+
## Table of Contents
|
16
|
+
|
17
|
+
- [Quick Start](#quick-start)
|
18
|
+
- [Supported Databases](#supported-databases)
|
19
|
+
- [Videos](#videos)
|
20
|
+
- [Screenshots](#screenshots)
|
21
|
+
|
22
|
+
<!-- Tocer[finish]: Auto-generated, don't remove. -->
|
23
|
+
|
24
|
+
## Quick Start
|
25
|
+
|
26
|
+
1. Add the GEM to your project
|
27
|
+
|
28
|
+
```sh
|
29
|
+
bundle add model_probe
|
30
|
+
```
|
31
|
+
|
32
|
+
_ModelProbe auto initializes in the Rails `development` environment._
|
33
|
+
|
34
|
+
1. Use in a Rails console
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
# examples for a User model
|
38
|
+
User.probe
|
39
|
+
User.print_model
|
40
|
+
User.print_fixture
|
41
|
+
```
|
42
|
+
1. Use with Rails (Rake) tasks
|
43
|
+
|
44
|
+
```sh
|
45
|
+
# examples for a User model
|
46
|
+
bin/rails model_probe:probe[User]
|
47
|
+
bin/rails model_probe:print_model[User]
|
48
|
+
bin/rails model_probe:print_fixture[User]
|
49
|
+
```
|
50
|
+
|
51
|
+
## Supported Databases
|
52
|
+
|
53
|
+
- MySQL
|
54
|
+
- PostgreSQL
|
55
|
+
- SQLite
|
56
|
+
- _...more? contributions welcome ;)_
|
57
|
+
|
58
|
+
## Videos
|
59
|
+
|
60
|
+
[](https://youtu.be/Q3IdyKateQE)
|
61
|
+
|
62
|
+
## Screenshots
|
63
|
+
|
64
|
+
Introspect your ActiveRecord models to build a deep understanding of the underlying database structure.
|
65
|
+
|
66
|
+

|
67
|
+
|
68
|
+
Generate a well organized template for your ActiveRecord model's class definition.
|
69
|
+
|
70
|
+

|
71
|
+
|
72
|
+
Create fixture stubs to use in the test suite.
|
73
|
+
|
74
|
+

|
data/Rakefile
CHANGED
data/lib/model_probe/color.rb
CHANGED
@@ -1,21 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ModelProbe
|
2
4
|
module Color
|
3
5
|
extend self
|
4
6
|
|
5
|
-
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
7
|
+
COLORS = {
|
8
|
+
blue: 34,
|
9
|
+
cyan: 36,
|
10
|
+
gray: "1;30",
|
11
|
+
green: 32,
|
12
|
+
green_light: 92,
|
13
|
+
magenta: 35,
|
14
|
+
magenta_light: 95,
|
15
|
+
pink: "1;91",
|
16
|
+
red: 31,
|
17
|
+
red_light: 91,
|
18
|
+
white: 37,
|
19
|
+
yellow: 33,
|
20
|
+
yellow_light: 93
|
14
21
|
}
|
15
22
|
|
16
|
-
|
23
|
+
COLORS.each do |name, code|
|
17
24
|
define_method name do |text|
|
18
|
-
|
25
|
+
"\e[#{code}m#{text}\e[0m"
|
19
26
|
end
|
20
27
|
end
|
21
28
|
end
|
data/lib/model_probe/railtie.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class <%= name -%> < <%= superclass_name %>
|
4
|
+
# extends ..................................................................................................
|
5
|
+
|
6
|
+
# includes .................................................................................................
|
7
|
+
|
8
|
+
# constants ................................................................................................
|
9
|
+
|
10
|
+
# class methods ............................................................................................
|
11
|
+
class << self
|
12
|
+
end
|
13
|
+
|
14
|
+
# relationships ............................................................................................
|
15
|
+
<% foreign_key_columns.each do |column| -%>
|
16
|
+
<%= "belongs_to :#{column.name.sub(/_id\z/, "")}" %>
|
17
|
+
<% end -%>
|
18
|
+
|
19
|
+
# validations ..............................................................................................
|
20
|
+
<% validation_columns.each do |column| -%>
|
21
|
+
<%= "validates :#{column.name}, presence: true" unless column.null if required_columns.include?(column) %>
|
22
|
+
<%= "validates :#{column.name}, length: {maximum: #{column.limit}}" if limit_columns.include?(column) %>
|
23
|
+
<% end -%>
|
24
|
+
|
25
|
+
# callbacks (caution: side effects) ........................................................................
|
26
|
+
|
27
|
+
# scopes (composable queries) ..............................................................................
|
28
|
+
|
29
|
+
# additional config (accepts_nested_attribute_for, etc.) ...................................................
|
30
|
+
|
31
|
+
# public instance methods ..................................................................................
|
32
|
+
|
33
|
+
# protected instance methods ...............................................................................
|
34
|
+
|
35
|
+
# private instance methods .................................................................................
|
36
|
+
end
|
data/lib/model_probe/version.rb
CHANGED
data/lib/model_probe.rb
CHANGED
@@ -1,114 +1,216 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require "
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
require_relative "model_probe/version"
|
5
|
+
require_relative "model_probe/color"
|
6
|
+
require_relative "model_probe/railtie" if defined?(Rails)
|
4
7
|
|
5
8
|
module ModelProbe
|
6
9
|
include ModelProbe::Color
|
7
10
|
|
8
11
|
# Pretty prints column meta data for an ActiveModel
|
9
12
|
def probe
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
name = column.name
|
16
|
-
name = "* #{name}" if primary_key_column?(column)
|
17
|
-
print yellow(name.to_s.rjust(name_pad))
|
18
|
-
print " "
|
19
|
-
print blue(column.type.to_s.ljust(type_pad, "."))
|
20
|
-
print magenta(column.sql_type.to_s.ljust(sql_type_pad))
|
21
|
-
column.null ? print(red("NULL")) : print(" ")
|
22
|
-
print " [#{column.default}]" if column.default
|
23
|
-
print " #{gray column.comment}" if column.comment
|
24
|
-
puts
|
25
|
-
end
|
13
|
+
probe_header
|
14
|
+
probe_ddl
|
15
|
+
probe_columns
|
16
|
+
probe_indexes
|
17
|
+
probe_footer
|
26
18
|
nil
|
27
19
|
end
|
28
20
|
|
29
21
|
# Prints a stub that can be used for a test fixture
|
30
22
|
def print_fixture
|
31
|
-
|
32
|
-
|
33
|
-
next if timestamp_column?(column)
|
34
|
-
memo[column.name] = column.default || "value"
|
35
|
-
end
|
36
|
-
|
37
|
-
hash = { self.name.underscore => values }
|
38
|
-
puts hash.to_yaml
|
23
|
+
template = erb_template("model_probe/templates/fixture.yml.erb")
|
24
|
+
puts template.result_with_hash(name: name, fixture_columns: fixture_columns)
|
39
25
|
nil
|
40
26
|
end
|
41
27
|
|
42
28
|
# Prints a new model definition based on the database schema
|
43
29
|
def print_model
|
44
|
-
|
45
|
-
puts
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
30
|
+
template = erb_template("model_probe/templates/model.rb.erb")
|
31
|
+
puts template.result_with_hash(
|
32
|
+
name: name,
|
33
|
+
superclass_name: superclass.name,
|
34
|
+
primary_key_columns: primary_key_columns,
|
35
|
+
foreign_key_columns: foreign_key_columns,
|
36
|
+
relation_columns: relation_columns,
|
37
|
+
required_columns: required_columns,
|
38
|
+
limit_columns: limit_columns,
|
39
|
+
validation_columns: validation_columns
|
40
|
+
)
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def erb_template(relative_path)
|
47
|
+
template_path = File.expand_path(relative_path, __dir__)
|
48
|
+
template_text = File.read(template_path)
|
49
|
+
# trim_mode doesn't seem to work regardless of how it's passed with Ruby 2.7.5
|
50
|
+
ERB.new template_text, trim_mode: "-"
|
51
|
+
end
|
52
|
+
|
53
|
+
def primary_key_column?(column)
|
54
|
+
column.name == primary_key
|
55
|
+
end
|
56
|
+
|
57
|
+
def foreign_key_column?(column)
|
58
|
+
return false if primary_key_column?(column)
|
59
|
+
column.name.end_with? "_id"
|
60
|
+
end
|
61
|
+
|
62
|
+
def timestamp_column?(column)
|
63
|
+
column.type == :datetime && column.name =~ /(created|updated|modified)/
|
64
|
+
end
|
65
|
+
|
66
|
+
def required_column?(column)
|
67
|
+
return false if primary_key_column?(column)
|
68
|
+
return false if foreign_key_column?(column)
|
69
|
+
return false if timestamp_column?(column)
|
70
|
+
!column.null
|
71
|
+
end
|
72
|
+
|
73
|
+
def limit_column?(column)
|
74
|
+
return false if primary_key_column?(column)
|
75
|
+
return false if foreign_key_column?(column)
|
76
|
+
return false if timestamp_column?(column)
|
77
|
+
%i[text string].include?(column.type) && column.limit.to_i > 0
|
78
|
+
end
|
79
|
+
|
80
|
+
def primary_key_columns
|
81
|
+
columns.select { |column| primary_key_column? column }.sort_by(&:name)
|
82
|
+
end
|
83
|
+
|
84
|
+
def foreign_key_columns
|
85
|
+
columns.select { |column| foreign_key_column? column }.sort_by(&:name)
|
86
|
+
end
|
87
|
+
|
88
|
+
def relation_columns
|
89
|
+
columns.select { |column| relation_column? column }.sort_by(&:name)
|
90
|
+
end
|
91
|
+
|
92
|
+
def required_columns
|
93
|
+
columns.select { |column| required_column? column }.sort_by(&:name)
|
94
|
+
end
|
95
|
+
|
96
|
+
def limit_columns
|
97
|
+
columns.select { |column| limit_column? column }.sort_by(&:name)
|
98
|
+
end
|
99
|
+
|
100
|
+
def validation_columns
|
101
|
+
(required_columns + limit_columns).uniq.sort_by(&:name)
|
102
|
+
end
|
103
|
+
|
104
|
+
def relation_column?(column)
|
105
|
+
return false if column.name == primary_key
|
106
|
+
column.name.end_with?("_id")
|
107
|
+
end
|
108
|
+
|
109
|
+
def fixture_columns
|
110
|
+
columns.sort_by(&:name).select do |column|
|
111
|
+
!primary_key_column?(column) && !timestamp_column?(column)
|
52
112
|
end
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
113
|
+
end
|
114
|
+
|
115
|
+
def ddl
|
116
|
+
config = connection_db_config.configuration_hash
|
117
|
+
@ddl ||= begin
|
118
|
+
case connection.adapter_name
|
119
|
+
when /sqlite/i
|
120
|
+
`sqlite3 #{config[:database]} '.schema #{table_name}'`
|
121
|
+
when /postgresql/i
|
122
|
+
`PGPASSWORD=#{config[:password]} pg_dump --host=#{config[:host]} --username=#{config[:username]} --schema-only --table=#{table_name} #{config[:database]}`
|
123
|
+
when /mysql/i
|
124
|
+
`mysqldump --host=#{config[:host]} --user=#{config[:username]} --password=#{config[:password]} --no-data --compact #{config[:database]} #{table_name}`
|
125
|
+
else
|
126
|
+
"DDL output is not yet supported for #{connection.adapter_name}!"
|
60
127
|
end
|
128
|
+
rescue => e
|
129
|
+
Color.red "Failed to generate DDL string! #{e.message}"
|
61
130
|
end
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
puts "
|
66
|
-
|
67
|
-
|
68
|
-
puts
|
69
|
-
puts "
|
131
|
+
end
|
132
|
+
|
133
|
+
def probe_header
|
134
|
+
puts Color.gray "".ljust(110, "=")
|
135
|
+
print connection.adapter_name
|
136
|
+
print Color.gray(" (#{connection.database_version}) - ")
|
137
|
+
puts Color.green(table_name)
|
138
|
+
puts Color.gray "".ljust(110, "=")
|
70
139
|
puts
|
71
|
-
|
140
|
+
end
|
141
|
+
|
142
|
+
def probe_ddl(pad: 2)
|
143
|
+
return unless ddl
|
144
|
+
lines = ddl.split("\n")
|
145
|
+
lines.each do |line|
|
146
|
+
next if line.strip.blank?
|
147
|
+
next if line.strip.start_with?("--")
|
148
|
+
next if line.strip.start_with?("/*")
|
149
|
+
print " ".ljust(pad)
|
150
|
+
puts Color.gray(line)
|
151
|
+
end
|
72
152
|
puts
|
73
|
-
|
74
|
-
|
153
|
+
end
|
154
|
+
|
155
|
+
def probe_column(column, name_pad:, type_pad:, sql_type_pad:)
|
156
|
+
name = column.name
|
157
|
+
if primary_key_column?(column)
|
158
|
+
print Color.pink("*#{name}".rjust(name_pad))
|
159
|
+
else
|
160
|
+
print Color.magenta(name.to_s.rjust(name_pad))
|
161
|
+
end
|
162
|
+
print " "
|
163
|
+
print column.type.to_s.ljust(type_pad, ".")
|
164
|
+
print Color.gray(column.sql_type.to_s.ljust(sql_type_pad))
|
165
|
+
print Color.gray("NULLABLE ") if column.null
|
166
|
+
print Color.pink("REQUIRED ") unless column.null
|
167
|
+
print Color.gray("default=#{column.default} ") if column.default
|
168
|
+
print "- #{Color.gray column.comment}" if column.comment
|
75
169
|
puts
|
76
|
-
puts " # private instance methods .................................................."
|
77
|
-
puts " private"
|
78
|
-
puts "end"
|
79
|
-
nil
|
80
170
|
end
|
81
171
|
|
82
|
-
|
172
|
+
def probe_columns
|
173
|
+
name_pad = columns.map { |c| c.name.length }.max + 2
|
174
|
+
type_pad = columns.map { |c| c.type.length }.max + 2
|
175
|
+
sql_type_pad = columns.map { |c| c.sql_type.length }.max + 1
|
83
176
|
|
84
|
-
|
85
|
-
|
86
|
-
columns.select { |column| relation_column? column }
|
87
|
-
end
|
177
|
+
columns.sort_by(&:name).each do |column|
|
178
|
+
probe_column column, name_pad: name_pad, type_pad: type_pad, sql_type_pad: sql_type_pad
|
88
179
|
end
|
180
|
+
puts
|
181
|
+
end
|
89
182
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
183
|
+
def probe_index(index, name_pad:)
|
184
|
+
print Color.yellow_light(index.name.to_s.rjust(name_pad))
|
185
|
+
print Color.gray(" [")
|
186
|
+
index.columns.each_with_index do |column, index|
|
187
|
+
print Color.gray(", ") if index > 0
|
188
|
+
print Color.magenta(column)
|
94
189
|
end
|
190
|
+
print Color.gray("]")
|
191
|
+
print Color.green_light(" UNIQUE") if index.unique
|
95
192
|
|
96
|
-
|
97
|
-
|
193
|
+
if index.where
|
194
|
+
print Color.gray(" where(#{index.where})")
|
98
195
|
end
|
99
196
|
|
100
|
-
|
101
|
-
|
197
|
+
if index.using
|
198
|
+
print Color.gray(" using(#{index.using})")
|
102
199
|
end
|
200
|
+
puts
|
201
|
+
end
|
103
202
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
203
|
+
def probe_indexes
|
204
|
+
indexes = connection.indexes(table_name)
|
205
|
+
name_pad = indexes.map { |c| c.name.length }.max + 1
|
108
206
|
|
109
|
-
|
110
|
-
|
111
|
-
return true unless column.null
|
112
|
-
%i(text string).include?(column.type) && column.limit.to_i > 0
|
207
|
+
indexes.sort_by(&:name).each do |index|
|
208
|
+
probe_index index, name_pad: name_pad
|
113
209
|
end
|
210
|
+
puts
|
211
|
+
end
|
212
|
+
|
213
|
+
def probe_footer
|
214
|
+
puts Color.gray "".ljust(110, "=")
|
215
|
+
end
|
114
216
|
end
|
data/lib/tasks/model_probe.rake
CHANGED
data/model_probe.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/model_probe/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "model_probe"
|
7
|
+
s.version = ModelProbe::VERSION
|
8
|
+
s.authors = ["Nathan Hopkins"]
|
9
|
+
s.email = ["natehop@gmail.com"]
|
10
|
+
s.summary = "ActiveRecord schema visualization and model organization made easy"
|
11
|
+
s.homepage = "http://hopsoft.github.com/model_probe/"
|
12
|
+
|
13
|
+
s.files = Dir["lib/**/*rb", "lib/tasks/*rake", "[A-Z]*"]
|
14
|
+
|
15
|
+
s.add_development_dependency "magic_frozen_string_literal"
|
16
|
+
s.add_development_dependency "standardrb"
|
17
|
+
end
|
data/tags
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
!_TAG_EXTRA_DESCRIPTION anonymous /Include tags for non-named objects like lambda/
|
2
|
+
!_TAG_EXTRA_DESCRIPTION fileScope /Include tags of file scope/
|
3
|
+
!_TAG_EXTRA_DESCRIPTION pseudo /Include pseudo tags/
|
4
|
+
!_TAG_EXTRA_DESCRIPTION subparser /Include tags generated by subparsers/
|
5
|
+
!_TAG_FIELD_DESCRIPTION epoch /the last modified time of the input file (only for F\/file kind tag)/
|
6
|
+
!_TAG_FIELD_DESCRIPTION file /File-restricted scoping/
|
7
|
+
!_TAG_FIELD_DESCRIPTION input /input file/
|
8
|
+
!_TAG_FIELD_DESCRIPTION name /tag name/
|
9
|
+
!_TAG_FIELD_DESCRIPTION pattern /pattern/
|
10
|
+
!_TAG_FIELD_DESCRIPTION typeref /Type and name of a variable or typedef/
|
11
|
+
!_TAG_FIELD_DESCRIPTION!Ruby mixin /how the class or module is mixed in (mixin:HOW:MODULE)/
|
12
|
+
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
13
|
+
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
14
|
+
!_TAG_KIND_DESCRIPTION!GemSpec g,gem /gems/
|
15
|
+
!_TAG_KIND_DESCRIPTION!Markdown S,subsection /level 2 sections/
|
16
|
+
!_TAG_KIND_DESCRIPTION!Markdown T,l4subsection /level 4 sections/
|
17
|
+
!_TAG_KIND_DESCRIPTION!Markdown c,chapter /chapters/
|
18
|
+
!_TAG_KIND_DESCRIPTION!Markdown n,footnote /footnotes/
|
19
|
+
!_TAG_KIND_DESCRIPTION!Markdown s,section /sections/
|
20
|
+
!_TAG_KIND_DESCRIPTION!Markdown t,subsubsection /level 3 sections/
|
21
|
+
!_TAG_KIND_DESCRIPTION!Markdown u,l5subsection /level 5 sections/
|
22
|
+
!_TAG_KIND_DESCRIPTION!Rake d,directory /directory tasks/
|
23
|
+
!_TAG_KIND_DESCRIPTION!Rake f,File /file tasks/
|
24
|
+
!_TAG_KIND_DESCRIPTION!Rake m,multitask /multi tasks/
|
25
|
+
!_TAG_KIND_DESCRIPTION!Rake n,namespace /namespaces/
|
26
|
+
!_TAG_KIND_DESCRIPTION!Rake t,task /tasks/
|
27
|
+
!_TAG_KIND_DESCRIPTION!Rake x,xtask /tasks defined with special constructor/
|
28
|
+
!_TAG_KIND_DESCRIPTION!Ruby A,accessor /accessors/
|
29
|
+
!_TAG_KIND_DESCRIPTION!Ruby C,constant /constants/
|
30
|
+
!_TAG_KIND_DESCRIPTION!Ruby L,library /libraries/
|
31
|
+
!_TAG_KIND_DESCRIPTION!Ruby S,singletonMethod /singleton methods/
|
32
|
+
!_TAG_KIND_DESCRIPTION!Ruby a,alias /aliases/
|
33
|
+
!_TAG_KIND_DESCRIPTION!Ruby c,class /classes/
|
34
|
+
!_TAG_KIND_DESCRIPTION!Ruby f,method /methods/
|
35
|
+
!_TAG_KIND_DESCRIPTION!Ruby m,module /modules/
|
36
|
+
!_TAG_KIND_DESCRIPTION!Sh a,alias /aliases/
|
37
|
+
!_TAG_KIND_DESCRIPTION!Sh f,function /functions/
|
38
|
+
!_TAG_KIND_DESCRIPTION!Sh h,heredoc /label for here document/
|
39
|
+
!_TAG_KIND_DESCRIPTION!Sh s,script /script files/
|
40
|
+
!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/
|
41
|
+
!_TAG_OUTPUT_FILESEP slash /slash or backslash/
|
42
|
+
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
|
43
|
+
!_TAG_OUTPUT_VERSION 0.0 /current.age/
|
44
|
+
!_TAG_PARSER_VERSION!GemSpec 0.0 /current.age/
|
45
|
+
!_TAG_PARSER_VERSION!Markdown 0.0 /current.age/
|
46
|
+
!_TAG_PARSER_VERSION!Rake 0.0 /current.age/
|
47
|
+
!_TAG_PARSER_VERSION!Ruby 0.0 /current.age/
|
48
|
+
!_TAG_PARSER_VERSION!Sh 0.0 /current.age/
|
49
|
+
!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/
|
50
|
+
!_TAG_PROC_CWD /Users/nathan/work/hopsoft/model_probe/ //
|
51
|
+
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
|
52
|
+
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
|
53
|
+
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
|
54
|
+
!_TAG_PROGRAM_VERSION 6.0.0 //
|
55
|
+
!_TAG_ROLE_DESCRIPTION!GemSpec!gem develDep /specifying development dependency/
|
56
|
+
!_TAG_ROLE_DESCRIPTION!GemSpec!gem runtimeDep /specifying runtime dependency/
|
57
|
+
!_TAG_ROLE_DESCRIPTION!Ruby!library loaded /loaded by "load" method/
|
58
|
+
!_TAG_ROLE_DESCRIPTION!Ruby!library required /loaded by "require" method/
|
59
|
+
!_TAG_ROLE_DESCRIPTION!Ruby!library requiredRel /loaded by "require_relative" method/
|
60
|
+
!_TAG_ROLE_DESCRIPTION!Sh!heredoc endmarker /end marker/
|
61
|
+
!_TAG_ROLE_DESCRIPTION!Sh!script loaded /loaded/
|
62
|
+
ActiveRecord schema visualization and model organization made easy 🙌 README.md /^## ActiveRecord schema visualization and model organization made easy 🙌$/;" s chapter:ModelProbe
|
63
|
+
COLORS lib/model_probe/color.rb /^ COLORS = {$/;" C module:ModelProbe.Color
|
64
|
+
Color lib/model_probe/color.rb /^ module Color$/;" m module:ModelProbe mixin:extend:self
|
65
|
+
ModelProbe README.md /^# ModelProbe$/;" c
|
66
|
+
ModelProbe lib/model_probe.rb /^module ModelProbe$/;" m mixin:include:ModelProbe.Color
|
67
|
+
ModelProbe lib/model_probe/color.rb /^module ModelProbe$/;" m
|
68
|
+
ModelProbe lib/model_probe/railtie.rb /^ module ModelProbe$/;" m
|
69
|
+
ModelProbe lib/model_probe/version.rb /^module ModelProbe$/;" m
|
70
|
+
Quick Start README.md /^## Quick Start$/;" s chapter:ModelProbe
|
71
|
+
Railtie lib/model_probe/railtie.rb /^ class Railtie < Rails::Railtie$/;" c module:ModelProbe
|
72
|
+
Screenshots README.md /^## Screenshots$/;" s chapter:ModelProbe
|
73
|
+
Supported Databases README.md /^## Supported Databases$/;" s chapter:ModelProbe
|
74
|
+
Table of Contents README.md /^## Table of Contents$/;" s chapter:ModelProbe
|
75
|
+
VERSION lib/model_probe/version.rb /^ VERSION = "1.1.0"$/;" C module:ModelProbe
|
76
|
+
Videos README.md /^## Videos$/;" s chapter:ModelProbe
|
77
|
+
ddl lib/model_probe.rb /^ def ddl$/;" f module:ModelProbe
|
78
|
+
erb_template lib/model_probe.rb /^ def erb_template(relative_path)$/;" f module:ModelProbe
|
79
|
+
fixture_columns lib/model_probe.rb /^ def fixture_columns$/;" f module:ModelProbe
|
80
|
+
foreign_key_column? lib/model_probe.rb /^ def foreign_key_column?(column)$/;" f module:ModelProbe
|
81
|
+
foreign_key_columns lib/model_probe.rb /^ def foreign_key_columns$/;" f module:ModelProbe
|
82
|
+
limit_column? lib/model_probe.rb /^ def limit_column?(column)$/;" f module:ModelProbe
|
83
|
+
limit_columns lib/model_probe.rb /^ def limit_columns$/;" f module:ModelProbe
|
84
|
+
model_probe lib/tasks/model_probe.rake /^namespace :model_probe do$/;" n
|
85
|
+
model_probe model_probe.gemspec /^ s.name = "model_probe"$/;" g
|
86
|
+
primary_key_column? lib/model_probe.rb /^ def primary_key_column?(column)$/;" f module:ModelProbe
|
87
|
+
primary_key_columns lib/model_probe.rb /^ def primary_key_columns$/;" f module:ModelProbe
|
88
|
+
print_fixture lib/model_probe.rb /^ def print_fixture$/;" f module:ModelProbe
|
89
|
+
print_fixture lib/tasks/model_probe.rake /^ task :print_fixture, [:klass] => :environment do |task, args|$/;" t namespace:model_probe
|
90
|
+
print_model lib/model_probe.rb /^ def print_model$/;" f module:ModelProbe
|
91
|
+
print_model lib/tasks/model_probe.rake /^ task :print_model, [:klass] => :environment do |task, args|$/;" t namespace:model_probe
|
92
|
+
probe lib/model_probe.rb /^ def probe$/;" f module:ModelProbe
|
93
|
+
probe lib/tasks/model_probe.rake /^ task :probe, [:klass] => :environment do |task, args|$/;" t namespace:model_probe
|
94
|
+
probe_column lib/model_probe.rb /^ def probe_column(column, name_pad:, type_pad:, sql_type_pad:)$/;" f module:ModelProbe
|
95
|
+
probe_columns lib/model_probe.rb /^ def probe_columns$/;" f module:ModelProbe
|
96
|
+
probe_ddl lib/model_probe.rb /^ def probe_ddl(pad: 2)$/;" f module:ModelProbe
|
97
|
+
probe_footer lib/model_probe.rb /^ def probe_footer$/;" f module:ModelProbe
|
98
|
+
probe_header lib/model_probe.rb /^ def probe_header$/;" f module:ModelProbe
|
99
|
+
probe_index lib/model_probe.rb /^ def probe_index(index, name_pad:)$/;" f module:ModelProbe
|
100
|
+
probe_indexes lib/model_probe.rb /^ def probe_indexes$/;" f module:ModelProbe
|
101
|
+
relation_column? lib/model_probe.rb /^ def relation_column?(column)$/;" f module:ModelProbe
|
102
|
+
relation_columns lib/model_probe.rb /^ def relation_columns$/;" f module:ModelProbe
|
103
|
+
required_column? lib/model_probe.rb /^ def required_column?(column)$/;" f module:ModelProbe
|
104
|
+
required_columns lib/model_probe.rb /^ def required_columns$/;" f module:ModelProbe
|
105
|
+
timestamp_column? lib/model_probe.rb /^ def timestamp_column?(column)$/;" f module:ModelProbe
|
106
|
+
validation_columns lib/model_probe.rb /^ def validation_columns$/;" f module:ModelProbe
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: model_probe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Hopkins
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: magic_frozen_string_literal
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -24,7 +24,21 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: standardrb
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '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'
|
41
|
+
description:
|
28
42
|
email:
|
29
43
|
- natehop@gmail.com
|
30
44
|
executables: []
|
@@ -39,12 +53,16 @@ files:
|
|
39
53
|
- lib/model_probe.rb
|
40
54
|
- lib/model_probe/color.rb
|
41
55
|
- lib/model_probe/railtie.rb
|
56
|
+
- lib/model_probe/templates/fixture.yml.erb
|
57
|
+
- lib/model_probe/templates/model.rb.erb
|
42
58
|
- lib/model_probe/version.rb
|
43
59
|
- lib/tasks/model_probe.rake
|
60
|
+
- model_probe.gemspec
|
61
|
+
- tags
|
44
62
|
homepage: http://hopsoft.github.com/model_probe/
|
45
63
|
licenses: []
|
46
64
|
metadata: {}
|
47
|
-
post_install_message:
|
65
|
+
post_install_message:
|
48
66
|
rdoc_options: []
|
49
67
|
require_paths:
|
50
68
|
- lib
|
@@ -59,9 +77,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
77
|
- !ruby/object:Gem::Version
|
60
78
|
version: '0'
|
61
79
|
requirements: []
|
62
|
-
|
63
|
-
|
64
|
-
signing_key:
|
80
|
+
rubygems_version: 3.4.10
|
81
|
+
signing_key:
|
65
82
|
specification_version: 4
|
66
|
-
summary:
|
83
|
+
summary: ActiveRecord schema visualization and model organization made easy
|
67
84
|
test_files: []
|