diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..cb23ccf4b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,6 @@ +language: ruby +rvm: + - 1.9.3 + +before_install: + - rvm @global do gem install bundler diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index a6b9ec07f..3f60694d4 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,3 +1,8 @@ +== 2.6.2 +* Retain the current annotate block unless --force is specified +* Always load models, since they may not be autoloaded by Rails +* The pg array type is now detected (see #158) + == 2.6.0.beta2 * support for composite_primary_keys (garysweaver) diff --git a/Rakefile b/Rakefile index 51048e9b4..250e7111e 100644 --- a/Rakefile +++ b/Rakefile @@ -44,8 +44,8 @@ namespace :gem do gem.license = "Ruby" gem.summary = %q{Annotates Rails Models, routes, fixtures, and others based on the database schema.} gem.description = %q{Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema.} - gem.email = ["alex@stinky.com", "ctran@pragmaquest.com", "x@nofxx.com", "turadg@aleahmad.net", "jon@cloudability.com"] - gem.authors = ["Cuong Tran", "Alex Chaffee", "Marcos Piccinini", "Turadg Aleahmad", "Jon Frisby"] + gem.email = ["alex@stinky.com", "cuong@gmail.com", "x@nofxx.com", "turadg@aleahmad.net", "jon@cloudability.com"] + gem.authors = ["Alex Chaffee", "Cuong Tran", "Marcos Piccinini", "Turadg Aleahmad", "Jon Frisby"] gem.require_paths = ["lib"] # gem.rdoc_options = ["--charset=UTF-8"] # gem.required_ruby_version = "> 1.9.2" diff --git a/annotate.gemspec b/annotate.gemspec index f13b5aa18..036149d0c 100644 --- a/annotate.gemspec +++ b/annotate.gemspec @@ -1,20 +1,18 @@ -# This file is auto-generated! -# DO NOT EDIT THIS FILE DIRECTLY! -# Instead, edit the Rakefile and run 'rake gems:gemspec'.# -*- encoding: utf-8 -*- +# -*- encoding: utf-8 -*- # stub: annotate 2.6.1 ruby lib Gem::Specification.new do |s| s.name = "annotate" - s.version = "2.6.1" + s.version = "2.6.2" s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Cuong Tran", "Alex Chaffee", "Marcos Piccinini", "Turadg Aleahmad", "Jon Frisby"] - s.date = "2013-12-21" + s.date = "2014-02-26" s.description = "Annotates Rails/ActiveRecord Models, routes, fixtures, and others based on the database schema." - s.email = ["alex@stinky.com", "ctran@pragmaquest.com", "x@nofxx.com", "turadg@aleahmad.net", "jon@cloudability.com"] + s.email = ["alex@stinky.com", "cuong.tran@gmail.com", "x@nofxx.com", "turadg@aleahmad.net", "jon@cloudability.com"] s.executables = ["annotate"] s.extra_rdoc_files = ["README.rdoc", "CHANGELOG.rdoc", "TODO.rdoc"] - s.files = ["AUTHORS.rdoc", "CHANGELOG.rdoc", "LICENSE.txt", "README.rdoc", "TODO.rdoc", "annotate.gemspec", "bin/annotate", "lib/annotate.rb", "lib/annotate/active_record_patch.rb", "lib/annotate/annotate_models.rb", "lib/annotate/annotate_routes.rb", "lib/annotate/tasks.rb", "lib/annotate/version.rb", "lib/generators/annotate/USAGE", "lib/generators/annotate/install_generator.rb", "lib/generators/annotate/templates/auto_annotate_models.rake", "lib/tasks/annotate_models.rake", "lib/tasks/annotate_routes.rake", "tasks/migrate.rake"] + s.files = ["AUTHORS.rdoc", "CHANGELOG.rdoc", "LICENSE.txt", "README.rdoc", "TODO.rdoc", "annotate.gemspec", "bin/annotate", "lib/annotate.rb", "lib/annotate/active_record_patch.rb", "lib/annotate/annotate_models.rb", "lib/annotate/annotate_routes.rb", "lib/annotate/tasks.rb", "lib/annotate/version.rb", "lib/generators/annotate/USAGE", "lib/generators/annotate/install_generator.rb", "lib/generators/annotate/templates/auto_annotate_models.rake", "lib/tasks/annotate_models.rake", "lib/tasks/annotate_routes.rake", "lib/tasks/migrate.rake"] s.homepage = "http://github.com/ctran/annotate_models" s.licenses = ["Ruby"] s.require_paths = ["lib"] diff --git a/bin/annotate b/bin/annotate index 657a22a63..2c8204bd7 100755 --- a/bin/annotate +++ b/bin/annotate @@ -119,8 +119,8 @@ OptionParser.new do |opts| end end - opts.on('-e', '--exclude [DIRS]', ['tests','fixtures','factories'], "Do not annotate fixtures, test files, and/or factories") do |exclusions| - exclusions ||= %w(tests fixtures factories) + opts.on('-e', '--exclude [tests,fixtures,factories]', Array, "Do not annotate fixtures, test files, and/or factories") do |exclusions| + exclusions ||= %w(tests fixtures factories) exclusions.each { |exclusion| ENV["exclude_#{exclusion}"] = "yes" } end diff --git a/lib/annotate/annotate_models.rb b/lib/annotate/annotate_models.rb index efaefc2bc..049dd93cc 100644 --- a/lib/annotate/annotate_models.rb +++ b/lib/annotate/annotate_models.rb @@ -31,8 +31,8 @@ module AnnotateModels FABRICATORS_SPEC_DIR = File.join("spec", "fabricators") TEST_PATTERNS = [ - [UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"], - [SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb"], + File.join(UNIT_TEST_DIR, "%MODEL_NAME%_test.rb"), + File.join(SPEC_MODEL_DIR, "%MODEL_NAME%_spec.rb"), ] FIXTURE_PATTERNS = [ @@ -131,6 +131,11 @@ def get_schema_info(klass, header, options = {}) end end + # Check out if we got an array column + if col.respond_to?(:array) && col.array + attrs << "is an Array" + end + # Check out if we got a geometric column # and print the type and SRID if col.respond_to?(:geometry_type) @@ -227,27 +232,23 @@ def annotate_one_file(file_name, info_block, position, options={}) if old_columns == new_columns && !options[:force] return false else + # Replace inline the old schema info with the new schema info + new_content = old_content.sub(PATTERN, info_block + "\n") -# todo: figure out if we need to extract any logic from this merge chunk -# <<<<<<< HEAD -# # Replace the old schema info with the new schema info -# new_content = old_content.sub(/^# #{COMPAT_PREFIX}.*?\n(#.*\n)*\n*/, info_block) -# # But, if there *was* no old schema info, we simply need to insert it -# if new_content == old_content -# old_content.sub!(encoding, '') -# new_content = options[:position] == 'after' ? -# (encoding_header + (old_content =~ /\n$/ ? old_content : old_content + "\n") + info_block) : -# (encoding_header + info_block + old_content) -# end -# ======= - - # Strip the old schema info, and insert new schema info. - old_content.sub!(encoding, '') - old_content.sub!(PATTERN, '') - - new_content = options[position].to_s == 'after' ? - (encoding_header + (old_content.rstrip + "\n\n" + info_block)) : - (encoding_header + info_block + "\n" + old_content) + if new_content.end_with? (info_block + "\n") + new_content = old_content.sub(PATTERN, "\n" + info_block) + end + + # if there *was* no old schema info (no substitution happened) or :force was passed, + # we simply need to insert it in correct position + if new_content == old_content || options[:force] + old_content.sub!(encoding, '') + old_content.sub!(PATTERN, '') + + new_content = options[position].to_s == 'after' ? + (encoding_header + (old_content.rstrip + "\n\n" + info_block)) : + (encoding_header + info_block + "\n" + old_content) + end File.open(file_name, "wb") { |f| f.puts new_content } return true @@ -301,8 +302,7 @@ def annotate(klass, file, header, options={}) unless options[:exclude_tests] did_annotate = TEST_PATTERNS. - map { |pat| [pat[0], resolve_filename(pat[1], model_name, table_name)] }. - map { |pat| find_test_file(*pat) }. + map { |file| resolve_filename(file, model_name, table_name) }. map { |file| annotate_one_file(file, info, :position_in_test, options_with_position(options, :position_in_test)) }. detect { |result| result } || did_annotate end @@ -370,7 +370,7 @@ def get_model_files(options) # in subdirectories without namespacing. def get_model_class(file) # this is for non-rails projects, which don't get Rails auto-require magic - require File.expand_path("#{model_dir}/#{file}") unless Module.const_defined?(:Rails) + require File.expand_path("#{model_dir}/#{file}") model_path = file.gsub(/\.rb$/, '') get_loaded_model(model_path) || get_loaded_model(model_path.split('/').last) end @@ -441,16 +441,7 @@ def remove_annotations(options={}) model_file_name = File.join(model_dir, file) deannotated_klass = true if(remove_annotation_of_file(model_file_name)) - TEST_PATTERNS. - map { |pat| [pat[0], resolve_filename(pat[1], model_name, table_name)]}. - map { |pat| find_test_file(*pat) }.each do |file| - if(File.exist?(file)) - remove_annotation_of_file(file) - deannotated_klass = true - end - end - - (FIXTURE_PATTERNS + FACTORY_PATTERNS). + (TEST_PATTERNS + FIXTURE_PATTERNS + FACTORY_PATTERNS). map { |file| resolve_filename(file, model_name, table_name) }. each do |file| if File.exist?(file) @@ -468,10 +459,6 @@ def remove_annotations(options={}) puts "Removed annotations from: #{deannotated.join(', ')}" end - def find_test_file(dir, file_name) - Dir.glob(File.join(dir, "**", file_name)).first || File.join(dir, file_name) - end - def resolve_filename(filename_template, model_name, table_name) return filename_template. gsub('%MODEL_NAME%', model_name). diff --git a/lib/annotate/version.rb b/lib/annotate/version.rb index 417f51d3f..11e398e7d 100644 --- a/lib/annotate/version.rb +++ b/lib/annotate/version.rb @@ -1,5 +1,5 @@ module Annotate def self.version - '2.6.1' + '2.6.2' end end diff --git a/tasks/migrate.rake b/lib/tasks/migrate.rake similarity index 100% rename from tasks/migrate.rake rename to lib/tasks/migrate.rake diff --git a/spec/annotate/annotate_models_spec.rb b/spec/annotate/annotate_models_spec.rb index c8a3b8538..f7a2c65c0 100644 --- a/spec/annotate/annotate_models_spec.rb +++ b/spec/annotate/annotate_models_spec.rb @@ -6,14 +6,14 @@ describe AnnotateModels do def mock_class(table_name, primary_key, columns) options = { - :connection => mock("Conn", :indexes => []), + :connection => double("Conn", :indexes => []), :table_name => table_name, :primary_key => primary_key, :column_names => columns.map { |col| col.name.to_s }, :columns => columns } - mock("An ActiveRecord class", options) + double("An ActiveRecord class", options) end def mock_column(name, type, options={}) @@ -27,7 +27,7 @@ def mock_column(name, type, options={}) stubs.merge!(options) stubs.merge!(:name => name, :type => type) - mock("Column", stubs) + double("Column", stubs) end it { AnnotateModels.quote(nil).should eql("NULL") } @@ -368,31 +368,67 @@ def encoding_comments_list_each ].each{|encoding_comment| yield encoding_comment } end - it "should annotate the file before the model if position == 'before'" do + it "should put annotation before class if :position == 'before'" do annotate_one_file :position => "before" File.read(@model_file_name).should == "#{@schema_info}\n#{@file_content}" end - it "should annotate before if given :position => :before" do + it "should put annotation before class if :position => :before" do annotate_one_file :position => :before File.read(@model_file_name).should == "#{@schema_info}\n#{@file_content}" end - it "should annotate after if given :position => :after" do + it "should put annotation after class if :position => :after" do annotate_one_file :position => :after File.read(@model_file_name).should == "#{@file_content}\n#{@schema_info}" end - it "should update annotate position" do - annotate_one_file :position => :before + describe "with existing annotation => :before" do + before do + annotate_one_file :position => :before + another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer),]), + "== Schema Info") + @schema_info = another_schema_info + end + + it "should retain current position" do + annotate_one_file + File.read(@model_file_name).should == "#{@schema_info}\n#{@file_content}" + end + + it "should retain current position even when :position is changed to :after" do + annotate_one_file :position => :after + File.read(@model_file_name).should == "#{@schema_info}\n#{@file_content}" + end + + it "should change position to :after when :force => true" do + annotate_one_file :position => :after, :force => true + File.read(@model_file_name).should == "#{@file_content}\n#{@schema_info}" + end + end - another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer),]), + describe "with existing annotation => :after" do + before do + annotate_one_file :position => :after + another_schema_info = AnnotateModels.get_schema_info(mock_class(:users, :id, [mock_column(:id, :integer),]), "== Schema Info") + @schema_info = another_schema_info + end - @schema_info = another_schema_info - annotate_one_file :position => :after + it "should retain current position" do + annotate_one_file + File.read(@model_file_name).should == "#{@file_content}\n#{@schema_info}" + end - File.read(@model_file_name).should == "#{@file_content}\n#{another_schema_info}" + it "should retain current position even when :position is changed to :before" do + annotate_one_file :position => :before + File.read(@model_file_name).should == "#{@file_content}\n#{@schema_info}" + end + + it "should change position to :before when :force => true" do + annotate_one_file :position => :before, :force => true + File.read(@model_file_name).should == "#{@schema_info}\n#{@file_content}" + end end it 'should skip columns with option[:ignore_columns] set' do diff --git a/spec/annotate/annotate_routes_spec.rb b/spec/annotate/annotate_routes_spec.rb index 6ee4fda82..9026aca71 100644 --- a/spec/annotate/annotate_routes_spec.rb +++ b/spec/annotate/annotate_routes_spec.rb @@ -4,7 +4,7 @@ describe AnnotateRoutes do def mock_file(stubs={}) - @mock_file ||= mock(File, stubs) + @mock_file ||= double(File, stubs) end it "should check if routes.rb exists" do diff --git a/spec/integration/integration_spec.rb b/spec/integration/integration_spec.rb index 3fc094841..6936cfee1 100644 --- a/spec/integration/integration_spec.rb +++ b/spec/integration/integration_spec.rb @@ -16,6 +16,7 @@ ENV['BUNDLE_GEMFILE'] = './Gemfile' describe "annotate inside Rails, using #{CURRENT_RUBY}" do + here = File.expand_path('..', __FILE__) chosen_scenario = nil if(!ENV['SCENARIO'].blank?) @@ -33,6 +34,8 @@ # Don't proceed if the working copy is dirty! Annotate::Integration.is_clean?(test_rig).should == true + pending "temporarily ignored until Travis can run them" + Bundler.with_clean_env do dir base_dir do temp_dir = Dir.pwd