Skip to content

Commit

Permalink
Remove namespace concept
Browse files Browse the repository at this point in the history
This will be completely unnecessary once we work with anonymous
modules.
  • Loading branch information
shioyama committed Jan 28, 2023
1 parent dbbaa13 commit 1eca0c2
Show file tree
Hide file tree
Showing 16 changed files with 55 additions and 588 deletions.
8 changes: 4 additions & 4 deletions lib/im/loader.rb
Expand Up @@ -116,8 +116,8 @@ def setup
mutex.synchronize do
break if @setup

actual_roots.each do |root_dir, root_namespace|
set_autoloads_in_dir(root_dir, root_namespace)
actual_roots.each do |root_dir|
set_autoloads_in_dir(root_dir, Object)
end

on_setup_callbacks.each(&:call)
Expand Down Expand Up @@ -319,7 +319,7 @@ def eager_load_namespace(mod)
#
# @sig () -> Array[String]
def all_dirs
Registry.loaders.flat_map(&:dirs).freeze
Registry.loaders.map(&:dirs).inject(&:+).freeze
end
end

Expand Down Expand Up @@ -462,7 +462,7 @@ def raise_if_conflicting_directory(dir)
next if loader == self
next if loader.__ignores?(dir)

loader.__roots.each_key do |root_dir|
loader.__root_dirs.each do |root_dir|
next if ignores?(root_dir)

root_dir_slash = root_dir + "/"
Expand Down
60 changes: 21 additions & 39 deletions lib/im/loader/config.rb
Expand Up @@ -13,21 +13,20 @@ module Im::Loader::Config
# @sig #call | #debug | nil
attr_accessor :logger

# Absolute paths of the root directories, mapped to their respective root namespaces:
# Absolute paths of the root directories, as a set:
#
# "/Users/fxn/blog/app/channels" => Object,
# "/Users/fxn/blog/app/adapters" => ActiveJob::QueueAdapters,
# ...
#
# Stored in a hash to preserve order, easily handle duplicates, and have a
# fast lookup by directory.
# #<Set: {
# "/Users/fxn/blog/app/channels",
# "/Users/fxn/blog/app/adapters",
# ...
# }>
#
# This is a private collection maintained by the loader. The public
# interface for it is `push_dir` and `dirs`.
#
# @sig Hash[String, Module]
attr_reader :roots
internal :roots
# @sig Array[String]
attr_reader :root_dirs
internal :root_dirs

# Absolute paths of files, directories, or glob patterns to be totally
# ignored.
Expand Down Expand Up @@ -88,7 +87,7 @@ def initialize
@logger = self.class.default_logger
@tag = SecureRandom.hex(3)
@initialized_at = Time.now
@roots = {}
@root_dirs = Set.new
@ignored_glob_patterns = Set.new
@ignored_paths = Set.new
@collapse_glob_patterns = Set.new
Expand All @@ -108,16 +107,11 @@ def initialize
#
# @raise [Im::Error]
# @sig (String | Pathname, Module) -> void
def push_dir(path, namespace: Object)
# Note that Class < Module.
unless namespace.is_a?(Module)
raise Im::Error, "#{namespace.inspect} is not a class or module object, should be"
end

def push_dir(path)
abspath = File.expand_path(path)
if dir?(abspath)
raise_if_conflicting_directory(abspath)
roots[abspath] = namespace
root_dirs << abspath
else
raise Im::Error, "the root directory #{abspath} does not exist"
end
Expand All @@ -140,29 +134,17 @@ def tag=(tag)
@tag = tag.to_s
end

# If `namespaces` is falsey (default), returns an array with the absolute
# paths of the root directories as strings. If truthy, returns a hash table
# instead. Keys are the absolute paths of the root directories as strings,
# values are their corresponding namespaces, class or module objects.
#
# Rturns an array with the absolute paths of the root directories as strings.
# If `ignored` is falsey (default), ignored root directories are filtered out.
#
# These are read-only collections, please add to them with `push_dir`.
#
# @sig () -> Array[String] | Hash[String, Module]
def dirs(namespaces: false, ignored: false)
if namespaces
if ignored || ignored_paths.empty?
roots.clone
else
roots.reject { |root_dir, _namespace| ignored_path?(root_dir) }
end
def dirs(ignored: false)
if ignored || ignored_paths.empty?
root_dirs
else
if ignored || ignored_paths.empty?
roots.keys
else
roots.keys.reject { |root_dir| ignored_path?(root_dir) }
end
root_dirs.reject { |root_dir| ignored_path?(root_dir) }
end.freeze
end

Expand Down Expand Up @@ -296,7 +278,7 @@ def log!

walk_up(abspath) do |abspath|
return true if ignored_path?(abspath)
return false if roots.key?(abspath)
return false if root_dir?(abspath)
end

false
Expand All @@ -309,14 +291,14 @@ def log!

# @sig () -> Array[String]
private def actual_roots
roots.reject do |root_dir, _root_namespace|
root_dirs.reject do |root_dir|
!dir?(root_dir) || ignored_path?(root_dir)
end
end

# @sig (String) -> bool
private def root_dir?(dir)
roots.key?(dir)
root_dirs.include?(dir)
end

# @sig (String) -> bool
Expand All @@ -326,7 +308,7 @@ def log!

walk_up(abspath) do |abspath|
return true if eager_load_exclusions.member?(abspath)
return false if roots.key?(abspath)
return false if root_dir?(abspath)
end

false
Expand Down
42 changes: 14 additions & 28 deletions lib/im/loader/eager_load.rb
Expand Up @@ -13,8 +13,8 @@ def eager_load(force: false)

log("eager load start") if logger

actual_roots.each do |root_dir, root_namespace|
actual_eager_load_dir(root_dir, root_namespace, force: force)
actual_roots.each do |root_dir|
actual_eager_load_dir(root_dir, Object, force: force)
end

autoloaded_dirs.each do |autoloaded_dir|
Expand All @@ -38,24 +38,24 @@ def eager_load_dir(path)

cnames = []

root_namespace = nil
found_root = false
walk_up(abspath) do |dir|
return if ignored_path?(dir)
return if eager_load_exclusions.member?(dir)

break if root_namespace = roots[dir]
break if found_root = root_dirs.include?(dir)

unless collapse?(dir)
basename = File.basename(dir)
cnames << inflector.camelize(basename, dir).to_sym
end
end

raise Im::Error.new("I do not manage #{abspath}") unless root_namespace
raise Im::Error.new("I do not manage #{abspath}") unless found_root

return if @eager_loaded

namespace = root_namespace
namespace = Object
cnames.reverse_each do |cname|
# Can happen if there are no Ruby files. This is not an error condition,
# the directory is actually managed. Could have Ruby files later.
Expand All @@ -81,24 +81,13 @@ def eager_load_namespace(mod)
mod_name = real_mod_name(mod)
return unless mod_name

actual_roots.each do |root_dir, root_namespace|
actual_roots.each do |root_dir|
if mod.equal?(Object)
# A shortcircuiting test depends on the invocation of this method.
# Please keep them in sync if refactored.
actual_eager_load_dir(root_dir, root_namespace)
elsif root_namespace.equal?(Object)
eager_load_child_namespace(mod, mod_name, root_dir, root_namespace)
actual_eager_load_dir(root_dir, Object)
else
root_namespace_name = real_mod_name(root_namespace)
if root_namespace_name.start_with?(mod_name + "::")
actual_eager_load_dir(root_dir, root_namespace)
elsif mod_name == root_namespace_name
actual_eager_load_dir(root_dir, root_namespace)
elsif mod_name.start_with?(root_namespace_name + "::")
eager_load_child_namespace(mod, mod_name, root_dir, root_namespace)
else
# Unrelated constant hierarchies, do nothing.
end
eager_load_child_namespace(mod, mod_name, root_dir)
end
end
end
Expand All @@ -121,23 +110,23 @@ def load_file(path)
basename = File.basename(abspath, ".rb")
base_cname = inflector.camelize(basename, abspath).to_sym

root_namespace = nil
root_included = false
cnames = []

walk_up(File.dirname(abspath)) do |dir|
raise Im::Error.new("#{abspath} is ignored") if ignored_path?(dir)

break if root_namespace = roots[dir]
break if root_included = root_dirs.include?(dir)

unless collapse?(dir)
basename = File.basename(dir)
cnames << inflector.camelize(basename, dir).to_sym
end
end

raise Im::Error.new("I do not manage #{abspath}") unless root_namespace
raise Im::Error.new("I do not manage #{abspath}") unless root_included

namespace = root_namespace
namespace = Object
cnames.reverse_each do |cname|
namespace = cget(namespace, cname)
end
Expand Down Expand Up @@ -186,11 +175,8 @@ def load_file(path)
# strict namespace descendendant of `root_namespace`.
#
# @sig (Module, String, Module, Boolean) -> void
private def eager_load_child_namespace(child, child_name, root_dir, root_namespace)
private def eager_load_child_namespace(child, child_name, root_dir)
suffix = child_name
unless root_namespace.equal?(Object)
suffix = suffix.delete_prefix(real_mod_name(root_namespace) + "::")
end

# These directories are at the same namespace level, there may be more if
# we find collapsed ones. As we scan, we look for matches for the first
Expand Down
2 changes: 1 addition & 1 deletion lib/im/loader/helpers.rb
Expand Up @@ -29,7 +29,7 @@ module Im::Loader::Helpers
next if ignored_path?(abspath)

if dir?(abspath)
next if roots.key?(abspath)
next if root_dirs.include?(abspath)
next if !has_at_least_one_ruby_file?(abspath)
else
next unless ruby?(abspath)
Expand Down
2 changes: 1 addition & 1 deletion test/lib/im/test_all_dirs.rb
Expand Up @@ -21,7 +21,7 @@ class TestAllDirs < LoaderTest
new_loader(dirs: "loaderA")
new_loader(dirs: "loaderB")

assert_equal ["#{Dir.pwd}/loaderA", "#{Dir.pwd}/loaderB"], Im::Loader.all_dirs
assert_equal ["#{Dir.pwd}/loaderA", "#{Dir.pwd}/loaderB"].to_set, Im::Loader.all_dirs
end
end
end
28 changes: 0 additions & 28 deletions test/lib/im/test_autovivification.rb
Expand Up @@ -3,8 +3,6 @@
require "test_helper"

class TestAutovivification < LoaderTest
module Namespace; end

test "autoloads a simple constant in an autovivified module (Object)" do
files = [["admin/x.rb", "Admin::X = true"]]
with_setup(files) do
Expand All @@ -13,28 +11,13 @@ module Namespace; end
end
end

test "autoloads a simple constant in an autovivified module (Namespace)" do
files = [["admin/x.rb", "#{Namespace}::Admin::X = true"]]
with_setup(files, namespace: Namespace) do
assert_kind_of Module, Namespace::Admin
assert Namespace::Admin::X
end
end

test "autovivifies several levels in a row (Object)" do
files = [["foo/bar/baz/woo.rb", "Foo::Bar::Baz::Woo = true"]]
with_setup(files) do
assert Foo::Bar::Baz::Woo
end
end

test "autovivifies several levels in a row (Namespace)" do
files = [["foo/bar/baz/woo.rb", "#{Namespace}::Foo::Bar::Baz::Woo = true"]]
with_setup(files, namespace: Namespace) do
assert Namespace::Foo::Bar::Baz::Woo
end
end

test "autoloads several constants from the same namespace (Object)" do
files = [
["rd1/admin/hotel.rb", "class Admin::Hotel; end"],
Expand All @@ -46,17 +29,6 @@ module Namespace; end
end
end

test "autoloads several constants from the same namespace (Namespace)" do
files = [
["rd1/admin/hotel.rb", "class #{Namespace}::Admin::Hotel; end"],
["rd2/admin/hotels_controller.rb", "class #{Namespace}::Admin::HotelsController; end"]
]
with_setup(files, namespace: Namespace) do
assert Namespace::Admin::Hotel
assert Namespace::Admin::HotelsController
end
end

test "autovivification is synchronized" do
$test_admin_const_set_queue = Queue.new

Expand Down

0 comments on commit 1eca0c2

Please sign in to comment.