rencoder 0.1.1 → 0.2.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 +5 -5
- data/.github/workflows/gem-push.yml +30 -0
- data/.github/workflows/on_push.yml +33 -0
- data/.rubocop.yml +27 -0
- data/.ruby-version +1 -1
- data/Gemfile +2 -0
- data/README.md +10 -10
- data/lib/rencoder.rb +10 -7
- data/lib/rencoder/coder.rb +3 -0
- data/lib/rencoder/decoder.rb +9 -6
- data/lib/rencoder/encoder.rb +12 -11
- data/lib/rencoder/version.rb +3 -1
- data/rencoder.gemspec +9 -6
- data/spec/rencoder/decoder_spec.rb +41 -23
- data/spec/rencoder/encoder_spec.rb +31 -29
- data/spec/spec_helper.rb +21 -6
- metadata +27 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f87f5dfd83820c67adf886b6b38ecc9ee5aa57da16e545c9f2698f7d94d8c1b2
|
4
|
+
data.tar.gz: 188690f46aff4d973bb593b83bdf775eb784a6608942d7af08bb3eb6ebb59432
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51cf0155f687f6687112a9e8953df56441847f7ca43c64c17eab7ca5db5f293febe61da70c8681a579d0265eeb0ca1d567baf10aff0ef33799dd2fde626e5a37
|
7
|
+
data.tar.gz: 8b36e60bc122a7e8a7b17d9b0ec829f55f0c5896d17815813a1654e13217b33086ea626426846ef9d9143ca3b83f7f60002432fcdd1a60ce70cf3880fe7abd96
|
@@ -0,0 +1,30 @@
|
|
1
|
+
name: Publish Ruby Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- v0.*
|
7
|
+
release:
|
8
|
+
types: [published]
|
9
|
+
jobs:
|
10
|
+
build:
|
11
|
+
name: Build + Publish
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
|
14
|
+
steps:
|
15
|
+
- uses: actions/checkout@v2
|
16
|
+
- name: Set up Ruby 2.7
|
17
|
+
uses: actions/setup-ruby@v1
|
18
|
+
with:
|
19
|
+
ruby-version: 2.7.x
|
20
|
+
|
21
|
+
- name: Publish to RubyGems
|
22
|
+
run: |
|
23
|
+
mkdir -p $HOME/.gem
|
24
|
+
touch $HOME/.gem/credentials
|
25
|
+
chmod 0600 $HOME/.gem/credentials
|
26
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
27
|
+
gem build *.gemspec
|
28
|
+
gem push *.gem
|
29
|
+
env:
|
30
|
+
GEM_HOST_API_KEY: "Bearer ${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: On Push
|
9
|
+
|
10
|
+
on: [push, pull_request]
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
test:
|
14
|
+
runs-on: ubuntu-latest
|
15
|
+
strategy:
|
16
|
+
max-parallel: 4
|
17
|
+
matrix:
|
18
|
+
ruby-version: [2.4, 2.7]
|
19
|
+
steps:
|
20
|
+
- uses: actions/checkout@v2
|
21
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
22
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
23
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
24
|
+
# uses: ruby/setup-ruby@v1
|
25
|
+
uses: ruby/setup-ruby@ec106b438a1ff6ff109590de34ddc62c540232e0
|
26
|
+
with:
|
27
|
+
ruby-version: ${{ matrix.ruby-version }}
|
28
|
+
- name: Install dependencies
|
29
|
+
run: bundle install
|
30
|
+
- name: Run RuboCop
|
31
|
+
run: bundle exec rubocop
|
32
|
+
- name: Run RSpec
|
33
|
+
run: bundle exec rspec spec
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# The behavior of RuboCop can be controlled via the .rubocop.yml
|
2
|
+
# configuration file. It makes it possible to enable/disable
|
3
|
+
# certain cops (checks) and to alter their behavior if they accept
|
4
|
+
# any parameters. The file can be placed either in your home
|
5
|
+
# directory or in some project directory.
|
6
|
+
#
|
7
|
+
# RuboCop will start looking for the configuration file in the directory
|
8
|
+
# where the inspected file is and continue its way up to the root directory.
|
9
|
+
#
|
10
|
+
# See https://docs.rubocop.org/rubocop/configuration
|
11
|
+
|
12
|
+
require: rubocop-rspec
|
13
|
+
|
14
|
+
|
15
|
+
AllCops:
|
16
|
+
NewCops: enable
|
17
|
+
|
18
|
+
Metrics/BlockLength:
|
19
|
+
Exclude:
|
20
|
+
- spec/**/*.rb
|
21
|
+
|
22
|
+
|
23
|
+
Metrics/MethodLength:
|
24
|
+
Max: 30
|
25
|
+
|
26
|
+
Metrics/CyclomaticComplexity:
|
27
|
+
Max: 10
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.7
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# Rencoder
|
2
2
|
|
3
|
-
Rencoder is pure Ruby implementation of Rencode serialization format encoding/decoding.
|
3
|
+
Rencoder is a pure Ruby implementation of Rencode serialization format encoding/decoding.
|
4
4
|
|
5
|
-
Rencoder is *FULLY* compliant with Python implementation, and uses all optimizations (by-type-offset integers, strings, arrays, hashes) both
|
5
|
+
Rencoder is a *FULLY* compliant with Python implementation, and uses all optimizations (by-type-offset integers, strings, arrays, hashes) both for encoding and decoding.
|
6
6
|
|
7
|
-
Rencoder
|
7
|
+
Rencoder have no runtime dependencies. Everything done in a pure Ruby.
|
8
8
|
|
9
9
|
More about Rencode format:
|
10
10
|
- <https://github.com/aresch/rencode>
|
@@ -30,15 +30,15 @@ Rencoder.dump(["hello", :world, 123]) # Arrays
|
|
30
30
|
```
|
31
31
|
|
32
32
|
**Float precion notice**
|
33
|
-
Rencoder uses 64-bit precision by default.
|
34
|
-
It's
|
35
|
-
If there is strong reason to use 32-bit precision, then please specify
|
36
|
-
``float32: true`` option
|
33
|
+
Rencoder uses a 64-bit precision by default.
|
34
|
+
It's recommended to stay this way.
|
35
|
+
If there is a strong reason to use 32-bit precision, then please specify
|
36
|
+
``float32: true`` option in a ``Rencoder.dump`` call:
|
37
37
|
|
38
38
|
```ruby
|
39
39
|
Rencoder.dump(1.000001, float32: true)
|
40
40
|
```
|
41
|
-
***Using 32-bit precision is
|
41
|
+
***Using 32-bit precision is NOT recommended***
|
42
42
|
|
43
43
|
### Deserialization
|
44
44
|
|
@@ -52,7 +52,7 @@ Rencoder.load(string_data)
|
|
52
52
|
# => "Hello World"
|
53
53
|
```
|
54
54
|
|
55
|
-
**Rencoder can read data from any IO object directly without using any buffers**
|
55
|
+
**Rencoder can read data from any IO object directly, without using any buffers**
|
56
56
|
```ruby
|
57
57
|
socket = TCPSocket.new('example.com', 8814)
|
58
58
|
Rendcoder.load(socket)
|
@@ -61,7 +61,7 @@ Rendcoder.load(socket)
|
|
61
61
|
|
62
62
|
### ActiveRecord
|
63
63
|
|
64
|
-
Rencoder is compliant with ActiveSupport ``serialize`` interface:
|
64
|
+
Rencoder is compliant with the ActiveSupport's ``serialize`` interface:
|
65
65
|
|
66
66
|
```ruby
|
67
67
|
class MyModel < ActiveRecord::Base
|
data/lib/rencoder.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rencoder/version'
|
2
4
|
|
5
|
+
# Rencode format encoder/decoder
|
3
6
|
module Rencoder
|
4
7
|
# Rencoder Constants
|
5
8
|
MAX_INT_LENGTH = 64
|
@@ -22,30 +25,30 @@ module Rencoder
|
|
22
25
|
# Dictionaries with length embedded in typecode.
|
23
26
|
DICT_FIXED_START = 102
|
24
27
|
DICT_FIXED_COUNT = 25
|
25
|
-
DICT_FIXED = (DICT_FIXED_START...DICT_FIXED_START + DICT_FIXED_COUNT)
|
28
|
+
DICT_FIXED = (DICT_FIXED_START...DICT_FIXED_START + DICT_FIXED_COUNT).freeze
|
26
29
|
|
27
30
|
# Positive integers with value embedded in typecode.
|
28
31
|
INT_POS_FIXED_START = 0
|
29
32
|
INT_POS_FIXED_COUNT = 44
|
30
|
-
INT_POS_FIXED = (INT_POS_FIXED_START...INT_POS_FIXED_START + INT_POS_FIXED_COUNT)
|
33
|
+
INT_POS_FIXED = (INT_POS_FIXED_START...INT_POS_FIXED_START + INT_POS_FIXED_COUNT).freeze
|
31
34
|
|
32
35
|
# Negative integers with value embedded in typecode.
|
33
36
|
INT_NEG_FIXED_START = 70
|
34
37
|
INT_NEG_FIXED_COUNT = 32
|
35
|
-
INT_NEG_FIXED = (INT_NEG_FIXED_START...INT_NEG_FIXED_START + INT_NEG_FIXED_COUNT)
|
38
|
+
INT_NEG_FIXED = (INT_NEG_FIXED_START...INT_NEG_FIXED_START + INT_NEG_FIXED_COUNT).freeze
|
36
39
|
|
37
40
|
# String length header
|
38
|
-
STR_HEADER = ('0'.ord..'9'.ord)
|
41
|
+
STR_HEADER = ('0'.ord..'9'.ord).freeze
|
39
42
|
|
40
43
|
# Strings with length embedded in typecode.
|
41
44
|
STR_FIXED_START = 128
|
42
45
|
STR_FIXED_COUNT = 64
|
43
|
-
STR_FIXED = (STR_FIXED_START
|
46
|
+
STR_FIXED = (STR_FIXED_START...STR_FIXED_START + STR_FIXED_COUNT).freeze
|
44
47
|
|
45
48
|
# Lists with length embedded in typecode.
|
46
|
-
LIST_FIXED_START = STR_FIXED_START+STR_FIXED_COUNT
|
49
|
+
LIST_FIXED_START = STR_FIXED_START + STR_FIXED_COUNT
|
47
50
|
LIST_FIXED_COUNT = 64
|
48
|
-
LIST_FIXED = (LIST_FIXED_START
|
51
|
+
LIST_FIXED = (LIST_FIXED_START...LIST_FIXED_START + LIST_FIXED_COUNT).freeze
|
49
52
|
|
50
53
|
require_relative 'rencoder/encoder'
|
51
54
|
require_relative 'rencoder/decoder'
|
data/lib/rencoder/coder.rb
CHANGED
data/lib/rencoder/decoder.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rencoder
|
4
|
+
# Rencode format decoder module
|
2
5
|
module Decoder
|
3
6
|
INTEGER_DECODING_MAP = {
|
4
7
|
CHR_INT1 => [1, 'c'],
|
5
8
|
CHR_INT2 => [2, 's>'],
|
6
9
|
CHR_INT4 => [4, 'l>'],
|
7
10
|
CHR_INT8 => [8, 'q>']
|
8
|
-
}
|
11
|
+
}.freeze
|
9
12
|
|
10
13
|
def decode(buffer)
|
11
14
|
buffer = StringIO.new(buffer) unless buffer.respond_to?(:read) # IO object
|
@@ -43,11 +46,11 @@ module Rencoder
|
|
43
46
|
when CHR_INT1, CHR_INT2, CHR_INT4, CHR_INT8
|
44
47
|
size, template = INTEGER_DECODING_MAP[type]
|
45
48
|
|
46
|
-
buffer.read(size).
|
49
|
+
buffer.read(size).unpack1(template)
|
47
50
|
when INT_POS_FIXED
|
48
51
|
type - INT_POS_FIXED_START
|
49
52
|
when INT_NEG_FIXED
|
50
|
-
-1-(type - INT_NEG_FIXED_START)
|
53
|
+
-1 - (type - INT_NEG_FIXED_START)
|
51
54
|
end
|
52
55
|
end
|
53
56
|
|
@@ -71,7 +74,7 @@ module Rencoder
|
|
71
74
|
end
|
72
75
|
end
|
73
76
|
|
74
|
-
def decode_boolean(
|
77
|
+
def decode_boolean(_buffer, type)
|
75
78
|
type == CHR_TRUE
|
76
79
|
end
|
77
80
|
|
@@ -88,7 +91,7 @@ module Rencoder
|
|
88
91
|
when LIST_FIXED
|
89
92
|
size = type - LIST_FIXED_START
|
90
93
|
|
91
|
-
size.times.map do |
|
94
|
+
size.times.map do |_i|
|
92
95
|
decode(buffer)
|
93
96
|
end
|
94
97
|
end
|
@@ -111,7 +114,7 @@ module Rencoder
|
|
111
114
|
end
|
112
115
|
end
|
113
116
|
|
114
|
-
def decode_nil(
|
117
|
+
def decode_nil(_buffer, _type)
|
115
118
|
nil
|
116
119
|
end
|
117
120
|
|
data/lib/rencoder/encoder.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rencoder
|
4
|
+
# Rencode format encoder module
|
2
5
|
module Encoder
|
3
6
|
class EncodingError < StandardError; end
|
4
7
|
|
5
8
|
def encode(object)
|
6
9
|
case object
|
7
10
|
when String, Symbol then encode_string(object)
|
8
|
-
when
|
11
|
+
when Integer then encode_integer(object)
|
9
12
|
when Float then encode_float(object)
|
10
13
|
when TrueClass, FalseClass then encode_boolean(object)
|
11
14
|
when NilClass then encode_nil(object)
|
@@ -16,26 +19,24 @@ module Rencoder
|
|
16
19
|
end
|
17
20
|
end
|
18
21
|
|
19
|
-
def encode_integer(object)
|
22
|
+
def encode_integer(object) # rubocop:disable Metrics/AbcSize
|
20
23
|
case object
|
21
24
|
when (0...INT_POS_FIXED_COUNT) # predefined positive intger
|
22
25
|
[INT_POS_FIXED_START + object].pack('C')
|
23
26
|
when (-INT_NEG_FIXED_COUNT...0) # predefined negative integer
|
24
|
-
[INT_NEG_FIXED_START-1-object].pack('C')
|
27
|
+
[INT_NEG_FIXED_START - 1 - object].pack('C')
|
25
28
|
when (-128...128)
|
26
29
|
[CHR_INT1, object].pack('Cc') # 8-bit signed
|
27
|
-
when (-
|
30
|
+
when (-32_768...32_768)
|
28
31
|
[CHR_INT2, object].pack('Cs>') # 16-bit signed
|
29
|
-
when (-
|
32
|
+
when (-2_147_483_648...2_147_483_648)
|
30
33
|
[CHR_INT4, object].pack('Cl>') # 32-bit signed
|
31
|
-
when (-
|
34
|
+
when (-9_223_372_036_854_775_808...9_223_372_036_854_775_808)
|
32
35
|
[CHR_INT8, object].pack('Cq>') # 64-bit signed
|
33
36
|
else # encode as ASCII
|
34
37
|
bytes = object.to_s.bytes
|
35
38
|
|
36
|
-
if bytes.size >= MAX_INT_LENGTH
|
37
|
-
raise EncodingError, "Unable to serialize Fixnum #{object} due to overflow"
|
38
|
-
end
|
39
|
+
raise EncodingError, "Unable to serialize Integer #{object} due to overflow" if bytes.size >= MAX_INT_LENGTH
|
39
40
|
|
40
41
|
[CHR_INT, *bytes, CHR_TERM].pack('C*')
|
41
42
|
end
|
@@ -61,7 +62,7 @@ module Rencoder
|
|
61
62
|
if bytes.size < STR_FIXED_COUNT
|
62
63
|
(STR_FIXED_START + bytes.size).chr + bytes
|
63
64
|
else
|
64
|
-
"#{bytes.bytesize
|
65
|
+
"#{bytes.bytesize}:#{bytes}"
|
65
66
|
end
|
66
67
|
end
|
67
68
|
|
@@ -89,7 +90,7 @@ module Rencoder
|
|
89
90
|
end
|
90
91
|
end
|
91
92
|
|
92
|
-
def encode_nil(
|
93
|
+
def encode_nil(_object)
|
93
94
|
[CHR_NONE].pack('C')
|
94
95
|
end
|
95
96
|
end
|
data/lib/rencoder/version.rb
CHANGED
data/rencoder.gemspec
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'rencoder/version'
|
5
6
|
|
@@ -8,16 +9,18 @@ Gem::Specification.new do |spec|
|
|
8
9
|
spec.version = Rencoder::VERSION
|
9
10
|
spec.authors = ['Igor Yamolov']
|
10
11
|
spec.email = ['clouster@yandex.ru']
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
12
|
+
spec.summary = 'Rencoder is pure Ruby implementation of Rencoder serialization format encoding/decoding.'
|
13
|
+
spec.description = 'Rencoder is implementation of Rencoder encoding/decoding.'
|
13
14
|
spec.homepage = 'https://github.com/t3hk0d3/rencoder'
|
14
15
|
spec.license = 'MIT'
|
16
|
+
spec.required_ruby_version = '>= 2.2' # rubocop:disable Gemspec/RequiredRubyVersion
|
15
17
|
|
16
18
|
spec.files = `git ls-files -z`.split("\x0")
|
17
19
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
20
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
21
|
+
spec.require_paths = ['lib']
|
20
22
|
|
21
|
-
spec.add_development_dependency 'bundler', '~> 1.7'
|
22
23
|
spec.add_development_dependency 'rspec', '~> 3.1.0'
|
24
|
+
spec.add_development_dependency 'rubocop', '~> 0.90'
|
25
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 1.43'
|
23
26
|
end
|
@@ -1,100 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Rencoder::Decoder do
|
4
|
-
|
6
|
+
subject(:decoder) { Rencoder::Coder.new }
|
5
7
|
|
6
|
-
|
8
|
+
include_context 'with serialization_values'
|
7
9
|
|
8
10
|
describe '#decode' do
|
9
11
|
it 'raises EOFError on EOF' do
|
10
|
-
expect
|
11
|
-
|
12
|
-
|
12
|
+
expect do
|
13
|
+
decoder.decode(StringIO.new)
|
14
|
+
end.to raise_error(EOFError)
|
13
15
|
end
|
14
16
|
|
15
17
|
describe 'string' do
|
16
18
|
it 'decode string' do
|
17
|
-
expect(
|
19
|
+
expect(decoder.decode(serialized_string)).to eq('Test')
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'decode empty string' do
|
23
|
+
expect(decoder.decode(serialized_empty_string)).to eq('')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'decode maximum embedded-length type string' do
|
27
|
+
expect(decoder.decode(serialized_63byte_string)).to eq('a' * 63)
|
18
28
|
end
|
19
29
|
|
20
30
|
it 'decode long string' do
|
21
|
-
expect(
|
31
|
+
expect(decoder.decode(serialized_long_string)).to eq('a' * 100)
|
22
32
|
end
|
23
33
|
end
|
24
34
|
|
25
35
|
describe 'integer' do
|
26
36
|
it 'decode positive small integer' do
|
27
|
-
expect(
|
37
|
+
expect(decoder.decode(serialized_positive_integer)).to eq(10)
|
28
38
|
end
|
29
39
|
|
30
40
|
it 'decode negative small integer' do
|
31
|
-
expect(
|
41
|
+
expect(decoder.decode(serialized_negative_integer)).to eq(-10)
|
32
42
|
end
|
33
43
|
|
34
44
|
it 'decode 8-bit integer' do
|
35
|
-
expect(
|
45
|
+
expect(decoder.decode(serialized_8bit_integer)).to eq(100)
|
36
46
|
end
|
37
47
|
|
38
48
|
it 'decode 16-bit integer' do
|
39
|
-
expect(
|
49
|
+
expect(decoder.decode(serialized_16bit_integer)).to eq(5000)
|
40
50
|
end
|
41
51
|
|
42
52
|
it 'decode 32-bit integer' do
|
43
|
-
expect(
|
53
|
+
expect(decoder.decode(serialized_32bit_integer)).to eq(50_000)
|
44
54
|
end
|
45
55
|
|
46
56
|
it 'decode 64-bit integer' do
|
47
|
-
expect(
|
57
|
+
expect(decoder.decode(serialized_64bit_integer)).to eq(5_000_000_000)
|
48
58
|
end
|
49
59
|
|
50
60
|
it 'decode big ascii integer' do
|
51
|
-
expect(
|
61
|
+
expect(decoder.decode(serialized_big_integer)).to eq(50_000_000_000_000_000_000)
|
52
62
|
end
|
53
63
|
end
|
54
64
|
|
55
65
|
describe 'float' do
|
56
66
|
it 'decode 32-bit float' do
|
57
|
-
expect(
|
67
|
+
expect(decoder.decode(serialized_32bit_float)).to eq(100.0)
|
58
68
|
end
|
59
69
|
|
60
70
|
it 'decode 64-bit float' do
|
61
|
-
expect(
|
71
|
+
expect(decoder.decode(serialized_float)).to eq(100.0001)
|
62
72
|
end
|
63
73
|
end
|
64
74
|
|
65
75
|
describe 'boolean' do
|
66
76
|
it 'decode true boolean' do
|
67
|
-
expect(
|
77
|
+
expect(decoder.decode(serialized_true)).to eq(true)
|
68
78
|
end
|
69
79
|
|
70
80
|
it 'decode false boolean' do
|
71
|
-
expect(
|
81
|
+
expect(decoder.decode(serialized_false)).to eq(false)
|
72
82
|
end
|
73
83
|
end
|
74
84
|
|
75
85
|
describe 'nil' do
|
76
86
|
it 'decode nil' do
|
77
|
-
expect(
|
87
|
+
expect(decoder.decode(serialized_nil)).to eq(nil)
|
78
88
|
end
|
79
89
|
end
|
80
90
|
|
81
91
|
describe 'array' do
|
92
|
+
it 'decode empty array' do
|
93
|
+
expect(decoder.decode(serialized_empty_array)).to eq([])
|
94
|
+
end
|
95
|
+
|
82
96
|
it 'decode small array' do
|
83
|
-
expect(
|
97
|
+
expect(decoder.decode(serialized_array)).to eq(['Test', 100, 100.0001, nil])
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'decode maximum embedded length type array' do
|
101
|
+
expect(decoder.decode(serialized_63_element_array)).to eq(63.times.to_a)
|
84
102
|
end
|
85
103
|
|
86
104
|
it 'decode big array' do
|
87
|
-
expect(
|
105
|
+
expect(decoder.decode(serialized_big_array)).to eq(100.times.to_a)
|
88
106
|
end
|
89
107
|
end
|
90
108
|
|
91
109
|
describe 'hash' do
|
92
110
|
it 'decode small hash' do
|
93
|
-
expect(
|
111
|
+
expect(decoder.decode(serialized_hash)).to eq({ 'test' => 123, 'hello' => 'world' })
|
94
112
|
end
|
95
113
|
|
96
114
|
it 'decode big hash' do
|
97
|
-
expect(
|
115
|
+
expect(decoder.decode(serialized_big_hash)).to eq(Hash[100.times.map { |i| [i, i.chr] }])
|
98
116
|
end
|
99
117
|
end
|
100
118
|
end
|
@@ -1,135 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Rencoder::Encoder do
|
4
|
-
|
6
|
+
subject(:encoder) { Rencoder::Coder.new }
|
5
7
|
|
6
|
-
|
8
|
+
include_context 'with serialization_values'
|
7
9
|
|
8
10
|
describe '#encode' do
|
9
11
|
it 'encode string' do
|
10
|
-
expect(
|
12
|
+
expect(encoder.encode('Test')).to eq(serialized_string)
|
11
13
|
end
|
12
14
|
|
13
15
|
it 'encode symbol' do
|
14
|
-
expect(
|
16
|
+
expect(encoder.encode(:test)).to eq(serialized_symbol)
|
15
17
|
end
|
16
18
|
|
17
19
|
it 'encode integer' do
|
18
|
-
expect(
|
20
|
+
expect(encoder.encode(100)).to eq(serialized_integer)
|
19
21
|
end
|
20
22
|
|
21
23
|
it 'encode float' do
|
22
|
-
expect(
|
24
|
+
expect(encoder.encode(100.0001)).to eq(serialized_float)
|
23
25
|
end
|
24
26
|
|
25
27
|
it 'encode boolean' do
|
26
|
-
expect(
|
28
|
+
expect(encoder.encode(false)).to eq(serialized_false)
|
27
29
|
end
|
28
30
|
|
29
31
|
it 'encode nil' do
|
30
|
-
expect(
|
32
|
+
expect(encoder.encode(nil)).to eq(serialized_nil)
|
31
33
|
end
|
32
34
|
|
33
35
|
it 'encode array' do
|
34
|
-
expect(
|
36
|
+
expect(encoder.encode(['Test', 100, 100.0001, nil])).to eq(serialized_array)
|
35
37
|
end
|
36
38
|
|
37
39
|
it 'encode hash' do
|
38
|
-
expect(
|
40
|
+
expect(encoder.encode({ test: 123, hello: 'world' })).to eq(serialized_hash)
|
39
41
|
end
|
40
42
|
|
41
43
|
it 'raise exception for non-serializable object' do
|
42
|
-
expect {
|
44
|
+
expect { encoder.encode(Object.new) }.to raise_error(Rencoder::Encoder::EncodingError)
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
46
48
|
describe '#encode_string' do
|
47
49
|
it 'encode small strings' do
|
48
|
-
expect(
|
50
|
+
expect(encoder.encode_string('Test')).to eq(serialized_string)
|
49
51
|
end
|
50
52
|
|
51
53
|
it 'encode big strings' do
|
52
|
-
expect(
|
54
|
+
expect(encoder.encode_string('a' * 100)).to eq(serialized_long_string)
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
58
|
describe '#encode_integer' do
|
57
59
|
it 'encode small positive number' do
|
58
|
-
expect(
|
60
|
+
expect(encoder.encode_integer(10)).to eq(serialized_positive_integer)
|
59
61
|
end
|
60
62
|
|
61
63
|
it 'encode small negative number' do
|
62
|
-
expect(
|
64
|
+
expect(encoder.encode_integer(-10)).to eq(serialized_negative_integer)
|
63
65
|
end
|
64
66
|
|
65
67
|
it 'encode 8-bit integer' do
|
66
|
-
expect(
|
68
|
+
expect(encoder.encode_integer(100)).to eq(serialized_8bit_integer)
|
67
69
|
end
|
68
70
|
|
69
71
|
it 'encode 16-bit integer' do
|
70
|
-
expect(
|
72
|
+
expect(encoder.encode_integer(5000)).to eq(serialized_16bit_integer)
|
71
73
|
end
|
72
74
|
|
73
75
|
it 'encode 32-bit integer' do
|
74
|
-
expect(
|
76
|
+
expect(encoder.encode_integer(50_000)).to eq(serialized_32bit_integer)
|
75
77
|
end
|
76
78
|
|
77
79
|
it 'encode 64-bit integer' do
|
78
|
-
expect(
|
80
|
+
expect(encoder.encode_integer(5_000_000_000)).to eq(serialized_64bit_integer)
|
79
81
|
end
|
80
82
|
|
81
83
|
it 'encode big integer as ascii' do
|
82
|
-
expect(
|
84
|
+
expect(encoder.encode_integer(50_000_000_000_000_000_000)).to eq(serialized_big_integer)
|
83
85
|
end
|
84
86
|
|
85
87
|
it 'raise error for super-big integers' do
|
86
88
|
expect do
|
87
|
-
|
89
|
+
encoder.encode_integer(128.times.map { '9' }.join.to_i)
|
88
90
|
end.to raise_error(Rencoder::Encoder::EncodingError)
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
92
94
|
describe '#encode_float' do
|
93
95
|
it 'encode 64-bit float' do
|
94
|
-
expect(
|
96
|
+
expect(encoder.encode_float(100.0001)).to eq(serialized_float)
|
95
97
|
end
|
96
98
|
end
|
97
99
|
|
98
100
|
describe '#encode_boolean' do
|
99
101
|
it 'encode true boolean' do
|
100
|
-
expect(
|
102
|
+
expect(encoder.encode_boolean(true)).to eq(serialized_true)
|
101
103
|
end
|
102
104
|
|
103
105
|
it 'encode false boolean' do
|
104
|
-
expect(
|
106
|
+
expect(encoder.encode_boolean(false)).to eq(serialized_false)
|
105
107
|
end
|
106
108
|
end
|
107
109
|
|
108
110
|
describe '#encode_nil' do
|
109
111
|
it 'encode nil' do
|
110
|
-
expect(
|
112
|
+
expect(encoder.encode_nil(nil)).to eq(serialized_nil)
|
111
113
|
end
|
112
114
|
end
|
113
115
|
|
114
116
|
describe '#encode_array' do
|
115
117
|
it 'encode small-sized array' do
|
116
|
-
expect(
|
118
|
+
expect(encoder.encode_array(['Test', 100, 100.0001, nil])).to eq(serialized_array)
|
117
119
|
end
|
118
120
|
|
119
121
|
it 'encode big-sized array' do
|
120
|
-
expect(
|
122
|
+
expect(encoder.encode_array(100.times.to_a)).to eq(serialized_big_array)
|
121
123
|
end
|
122
124
|
end
|
123
125
|
|
124
126
|
describe '#encode_hash' do
|
125
127
|
it 'encode small-sized hash' do
|
126
|
-
expect(
|
128
|
+
expect(encoder.encode_hash({ test: 123, hello: 'world' })).to eq(serialized_hash)
|
127
129
|
end
|
128
130
|
|
129
131
|
it 'encode big-sized hash' do
|
130
132
|
hash = Hash[100.times.map { |i| [i, i.chr] }]
|
131
133
|
|
132
|
-
expect(
|
134
|
+
expect(encoder.encode_hash(hash)).to eq(serialized_big_hash)
|
133
135
|
end
|
134
136
|
end
|
135
137
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
|
2
4
|
|
3
5
|
require 'rspec'
|
4
6
|
require 'rencoder'
|
5
7
|
|
6
8
|
require 'base64'
|
7
9
|
|
8
|
-
shared_context 'serialization_values' do
|
9
|
-
|
10
|
+
shared_context 'with serialization_values' do # rubocop:disable RSpec/MultipleMemoizedHelpers
|
10
11
|
# Values encoded using original Python code
|
11
12
|
|
12
13
|
# Integers
|
@@ -41,8 +42,14 @@ shared_context 'serialization_values' do
|
|
41
42
|
# :test (symbol)
|
42
43
|
let(:serialized_symbol) { Base64.decode64('hHRlc3Q=') }
|
43
44
|
|
45
|
+
# ''
|
46
|
+
let(:serialized_empty_string) { Base64.decode64("gA==\n") }
|
47
|
+
|
48
|
+
# maximum embedded-length string type ('a' * 63)
|
49
|
+
let(:serialized_63byte_string) { "\xBF#{'a' * 63}" }
|
50
|
+
|
44
51
|
# 'a' * 100
|
45
|
-
let(:serialized_long_string) {
|
52
|
+
let(:serialized_long_string) { "100:#{'a' * 100}" }
|
46
53
|
|
47
54
|
# Booleans
|
48
55
|
# true
|
@@ -61,12 +68,20 @@ shared_context 'serialization_values' do
|
|
61
68
|
let(:serialized_nil) { 69.chr }
|
62
69
|
|
63
70
|
# Array
|
71
|
+
# []
|
72
|
+
let(:serialized_empty_array) { "\xC0" }
|
73
|
+
|
64
74
|
# ["Test", 100, 100.0001, nil]
|
65
75
|
let(:serialized_array) { Base64.decode64('xIRUZXN0PmQsQFkAAaNuLrJF') }
|
66
76
|
|
77
|
+
# maximum embedded-length array type (63.times.to_a)
|
78
|
+
let(:serialized_63_element_array) do
|
79
|
+
Base64.decode64("/z4APgE+Aj4DPgQ+BT4GPgc+CD4JPgo+Cz4MPg0+Dj4PPhA+ET4SPhM+FD4V\nPhY+Fz4YPhk+Gj4bPhw+HT4ePh8+ID4hPiI+Iz4kPiU+Jj4nPig+KT4qPis+\nLD4tPi4+Lz4wPjE+Mj4zPjQ+NT42Pjc+OD45Pjo+Oz48Pj0+Pg==\n") # rubocop:disable Layout/LineLength
|
80
|
+
end
|
81
|
+
|
67
82
|
# big array (100.times.to_a)
|
68
83
|
let(:serialized_big_array) do
|
69
|
-
Base64.decode64('OwABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorPiw+LT4uPi8+MD4xPjI+Mz40PjU+Nj43Pjg+OT46Pjs+PD49Pj4+Pz5APkE+Qj5DPkQ+RT5GPkc+SD5JPko+Sz5MPk0+Tj5PPlA+UT5SPlM+VD5VPlY+Vz5YPlk+Wj5bPlw+XT5ePl8+YD5hPmI+Y38=')
|
84
|
+
Base64.decode64('OwABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorPiw+LT4uPi8+MD4xPjI+Mz40PjU+Nj43Pjg+OT46Pjs+PD49Pj4+Pz5APkE+Qj5DPkQ+RT5GPkc+SD5JPko+Sz5MPk0+Tj5PPlA+UT5SPlM+VD5VPlY+Vz5YPlk+Wj5bPlw+XT5ePl8+YD5hPmI+Y38=') # rubocop:disable Layout/LineLength
|
70
85
|
end
|
71
86
|
|
72
87
|
# Hash
|
@@ -75,6 +90,6 @@ shared_context 'serialization_values' do
|
|
75
90
|
|
76
91
|
# big hash (Hash[100.times.map { |i| [i, i.chr] }])
|
77
92
|
let(:serialized_big_hash) do
|
78
|
-
Base64.decode64('PACBAAGBAQKBAgOBAwSBBAWBBQaBBgeBBwiBCAmBCQqBCguBCwyBDA2BDQ6BDg+BDxCBEBGBERKBEhOBExSBFBWBFRaBFheBFxiBGBmBGRqBGhuBGxyBHB2BHR6BHh+BHyCBICGBISKBIiOBIySBJCWBJSaBJieBJyiBKCmBKSqBKiuBKz4sgSw+LYEtPi6BLj4vgS8+MIEwPjGBMT4ygTI+M4EzPjSBND41gTU+NoE2PjeBNz44gTg+OYE5PjqBOj47gTs+PIE8Pj2BPT4+gT4+P4E/PkCBQD5BgUE+QoFCPkOBQz5EgUQ+RYFFPkaBRj5HgUc+SIFIPkmBST5KgUo+S4FLPkyBTD5NgU0+ToFOPk+BTz5QgVA+UYFRPlKBUj5TgVM+VIFUPlWBVT5WgVY+V4FXPliBWD5ZgVk+WoFaPluBWz5cgVw+XYFdPl6BXj5fgV8+YIFgPmGBYT5igWI+Y4Fjfw==')
|
93
|
+
Base64.decode64('PACBAAGBAQKBAgOBAwSBBAWBBQaBBgeBBwiBCAmBCQqBCguBCwyBDA2BDQ6BDg+BDxCBEBGBERKBEhOBExSBFBWBFRaBFheBFxiBGBmBGRqBGhuBGxyBHB2BHR6BHh+BHyCBICGBISKBIiOBIySBJCWBJSaBJieBJyiBKCmBKSqBKiuBKz4sgSw+LYEtPi6BLj4vgS8+MIEwPjGBMT4ygTI+M4EzPjSBND41gTU+NoE2PjeBNz44gTg+OYE5PjqBOj47gTs+PIE8Pj2BPT4+gT4+P4E/PkCBQD5BgUE+QoFCPkOBQz5EgUQ+RYFFPkaBRj5HgUc+SIFIPkmBST5KgUo+S4FLPkyBTD5NgU0+ToFOPk+BTz5QgVA+UYFRPlKBUj5TgVM+VIFUPlWBVT5WgVY+V4FXPliBWD5ZgVk+WoFaPluBWz5cgVw+XYFdPl6BXj5fgV8+YIFgPmGBYT5igWI+Y4Fjfw==') # rubocop:disable Layout/LineLength
|
79
94
|
end
|
80
95
|
end
|
metadata
CHANGED
@@ -1,43 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rencoder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Igor Yamolov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rspec
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 3.1.0
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 3.1.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rubocop
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '0.90'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '0.90'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop-rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.43'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.43'
|
41
55
|
description: Rencoder is implementation of Rencoder encoding/decoding.
|
42
56
|
email:
|
43
57
|
- clouster@yandex.ru
|
@@ -45,7 +59,10 @@ executables: []
|
|
45
59
|
extensions: []
|
46
60
|
extra_rdoc_files: []
|
47
61
|
files:
|
62
|
+
- ".github/workflows/gem-push.yml"
|
63
|
+
- ".github/workflows/on_push.yml"
|
48
64
|
- ".gitignore"
|
65
|
+
- ".rubocop.yml"
|
49
66
|
- ".ruby-version"
|
50
67
|
- Gemfile
|
51
68
|
- LICENSE.txt
|
@@ -71,15 +88,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
71
88
|
requirements:
|
72
89
|
- - ">="
|
73
90
|
- !ruby/object:Gem::Version
|
74
|
-
version: '
|
91
|
+
version: '2.2'
|
75
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
93
|
requirements:
|
77
94
|
- - ">="
|
78
95
|
- !ruby/object:Gem::Version
|
79
96
|
version: '0'
|
80
97
|
requirements: []
|
81
|
-
|
82
|
-
rubygems_version: 2.2.2
|
98
|
+
rubygems_version: 3.0.3
|
83
99
|
signing_key:
|
84
100
|
specification_version: 4
|
85
101
|
summary: Rencoder is pure Ruby implementation of Rencoder serialization format encoding/decoding.
|
@@ -87,4 +103,3 @@ test_files:
|
|
87
103
|
- spec/rencoder/decoder_spec.rb
|
88
104
|
- spec/rencoder/encoder_spec.rb
|
89
105
|
- spec/spec_helper.rb
|
90
|
-
has_rdoc:
|