lib/tapioca/gemfile.rb in tapioca-0.6.1 vs lib/tapioca/gemfile.rb in tapioca-0.6.2

- old
+ new

@@ -97,39 +97,28 @@ IGNORED_GEMS = T.let(["sorbet", "sorbet-static", "sorbet-runtime"].freeze, T::Array[String]) sig { returns(String) } attr_reader :full_gem_path, :version + sig { returns(T::Array[Pathname]) } + attr_reader :files + sig { params(spec: Spec).void } def initialize(spec) @spec = T.let(spec, Tapioca::Gemfile::Spec) real_gem_path = to_realpath(@spec.full_gem_path) @full_gem_path = T.let(real_gem_path, String) @version = T.let(version_string, String) @exported_rbi_files = T.let(nil, T.nilable(T::Array[String])) + @files = T.let(collect_files, T::Array[Pathname]) end sig { params(gemfile_dir: String).returns(T::Boolean) } def ignore?(gemfile_dir) gem_ignored? || gem_in_app_dir?(gemfile_dir) end - sig { returns(T::Array[Pathname]) } - def files - if default_gem? - # `Bundler::RemoteSpecification` delegates missing methods to - # `Gem::Specification`, so `files` actually always exists on spec. - T.unsafe(@spec).files.map do |file| - ruby_lib_dir.join(file) - end - else - @spec.full_require_paths.flat_map do |path| - Pathname.glob((Pathname.new(path) / "**/*.rb").to_s) - end - end - end - sig { returns(String) } def name @spec.name end @@ -152,11 +141,11 @@ files.each { |path| YARD.parse(path.to_s, [], Logger::Severity::FATAL) } end sig { returns(T::Array[String]) } def exported_rbi_files - @exported_rbi_files ||= Dir.glob("#{full_gem_path}/rbi/**/*.rbi") + @exported_rbi_files ||= Dir.glob("#{full_gem_path}/rbi/**/*.rbi").sort end sig { returns(T::Boolean) } def export_rbi_files? exported_rbi_files.any? @@ -174,17 +163,52 @@ rewriter.tree end private - sig { returns(T::Boolean) } + sig { returns(T::Array[Pathname]) } + def collect_files + if default_gem? + # `Bundler::RemoteSpecification` delegates missing methods to + # `Gem::Specification`, so `files` actually always exists on spec. + T.unsafe(@spec).files.map do |file| + resolve_to_ruby_lib_dir(file) + end + else + @spec.full_require_paths.flat_map do |path| + Pathname.glob((Pathname.new(path) / "**/*.rb").to_s) + end + end + end + + sig { returns(T.nilable(T::Boolean)) } def default_gem? @spec.respond_to?(:default_gem?) && @spec.default_gem? end - sig { returns(Pathname) } - def ruby_lib_dir - Pathname.new(RbConfig::CONFIG["rubylibdir"]) + sig { returns(Regexp) } + def require_paths_prefix_matcher + @require_paths_prefix_matcher = T.let(@require_paths_prefix_matcher, T.nilable(Regexp)) + + @require_paths_prefix_matcher ||= begin + require_paths = T.unsafe(@spec).require_paths + prefix_matchers = require_paths.map { |rp| Regexp.new("^#{rp}/") } + Regexp.union(prefix_matchers) + end + end + + sig { params(file: String).returns(Pathname) } + def resolve_to_ruby_lib_dir(file) + # We want to match require prefixes but fallback to an empty match + # if none of the require prefixes actually match. This is so that + # we can always replace the match with the Ruby lib directory and + # we would have properly resolved the file under the Ruby lib dir. + prefix_matcher = Regexp.union(require_paths_prefix_matcher, //) + + ruby_lib_dir = RbConfig::CONFIG["rubylibdir"] + file = file.sub(prefix_matcher, "#{ruby_lib_dir}/") + + Pathname.new(file).expand_path end sig { returns(String) } def version_string version = @spec.version.to_s