roda 3.103.0 → 3.104.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: d9809241399d00f1fc975608188f61e99c76c5818d7775a4fe8f0b7eeb9715e3
4
- data.tar.gz: e04d8e54e041a4f96e998ebdd0431aada5e6d201fb1b6acc4b8c2a3fab50ea79
3
+ metadata.gz: 7ea3b3c7c8ffcfffa22412e123d09e718e876c13bdfcddbfae461daa813d81bd
4
+ data.tar.gz: 275d90d97fa2893654e368316c1233092ae5fcd60ac7e76ac026a45d2200582b
5
5
  SHA512:
6
- metadata.gz: 19235fd38195015a2b7392ebbf97d34d2f7bda2977c6d45c42fd3b2fd86b1cdee5eff2b65bccf485157955ad474994567ae1b99e93c9459a3a9601df65800f6c
7
- data.tar.gz: 628a775ff0bbb503e18d3cc1989ddfb8dcafec407b890b96adf30684674f5ca749cc6ae6fdc9c4ff9ec59e7779f878f55ae37e76c0e52c26da4e8127a5a0f0f9
6
+ metadata.gz: 546ee3b7cb9d6c8eac9eb6bbc40272a1a5760f522bbe94b38bb78afa3f552a61dd23496d2dfcf4e65fe490b1cad67b229fed4c31ac22b9d25409e501f6bb5c82
7
+ data.tar.gz: f9e94f7612706155c60db6f9a14bb9b130386875f1c86e6a65bc29bf9fdb789719c08f5398f58708ac862ab8b3ec41fb34f11b21d7454878be4364fceb50ce91
@@ -1,7 +1,5 @@
1
1
  # frozen-string-literal: true
2
2
 
3
- require 'digest/sha2'
4
-
5
3
  class Roda
6
4
  module RodaPlugins
7
5
  # The hash_public plugin adds a +hash_path+ method for constructing
@@ -26,7 +24,9 @@ class Roda
26
24
  # This plugin caches the digest of file content on first read. That means
27
25
  # if you change the file after that, it will continue to show the old hash.
28
26
  # This can cause problems in development mode if you are modifying the
29
- # content of files served by the plugin.
27
+ # content of files served by the plugin. You can use the hash_public_cache
28
+ # plugin to scan the public directory in and store the digests in a file,
29
+ # avoiding the need for the process to read files to calculate the digest.
30
30
  #
31
31
  # Examples:
32
32
  #
@@ -48,6 +48,20 @@ class Roda
48
48
  # end
49
49
  # end
50
50
  module HashPublic
51
+ Digest = begin
52
+ require 'openssl'
53
+ ::OpenSSL::Digest
54
+ # :nocov:
55
+ rescue LoadError
56
+ require 'digest/sha2'
57
+ ::Digest
58
+ # :nocov:
59
+ end
60
+
61
+ def self.load_dependencies(app, opts = OPTS)
62
+ app.plugin :public, opts
63
+ end
64
+
51
65
  # Use options given to setup content-hash-based file serving. The
52
66
  # following options are recognized by the plugin:
53
67
  #
@@ -57,23 +71,20 @@ class Roda
57
71
  #
58
72
  # The options given are also passed to the public plugin.
59
73
  def self.configure(app, opts = {})
60
- app.plugin :public, opts
61
74
  app.opts[:hash_public_prefix] = (opts[:prefix] || app.opts[:hash_public_prefix] || 'static').dup.freeze
62
75
  app.opts[:hash_public_length] = opts[:length] || app.opts[:hash_public_length]
63
76
  app.opts[:hash_public_mutex] ||= Mutex.new
64
77
  app.opts[:hash_public_cache] ||= {}
65
78
  end
66
79
 
67
- module InstanceMethods
68
- # Return a path to the static file that could be served by r.hash_public.
69
- # This does not check the file is inside the directory for performance
70
- # reasons, so this should not be called with untrusted input.
71
- def hash_path(file)
80
+ module ClassMethods
81
+ # The digest for the given file to use in hash_path.
82
+ def hash_path_digest(file)
72
83
  opts = self.opts
73
84
  cache = opts[:hash_public_cache]
74
85
  mutex = opts[:hash_public_mutex]
75
86
  unless digest = mutex.synchronize{cache[file]}
76
- digest = ::Digest::SHA256.file(File.join(opts[:public_root], file)).base64digest
87
+ digest = Digest::SHA256.file(File.join(opts[:public_root], file)).base64digest
77
88
  digest.chomp!("=")
78
89
  digest.tr!("+/", "-_")
79
90
  if length = opts[:hash_public_length]
@@ -82,7 +93,16 @@ class Roda
82
93
  digest.freeze
83
94
  mutex.synchronize{cache[file] = digest}
84
95
  end
85
- "/#{opts[:hash_public_prefix]}/#{digest}/#{file}"
96
+ digest
97
+ end
98
+ end
99
+
100
+ module InstanceMethods
101
+ # Return a path to the static file that could be served by r.hash_public.
102
+ # This does not check the file is inside the directory for performance
103
+ # reasons, so this should not be called with untrusted input.
104
+ def hash_path(file)
105
+ "/#{opts[:hash_public_prefix]}/#{self.class.hash_path_digest(file)}/#{file}"
86
106
  end
87
107
  end
88
108
 
@@ -0,0 +1,91 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'json'
4
+ require 'find'
5
+
6
+ class Roda
7
+ module RodaPlugins
8
+ # The hash_public_cache plugin builds on top of the hash_public plugin and
9
+ # adds the ability to store the digests for the public files in a json file,
10
+ # and load that file at startup, which avoids the need for the process to
11
+ # read the public file in order to compute the digest.
12
+ #
13
+ # Examples:
14
+ #
15
+ # # Load the plugin. Options given will be passed to public and hash_public.
16
+ # plugin :hash_public_cache, "path/to/cache_file.json"
17
+ #
18
+ # # When rebuilding the cache:
19
+ # #
20
+ # # * Scan the public directory for files, calculate the digest on each.
21
+ # # * Write the hash public cache to a file.
22
+ # #
23
+ # # This is split into separate steps in case you want to modify the cache
24
+ # # manually after the scan.
25
+ # scan_hash_public_cache_dir
26
+ # dump_hash_public_cache_file
27
+ #
28
+ # # To load the cache at application startup (if the file exists):
29
+ # load_hash_public_cache_file
30
+ module HashPublicCache
31
+ def self.load_dependencies(app, _cache_file, opts = OPTS)
32
+ app.plugin :hash_public, opts
33
+ end
34
+
35
+ # Specify the location of the hash public cache file.
36
+ #
37
+ # The options given are passed to the hash_public plugin.
38
+ def self.configure(app, cache_file, opts = OPTS)
39
+ app.opts[:hash_public_cache_file] = cache_file
40
+ end
41
+
42
+ module ClassMethods
43
+ # Load the hash public cache file, if it exists. This replaces the hash
44
+ # public cache with the values from the file.
45
+ def load_hash_public_cache_file
46
+ file = opts[:hash_public_cache_file]
47
+ return unless File.file?(file)
48
+
49
+ cache = opts[:hash_public_cache] = (opts[:json_parser] || ::JSON.method(:parse)).call(::File.read(file))
50
+ cache.each_value(&:freeze)
51
+ nil
52
+ end
53
+
54
+ # Scan the public directory for files, computing the hash public digest
55
+ # for each. This will not rescan files that already have digest values.
56
+ # If a block is given, it will only calculate the digest for the file
57
+ # if the block returns truthy.
58
+ def scan_hash_public_cache_dir
59
+ cache = opts[:hash_public_cache]
60
+
61
+ # Public root doesn't have trailing slash even if given, as
62
+ # File.expand_path removes it.
63
+ root = opts[:public_root] + File::SEPARATOR
64
+
65
+ Find.find(opts[:public_root]) do |file|
66
+ if File.file?(file)
67
+ file = file.sub(root, '')
68
+ next if cache[file]
69
+
70
+ if defined?(yield)
71
+ next unless yield file
72
+ end
73
+
74
+ cache[file] = hash_path_digest(file)
75
+ end
76
+ end
77
+
78
+ nil
79
+ end
80
+
81
+ # Write the current hash public cache to the cache file.
82
+ def dump_hash_public_cache_file
83
+ File.write(opts[:hash_public_cache_file], (opts[:json_serializer] || :to_json.to_proc).call(opts[:hash_public_cache]))
84
+ nil
85
+ end
86
+ end
87
+ end
88
+
89
+ register_plugin(:hash_public_cache, HashPublicCache)
90
+ end
91
+ end
@@ -56,10 +56,12 @@ class Roda
56
56
  # This plugin depends on the custom_block_results plugin, and therefore does
57
57
  # not support treating String, FalseClass, or NilClass values as JSON.
58
58
  module Json
59
- # Set the classes to automatically convert to JSON, and the serializer to use.
60
- def self.configure(app, opts=OPTS)
59
+ def self.load_dependencies(app, opts=OPTS)
61
60
  app.plugin :custom_block_results
61
+ end
62
62
 
63
+ # Set the classes to automatically convert to JSON, and the serializer to use.
64
+ def self.configure(app, opts=OPTS)
63
65
  classes = opts[:classes] || [Array, Hash]
64
66
  app.opts[:json_result_classes] ||= []
65
67
  app.opts[:json_result_classes] += classes
@@ -35,14 +35,17 @@ class Roda
35
35
  # end
36
36
  # end
37
37
  module TimestampPublic
38
+ def self.load_dependencies(app, opts=OPTS)
39
+ app.plugin :public, opts
40
+ end
41
+
38
42
  # Use options given to setup timestamped file serving. The following option is
39
43
  # recognized by the plugin:
40
44
  #
41
45
  # :prefix :: The prefix for paths, before the timestamp segment
42
46
  #
43
47
  # The options given are also passed to the public plugin.
44
- def self.configure(app, opts={})
45
- app.plugin :public, opts
48
+ def self.configure(app, opts=OPTS)
46
49
  app.opts[:timestamp_public_prefix] = (opts[:prefix] || app.opts[:timestamp_public_prefix] || "static").dup.freeze
47
50
  end
48
51
 
data/lib/roda/version.rb CHANGED
@@ -4,7 +4,7 @@ class Roda
4
4
  RodaMajorVersion = 3
5
5
 
6
6
  # The minor version of Roda, updated for new feature releases of Roda.
7
- RodaMinorVersion = 103
7
+ RodaMinorVersion = 104
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roda
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.103.0
4
+ version: 3.104.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -219,6 +219,7 @@ files:
219
219
  - lib/roda/plugins/hash_matcher.rb
220
220
  - lib/roda/plugins/hash_paths.rb
221
221
  - lib/roda/plugins/hash_public.rb
222
+ - lib/roda/plugins/hash_public_cache.rb
222
223
  - lib/roda/plugins/hash_routes.rb
223
224
  - lib/roda/plugins/head.rb
224
225
  - lib/roda/plugins/header_matchers.rb
@@ -337,7 +338,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
337
338
  - !ruby/object:Gem::Version
338
339
  version: '0'
339
340
  requirements: []
340
- rubygems_version: 4.0.3
341
+ rubygems_version: 4.0.10
341
342
  specification_version: 4
342
343
  summary: Routing tree web toolkit
343
344
  test_files: []