kennel 1.163.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1719d52ba321517c50fe0d2b3ffff1d98d66789cfe0cb86aa9c70c8524ec63de
4
- data.tar.gz: 58ee09fd3667cecb7fc2c6c382269362b72ac03d3f3e04ea102edfb76478f973
3
+ metadata.gz: ccf24b963a06289a82a03996aafdf59c7932ba1e55f1be8a27e8e5c2e7366a59
4
+ data.tar.gz: c691e5fca96de9a9ff904d90e56d15ad8df45b018e530b83bc9b6d1e57ca7035
5
5
  SHA512:
6
- metadata.gz: b7dd527ce56869145e5cb0ae4f506bfef321bbff8ecaeb9c31f9dc1851c3ea422e154e71a457c438b99511c937beacf12d84992e7a95d5d6c738c761cfda6ce2
7
- data.tar.gz: d1eeddcc2147d2aade9aaf720e383d791255e892798509228d3c2e4c9ef31d85d8693607a7ac8e717c16d91efb228e373d73e4cc4960549f771e6cc3841f4a25
6
+ metadata.gz: cbae40312ac008e6a213549d0d0c6393276c77081ab2a866cd6b787df33d18ac13d962b78e44f64520c356b6c015f487517bedd909bd82fb9fa019b7e6c40e53
7
+ data.tar.gz: 10f59d9002d8504a5bf19dbeea8051c3bba8670332b8f28bdaf1413ecc1889d5e86e30fce8699f94760091d713b0522dfcafc9d8a3cb6eea6583ed4d322d0af1
@@ -9,18 +9,9 @@ module Kennel
9
9
  end
10
10
 
11
11
  # @return [Array<Models::Project>]
12
- # All projects in the system. This is a slow operation.
13
- # Use `projects` to get all projects in the system.
14
- def all_projects
15
- load_all
16
- loaded_projects.map(&:new)
17
- end
18
-
19
- # @return [Array<Models::Project>]
20
- # All projects in the system. This is a slow operation.
21
-
12
+ # All requested projects. This is a slow operation when loading all projects.
22
13
  def projects
23
- load_all
14
+ load_requested
24
15
  loaded_projects.map(&:new)
25
16
  end
26
17
 
@@ -30,61 +21,27 @@ module Kennel
30
21
  Models::Project.recursive_subclasses
31
22
  end
32
23
 
33
- # load_all's purpose is to "require" all the .rb files under './projects',
24
+ # "require" requested .rb files under './projects',
34
25
  # while allowing them to resolve reference to ./teams and ./parts via autoload
35
- def load_all
36
- # Zeitwerk rejects second and subsequent calls.
37
- # Even if we skip over the Zeitwerk part, the nature of 'require' is
38
- # one-way: ruby does not provide a mechanism to *un*require things.
39
- return if defined?(@@load_all) && @@load_all
40
- @@load_all = true
41
-
42
- loader = Zeitwerk::Loader.new
43
- Dir.exist?("teams") && loader.push_dir("teams", namespace: Teams)
44
- Dir.exist?("parts") && loader.push_dir("parts")
45
-
46
- if (autoload = ENV["AUTOLOAD_PROJECTS"]) && autoload != "false"
47
- loader.push_dir("projects")
48
- loader.setup
49
-
50
- if (projects = @filter.project_filter)
51
- projects_path = "#{File.expand_path("projects")}/"
52
- known_paths = loader.all_expected_cpaths.keys.select! { |path| path.start_with?(projects_path) }
53
-
54
- projects.each do |project|
55
- search = project_search project
56
-
57
- # sort by name and nesting level to pick the best candidate
58
- found = known_paths.grep(search).sort.sort_by { |path| path.count("/") }
59
-
60
- if found.any?
61
- require found.first
62
- assert_project_loaded search, found
63
- elsif autoload != "abort"
64
- Kennel.err.puts(
65
- "No projects/ file matching #{search} found, falling back to slow loading of all projects instead"
66
- )
67
- loader.eager_load
68
- break
69
- else
70
- raise AutoloadFailed, "No projects/ file matching #{search} found"
71
- end
26
+ def load_requested
27
+ return if ensure_load_once!
28
+ loader = setup_zeitwerk_loader
29
+ if (projects = @filter.project_filter)
30
+ known_paths = zeitwerk_known_paths(loader)
31
+ projects.each do |project|
32
+ search = project_search project
33
+ found = sort_paths(known_paths.grep(search))
34
+ if found.any?
35
+ require found.first
36
+ assert_project_loaded search, found
37
+ else
38
+ raise AutoloadFailed, "Unable to load #{project} since there are no projects/ files matching #{search}"
72
39
  end
73
- else
74
- # all projects needed
75
- loader.eager_load
76
40
  end
77
- else
78
- # old style without autoload to be removed eventually
79
- loader.setup
80
- loader.eager_load # TODO: this should not be needed but we see hanging CI processes when it's not added
81
- # TODO: also auto-load projects and update expected path too
82
- # but to do that we need to stop the pattern of having a class at the bottom of the project structure
83
- # and change to Module::Project + Module::Support
84
- # we need the extra sort so foo/bar.rb is loaded before foo/bar/baz.rb
85
- Dir["projects/**/*.rb"].sort.each { |f| require "./#{f}" } # rubocop:disable Lint/RedundantDirGlobSort
41
+ else # load everything
42
+ loader.eager_load force: true
86
43
  end
87
- rescue NameError => e
44
+ rescue NameError => e # improve error message when file does not match constant
88
45
  message = e.message
89
46
  raise unless (klass = message[/uninitialized constant (.*)/, 1])
90
47
 
@@ -105,6 +62,29 @@ module Kennel
105
62
  raise
106
63
  end
107
64
 
65
+ def setup_zeitwerk_loader
66
+ loader = Zeitwerk::Loader.new
67
+ Dir.exist?("teams") && loader.push_dir("teams", namespace: Teams)
68
+ Dir.exist?("parts") && loader.push_dir("parts")
69
+ loader.push_dir("projects")
70
+ loader.setup
71
+ loader
72
+ end
73
+
74
+ # Zeitwerk rejects subsequent calls.
75
+ # Even if we skip over the Zeitwerk part, the nature of 'require' is
76
+ # one-way: ruby does not provide a mechanism to *un*require things.
77
+ def ensure_load_once!
78
+ return true if defined?(@@loaded) && @@loaded
79
+ @@loaded = true
80
+ false
81
+ end
82
+
83
+ def zeitwerk_known_paths(loader)
84
+ projects_path = "#{File.expand_path("projects")}/"
85
+ loader.all_expected_cpaths.keys.select! { |path| path.start_with?(projects_path) }
86
+ end
87
+
108
88
  # - support PROJECT being used for nested folders, to allow teams to easily group their projects
109
89
  # - support PROJECT.rb but also PROJECT/base.rb or PROJECT/project.rb
110
90
  def project_search(project)
@@ -113,13 +93,14 @@ module Kennel
113
93
  /\/#{project_match}(\.rb|#{suffixes.map { |s| Regexp.escape "/#{s}" }.join("|")})$/
114
94
  end
115
95
 
96
+ # keep message in sync with logic in sort_paths
116
97
  def assert_project_loaded(search, paths)
117
98
  return if loaded_projects.any?
118
99
  paths = paths.map { |path| path.sub("#{Dir.pwd}/", "") }
119
100
  raise(
120
101
  AutoloadFailed,
121
102
  <<~MSG
122
- No project found in loaded files!
103
+ No project found in loaded files! (no class inheriting from Kennel::Models::Project)
123
104
  Ensure the project file you want to load is first in the list,
124
105
  list is sorted alphabetically and by nesting level.
125
106
 
@@ -132,5 +113,11 @@ module Kennel
132
113
  MSG
133
114
  )
134
115
  end
116
+
117
+ # sort by name and nesting level to pick the best candidate
118
+ # keep logic in sync with message in assert_project_loaded
119
+ def sort_paths(paths)
120
+ paths.sort.sort_by { |path| path.count("/") }
121
+ end
135
122
  end
136
123
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Kennel
3
- VERSION = "1.163.3"
3
+ VERSION = "2.0.0"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kennel
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.163.3
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Grosser
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-06-26 00:00:00.000000000 Z
11
+ date: 2025-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs