Commit 69cd69cb by Jon Frisby

Add configurable for routes position, ability to remove routes, fix handling of…

Add configurable for routes position, ability to remove routes, fix handling of output from newer Rake versions.
parent 22b97fa6
...@@ -6,6 +6,10 @@ ...@@ -6,6 +6,10 @@
* Bugfix: Load the Rakefile from the current directory, not the first Rakefile * Bugfix: Load the Rakefile from the current directory, not the first Rakefile
in our load path. in our load path.
* Added support for new FactoryGirl naming convention. * Added support for new FactoryGirl naming convention.
* Fix behavior of route annotations in newer versions of Rake that don't spit
out the CWD as their first line of output.
* Routes can now be appended, pre-pended, or removed -- and do sane things in
all cases.
* Expose all `position_*` variables as CLI params. * Expose all `position_*` variables as CLI params.
* Make `ENV ['position']` work as a default for all the `ENV ['position_*']` * Make `ENV ['position']` work as a default for all the `ENV ['position_*']`
variables. variables.
......
...@@ -112,6 +112,8 @@ anywhere in the file: ...@@ -112,6 +112,8 @@ anywhere in the file:
Place the annotations at the top (before) or the bottom (after) of any fixture files Place the annotations at the top (before) or the bottom (after) of any fixture files
--pt, --position-in-test [before|after] --pt, --position-in-test [before|after]
Place the annotations at the top (before) or the bottom (after) of any test files Place the annotations at the top (before) or the bottom (after) of any test files
--pr, --position-in-routes [before|after]
Place the annotations at the top (before) or the bottom (after) of the routes.rb file
-r, --routes Annotate routes.rb with the output of 'rake routes' -r, --routes Annotate routes.rb with the output of 'rake routes'
-v, --version Show the current version of this gem -v, --version Show the current version of this gem
-m, --show-migration Include the migration version number in the annotation -m, --show-migration Include the migration version number in the annotation
......
...@@ -25,16 +25,20 @@ OptionParser.new do |opts| ...@@ -25,16 +25,20 @@ OptionParser.new do |opts|
opts.banner = "Usage: annotate [options] [model_file]*" opts.banner = "Usage: annotate [options] [model_file]*"
opts.on('-d', '--delete', opts.on('-d', '--delete',
"Remove annotations from all model files") do "Remove annotations from all model files or the routes.rb file") do
if(task == :annotate_routes)
task = :remove_routes
else
task = :remove_annotation task = :remove_annotation
end end
end
ENV['position'] = 'before' # hack: make sure default position is "before" ENV['position'] = 'before' # hack: make sure default position is "before"
opts.on('-p', '--position [before|after]', ['before', 'after'], opts.on('-p', '--position [before|after]', ['before', 'after'],
"Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory file(s)") do |p| "Place the annotations at the top (before) or the bottom (after) of the model/test/fixture/factory file(s)") do |p|
ENV['position'] = p ENV['position'] = p
[ [
'position_in_class','position_in_factory','position_in_fixture','position_in_test' 'position_in_class','position_in_factory','position_in_fixture','position_in_test', 'position_in_routes'
].each do |key| ].each do |key|
ENV[key] = p unless(has_set_position[key]) ENV[key] = p unless(has_set_position[key])
end end
...@@ -64,6 +68,12 @@ OptionParser.new do |opts| ...@@ -64,6 +68,12 @@ OptionParser.new do |opts|
has_set_position['position_in_test'] = true has_set_position['position_in_test'] = true
end end
opts.on('--pr', '--position-in-routes [before|after]', ['before', 'after'],
"Place the annotations at the top (before) or the bottom (after) of the routes.rb file") do |p|
ENV['position_in_test'] = p
has_set_position['position_in_routes'] = true
end
opts.on('-r', '--routes', opts.on('-r', '--routes',
"Annotate routes.rb with the output of 'rake routes'") do "Annotate routes.rb with the output of 'rake routes'") do
task = :annotate_routes task = :annotate_routes
......
...@@ -18,25 +18,130 @@ ...@@ -18,25 +18,130 @@
# Released under the same license as Ruby. No Support. No Warranty. # Released under the same license as Ruby. No Support. No Warranty.
# #
module AnnotateRoutes module AnnotateRoutes
PREFIX = "#== Route Map" PREFIX = "# == Route Map"
def self.do_annotate def self.do_annotate(options={})
routes_rb = File.join("config", "routes.rb") return unless(routes_exists?)
header = PREFIX + "\n# Generated on #{Time.now.strftime("%d %b %Y %H:%M")}\n#"
if File.exists? routes_rb position_after = options[:position_in_routes] != 'before'
routes_map = `rake routes`
routes_map = routes_map.split("\n") routes_map = `rake routes`.split(/\n/, -1)
routes_map.shift # remove the first line of rake routes which is just a file path
routes_map = routes_map.inject(header){|sum, line| sum<<"\n# "<<line} # In old versions of Rake, the first line of output was the cwd. Not so
content = File.read(routes_rb) # much in newer ones. We ditch that line if it exists, and if not, we
content, old = content.split(/^#== Route .*?\n/) # keep the line around.
File.open(routes_rb, "wb") do |f| routes_map.shift if(routes_map.first =~ /^\(in \//)
f.puts content.sub!(/\n?\z/, "\n") + routes_map
header = [
"#{PREFIX} (Updated #{Time.now.strftime("%Y-%m-%d %H:%M")})",
"#"
] + routes_map.map { |line| "# #{line}".rstrip }
(content, where_header_found) = strip_annotations(File.read(routes_file))
changed = where_header_found != 0 # This will either be :before, :after, or
# a number. If the number is > 0, the
# annotation was found somewhere in the
# middle of the file. If the number is
# zero, no annotation was found.
if(position_after)
# Ensure we have adequate trailing newlines at the end of the file to
# ensure a blank line separating the content from the annotation.
content << '' if(content.last != '')
# We're moving something from the top of the file to the bottom, so ditch
# the spacer we put in the first time around.
if(changed && where_header_found == :before)
content.shift if(content.first == '')
end
else
header = header << '' if(content.first != '' || changed)
end end
content = position_after ? (content + header) : header + content
write_contents(content)
puts "Route file annotated." puts "Route file annotated."
end
def self.remove_annotations(options={})
return unless(routes_exists?)
(content, where_header_found) = strip_annotations(File.read(routes_file))
content = strip_on_removal(content, where_header_found)
write_contents(content)
puts "Removed annotations from routes file."
end
protected
def self.routes_file
@routes_rb ||= File.join("config", "routes.rb")
end
def self.routes_exists?
routes_exists = File.exists?(routes_file)
puts "Can`t find routes.rb" if(!routes_exists)
return routes_exists
end
def self.write_contents(content)
content << '' unless(content.last == '') # Make sure we end on a trailing
# newline.
File.open(routes_file, "wb") { |f| f.puts(content.join("\n")) }
end
def self.strip_annotations(content)
real_content = []
mode = :content
line_number = 0
header_found_at = 0
content.split(/\n/, -1).each do |line|
line_number += 1
begin
if(mode == :header)
if(line !~ /\s*#/)
mode = :content
raise unless (line == '')
end
elsif(mode == :content)
if(line =~ /^\s*#\s*== Route.*$/)
header_found_at = line_number
mode = :header
else else
puts "Can`t find routes.rb" real_content << line
end
end end
rescue
retry
end end
end
content_lines = real_content.count
# By default assume the annotation was found in the middle of the file...
where_header_found = header_found_at
# ... unless we have evidence it was at the beginning ...
where_header_found = :before if(header_found_at == 1)
# ... or that it was at the end.
where_header_found = :after if(header_found_at >= content_lines)
return real_content, where_header_found
end
def self.strip_on_removal(content, where_header_found)
if(where_header_found == :before)
content.shift while(content.first == '')
elsif(where_header_found == :after)
content.pop while(content.last == '')
end
# TODO: If the user buried it in the middle, we should probably see about
# TODO: preserving a single line of space between the content above and
# TODO: below...
return content
end
end end
desc "Prepends the route map to the top of routes.rb" desc "Adds the route map to routes.rb"
task :annotate_routes => :environment do task :annotate_routes => :environment do
annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__))) annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__)))
require "#{annotate_lib}/annotate/annotate_routes" require "#{annotate_lib}/annotate/annotate_routes"
AnnotateRoutes.do_annotate
options={}
options[:position_in_routes] = ENV['position_in_routes'] || ENV['position'] || 'after'
AnnotateRoutes.do_annotate(options)
end
desc "Removes the route map from routes.rb"
task :remove_routes => :environment do
annotate_lib = File.expand_path(File.dirname(File.dirname(__FILE__)))
require "#{annotate_lib}/annotate/annotate_routes"
options={}
AnnotateRoutes.remove_annotations(options)
end end
...@@ -7,15 +7,13 @@ describe AnnotateRoutes do ...@@ -7,15 +7,13 @@ describe AnnotateRoutes do
@mock_file ||= mock(File, stubs) @mock_file ||= mock(File, stubs)
end end
describe "Annotate Job" do
it "should check if routes.rb exists" do it "should check if routes.rb exists" do
File.should_receive(:exists?).with("config/routes.rb").and_return(false) File.should_receive(:exists?).with("config/routes.rb").and_return(false)
AnnotateRoutes.should_receive(:puts).with("Can`t find routes.rb") AnnotateRoutes.should_receive(:puts).with("Can`t find routes.rb")
AnnotateRoutes.do_annotate AnnotateRoutes.do_annotate
end end
describe "When Annotating" do describe "When Annotating, with older Rake Versions" do
before(:each) do before(:each) do
File.should_receive(:exists?).with("config/routes.rb").and_return(true) File.should_receive(:exists?).with("config/routes.rb").and_return(true)
...@@ -26,18 +24,61 @@ describe AnnotateRoutes do ...@@ -26,18 +24,61 @@ describe AnnotateRoutes do
it "should annotate and add a newline!" do it "should annotate and add a newline!" do
File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo") File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo")
@mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n#== Route Map\n# Generated on .*\n#\n# good line/) @mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# good line\n/)
AnnotateRoutes.do_annotate
end
it "should not add a newline if there are empty lines" do
File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n")
@mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# good line\n/)
AnnotateRoutes.do_annotate
end
end
describe "When Annotating, with newer Rake Versions" do
before(:each) do
File.should_receive(:exists?).with("config/routes.rb").and_return(true)
AnnotateRoutes.should_receive(:`).with("rake routes").and_return("another good line\ngood line")
File.should_receive(:open).with("config/routes.rb", "wb").and_yield(mock_file)
AnnotateRoutes.should_receive(:puts).with("Route file annotated.")
end
it "should annotate and add a newline!" do
File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo")
@mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# another good line\n# good line\n/)
AnnotateRoutes.do_annotate AnnotateRoutes.do_annotate
end end
it "should not add a newline if there are empty lines" do it "should not add a newline if there are empty lines" do
File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n") File.should_receive(:read).with("config/routes.rb").and_return("ActionController::Routing...\nfoo\n")
@mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n#== Route Map\n# Generated on .*\n#\n# good line/) @mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n# == Route Map \(Updated \d{4}-\d{2}-\d{2} \d{2}:\d{2}\)\n#\n# another good line\n# good line\n/)
AnnotateRoutes.do_annotate AnnotateRoutes.do_annotate
end end
end end
describe "When Removing Annotation" do
before(:each) do
File.should_receive(:exists?).with("config/routes.rb").and_return(true)
File.should_receive(:open).with("config/routes.rb", "wb").and_yield(mock_file)
AnnotateRoutes.should_receive(:puts).with("Removed annotations from routes file.")
end
it "should remove trailing annotation and trim trailing newlines, but leave leading newlines alone" do
File.should_receive(:read).with("config/routes.rb").and_return("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n# == Route Map (Updated 2012-08-16 00:00)\n#\n# another good line\n# good line\n")
@mock_file.should_receive(:puts).with(/\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n/)
AnnotateRoutes.remove_annotations
end
it "should remove prepended annotation and trim leading newlines, but leave trailing newlines alone" do
File.should_receive(:read).with("config/routes.rb").and_return("# == Route Map (Updated 2012-08-16 00:00)\n#\n# another good line\n# good line\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n")
@mock_file.should_receive(:puts).with(/ActionController::Routing...\nfoo\n\n\n\n\n\n\n\n\n\n\n/)
AnnotateRoutes.remove_annotations
end
end end
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment