rails-diff 0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a5049aad3c07aafb46e197ad4a1e57655615d1c0b577ab07939a13cb0a28cce9
4
+ data.tar.gz: 589d63e3f324dc0a86b9816586d88517146f9e2dc84f71c4b10c7b414e4de054
5
+ SHA512:
6
+ metadata.gz: cf848b14e60228991ee6f6091f17a49ad30e69fe3efd1fdbddf9a069826a6ba4af0460ec4e6e9891bd1dfcd5762a6b457e7c68c115972229ca18a64f375ef5ae
7
+ data.tar.gz: f72083a3b5329062e0939ad04c7dc3745262d755550197a4e8e5e814a9561705e9c9cee45a9e010a5d323698fe8987240e33a8d1cb7dd8555431ca1fa7d98a44
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-02-21
4
+
5
+ - Initial release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Matheus Richard
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # Rails::Diff
2
+
3
+ Compare your Rails application files with the ones generated by Rails main
4
+ branch. This helps you keep track of changes between your customized files and
5
+ the latest Rails templates.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'rails-diff'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ ```bash
18
+ $ bundle install
19
+ ```
20
+
21
+ Or install it yourself as:
22
+
23
+ ```bash
24
+ $ gem install rails-diff
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### Compare specific files
30
+
31
+ ```bash
32
+ # Compare a single file
33
+ rails-diff file config/routes.rb
34
+
35
+ # Compare multiple files
36
+ rails-diff file config/routes.rb config/application.rb
37
+
38
+ # Force regenerate Rails app by clearing cache
39
+ rails-diff file config/routes.rb --clear-cache
40
+ ```
41
+
42
+ ### Compare generator files
43
+
44
+ ```bash
45
+ # Compare files that would be created by a generator
46
+ rails-diff generated authentication
47
+
48
+ # Compare files with generator arguments
49
+ rails-diff generated scaffold Post title:string body:text
50
+
51
+ # Force regenerate Rails app by clearing cache
52
+ rails-diff generated scaffold Post --clear-cache
53
+
54
+ # Skip specific files or directories during the diff
55
+ rails-diff generated scaffold Post --skip app/views app/helpers
56
+ ```
57
+
58
+ ## How it works
59
+
60
+ When you run the diff, it will:
61
+
62
+ 1. Clone the latest Rails from main branch
63
+ 1. Generate a new Rails app with the same name as yours
64
+ 1. Show you a colored diff between your file and the generated one
65
+
66
+ ### Cache
67
+
68
+ The gem caches the generated Rails application to avoid regenerating it on every run. The cache is automatically invalidated when:
69
+ - Rails has new commits on main
70
+ - The cache directory doesn't exist
71
+
72
+ You can also force clear the cache by using the `--no-cache` option (or its alias `--clear-cache`) with any command.
73
+
74
+ ## Development
75
+
76
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
77
+
78
+ To install this gem onto your local machine, run `bundle exec rake install`.
79
+
80
+ ## Contributing
81
+
82
+ Bug reports and pull requests are welcome on GitHub at https://github.com/matheusrich/rails-diff.
83
+
84
+ ## License
85
+
86
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
data/exe/rails-diff ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift("#{__dir__}/../lib")
4
+ require "rails/diff"
5
+
6
+ Rails::Diff::CLI.start(ARGV)
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rails
4
+ module Diff
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
data/lib/rails/diff.rb ADDED
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "diff/version"
4
+ require "rails"
5
+ require "thor"
6
+ require "diffy"
7
+ require "fileutils"
8
+
9
+ module Rails
10
+ module Diff
11
+ class Error < StandardError; end
12
+
13
+ RAILS_REPO = "https://github.com/rails/rails.git"
14
+ CACHE_DIR = File.expand_path("~/.rails-diff/cache")
15
+
16
+ class << self
17
+ def file(*files, no_cache: false)
18
+ clear_cache if no_cache
19
+ ensure_template_app_exists
20
+
21
+ files.map { |file| diff_with_header(file) }.join("\n")
22
+ end
23
+
24
+ def generated(generator_name, *args, no_cache: false, skip: [])
25
+ clear_cache if no_cache
26
+ ensure_template_app_exists
27
+ install_app_dependencies
28
+
29
+ generated_files(skip)
30
+ .map { |it| diff_generated_file(it) }
31
+ .join("\n\n")
32
+ end
33
+
34
+ private
35
+
36
+ def app_name
37
+ @app_name ||= File.basename(Dir.pwd)
38
+ end
39
+
40
+ def template_app_path
41
+ @template_app_path ||= File.join(CACHE_DIR, app_name)
42
+ end
43
+
44
+ def rails_path
45
+ @rails_path ||= File.join(CACHE_DIR, "rails")
46
+ end
47
+
48
+ def clear_cache
49
+ puts "Clearing cache..."
50
+ FileUtils.rm_rf(CACHE_DIR)
51
+ end
52
+
53
+ def list_files(dir, skip = [])
54
+ Dir.glob("#{dir}/**/*", File::FNM_DOTMATCH).reject do |it|
55
+ File.directory?(it) ||
56
+ it.start_with?("#{dir}/.git") ||
57
+ it.start_with?("#{dir}/tmp") ||
58
+ it.start_with?("#{dir}/log") ||
59
+ it.start_with?("#{dir}/test") ||
60
+ skip.any? { |s| it.start_with?("#{dir}/#{s}") }
61
+ end
62
+ end
63
+
64
+ def track_new_files(skip)
65
+ files_before = list_files(template_app_path)
66
+ yield
67
+ files_after = list_files(template_app_path, skip)
68
+ files_after - files_before
69
+ end
70
+
71
+ def generated_files(skip)
72
+ command = "#{generator_name} #{args.join(' ')}"
73
+ Dir.chdir(template_app_path) do
74
+ system("bin/rails destroy #{command} >/dev/null 2>&1")
75
+ puts "Running generator: rails generate #{command}"
76
+ track_new_files(skip) { system("bin/rails generate #{command} > /dev/null 2>&1") }
77
+ end
78
+ end
79
+
80
+ def diff_with_header(file)
81
+ header = "#{file} diff:"
82
+ [
83
+ header,
84
+ "=" * header.size,
85
+ diff_file(file)
86
+ ].join("\n")
87
+ end
88
+
89
+ def diff_generated_file(file)
90
+ relative_path = file.delete_prefix("#{template_app_path}/")
91
+ [
92
+ "#{relative_path} diff:",
93
+ "=" * (10 + relative_path.length),
94
+ diff_file(relative_path)
95
+ ].join("\n")
96
+ end
97
+
98
+ def install_app_dependencies
99
+ Dir.chdir(template_app_path) do
100
+ unless system("bundle check >/dev/null 2>&1")
101
+ puts "Installing application dependencies..."
102
+ system("bundle install >/dev/null 2>&1")
103
+ end
104
+ end
105
+ end
106
+
107
+ def diff_file(file)
108
+ rails_file = File.join(template_app_path, file)
109
+ repo_file = File.join(Dir.pwd, file)
110
+
111
+ return "#{file} not found in the Rails template" unless File.exist?(rails_file)
112
+ return "#{file} not found in your repository" unless File.exist?(repo_file)
113
+
114
+ Diffy::Diff.new(
115
+ File.read(rails_file),
116
+ File.read(repo_file),
117
+ context: 2
118
+ ).to_s(:color)
119
+ end
120
+
121
+ def ensure_template_app_exists
122
+ FileUtils.mkdir_p(CACHE_DIR)
123
+
124
+ return if cached_app?
125
+
126
+ FileUtils.rm_rf(template_app_path)
127
+ create_new_rails_app
128
+ end
129
+
130
+ def cached_app?
131
+ File.exist?(template_app_path) && !rails_updated?
132
+ end
133
+
134
+ def rails_updated?
135
+ return true if !File.exist?(rails_path)
136
+
137
+ Dir.chdir(rails_path) do
138
+ system("git fetch origin main >/dev/null 2>&1")
139
+ current = `git rev-parse HEAD`.strip
140
+ latest = `git rev-parse origin/main`.strip
141
+
142
+ if current != latest
143
+ FileUtils.rm_rf(rails_path)
144
+ return true
145
+ end
146
+ end
147
+
148
+ false
149
+ end
150
+
151
+ def create_new_rails_app
152
+ unless File.exist?(rails_path)
153
+ system("git clone --depth 1 #{RAILS_REPO} #{rails_path} >/dev/null 2>&1")
154
+ end
155
+
156
+ Dir.chdir(rails_path) do
157
+ commit = `git rev-parse HEAD`.strip
158
+ puts "Using Rails edge (commit #{commit[0..6]})"
159
+
160
+ unless system("bundle check >/dev/null 2>&1")
161
+ puts "Installing Rails dependencies..."
162
+ system("bundle install >/dev/null 2>&1")
163
+ end
164
+
165
+ Dir.chdir("railties") do
166
+ puts "Generating new Rails application..."
167
+ system("bundle exec rails new #{template_app_path} --main --skip-bundle --force --skip-test --skip-system-test --quiet")
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ class CLI < Thor
174
+ class_option :no_cache, type: :boolean, desc: "Clear cache before running", aliases: ["--clear-cache"]
175
+ def self.exit_on_failure? = true
176
+
177
+ desc "file FILE [FILE ...]", "Compare one or more files from your repository with Rails' generated version"
178
+ def file(*files)
179
+ abort "Please provide at least one file to compare" if files.empty?
180
+
181
+ puts Rails::Diff.file(*files, no_cache: options[:no_cache])
182
+ end
183
+
184
+ desc "generated GENERATOR [args]", "Compare files that would be created by a Rails generator"
185
+ option :skip, type: :array, desc: "Skip specific files or directories", aliases: ["-s"], default: []
186
+ def generated(generator_name, *args)
187
+ puts Rails::Diff.generated(generator_name, *args, no_cache: options[:no_cache], skip: options[:skip])
188
+ end
189
+ end
190
+ end
191
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-diff
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Matheus Richard
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 2025-02-21 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: rails
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '7.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: diffy
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '3.4'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.4'
40
+ - !ruby/object:Gem::Dependency
41
+ name: thor
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.0'
54
+ description: rails-diff helps you compare files generated by Rails (like Dockerfile,
55
+ .gitignore, etc) with the ones in your repository, making it easier to keep track
56
+ of changes and updates.
57
+ email:
58
+ - matheusrichardt@gmail.com
59
+ executables:
60
+ - rails-diff
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".rspec"
65
+ - CHANGELOG.md
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - exe/rails-diff
70
+ - lib/rails/diff.rb
71
+ - lib/rails/diff/version.rb
72
+ homepage: https://github.com/matheusrich/rails-diff
73
+ licenses:
74
+ - MIT
75
+ metadata:
76
+ allowed_push_host: https://rubygems.org
77
+ homepage_uri: https://github.com/matheusrich/rails-diff
78
+ source_code_uri: https://github.com/matheusrich/rails-diff
79
+ changelog_uri: https://github.com/matheusrich/rails-diff/blob/main/CHANGELOG.md
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '3.2'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubygems_version: 3.6.2
95
+ specification_version: 4
96
+ summary: Compare Rails-generated files with the ones in your repository
97
+ test_files: []