2006-07-08 14:14:49 -04:00
|
|
|
require File.dirname(__FILE__) + '/abstract_unit'
|
2006-08-29 02:52:39 -04:00
|
|
|
require 'pp'
|
2004-12-29 16:03:21 -05:00
|
|
|
|
2006-08-16 13:50:52 -04:00
|
|
|
module ModuleWithMissing
|
|
|
|
mattr_accessor :missing_count
|
|
|
|
def self.const_missing(name)
|
|
|
|
self.missing_count += 1
|
|
|
|
name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2004-12-29 16:03:21 -05:00
|
|
|
class DependenciesTest < Test::Unit::TestCase
|
|
|
|
def teardown
|
|
|
|
Dependencies.clear
|
|
|
|
end
|
2006-07-08 14:14:49 -04:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
def with_loading(*from)
|
2006-03-27 00:13:46 -05:00
|
|
|
old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load
|
2006-08-08 17:21:04 -04:00
|
|
|
dir = File.dirname(__FILE__)
|
2006-08-29 02:52:39 -04:00
|
|
|
prior_load_paths = Dependencies.load_paths
|
|
|
|
Dependencies.load_paths = from.collect { |f| "#{dir}/#{f}" }
|
2006-03-27 00:13:46 -05:00
|
|
|
yield
|
|
|
|
ensure
|
2006-08-29 02:52:39 -04:00
|
|
|
Dependencies.load_paths = prior_load_paths
|
2006-03-27 00:13:46 -05:00
|
|
|
Dependencies.mechanism = old_mechanism
|
2006-10-15 19:32:31 -04:00
|
|
|
Dependencies.explicitly_unloadable_constants = []
|
2006-03-27 00:13:46 -05:00
|
|
|
end
|
2004-12-29 16:03:21 -05:00
|
|
|
|
2005-11-23 16:31:51 -05:00
|
|
|
def test_tracking_loaded_files
|
2005-02-15 10:02:43 -05:00
|
|
|
require_dependency(File.dirname(__FILE__) + "/dependencies/service_one")
|
|
|
|
require_dependency(File.dirname(__FILE__) + "/dependencies/service_two")
|
2004-12-29 16:03:21 -05:00
|
|
|
assert_equal 2, Dependencies.loaded.size
|
|
|
|
end
|
2005-11-23 16:31:51 -05:00
|
|
|
|
|
|
|
def test_tracking_identical_loaded_files
|
2005-02-15 10:02:43 -05:00
|
|
|
require_dependency(File.dirname(__FILE__) + "/dependencies/service_one")
|
|
|
|
require_dependency(File.dirname(__FILE__) + "/dependencies/service_one")
|
2004-12-29 16:03:21 -05:00
|
|
|
assert_equal 1, Dependencies.loaded.size
|
|
|
|
end
|
|
|
|
|
2005-11-23 16:31:51 -05:00
|
|
|
def test_missing_dependency_raises_missing_source_file
|
2005-11-06 20:48:33 -05:00
|
|
|
assert_raises(MissingSourceFile) { require_dependency("missing_service") }
|
2004-12-29 16:03:21 -05:00
|
|
|
end
|
2005-11-23 16:31:51 -05:00
|
|
|
|
|
|
|
def test_missing_association_raises_nothing
|
2004-12-29 16:03:21 -05:00
|
|
|
assert_nothing_raised { require_association("missing_model") }
|
|
|
|
end
|
2005-11-23 16:31:51 -05:00
|
|
|
|
|
|
|
def test_dependency_which_raises_exception_isnt_added_to_loaded_set
|
2006-03-27 00:13:46 -05:00
|
|
|
with_loading do
|
|
|
|
filename = "#{File.dirname(__FILE__)}/dependencies/raises_exception"
|
|
|
|
$raises_exception_load_count = 0
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
5.times do |count|
|
2006-11-06 14:23:30 -05:00
|
|
|
begin
|
|
|
|
require_dependency filename
|
|
|
|
flunk 'should have loaded dependencies/raises_exception which raises an exception'
|
|
|
|
rescue Exception => e
|
|
|
|
assert_equal 'Loading me failed, so do not add to loaded or history.', e.message
|
|
|
|
end
|
2006-03-27 00:13:46 -05:00
|
|
|
assert_equal count + 1, $raises_exception_load_count
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
assert !Dependencies.loaded.include?(filename)
|
|
|
|
assert !Dependencies.history.include?(filename)
|
|
|
|
end
|
2005-11-23 16:31:51 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_warnings_should_be_enabled_on_first_load
|
2006-08-16 16:33:31 -04:00
|
|
|
with_loading 'dependencies' do
|
2006-03-27 00:13:46 -05:00
|
|
|
old_warnings, Dependencies.warnings_on_first_load = Dependencies.warnings_on_first_load, true
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-08-16 16:33:31 -04:00
|
|
|
filename = "check_warnings"
|
|
|
|
expanded = File.expand_path("test/dependencies/#{filename}")
|
2006-03-27 00:13:46 -05:00
|
|
|
$check_warnings_load_count = 0
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-08-08 18:08:09 -04:00
|
|
|
assert !Dependencies.loaded.include?(expanded)
|
|
|
|
assert !Dependencies.history.include?(expanded)
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
silence_warnings { require_dependency filename }
|
|
|
|
assert_equal 1, $check_warnings_load_count
|
|
|
|
assert_equal true, $checked_verbose, 'On first load warnings should be enabled.'
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-08-08 18:08:09 -04:00
|
|
|
assert Dependencies.loaded.include?(expanded)
|
2006-03-27 00:13:46 -05:00
|
|
|
Dependencies.clear
|
2006-08-08 18:08:09 -04:00
|
|
|
assert !Dependencies.loaded.include?(expanded)
|
|
|
|
assert Dependencies.history.include?(expanded)
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
silence_warnings { require_dependency filename }
|
|
|
|
assert_equal 2, $check_warnings_load_count
|
|
|
|
assert_equal nil, $checked_verbose, 'After first load warnings should be left alone.'
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-08-08 18:08:09 -04:00
|
|
|
assert Dependencies.loaded.include?(expanded)
|
2006-03-27 00:13:46 -05:00
|
|
|
Dependencies.clear
|
2006-08-08 18:08:09 -04:00
|
|
|
assert !Dependencies.loaded.include?(expanded)
|
|
|
|
assert Dependencies.history.include?(expanded)
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
enable_warnings { require_dependency filename }
|
|
|
|
assert_equal 3, $check_warnings_load_count
|
|
|
|
assert_equal true, $checked_verbose, 'After first load warnings should be left alone.'
|
2005-11-23 16:31:51 -05:00
|
|
|
|
2006-08-08 18:08:09 -04:00
|
|
|
assert Dependencies.loaded.include?(expanded)
|
2006-03-27 00:13:46 -05:00
|
|
|
end
|
2005-11-23 16:31:51 -05:00
|
|
|
end
|
2005-11-24 00:43:27 -05:00
|
|
|
|
|
|
|
def test_mutual_dependencies_dont_infinite_loop
|
2006-03-27 00:13:46 -05:00
|
|
|
with_loading 'dependencies' do
|
|
|
|
$mutual_dependencies_count = 0
|
|
|
|
assert_nothing_raised { require_dependency 'mutual_one' }
|
|
|
|
assert_equal 2, $mutual_dependencies_count
|
2005-11-24 00:43:27 -05:00
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
Dependencies.clear
|
2005-11-24 00:43:27 -05:00
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
$mutual_dependencies_count = 0
|
|
|
|
assert_nothing_raised { require_dependency 'mutual_two' }
|
|
|
|
assert_equal 2, $mutual_dependencies_count
|
|
|
|
end
|
2005-11-24 00:43:27 -05:00
|
|
|
end
|
2006-07-08 14:14:49 -04:00
|
|
|
|
2006-01-28 19:37:39 -05:00
|
|
|
def test_as_load_path
|
|
|
|
assert_equal '', DependenciesTest.as_load_path
|
|
|
|
end
|
2006-07-08 14:14:49 -04:00
|
|
|
|
2006-01-28 19:37:39 -05:00
|
|
|
def test_module_loading
|
2006-03-27 00:13:46 -05:00
|
|
|
with_loading 'autoloading_fixtures' do
|
2006-02-04 16:24:40 -05:00
|
|
|
assert_kind_of Module, A
|
|
|
|
assert_kind_of Class, A::B
|
|
|
|
assert_kind_of Class, A::C::D
|
|
|
|
assert_kind_of Class, A::C::E::F
|
|
|
|
end
|
|
|
|
end
|
2006-07-08 14:14:49 -04:00
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
def test_non_existing_const_raises_name_error
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert_raises(NameError) { DoesNotExist }
|
|
|
|
assert_raises(NameError) { NoModule::DoesNotExist }
|
|
|
|
assert_raises(NameError) { A::DoesNotExist }
|
|
|
|
assert_raises(NameError) { A::B::DoesNotExist }
|
2006-02-04 16:24:40 -05:00
|
|
|
end
|
2006-01-28 19:37:39 -05:00
|
|
|
end
|
2006-07-08 14:14:49 -04:00
|
|
|
|
2006-08-16 05:18:17 -04:00
|
|
|
def test_directories_manifest_as_modules_unless_const_defined
|
2006-03-27 00:13:46 -05:00
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert_kind_of Module, ModuleFolder
|
|
|
|
Object.send :remove_const, :ModuleFolder
|
|
|
|
end
|
|
|
|
end
|
2006-07-08 14:14:49 -04:00
|
|
|
|
2006-08-16 05:18:17 -04:00
|
|
|
def test_module_with_nested_class
|
2006-03-27 00:13:46 -05:00
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert_kind_of Class, ModuleFolder::NestedClass
|
|
|
|
Object.send :remove_const, :ModuleFolder
|
|
|
|
end
|
|
|
|
end
|
2006-07-08 14:14:49 -04:00
|
|
|
|
2006-08-16 05:18:17 -04:00
|
|
|
def test_module_with_nested_inline_class
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert_kind_of Class, ModuleFolder::InlineClass
|
|
|
|
Object.send :remove_const, :ModuleFolder
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_directories_may_manifest_as_nested_classes
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert_kind_of Class, ClassFolder
|
|
|
|
Object.send :remove_const, :ClassFolder
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_class_with_nested_class
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert_kind_of Class, ClassFolder::NestedClass
|
|
|
|
Object.send :remove_const, :ClassFolder
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_class_with_nested_inline_class
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert_kind_of Class, ClassFolder::InlineClass
|
|
|
|
Object.send :remove_const, :ClassFolder
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-11-16 17:50:46 -05:00
|
|
|
def test_class_with_nested_inline_subclass_of_parent
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert_kind_of Class, ClassFolder::ClassFolderSubclass
|
|
|
|
assert_kind_of Class, ClassFolder
|
|
|
|
assert_equal 'indeed', ClassFolder::ClassFolderSubclass::ConstantInClassFolder
|
|
|
|
Object.send :remove_const, :ClassFolder
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
def test_nested_class_can_access_sibling
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
sibling = ModuleFolder::NestedClass.class_eval "NestedSibling"
|
|
|
|
assert defined?(ModuleFolder::NestedSibling)
|
|
|
|
assert_equal ModuleFolder::NestedSibling, sibling
|
|
|
|
Object.send :remove_const, :ModuleFolder
|
|
|
|
end
|
|
|
|
end
|
2006-07-08 14:14:49 -04:00
|
|
|
|
2006-03-27 00:13:46 -05:00
|
|
|
def failing_test_access_thru_and_upwards_fails
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert ! defined?(ModuleFolder)
|
|
|
|
assert_raises(NameError) { ModuleFolder::Object }
|
|
|
|
assert_raises(NameError) { ModuleFolder::NestedClass::Object }
|
|
|
|
Object.send :remove_const, :ModuleFolder
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-05 18:52:15 -04:00
|
|
|
def test_non_existing_const_raises_name_error_with_fully_qualified_name
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
begin
|
2006-08-08 17:21:04 -04:00
|
|
|
A::DoesNotExist.nil?
|
2006-08-05 18:52:15 -04:00
|
|
|
flunk "No raise!!"
|
|
|
|
rescue NameError => e
|
|
|
|
assert_equal "uninitialized constant A::DoesNotExist", e.message
|
|
|
|
end
|
|
|
|
begin
|
2006-08-08 17:21:04 -04:00
|
|
|
A::B::DoesNotExist.nil?
|
2006-08-05 18:52:15 -04:00
|
|
|
flunk "No raise!!"
|
|
|
|
rescue NameError => e
|
|
|
|
assert_equal "uninitialized constant A::B::DoesNotExist", e.message
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-05 18:52:15 -04:00
|
|
|
def test_smart_name_error_strings
|
|
|
|
begin
|
|
|
|
Object.module_eval "ImaginaryObject"
|
|
|
|
flunk "No raise!!"
|
|
|
|
rescue NameError => e
|
|
|
|
assert e.message.include?("uninitialized constant ImaginaryObject")
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-29 02:52:39 -04:00
|
|
|
def test_loadable_constants_for_path_should_handle_empty_autoloads
|
|
|
|
assert_equal [], Dependencies.loadable_constants_for_path('hello')
|
2006-08-08 17:21:04 -04:00
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-29 02:52:39 -04:00
|
|
|
def test_loadable_constants_for_path_should_handle_relative_paths
|
2006-08-08 17:21:04 -04:00
|
|
|
fake_root = 'dependencies'
|
|
|
|
relative_root = File.dirname(__FILE__) + '/dependencies'
|
|
|
|
['', '/'].each do |suffix|
|
|
|
|
with_loading fake_root + suffix do
|
2006-08-29 02:52:39 -04:00
|
|
|
assert_equal ["A::B"], Dependencies.loadable_constants_for_path(relative_root + '/a/b')
|
2006-08-08 17:21:04 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-29 02:52:39 -04:00
|
|
|
def test_loadable_constants_for_path_should_provide_all_results
|
2006-08-08 17:21:04 -04:00
|
|
|
fake_root = '/usr/apps/backpack'
|
|
|
|
with_loading fake_root, fake_root + '/lib' do
|
2006-08-29 02:52:39 -04:00
|
|
|
root = Dependencies.load_paths.first
|
|
|
|
assert_equal ["Lib::A::B", "A::B"], Dependencies.loadable_constants_for_path(root + '/lib/a/b')
|
2006-08-08 17:21:04 -04:00
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-29 02:52:39 -04:00
|
|
|
def test_loadable_constants_for_path_should_uniq_results
|
2006-08-08 17:21:04 -04:00
|
|
|
fake_root = '/usr/apps/backpack/lib'
|
|
|
|
with_loading fake_root, fake_root + '/' do
|
2006-08-29 02:52:39 -04:00
|
|
|
root = Dependencies.load_paths.first
|
|
|
|
assert_equal ["A::B"], Dependencies.loadable_constants_for_path(root + '/a/b')
|
2006-08-08 17:21:04 -04:00
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-09-06 16:31:28 -04:00
|
|
|
def test_loadable_constants_with_load_path_without_trailing_slash
|
|
|
|
path = File.dirname(__FILE__) + '/autoloading_fixtures/class_folder/inline_class.rb'
|
|
|
|
with_loading 'autoloading_fixtures/class/' do
|
|
|
|
assert_equal [], Dependencies.loadable_constants_for_path(path)
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
def test_qualified_const_defined
|
|
|
|
assert Dependencies.qualified_const_defined?("Object")
|
|
|
|
assert Dependencies.qualified_const_defined?("::Object")
|
|
|
|
assert Dependencies.qualified_const_defined?("::Object::Kernel")
|
|
|
|
assert Dependencies.qualified_const_defined?("::Object::Dependencies")
|
|
|
|
assert Dependencies.qualified_const_defined?("::Test::Unit::TestCase")
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-16 13:50:52 -04:00
|
|
|
def test_qualified_const_defined_should_not_call_method_missing
|
|
|
|
ModuleWithMissing.missing_count = 0
|
|
|
|
assert ! Dependencies.qualified_const_defined?("ModuleWithMissing::A")
|
|
|
|
assert_equal 0, ModuleWithMissing.missing_count
|
|
|
|
assert ! Dependencies.qualified_const_defined?("ModuleWithMissing::A::B")
|
|
|
|
assert_equal 0, ModuleWithMissing.missing_count
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
def test_autoloaded?
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert ! Dependencies.autoloaded?("ModuleFolder")
|
|
|
|
assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
assert Dependencies.autoloaded?(ModuleFolder)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
assert Dependencies.autoloaded?("ModuleFolder")
|
|
|
|
assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
assert Dependencies.autoloaded?(ModuleFolder::NestedClass)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
assert Dependencies.autoloaded?("ModuleFolder")
|
|
|
|
assert Dependencies.autoloaded?("ModuleFolder::NestedClass")
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
assert Dependencies.autoloaded?("::ModuleFolder")
|
|
|
|
assert Dependencies.autoloaded?(:ModuleFolder)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
Object.send :remove_const, :ModuleFolder
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
def test_qualified_name_for
|
|
|
|
assert_equal "A", Dependencies.qualified_name_for(Object, :A)
|
|
|
|
assert_equal "A", Dependencies.qualified_name_for(:Object, :A)
|
|
|
|
assert_equal "A", Dependencies.qualified_name_for("Object", :A)
|
|
|
|
assert_equal "A", Dependencies.qualified_name_for("::Object", :A)
|
|
|
|
assert_equal "A", Dependencies.qualified_name_for("::Kernel", :A)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
assert_equal "Dependencies::A", Dependencies.qualified_name_for(:Dependencies, :A)
|
|
|
|
assert_equal "Dependencies::A", Dependencies.qualified_name_for(Dependencies, :A)
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
def test_file_search
|
|
|
|
with_loading 'dependencies' do
|
2006-08-29 02:52:39 -04:00
|
|
|
root = Dependencies.load_paths.first
|
|
|
|
assert_equal nil, Dependencies.search_for_file('service_three')
|
|
|
|
assert_equal nil, Dependencies.search_for_file('service_three.rb')
|
|
|
|
assert_equal root + '/service_one.rb', Dependencies.search_for_file('service_one')
|
|
|
|
assert_equal root + '/service_one.rb', Dependencies.search_for_file('service_one.rb')
|
2006-08-08 17:21:04 -04:00
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-29 02:52:39 -04:00
|
|
|
def test_file_search_uses_first_in_load_path
|
2006-08-08 17:21:04 -04:00
|
|
|
with_loading 'dependencies', 'autoloading_fixtures' do
|
2006-08-29 02:52:39 -04:00
|
|
|
deps, autoload = Dependencies.load_paths
|
2006-08-08 17:21:04 -04:00
|
|
|
assert_match %r/dependencies/, deps
|
|
|
|
assert_match %r/autoloading_fixtures/, autoload
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-29 02:52:39 -04:00
|
|
|
assert_equal deps + '/conflict.rb', Dependencies.search_for_file('conflict')
|
2006-08-08 17:21:04 -04:00
|
|
|
end
|
|
|
|
with_loading 'autoloading_fixtures', 'dependencies' do
|
2006-08-29 02:52:39 -04:00
|
|
|
autoload, deps = Dependencies.load_paths
|
2006-08-08 17:21:04 -04:00
|
|
|
assert_match %r/dependencies/, deps
|
|
|
|
assert_match %r/autoloading_fixtures/, autoload
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-29 02:52:39 -04:00
|
|
|
assert_equal autoload + '/conflict.rb', Dependencies.search_for_file('conflict')
|
2006-08-08 17:21:04 -04:00
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
def test_custom_const_missing_should_work
|
|
|
|
Object.module_eval <<-end_eval
|
|
|
|
module ModuleWithCustomConstMissing
|
|
|
|
def self.const_missing(name)
|
|
|
|
const_set name, name.to_s.hash
|
|
|
|
end
|
|
|
|
|
|
|
|
module A
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end_eval
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:21:04 -04:00
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert_kind_of Integer, ::ModuleWithCustomConstMissing::B
|
|
|
|
assert_kind_of Module, ::ModuleWithCustomConstMissing::A
|
|
|
|
assert_kind_of String, ::ModuleWithCustomConstMissing::A::B
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-08 17:44:34 -04:00
|
|
|
def test_const_missing_should_not_double_load
|
2006-08-16 16:54:25 -04:00
|
|
|
$counting_loaded_times = 0
|
2006-08-08 17:44:34 -04:00
|
|
|
with_loading 'autoloading_fixtures' do
|
2006-08-08 18:08:09 -04:00
|
|
|
require_dependency '././counting_loader'
|
2006-08-08 17:44:34 -04:00
|
|
|
assert_equal 1, $counting_loaded_times
|
2006-08-16 16:54:25 -04:00
|
|
|
assert_raises(ArgumentError) { Dependencies.load_missing_constant Object, :CountingLoader }
|
|
|
|
assert_equal 1, $counting_loaded_times
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-16 16:54:25 -04:00
|
|
|
def test_const_missing_within_anonymous_module
|
|
|
|
$counting_loaded_times = 0
|
|
|
|
m = Module.new
|
|
|
|
m.module_eval "def a() CountingLoader; end"
|
|
|
|
extend m
|
2006-11-06 14:23:30 -05:00
|
|
|
kls = nil
|
2006-08-16 16:54:25 -04:00
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
kls = nil
|
|
|
|
assert_nothing_raised { kls = a }
|
|
|
|
assert_equal "CountingLoader", kls.name
|
|
|
|
assert_equal 1, $counting_loaded_times
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-16 16:54:25 -04:00
|
|
|
assert_nothing_raised { kls = a }
|
2006-08-08 17:44:34 -04:00
|
|
|
assert_equal 1, $counting_loaded_times
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-16 23:35:36 -04:00
|
|
|
def test_removal_from_tree_should_be_detected
|
|
|
|
with_loading 'dependencies' do
|
2006-08-29 02:52:39 -04:00
|
|
|
root = Dependencies.load_paths.first
|
2006-08-16 23:35:36 -04:00
|
|
|
c = ServiceOne
|
|
|
|
Dependencies.clear
|
|
|
|
assert ! defined?(ServiceOne)
|
|
|
|
begin
|
|
|
|
Dependencies.load_missing_constant(c, :FakeMissing)
|
|
|
|
flunk "Expected exception"
|
|
|
|
rescue ArgumentError => e
|
|
|
|
assert_match %r{ServiceOne has been removed from the module tree}i, e.message
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-17 13:32:23 -04:00
|
|
|
def test_nested_load_error_isnt_rescued
|
|
|
|
with_loading 'dependencies' do
|
|
|
|
assert_raises(MissingSourceFile) do
|
|
|
|
RequiresNonexistent1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-29 02:52:39 -04:00
|
|
|
def test_load_once_paths_do_not_add_to_autoloaded_constants
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
Dependencies.load_once_paths = Dependencies.load_paths.dup
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-08-29 02:52:39 -04:00
|
|
|
assert ! Dependencies.autoloaded?("ModuleFolder")
|
|
|
|
assert ! Dependencies.autoloaded?("ModuleFolder::NestedClass")
|
|
|
|
assert ! Dependencies.autoloaded?(ModuleFolder)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-09-02 17:13:30 -04:00
|
|
|
1 if ModuleFolder::NestedClass # 1 if to avoid warning
|
2006-08-29 02:52:39 -04:00
|
|
|
assert ! Dependencies.autoloaded?(ModuleFolder::NestedClass)
|
|
|
|
end
|
|
|
|
ensure
|
|
|
|
Object.send(:remove_const, :ModuleFolder) if defined?(ModuleFolder)
|
|
|
|
Dependencies.load_once_paths = []
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-09-02 17:13:30 -04:00
|
|
|
def test_application_should_special_case_application_controller
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
require_dependency 'application'
|
|
|
|
assert_equal 10, ApplicationController
|
|
|
|
assert Dependencies.autoloaded?(:ApplicationController)
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-09-05 18:36:28 -04:00
|
|
|
def test_const_missing_on_kernel_should_fallback_to_object
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
kls = Kernel::E
|
|
|
|
assert_equal "E", kls.name
|
|
|
|
assert_equal kls.object_id, Kernel::E.object_id
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-09-05 19:36:14 -04:00
|
|
|
def test_preexisting_constants_are_not_marked_as_autoloaded
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
require_dependency 'e'
|
|
|
|
assert Dependencies.autoloaded?(:E)
|
|
|
|
Dependencies.clear
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-09-05 19:36:14 -04:00
|
|
|
Object.const_set :E, Class.new
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
require_dependency 'e'
|
|
|
|
assert ! Dependencies.autoloaded?(:E), "E shouldn't be marked autoloaded!"
|
|
|
|
Dependencies.clear
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-09-05 19:36:14 -04:00
|
|
|
ensure
|
|
|
|
Object.send :remove_const, :E if Object.const_defined?(:E)
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-10-15 19:32:31 -04:00
|
|
|
def test_unloadable
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
Object.const_set :M, Module.new
|
|
|
|
M.unloadable
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-10-15 19:32:31 -04:00
|
|
|
Dependencies.clear
|
|
|
|
assert ! defined?(M)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-10-15 19:32:31 -04:00
|
|
|
Object.const_set :M, Module.new
|
|
|
|
Dependencies.clear
|
|
|
|
assert ! defined?(M), "Dependencies should unload unloadable constants each time"
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-10-15 19:32:31 -04:00
|
|
|
def test_unloadable_should_fail_with_anonymous_modules
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
m = Module.new
|
|
|
|
assert_raises(ArgumentError) { m.unloadable }
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-10-15 19:32:31 -04:00
|
|
|
def test_unloadable_should_return_change_flag
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
Object.const_set :M, Module.new
|
|
|
|
assert_equal true, M.unloadable
|
|
|
|
assert_equal false, M.unloadable
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
def test_new_contants_in_without_constants
|
|
|
|
assert_equal [], (Dependencies.new_constants_in(Object) { })
|
2006-11-06 14:23:30 -05:00
|
|
|
assert Dependencies.constant_watch_stack.empty?
|
2006-11-01 18:21:13 -05:00
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
def test_new_constants_in_with_a_single_constant
|
|
|
|
assert_equal(["Hello"], (Dependencies.new_constants_in(Object) do
|
|
|
|
Object.const_set :Hello, 10
|
|
|
|
end))
|
2006-11-06 14:23:30 -05:00
|
|
|
assert Dependencies.constant_watch_stack.empty?
|
2006-11-01 18:21:13 -05:00
|
|
|
ensure
|
|
|
|
Object.send :remove_const, :Hello rescue nil
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
def test_new_constants_in_with_nesting
|
|
|
|
outer = Dependencies.new_constants_in(Object) do
|
|
|
|
Object.const_set :OuterBefore, 10
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
inner = Dependencies.new_constants_in(Object) do
|
|
|
|
Object.const_set :Inner, 20
|
|
|
|
end
|
|
|
|
assert_equal ["Inner"], inner
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
Object.const_set :OuterAfter, 30
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert_equal ["OuterAfter", "OuterBefore"], outer.sort
|
|
|
|
assert Dependencies.constant_watch_stack.empty?
|
|
|
|
ensure
|
|
|
|
%w(OuterBefore Inner OuterAfter).each do |name|
|
|
|
|
Object.send :remove_const, name rescue nil
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
def test_new_constants_in_module
|
|
|
|
Object.const_set :M, Module.new
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
outer = Dependencies.new_constants_in(M) do
|
|
|
|
M.const_set :OuterBefore, 10
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
inner = Dependencies.new_constants_in(M) do
|
|
|
|
M.const_set :Inner, 20
|
|
|
|
end
|
|
|
|
assert_equal ["M::Inner"], inner
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
M.const_set :OuterAfter, 30
|
|
|
|
end
|
|
|
|
assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
|
2006-11-06 14:23:30 -05:00
|
|
|
assert Dependencies.constant_watch_stack.empty?
|
2006-11-01 18:21:13 -05:00
|
|
|
ensure
|
|
|
|
Object.send :remove_const, :M rescue nil
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
def test_new_constants_in_module_using_name
|
|
|
|
outer = Dependencies.new_constants_in(:M) do
|
|
|
|
Object.const_set :M, Module.new
|
|
|
|
M.const_set :OuterBefore, 10
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
inner = Dependencies.new_constants_in(:M) do
|
|
|
|
M.const_set :Inner, 20
|
|
|
|
end
|
|
|
|
assert_equal ["M::Inner"], inner
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
M.const_set :OuterAfter, 30
|
|
|
|
end
|
|
|
|
assert_equal ["M::OuterAfter", "M::OuterBefore"], outer.sort
|
2006-11-06 14:23:30 -05:00
|
|
|
assert Dependencies.constant_watch_stack.empty?
|
2006-11-01 18:21:13 -05:00
|
|
|
ensure
|
|
|
|
Object.send :remove_const, :M rescue nil
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
def test_file_with_multiple_constants_and_require_dependency
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert ! defined?(MultipleConstantFile)
|
|
|
|
assert ! defined?(SiblingConstant)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
require_dependency 'multiple_constant_file'
|
|
|
|
assert defined?(MultipleConstantFile)
|
|
|
|
assert defined?(SiblingConstant)
|
|
|
|
assert Dependencies.autoloaded?(:MultipleConstantFile)
|
|
|
|
assert Dependencies.autoloaded?(:SiblingConstant)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
Dependencies.clear
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert ! defined?(MultipleConstantFile)
|
|
|
|
assert ! defined?(SiblingConstant)
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
def test_file_with_multiple_constants_and_auto_loading
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert ! defined?(MultipleConstantFile)
|
|
|
|
assert ! defined?(SiblingConstant)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert_equal 10, MultipleConstantFile
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert defined?(MultipleConstantFile)
|
|
|
|
assert defined?(SiblingConstant)
|
|
|
|
assert Dependencies.autoloaded?(:MultipleConstantFile)
|
|
|
|
assert Dependencies.autoloaded?(:SiblingConstant)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
Dependencies.clear
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert ! defined?(MultipleConstantFile)
|
|
|
|
assert ! defined?(SiblingConstant)
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
def test_nested_file_with_multiple_constants_and_require_dependency
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert ! defined?(ClassFolder::NestedClass)
|
|
|
|
assert ! defined?(ClassFolder::SiblingClass)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
require_dependency 'class_folder/nested_class'
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert defined?(ClassFolder::NestedClass)
|
|
|
|
assert defined?(ClassFolder::SiblingClass)
|
|
|
|
assert Dependencies.autoloaded?("ClassFolder::NestedClass")
|
|
|
|
assert Dependencies.autoloaded?("ClassFolder::SiblingClass")
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
Dependencies.clear
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert ! defined?(ClassFolder::NestedClass)
|
|
|
|
assert ! defined?(ClassFolder::SiblingClass)
|
|
|
|
end
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
def test_nested_file_with_multiple_constants_and_auto_loading
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert ! defined?(ClassFolder::NestedClass)
|
|
|
|
assert ! defined?(ClassFolder::SiblingClass)
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert_kind_of Class, ClassFolder::NestedClass
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert defined?(ClassFolder::NestedClass)
|
|
|
|
assert defined?(ClassFolder::SiblingClass)
|
|
|
|
assert Dependencies.autoloaded?("ClassFolder::NestedClass")
|
|
|
|
assert Dependencies.autoloaded?("ClassFolder::SiblingClass")
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
Dependencies.clear
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-01 18:21:13 -05:00
|
|
|
assert ! defined?(ClassFolder::NestedClass)
|
|
|
|
assert ! defined?(ClassFolder::SiblingClass)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2006-11-07 15:29:50 -05:00
|
|
|
def test_autoload_doesnt_shadow_no_method_error_with_relative_constant
|
2006-11-06 14:23:30 -05:00
|
|
|
with_loading 'autoloading_fixtures' do
|
2006-11-07 15:29:50 -05:00
|
|
|
assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
|
2006-11-06 14:23:30 -05:00
|
|
|
2.times do
|
|
|
|
assert_raise(NoMethodError) { RaisesNoMethodError }
|
2006-11-07 15:29:50 -05:00
|
|
|
assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
|
2006-11-06 14:23:30 -05:00
|
|
|
end
|
2006-11-07 15:29:50 -05:00
|
|
|
end
|
2006-11-07 15:45:36 -05:00
|
|
|
|
|
|
|
ensure
|
2006-11-07 15:29:50 -05:00
|
|
|
Object.send(:remove_const, :RaisesNoMethodError) if defined?(::RaisesNoMethodError)
|
|
|
|
end
|
2006-11-06 14:23:30 -05:00
|
|
|
|
2006-11-07 15:29:50 -05:00
|
|
|
def test_autoload_doesnt_shadow_no_method_error_with_absolute_constant
|
|
|
|
with_loading 'autoloading_fixtures' do
|
|
|
|
assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it hasn't been referenced yet!"
|
2006-11-06 14:23:30 -05:00
|
|
|
2.times do
|
|
|
|
assert_raise(NoMethodError) { ::RaisesNoMethodError }
|
2006-11-07 15:29:50 -05:00
|
|
|
assert !defined?(::RaisesNoMethodError), "::RaisesNoMethodError is defined but it should have failed!"
|
2006-11-06 14:23:30 -05:00
|
|
|
end
|
|
|
|
end
|
2006-11-07 15:45:36 -05:00
|
|
|
|
|
|
|
ensure
|
2006-11-07 15:29:50 -05:00
|
|
|
Object.send(:remove_const, :RaisesNoMethodError) if defined?(::RaisesNoMethodError)
|
2006-11-06 14:23:30 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def test_autoload_doesnt_shadow_name_error
|
|
|
|
with_loading 'autoloading_fixtures' do
|
2006-11-07 15:29:50 -05:00
|
|
|
assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it hasn't been referenced yet!"
|
2006-11-06 14:23:30 -05:00
|
|
|
2.times do
|
|
|
|
begin
|
2006-11-06 18:45:39 -05:00
|
|
|
::RaisesNameError.object_id
|
2006-11-06 14:23:30 -05:00
|
|
|
flunk 'should have raised NameError when autoloaded file referenced FooBarBaz'
|
|
|
|
rescue NameError => e
|
|
|
|
assert_equal 'uninitialized constant RaisesNameError::FooBarBaz', e.message
|
|
|
|
end
|
2006-11-07 15:29:50 -05:00
|
|
|
assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
|
2006-11-06 14:23:30 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
assert !defined?(RaisesNameError)
|
|
|
|
2.times do
|
|
|
|
assert_raise(NameError) { RaisesNameError }
|
2006-11-07 15:29:50 -05:00
|
|
|
assert !defined?(::RaisesNameError), "::RaisesNameError is defined but it should have failed!"
|
2006-11-06 14:23:30 -05:00
|
|
|
end
|
|
|
|
end
|
2006-11-07 15:29:50 -05:00
|
|
|
|
2006-11-07 15:45:36 -05:00
|
|
|
ensure
|
2006-11-07 15:29:50 -05:00
|
|
|
Object.send(:remove_const, :RaisesNameError) if defined?(::RaisesNameError)
|
2006-11-06 14:23:30 -05:00
|
|
|
end
|
2006-12-09 00:21:33 -05:00
|
|
|
|
|
|
|
def test_remove_constant_handles_double_colon_at_start
|
|
|
|
Object.const_set 'DeleteMe', Module.new
|
|
|
|
DeleteMe.const_set 'OrMe', Module.new
|
|
|
|
Dependencies.send :remove_constant, "::DeleteMe::OrMe"
|
|
|
|
assert ! defined?(DeleteMe::OrMe)
|
|
|
|
assert defined?(DeleteMe)
|
|
|
|
Dependencies.send :remove_constant, "::DeleteMe"
|
|
|
|
assert ! defined?(DeleteMe)
|
|
|
|
end
|
|
|
|
|
2005-11-23 16:31:51 -05:00
|
|
|
end
|