diff --git a/lib/active_record/annotate.rb b/lib/active_record/annotate.rb index 623513c..d3a9fa9 100644 --- a/lib/active_record/annotate.rb +++ b/lib/active_record/annotate.rb @@ -9,21 +9,21 @@ module Annotate class << self def annotate processed_models = [] - + models.each do |table_name, file_paths_and_classes| annotation = Dumper.dump(table_name) - + file_paths_and_classes.each do |path, klass| file = File.new(path) file.annotate_with(annotation.dup, configurator) - + if file.changed? file.write processed_models << "#{klass} (#{file.relative_path})" end end end - + unless processed_models.empty? puts 'Annotated models:' processed_models.each do |model| @@ -31,45 +31,45 @@ def annotate end end end - + def models files_mask = models_dir.join('**', '*.rb') - + hash_with_arrays = Hash.new do |hash, key| hash[key] = [] end - + Dir.glob(files_mask).each_with_object(hash_with_arrays) do |path, models| short_path = short_path_for(path) next if short_path.starts_with?('concerns') # skip any app/models/concerns files - + klass = class_name_for(short_path) next unless klass < ActiveRecord::Base # collect only AR::Base descendants next if klass.respond_to?(:abstract_class?) && klass.abstract_class? - + models[klass.table_name] << [path, klass] end end - + # .../app/models/car/hatchback.rb -> car/hatchback def short_path_for(full_path) full_path.sub(models_dir.to_s + '/', '').sub(/\.rb$/, '') end - + # car/hatchback -> Car::Hatchback def class_name_for(short_path) short_path.camelize.constantize end - + def configure(&block) configurator.tap(&block) end - + private def models_dir Rails.root.join('app/models') end - + def configurator @configurator ||= Configurator.new end diff --git a/lib/active_record/annotate/configurator.rb b/lib/active_record/annotate/configurator.rb index 295198c..a267f1e 100644 --- a/lib/active_record/annotate/configurator.rb +++ b/lib/active_record/annotate/configurator.rb @@ -1,18 +1,22 @@ module ActiveRecord module Annotate class Configurator - %w(yard).each do |setting| + BOOLEAN_ATTRIBUTES = %w(yard debug) + + BOOLEAN_ATTRIBUTES.each do |setting| attr_accessor setting alias_method "#{setting}?", setting end - + def initialize reset end - + private def reset - @yard = false + BOOLEAN_ATTRIBUTES.each do |attr| + instance_variable_set("@#{attr}", false) + end end end end diff --git a/lib/active_record/annotate/file.rb b/lib/active_record/annotate/file.rb index 48ac2d2..27c3682 100644 --- a/lib/active_record/annotate/file.rb +++ b/lib/active_record/annotate/file.rb @@ -2,15 +2,16 @@ module ActiveRecord module Annotate class File attr_reader :path, :lines - + def initialize(path) @path = path @content = ::File.read(path) @lines = @content.split(?\n) end - + def annotate_with(annotation, configurator) magic_comments = [] + while @lines.first =~ /^\s*#.*(coding|frozen_string_literal|warn_indent)/i magic_comments.push(@lines.shift) end @@ -19,39 +20,46 @@ def annotate_with(annotation, configurator) # separate magic comments from the annotation with an empty line magic_comments << nil end - + while @lines.first.start_with?('#') || @lines.first.blank? # throw out comments and empty lines # in the beginning of the file (old annotation) @lines.shift end - - if configurator.yard? - backticks = '# ```' - annotation.unshift(backticks).push(backticks) + + if annotation.first.start_with?("# create_table") + if configurator.yard? + backticks = '# ```' + annotation.unshift(backticks).push(backticks) + end + + @lines.unshift(*annotation, nil) + elsif configurator.debug + ### If debugging enabled print errors, Else squelch the error + puts annotation end - - @lines.unshift(*annotation, nil) + @lines.unshift(*magic_comments) + @lines.push(nil) # newline at the end of file end - + def write new_file_content = @lines.join(?\n) temp_path = "#{@path}.annotated" - + ::File.open(temp_path, 'w') do |temp_file| temp_file.write(new_file_content) end - + ::File.delete(@path) ::File.rename(temp_path, @path) end - + def changed? @lines.join(?\n) != @content end - + def relative_path path.sub(/^#{Rails.root}\//, '') end diff --git a/spec/active_record/annotate/configurator_spec.rb b/spec/active_record/annotate/configurator_spec.rb index 09c1d77..df630e2 100644 --- a/spec/active_record/annotate/configurator_spec.rb +++ b/spec/active_record/annotate/configurator_spec.rb @@ -4,6 +4,7 @@ describe "#initialize" do it "resets all settings to their default values" do expect(subject.yard).to be_falsy + expect(subject.debug).to be_falsy end end @@ -13,6 +14,11 @@ subject.yard = true expect(subject.yard).to be_truthy + + expect(subject.debug).to be_falsy + + subject.debug = true + expect(subject.debug).to be_truthy end end end diff --git a/spec/active_record/annotate/file_spec.rb b/spec/active_record/annotate/file_spec.rb index 7cfba27..13975a5 100644 --- a/spec/active_record/annotate/file_spec.rb +++ b/spec/active_record/annotate/file_spec.rb @@ -78,7 +78,11 @@ class User < ActiveRecord::Base end let(:file) { ActiveRecord::Annotate::File.new(file_path) } - let(:configurator) { ActiveRecord::Annotate::Configurator.new } + let(:configurator) { + c = ActiveRecord::Annotate::Configurator.new + c.debug = true + c + } describe "#annotate_with" do it "changes the lines adding the new annotation" do @@ -149,4 +153,19 @@ class User < ActiveRecord::Base expect(file.relative_path).to eq('namespace/path.rb') end end + + describe "Annotation Errors" do + it "Removes Old Annotation" do + file.annotate_with(["error"], configurator) + expect(file).to be_changed + + file.write + new_file = ActiveRecord::Annotate::File.new(file.path) + + ### Doesnt add new annotation to non-annotated file + new_file.annotate_with(["error"], configurator) + expect(new_file).not_to be_changed + end + end + end