~singpolyma/dhall-ruby

a49a8991d548ae1383b7c4384e2451ff867840d7 — Stephen Paul Weber 1 year, 3 months ago 93e4efb 0.2.0
Customizable cache

Caches implemented in this commit:

StandardFileCache - cache conforming to dhall-lang
RamCache - stores in a hash, meant for single-load caching
NoCache - when you want to be sure
3 files changed, 83 insertions(+), 6 deletions(-)

M lib/dhall/ast.rb
M lib/dhall/resolve.rb
M test/test_resolve.rb
M lib/dhall/ast.rb => lib/dhall/ast.rb +1 -1
@@ 1500,7 1500,7 @@ module Dhall

		def cache_key(relative_to)
			if integrity_check.protocol == :nocheck
				real_path(relative_to).to_s
				real_path(relative_to)
			else
				integrity_check.to_s
			end

M lib/dhall/resolve.rb => lib/dhall/resolve.rb +51 -5
@@ 149,6 149,52 @@ module Dhall
			end
		end

		module NoCache
			def self.fetch(*)
				yield
			end
		end

		class RamCache
			def initialize
				@cache = {}
			end

			def fetch(key, &block)
				return @cache[key] if @cache.key?(key)

				Promise.resolve(nil).then(&block).then do |result|
					@cache[key] = result
				end
			end
		end

		class StandardFileCache
			def initialize(
				dir=Pathname.new(ENV.fetch(
					"XDG_CACHE_HOME", ENV.fetch("HOME") + "/.cache/"
				)) + "dhall/"
			)
				dir.mkpath
				@dir = dir
				@ram = RamCache.new
			end

			def fetch(key, &block)
				if key.is_a?(String) && key.start_with?("sha256:")
					file = @dir + key.sub(/^sha256:/, "")
					return Dhall.from_binary(file.binread) if file.exist?

					Promise.resolve(nil).then(&block).then do |result|
						file.open("wb") { |fh| fh.write(result.to_binary) }
						result
					end
				else
					@ram.fetch(key, &block)
				end
			end
		end

		class ResolutionSet
			def initialize(reader, max_depth:)
				@reader = reader


@@ 220,6 266,7 @@ module Dhall
				http_reader: StandardReadHttpSources,
				https_reader: http_reader,
				environment_reader: ReadEnvironmentSources,
				cache: StandardFileCache.new,
				max_depth: Float::INFINITY
			)
				@path_resolutions = ResolutionSet.new(path_reader, max_depth: max_depth)


@@ 229,7 276,7 @@ module Dhall
					environment_reader, max_depth: max_depth
				)
				@deadline = Util::NoDeadline.new
				@cache = {}
				@cache = cache
			end

			def with_deadline(deadline)


@@ 242,9 289,7 @@ module Dhall

			def cache_fetch(key, &fallback)
				@cache.fetch(key) do
					Promise.resolve(nil).then(&fallback).then do |result|
						@cache[key] = result
					end
					Promise.resolve(nil).then(&fallback)
				end
			end



@@ 315,6 360,7 @@ module Dhall
				https_reader: http_reader,
				environment_reader: ReadEnvironmentSources,
				ipfs_public_gateway: "cloudflare-ipfs.com",
				cache: RamCache.new,
				max_depth: 50
			)
				super(


@@ 324,7 370,7 @@ module Dhall
						https_reader:   https_reader,
						public_gateway: ipfs_public_gateway
					),
					http_reader: http_reader, https_reader: https_reader,
					http_reader: http_reader, https_reader: https_reader, cache: cache,
					environment_reader: environment_reader, max_depth: max_depth
				)
			end

M test/test_resolve.rb => test/test_resolve.rb +31 -0
@@ 254,6 254,37 @@ class TestResolve < Minitest::Test
		assert_equal Dhall::Variable["_"], subject(expr)
	end

	def test_cache
		req = stub_request(:get, "http://example.com/thing.dhall")
		      .to_return(status: 200, body: "\x00".b)

		expr = Dhall::Import.new(
			Dhall::Import::IntegrityCheck.new(
				"sha256", Dhall::Variable["_"].digest.hexdigest
			),
			Dhall::Import::Expression,
			Dhall::Import::Http.new(nil, "example.com", "thing.dhall", nil)
		)

		cache = Dhall::Resolvers::RamCache.new

		assert_equal(
			Dhall::Variable["_"],
			expr.resolve(
				resolver: Dhall::Resolvers::Default.new(cache: cache)
			).sync
		)

		assert_equal(
			Dhall::Variable["_"],
			expr.resolve(
				resolver: Dhall::Resolvers::Default.new(cache: cache)
			).sync
		)

		assert_requested(req, times: 1)
	end

	def test_ipfs
		stub_request(:get, "http://localhost:8000/ipfs/TESTCID")
			.to_return(status: 200, body: "\x00".b)