feedx 0.9.0 → 0.11.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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +12 -10
- data/Gemfile.lock +44 -21
- data/Makefile +5 -0
- data/consumer_test.go +5 -5
- data/feedx.gemspec +3 -2
- data/feedx_test.go +13 -13
- data/format.go +16 -16
- data/format_test.go +6 -7
- data/go.mod +6 -11
- data/go.sum +47 -28
- data/internal/testdata/testdata.pb.go +124 -0
- data/internal/testdata/testdata.proto +15 -0
- data/lib/feedx/compression.rb +11 -4
- data/lib/feedx/compression/abstract.rb +2 -2
- data/lib/feedx/compression/gzip.rb +14 -2
- data/lib/feedx/compression/none.rb +4 -4
- data/lib/feedx/consumer.rb +4 -4
- data/lib/feedx/format.rb +15 -9
- data/lib/feedx/format/abstract.rb +42 -13
- data/lib/feedx/format/json.rb +12 -8
- data/lib/feedx/format/parquet.rb +102 -0
- data/lib/feedx/format/protobuf.rb +16 -8
- data/lib/feedx/producer.rb +6 -5
- data/lib/feedx/stream.rb +17 -21
- data/producer.go +4 -11
- data/producer_test.go +16 -6
- data/reader_test.go +7 -8
- data/spec/feedx/compression/gzip_spec.rb +4 -2
- data/spec/feedx/compression/none_spec.rb +2 -2
- data/spec/feedx/compression_spec.rb +9 -9
- data/spec/feedx/consumer_spec.rb +6 -3
- data/spec/feedx/format/abstract_spec.rb +11 -8
- data/spec/feedx/format/json_spec.rb +12 -11
- data/spec/feedx/format/parquet_spec.rb +30 -0
- data/spec/feedx/format/protobuf_spec.rb +12 -11
- data/spec/feedx/format_spec.rb +8 -8
- data/spec/feedx/stream_spec.rb +20 -1
- data/spec/spec_helper.rb +17 -1
- data/writer.go +20 -15
- data/writer_test.go +3 -5
- metadata +22 -3
@@ -1,22 +1,23 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe Feedx::Format::Protobuf do
|
4
|
-
subject { described_class.new(wio) }
|
5
4
|
let(:wio) { StringIO.new }
|
5
|
+
let(:rio) { StringIO.open(wio.string) }
|
6
6
|
|
7
7
|
it 'should encode/decode' do
|
8
|
-
subject.
|
9
|
-
|
10
|
-
|
8
|
+
subject.encoder wio do |enc|
|
9
|
+
enc.encode(Feedx::TestCase::Model.new('X'))
|
10
|
+
enc.encode(Feedx::TestCase::Model.new('Y'))
|
11
|
+
enc.encode(Feedx::TestCase::Message.new(title: 'Z'))
|
12
|
+
end
|
11
13
|
expect(wio.string.bytes).to eq([3, 10, 1, 88] + [3, 10, 1, 89] + [3, 10, 1, 90])
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
expect(
|
16
|
-
expect(
|
17
|
-
expect(
|
18
|
-
expect(
|
19
|
-
expect(fmt).to be_eof
|
15
|
+
subject.decoder rio do |dec|
|
16
|
+
expect(dec.decode(Feedx::TestCase::Message)).to eq(Feedx::TestCase::Message.new(title: 'X'))
|
17
|
+
expect(dec.decode(Feedx::TestCase::Message)).to eq(Feedx::TestCase::Message.new(title: 'Y'))
|
18
|
+
expect(dec.decode(Feedx::TestCase::Message)).to eq(Feedx::TestCase::Message.new(title: 'Z'))
|
19
|
+
expect(dec.decode(Feedx::TestCase::Message)).to be_nil
|
20
|
+
expect(dec).to be_eof
|
20
21
|
end
|
21
22
|
end
|
22
23
|
end
|
data/spec/feedx/format_spec.rb
CHANGED
@@ -2,18 +2,18 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe Feedx::Format do
|
4
4
|
it 'should resolve' do
|
5
|
-
expect(described_class.resolve(:json)).to
|
6
|
-
expect(described_class.resolve(:pb)).to
|
5
|
+
expect(described_class.resolve(:json)).to be_instance_of(described_class::JSON)
|
6
|
+
expect(described_class.resolve(:pb)).to be_instance_of(described_class::Protobuf)
|
7
7
|
expect { described_class.resolve(:txt) }.to raise_error(/invalid format txt/)
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'should detect' do
|
11
|
-
expect(described_class.detect('path/to/file.json')).to
|
12
|
-
expect(described_class.detect('path/to/file.jsonz')).to
|
13
|
-
expect(described_class.detect('path/to/file.json.gz')).to
|
14
|
-
expect(described_class.detect('path/to/file.pb')).to
|
15
|
-
expect(described_class.detect('path/to/file.pbz')).to
|
16
|
-
expect(described_class.detect('path/to/file.pb.z')).to
|
11
|
+
expect(described_class.detect('path/to/file.json')).to be_instance_of(described_class::JSON)
|
12
|
+
expect(described_class.detect('path/to/file.jsonz')).to be_instance_of(described_class::JSON)
|
13
|
+
expect(described_class.detect('path/to/file.json.gz')).to be_instance_of(described_class::JSON)
|
14
|
+
expect(described_class.detect('path/to/file.pb')).to be_instance_of(described_class::Protobuf)
|
15
|
+
expect(described_class.detect('path/to/file.pbz')).to be_instance_of(described_class::Protobuf)
|
16
|
+
expect(described_class.detect('path/to/file.pb.z')).to be_instance_of(described_class::Protobuf)
|
17
17
|
expect do
|
18
18
|
described_class.detect('path/to/file.txt')
|
19
19
|
end.to raise_error(/unable to detect format/)
|
data/spec/feedx/stream_spec.rb
CHANGED
@@ -13,13 +13,32 @@ RSpec.describe Feedx::Stream do
|
|
13
13
|
end.to raise_error(/unable to detect format/)
|
14
14
|
end
|
15
15
|
|
16
|
+
it 'should accept custom formats' do
|
17
|
+
format = Class.new do
|
18
|
+
def encoder(io, &block)
|
19
|
+
Feedx::Format::JSON::Encoder.open(io, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def decoder(io, &block)
|
23
|
+
Feedx::Format::JSON::Decoder.open(io, &block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
stream = described_class.new('mock:///dir/file.txt', format: format.new)
|
28
|
+
stream.create {|s| s.encode Feedx::TestCase::Model.new('X') }
|
29
|
+
|
30
|
+
expect(bucket.read('dir/file.txt')).to eq(
|
31
|
+
%({"title":"X","updated_at":"2018-01-05 11:25:15 UTC"}\n),
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
16
35
|
it 'should encode' do
|
17
36
|
subject.create do |s|
|
18
37
|
s.encode(Feedx::TestCase::Model.new('X'))
|
19
38
|
s.encode(Feedx::TestCase::Model.new('Y'))
|
20
39
|
end
|
21
40
|
|
22
|
-
expect(bucket.
|
41
|
+
expect(bucket.read('dir/file.json')).to eq(
|
23
42
|
%({"title":"X","updated_at":"2018-01-05 11:25:15 UTC"}\n) +
|
24
43
|
%({"title":"Y","updated_at":"2018-01-05 11:25:15 UTC"}\n),
|
25
44
|
)
|
data/spec/spec_helper.rb
CHANGED
@@ -28,13 +28,29 @@ module Feedx
|
|
28
28
|
end
|
29
29
|
alias eql? ==
|
30
30
|
|
31
|
+
def updated_at
|
32
|
+
Time.at(1515151515).utc
|
33
|
+
end
|
34
|
+
|
31
35
|
def from_json(data, *)
|
32
36
|
hash = ::JSON.parse(data)
|
33
37
|
@title = hash['title'] if hash.is_a?(Hash)
|
34
38
|
end
|
35
39
|
|
36
40
|
def to_json(*)
|
37
|
-
::JSON.dump(title: @title, updated_at:
|
41
|
+
::JSON.dump(title: @title, updated_at: updated_at)
|
42
|
+
end
|
43
|
+
|
44
|
+
def from_parquet(rec)
|
45
|
+
rec.each_pair do |name, value|
|
46
|
+
@title = value if name == 'title'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_parquet(schema, *)
|
51
|
+
schema.fields.map do |field|
|
52
|
+
send(field.name)
|
53
|
+
end
|
38
54
|
end
|
39
55
|
end
|
40
56
|
end
|
data/writer.go
CHANGED
@@ -39,33 +39,29 @@ func (o *WriterOptions) norm(name string) {
|
|
39
39
|
// Writer encodes feeds to remote locations.
|
40
40
|
type Writer struct {
|
41
41
|
ctx context.Context
|
42
|
-
cancel context.CancelFunc
|
43
|
-
|
44
42
|
remote *bfs.Object
|
45
43
|
opt WriterOptions
|
46
44
|
num int
|
47
45
|
|
48
|
-
bw
|
46
|
+
bw bfs.Writer
|
49
47
|
cw io.WriteCloser // compression writer
|
50
48
|
ww *bufio.Writer
|
51
49
|
fe FormatEncoder
|
52
50
|
}
|
53
51
|
|
54
52
|
// NewWriter inits a new feed writer.
|
55
|
-
func NewWriter(ctx context.Context, remote *bfs.Object, opt *WriterOptions)
|
53
|
+
func NewWriter(ctx context.Context, remote *bfs.Object, opt *WriterOptions) *Writer {
|
56
54
|
var o WriterOptions
|
57
55
|
if opt != nil {
|
58
56
|
o = *opt
|
59
57
|
}
|
60
58
|
o.norm(remote.Name())
|
61
59
|
|
62
|
-
ctx, cancel := context.WithCancel(ctx)
|
63
60
|
return &Writer{
|
64
61
|
ctx: ctx,
|
65
|
-
cancel: cancel,
|
66
62
|
remote: remote,
|
67
63
|
opt: o,
|
68
|
-
}
|
64
|
+
}
|
69
65
|
}
|
70
66
|
|
71
67
|
// Write write raw bytes to the feed.
|
@@ -113,13 +109,27 @@ func (w *Writer) NumWritten() int {
|
|
113
109
|
|
114
110
|
// Discard closes the writer and discards the contents.
|
115
111
|
func (w *Writer) Discard() error {
|
116
|
-
w.
|
117
|
-
|
112
|
+
err := w.close()
|
113
|
+
if w.bw != nil {
|
114
|
+
if e := w.bw.Discard(); e != nil {
|
115
|
+
err = e
|
116
|
+
}
|
117
|
+
}
|
118
|
+
return err
|
118
119
|
}
|
119
120
|
|
120
121
|
// Commit closes the writer and persists the contents.
|
121
122
|
func (w *Writer) Commit() error {
|
122
|
-
|
123
|
+
err := w.close()
|
124
|
+
if w.bw != nil {
|
125
|
+
if e := w.bw.Commit(); e != nil {
|
126
|
+
err = e
|
127
|
+
}
|
128
|
+
}
|
129
|
+
return err
|
130
|
+
}
|
131
|
+
|
132
|
+
func (w *Writer) close() (err error) {
|
123
133
|
if w.fe != nil {
|
124
134
|
if e := w.fe.Close(); e != nil {
|
125
135
|
err = e
|
@@ -135,11 +145,6 @@ func (w *Writer) Commit() error {
|
|
135
145
|
err = e
|
136
146
|
}
|
137
147
|
}
|
138
|
-
if w.bw != nil {
|
139
|
-
if e := w.bw.Close(); e != nil {
|
140
|
-
err = e
|
141
|
-
}
|
142
|
-
}
|
143
148
|
return err
|
144
149
|
}
|
145
150
|
|
data/writer_test.go
CHANGED
@@ -21,10 +21,9 @@ var _ = Describe("Writer", func() {
|
|
21
21
|
})
|
22
22
|
|
23
23
|
It("should write plain", func() {
|
24
|
-
w
|
24
|
+
w := feedx.NewWriter(context.Background(), plain, &feedx.WriterOptions{
|
25
25
|
LastMod: time.Unix(1515151515, 123456789),
|
26
26
|
})
|
27
|
-
Expect(err).NotTo(HaveOccurred())
|
28
27
|
defer w.Discard()
|
29
28
|
|
30
29
|
Expect(w.Write(bytes.Repeat([]byte{'x'}, 10000))).To(Equal(10000))
|
@@ -37,10 +36,9 @@ var _ = Describe("Writer", func() {
|
|
37
36
|
})
|
38
37
|
|
39
38
|
It("should write compressed", func() {
|
40
|
-
w
|
39
|
+
w := feedx.NewWriter(context.Background(), compressed, &feedx.WriterOptions{
|
41
40
|
LastMod: time.Unix(1515151515, 123456789),
|
42
41
|
})
|
43
|
-
Expect(err).NotTo(HaveOccurred())
|
44
42
|
defer w.Discard()
|
45
43
|
|
46
44
|
Expect(w.Write(bytes.Repeat([]byte{'x'}, 10000))).To(Equal(10000))
|
@@ -58,7 +56,7 @@ var _ = Describe("Writer", func() {
|
|
58
56
|
|
59
57
|
info, err := plain.Head(ctx)
|
60
58
|
Expect(err).NotTo(HaveOccurred())
|
61
|
-
Expect(info.Size).To(BeNumerically("~",
|
59
|
+
Expect(info.Size).To(BeNumerically("~", 370, 10))
|
62
60
|
Expect(info.Metadata).To(Equal(bfs.Metadata{"X-Feedx-Last-Modified": "1515151515123"}))
|
63
61
|
|
64
62
|
info, err = compressed.Head(ctx)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feedx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Black Square Media Ltd
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bfs
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: red-parquet
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rspec
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +150,8 @@ files:
|
|
136
150
|
- format_test.go
|
137
151
|
- go.mod
|
138
152
|
- go.sum
|
153
|
+
- internal/testdata/testdata.pb.go
|
154
|
+
- internal/testdata/testdata.proto
|
139
155
|
- lib/feedx.rb
|
140
156
|
- lib/feedx/cache.rb
|
141
157
|
- lib/feedx/cache/abstract.rb
|
@@ -149,6 +165,7 @@ files:
|
|
149
165
|
- lib/feedx/format.rb
|
150
166
|
- lib/feedx/format/abstract.rb
|
151
167
|
- lib/feedx/format/json.rb
|
168
|
+
- lib/feedx/format/parquet.rb
|
152
169
|
- lib/feedx/format/protobuf.rb
|
153
170
|
- lib/feedx/producer.rb
|
154
171
|
- lib/feedx/pusher.rb
|
@@ -165,6 +182,7 @@ files:
|
|
165
182
|
- spec/feedx/consumer_spec.rb
|
166
183
|
- spec/feedx/format/abstract_spec.rb
|
167
184
|
- spec/feedx/format/json_spec.rb
|
185
|
+
- spec/feedx/format/parquet_spec.rb
|
168
186
|
- spec/feedx/format/protobuf_spec.rb
|
169
187
|
- spec/feedx/format_spec.rb
|
170
188
|
- spec/feedx/producer_spec.rb
|
@@ -191,7 +209,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
209
|
- !ruby/object:Gem::Version
|
192
210
|
version: '0'
|
193
211
|
requirements: []
|
194
|
-
rubygems_version: 3.
|
212
|
+
rubygems_version: 3.1.4
|
195
213
|
signing_key:
|
196
214
|
specification_version: 4
|
197
215
|
summary: Exchange data between components via feeds
|
@@ -204,6 +222,7 @@ test_files:
|
|
204
222
|
- spec/feedx/consumer_spec.rb
|
205
223
|
- spec/feedx/format/abstract_spec.rb
|
206
224
|
- spec/feedx/format/json_spec.rb
|
225
|
+
- spec/feedx/format/parquet_spec.rb
|
207
226
|
- spec/feedx/format/protobuf_spec.rb
|
208
227
|
- spec/feedx/format_spec.rb
|
209
228
|
- spec/feedx/producer_spec.rb
|