1
0
Fork 0
mirror of https://github.com/thoughtbot/shoulda-matchers.git synced 2022-11-09 12:01:38 -05:00

Fix define_class/model to support namespaces

You can now say `define_class('Models::User')` and it will define a User
class inside of the Models module.

Similarly, you can also say `define_model('Models::User')` and it will
set the table name of the model to `models_users` instead of just
`users`.
This commit is contained in:
Elliot Winkler 2014-10-07 23:19:07 -06:00
parent ec71c24281
commit 72e2b3411e
4 changed files with 47 additions and 18 deletions

View file

@ -3,6 +3,7 @@ require 'shoulda/matchers/doublespeak'
require 'shoulda/matchers/error'
require 'shoulda/matchers/matcher_context'
require 'shoulda/matchers/rails_shim'
require 'shoulda/matchers/util'
require 'shoulda/matchers/version'
require 'shoulda/matchers/warn'

View file

@ -0,0 +1,15 @@
module Shoulda
module Matchers
# @private
module Util
def self.deconstantize(path)
if defined?(ActiveSupport::Inflector) &&
ActiveSupport::Inflector.respond_to?(:deconstantize)
ActiveSupport::Inflector.deconstantize(path)
else
path.to_s[0...(path.to_s.rindex('::') || 0)]
end
end
end
end
end

View file

@ -7,31 +7,37 @@ module ClassBuilder
end
end
def define_class(class_name, base = Object, &block)
def self.parse_constant_name(name)
namespace = Shoulda::Matchers::Util.deconstantize(name)
qualified_namespace = (namespace.presence || 'Object').constantize
name_without_namespace = name.to_s.demodulize
[qualified_namespace, name_without_namespace]
end
def define_class(class_name, parent_class = Object, &block)
class_name = class_name.to_s.camelize
if Object.const_defined?(class_name)
Object.__send__(:remove_const, class_name)
namespace, name_without_namespace =
ClassBuilder.parse_constant_name(class_name)
if namespace.const_defined?(name_without_namespace, false)
namespace.__send__(:remove_const, name_without_namespace)
end
# FIXME: ActionMailer 3.2 calls `name.underscore` immediately upon
# subclassing. Class.new.name == nil. So, Class.new(ActionMailer::Base)
# errors out since it's trying to do `nil.underscore`. This is very ugly but
# allows us to test against ActionMailer 3.2.x.
eval <<-A_REAL_CLASS_FOR_ACTION_MAILER_3_2
class ::#{class_name} < #{base}
end
A_REAL_CLASS_FOR_ACTION_MAILER_3_2
eval <<-RUBY
class #{namespace}::#{name_without_namespace} < #{parent_class}
end
RUBY
Object.const_get(class_name).tap do |constant_class|
constant_class.unloadable
namespace.const_get(name_without_namespace).tap do |constant|
constant.unloadable
if block_given?
constant_class.class_eval(&block)
constant.class_eval(&block)
end
if constant_class.respond_to?(:reset_column_information)
constant_class.reset_column_information
if constant.respond_to?(:reset_column_information)
constant.reset_column_information
end
end
end

View file

@ -46,7 +46,8 @@ module ModelBuilder
def define_model(name, columns = {}, &block)
class_name = name.to_s.pluralize.classify
table_name = class_name.tableize
table_name = class_name.tableize.gsub('/', '_')
table_block = lambda do |table|
columns.each do |name, specification|
if specification.is_a?(Hash)
@ -64,7 +65,13 @@ module ModelBuilder
create_table(table_name, &table_block)
end
define_model_class(class_name, &block)
define_model_class(class_name).tap do |model|
if block
model.class_eval(&block)
end
model.table_name = table_name
end
end
def drop_created_tables