Hello community,

here is the log from the commit of package rubygem-zeitwerk for 
openSUSE:Factory checked in at 2020-07-14 08:00:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-zeitwerk (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-zeitwerk.new.3060 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-zeitwerk"

Tue Jul 14 08:00:55 2020 rev:5 rq:820704 version:2.3.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/rubygem-zeitwerk/rubygem-zeitwerk.changes        
2020-04-27 23:41:15.383860339 +0200
+++ 
/work/SRC/openSUSE:Factory/.rubygem-zeitwerk.new.3060/rubygem-zeitwerk.changes  
    2020-07-14 08:01:47.842276832 +0200
@@ -1,0 +2,11 @@
+Mon Jul 13 14:43:11 UTC 2020 - Manuel Schnitzer <[email protected]>
+
+- updated to version 2.3.1
+
+  * Saves some unnecessary allocations made internally by MRI. See 
[#125](https://github.com/fxn/zeitwerk/pull/125), by 
[@casperisfine](https://github.com/casperisfine).
+
+  * Documentation improvements.
+
+  * Internal code base maintenance.
+
+-------------------------------------------------------------------

Old:
----
  zeitwerk-2.3.0.gem

New:
----
  zeitwerk-2.3.1.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-zeitwerk.spec ++++++
--- /var/tmp/diff_new_pack.E5pWKe/_old  2020-07-14 08:01:50.014283865 +0200
+++ /var/tmp/diff_new_pack.E5pWKe/_new  2020-07-14 08:01:50.018283878 +0200
@@ -24,7 +24,7 @@
 #
 
 Name:           rubygem-zeitwerk
-Version:        2.3.0
+Version:        2.3.1
 Release:        0
 %define mod_name zeitwerk
 %define mod_full_name %{mod_name}-%{version}
@@ -42,7 +42,7 @@
 %description
 Zeitwerk implements constant autoloading with Ruby semantics. Each gem
 and application may have their own independent autoloader, with its own
-configuration, inflector, and logger. Supports autoloading, preloading,
+configuration, inflector, and logger. Supports autoloading,
 reloading, and eager loading.
 
 %prep

++++++ zeitwerk-2.3.0.gem -> zeitwerk-2.3.1.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/README.md new/README.md
--- old/README.md       2020-03-03 20:52:17.000000000 +0100
+++ new/README.md       2020-06-29 01:10:59.000000000 +0200
@@ -16,6 +16,8 @@
     - [Nested root directories](#nested-root-directories)
 - [Usage](#usage)
     - [Setup](#setup)
+        - [Generic](#generic)
+        - [for_gem](#for_gem)
     - [Autoloading](#autoloading)
     - [Eager loading](#eager-loading)
     - [Reloading](#reloading)
@@ -30,8 +32,11 @@
         - [Use case: The adapter pattern](#use-case-the-adapter-pattern)
         - [Use case: Test files mixed with implementation 
files](#use-case-test-files-mixed-with-implementation-files)
     - [Edge cases](#edge-cases)
+    - [Reopening third-party namespaces](#reopening-third-party-namespaces)
     - [Rules of thumb](#rules-of-thumb)
-    - [Autoloading, explicit namespaces, and 
debuggers](#autoloading-explicit-namespaces-and-debuggers)
+    - [Debuggers](#debuggers)
+        - [Break](#break)
+        - [Byebug](#byebug)
 - [Pronunciation](#pronunciation)
 - [Supported Ruby versions](#supported-ruby-versions)
 - [Testing](#testing)
@@ -52,7 +57,9 @@
 
 The gem is designed so that any project, gem dependency, application, etc. can 
have their own independent loader, coexisting in the same process, managing 
their own project trees, and independent of each other. Each loader has its own 
configuration, inflector, and optional logger.
 
-Internally, Zeitwerk issues `require` calls exclusively using absolute file 
names, so there are no costly file system lookups in `$LOAD_PATH`. Technically, 
the directories managed by Zeitwerk do not even need to be in `$LOAD_PATH`. 
Furthermore, Zeitwerk does only one single scan of the project tree, and it 
descends into subdirectories lazily, only if their namespaces are used.
+Internally, Zeitwerk issues `require` calls exclusively using absolute file 
names, so there are no costly file system lookups in `$LOAD_PATH`. Technically, 
the directories managed by Zeitwerk do not even need to be in `$LOAD_PATH`.
+
+Furthermore, Zeitwerk does at most one single scan of the project tree, and it 
descends into subdirectories lazily, only if their namespaces are used.
 
 <a id="markdown-synopsis" name="synopsis"></a>
 ## Synopsis
@@ -211,6 +218,9 @@
 <a id="markdown-setup" name="setup"></a>
 ### Setup
 
+<a id="markdown-generic" name="generic"></a>
+#### Generic
+
 Loaders are ready to load code right after calling `setup` on them:
 
 ```ruby
@@ -227,9 +237,36 @@
 loader.setup
 ```
 
-The loader returned by `Zeitwerk::Loader.for_gem` has the directory of the 
caller pushed, normally that is the absolute path of `lib`. In that sense, 
`for_gem` can be used also by projects with a gem structure, even if they are 
not technically gems. That is, you don't need a gemspec or anything.
+<a id="markdown-for_gem" name="for_gem"></a>
+#### for_gem
+
+`Zeitwerk::Loader.for_gem` is a convenience shortcut for the common case in 
which a gem has its entry point directly under the `lib` directory:
+
+```
+lib/my_gem.rb         # MyGem
+lib/my_gem/version.rb # MyGem::VERSION
+lib/my_gem/foo.rb     # MyGem::Foo
+```
+
+Neither a gemspec nor a version file are technically required, this helper 
works as long as the code is organized using that standard structure.
+
+If the entry point of your gem lives in a subdirectory of `lib` because it is 
reopening a namespace defined somewhere else, please use the generic API to 
setup the loader, and make sure you check the section [_Reopening third-party 
namespaces_](https://github.com/fxn/zeitwerk#reopening-third-party-namespaces) 
down below.
+
+Conceptually, `for_gem` translates to:
+
+```ruby
+# lib/my_gem.rb
+
+require "zeitwerk"
+loader = Zeitwerk::Loader.new
+loader.tag = File.basename(__FILE__, ".rb")
+loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
+loader.push_dir(__dir__)
+```
+
+except that this method returns the same object in subsequent calls from the 
same file, in the unlikely case the gem wants to be able to reload.
 
-If the main module of a library references project constants at the top-level, 
Zeitwerk has to be ready to load them. Their definitions, in turn, may 
reference other project constants. And this is recursive. Therefore, it is 
important that the `setup` call happens above the main module definition:
+If the main module references project constants at the top-level, Zeitwerk has 
to be ready to load them. Their definitions, in turn, may reference other 
project constants. And this is recursive. Therefore, it is important that the 
`setup` call happens above the main module definition:
 
 ```ruby
 # lib/my_gem.rb (main file)
@@ -245,8 +282,6 @@
 end
 ```
 
-Zeitwerk works internally only with absolute paths to avoid costly file 
searches in `$LOAD_PATH`. Indeed, the root directories do not even need to 
belong to `$LOAD_PATH`, everything just works by design if they don't.
-
 <a id="markdown-autoloading" name="autoloading"></a>
 ### Autoloading
 
@@ -619,6 +654,42 @@
 
 This only affects explicit namespaces, those idioms work well for any other 
ordinary class or module.
 
+<a id="markdown-reopening-third-party-namespaces" 
name="reopening-third-party-namespaces"></a>
+### Reopening third-party namespaces
+
+Projects managed by Zeitwerk can work with namespaces defined by third-party 
libraries. However, they have to be loaded in memory before calling `setup`.
+
+For example, let's imagine you're writing a gem that implements an adapter for 
[Active Job](https://guides.rubyonrails.org/active_job_basics.html) that uses 
AwesomeQueue as backend. By convention, your gem has to define a class called 
`ActiveJob::QueueAdapters::AwesomeQueue`, and it has to do so in a file with a 
matching path:
+
+```ruby
+# lib/active_job/queue_adapters/awesome_queue.rb
+module ActiveJob
+  module QueueAdapters
+    class AwesomeQueue
+      # ...
+    end
+  end
+end
+```
+
+It is very important that your gem _reopens_ the modules `ActiveJob` and 
`ActiveJob::QueueAdapters` instead of _defining_ them. Because their proper 
definition lives in Active Job. Furthermore, if the project reloads, you do not 
want any of `ActiveJob` or `ActiveJob::QueueAdapters` to be reloaded.
+
+Bottom line, Zeitwerk should not be managing those namespaces. Active Job owns 
them and defines them. Your gem needs to _reopen_ them.
+
+In order to do so, you need to make sure those modules are loaded before 
calling `setup`. For instance, in the entry file for the gem:
+
+```ruby
+# Ensure these namespaces are reopened, not defined.
+require "active_job"
+require "active_job/queue_adapters"
+
+require "zeitwerk"
+loader = Zeitwerk::Loader.for_gem
+loader.setup
+```
+
+With that, when Zeitwerk scans the file system and reaches the gem directories 
`lib/active_job` and `lib/active_job/queue_adapters`, it detects the 
corresponding modules already exist and therefore understands it does not have 
to manage them. The loader just descends into those directories. Eventually 
will reach `lib/active_job/queue_adapters/awesome_queue.rb`, and since 
`ActiveJob::QueueAdapters::AwesomeQueue` is unknown, Zeitwerk will manage it. 
Which is what happens regularly with the files in your gem. On reload, the 
namespaces are safe, won't be reloaded. The loader only reloads what it 
manages, which in this case is the adapter itself.
+
 <a id="markdown-rules-of-thumb" name="rules-of-thumb"></a>
 ### Rules of thumb
 
@@ -634,14 +705,18 @@
 
 6. In a given process, ideally, there should be at most one loader with 
reloading enabled. Technically, you can have more, but it may get tricky if one 
refers to constants managed by the other one. Do that only if you know what you 
are doing.
 
-<a id="markdown-autoloading-explicit-namespaces-and-debuggers" 
name="autoloading-explicit-namespaces-and-debuggers"></a>
-### Autoloading, explicit namespaces, and debuggers
+<a id="markdown-debuggers" name="debuggers"></a>
+### Debuggers
+
+<a id="markdown-break" name="break"></a>
+#### Break
 
-As of this writing, Zeitwerk is unable to autoload classes or modules that 
belong to [explicit namespaces](#explicit-namespaces) inside debugger sessions. 
You'll get a `NameError`.
+Zeitwerk works fine with [@gsamokovarov](https://github.com/gsamokovarov)'s 
[Break](https://github.com/gsamokovarov/break) debugger.
 
-The root cause is that debuggers set trace points, and Zeitwerk does too to 
support explicit namespaces. A debugger session happens inside a trace point 
handler, and Ruby does not invoke other handlers from within a running handler. 
Therefore, the code that manages explicit namespaces in Zeitwerk does not get 
called by the interpreter. See [this 
issue](https://github.com/deivid-rodriguez/byebug/issues/564#issuecomment-499413606)
 for further details.
+<a id="markdown-byebug" name="byebug"></a>
+#### Byebug
 
-As a workaround, you can eager load. Zeitwerk tries hard to succeed or fail 
consistently both autoloading and eager loading, so switching to eager loading 
should not introduce any interference in your debugging logic, generally 
speaking.
+Zeitwerk and [Byebug](https://github.com/deivid-rodriguez/byebug) are 
incompatible, classes or modules that belong to [explicit 
namespaces](#explicit-namespaces) are not autoloaded inside a Byebug session. 
See [this 
issue](https://github.com/deivid-rodriguez/byebug/issues/564#issuecomment-499413606)
 for further details.
 
 <a id="markdown-pronunciation" name="pronunciation"></a>
 ## Pronunciation
Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/zeitwerk/kernel.rb new/lib/zeitwerk/kernel.rb
--- old/lib/zeitwerk/kernel.rb  2020-03-03 20:52:17.000000000 +0100
+++ new/lib/zeitwerk/kernel.rb  2020-06-29 01:10:59.000000000 +0200
@@ -3,6 +3,17 @@
 module Kernel
   module_function
 
+  # We are going to decorate Kerner#require with two goals.
+  #
+  # First, by intercepting Kernel#require calls, we are able to autovivify
+  # modules on required directories, and also do internal housekeeping when
+  # managed files are loaded.
+  #
+  # On the other hand, if you publish a new version of a gem that is now 
managed
+  # by Zeitwerk, client code can reference directly your classes and modules 
and
+  # should not require anything. But if someone has legacy require calls 
around,
+  # they will work as expected, and in a compatible way.
+  #
   # We cannot decorate with prepend + super because Kernel has already been
   # included in Object, and changes in ancestors don't get propagated into
   # already existing ancestor chains.
@@ -30,4 +41,24 @@
       end
     end
   end
+
+  # By now, I have seen no way so far to decorate require_relative.
+  #
+  # For starters, at least in CRuby, require_relative does not delegate to
+  # require. Both require and require_relative delegate the bulk of their work
+  # to an internal C function called rb_require_safe. So, our require wrapper 
is
+  # not executed.
+  #
+  # On the other hand, we cannot use the aliasing technique above because
+  # require_relative receives a path relative to the directory of the file in
+  # which the call is performed. If a wrapper here invoked the original method,
+  # Ruby would resolve the relative path taking lib/zeitwerk as base directory.
+  #
+  # A workaround could be to extract the base directory from caller_locations,
+  # but what if someone else decorated require_relative before us? You can't
+  # really know with certainty where's the original call site in the stack.
+  #
+  # However, the main use case for require_relative is to load files from your
+  # own project. Projects managed by Zeitwerk don't do this for files managed 
by
+  # Zeitwerk, precisely.
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/zeitwerk/loader.rb new/lib/zeitwerk/loader.rb
--- old/lib/zeitwerk/loader.rb  2020-03-03 20:52:17.000000000 +0100
+++ new/lib/zeitwerk/loader.rb  2020-06-29 01:10:59.000000000 +0200
@@ -464,7 +464,7 @@
       #   require "zeitwerk"
       #   loader = Zeitwerk::Loader.new
       #   loader.tag = File.basename(__FILE__, ".rb")
-      #   loader.inflector = Zeitwerk::GemInflector.new
+      #   loader.inflector = Zeitwerk::GemInflector.new(__FILE__)
       #   loader.push_dir(__dir__)
       #
       # except that this method returns the same object in subsequent calls 
from
@@ -616,7 +616,10 @@
       # $LOADED_FEATURES stores real paths since Ruby 2.4.4. We set and save 
the
       # real path to be able to delete it from $LOADED_FEATURES on unload, and 
to
       # be able to do a lookup later in Kernel#require for manual require 
calls.
-      realpath = File.realpath(abspath)
+      #
+      # We freeze realpath because that saves allocations in Module#autoload.
+      # See #125.
+      realpath = File.realpath(abspath).freeze
       parent.autoload(cname, realpath)
       if logger
         if ruby?(realpath)
@@ -719,8 +722,13 @@
     def ls(dir)
       Dir.foreach(dir) do |basename|
         next if basename.start_with?(".")
+
         abspath = File.join(dir, basename)
-        yield basename, abspath unless ignored_paths.member?(abspath)
+        next if ignored_paths.member?(abspath)
+
+        # We freeze abspath because that saves allocations when passed later to
+        # File methods. See #125.
+        yield basename, abspath.freeze
       end
     end
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/zeitwerk/version.rb new/lib/zeitwerk/version.rb
--- old/lib/zeitwerk/version.rb 2020-03-03 20:52:17.000000000 +0100
+++ new/lib/zeitwerk/version.rb 2020-06-29 01:10:59.000000000 +0200
@@ -1,5 +1,5 @@
 # frozen_string_literal: true
 
 module Zeitwerk
-  VERSION = "2.3.0"
+  VERSION = "2.3.1"
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        2020-03-03 20:52:17.000000000 +0100
+++ new/metadata        2020-06-29 01:10:59.000000000 +0200
@@ -1,19 +1,19 @@
 --- !ruby/object:Gem::Specification
 name: zeitwerk
 version: !ruby/object:Gem::Version
-  version: 2.3.0
+  version: 2.3.1
 platform: ruby
 authors:
 - Xavier Noria
 autorequire: 
 bindir: bin
 cert_chain: []
-date: 2020-03-03 00:00:00.000000000 Z
+date: 2020-06-28 00:00:00.000000000 Z
 dependencies: []
 description: |2
       Zeitwerk implements constant autoloading with Ruby semantics. Each gem
       and application may have their own independent autoloader, with its own
-      configuration, inflector, and logger. Supports autoloading, preloading,
+      configuration, inflector, and logger. Supports autoloading,
       reloading, and eager loading.
 email: [email protected]
 executables: []
@@ -36,7 +36,11 @@
 homepage: https://github.com/fxn/zeitwerk
 licenses:
 - MIT
-metadata: {}
+metadata:
+  homepage_uri: https://github.com/fxn/zeitwerk
+  changelog_uri: https://github.com/fxn/zeitwerk/blob/master/CHANGELOG.md
+  source_code_uri: https://github.com/fxn/zeitwerk
+  bug_tracker_uri: https://github.com/fxn/zeitwerk/issues
 post_install_message: 
 rdoc_options: []
 require_paths:
@@ -52,7 +56,7 @@
     - !ruby/object:Gem::Version
       version: '0'
 requirements: []
-rubygems_version: 3.0.3
+rubygems_version: 3.1.2
 signing_key: 
 specification_version: 4
 summary: Efficient and thread-safe constant autoloader


Reply via email to