module ModelBuilder TMP_VIEW_PATH = File.expand_path(File.join(TESTAPP_ROOT, 'tmp', 'views')).freeze def self.included(example_group) example_group.class_eval do before do @created_tables ||= [] end after do teardown_defined_constants end end end def create_table(table_name, options = {}, &block) connection = ActiveRecord::Base.connection begin connection.execute("DROP TABLE IF EXISTS #{table_name}") connection.create_table(table_name, options, &block) @created_tables << table_name connection rescue Exception => e connection.execute("DROP TABLE IF EXISTS #{table_name}") raise e end end def define_constant(class_name, base = Object, &block) class_name = class_name.to_s.camelize Class.new(base).tap do |constant_class| Object.const_set(class_name, constant_class) constant_class.unloadable if block_given? constant_class.class_eval(&block) end if constant_class.respond_to?(:reset_column_information) constant_class.reset_column_information end end end def define_model_class(class_name, &block) define_constant(class_name, ActiveRecord::Base, &block) end def define_active_model_class(class_name, options = {}, &block) define_constant(class_name, Object) do include ActiveModel::Validations options[:accessors].each do |column| attr_accessor column.to_sym end if block_given? class_eval(&block) end end end def define_model(name, columns = {}, &block) class_name = name.to_s.pluralize.classify table_name = class_name.tableize create_table(table_name) do |table| columns.each do |name, type| table.column name, type end end define_model_class(class_name, &block) end def define_mailer(name, paths, &block) class_name = name.to_s.pluralize.classify define_constant(class_name, ActionMailer::Base, &block) end def define_controller(class_name, &block) class_name = class_name.to_s class_name << 'Controller' unless class_name =~ /Controller$/ define_constant(class_name, ActionController::Base, &block) end def define_routes(&block) Rails.application.routes.draw(&block) @routes = Rails.application.routes class << self include ActionDispatch::Assertions end end def build_response(opts = {}, &block) action = opts[:action] || 'example' partial = opts[:partial] || '_partial' klass = define_controller('Examples') block ||= lambda { render :nothing => true } klass.class_eval { layout false; define_method(action, &block) } define_routes do match 'examples', :to => "examples##{action}" end create_view("examples/#{action}.html.erb", "abc") create_view("examples/#{partial}.html.erb", "partial") klass.view_paths = [TMP_VIEW_PATH] @controller = klass.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new @controller.send :assign_shortcuts, @request, @response @controller.send :initialize_template_class, @response class << self include ActionController::TestCase::Behavior end @routes = Rails.application.routes get action @controller end def create_view(path, contents) full_path = File.join(TMP_VIEW_PATH, path) FileUtils.mkdir_p(File.dirname(full_path)) File.open(full_path, 'w') { |file| file.write(contents) } end def teardown_defined_constants ActiveSupport::Dependencies.clear connection = ActiveRecord::Base.connection @created_tables.each do |table_name| connection.execute("DROP TABLE IF EXISTS #{table_name}") end FileUtils.rm_rf(TMP_VIEW_PATH) Rails.application.reload_routes! end end RSpec.configure do |config| config.include ModelBuilder end