Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for Ignoring Models with config.ignored_models #16

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,30 @@ class Document < ActiveRecord::Base

### Configuration

The annotation process can be configured via the `ActiveRecord::Annotate.configure` block which is handy to keep in the initializer.
The annotation process can be configured via the `ActiveRecord::Annotate.configure` block which is handy to keep in an initializer.

You can generate the basic initializer with a built-in generator:

```sh
$ rails generate active_record:annotate:install
```

It creates an initializer at `config/initializers/annotate.rb` which contains descriptive comments about all settings (currently just one setting, `yard`).
It creates an initializer at `config/initializers/annotate.rb` which contains descriptive comments about each setting.

```ruby
require 'active_record/annotate'

if defined?(ActiveRecord::Annotate)
ActiveRecord::Annotate.configure do |config|
# # set this to true to wrap annotations in triple backticks (```)
# # so YARD documentation can process the annotation as a code block
# config.yard = false
#
# # Define any models to be skipped by Annotate
# config.ignored_models = [SomeIgnoredModel, AnotherIgnoredModel]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see a potential problem here: AFAIK rails runs initializers before loading the application code so referring to the model classes as constants here will either fail or autoload them, possibly before other initializers are fired (and this doesn't sound good to me).

What if instead of class constants themselves we will use their names as strings? Like %w[SomeIgnoredModel AnotherIgnoredModel]. What do you think?

end
end
```

## Changelog

Expand Down
32 changes: 18 additions & 14 deletions lib/active_record/annotate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,70 +9,74 @@ 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|
puts " * #{model}"
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?

next if configurator.ignored_models.includes?(klass)

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

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to add empty lines only before public/protected/private keywords, not after them; please don't change it.

def models_dir
Rails.root.join('app/models')
end

def configurator
@configurator ||= Configurator.new
end

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This empy line is redundant.

end
end
end
16 changes: 14 additions & 2 deletions lib/active_record/annotate/configurator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,27 @@ class Configurator
attr_accessor setting
alias_method "#{setting}?", setting
end


attr_accessor :ignored_models
def ignored_models=(models)
if models.is_a?(Array)
@ignored_models = models
else
raise "ActiveRecord::Annotate.config.ignored_models must be an Array of model classes"
end
end

def initialize
reset
end

private

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here.

def reset
@yard = false
@ignored_models = []
end

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here.

end
end
end
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
require 'active_record/annotate'

ActiveRecord::Annotate.configure do |config|
# set this to true to wrap annotations in triple backticks (```)
# so YARD documentation can process the annotation as a code block
# config.yard = false
end if ActiveRecord.const_defined?(:Annotate)
if defined?(ActiveRecord::Annotate)
ActiveRecord::Annotate.configure do |config|
# # set this to true to wrap annotations in triple backticks (```)
# # so YARD documentation can process the annotation as a code block
# config.yard = false
#
# # Define any models to be skipped by Annotate
# config.ignored_models = [SomeIgnoredModel, AnotherIgnoredModel]
end
end
11 changes: 11 additions & 0 deletions spec/active_record/annotate/configurator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
describe "#initialize" do
it "resets all settings to their default values" do
expect(subject.yard).to be_falsy
expect(subject.ignored_models).to eq([])
end
end

Expand All @@ -13,6 +14,16 @@

subject.yard = true
expect(subject.yard).to be_truthy

expect(subject.ignored_models).to eq([])

subject.ignored_models = [:foobar]
subject.ignored_models.push(:bar)
expect(subject.ignored_models).to eq([:foobar, :bar])

expect {
subject.ignored_models = "bad value"
}.to raise_exception(StandardError)
end
end
end
12 changes: 12 additions & 0 deletions spec/active_record/annotate/file_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,18 @@ class User < ActiveRecord::Base
# t.integer :age, null: false, default: 0
# end

class User < ActiveRecord::Base
has_many :posts
end
FILE
end

let(:expected_ignored_result) do
<<-FILE
# enCoding: utf-8
# frozen_string_literal: true
# warn_indent: true

class User < ActiveRecord::Base
has_many :posts
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the expected result here as the ignored file will not be touched at all - the gem won't erase the old annotation. This is what should be expected.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But since this is a wrong place to test ignored_models you can just delete this.

Expand Down
4 changes: 4 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@
require 'active_record/annotate'
require 'pry'
require 'awesome_print'

class User < ActiveRecord::Base
### Define User constant
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this being used anywhere?