From cea8a7099601e560d9c7b8c9d4263f4166336f90 Mon Sep 17 00:00:00 2001 From: Alexander Belozerov Date: Wed, 18 Oct 2017 19:19:35 +0600 Subject: [PATCH] Do not remove magic comments (AnnotateRoutes) --- lib/annotate/annotate_routes.rb | 33 ++++- spec/annotate/annotate_routes_spec.rb | 168 ++++++++++++++++++++++---- 2 files changed, 177 insertions(+), 24 deletions(-) diff --git a/lib/annotate/annotate_routes.rb b/lib/annotate/annotate_routes.rb index fbae767d5..e04960113 100644 --- a/lib/annotate/annotate_routes.rb +++ b/lib/annotate/annotate_routes.rb @@ -38,7 +38,13 @@ def content(line, maxs, options = {}) def header(options = {}) routes_map = app_routes_map(options) + magic_comments_map, routes_map = extract_magic_comments_from_array(routes_map) out = [] + + magic_comments_map.each do |magic_comment| + out << magic_comment + end + out += ["# #{options[:wrapper_open]}"] if options[:wrapper_open] out += ["# #{options[:format_markdown] ? PREFIX_MD : PREFIX}" + (options[:timestamp] ? " (Updated #{Time.now.strftime('%Y-%m-%d %H:%M')})" : '')] @@ -82,6 +88,28 @@ def remove_annotations(_options={}) end end + def self.magic_comment_matcher + Regexp.new(/(^#\s*encoding:.*)|(^# coding:.*)|(^# -\*- coding:.*)|(^# -\*- encoding\s?:.*)|(^#\s*frozen_string_literal:.+)|(^# -\*- frozen_string_literal\s*:.+-\*-)/) + end + + # @param [Array] content + # @return [Array] all found magic comments + # @return [Array] content without magic comments + def self.extract_magic_comments_from_array(content_array) + magic_comments = [] + new_content = [] + + content_array.map do |row| + if row =~ magic_comment_matcher + magic_comments << row.strip + else + new_content << row + end + end + + [magic_comments, new_content] + end + def self.app_routes_map(options) routes_map = `rake routes`.chomp("\n").split(/\n/, -1) @@ -143,9 +171,10 @@ def self.rewrite_contents_with_header(existing_text, header, options = {}) end def self.annotate_routes(header, content, where_header_found, options = {}) + magic_comments_map, content = extract_magic_comments_from_array(content) if %w(before top).include?(options[:position_in_routes]) header = header << '' if content.first != '' - new_content = header + content + new_content = magic_comments_map + header + content else # Ensure we have adequate trailing newlines at the end of the file to # ensure a blank line separating the content from the annotation. @@ -155,7 +184,7 @@ def self.annotate_routes(header, content, where_header_found, options = {}) # the spacer we put in the first time around. content.shift if where_header_found == :before && content.first == '' - new_content = content + header + new_content = magic_comments_map + content + header end new_content diff --git a/spec/annotate/annotate_routes_spec.rb b/spec/annotate/annotate_routes_spec.rb index 719d2fe4b..005f1ff70 100644 --- a/spec/annotate/annotate_routes_spec.rb +++ b/spec/annotate/annotate_routes_spec.rb @@ -11,6 +11,22 @@ def mock_file(stubs = {}) @mock_file ||= double(File, stubs) end + def magic_comments_list_each + [ + '# encoding: UTF-8', + '# coding: UTF-8', + '# -*- coding: UTF-8 -*-', + '#encoding: utf-8', + '# encoding: utf-8', + '# -*- encoding : utf-8 -*-', + "# encoding: utf-8\n# frozen_string_literal: true", + "# frozen_string_literal: true\n# encoding: utf-8", + '# frozen_string_literal: true', + '#frozen_string_literal: false', + '# -*- frozen_string_literal : true -*-' + ].each { |magic_comment| yield magic_comment } + end + it 'should check if routes.rb exists' do expect(File).to receive(:exists?).with(ROUTE_FILE).and_return(false) expect(AnnotateRoutes).to receive(:puts).with("Can't find routes.rb") @@ -18,21 +34,29 @@ def mock_file(stubs = {}) end describe 'Annotate#example' do - before(:each) do - expect(File).to receive(:exists?).with(ROUTE_FILE).and_return(true) - - expect(File).to receive(:read).with(ROUTE_FILE).and_return("") - expect(AnnotateRoutes).to receive(:`).with('rake routes').and_return(" Prefix Verb URI Pattern Controller#Action + let(:rake_routes_content) do + " Prefix Verb URI Pattern Controller#Action myaction1 GET /url1(.:format) mycontroller1#action myaction2 POST /url2(.:format) mycontroller2#action - myaction3 DELETE|GET /url3(.:format) mycontroller3#action\n") + myaction3 DELETE|GET /url3(.:format) mycontroller3#action\n" + end - expect(AnnotateRoutes).to receive(:puts).with(ANNOTATION_ADDED) + before(:each) do + expect(File).to receive(:exists?).with(ROUTE_FILE).and_return(true).at_least(:once) + + expect(File).to receive(:read).with(ROUTE_FILE).and_return("").at_least(:once) + + expect(AnnotateRoutes).to receive(:puts).with(ANNOTATION_ADDED).at_least(:once) end - it 'annotate normal' do - expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) - expect(@mock_file).to receive(:puts).with(" + context 'without magic comments' do + before(:each) do + expect(AnnotateRoutes).to receive(:`).with('rake routes').and_return(rake_routes_content) + end + + it 'annotate normal' do + expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) + expect(@mock_file).to receive(:puts).with(" # == Route Map # # Prefix Verb URI Pattern Controller#Action @@ -40,12 +64,12 @@ def mock_file(stubs = {}) # myaction2 POST /url2(.:format) mycontroller2#action # myaction3 DELETE|GET /url3(.:format) mycontroller3#action\n") - AnnotateRoutes.do_annotations - end + AnnotateRoutes.do_annotations + end - it 'annotate markdown' do - expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) - expect(@mock_file).to receive(:puts).with(" + it 'annotate markdown' do + expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) + expect(@mock_file).to receive(:puts).with(" # ## Route Map # # Prefix | Verb | URI Pattern | Controller#Action @@ -54,12 +78,72 @@ def mock_file(stubs = {}) # myaction2 | POST | /url2(.:format) | mycontroller2#action # myaction3 | DELETE-GET | /url3(.:format) | mycontroller3#action\n") - AnnotateRoutes.do_annotations(format_markdown: true) + AnnotateRoutes.do_annotations(format_markdown: true) + end + + it 'wraps annotation if wrapper is specified' do + expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) + expect(@mock_file).to receive(:puts).with(" +# START +# == Route Map +# +# Prefix Verb URI Pattern Controller#Action +# myaction1 GET /url1(.:format) mycontroller1#action +# myaction2 POST /url2(.:format) mycontroller2#action +# myaction3 DELETE|GET /url3(.:format) mycontroller3#action +# END\n") + + AnnotateRoutes.do_annotations(wrapper_open: 'START', wrapper_close: 'END') + end end - it 'wraps annotation if wrapper is specified' do - expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) - expect(@mock_file).to receive(:puts).with(" + context 'file with magic comments' do + it 'should not remove magic comments' do + magic_comments_list_each do |magic_comment| + expect(AnnotateRoutes).to receive(:`).with('rake routes') + .and_return("#{magic_comment}\n#{rake_routes_content}") + + expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) + expect(@mock_file).to receive(:puts).with(" +#{magic_comment} +# == Route Map +# +# Prefix Verb URI Pattern Controller#Action +# myaction1 GET /url1(.:format) mycontroller1#action +# myaction2 POST /url2(.:format) mycontroller2#action +# myaction3 DELETE|GET /url3(.:format) mycontroller3#action\n") + + AnnotateRoutes.do_annotations + end + end + + it 'annotate markdown' do + magic_comments_list_each do |magic_comment| + expect(AnnotateRoutes).to receive(:`).with('rake routes') + .and_return("#{magic_comment}\n#{rake_routes_content}") + + expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) + expect(@mock_file).to receive(:puts).with(" +#{magic_comment} +# ## Route Map +# +# Prefix | Verb | URI Pattern | Controller#Action +# --------- | ---------- | --------------- | -------------------- +# myaction1 | GET | /url1(.:format) | mycontroller1#action +# myaction2 | POST | /url2(.:format) | mycontroller2#action +# myaction3 | DELETE-GET | /url3(.:format) | mycontroller3#action\n") + + AnnotateRoutes.do_annotations(format_markdown: true) + end + end + + it 'wraps annotation if wrapper is specified' do + magic_comments_list_each do |magic_comment| + expect(AnnotateRoutes).to receive(:`).with('rake routes') + .and_return("#{magic_comment}\n#{rake_routes_content}") + expect(File).to receive(:open).with(ROUTE_FILE, 'wb').and_yield(mock_file) + expect(@mock_file).to receive(:puts).with(" +#{magic_comment} # START # == Route Map # @@ -69,14 +153,18 @@ def mock_file(stubs = {}) # myaction3 DELETE|GET /url3(.:format) mycontroller3#action # END\n") - AnnotateRoutes.do_annotations(wrapper_open: 'START', wrapper_close: 'END') + AnnotateRoutes.do_annotations(wrapper_open: 'START', wrapper_close: 'END') + end + end end end describe 'When adding' do before(:each) do - expect(File).to receive(:exists?).with(ROUTE_FILE).and_return(true) - expect(AnnotateRoutes).to receive(:`).with('rake routes').and_return('') + expect(File).to receive(:exists?).with(ROUTE_FILE) + .and_return(true).at_least(:once) + expect(AnnotateRoutes).to receive(:`).with('rake routes') + .and_return('').at_least(:once) end it 'should insert annotations if file does not contain annotations' do @@ -112,6 +200,42 @@ def mock_file(stubs = {}) AnnotateRoutes.do_annotations end + + context 'file with magic comments' do + it 'leaves magic comment on top, adds an empty line between magic comment and annotation (position_in_routes :top)' do + expect(File).to receive(:open).with(ROUTE_FILE, 'wb') + .and_yield(mock_file).at_least(:once) + + magic_comments_list_each do |magic_comment| + expect(File).to receive(:read).with(ROUTE_FILE).and_return("#{magic_comment}\nSomething") + expect(@mock_file).to receive(:puts).with("#{magic_comment}\n# == Route Map\n#\n\nSomething\n") + expect(AnnotateRoutes).to receive(:puts).with(ANNOTATION_ADDED) + AnnotateRoutes.do_annotations(position_in_routes: 'top') + end + end + + it 'leaves magic comment on top, adds an empty line between magic comment and annotation (position_in_routes :bottom)' do + expect(File).to receive(:open).with(ROUTE_FILE, 'wb') + .and_yield(mock_file).at_least(:once) + + magic_comments_list_each do |magic_comment| + expect(File).to receive(:read).with(ROUTE_FILE).and_return("#{magic_comment}\nSomething") + expect(@mock_file).to receive(:puts).with("#{magic_comment}\nSomething\n\n# == Route Map\n#\n") + expect(AnnotateRoutes).to receive(:puts).with(ANNOTATION_ADDED) + AnnotateRoutes.do_annotations(position_in_routes: 'bottom') + end + end + + it 'skips annotations if file does already contain annotation' do + magic_comments_list_each do |magic_comment| + expect(File).to receive(:read).with(ROUTE_FILE) + .and_return("#{magic_comment}\n\n# == Route Map\n#\n") + expect(AnnotateRoutes).to receive(:puts).with(FILE_UNCHANGED) + + AnnotateRoutes.do_annotations + end + end + end end describe 'When adding with older Rake versions' do