rencoder 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|