Skip to content

Commit 4685151

Browse files
authored
Merge pull request #44 from Shopify/exclude_load_paths
Exclude load paths
2 parents e679e28 + b27f8d4 commit 4685151

3 files changed

Lines changed: 41 additions & 3 deletions

File tree

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,23 @@ context.name # => "::Some::Nested::Model"
6262
context.location # => "models/some/nested/model.rb"
6363
```
6464

65+
### Ignoring paths
66+
67+
You may want to only resolve constants from certain sections of your application. If you want to leave any paths out, use `exclude`:
68+
69+
```ruby
70+
resolver = ConstantResolver.new(
71+
root_path: "/app",
72+
load_paths: [
73+
"/app/models",
74+
"/some/engine/app/models",
75+
],
76+
exclude: [
77+
"some/engine/**/*"
78+
],
79+
)
80+
```
81+
6582
## Development
6683

6784
After checking out the repo, run `bundle` to install dependencies. Then, run `rake test` to run the tests.

lib/constant_resolver.rb

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
# have no way of inferring the file it is defined in. You could argue though that inheritance means that another
1414
# constant with the same name exists in the inheriting class, and this view is sufficient for all our use cases.
1515
class ConstantResolver
16+
RUBY_FILES_GLOB = "**/*.rb"
17+
1618
class Error < StandardError; end
1719
class ConstantContext < Struct.new(:name, :location); end
1820

@@ -25,10 +27,12 @@ def camelize(string)
2527
end
2628
end
2729

30+
private_constant :RUBY_FILES_GLOB
2831
private_constant :DefaultInflector
2932

3033
# @param root_path [String] The root path of the application to analyze
3134
# @param load_paths [Array<String>] The autoload paths of the application.
35+
# @param exclude [Array<String>] Paths to exclude to scan for constants.
3236
# @param inflector [Object] Any object that implements a `camelize` function.
3337
#
3438
# @example usage in a Rails app
@@ -39,13 +43,14 @@ def camelize(string)
3943
# root_path: Rails.root.to_s,
4044
# load_paths: load_paths
4145
# )
42-
def initialize(root_path:, load_paths:, inflector: DefaultInflector.new)
46+
def initialize(root_path:, load_paths:, exclude: [], inflector: DefaultInflector.new)
4347
root_path += "/" unless root_path.end_with?("/")
4448

4549
@root_path = root_path
4650
@load_paths = coerce_load_paths(load_paths)
4751
@file_map = nil
4852
@inflector = inflector
53+
@exclude = exclude
4954
end
5055

5156
# Resolve a constant via its name.
@@ -87,7 +92,10 @@ def file_map
8792
duplicate_files[const_name] ||= [existing_entry]
8893
duplicate_files[const_name] << root_relative_path
8994
end
90-
@file_map[const_name] = root_relative_path
95+
96+
if allowed?(root_relative_path)
97+
@file_map[const_name] = root_relative_path
98+
end
9199
end
92100
end
93101

@@ -120,6 +128,10 @@ def config
120128

121129
private
122130

131+
def allowed?(path)
132+
!@exclude.any? { |glob| File.fnmatch(glob, path, File::FNM_EXTGLOB | File::FNM_PATHNAME) }
133+
end
134+
123135
def coerce_load_paths(load_paths)
124136
load_paths = Hash[load_paths.map { |p| [p, "Object"] }] unless load_paths.respond_to?(:transform_keys)
125137

@@ -137,7 +149,7 @@ def ambiguous_constant_message(const_name, paths)
137149
end
138150

139151
def glob_path(path)
140-
@root_path + path + "**/*.rb"
152+
File.join(@root_path, path, RUBY_FILES_GLOB)
141153
end
142154

143155
def resolve_constant(const_name, current_namespace_path, original_name: const_name)

test/constant_resolver_test.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,5 +197,14 @@ def test_raises_if_no_files
197197
MSG
198198
end
199199
end
200+
201+
def test_respects_exclude
202+
resolver = ConstantResolver.new(**@resolver.config.merge(
203+
exclude: ["app/models/**/*"],
204+
))
205+
206+
constant = resolver.resolve("Order")
207+
assert_nil(constant)
208+
end
200209
end
201210
end

0 commit comments

Comments
 (0)