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

Ignore non active record subclasses #50

Merged
124 changes: 124 additions & 0 deletions lib/active_mocker/file_writer.rb
@@ -0,0 +1,124 @@
module ActiveMocker
class FileWriter
include Virtus.model
delegate :name, to: :model, prefix: true

attribute :model, Object
attribute :file, String
attribute :display_errors
attribute :config
attribute :model_names, Array

def write!
assure_dir_path_exists!

safe_write { |f| process!(f) }
end

private

def process!(file_out)
result = create_mock(file_out)
status = collect_errors(result.errors)

ok = result.completed? && status.successful?
return unless ok

display_errors.success_count += 1
end

def safe_write
File.open(mock_file_path, "w") do |file_out|
begin
yield file_out
rescue StandardError => e
rescue_clean_up(e, file_out)
end
end
end

def rescue_clean_up(e, file_out)
display_errors.failed_models << model_name
file_out.close unless file_out.closed?
File.delete(file_out.path) if File.exist?(file_out.path)
display_errors.wrap_an_exception(e, model_name)
end

def scrapper
@scrapper ||= ActiveRecordSchemaScrapper.new(model: model)
end

def mock_file_path
File.join(Config.mock_dir, mock_file_name)
end

def mock_file_name
"#{model_name.underscore}_#{config.mock_append_name.underscore}.rb"
end

def assure_dir_path_exists!
unless File.exist?(File.dirname(mock_file_path))
FileUtils.mkdir_p(File.dirname(mock_file_path))
end
end

def create_mock(file_out)
MockCreator.new(file: File.open(file),
file_out: file_out,
schema_scrapper: scrapper,
klasses_to_be_mocked: model_names,
enabled_partials: enabled_partials,
mock_append_name: config.mock_append_name).create
end

OtherErrors = Struct.new(:successful?)

def collect_errors(create_mock_errors)
add_errors!

if create_mock_errors.present? || schema.attribute_errors?
display_errors.failed_models << model_name
File.delete(mock_file_path) if File.exist?(mock_file_path)
display_errors.add(create_mock_errors)
OtherErrors.new(false)
else
OtherErrors.new(true)
end
end

def add_errors!
add_error(schema.association_errors, :associations)
add_error(schema.attribute_errors, :attributes)
end

def add_error(error, type)
display_errors.wrap_errors(error, model_name, type: type)
end

def enabled_partials
if config.disable_modules_and_constants
MockCreator.enabled_partials_default - [*:modules_constants]
else
MockCreator.enabled_partials_default
end
end

Copy link
Collaborator

Choose a reason for hiding this comment

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

Extra empty line detected at module body end.

def schema
@schema ||= Schema.new(ActiveRecordSchemaScrapper.new(model: model))
end

class Schema < SimpleDelegator
def attribute_errors?
attribute_errors.any? { |e| e.level == :error }
end

def association_errors
associations.errors
end

def attribute_errors
attributes.errors
end
end
end
end
123 changes: 55 additions & 68 deletions lib/active_mocker/generate.rb
@@ -1,101 +1,96 @@
# frozen_string_literal: true
require_relative "file_writer"

module ActiveMocker
class Generate
def initialize
raise ArgumentError, "mock_dir is missing a valued value!" if config.mock_dir.nil? || config.mock_dir.empty?
check_directory!(:mock_dir)
create_mock_dir
raise ArgumentError, "model_dir is missing a valued value!" if config.model_dir.nil? || config.model_dir.empty? || !Dir.exist?(config.model_dir)
check_directory!(:model_dir)
raise_missing_arg(:model_dir) unless Dir.exist?(config.model_dir)

@display_errors = DisplayErrors.new(models_paths.count)
end

# @return self
def call
clean_up
progress_init
models_paths.each do |file|
model_name = model_name(file)
model = get_model_const(model_name)
mock_file_name = "#{model_name.underscore}_#{config.mock_append_name.underscore}.rb"
mock_file_path = File.join(Config.mock_dir, mock_file_name)
assure_dir_path_exists(mock_file_path)
schema_scrapper = ActiveRecordSchemaScrapper.new(model: model)
File.open(mock_file_path, "w") do |file_out|
begin
result = create_mock(file, file_out, schema_scrapper)
status = collect_errors(mock_file_path, result.errors, schema_scrapper, model_name)
display_errors.success_count += 1 if result.completed? && status.successful?
rescue => e
rescue_clean_up(e, file_out, model_name)
end
end

active_record_models_with_files.each do |model, file|
write_file(model, file)

progress.increment
end

display_errors.display_errors
self
end

def get_model_const(model_name)
model_name.constantize
rescue StandardError, LoadError => e
display_errors.wrap_an_exception(e, model_name)
def active_record_models
@active_record_models ||= active_record_models_with_files.map(&:first)
end

private

attr_reader :display_errors

def create_mock(file, file_out, schema_scrapper)
MockCreator.new(file: File.open(file),
file_out: file_out,
schema_scrapper: schema_scrapper,
klasses_to_be_mocked: model_names,
enabled_partials: enabled_partials,
mock_append_name: config.mock_append_name).create
end

OtherErrors = Struct.new(:successful?)
def collect_errors(mock_file_path, create_mock_errors, schema_scrapper, model_name)
display_errors.wrap_errors(schema_scrapper.associations.errors, model_name, type: :associations)
display_errors.wrap_errors(schema_scrapper.attributes.errors, model_name, type: :attributes)
if create_mock_errors.present? || schema_scrapper.attributes.errors.any? { |e| e.level == :error }
display_errors.failed_models << model_name
File.delete(mock_file_path) if File.exist?(mock_file_path)
display_errors.add(create_mock_errors)
OtherErrors.new(false)
else
OtherErrors.new(true)
attr_reader :display_errors, :progress

def check_directory!(type)
value = config.send(type)

if value.nil? || value.empty?
raise_missing_arg(type)
end
end

def rescue_clean_up(e, file_out, model_name)
display_errors.failed_models << model_name
file_out.close unless file_out.closed?
File.delete(file_out.path) if File.exist?(file_out.path)
display_errors.wrap_an_exception(e, model_name)
def raise_missing_arg(type)
raise ArgumentError, "#{type} is missing a valued value!"
end

def model_name(file)
FilePathToRubyClass.new(base_path: config.model_dir, class_path: file).to_s
def write_file(model, file)
writer = FileWriter.new(
model: model,
file: file,
display_errors: display_errors,
config: config,
model_names: model_names)

writer.write!
end

def model_names
@model_names ||= models_paths.map { |p| model_name(p) }
def progress_init
@progress = config.progress_class.create(active_record_models.count)
end

attr_reader :progress
def model_names
@model_names ||= active_record_models.map(&:name)
end

def progress_init
@progress = config.progress_class.create(models_paths.count)
def active_record_models_with_files
@active_record_models_with_files ||= models_paths.map do |file|
model = constant_from(model_name_from(file))
[model, file] if model
end.compact
end

def models_paths
@models_paths ||= Dir.glob(config.single_model_path || File.join(config.model_dir, "**/*.rb"))
end

def assure_dir_path_exists(file)
unless File.exist?(File.dirname(file))
FileUtils.mkdir_p(File.dirname(file))
end
def constant_from(model_name)
constant = model_name.constantize
return unless constant.ancestors.include?(ActiveRecord::Base)
constant
rescue NameError, LoadError => e
display_errors.wrap_an_exception(e, model_name)
nil
end

def model_name_from(file)
FilePathToRubyClass.new(
base_path: config.model_dir,
class_path: file
).to_s
end

def config
Expand All @@ -106,14 +101,6 @@ def create_mock_dir
FileUtils.mkdir_p(config.mock_dir) unless Dir.exist?(config.mock_dir)
end

def enabled_partials
if config.disable_modules_and_constants
MockCreator.enabled_partials_default - [*:modules_constants]
else
MockCreator.enabled_partials_default
end
end

def clean_up
delete_mocks unless config.single_model_path
end
Expand Down
35 changes: 29 additions & 6 deletions spec/lib/active_mocker/generate_spec.rb
Expand Up @@ -4,15 +4,18 @@

RSpec.describe ActiveMocker::Generate do
describe ".new" do
let(:not_found_dir) { File.join(File.expand_path("../test_mock_dir", __FILE__)) }
let(:not_found_dir) { File.expand_path("../test_mock_dir", __FILE__) }

before do
ActiveMocker::Config.set do |config|
config.model_dir = File.join(File.expand_path("../", __FILE__))
config.model_dir = File.expand_path("../", __FILE__)
config.mock_dir = not_found_dir
config.error_verbosity = 0
config.progress_bar = false
end
stub_const("ActiveRecord::Base", class_double("ActiveRecord::Base"))
stub_const("Model", class_double("Model", ancestors: [ActiveRecord::Base]))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Line is too long. [81/80]

stub_const("SomeNamespace::SomeModule", class_double("SomeNamespace::SomeModule", ancestors: [Module]))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Line is too long. [109/80]

end

before do
Expand Down Expand Up @@ -68,10 +71,9 @@
context "when old mock exist" do
let(:current_mock_path) { File.join(not_found_dir, "model_mock.rb") }
let(:old_mock_path) { File.join(not_found_dir, "old_mock_from_deleted_model_mock.rb") }
let(:models_dir) { File.join(File.expand_path("../../", __FILE__), "models") }
let(:models_dir) { File.expand_path("../../models", __FILE__) }

before do
stub_const("ActiveRecord::Base", class_double("ActiveRecord::Base"))
FileUtils.mkdir_p(not_found_dir)
File.open(old_mock_path, "w") { |w| w.write "" }
File.open(current_mock_path, "w") { |w| w.write "" }
Expand All @@ -93,11 +95,31 @@
end
end

describe "#active_record_models" do
let(:models_dir) { File.expand_path("../../models", __FILE__) }

before do
ActiveMocker::Config.model_dir = models_dir
end

context "with some non ActiveRecord subclasses" do
before do
stub_const("NonActiveRecordModel", class_double("NonActiveRecordModel", ancestors: [Object]))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Line is too long. [103/80]

end

it "ignores non ActiveRecord subclasses" do
result = described_class.new.call
expect(result.active_record_models).to eq [Model]
end
end
end

describe "ActiveMocker::Config.disable_modules_and_constants" do
before do
ActiveMocker::Config.disable_modules_and_constants = set_to
ActiveMocker::Config.progress_bar = false
ActiveMocker::Config.single_model_path = File.join(File.expand_path("../../", __FILE__), "models/model.rb")
ActiveMocker::Config.model_dir = File.expand_path("../../models", __FILE__)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Line is too long. [103/80]

ActiveMocker::Config.single_model_path = File.expand_path("../../models/model.rb", __FILE__)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Line is too long. [112/80]

end

context "when true" do
Expand All @@ -122,7 +144,8 @@
describe "ActiveMocker::Config.mock_append_name" do
before do
ActiveMocker::Config.progress_bar = false
ActiveMocker::Config.single_model_path = File.join(File.expand_path("../../models", __FILE__), "model.rb")
ActiveMocker::Config.model_dir = File.expand_path("../../models", __FILE__)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Line is too long. [91/80]

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Seems like this bot is still set to complain at 80 characters

Copy link
Owner

Choose a reason for hiding this comment

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

Just merged in your RuboCop config

Copy link
Collaborator

Choose a reason for hiding this comment

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

Line is too long. [91/80]

ActiveMocker::Config.single_model_path = File.expand_path("../../models/model.rb", __FILE__)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Line is too long. [100/80]

end

context "defaults" do
Expand Down
2 changes: 2 additions & 0 deletions spec/lib/models/non_active_record_model.rb
@@ -0,0 +1,2 @@
class NonActiveRecordModel
end
7 changes: 7 additions & 0 deletions spec/lib/models/some_namespace/some_module.rb
@@ -0,0 +1,7 @@
module SomeNamespace
module SomeModule
def some_method
"some return value"
end
end
end
2 changes: 1 addition & 1 deletion test_rails_4_app/gemfiles/rails_4.0.gemfile.lock
Expand Up @@ -162,13 +162,13 @@ GEM
rspec-mocks (~> 3.4.0)
rspec-support (~> 3.4.0)
rspec-support (3.4.0)
ruby-progressbar (1.8.0)
rubocop (0.38.0)
parser (>= 2.3.0.6, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.8.0)
sprockets (3.4.0)
rack (> 1, < 3)
sprockets-rails (2.3.3)
Expand Down