Skip to content

Commit 7b38c75

Browse files
committed
Release cached files after OpenapiFirst.load
Make FileLoader and RefResolver classes
1 parent cd4de96 commit 7b38c75

6 files changed

Lines changed: 74 additions & 71 deletions

File tree

lib/openapi_first.rb

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ module OpenapiFirst
2222

2323
FAILURE = :openapi_first_validation_failure
2424

25-
# Clears cached files
26-
def self.clear_cache!
27-
FileLoader.clear_cache!
28-
end
29-
3025
# @return [Configuration]
3126
def self.configuration
3227
@configuration ||= Configuration.new

lib/openapi_first/builder.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,20 @@ def initialize(contents, filepath:, config:)
2727
meta_schema = detect_meta_schema(contents, filepath)
2828
@schemer_configuration = build_schemer_config(filepath:, meta_schema:)
2929
@config = config
30-
@contents = RefResolver.for(contents, filepath:)
30+
@file_loader = FileLoader.new
31+
ref_resolver = RefResolver.new(file_loader:)
32+
@contents = ref_resolver.for(contents, filepath:)
3133
end
3234

3335
attr_reader :config
34-
private attr_reader :schemer_configuration
36+
private attr_reader :schemer_configuration, :file_loader
3537

3638
def build_schemer_config(filepath:, meta_schema:)
3739
result = JSONSchemer.configuration.clone
3840
dir = (filepath && File.absolute_path(File.dirname(filepath))) || Dir.pwd
3941
result.base_uri = URI::File.build({ path: "#{dir}/" })
4042
result.ref_resolver = JSONSchemer::CachedResolver.new do |uri|
41-
FileLoader.load(uri.path)
43+
file_loader.load(uri.path)
4244
end
4345
result.meta_schema = meta_schema
4446
result.insert_property_defaults = true

lib/openapi_first/file_loader.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,15 @@
55

66
module OpenapiFirst
77
# @!visibility private
8-
module FileLoader
9-
@cache = {}
10-
@mutex = Mutex.new
8+
class FileLoader
9+
def self.load(file_path)
10+
new.load(file_path)
11+
end
1112

12-
module_function
13+
def initialize
14+
@cache = {}
15+
@mutex = Mutex.new
16+
end
1317

1418
def load(file_path)
1519
@cache[file_path] || @mutex.synchronize do
@@ -29,9 +33,5 @@ def load(file_path)
2933
end
3034
end
3135
end
32-
33-
def clear_cache!
34-
@mutex.synchronize { @cache.clear }
35-
end
3636
end
3737
end

lib/openapi_first/ref_resolver.rb

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,42 @@
55
module OpenapiFirst
66
# This is here to give traverse an OAD while keeping $refs intact
77
# @visibility private
8-
module RefResolver
9-
def self.load(filepath)
10-
contents = OpenapiFirst::FileLoader.load(filepath)
8+
class RefResolver
9+
def initialize(file_loader:)
10+
@file_loader = file_loader
11+
end
12+
13+
private attr_reader :file_loader
14+
15+
def load(filepath)
16+
contents = file_loader.load(filepath)
1117
self.for(contents, filepath:)
1218
end
1319

14-
def self.for(value, filepath: nil, context: value)
20+
def for(value, filepath: nil, context: value)
1521
case value
1622
when ::Hash
17-
resolver = Hash.new(value, context:, filepath:)
23+
resolver = Hash.new(value, context:, filepath:, ref_resolver: self)
1824
if value.key?('$ref')
1925
probe = resolver.resolve_ref(value['$ref'])
2026
return probe if probe.is_a?(Array)
2127
end
2228
resolver
2329
when ::Array
24-
Array.new(value, context:, filepath:)
30+
Array.new(value, context:, filepath:, ref_resolver: self)
2531
when ::NilClass
2632
nil
2733
else
28-
Simple.new(value)
34+
Simple.new(value, ref_resolver: self)
2935
end
3036
end
3137

38+
def file_at(filepath, file_pointer)
39+
file_contents = file_loader.load(filepath)
40+
value = Hana::Pointer.new(file_pointer).eval(file_contents)
41+
self.for(value, filepath: filepath, context: file_contents)
42+
end
43+
3244
# @visibility private
3345
module Diggable
3446
def dig(*keys)
@@ -42,10 +54,11 @@ def dig(*keys)
4254

4355
# @visibility private
4456
module Resolvable
45-
def initialize(value, context: value, filepath: nil)
57+
def initialize(value, ref_resolver:, context: value, filepath: nil)
4658
@value = value
4759
@context = context
4860
@filepath = filepath
61+
@ref_resolver = ref_resolver
4962
@dir = if filepath
5063
File.dirname(File.absolute_path(filepath))
5164
else
@@ -62,6 +75,8 @@ def initialize(value, context: value, filepath: nil)
6275

6376
attr_reader :filepath
6477

78+
private attr_reader :ref_resolver
79+
6580
def ==(_other)
6681
raise "Don't call == on an unresolved value. Use .value == other instead."
6782
end
@@ -71,16 +86,14 @@ def resolve_ref(pointer)
7186
value = Hana::Pointer.new(pointer[1..]).eval(context)
7287
raise "Unknown reference #{pointer} in #{context}" unless value
7388

74-
return RefResolver.for(value, filepath:, context:)
89+
return ref_resolver.for(value, filepath:, context:)
7590
end
7691

7792
relative_path, file_pointer = pointer.split('#')
7893
full_path = File.expand_path(relative_path, dir)
79-
return RefResolver.load(full_path) unless file_pointer
94+
return ref_resolver.load(full_path) unless file_pointer
8095

81-
file_contents = FileLoader.load(full_path)
82-
value = Hana::Pointer.new(file_pointer).eval(file_contents)
83-
RefResolver.for(value, filepath: full_path, context: file_contents)
96+
ref_resolver.file_at(full_path, file_pointer)
8497
rescue OpenapiFirst::FileNotFoundError => e
8598
message = "Problem with reference resolving #{pointer.inspect} in " \
8699
"file #{File.absolute_path(filepath).inspect}: #{e.message}"
@@ -114,13 +127,13 @@ def resolved
114127
def [](key)
115128
return resolve_ref(@value['$ref'])[key] if !@value.key?(key) && @value.key?('$ref')
116129

117-
RefResolver.for(@value[key], filepath:, context:)
130+
ref_resolver.for(@value[key], filepath:, context:)
118131
end
119132

120133
def fetch(key)
121134
return resolve_ref(@value['$ref']).fetch(key) if !@value.key?(key) && @value.key?('$ref')
122135

123-
RefResolver.for(@value.fetch(key), filepath:, context:)
136+
ref_resolver.for(@value.fetch(key), filepath:, context:)
124137
end
125138

126139
def each
@@ -170,7 +183,7 @@ def [](index)
170183
item = @value[index]
171184
return resolve_ref(item['$ref']) if item.is_a?(::Hash) && item.key?('$ref')
172185

173-
RefResolver.for(item, filepath:, context:)
186+
ref_resolver.for(item, filepath:, context:)
174187
end
175188

176189
def each

spec/openapi_first_spec.rb

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,6 @@
5252
end
5353
end
5454

55-
describe '.clear_cache!' do
56-
it 'clears the file cache so files are reloaded on next load' do
57-
first = OpenapiFirst.load(spec_path)
58-
OpenapiFirst.clear_cache!
59-
second = OpenapiFirst.load(spec_path)
60-
expect(second).not_to be(first)
61-
end
62-
end
63-
6455
describe '.load' do
6556
begin
6657
require 'multi_json'

0 commit comments

Comments
 (0)