datagaze 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +25 -0
- data/MIT-LICENSE +20 -0
- data/README.md +115 -0
- data/bin/datagaze +20 -0
- data/lib/datagaze/models/models/base.rb +70 -0
- data/lib/datagaze/models/models/fixed_text_elements.rb +25 -0
- data/lib/datagaze/models/models/get_all_model_constants.rb +20 -0
- data/lib/datagaze/models/models/print_schema_information.rb +47 -0
- data/lib/datagaze/models/models.rb +5 -0
- data/lib/datagaze/version.rb +6 -0
- data/lib/datagaze.rb +10 -0
- data/lib/tasks/datagaze_models.rb +16 -0
- data/lib/tasks/installation.rb +36 -0
- data/lib/tasks/templates/datagaze_on_migration.rake +20 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 40843266b1b5f1b3b5e42c8b86d0df281a507bed943fe2cfb93f1ad2ac9a90d3
|
4
|
+
data.tar.gz: ded9dd284b9e1a42ecfb19718ebfe0b9ba854ff08e0e9679c21ab65037c9b679
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b237da054b7831101b4fb0a1d653743a3a16159f43aa433d5a8551651bdf6d45c71be10686def2da01013ac4e60213c9cdf9b9b7394212d9294127c0cf2f1731
|
7
|
+
data.tar.gz: c4ad5939241100066d3f862a695595f9c81c4e5b0faff315ed88352ce3399051b5e946b1fca5024d4fd2452542b20653bd52a4fbd2d95d2cc6e4e96f15e125f2
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
datagaze (0.0.1)
|
5
|
+
rake
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
coderay (1.1.3)
|
11
|
+
method_source (1.0.0)
|
12
|
+
pry (0.14.1)
|
13
|
+
coderay (~> 1.1)
|
14
|
+
method_source (~> 1.0)
|
15
|
+
rake (13.0.6)
|
16
|
+
|
17
|
+
PLATFORMS
|
18
|
+
x86_64-darwin-19
|
19
|
+
|
20
|
+
DEPENDENCIES
|
21
|
+
datagaze!
|
22
|
+
pry
|
23
|
+
|
24
|
+
BUNDLED WITH
|
25
|
+
2.2.27
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2021 Jurriaan Schrofer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
|
2
|
+
# Datagaze
|
3
|
+
|
4
|
+
Look at your database without ever leaving your model. Yay!
|
5
|
+
|
6
|
+
`datagaze` dynamically inserts and updates schema information into your Rails models, which in effect prevents you from having to visit schema.rb and helps other developers to quickly grasp the nature of your models.
|
7
|
+
|
8
|
+
If you are curious what problems are fixed by `datagaze` (which are prevalent in other gems, such as `annotate`) skip down some sections below.
|
9
|
+
|
10
|
+
# Overview
|
11
|
+
|
12
|
+
## Sneak preview
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
|
16
|
+
# app/models/user.rb
|
17
|
+
|
18
|
+
=begin
|
19
|
+
|
20
|
+
== Schema information for table 'users'
|
21
|
+
|
22
|
+
column_name column_type column_default
|
23
|
+
|
24
|
+
id integer -
|
25
|
+
first_name string -
|
26
|
+
last_name string -
|
27
|
+
confirmed boolean false
|
28
|
+
created_at datetime -
|
29
|
+
updated_at datetime -
|
30
|
+
|
31
|
+
=end
|
32
|
+
|
33
|
+
class User < ApplicationRecord
|
34
|
+
|
35
|
+
# Just your User model contents, as it already is.
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
```
|
40
|
+
|
41
|
+
## Installation
|
42
|
+
|
43
|
+
Using Rubygems in your gemfile:
|
44
|
+
```ruby
|
45
|
+
group :development do
|
46
|
+
gem 'datagaze'
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Or, alternatively, using Github in your gemfile:
|
51
|
+
```ruby
|
52
|
+
group :development do
|
53
|
+
gem 'datagaze', git: 'https://github.com/jurriaanschrofer/datagaze'
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
Afterwards, run the following command in the root of your project directory. This enables datagaze to update your models automatically on every future migration.
|
58
|
+
|
59
|
+
```
|
60
|
+
$ bundle exec datagaze install
|
61
|
+
```
|
62
|
+
|
63
|
+
## Usage
|
64
|
+
|
65
|
+
Besides the installation command listed above (which enables datagaze to automatically update your models on every future migration) datagaze provides you with three other commands:
|
66
|
+
|
67
|
+
Run datagaze by hand with:
|
68
|
+
```
|
69
|
+
$ bundle exec datagaze models
|
70
|
+
```
|
71
|
+
|
72
|
+
Remove all informational tables created by datagaze with:
|
73
|
+
```
|
74
|
+
$ bundle exec datagaze remove
|
75
|
+
```
|
76
|
+
|
77
|
+
Uninstall datagaze (and prevent it from running automatically) with:
|
78
|
+
```
|
79
|
+
$ bundle exec datagaze uninstall
|
80
|
+
```
|
81
|
+
|
82
|
+
# vs. Annotate
|
83
|
+
|
84
|
+
## The problem of the annotate gem
|
85
|
+
|
86
|
+
The wildly popular `annotate` gem (which is awesome, thanks guys) has a fundamental flaw, which `datagaze` fixes:
|
87
|
+
|
88
|
+
Annotate requires that your project has one single directory for all models (by default the `app/models` directory). Any models that are not placed in this directory, will produce an error and prevent ALL models from being annotated.
|
89
|
+
|
90
|
+
For some this may just be fine – but for the many who are maintaining larger applications, gems or simply projects that require flexibility, this is breaking.
|
91
|
+
|
92
|
+
## The fix by datagaze
|
93
|
+
|
94
|
+
Instead of relying on a rigid file structure, datagaze combines ruby's dynamic `const_source_location` with rails' dynamic `ApplicationRecord.descendants`.
|
95
|
+
|
96
|
+
In effect, datagaze is able to dynamically trace the location of ANY model that inherits from ApplicationRecord, no matter where it is hidden in your project.
|
97
|
+
|
98
|
+
## datagaze vs. annotate
|
99
|
+
|
100
|
+
Whilst this approach is crucial to some, annotate is better for others. So let's make a fair comparision:
|
101
|
+
|
102
|
+
### Why datagaze is better
|
103
|
+
|
104
|
+
- Datagaze handles all models irregardless of their source location, thereby putting no constraints on your project.
|
105
|
+
- Datagaze has a substantially smaller memory footprint than annotate.
|
106
|
+
- Datagaze is simpler to use: due to configuration being absent, you just have install the gem and run `bundle exec datagaze install` once.
|
107
|
+
- Datagaze's source code is much easier to customize or fork (sorry folks, annotate's code base is a mess).
|
108
|
+
|
109
|
+
### Why annotate is better
|
110
|
+
|
111
|
+
- Datagaze relies on ruby's `const_source_location` method, which was only released in ruby 2.7. If you operate below, you can't use datagaze.
|
112
|
+
- Annotate has more configurable options (pull requests are welcome though).
|
113
|
+
|
114
|
+
|
115
|
+
|
data/bin/datagaze
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
require 'datagaze'
|
3
|
+
require 'optparse'
|
4
|
+
require './config/environment'
|
5
|
+
|
6
|
+
if ARGV.include?("install")
|
7
|
+
Rake::Task[:install].invoke
|
8
|
+
|
9
|
+
elsif ARGV.include?("uninstall")
|
10
|
+
Rake::Task[:uninstall].invoke
|
11
|
+
|
12
|
+
elsif ARGV.include?("models")
|
13
|
+
Rake::Task[:datagaze_models].invoke
|
14
|
+
|
15
|
+
elsif ARGV.include?("remove")
|
16
|
+
Rake::Task[:datagaze_remove].invoke
|
17
|
+
|
18
|
+
else
|
19
|
+
raise ArgumentError, "no valid rake task argument was given, options are: 'models', 'remove'"
|
20
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Datagaze::Models
|
2
|
+
class << self
|
3
|
+
|
4
|
+
# The method that creates all annotations
|
5
|
+
def annotate_all_models
|
6
|
+
collect_all_models.each do |model, atts|
|
7
|
+
annotate_one_model(model: model, **atts.slice(:path, :table_name) )
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# The method that removes all annotations, if desired
|
12
|
+
def clean_all_annotations
|
13
|
+
collect_all_models.each do |model, atts|
|
14
|
+
clean_one_model(model: model, **atts.slice(:path) )
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def annotate_one_model(model:, path:, table_name:)
|
21
|
+
@model = model
|
22
|
+
@path = path
|
23
|
+
@table_name = table_name
|
24
|
+
@columns = columns
|
25
|
+
@contents = generate_schema_information
|
26
|
+
|
27
|
+
File.open(path, "w+") { _1 << @contents }
|
28
|
+
end
|
29
|
+
|
30
|
+
def clean_one_model(model:, path:)
|
31
|
+
@model = model
|
32
|
+
@path = path
|
33
|
+
@contents = exisiting_file_contents
|
34
|
+
|
35
|
+
File.open(path, "w+") { _1 << @contents }
|
36
|
+
end
|
37
|
+
|
38
|
+
def generate_schema_information
|
39
|
+
begin_of_comment +
|
40
|
+
informational_header +
|
41
|
+
table_information +
|
42
|
+
end_of_comment +
|
43
|
+
exisiting_file_contents
|
44
|
+
end
|
45
|
+
|
46
|
+
def columns
|
47
|
+
columns = ApplicationRecord.connection.columns(@table_name)
|
48
|
+
sort_columns(columns)
|
49
|
+
end
|
50
|
+
|
51
|
+
def sort_columns(columns)
|
52
|
+
columns.sort_by { _1.name }
|
53
|
+
end
|
54
|
+
|
55
|
+
def table_information
|
56
|
+
@columns.map { column_information(_1) }.join("\n")
|
57
|
+
end
|
58
|
+
|
59
|
+
def exisiting_file_contents
|
60
|
+
file_contents = File.read(@path)
|
61
|
+
remove_previous_annotation(file_contents)
|
62
|
+
end
|
63
|
+
|
64
|
+
def remove_previous_annotation(file_contents)
|
65
|
+
annotation_matcher = /^=begin\n\n== Schema information.*^?(?=class)/m
|
66
|
+
file_contents.gsub(annotation_matcher, '')
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Datagaze::Models
|
2
|
+
class << self
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def begin_of_comment
|
7
|
+
<<~EOL
|
8
|
+
=begin
|
9
|
+
|
10
|
+
== Schema information for table '#{@table_name}'
|
11
|
+
|
12
|
+
EOL
|
13
|
+
end
|
14
|
+
|
15
|
+
def end_of_comment
|
16
|
+
<<~EOL
|
17
|
+
|
18
|
+
|
19
|
+
=end
|
20
|
+
|
21
|
+
EOL
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Datagaze::Models
|
2
|
+
class << self
|
3
|
+
|
4
|
+
def collect_all_models
|
5
|
+
|
6
|
+
models = ApplicationRecord.descendants.select { |model| !model.abstract_class? }
|
7
|
+
|
8
|
+
models.map do |model|
|
9
|
+
|
10
|
+
path, line_no = ApplicationRecord.const_source_location(model.to_s)
|
11
|
+
table_name = model.table_name
|
12
|
+
|
13
|
+
{ model => { path: path, table_name: table_name } }
|
14
|
+
|
15
|
+
end.reduce(&:merge)
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Datagaze::Models
|
2
|
+
class << self
|
3
|
+
|
4
|
+
ColumnPadding = 5
|
5
|
+
|
6
|
+
private
|
7
|
+
|
8
|
+
def informational_header
|
9
|
+
name_header = "column_name".ljust(name_column_width)
|
10
|
+
type_header = "column_type".ljust(type_column_width)
|
11
|
+
default_header = "column_default".ljust(default_column_width)
|
12
|
+
returns = "\n\n"
|
13
|
+
name_header + type_header + default_header + returns
|
14
|
+
end
|
15
|
+
|
16
|
+
def name_column_width
|
17
|
+
[*@columns.map { _1.name.length }, "column_name".length].compact.max + ColumnPadding
|
18
|
+
end
|
19
|
+
|
20
|
+
def type_column_width
|
21
|
+
[*@columns.map { _1.type.to_s.length }, "column_type".length].compact.max + ColumnPadding
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_column_width
|
25
|
+
[*@columns.map { _1.default&.length }, "column_default".length].compact.max + ColumnPadding
|
26
|
+
end
|
27
|
+
|
28
|
+
def name_column_value
|
29
|
+
(@column.name || "-").ljust(name_column_width)
|
30
|
+
end
|
31
|
+
|
32
|
+
def type_column_value
|
33
|
+
(@column.type.to_s || "-").ljust(type_column_width)
|
34
|
+
end
|
35
|
+
|
36
|
+
def default_column_value
|
37
|
+
(@column.default || "-").ljust(default_column_width)
|
38
|
+
end
|
39
|
+
|
40
|
+
def column_information(column)
|
41
|
+
@column = column
|
42
|
+
name_column_value + type_column_value + default_column_value
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/lib/datagaze.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative "../datagaze/models/models"
|
2
|
+
|
3
|
+
desc "Adds a table representation to your model files."
|
4
|
+
task :datagaze_models do
|
5
|
+
puts "Datagaze is adding table representations to your model files..."
|
6
|
+
Rails.application.eager_load!
|
7
|
+
Datagaze::Models.annotate_all_models
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "Removes the table representation from your model files."
|
11
|
+
task :datagaze_remove do
|
12
|
+
puts "Datagaze is removing table representations from your model files..."
|
13
|
+
Rails.application.eager_load!
|
14
|
+
Datagaze::Models.clean_all_annotations
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
Instead of using Rails generators to run the gem's installation (and thereby
|
4
|
+
requiring a railtie), we simply copy and paste the required file into the
|
5
|
+
main application's lib directory ourselves. Doing so will add hooks to all
|
6
|
+
migration rake tasks as provided by rails, effectively running `bundle exec
|
7
|
+
datagaze models` everytime a database operation is performed.
|
8
|
+
|
9
|
+
=end
|
10
|
+
|
11
|
+
desc "Install datagaze and let it run on every migration."
|
12
|
+
task :install do
|
13
|
+
|
14
|
+
puts "Datagaze is enabling to automatically run on every future migrations..."
|
15
|
+
|
16
|
+
require './config/environment'
|
17
|
+
|
18
|
+
source_path = File.expand_path('../templates/datagaze_on_migration.rake', __FILE__)
|
19
|
+
destination_path = Rails.root.join('lib/tasks/datagaze_on_migration.rake')
|
20
|
+
|
21
|
+
`cp #{source_path} #{destination_path}`
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Uninstall datagaze and prevent it from running on every migration."
|
26
|
+
task :uninstall do
|
27
|
+
|
28
|
+
puts "Datagaze is uninstalling and stops to automatically run on future migrations..."
|
29
|
+
|
30
|
+
require './config/environment'
|
31
|
+
|
32
|
+
installation_path = Rails.root.join('lib/tasks/datagaze_on_migration.rake')
|
33
|
+
|
34
|
+
`rm #{installation_path}`
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
|
2
|
+
# Using an initializtion rake task, this file somehow needs to be copied
|
3
|
+
# to the main application's app/lib/tasks directory
|
4
|
+
|
5
|
+
if Kernel.const_defined?("Rails::Application") && Rails::VERSION::MAJOR >= 6
|
6
|
+
|
7
|
+
require "active_record"
|
8
|
+
|
9
|
+
migration_tasks = %w( db:migrate db:migrate:up db:migrate:down db:migrate:reset
|
10
|
+
db:migrate:redo db:rollback )
|
11
|
+
|
12
|
+
migration_tasks.each do |task|
|
13
|
+
|
14
|
+
next unless Rake::Task.task_defined?(task)
|
15
|
+
|
16
|
+
Rake::Task[task].enhance do
|
17
|
+
Rake::Task['datagaze_models'].invoke
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: datagaze
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jurriaan Schrofer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-10-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
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: Take a look at your database without ever leaving your models.
|
42
|
+
email:
|
43
|
+
- jschrofer@gmail.com
|
44
|
+
executables:
|
45
|
+
- datagaze
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- Gemfile
|
50
|
+
- Gemfile.lock
|
51
|
+
- MIT-LICENSE
|
52
|
+
- README.md
|
53
|
+
- bin/datagaze
|
54
|
+
- lib/datagaze.rb
|
55
|
+
- lib/datagaze/models/models.rb
|
56
|
+
- lib/datagaze/models/models/base.rb
|
57
|
+
- lib/datagaze/models/models/fixed_text_elements.rb
|
58
|
+
- lib/datagaze/models/models/get_all_model_constants.rb
|
59
|
+
- lib/datagaze/models/models/print_schema_information.rb
|
60
|
+
- lib/datagaze/version.rb
|
61
|
+
- lib/tasks/datagaze_models.rb
|
62
|
+
- lib/tasks/installation.rb
|
63
|
+
- lib/tasks/templates/datagaze_on_migration.rake
|
64
|
+
homepage: https://github.com/jurriaanschrofer/datagaze
|
65
|
+
licenses:
|
66
|
+
- MIT
|
67
|
+
metadata:
|
68
|
+
homepage_uri: https://github.com/jurriaanschrofer/datagaze
|
69
|
+
source_code_uri: https://github.com/jurriaanschrofer/datagaze
|
70
|
+
changelog_uri: https://github.com/jurriaanschrofer/datagaze
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubygems_version: 3.0.9
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Take a look at your database without ever leaving your models.
|
90
|
+
test_files: []
|