paquito 0.8.0 → 0.9.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: 2cfefa4171fc3e9f968368e99c134e864d493c6651ed21aff0e1bc299a95fb7f
4
- data.tar.gz: e92cacde6d2aa0867b740f99a001d3ff109f4c88eddb7d89594305a579122af3
3
+ metadata.gz: 2882e208a7d6cc2c9b98f748578ea1c8e91133a5ecc71fdc4e41861bb7788f7e
4
+ data.tar.gz: 8376bc939c974028dd6957e1d98467594c33807cdf13fc0470b216aa2476f9ce
5
5
  SHA512:
6
- metadata.gz: 3e032eb7438d07371862c7f9015b8c0a2f72dc8a93004387f1b151f75d06614dba89bc97da21d3eb83399f1c86909f1dc0bbd5702ec8cc4fef1f5001f512a3da
7
- data.tar.gz: e1bd239ec600c28dc5e322b8a8a95daeb539aaada4c9167cf046f5ee5716eb3a6231487b663b534d0db8cb6e1ce2ce53d1dd1b6706184b57f36890edbcbfa663
6
+ metadata.gz: 7bb6ab11609d478cae8993c65fb12db8ea22363064401c718f6e6915ccdd75ad9ddd5c3f7a5a88a8c0562e943c2fda44c4dab101a3db4266f26134ae2ac0e26f
7
+ data.tar.gz: 268549cd0b872b554397b7d685e0ba9f8db9572690091ebaa4936e7a488a26569e9691ad0bfdf2447d1521a36aa5c26b8a7acf96a04271d449c0a6036de7d777
@@ -13,7 +13,7 @@ jobs:
13
13
  - name: Set up Ruby
14
14
  uses: ruby/setup-ruby@v1
15
15
  with:
16
- ruby-version: '2.6'
16
+ ruby-version: '2.7'
17
17
  bundler-cache: true
18
18
  - name: Run test
19
19
  run: bundle exec rubocop
@@ -23,18 +23,17 @@ jobs:
23
23
  strategy:
24
24
  fail-fast: false
25
25
  matrix:
26
- ruby: [ ruby-head, '3.1', '3.0', '2.7', '2.6' ]
26
+ ruby: [ ruby-head, '3.1', '3.0', '2.7' ]
27
27
  steps:
28
28
  - name: Checkout
29
29
  uses: actions/checkout@v3
30
+ - name: Remove Gemfile.lock
31
+ run: rm Gemfile.lock
30
32
  - name: Set up Ruby
31
33
  uses: ruby/setup-ruby@v1
32
34
  with:
33
35
  ruby-version: ${{ matrix.ruby }}
34
- - name: Install dependencies
35
- run: |
36
- rm Gemfile.lock
37
- bundle install
36
+ bundler-cache: true
38
37
  - name: Run test
39
38
  run: bundle exec rake
40
39
  - name: Install gem
data/.rubocop.yml CHANGED
@@ -2,7 +2,7 @@ inherit_gem:
2
2
  rubocop-shopify: rubocop.yml
3
3
 
4
4
  AllCops:
5
- TargetRubyVersion: 2.6
5
+ TargetRubyVersion: 2.7
6
6
 
7
7
  Style/ClassMethodsDefinitions:
8
8
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Unreleased
2
2
 
3
+ # 0.9.0
4
+
5
+ * Handle `compress / decompress` coders (#22)
6
+ * Introduce `FlatCacheEntryCoder` (#21).
7
+ * Drop the partial Ruby 2.6 support.
8
+
9
+ # 0.8.0
10
+
3
11
  * Introduce `SingleBytePrefixVersionWithStringBypass` (#18, #20).
4
12
 
5
13
  # 0.7.0
data/Gemfile.lock CHANGED
@@ -1,23 +1,22 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- paquito (0.8.0)
4
+ paquito (0.9.0)
5
5
  msgpack (>= 1.5.2)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (6.1.6.1)
11
- activesupport (= 6.1.6.1)
12
- activerecord (6.1.6.1)
13
- activemodel (= 6.1.6.1)
14
- activesupport (= 6.1.6.1)
15
- activesupport (6.1.6.1)
10
+ activemodel (7.0.4)
11
+ activesupport (= 7.0.4)
12
+ activerecord (7.0.4)
13
+ activemodel (= 7.0.4)
14
+ activesupport (= 7.0.4)
15
+ activesupport (7.0.4)
16
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
17
17
  i18n (>= 1.6, < 2)
18
18
  minitest (>= 5.1)
19
19
  tzinfo (~> 2.0)
20
- zeitwerk (~> 2.3)
21
20
  ast (2.4.2)
22
21
  benchmark-ips (2.10.0)
23
22
  byebug (11.1.3)
@@ -52,7 +51,6 @@ GEM
52
51
  tzinfo (2.0.5)
53
52
  concurrent-ruby (~> 1.0)
54
53
  unicode-display_width (2.2.0)
55
- zeitwerk (2.6.0)
56
54
 
57
55
  PLATFORMS
58
56
  ruby
data/README.md CHANGED
@@ -161,6 +161,28 @@ Example:
161
161
  ActiveSupport::Cache::FileStore.new("tmp/cache", coder: Paquito.chain(Paquito::CacheEntryCoder, JSON))
162
162
  ```
163
163
 
164
+ ### `FlatCacheEntryCoder`
165
+
166
+ `Paquito::FlatCacheEntryCoder` is a variation of `Paquito::CacheEntryCoder`. Instead of encoding `ActiveSupport::Cache::Entry`
167
+ into an Array of three members, it serializes the entry metadata itself and adds it as a prefix to the serialized payload.
168
+
169
+ This allows to leverage `Paquito::SingleBytePrefixVersionWithStringBypass` effectively.
170
+
171
+ Example:
172
+
173
+ ```ruby
174
+ ActiveSupport::Cache::FileStore.new(
175
+ "tmp/cache",
176
+ coder: Paquito::FlatCacheEntryCoder.new(
177
+ Paquito::SingleBytePrefixVersionWithStringBypass.new(
178
+ 1,
179
+ 0 => Marshal,
180
+ 1 => JSON,
181
+ )
182
+ )
183
+ )
184
+ ```
185
+
164
186
  ### `SerializedColumn`
165
187
 
166
188
  `Paquito::SerializedColumn` allows you to decorate any encoder to behave like Rails's builtin `YAMLColumn`
data/Rakefile CHANGED
@@ -3,8 +3,7 @@
3
3
  require "bundler/gem_tasks"
4
4
  require "rake/testtask"
5
5
 
6
- suites = [:vanilla, :activesupport]
7
- suites << :activerecord if RUBY_VERSION >= "2.7"
6
+ suites = [:vanilla, :activesupport, :activerecord]
8
7
  namespace :test do
9
8
  suites.each do |suite|
10
9
  Rake::TestTask.new(suite) do |t|
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "paquito"
6
+ require "active_support"
7
+ require "benchmark/ips"
8
+
9
+ CODEC = Paquito::CodecFactory.build
10
+ ORIGINAL = Paquito::SingleBytePrefixVersion.new(
11
+ 0,
12
+ 0 => Paquito.chain(
13
+ Paquito::CacheEntryCoder,
14
+ CODEC,
15
+ ),
16
+ )
17
+ FLAT = Paquito::FlatCacheEntryCoder.new(
18
+ Paquito::SingleBytePrefixVersionWithStringBypass.new(
19
+ 0,
20
+ 0 => CODEC,
21
+ )
22
+ )
23
+
24
+ entries = {
25
+ small_string: "Hello World!",
26
+ bytes_1mb: Random.bytes(1_000_000),
27
+ int_array: 1000.times.to_a,
28
+ }
29
+
30
+ entries.each do |name, object|
31
+ entry = ActiveSupport::Cache::Entry.new(object, expires_at: 15.minutes.from_now.to_f)
32
+ original_payload = ORIGINAL.dump(entry).freeze
33
+ flat_payload = FLAT.dump(entry).freeze
34
+
35
+ puts " === Read #{name} ==="
36
+ Benchmark.ips do |x|
37
+ x.report("original") { ORIGINAL.load(original_payload) }
38
+ x.report("flat") { FLAT.load(flat_payload) }
39
+ x.compare!(order: :baseline)
40
+ end
41
+
42
+ puts " === Write #{name} ==="
43
+ Benchmark.ips do |x|
44
+ x.report("original") { ORIGINAL.dump(entry) }
45
+ x.report("flat") { FLAT.dump(entry) }
46
+ x.compare!(order: :baseline)
47
+ end
48
+
49
+ puts
50
+ end
data/dev.yml CHANGED
@@ -2,11 +2,11 @@ name: paquito
2
2
 
3
3
  up:
4
4
  - ruby:
5
- version: 2.6.9
5
+ version: 2.7.5
6
6
  - bundler
7
7
 
8
8
  commands:
9
9
  test:
10
10
  syntax: ""
11
11
  desc: 'run all the tests'
12
- run: bundle exec rake test
12
+ run: bundle exec rake test
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ gem "activerecord", ">= 7.0"
3
4
  require "paquito/errors"
4
5
 
5
6
  module Paquito
@@ -1,22 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ gem "activesupport", ">= 7.0"
4
+
3
5
  module Paquito
4
6
  module CacheEntryCoder
5
7
  def self.dump(entry)
6
- attrs = [entry.value, entry.expires_at, entry.version]
7
- # drop any trailing nil values to save a couple bytes
8
- attrs.pop until !attrs.last.nil? || attrs.empty?
9
- attrs
8
+ entry.pack
10
9
  end
11
10
 
12
11
  def self.load(payload)
13
- entry = ::ActiveSupport::Cache::Entry.allocate
14
- value, expires_in, version = payload
15
- entry.instance_variable_set(:@value, value)
16
- entry.instance_variable_set(:@expires_in, expires_in)
17
- entry.instance_variable_set(:@created_at, 0.0)
18
- entry.instance_variable_set(:@version, version)
19
- entry
12
+ ::ActiveSupport::Cache::Entry.unpack(payload)
20
13
  end
21
14
  end
22
15
  end
@@ -5,7 +5,7 @@ require "paquito/coder_chain"
5
5
 
6
6
  module Paquito
7
7
  class CodecFactory
8
- def self.build(types, freeze: false, serializable_type: false, pool: 1)
8
+ def self.build(types = [], freeze: false, serializable_type: false, pool: 1)
9
9
  factory = if types.empty? && !serializable_type
10
10
  MessagePack::DefaultFactory
11
11
  else
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Paquito
4
+ class Compressor
5
+ def initialize(compressor)
6
+ @compressor = compressor
7
+ end
8
+
9
+ def dump(serial)
10
+ @compressor.compress(serial)
11
+ end
12
+
13
+ def load(payload)
14
+ @compressor.decompress(payload)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem "activesupport", ">= 7.0"
4
+
5
+ module Paquito
6
+ class FlatCacheEntryCoder
7
+ METADATA_CODEC = CodecFactory.build
8
+
9
+ EXPIRES_AT_FORMAT = "E" # Float double-precision, little-endian byte order (8 bytes)
10
+ VERSION_SIZE_FORMAT = "l<" # 32-bit signed, little-endian byte order (int32_t) (4 bytes)
11
+ PREFIX_FORMAT = -(EXPIRES_AT_FORMAT + VERSION_SIZE_FORMAT)
12
+ VERSION_SIZE_OFFSET = [0.0].pack(EXPIRES_AT_FORMAT).bytesize # should be 8
13
+ VERSION_OFFSET = [0.0, 0].pack(PREFIX_FORMAT).bytesize # Should be 12
14
+ VERSION_SIZE_UNPACK = -"@#{VERSION_SIZE_OFFSET}#{VERSION_SIZE_FORMAT}"
15
+
16
+ def initialize(value_coder)
17
+ @value_coder = value_coder
18
+ end
19
+
20
+ def dump(entry)
21
+ version = entry.version
22
+ payload = [
23
+ entry.expires_at || 0.0,
24
+ version ? version.bytesize : -1,
25
+ ].pack(PREFIX_FORMAT)
26
+ payload << version if version
27
+ payload << @value_coder.dump(entry.value)
28
+ end
29
+
30
+ def load(payload)
31
+ expires_at = payload.unpack1(EXPIRES_AT_FORMAT)
32
+ expires_at = nil if expires_at == 0.0
33
+
34
+ version_size = payload.unpack1(VERSION_SIZE_UNPACK)
35
+ if version_size < 0
36
+ version_size = 0
37
+ else
38
+ version = payload.byteslice(VERSION_OFFSET, version_size)
39
+ end
40
+
41
+ ::ActiveSupport::Cache::Entry.new(
42
+ @value_coder.load(payload.byteslice((VERSION_OFFSET + version_size)..-1).freeze),
43
+ expires_at: expires_at,
44
+ version: version,
45
+ )
46
+ end
47
+ end
48
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Paquito
4
- VERSION = "0.8.0"
4
+ VERSION = "0.9.0"
5
5
  end
data/lib/paquito.rb CHANGED
@@ -14,7 +14,6 @@ require "paquito/allow_nil"
14
14
  require "paquito/translate_errors"
15
15
  require "paquito/safe_yaml"
16
16
  require "paquito/conditional_compressor"
17
- require "paquito/cache_entry_coder"
18
17
  require "paquito/single_byte_prefix_version"
19
18
  require "paquito/single_byte_prefix_version_with_string_bypass"
20
19
  require "paquito/comment_prefix_version"
@@ -25,6 +24,8 @@ require "paquito/typed_struct"
25
24
  require "paquito/serialized_column"
26
25
 
27
26
  module Paquito
27
+ autoload :CacheEntryCoder, "paquito/cache_entry_coder"
28
+ autoload :FlatCacheEntryCoder, "paquito/flat_cache_entry_coder"
28
29
  autoload :ActiveRecordCoder, "paquito/active_record_coder"
29
30
 
30
31
  class << self
@@ -33,6 +34,8 @@ module Paquito
33
34
  coder
34
35
  elsif coder.respond_to?(:deflate) && coder.respond_to?(:inflate)
35
36
  Deflater.new(coder)
37
+ elsif coder.respond_to?(:compress) && coder.respond_to?(:decompress)
38
+ Compressor.new(coder)
36
39
  else
37
40
  raise TypeError, "Coders must respond to #dump and #load, #{coder.inspect} doesn't"
38
41
  end
data/paquito.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
  spec.description = "Framework for defining efficient and extendable serializers"
13
13
  spec.homepage = "https://github.com/Shopify/paquito"
14
14
  spec.license = "MIT"
15
- spec.required_ruby_version = ">= 2.6.0"
15
+ spec.required_ruby_version = ">= 2.7.0"
16
16
 
17
17
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
18
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paquito
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-25 00:00:00.000000000 Z
11
+ date: 2022-12-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack
@@ -40,6 +40,7 @@ files:
40
40
  - LICENSE.txt
41
41
  - README.md
42
42
  - Rakefile
43
+ - benchmark/flat-entry-coder.rb
43
44
  - benchmark/msgpack-pooling.rb
44
45
  - benchmark/string-bypass.rb
45
46
  - bin/console
@@ -52,9 +53,11 @@ files:
52
53
  - lib/paquito/codec_factory.rb
53
54
  - lib/paquito/coder_chain.rb
54
55
  - lib/paquito/comment_prefix_version.rb
56
+ - lib/paquito/compressor.rb
55
57
  - lib/paquito/conditional_compressor.rb
56
58
  - lib/paquito/deflater.rb
57
59
  - lib/paquito/errors.rb
60
+ - lib/paquito/flat_cache_entry_coder.rb
58
61
  - lib/paquito/safe_yaml.rb
59
62
  - lib/paquito/serialized_column.rb
60
63
  - lib/paquito/single_byte_prefix_version.rb
@@ -81,7 +84,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
84
  requirements:
82
85
  - - ">="
83
86
  - !ruby/object:Gem::Version
84
- version: 2.6.0
87
+ version: 2.7.0
85
88
  required_rubygems_version: !ruby/object:Gem::Requirement
86
89
  requirements:
87
90
  - - ">="