feedx 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c601b31c975bf931998f4c498b86f4e0308be42d0064b9d138d64dc58f2ddb4e
4
- data.tar.gz: ab223f06c6b9f9bf6c5b000f1268ded7a86e10e36715d43628bb19d08ac7809f
3
+ metadata.gz: 7d1c12376b32188b646923935967905bb97ab8c86dde28236a0341ee878eb631
4
+ data.tar.gz: 3c76d4356a0f6aafcad0e8ea37a2159f8170f5d1cea4072753e3c9947afd7613
5
5
  SHA512:
6
- metadata.gz: e5200ae2328cb6353f1262639aca392cc09f18e30f9023c8db9da5e81e7236cb00bb07b543b660497d7c98d5368dfe24f8dbc410ac5234ef82ce270d0cc253d9
7
- data.tar.gz: 940fe6bf7295e7b24dc71cea752fa2850ed1fc0dac736559f8289f93704690393ca81e216d222385eb33e5674709d06c82ff108ee10e8dad8b6bf6f57e97ed51
6
+ metadata.gz: d55b8ee3620301c3ffc5c95d2895d00f54ee562250c4aa8236ed93fd99e552cd67c126feab4a17b063415518e46b113ef918491b19e37043b5d36fa9e09c2808
7
+ data.tar.gz: b8eee064c4e12e462097087431cdd9b435720eead2d7524c9cc7d44cb4a7dde410756f443b71cd5b24261d3b06c95f1d3975ddca6b6ff69692e0e9a77a742446
data/.travis.yml CHANGED
@@ -1,4 +1,13 @@
1
- language: ruby
2
- rvm:
3
- - 2.5
4
- - 2.4
1
+ matrix:
2
+ include:
3
+ - language: ruby
4
+ rvm:
5
+ - 2.5
6
+ - language: ruby
7
+ rvm:
8
+ - 2.4
9
+ - language: go
10
+ go:
11
+ - 1.11.x
12
+ env:
13
+ - GO111MODULE=on
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- feedx (0.3.1)
4
+ feedx (0.3.2)
5
5
  bfs (>= 0.3.4)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  ast (2.4.0)
11
- bfs (0.3.4)
11
+ bfs (0.3.6)
12
12
  diff-lcs (1.3)
13
13
  google-protobuf (3.6.1)
14
14
  jaro_winkler (1.5.1)
@@ -19,7 +19,7 @@ GEM
19
19
  google-protobuf
20
20
  powerpack (0.1.2)
21
21
  rainbow (3.0.0)
22
- rake (12.3.1)
22
+ rake (12.3.2)
23
23
  rspec (3.8.0)
24
24
  rspec-core (~> 3.8.0)
25
25
  rspec-expectations (~> 3.8.0)
@@ -33,7 +33,7 @@ GEM
33
33
  diff-lcs (>= 1.2.0, < 2.0)
34
34
  rspec-support (~> 3.8.0)
35
35
  rspec-support (3.8.0)
36
- rubocop (0.60.0)
36
+ rubocop (0.61.1)
37
37
  jaro_winkler (~> 1.5.1)
38
38
  parallel (~> 1.10)
39
39
  parser (>= 2.5, != 2.5.1.1)
@@ -56,4 +56,4 @@ DEPENDENCIES
56
56
  rubocop
57
57
 
58
58
  BUNDLED WITH
59
- 1.16.4
59
+ 1.17.2
data/Makefile ADDED
@@ -0,0 +1,7 @@
1
+ default: vet test
2
+
3
+ test:
4
+ go test ./...
5
+
6
+ vet:
7
+ go vet ./...
data/compression.go ADDED
@@ -0,0 +1,63 @@
1
+ package feedx
2
+
3
+ import (
4
+ "compress/gzip"
5
+ "io"
6
+ "path"
7
+ )
8
+
9
+ // Compression represents the data compression.
10
+ type Compression interface {
11
+ // NewReader wraps a reader.
12
+ NewReader(io.Reader) (io.ReadCloser, error)
13
+ // NewWriter wraps a writer.
14
+ NewWriter(io.Writer) (io.WriteCloser, error)
15
+ }
16
+
17
+ // DetectCompression detects the compression type from a URL path or file name.
18
+ func DetectCompression(name string) Compression {
19
+ if name != "" {
20
+ ext := path.Ext(path.Base(name))
21
+ if ext != "" && ext[0] == '.' && ext[len(ext)-1] == 'z' {
22
+ return GZipCompression
23
+ }
24
+ }
25
+ return NoCompression
26
+ }
27
+
28
+ // --------------------------------------------------------------------
29
+
30
+ // NoCompression is just a pass-through without compression.
31
+ var NoCompression = noCompression{}
32
+
33
+ type noCompression struct{}
34
+
35
+ func (noCompression) NewReader(r io.Reader) (io.ReadCloser, error) {
36
+ return noCompressionWrapper{Reader: r}, nil
37
+ }
38
+
39
+ func (noCompression) NewWriter(w io.Writer) (io.WriteCloser, error) {
40
+ return noCompressionWrapper{Writer: w}, nil
41
+ }
42
+
43
+ type noCompressionWrapper struct {
44
+ io.Reader
45
+ io.Writer
46
+ }
47
+
48
+ func (noCompressionWrapper) Close() error { return nil }
49
+
50
+ // --------------------------------------------------------------------
51
+
52
+ // GZipCompression supports gzip compression format.
53
+ var GZipCompression = gzipCompression{}
54
+
55
+ type gzipCompression struct{}
56
+
57
+ func (gzipCompression) NewReader(r io.Reader) (io.ReadCloser, error) {
58
+ return gzip.NewReader(r)
59
+ }
60
+
61
+ func (gzipCompression) NewWriter(w io.Writer) (io.WriteCloser, error) {
62
+ return gzip.NewWriter(w), nil
63
+ }
@@ -0,0 +1,66 @@
1
+ package feedx_test
2
+
3
+ import (
4
+ "bytes"
5
+
6
+ "github.com/bsm/feedx"
7
+ . "github.com/onsi/ginkgo"
8
+ . "github.com/onsi/gomega"
9
+ )
10
+
11
+ var _ = Describe("Compression", func() {
12
+ var data = bytes.Repeat([]byte("wxyz"), 1024)
13
+
14
+ runSharedTest := func(subject feedx.Compression) {
15
+ buf := new(bytes.Buffer)
16
+
17
+ w, err := subject.NewWriter(buf)
18
+ Expect(err).NotTo(HaveOccurred())
19
+ defer w.Close()
20
+
21
+ Expect(w.Write(data)).To(Equal(4096))
22
+ Expect(w.Write(data)).To(Equal(4096))
23
+ Expect(w.Close()).To(Succeed())
24
+
25
+ r, err := subject.NewReader(buf)
26
+ Expect(err).NotTo(HaveOccurred())
27
+ defer r.Close()
28
+
29
+ p := make([]byte, 20)
30
+ Expect(r.Read(p)).To(Equal(20))
31
+ Expect(string(p)).To(Equal("wxyzwxyzwxyzwxyzwxyz"))
32
+ Expect(r.Close()).To(Succeed())
33
+ }
34
+
35
+ It("should detect the format", func() {
36
+ Expect(feedx.DetectCompression("/path/to/file.json")).To(Equal(feedx.NoCompression))
37
+ Expect(feedx.DetectCompression("/path/to/file.json.gz")).To(Equal(feedx.GZipCompression))
38
+ Expect(feedx.DetectCompression("/path/to/file.jsonz")).To(Equal(feedx.GZipCompression))
39
+
40
+ Expect(feedx.DetectCompression("/path/to/file.pb")).To(Equal(feedx.NoCompression))
41
+ Expect(feedx.DetectCompression("/path/to/file.pb.gz")).To(Equal(feedx.GZipCompression))
42
+ Expect(feedx.DetectCompression("/path/to/file.pbz")).To(Equal(feedx.GZipCompression))
43
+
44
+ Expect(feedx.DetectCompression("")).To(Equal(feedx.NoCompression))
45
+ Expect(feedx.DetectCompression("/path/to/file")).To(Equal(feedx.NoCompression))
46
+ Expect(feedx.DetectCompression("/path/to/file.txt")).To(Equal(feedx.NoCompression))
47
+ })
48
+
49
+ Describe("NoCompression", func() {
50
+ var subject = feedx.NoCompression
51
+ var _ feedx.Compression = subject
52
+
53
+ It("should write/read", func() {
54
+ runSharedTest(subject)
55
+ })
56
+ })
57
+
58
+ Describe("GZipCompression", func() {
59
+ var subject = feedx.GZipCompression
60
+ var _ feedx.Compression = subject
61
+
62
+ It("should write/read", func() {
63
+ runSharedTest(subject)
64
+ })
65
+ })
66
+ })
data/consumer.go ADDED
@@ -0,0 +1,206 @@
1
+ package feedx
2
+
3
+ import (
4
+ "context"
5
+ "fmt"
6
+ "strconv"
7
+ "sync/atomic"
8
+ "time"
9
+
10
+ "github.com/bsm/bfs"
11
+ )
12
+
13
+ // ConsumerOptions configure the Puller instance.
14
+ type ConsumerOptions struct {
15
+ // The interval used by Puller to check the remote changes.
16
+ // Default: 1m
17
+ Interval time.Duration
18
+
19
+ // Format specifies the format
20
+ // Default: auto-detected from URL path.
21
+ Format Format
22
+
23
+ // Compression specifies the compression type.
24
+ // Default: auto-detected from URL path.
25
+ Compression Compression
26
+
27
+ // AfterSync callbacks are triggered after each sync, receiving
28
+ // the updated status and error (if occurred).
29
+ AfterSync func(updated bool, err error)
30
+ }
31
+
32
+ func (o *ConsumerOptions) norm(name string) error {
33
+ if o.Interval <= 0 {
34
+ o.Interval = time.Minute
35
+ }
36
+ if o.Format == nil {
37
+ o.Format = DetectFormat(name)
38
+
39
+ if o.Format == nil {
40
+ return fmt.Errorf("feedx: unable to detect format from %q", name)
41
+ }
42
+ }
43
+ if o.Compression == nil {
44
+ o.Compression = DetectCompression(name)
45
+ }
46
+ return nil
47
+ }
48
+
49
+ // ParseFunc is a data parse function.
50
+ type ParseFunc func(FormatDecoder) (data interface{}, size int64, err error)
51
+
52
+ // Consumer manages data retrieval from a remote feed.
53
+ // It queries the feed in regular intervals, continuously retrieving new updates.
54
+ type Consumer interface {
55
+ // Data returns the data as returned by ParseFunc on last sync.
56
+ Data() interface{}
57
+ // LastCheck returns time of last sync attempt.
58
+ LastCheck() time.Time
59
+ // LastModified returns time at which the remote feed was last modified.
60
+ LastModified() time.Time
61
+ // Size returns the size as returned by ParseFunc on last sync.
62
+ Size() int64
63
+ // Close stops the underlying sync process.
64
+ Close() error
65
+ }
66
+
67
+ // NewConsumer starts a new feed consumer.
68
+ func NewConsumer(ctx context.Context, srcURL string, opt *ConsumerOptions, parse ParseFunc) (Consumer, error) {
69
+ src, err := bfs.NewObject(ctx, srcURL)
70
+ if err != nil {
71
+ return nil, err
72
+ }
73
+
74
+ var o ConsumerOptions
75
+ if opt != nil {
76
+ o = *opt
77
+ }
78
+ if err := o.norm(src.Name()); err != nil {
79
+ _ = src.Close()
80
+ return nil, err
81
+ }
82
+
83
+ ctx, stop := context.WithCancel(ctx)
84
+ f := &consumer{
85
+ src: src,
86
+ opt: o,
87
+ ctx: ctx,
88
+ stop: stop,
89
+ parse: parse,
90
+ }
91
+
92
+ // run initial sync
93
+ if _, err := f.sync(true); err != nil {
94
+ _ = f.Close()
95
+ return nil, err
96
+ }
97
+
98
+ // start continuous loop
99
+ go f.loop()
100
+
101
+ return f, nil
102
+ }
103
+
104
+ type consumer struct {
105
+ src *bfs.Object
106
+ opt ConsumerOptions
107
+ ctx context.Context
108
+ stop context.CancelFunc
109
+
110
+ parse ParseFunc
111
+
112
+ size, lastModMs int64
113
+ data, lastCheck atomic.Value
114
+ }
115
+
116
+ // Data implements Feed interface.
117
+ func (f *consumer) Data() interface{} {
118
+ return f.data.Load()
119
+ }
120
+
121
+ // Size implements Feed interface.
122
+ func (f *consumer) Size() int64 {
123
+ return atomic.LoadInt64(&f.size)
124
+ }
125
+
126
+ // LastCheck implements Feed interface.
127
+ func (f *consumer) LastCheck() time.Time {
128
+ return f.lastCheck.Load().(time.Time)
129
+ }
130
+
131
+ // LastModified implements Feed interface.
132
+ func (f *consumer) LastModified() time.Time {
133
+ msec := atomic.LoadInt64(&f.lastModMs)
134
+ return time.Unix(msec/1000, msec%1000*1e6)
135
+ }
136
+
137
+ // Close implements Feed interface.
138
+ func (f *consumer) Close() error {
139
+ f.stop()
140
+ return f.src.Close()
141
+ }
142
+
143
+ func (f *consumer) sync(force bool) (bool, error) {
144
+ f.lastCheck.Store(time.Now())
145
+
146
+ info, err := f.src.Head(f.ctx)
147
+ if err != nil {
148
+ return false, err
149
+ }
150
+
151
+ // calculate last modified time
152
+ msec, _ := strconv.ParseInt(info.Metadata[lastModifiedMetaKey], 10, 64)
153
+
154
+ // skip update if not forced or modified
155
+ if msec == atomic.LoadInt64(&f.lastModMs) && !force {
156
+ return false, nil
157
+ }
158
+
159
+ // open remote for reading
160
+ r, err := f.src.Open(f.ctx)
161
+ if err != nil {
162
+ return false, err
163
+ }
164
+ defer r.Close()
165
+
166
+ // wrap in compressed reader
167
+ c, err := f.opt.Compression.NewReader(r)
168
+ if err != nil {
169
+ return false, err
170
+ }
171
+ defer c.Close()
172
+
173
+ // open decoder
174
+ d, err := f.opt.Format.NewDecoder(c)
175
+ if err != nil {
176
+ return false, err
177
+ }
178
+ defer f.Close()
179
+
180
+ // parse feed
181
+ data, size, err := f.parse(d)
182
+ if err != nil {
183
+ return false, err
184
+ }
185
+
186
+ // update stores
187
+ f.data.Store(data)
188
+ atomic.StoreInt64(&f.size, size)
189
+ atomic.StoreInt64(&f.lastModMs, msec)
190
+ return true, nil
191
+ }
192
+
193
+ func (f *consumer) loop() {
194
+ ticker := time.NewTicker(f.opt.Interval)
195
+ defer ticker.Stop()
196
+
197
+ for {
198
+ select {
199
+ case <-f.ctx.Done():
200
+ return
201
+ case <-ticker.C:
202
+ updated, err := f.sync(false)
203
+ f.opt.AfterSync(updated, err)
204
+ }
205
+ }
206
+ }
data/consumer_test.go ADDED
@@ -0,0 +1,70 @@
1
+ package feedx_test
2
+
3
+ import (
4
+ "context"
5
+ "io"
6
+ "time"
7
+
8
+ "github.com/bsm/bfs"
9
+ "github.com/bsm/feedx"
10
+ tbp "github.com/golang/protobuf/proto/proto3_proto"
11
+ . "github.com/onsi/ginkgo"
12
+ . "github.com/onsi/gomega"
13
+ )
14
+
15
+ var _ = Describe("Consumer", func() {
16
+ ctx := context.Background()
17
+ msg := &tbp.Message{
18
+ Name: "Joe",
19
+ TrueScotsman: true,
20
+ Hilarity: tbp.Message_BILL_BAILEY,
21
+ }
22
+ pfn := func(dec feedx.FormatDecoder) (interface{}, int64, error) {
23
+ var msgs []*tbp.Message
24
+ for {
25
+ msg := new(tbp.Message)
26
+ if err := dec.Decode(msg); err == io.EOF {
27
+ break
28
+ } else if err != nil {
29
+ return nil, 0, err
30
+ }
31
+ msgs = append(msgs, msg)
32
+ }
33
+ return msgs, int64(len(msgs)), nil
34
+ }
35
+
36
+ BeforeEach(func() {
37
+ memStore = bfs.NewInMem()
38
+ w, err := memStore.Create(ctx, "path/to/file.jsonz", &bfs.WriteOptions{
39
+ Metadata: map[string]string{"x-feedx-pusher-last-modified": "1544477788899"},
40
+ })
41
+ Expect(err).NotTo(HaveOccurred())
42
+ defer w.Close()
43
+
44
+ c, err := feedx.GZipCompression.NewWriter(w)
45
+ Expect(err).NotTo(HaveOccurred())
46
+ defer c.Close()
47
+
48
+ f, err := feedx.JSONFormat.NewEncoder(c)
49
+ Expect(err).NotTo(HaveOccurred())
50
+ defer f.Close()
51
+
52
+ Expect(f.Encode(msg)).To(Succeed())
53
+ Expect(f.Encode(msg)).To(Succeed())
54
+ Expect(f.Close()).To(Succeed())
55
+ Expect(c.Close()).To(Succeed())
56
+ Expect(w.Close()).To(Succeed())
57
+ })
58
+
59
+ It("should sync and retrieve feeds from remote", func() {
60
+ subject, err := feedx.NewConsumer(ctx, "mem:///path/to/file.jsonz", nil, pfn)
61
+ Expect(err).NotTo(HaveOccurred())
62
+ defer subject.Close()
63
+
64
+ Expect(subject.LastCheck()).To(BeTemporally("~", time.Now(), time.Second))
65
+ Expect(subject.LastModified()).To(BeTemporally("~", time.Unix(1544477788, 0), time.Second))
66
+ Expect(subject.Size()).To(Equal(int64(2)))
67
+ Expect(subject.Data()).To(Equal([]*tbp.Message{msg, msg}))
68
+ Expect(subject.Close()).To(Succeed())
69
+ })
70
+ })
data/feedx.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'feedx'
3
- s.version = '0.3.1'
3
+ s.version = '0.3.2'
4
4
  s.authors = ['Black Square Media Ltd']
5
5
  s.email = ['info@blacksquaremedia.com']
6
6
  s.summary = %(Exchange data between components via feeds)
data/feedx.go ADDED
@@ -0,0 +1,3 @@
1
+ package feedx
2
+
3
+ const lastModifiedMetaKey = "x-feedx-pusher-last-modified"
data/feedx_test.go ADDED
@@ -0,0 +1,27 @@
1
+ package feedx_test
2
+
3
+ import (
4
+ "context"
5
+ "net/url"
6
+ "testing"
7
+
8
+ "github.com/bsm/bfs"
9
+ . "github.com/onsi/ginkgo"
10
+ . "github.com/onsi/gomega"
11
+ )
12
+
13
+ // ------------------------------------------------------------------------
14
+
15
+ var memStore *bfs.InMem
16
+
17
+ func init() {
18
+ memStore = bfs.NewInMem()
19
+ bfs.Register("mem", func(_ context.Context, u *url.URL) (bfs.Bucket, error) {
20
+ return memStore, nil
21
+ })
22
+ }
23
+
24
+ func TestSuite(t *testing.T) {
25
+ RegisterFailHandler(Fail)
26
+ RunSpecs(t, "feedx")
27
+ }
data/format.go ADDED
@@ -0,0 +1,122 @@
1
+ package feedx
2
+
3
+ import (
4
+ "encoding/json"
5
+ "fmt"
6
+ "io"
7
+ "path"
8
+
9
+ "github.com/golang/protobuf/proto"
10
+
11
+ pbio "github.com/gogo/protobuf/io"
12
+ )
13
+
14
+ // Format represents the data format.
15
+ type Format interface {
16
+ // NewDecoder wraps a decoder around a reader.
17
+ NewDecoder(io.Reader) (FormatDecoder, error)
18
+ // NewEncoder wraps an encoder around a writer.
19
+ NewEncoder(io.Writer) (FormatEncoder, error)
20
+ }
21
+
22
+ // DetectFormat detects the data format from a URL path or file name.
23
+ // May return nil.
24
+ func DetectFormat(name string) Format {
25
+ ext := path.Ext(path.Base(name))
26
+ switch ext {
27
+ case ".json":
28
+ return JSONFormat
29
+ case ".pb", ".proto", ".protobuf":
30
+ return ProtobufFormat
31
+ default:
32
+ if name != "" && ext != "" && ext[0] == '.' {
33
+ if ext[len(ext)-1] == 'z' {
34
+ return DetectFormat(name[0 : len(name)-1])
35
+ }
36
+ return DetectFormat(name[0 : len(name)-len(ext)])
37
+ }
38
+ }
39
+ return nil
40
+ }
41
+
42
+ // FormatDecoder methods
43
+ type FormatDecoder interface {
44
+ // Decode decodes the next message into an interface.
45
+ Decode(v interface{}) error
46
+
47
+ io.Closer
48
+ }
49
+
50
+ // FormatEncoder methods
51
+ type FormatEncoder interface {
52
+ // Encode encodes the value to the stream.
53
+ Encode(v interface{}) error
54
+
55
+ io.Closer
56
+ }
57
+
58
+ // --------------------------------------------------------------------
59
+
60
+ // JSONFormat provides a Format implemention for JSON.
61
+ var JSONFormat = jsonFormat{}
62
+
63
+ type jsonFormat struct{}
64
+
65
+ // NewDecoder implements Format.
66
+ func (jsonFormat) NewDecoder(r io.Reader) (FormatDecoder, error) {
67
+ return jsonDecoderWrapper{Decoder: json.NewDecoder(r)}, nil
68
+ }
69
+
70
+ // NewEncoder implements Format.
71
+ func (jsonFormat) NewEncoder(w io.Writer) (FormatEncoder, error) {
72
+ return jsonEncoderWrapper{Encoder: json.NewEncoder(w)}, nil
73
+ }
74
+
75
+ type jsonDecoderWrapper struct{ *json.Decoder }
76
+
77
+ func (jsonDecoderWrapper) Close() error { return nil }
78
+
79
+ type jsonEncoderWrapper struct{ *json.Encoder }
80
+
81
+ func (jsonEncoderWrapper) Close() error { return nil }
82
+
83
+ // --------------------------------------------------------------------
84
+
85
+ const protobufMaxMessageSize = 20 * 1024 * 1024 // 20MB
86
+
87
+ // ProtobufFormat provides a Format implemention for Protobuf.
88
+ var ProtobufFormat = protobufFormat{}
89
+
90
+ type protobufFormat struct{}
91
+
92
+ // NewDecoder implements Format.
93
+ func (protobufFormat) NewDecoder(r io.Reader) (FormatDecoder, error) {
94
+ rc := pbio.NewDelimitedReader(r, protobufMaxMessageSize)
95
+ return protobufDecoderWrapper{ReadCloser: rc}, nil
96
+ }
97
+
98
+ // NewEncoder implements Format.
99
+ func (protobufFormat) NewEncoder(w io.Writer) (FormatEncoder, error) {
100
+ wc := pbio.NewDelimitedWriter(w)
101
+ return protobufEncoderWrapper{WriteCloser: wc}, nil
102
+ }
103
+
104
+ type protobufDecoderWrapper struct{ pbio.ReadCloser }
105
+
106
+ func (w protobufDecoderWrapper) Decode(v interface{}) error {
107
+ msg, ok := v.(proto.Message)
108
+ if !ok {
109
+ return fmt.Errorf("feedx: value %v is not a proto.Message", v)
110
+ }
111
+ return w.ReadCloser.ReadMsg(msg)
112
+ }
113
+
114
+ type protobufEncoderWrapper struct{ pbio.WriteCloser }
115
+
116
+ func (w protobufEncoderWrapper) Encode(v interface{}) error {
117
+ msg, ok := v.(proto.Message)
118
+ if !ok {
119
+ return fmt.Errorf("feedx: value %v is not a proto.Message", v)
120
+ }
121
+ return w.WriteMsg(msg)
122
+ }
data/format_test.go ADDED
@@ -0,0 +1,80 @@
1
+ package feedx_test
2
+
3
+ import (
4
+ "bytes"
5
+ "io"
6
+
7
+ "github.com/bsm/feedx"
8
+ tbp "github.com/golang/protobuf/proto/proto3_proto"
9
+ . "github.com/onsi/ginkgo"
10
+ . "github.com/onsi/gomega"
11
+ )
12
+
13
+ var _ = Describe("Format", func() {
14
+ msg := &tbp.Message{
15
+ Name: "Joe",
16
+ TrueScotsman: true,
17
+ Hilarity: tbp.Message_BILL_BAILEY,
18
+ }
19
+
20
+ runSharedTest := func(subject feedx.Format) {
21
+ buf := new(bytes.Buffer)
22
+
23
+ enc, err := subject.NewEncoder(buf)
24
+ Expect(err).NotTo(HaveOccurred())
25
+ defer enc.Close()
26
+
27
+ Expect(enc.Encode(msg)).To(Succeed())
28
+ Expect(enc.Encode(msg)).To(Succeed())
29
+ Expect(enc.Close()).To(Succeed())
30
+
31
+ dec, err := subject.NewDecoder(buf)
32
+ Expect(err).NotTo(HaveOccurred())
33
+ defer dec.Close()
34
+
35
+ v1 := new(tbp.Message)
36
+ Expect(dec.Decode(v1)).To(Succeed())
37
+ Expect(v1.Name).To(Equal("Joe"))
38
+
39
+ v2 := new(tbp.Message)
40
+ Expect(dec.Decode(v2)).To(Succeed())
41
+ Expect(v2.Name).To(Equal("Joe"))
42
+
43
+ v3 := new(tbp.Message)
44
+ Expect(dec.Decode(v3)).To(MatchError(io.EOF))
45
+
46
+ Expect(dec.Close()).To(Succeed())
47
+ }
48
+
49
+ It("should detect the format", func() {
50
+ Expect(feedx.DetectFormat("/path/to/file.json")).To(Equal(feedx.JSONFormat))
51
+ Expect(feedx.DetectFormat("/path/to/file.json.gz")).To(Equal(feedx.JSONFormat))
52
+ Expect(feedx.DetectFormat("/path/to/file.jsonz")).To(Equal(feedx.JSONFormat))
53
+
54
+ Expect(feedx.DetectFormat("/path/to/file.pb")).To(Equal(feedx.ProtobufFormat))
55
+ Expect(feedx.DetectFormat("/path/to/file.pb.gz")).To(Equal(feedx.ProtobufFormat))
56
+ Expect(feedx.DetectFormat("/path/to/file.pbz")).To(Equal(feedx.ProtobufFormat))
57
+
58
+ Expect(feedx.DetectFormat("")).To(BeNil())
59
+ Expect(feedx.DetectFormat("/path/to/file")).To(BeNil())
60
+ Expect(feedx.DetectFormat("/path/to/file.txt")).To(BeNil())
61
+ })
62
+
63
+ Describe("JSONFormat", func() {
64
+ var subject = feedx.JSONFormat
65
+ var _ feedx.Format = subject
66
+
67
+ It("should encode/decode", func() {
68
+ runSharedTest(subject)
69
+ })
70
+ })
71
+
72
+ Describe("ProtobufFormat", func() {
73
+ var subject = feedx.ProtobufFormat
74
+ var _ feedx.Format = subject
75
+
76
+ It("should encode/decode", func() {
77
+ runSharedTest(subject)
78
+ })
79
+ })
80
+ })
data/go.mod ADDED
@@ -0,0 +1,13 @@
1
+ module github.com/bsm/feedx
2
+
3
+ require (
4
+ github.com/bsm/bfs v0.4.0
5
+ github.com/gogo/protobuf v1.2.0
6
+ github.com/golang/protobuf v1.2.0
7
+ github.com/kr/pretty v0.1.0 // indirect
8
+ github.com/onsi/ginkgo v1.7.0
9
+ github.com/onsi/gomega v1.4.3
10
+ golang.org/x/net v0.0.0-20181213202711-891ebc4b82d6 // indirect
11
+ golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06 // indirect
12
+ gopkg.in/yaml.v2 v2.2.2 // indirect
13
+ )
data/go.sum ADDED
@@ -0,0 +1,111 @@
1
+ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
2
+ cloud.google.com/go v0.32.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
3
+ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
4
+ git.apache.org/thrift.git v0.0.0-20181106172052-f7d43ce0aa58/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
5
+ github.com/aws/aws-sdk-go v1.15.71/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
6
+ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
7
+ github.com/bmatcuk/doublestar v1.1.1 h1:YroD6BJCZBYx06yYFEWvUuKVWQn3vLLQAVmDmvTSaiQ=
8
+ github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
9
+ github.com/bsm/bfs v0.4.0 h1:+fT6iDNt1ytYVbSA1PCJFQez8j+DuO53D38wy39ol1g=
10
+ github.com/bsm/bfs v0.4.0/go.mod h1:b96pNJ2nox+3JhdQL2oaVrzSsTpd1pEL+GgQuWjxIO0=
11
+ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
12
+ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
13
+ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
14
+ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
15
+ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
16
+ github.com/go-ini/ini v1.39.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
17
+ github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
18
+ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
19
+ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
20
+ github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
21
+ github.com/golang/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
22
+ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
23
+ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
24
+ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
25
+ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
26
+ github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
27
+ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
28
+ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
29
+ github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
30
+ github.com/grpc-ecosystem/grpc-gateway v1.5.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
31
+ github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
32
+ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
33
+ github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
34
+ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
35
+ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
36
+ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
37
+ github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
38
+ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
39
+ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
40
+ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
41
+ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
42
+ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
43
+ github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
44
+ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
45
+ github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
46
+ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
47
+ github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
48
+ github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
49
+ github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
50
+ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
51
+ github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
52
+ github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
53
+ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
54
+ github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
55
+ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
56
+ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
57
+ github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
58
+ github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
59
+ github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
60
+ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
61
+ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
62
+ github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
63
+ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
64
+ go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
65
+ golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
66
+ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
67
+ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
68
+ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
69
+ golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
70
+ golang.org/x/net v0.0.0-20181108082009-03003ca0c849 h1:FSqE2GGG7wzsYUsWiQ8MZrvEd1EOyU3NCF0AW3Wtltg=
71
+ golang.org/x/net v0.0.0-20181108082009-03003ca0c849/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
72
+ golang.org/x/net v0.0.0-20181213202711-891ebc4b82d6 h1:gT0Y6H7hbVPUtvtk0YGxMXPgN+p8fYlqWkgJeUCZcaQ=
73
+ golang.org/x/net v0.0.0-20181213202711-891ebc4b82d6/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
74
+ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
75
+ golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
76
+ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
77
+ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
78
+ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
79
+ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
80
+ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
81
+ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8 h1:YoY1wS6JYVRpIfFngRf2HHo9R9dAne3xbkGOQ5rJXjU=
82
+ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
83
+ golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06 h1:0oC8rFnE+74kEmuHZ46F6KHsMr5Gx2gUQPuNz28iQZM=
84
+ golang.org/x/sys v0.0.0-20181213200352-4d1cda033e06/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
85
+ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
86
+ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
87
+ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
88
+ golang.org/x/tools v0.0.0-20181107225058-a28dfb48e06b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
89
+ google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
90
+ google.golang.org/api v0.0.0-20181108001712-cfbc873f6b93/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
91
+ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
92
+ google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
93
+ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
94
+ google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
95
+ google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
96
+ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
97
+ google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
98
+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
99
+ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
100
+ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
101
+ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
102
+ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
103
+ gopkg.in/ini.v1 v1.39.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
104
+ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
105
+ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
106
+ gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
107
+ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
108
+ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
109
+ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
110
+ honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
111
+ honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
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.3.1
4
+ version: 0.3.2
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: 2018-11-29 00:00:00.000000000 Z
11
+ date: 2018-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bfs
@@ -108,9 +108,20 @@ files:
108
108
  - Gemfile
109
109
  - Gemfile.lock
110
110
  - LICENSE
111
+ - Makefile
111
112
  - README.md
112
113
  - Rakefile
114
+ - compression.go
115
+ - compression_test.go
116
+ - consumer.go
117
+ - consumer_test.go
113
118
  - feedx.gemspec
119
+ - feedx.go
120
+ - feedx_test.go
121
+ - format.go
122
+ - format_test.go
123
+ - go.mod
124
+ - go.sum
114
125
  - lib/feedx.rb
115
126
  - lib/feedx/compression.rb
116
127
  - lib/feedx/compression/abstract.rb
@@ -149,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
149
160
  version: '0'
150
161
  requirements: []
151
162
  rubyforge_project:
152
- rubygems_version: 2.7.6
163
+ rubygems_version: 2.7.7
153
164
  signing_key:
154
165
  specification_version: 4
155
166
  summary: Exchange data between components via feeds