Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion bin/magic_frozen_string_literal
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,19 @@
# A simple tool to prepend magic '# frozen_string_literal: true' comments to multiple ".rb" files

require_relative '../lib/add_magic_comment'
require "optparse"

AddMagicComment.process(ARGV)
process_files = false
OptionParser.new do |opts|
opts.banner = "Usage: magic_frozen_string_literal app/ lib/"

opts.on("-f", "--files", "Apply to specific files instead of files in directories") do |v|
process_files = true
end
end.parse!

if process_files
AddMagicComment.process_files_at(ARGV)
else
AddMagicComment.process(ARGV)
end
81 changes: 50 additions & 31 deletions lib/add_magic_comment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,48 +18,67 @@ module AddMagicComment
"*.gemspec" => "# #{MAGIC_COMMENT}\n\n",
"*.rabl" => "# #{MAGIC_COMMENT}\n\n",
"*.jbuilder" => "# #{MAGIC_COMMENT}\n\n",
"*.pbbuilder" => "# #{MAGIC_COMMENT}\n\n",
"*.haml" => "-# #{MAGIC_COMMENT}\n",
"*.slim" => "-# #{MAGIC_COMMENT}\n"
}

def self.process(argv)
directory = argv.first || Dir.pwd

count = 0

touched_paths = []
EXTENSION_COMMENTS.each do |pattern, comment|
filename_pattern = File.join(directory, "**", "#{pattern}")
Dir.glob(filename_pattern).each do |filename|
File.open(filename, "rb+") do |file|
lines = file.readlines
newline = detect_newline(lines.first)
next unless lines.any?
count += 1

if lines.first =~ SHEBANG_PATTERN
shebang = lines.shift
end

# remove current magic comment(s)
while lines.first && (lines.first.match(MAGIC_COMMENT_PATTERN) || lines.first.match(EMPTY_LINE_PATTERN))
lines.shift
end

# add magic comment as the first line
lines.unshift(comment.gsub("\n", newline))

# put shebang back
if shebang
lines.unshift(shebang)
end

file.pos = 0
file.print(*lines)
file.truncate(file.pos)
end
file_path_pattern = File.join(directory, "**", "#{pattern}")
Dir.glob(file_path_pattern).each do |file_path|
process_file_at(file_path, comment, touched_paths)
end
end

puts "Magic comments added to #{touched_paths.size} source file(s)"
end

def self.process_file_at(path, comment, touched_paths)
File.open(path, "rb+") do |file|
lines = file.readlines
newline = detect_newline(lines.first)
return unless lines.any?

if lines.first =~ SHEBANG_PATTERN
shebang = lines.shift
end

# remove current magic comment(s)
while lines.first && (lines.first.match(MAGIC_COMMENT_PATTERN) || lines.first.match(EMPTY_LINE_PATTERN))
lines.shift
end

# add magic comment as the first line
lines.unshift(comment.gsub("\n", newline))

# put shebang back
if shebang
lines.unshift(shebang)
end

file.pos = 0
file.print(*lines)
file.truncate(file.pos)
end
touched_paths << path
end

def self.process_files_at(paths)
touched_paths = []
paths.each do |path|
matching_pattern_and_comment = EXTENSION_COMMENTS.find do |(glob_pattern, _comment)|
File.fnmatch(glob_pattern, path)
end
_, comment = matching_pattern_and_comment
process_file_at(path, comment, touched_paths) if comment
end

puts "Magic comments added to #{count} source file(s)"
puts "Magic comments added to #{touched_paths.size} source file(s)"
end

def self.detect_newline(line)
Expand Down
20 changes: 19 additions & 1 deletion spec/acceptance_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,26 @@
}
end

it "inserts magic comments where expected", :aggregate_failures do
it "inserts magic comments across directories", :aggregate_failures do
AddMagicComment.process([directories[:test]])

Dir["#{directories[:test]}/*"].each do |path|
assert_file_matches_expected(File.basename(path))
end
end

it "inserts magic comments just into specific files", :aggregate_failures do
paths = Dir.glob(directories[:test] + "/*.rb")
AddMagicComment.process_files_at(paths)

rb_paths = Dir["#{directories[:test]}/*.rb"]
rb_paths.each do |path|
assert_file_matches_expected(File.basename(path))
end

assert_file_not_touched("Rakefile")
end

def setup_test_files
FileUtils.mkdir_p(File.dirname(directories[:test]))
FileUtils.cp_r(directories[:input], directories[:test])
Expand All @@ -31,6 +43,12 @@ def teardown_test_files
FileUtils.rm_rf(directories[:test])
end

def assert_file_not_touched(filename)
processed_path = File.join(directories[:test], filename)
expected_path = File.join(directories[:expected], filename)
expect(FileUtils).not_to be_identical(processed_path, expected_path)
end

def assert_file_matches_expected(filename)
paths = {
test: File.join(directories[:test], filename),
Expand Down
4 changes: 4 additions & 0 deletions spec/fixtures/expected/shebang_already_commented.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/ruby
# frozen_string_literal: true

puts "hello"
2 changes: 0 additions & 2 deletions spec/fixtures/input/Gemfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# frozen_string_literal: true

source 'https://rubygems.org'

gem 'magic_frozen_string_literal'
2 changes: 0 additions & 2 deletions spec/fixtures/input/Rakefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# frozen_string_literal: true

require "bundler/gem_tasks"

task :test do
Expand Down
2 changes: 0 additions & 2 deletions spec/fixtures/input/blank_line.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
# frozen_string_literal: true

puts "hello"
2 changes: 0 additions & 2 deletions spec/fixtures/input/config.ru
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# frozen_string_literal: true

# This file is used by Rack-based servers to start the application.

require_relative 'config/environment'
Expand Down
1 change: 0 additions & 1 deletion spec/fixtures/input/shebang.rb
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/ruby
# frozen_string_literal: true

puts "hello"
4 changes: 4 additions & 0 deletions spec/fixtures/input/shebang_already_commented.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/ruby
# frozen_string_literal: true

puts "hello"
1 change: 0 additions & 1 deletion spec/fixtures/input/shebang_blank_line.rb
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#!/usr/bin/ruby
# frozen_string_literal: true

puts "hello"
1 change: 0 additions & 1 deletion spec/fixtures/input/t1.haml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
-# frozen_string_literal: true
<b>Hello!</b>
2 changes: 0 additions & 2 deletions spec/fixtures/input/t1.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
# frozen_string_literal: true

puts "hello"
1 change: 0 additions & 1 deletion spec/fixtures/input/t1.slim
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
-# frozen_string_literal: true
<b>Hello!</b>
2 changes: 0 additions & 2 deletions spec/fixtures/input/utf8.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
# frozen_string_literal: true

puts " "