pyper_rb 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/Gemfile +24 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +178 -0
  6. data/Rakefile +10 -0
  7. data/lib/pyper/all.rb +4 -0
  8. data/lib/pyper/pipeline.rb +63 -0
  9. data/lib/pyper/pipes/cassandra/all_items_reader.rb +40 -0
  10. data/lib/pyper/pipes/cassandra/deleter.rb +19 -0
  11. data/lib/pyper/pipes/cassandra/mod_key.rb +32 -0
  12. data/lib/pyper/pipes/cassandra/mod_key_reader.rb +41 -0
  13. data/lib/pyper/pipes/cassandra/pagination_decoding.rb +22 -0
  14. data/lib/pyper/pipes/cassandra/pagination_encoding.rb +17 -0
  15. data/lib/pyper/pipes/cassandra/reader.rb +35 -0
  16. data/lib/pyper/pipes/cassandra/writer.rb +24 -0
  17. data/lib/pyper/pipes/cassandra.rb +8 -0
  18. data/lib/pyper/pipes/content/fetch.rb +30 -0
  19. data/lib/pyper/pipes/content/store.rb +36 -0
  20. data/lib/pyper/pipes/content.rb +2 -0
  21. data/lib/pyper/pipes/default_values.rb +15 -0
  22. data/lib/pyper/pipes/field_rename.rb +23 -0
  23. data/lib/pyper/pipes/force_enumerator.rb +13 -0
  24. data/lib/pyper/pipes/model/attribute_deserializer.rb +27 -0
  25. data/lib/pyper/pipes/model/attribute_serializer.rb +34 -0
  26. data/lib/pyper/pipes/model/attribute_validation.rb +57 -0
  27. data/lib/pyper/pipes/model/virtus_deserializer.rb +39 -0
  28. data/lib/pyper/pipes/model/virtus_parser.rb +13 -0
  29. data/lib/pyper/pipes/model.rb +5 -0
  30. data/lib/pyper/pipes/no_op.rb +15 -0
  31. data/lib/pyper/pipes/pry.rb +9 -0
  32. data/lib/pyper/pipes/remove_fields.rb +22 -0
  33. data/lib/pyper/pipes.rb +8 -0
  34. data/lib/pyper/version.rb +3 -0
  35. data/lib/pyper.rb +4 -0
  36. data/pyper_rb.gemspec +22 -0
  37. data/test/fixtures/cass_schema_config.yml +6 -0
  38. data/test/fixtures/test_datastore/schema.cql +23 -0
  39. data/test/test_helper.rb +34 -0
  40. data/test/unit/pyper/pipeline_test.rb +81 -0
  41. data/test/unit/pyper/pipes/cassandra/all_items_reader_test.rb +47 -0
  42. data/test/unit/pyper/pipes/cassandra/deleter_test.rb +37 -0
  43. data/test/unit/pyper/pipes/cassandra/mod_key_reader_test.rb +47 -0
  44. data/test/unit/pyper/pipes/cassandra/pagination_decoding_test.rb +29 -0
  45. data/test/unit/pyper/pipes/cassandra/pagination_encoding_test.rb +29 -0
  46. data/test/unit/pyper/pipes/cassandra/reader_test.rb +79 -0
  47. data/test/unit/pyper/pipes/cassandra/writer_test.rb +51 -0
  48. data/test/unit/pyper/pipes/content/fetch_test.rb +38 -0
  49. data/test/unit/pyper/pipes/content/store_test.rb +49 -0
  50. data/test/unit/pyper/pipes/field_rename_test.rb +24 -0
  51. data/test/unit/pyper/pipes/model/attribute_deserializer_test.rb +69 -0
  52. data/test/unit/pyper/pipes/model/attribute_serializer_test.rb +60 -0
  53. data/test/unit/pyper/pipes/model/attribute_validation_test.rb +96 -0
  54. data/test/unit/pyper/pipes/model/virtus_deserializer_test.rb +75 -0
  55. data/test/unit/pyper/pipes/no_op_test.rb +12 -0
  56. data/test/unit/pyper/pipes/remove_fields_test.rb +24 -0
  57. metadata +147 -0
@@ -0,0 +1,79 @@
1
+ require 'test_helper'
2
+
3
+ module Pyper::Pipes::Cassandra
4
+ class ReaderTest < Minitest::Should::TestCase
5
+ context 'a cassandra reader pipe' do
6
+
7
+ setup do
8
+ setup_cass_schema
9
+
10
+ @client = create_cass_client('test_datastore')
11
+ @pipe = Reader.new(:test, @client)
12
+
13
+ # populate some test data
14
+ @client.insert(:test, {id: 'id', a: '1', b: 'b'})
15
+ @client.insert(:test, {id: 'id', a: '2', b: 'b'})
16
+ end
17
+
18
+ teardown do
19
+ teardown_cass_schema
20
+ end
21
+
22
+ should 'read items from the cassandra table' do
23
+ out = @pipe.pipe(id: 'id').to_a
24
+ assert_equal 2, out.count
25
+ assert_equal({ "id" => "id", "a" => "1", "b" => "b" }, out.first)
26
+ end
27
+
28
+ should 'return items in ascending order' do
29
+ out = @pipe.pipe(id: 'id').to_a
30
+ assert_equal %w(1 2), out.map { |i| i['a'] }
31
+ end
32
+
33
+ should 'limit results if limit arg provided' do
34
+ out = @pipe.pipe(id: 'id', :limit => 1).to_a
35
+ assert_equal 1, out.count
36
+ end
37
+
38
+ should 'order results by field and direction if order pair provided' do
39
+ out = @pipe.pipe(id: 'id', :order => [:a, :desc]).to_a
40
+ assert_equal %w(2 1), out.map { |i| i['a'] }
41
+ end
42
+
43
+ should 'save page state and last_page in status' do
44
+ status = {}
45
+ out = @pipe.pipe({id: 'id', :page_size => 1}, status).to_a
46
+ assert_equal 1, out.count
47
+ assert_equal '1', out.first['a']
48
+ assert status[:paging_state]
49
+ assert_equal false, status[:last_page]
50
+ end
51
+
52
+ should 'page through results if :page_size and/or :paging_state provided' do
53
+ status = {}
54
+ out = @pipe.pipe({id: 'id', :page_size => 1}, status).to_a
55
+ assert_equal 1, out.count
56
+ assert_equal '1', out.first['a']
57
+ paging_state = status[:paging_state]
58
+
59
+ out = @pipe.pipe({id: 'id', :page_size => 1, :paging_state => paging_state}, status).to_a
60
+ assert_equal 1, out.count
61
+ assert_equal '2', out.first['a']
62
+ assert_equal false, status[:last_page]
63
+ end
64
+
65
+ context "columns selecting" do
66
+ should "only select given columns from columns argument" do
67
+ out = @pipe.pipe({id: 'id', :columns => [:a]}).to_a
68
+ assert_equal({'a' => '1'}, out.first)
69
+ assert_equal({'a' => '2'}, out.last)
70
+ end
71
+
72
+ should "select all columns when columns argument not given" do
73
+ out = @pipe.pipe({id: 'id'}).to_a
74
+ assert_equal({ "id" => "id", "a" => "1", "b" => "b" }, out.first)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,51 @@
1
+ require 'test_helper'
2
+
3
+ module Pyper::Pipes::Cassandra
4
+ class WriterTest < Minitest::Should::TestCase
5
+ context 'a cassandra writer pipe' do
6
+
7
+ setup do
8
+ setup_cass_schema
9
+
10
+ @client = create_cass_client('test_datastore')
11
+ @writer = Writer.new(:test, @client)
12
+ end
13
+
14
+ teardown do
15
+ teardown_cass_schema
16
+ end
17
+
18
+ should 'write to the specified cassandra table' do
19
+ attributes = {id: 'id', a: 'a', b: 'b'}
20
+ @writer.pipe(attributes)
21
+ row = @client.select(:test).execute.first
22
+
23
+ attributes.keys.each do |key|
24
+ assert_equal attributes[key], row[key.to_s]
25
+ end
26
+ end
27
+
28
+ should 'raise an error if required attributes are not provided' do
29
+ attributes = {a: 'a', b: 'b'}
30
+ assert_raises(Cassandra::Errors::InvalidError) { @writer.pipe(attributes) }
31
+ end
32
+
33
+ should 'return the original attributes if the write succeeds' do
34
+ attributes = {id: 'id', a: 'a', b: 'b'}
35
+ assert_equal attributes, @writer.pipe(attributes)
36
+ end
37
+
38
+ should 'raise an error if too many attributes are provided' do
39
+ attributes = {id: 'id', a: 'a', b: 'b', not_an_attribute: 'x'}
40
+ assert_raises(Cassandra::Errors::InvalidError) { @writer.pipe(attributes) }
41
+ end
42
+
43
+ should 'filter attributes if a filter set is given, returning the original attributes' do
44
+ attributes = {id: 'id', a: 'a', b: 'b', not_an_attribute: 'x'}
45
+ filter = [:id, :a, :b]
46
+ writer = Writer.new(:test, @client, filter)
47
+ assert_equal attributes, writer.pipe(attributes)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,38 @@
1
+ require 'test_helper'
2
+
3
+ module Pyper::Pipes::Content
4
+ class FetchTest < Minitest::Should::TestCase
5
+ context 'the content fetch pipe' do
6
+
7
+ setup do
8
+ @dir = Dir.mktmpdir
9
+ @storage_builder = lambda do |item|
10
+ StorageStrategy.get("#{@dir}/content",
11
+ filters: [:size, :checksum],
12
+ size: { metadata_key: :raw_size },
13
+ checksum: {
14
+ digest: :sha256,
15
+ hash_type: :hex,
16
+ metadata_key: :raw_sha256
17
+ })
18
+ end
19
+
20
+ @pipe = Fetch.new(:content, &@storage_builder)
21
+ @strategy = @storage_builder.call({})
22
+ end
23
+
24
+ should 'fetch content using the provided storage builder' do
25
+ content = 'asdf'
26
+ @strategy.write(content)
27
+
28
+ attributes = @pipe.pipe([{}])
29
+ assert_equal content, attributes.first[:content]
30
+ end
31
+
32
+ should 'add nothing if there is no content to store' do
33
+ attributes = @pipe.pipe([{}])
34
+ refute @content, attributes.first[:content]
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,49 @@
1
+ require 'test_helper'
2
+
3
+ module Pyper::Pipes::Content
4
+ class StoreTest < Minitest::Should::TestCase
5
+ context 'the content storage pipe' do
6
+
7
+ setup do
8
+ @dir = Dir.mktmpdir
9
+ @storage_builder = lambda do |attributes|
10
+ StorageStrategy.get("#{@dir}/metadata",
11
+ filters: [:size, :checksum],
12
+ size: { metadata_key: :raw_size },
13
+ checksum: {
14
+ digest: :sha256,
15
+ hash_type: :hex,
16
+ metadata_key: :raw_sha256
17
+ })
18
+ end
19
+
20
+ @pipe = Store.new(:content, &@storage_builder)
21
+ @strategy = @storage_builder.call({})
22
+ end
23
+
24
+ should 'store content using the provided storage builder' do
25
+ content = 'asdf'
26
+ @pipe.pipe(:content => content)
27
+
28
+ assert_equal content, @strategy.read
29
+ end
30
+
31
+
32
+ should 'store size and checksum metadata' do
33
+ content = 'asdf'
34
+ @pipe.pipe(:content => content)
35
+
36
+ assert_equal '4', @strategy.metadata[:raw_size]
37
+ assert @strategy.metadata[:raw_sha256]
38
+ end
39
+
40
+ should 'remove content from attributes adding new metadata fields' do
41
+ content = 'asdf'
42
+ attributes = @pipe.pipe(:content => content)
43
+
44
+ assert_equal '4', attributes[:raw_size]
45
+ assert attributes[:raw_sha256]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ module Pyper::Pipes
4
+ class FieldRenameTest < Minitest::Should::TestCase
5
+ context 'the field rename pipe' do
6
+
7
+ setup do
8
+ @pipe = FieldRename.new(:a => :b, "c" => "d")
9
+ end
10
+
11
+ should 'rename provided symbols as symbols' do
12
+ assert_equal({ :b => 1, :d => 1}, @pipe.pipe(:a => 1, :c => 1))
13
+ end
14
+
15
+ should 'rename provided strings as strings' do
16
+ assert_equal({ "b" => 1, "d" => 1}, @pipe.pipe("a" => 1, "c" => 1))
17
+ end
18
+
19
+ should 'rename nil values' do
20
+ assert_equal({ :b => nil, "d" => nil}, @pipe.pipe(:a => nil, "c" => nil))
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,69 @@
1
+ require 'test_helper'
2
+ require 'json'
3
+
4
+ module Pyper::Pipes::Model
5
+ class AttributeDeserializerTest < Minitest::Should::TestCase
6
+ setup do
7
+ type_mapping = {
8
+ :array => Array,
9
+ :hash => Hash,
10
+ :int => Integer,
11
+ :float => Float,
12
+ :other => String
13
+ }
14
+ @pipe = AttributeDeserializer.new(type_mapping)
15
+ end
16
+
17
+ should 'deserialize json arrays' do
18
+ value = [1,2,3]
19
+ item = { :array => JSON.generate(value) }
20
+ out = @pipe.pipe([item])
21
+ assert_equal 1, out.count
22
+ assert_equal value, out.first[:array]
23
+ end
24
+
25
+ should 'deserialize json hashes' do
26
+ value = {'a' => 1}
27
+ item = { :hash => JSON.generate(value) }
28
+ out = @pipe.pipe([item])
29
+ assert_equal 1, out.count
30
+ assert_equal value, out.first[:hash]
31
+ end
32
+
33
+ should 'deserialize ints' do
34
+ value = 1
35
+ item = { :int => value.to_s }
36
+ out = @pipe.pipe([item])
37
+ assert_equal 1, out.count
38
+ assert_equal value, out.first[:int]
39
+ end
40
+
41
+ should 'deserialize fixnums' do
42
+ value = 1.5
43
+ item = { :float => value.to_s }
44
+ out = @pipe.pipe([item])
45
+ assert_equal 1, out.count
46
+ assert_equal value, out.first[:float]
47
+ end
48
+
49
+ should 'not deserialize other fields' do
50
+ value = 'asdf'
51
+ item = { :other => value }
52
+ out = @pipe.pipe([item])
53
+ assert_equal 1, out.count
54
+ assert_equal value, out.first[:other]
55
+ end
56
+
57
+ should 'not modify original values when deserializng' do
58
+ value = [1,2,3]
59
+ item = { :array => JSON.generate(value) }
60
+ out = @pipe.pipe([item])
61
+ assert_equal 1, out.count
62
+ assert_equal value, out.first[:array]
63
+
64
+ # This throws an error if we have modified the original values
65
+ out = @pipe.pipe([item])
66
+ assert_equal value, out.first[:array]
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,60 @@
1
+ require 'test_helper'
2
+ require 'json'
3
+
4
+ module Pyper::Pipes::Model
5
+ class AttributeSerializerTest < Minitest::Should::TestCase
6
+ setup do
7
+ @pipe = AttributeSerializer.new
8
+ end
9
+
10
+ should 'serialize arrays to JSON' do
11
+ value = [1,2,3]
12
+ attributes = { :array => value }
13
+ out = @pipe.pipe(attributes)
14
+ assert_equal 1, out.count
15
+ assert_equal JSON.generate(value), out[:array]
16
+ end
17
+
18
+ should 'serialize hashes to JSON' do
19
+ value = {'a' => 1}
20
+ attributes = { :hash => value }
21
+ out = @pipe.pipe(attributes)
22
+ assert_equal 1, out.count
23
+ assert_equal JSON.generate(value), out[:hash]
24
+ end
25
+
26
+ should 'serialize datetimes to times' do
27
+ value = DateTime.now
28
+ attributes = { :datetime => value }
29
+ out = @pipe.pipe(attributes)
30
+ assert_equal 1, out.count
31
+ assert_equal value.to_time, out[:datetime]
32
+ end
33
+
34
+ should 'encode strings to utf-8' do
35
+ value = 'str'.force_encoding('ascii-8bit')
36
+ attributes = { :string => value }
37
+ out = @pipe.pipe(attributes)
38
+ assert_equal 1, out.count
39
+ assert_equal Encoding::UTF_8, out[:string].encoding
40
+ end
41
+
42
+ should 'be able to serialize collections containing strings with non-UTF8 characters to JSON' do
43
+ ascii = "\xC2\xA0".force_encoding('ascii-8bit')
44
+ time = DateTime.now
45
+ ascii_values = { :array => [ascii], :datetime => time, :fixnum => 1, :string => ascii }
46
+ utf8_values = { :array => [ascii.force_encoding("UTF-8")], :datetime => time, :fixnum => 1, :string => ascii.force_encoding("UTF-8") }
47
+ out = @pipe.pipe({ :hash => ascii_values })
48
+ assert_equal 1, out.count
49
+ assert_equal JSON.generate(utf8_values), out[:hash]
50
+ end
51
+
52
+ should 'not serialize other fields' do
53
+ value = 1.5
54
+ attributes = { :fixnum => value }
55
+ out = @pipe.pipe(attributes)
56
+ assert_equal 1, out.count
57
+ assert_equal value, out[:fixnum]
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,96 @@
1
+ require 'test_helper'
2
+
3
+ module Pyper::Pipes::Model
4
+ class AttributeValidationTest < Minitest::Should::TestCase
5
+ context "pipe" do
6
+ context "with required attributes" do
7
+ setup do
8
+ @opts = { :required => [:foo, :bar] }
9
+ @pipe = AttributeValidation.new(@opts)
10
+ end
11
+
12
+ should "raise when missing required attribute" do
13
+ error_1 = assert_raises(AttributeValidation::Failure) do
14
+ @pipe.pipe({})
15
+ end
16
+ assert_equal "Missing required attribute foo.", error_1.message
17
+
18
+ error_2 = assert_raises(AttributeValidation::Failure) do
19
+ @pipe.pipe({ :foo => "bar" })
20
+ end
21
+ assert_equal "Missing required attribute bar.", error_2.message
22
+
23
+ # Nothing should be raised now.
24
+ @pipe.pipe({ :foo => "bar", :bar => "qux" })
25
+ end
26
+
27
+ should "raise when required attribute is nil" do
28
+ error = assert_raises(AttributeValidation::Failure) do
29
+ @pipe.pipe({ :foo => nil, :bar => "qux"})
30
+ end
31
+ assert_equal "Missing required attribute foo.", error.message
32
+ end
33
+ end
34
+
35
+ context "with allowed attributes" do
36
+ setup do
37
+ @opts = { :allowed => [:foo, :bar] }
38
+ @pipe = AttributeValidation.new(@opts)
39
+ end
40
+
41
+ should "raise when attribute is not included in the whitelist" do
42
+ error = assert_raises(AttributeValidation::Failure) do
43
+ @pipe.pipe({ :foo => "foo", :bar => "bar", :baz => "baz" })
44
+ end
45
+ assert_equal "Attribute baz is not allowed.", error.message
46
+
47
+ # Nothing should be raised now.
48
+ @pipe.pipe({ :foo => "foo", :bar => "bar" })
49
+ end
50
+
51
+ should "allow all attributes when allowed option is not set" do
52
+ pipe = AttributeValidation.new
53
+
54
+ # Nothing should be raised now.
55
+ pipe.pipe({ :foo => "foo", :bar => "bar", :baz => "baz" })
56
+ end
57
+ end
58
+
59
+
60
+ context "with restricted attributes" do
61
+ setup do
62
+ @opts = {
63
+ :restricted => {
64
+ :bar => lambda { |value| ["qux", "bazqux"].include?(value) }
65
+ }
66
+ }
67
+ @pipe = AttributeValidation.new(@opts)
68
+ end
69
+
70
+ should "raise when lambda returns false" do
71
+ error = assert_raises(AttributeValidation::Failure) do
72
+ @pipe.pipe({ :bar => "foo"})
73
+ end
74
+ assert_equal "Invalid value for attribute bar.", error.message
75
+
76
+ # Nothing should be raised now.
77
+ @pipe.pipe({ :bar => "qux" })
78
+ @pipe.pipe({ :bar => "bazqux" })
79
+ end
80
+ end
81
+
82
+ should "return attributes hash when all is well" do
83
+ opts = {
84
+ :allowed => [:foo, :bar],
85
+ :required => [:foo],
86
+ :restricted => {
87
+ :bar => lambda { |value| ["bar", "foobar"].include?(value) }
88
+ }
89
+ }
90
+ pipe = AttributeValidation.new(opts)
91
+ attributes = { :foo => "bar", :bar => "foobar" }
92
+ assert_equal attributes, pipe.pipe(attributes)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,75 @@
1
+ require 'test_helper'
2
+ require 'json'
3
+ require 'virtus'
4
+
5
+ module Pyper::Pipes::Model
6
+ class VirtusDeserializerTest < Minitest::Should::TestCase
7
+
8
+ class TestVirtus
9
+ include ::Virtus.model
10
+
11
+ attribute :array, Array[String]
12
+ attribute :hash, Hash
13
+ attribute :int, Integer
14
+ attribute :float, Float
15
+ attribute :other, String
16
+ end
17
+
18
+ setup do
19
+ @pipe = VirtusDeserializer.new(TestVirtus.attribute_set)
20
+ end
21
+
22
+ should 'deserialize json arrays' do
23
+ value = [1,2,3]
24
+ item = { 'array' => JSON.generate(value) }
25
+ out = @pipe.pipe([item])
26
+ assert_equal 1, out.count
27
+
28
+ assert_equal value, out.first['array']
29
+ end
30
+
31
+ should 'deserialize json hashes' do
32
+ value = {'a' => 1}
33
+ item = { 'hash' => JSON.generate(value) }
34
+ out = @pipe.pipe([item])
35
+ assert_equal 1, out.count
36
+ assert_equal value, out.first['hash']
37
+ end
38
+
39
+ should 'deserialize ints' do
40
+ value = 1
41
+ item = { 'int' => value.to_s }
42
+ out = @pipe.pipe([item])
43
+ assert_equal 1, out.count
44
+ assert_equal value, out.first['int']
45
+ end
46
+
47
+ should 'deserialize floats' do
48
+ value = 1.5
49
+ item = { 'float' => value.to_s }
50
+ out = @pipe.pipe([item])
51
+ assert_equal 1, out.count
52
+ assert_equal value, out.first['float']
53
+ end
54
+
55
+ should 'not deserialize other fields' do
56
+ value = 'asdf'
57
+ item = { 'other' => value }
58
+ out = @pipe.pipe([item])
59
+ assert_equal 1, out.count
60
+ assert_equal value, out.first['other']
61
+ end
62
+
63
+ should 'not modify original values when deserializng' do
64
+ value = [1,2,3]
65
+ item = { 'array' => JSON.generate(value) }
66
+ out = @pipe.pipe([item])
67
+ assert_equal 1, out.count
68
+ assert_equal value, out.first['array']
69
+
70
+ # This throws an error if we have modified the original values
71
+ out = @pipe.pipe([item])
72
+ assert_equal value, out.first['array']
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,12 @@
1
+ require 'test_helper'
2
+
3
+ module Pyper::Pipes
4
+ class NoOpTest < Minitest::Should::TestCase
5
+ context 'NoOp pipe' do
6
+ should 'perform no operation' do
7
+ pipe_input = { :pipe_var => "this is a string" }
8
+ assert_equal pipe_input, NoOp.pipe(pipe_input)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+
3
+ module Pyper::Pipes
4
+ class RemoveFieldsTest < Minitest::Should::TestCase
5
+ context 'the remove fields pipe' do
6
+
7
+ should "accept a symbol" do
8
+ pipe = RemoveFields.new(:a)
9
+ assert_equal({ :b => 2 }, pipe.pipe(:a => 1, :b => 2))
10
+ end
11
+
12
+ should "accept an array of symbol" do
13
+ pipe = RemoveFields.new([:a])
14
+ assert_equal({ :b => 2 }, pipe.pipe(:a => 1, :b => 2))
15
+ end
16
+
17
+ should 'remove fields provided an array of symbols' do
18
+ pipe = RemoveFields.new([:a])
19
+ assert_equal({ :b => 2 }, pipe.pipe(:a => 1, :b => 2))
20
+ end
21
+
22
+ end
23
+ end
24
+ end