gotime-cassandra_object 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -15,6 +15,7 @@ Add the following to your Gemfile:
15
15
  string :name
16
16
  string :description
17
17
  integer :price
18
+ array :colors, unique: true
18
19
 
19
20
  validates :name, presence: :true
20
21
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'gotime-cassandra_object'
5
- s.version = '2.5.0'
5
+ s.version = '2.6.0'
6
6
  s.description = 'Cassandra ActiveModel'
7
7
  s.summary = 'Cassandra ActiveModel'
8
8
 
@@ -1,15 +1,17 @@
1
1
  module CassandraObject
2
2
  class Attribute
3
3
  attr_reader :name, :coder, :expected_type
4
- def initialize(name, coder, expected_type)
4
+ def initialize(name, type_mapping, options)
5
5
  @name = name.to_s
6
- @coder = coder
7
- @expected_type = expected_type
6
+ @coder = type_mapping.coder.new(options)
7
+ @expected_type = type_mapping.expected_type
8
8
  end
9
9
 
10
- def check_value!(value)
11
- return value if value.nil?
12
- value.kind_of?(expected_type) ? value : coder.decode(value)
10
+ def instantiate(record, value)
11
+ return if value.nil? && coder.ignore_nil?
12
+
13
+ value = value.kind_of?(expected_type) ? value : coder.decode(value)
14
+ coder.wrap(record, name, value)
13
15
  end
14
16
  end
15
17
 
@@ -23,11 +25,11 @@ module CassandraObject
23
25
 
24
26
  attribute_method_suffix("", "=")
25
27
 
26
- %w(array boolean date float integer time time_with_zone set string).each do |type|
28
+ %w(array boolean date float integer time time_with_zone string).each do |type|
27
29
  instance_eval <<-EOV, __FILE__, __LINE__ + 1
28
- def #{type}(name, options = {}) # def string(name, options = {})
29
- attribute(name, options.update(type: :#{type})) # attribute(name, options.update(type: :string))
30
- end # end
30
+ def #{type}(name, options = {}) # def string(name, options = {})
31
+ attribute(name, options.update(type: :#{type})) # attribute(name, options.update(type: :string))
32
+ end # end
31
33
  EOV
32
34
  end
33
35
  end
@@ -38,18 +40,31 @@ module CassandraObject
38
40
  child.model_attributes = model_attributes.dup
39
41
  end
40
42
 
43
+ #
44
+ # attribute :name, type: :string
45
+ # attribute :ammo, type: Ammo, coder: AmmoCodec
46
+ #
41
47
  def attribute(name, options)
42
- if type_mapping = CassandraObject::Type.get_mapping(options[:type])
43
- coder = type_mapping.coder
44
- expected_type = type_mapping.expected_type
45
- elsif options[:coder]
46
- coder = options[:coder]
47
- expected_type = options[:type]
48
+ expected_type = options.delete :type
49
+ coder = options.delete :coder
50
+
51
+ if expected_type.is_a?(Symbol)
52
+ type_mapping = CassandraObject::Type.get_mapping(expected_type) || (raise "Unknown type #{type}")
53
+ elsif coder.nil?
54
+ raise "Must supply a :coder for #{name}"
48
55
  else
49
- raise "Unknown type #{options[:type]}"
56
+ type_mapping = CassandraObject::Type::TypeMapping.new(expected_type, coder)
50
57
  end
51
58
 
52
- model_attributes[name] = Attribute.new(name, coder, expected_type)
59
+ model_attributes[name] = Attribute.new(name, type_mapping, options)
60
+ end
61
+
62
+ def instantiate_attribute(record, name, value)
63
+ if model_attribute = model_attributes[name]
64
+ model_attribute.instantiate(record, value)
65
+ else
66
+ raise NoMethodError, "Unknown attribute #{name.inspect}"
67
+ end
53
68
  end
54
69
 
55
70
  def define_attribute_methods
@@ -58,11 +73,7 @@ module CassandraObject
58
73
  end
59
74
 
60
75
  def write_attribute(name, value)
61
- if ma = self.class.model_attributes[name]
62
- @attributes[name.to_s] = ma.check_value!(value)
63
- else
64
- raise NoMethodError, "Unknown attribute #{name.inspect}"
65
- end
76
+ @attributes[name.to_s] = self.class.instantiate_attribute(self, name, value)
66
77
  end
67
78
 
68
79
  def read_attribute(name)
@@ -4,12 +4,12 @@ module CassandraObject
4
4
 
5
5
  module ClassMethods
6
6
  def find(key)
7
- key = key.try :to_s
7
+ key_string = key.try :to_s
8
8
 
9
- if !parse_key(key)
9
+ if key_string.blank?
10
10
  raise CassandraObject::RecordNotFound, "Couldn't find #{self.name} with key #{key.inspect}"
11
- elsif attributes = connection.get(column_family, key)
12
- instantiate(key, attributes)
11
+ elsif attributes = connection.get(column_family, key_string).presence
12
+ instantiate(key_string, attributes)
13
13
  else
14
14
  raise CassandraObject::RecordNotFound
15
15
  end
@@ -40,7 +40,7 @@ module CassandraObject
40
40
  object.instance_variable_set("@key", parse_key(key))
41
41
  object.instance_variable_set("@new_record", false)
42
42
  object.instance_variable_set("@destroyed", false)
43
- object.instance_variable_set("@attributes", decode_columns_hash(attributes))
43
+ object.instance_variable_set("@attributes", decode_columns_hash(object, attributes))
44
44
  end
45
45
  end
46
46
 
@@ -54,8 +54,8 @@ module CassandraObject
54
54
  end.merge({"schema_version" => schema_version.to_s})
55
55
  end
56
56
 
57
- def decode_columns_hash(attributes)
58
- Hash[attributes.map { |k, v| [k.to_s, model_attributes[k].coder.decode(v)] }]
57
+ def decode_columns_hash(object, attributes)
58
+ Hash[attributes.map { |k, v| [k.to_s, instantiate_attribute(object, k, v)] }]
59
59
  end
60
60
 
61
61
  def column_family_configuration
@@ -8,7 +8,7 @@ module CassandraObject
8
8
 
9
9
  class << self
10
10
  def register(name, expected_type, coder)
11
- attribute_types[name] = TypeMapping.new(expected_type, coder.new)
11
+ attribute_types[name] = TypeMapping.new(expected_type, coder)
12
12
  end
13
13
 
14
14
  def get_mapping(name)
@@ -4,7 +4,6 @@ CassandraObject::Type.register(:date, Date, CassandraObject::Types::DateType)
4
4
  CassandraObject::Type.register(:float, Float, CassandraObject::Types::FloatType)
5
5
  CassandraObject::Type.register(:hash, Hash, CassandraObject::Types::HashType)
6
6
  CassandraObject::Type.register(:integer, Integer, CassandraObject::Types::IntegerType)
7
- CassandraObject::Type.register(:set, Array, CassandraObject::Types::SetType)
8
7
  CassandraObject::Type.register(:time, Time, CassandraObject::Types::TimeType)
9
8
  CassandraObject::Type.register(:time_with_zone, ActiveSupport::TimeWithZone, CassandraObject::Types::TimeWithZoneType)
10
9
  CassandraObject::Type.register(:string, String, CassandraObject::Types::StringType)
@@ -1,13 +1,44 @@
1
1
  module CassandraObject
2
2
  module Types
3
- class ArrayType
3
+ class ArrayType < BaseType
4
+ class Proxy < BasicObject
5
+ attr_accessor :record, :name, :array, :options
6
+ def initialize(record, name, array, options)
7
+ @record = record
8
+ @name = name
9
+ @array = array.presence || []
10
+ @options = options
11
+ end
12
+
13
+ def <<(obj)
14
+ array << obj
15
+ array.sort!
16
+ array.uniq! if options[:unique]
17
+ record.send("#{name}=", array)
18
+ end
19
+
20
+ def method_missing(method, *args, &block)
21
+ array.send(method, *args, &block)
22
+ end
23
+ end
24
+
25
+ def ignore_nil?
26
+ false
27
+ end
28
+
4
29
  def encode(array)
5
30
  raise ArgumentError.new("#{self} requires an Array") unless array.kind_of?(Array)
6
- array.to_json
31
+ array.to_a.to_json
7
32
  end
8
33
 
9
34
  def decode(str)
10
- ActiveSupport::JSON.decode(str)
35
+ array = ActiveSupport::JSON.decode(str)
36
+ array.uniq! if options[:unique]
37
+ array
38
+ end
39
+
40
+ def wrap(record, name, value)
41
+ Proxy.new(record, name, value, options)
11
42
  end
12
43
  end
13
44
  end
@@ -0,0 +1,26 @@
1
+ module CassandraObject
2
+ module Types
3
+ class BaseType
4
+ attr_accessor :options
5
+ def initialize(options = {})
6
+ @options = options
7
+ end
8
+
9
+ def ignore_nil?
10
+ true
11
+ end
12
+
13
+ def encode(value)
14
+ value.to_s
15
+ end
16
+
17
+ def decode(str)
18
+ str
19
+ end
20
+
21
+ def wrap(record, name, value)
22
+ value
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,6 +1,6 @@
1
1
  module CassandraObject
2
2
  module Types
3
- class BooleanType
3
+ class BooleanType < BaseType
4
4
  TRUE_VALS = [true, 'true', '1']
5
5
  FALSE_VALS = [false, 'false', '0', '', nil]
6
6
  VALID_VALS = TRUE_VALS + FALSE_VALS
@@ -1,18 +1,18 @@
1
1
  module CassandraObject
2
2
  module Types
3
- class DateType
3
+ class DateType < BaseType
4
4
  FORMAT = '%Y-%m-%d'
5
5
  REGEX = /\A\d{4}-\d{2}-\d{2}\Z/
6
- def encode(date)
7
- raise ArgumentError.new("#{self} requires a Date") unless date.kind_of?(Date)
8
- date.strftime(FORMAT)
6
+
7
+ def encode(value)
8
+ raise ArgumentError.new("#{self} requires a Date") unless value.kind_of?(Date)
9
+ value.strftime(FORMAT)
9
10
  end
10
11
 
11
12
  def decode(str)
12
13
  return nil if str.empty?
13
- raise ArgumentError.new("Cannot convert #{str} into a Date") unless str.kind_of?(String) && str.match(REGEX)
14
- Date.strptime(str, FORMAT)
14
+ Date.parse(str)
15
15
  end
16
16
  end
17
17
  end
18
- end
18
+ end
@@ -1,6 +1,6 @@
1
1
  module CassandraObject
2
2
  module Types
3
- class FloatType
3
+ class FloatType < BaseType
4
4
  REGEX = /\A[-+]?\d+(\.\d+)?\Z/
5
5
  def encode(float)
6
6
  raise ArgumentError.new("#{self} requires a Float") unless float.kind_of?(Float)
@@ -1,6 +1,6 @@
1
1
  module CassandraObject
2
2
  module Types
3
- class HashType
3
+ class HashType < BaseType
4
4
  def encode(hash)
5
5
  raise ArgumentError.new("#{self} requires a Hash") unless hash.kind_of?(Hash)
6
6
  ActiveSupport::JSON.encode(hash)
@@ -1,6 +1,6 @@
1
1
  module CassandraObject
2
2
  module Types
3
- class IntegerType
3
+ class IntegerType < BaseType
4
4
  REGEX = /\A[-+]?\d+\Z/
5
5
  def encode(int)
6
6
  raise ArgumentError.new("#{self} requires an Integer. You passed #{int.inspect}") unless int.kind_of?(Integer)
@@ -1,6 +1,6 @@
1
1
  module CassandraObject
2
2
  module Types
3
- class StringType
3
+ class StringType < BaseType
4
4
  def encode(str)
5
5
  raise ArgumentError.new("#{self} requires a String") unless str.kind_of?(String)
6
6
  str.dup
@@ -1,6 +1,6 @@
1
1
  module CassandraObject
2
2
  module Types
3
- class TimeType
3
+ class TimeType < BaseType
4
4
  # lifted from the implementation of Time.xmlschema and simplified
5
5
  REGEX = /\A\s*
6
6
  (-?\d+)-(\d\d)-(\d\d)
@@ -1,6 +1,6 @@
1
1
  module CassandraObject
2
2
  module Types
3
- class TimeWithZoneType
3
+ class TimeWithZoneType < BaseType
4
4
  def encode(time)
5
5
  raise ArgumentError.new("#{self} requires a Time") unless time.kind_of?(Time)
6
6
  time.utc.xmlschema(6)
@@ -34,13 +34,13 @@ module CassandraObject
34
34
  module Types
35
35
  extend ActiveSupport::Autoload
36
36
 
37
+ autoload :BaseType
37
38
  autoload :ArrayType
38
39
  autoload :BooleanType
39
40
  autoload :DateType
40
41
  autoload :FloatType
41
42
  autoload :HashType
42
43
  autoload :IntegerType
43
- autoload :SetType
44
44
  autoload :StringType
45
45
  autoload :TimeType
46
46
  autoload :TimeWithZoneType
@@ -1,14 +1,38 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class CassandraObject::AttributesTest < CassandraObject::TestCase
4
+ class CustomType
5
+ end
6
+
7
+ class CustomCoder < CassandraObject::Types::BaseType
8
+ end
9
+
4
10
  class TestIssue < CassandraObject::Base
5
11
  self.column_family = 'Issue'
12
+ attribute :custom_column, type: CustomType, coder: CustomCoder
13
+ integer :price
6
14
  end
7
15
 
8
16
  class TestChildIssue < TestIssue
9
17
  string :description
10
18
  end
11
19
 
20
+ test 'custom attribute definer' do
21
+ model_attribute = TestIssue.model_attributes[:custom_column]
22
+
23
+ assert_kind_of CustomCoder, model_attribute.coder
24
+ assert_equal CustomType, model_attribute.expected_type
25
+ end
26
+
27
+ test 'instantiate_attribute' do
28
+ assert_equal 1, TestIssue.instantiate_attribute(TestIssue.new, 'price', 1)
29
+ assert_equal 1, TestIssue.instantiate_attribute(TestIssue.new, :price, 1)
30
+
31
+ assert_raise NoMethodError do
32
+ TestIssue.instantiate_attribute(TestIssue.new, 'wtf', 1)
33
+ end
34
+ end
35
+
12
36
  test 'attributes not shared' do
13
37
  assert_nothing_raised { Issue.new.description }
14
38
  assert_raise(NoMethodError) { TestIssue.new.description }
@@ -24,4 +48,4 @@ class CassandraObject::AttributesTest < CassandraObject::TestCase
24
48
 
25
49
  assert_equal 'foo', issue.description
26
50
  end
27
- end
51
+ end
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ class CassandraObject::DirtyTest < CassandraObject::TestCase
4
+ class TestRecord < CassandraObject::Base
5
+ key :uuid
6
+ self.column_family = 'Issues'
7
+ string :name
8
+ end
9
+
10
+ test 'save clears dirty' do
11
+ record = TestRecord.new(name: 'foo')
12
+ assert record.changed?
13
+
14
+ record.save
15
+
16
+ assert !record.changed?
17
+ end
18
+ end
@@ -13,7 +13,7 @@ class CassandraObject::FinderMethodsTest < CassandraObject::TestCase
13
13
  rescue => e
14
14
  assert_equal "Couldn't find Issue with key nil", e.message
15
15
  end
16
-
16
+
17
17
  assert_raise CassandraObject::RecordNotFound do
18
18
  Issue.find('what')
19
19
  end
@@ -1,6 +1,10 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class CassandraObject::Types::ArrayTypeTest < CassandraObject::Types::TestCase
4
+ test 'ignore_nil' do
5
+ assert_equal false, coder.ignore_nil?
6
+ end
7
+
4
8
  test 'encode' do
5
9
  assert_equal ['1', '2'].to_json, coder.encode(['1', '2'])
6
10
 
@@ -12,4 +16,21 @@ class CassandraObject::Types::ArrayTypeTest < CassandraObject::Types::TestCase
12
16
  test 'decode' do
13
17
  assert_equal ['1', '2'], coder.decode(['1', '2'].to_json)
14
18
  end
15
- end
19
+
20
+ class TestIssue < CassandraObject::Base
21
+ self.column_family = 'Issue'
22
+ array :favorite_colors
23
+ end
24
+
25
+ test 'wrap' do
26
+ issue = TestIssue.new
27
+ colors = []
28
+ wrapper = coder.wrap(issue, 'favorite_colors', colors)
29
+
30
+ assert_kind_of Array, wrapper
31
+
32
+ assert !issue.changed?
33
+ wrapper << 'red'
34
+ assert issue.changed?
35
+ end
36
+ end
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+
3
+ class CassandraObject::Types::BaseTypeTest < CassandraObject::Types::TestCase
4
+ test 'ignore_nil' do
5
+ assert_equal true, coder.ignore_nil?
6
+ end
7
+
8
+ test 'encode' do
9
+ assert_equal '1', coder.encode(1)
10
+ assert_equal '', coder.encode(nil)
11
+ assert_equal '1', coder.encode('1')
12
+ end
13
+
14
+ test 'decode' do
15
+ assert_equal 'abc', coder.decode('abc')
16
+ end
17
+
18
+ test 'wrap' do
19
+ object = Object.new
20
+ assert_equal object, coder.wrap(nil, nil, object)
21
+ end
22
+ end
@@ -1,4 +1,11 @@
1
1
  require 'test_helper'
2
2
 
3
- class CassandraObject::Type::DateTypeTest < CassandraObject::Types::TestCase
4
- end
3
+ class CassandraObject::Types::DateTypeTest < CassandraObject::Types::TestCase
4
+ test 'encode' do
5
+ assert_equal '2004-04-25', coder.encode(Date.new(2004, 4, 25))
6
+ end
7
+
8
+ test 'decode' do
9
+ assert_equal Date.new(2004, 4, 25), coder.decode('2004-04-25')
10
+ end
11
+ end
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class CassandraObject::Type::FloatTypeTest < CassandraObject::Types::TestCase
4
+
4
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gotime-cassandra_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-08-26 00:00:00.000000000Z
13
+ date: 2011-08-29 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activemodel
17
- requirement: &70322955465140 !ruby/object:Gem::Requirement
17
+ requirement: &70153564769440 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '3.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70322955465140
25
+ version_requirements: *70153564769440
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: cassandra
28
- requirement: &70322955464620 !ruby/object:Gem::Requirement
28
+ requirement: &70153564768800 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ~>
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 0.12.0
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *70322955464620
36
+ version_requirements: *70153564768800
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: bundler
39
- requirement: &70322955464020 !ruby/object:Gem::Requirement
39
+ requirement: &70153564768060 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ~>
@@ -44,7 +44,7 @@ dependencies:
44
44
  version: 1.0.0
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *70322955464020
47
+ version_requirements: *70153564768060
48
48
  description: Cassandra ActiveModel
49
49
  email: gems@gotime.com
50
50
  executables: []
@@ -101,12 +101,12 @@ files:
101
101
  - lib/cassandra_object/type.rb
102
102
  - lib/cassandra_object/types.rb
103
103
  - lib/cassandra_object/types/array_type.rb
104
+ - lib/cassandra_object/types/base_type.rb
104
105
  - lib/cassandra_object/types/boolean_type.rb
105
106
  - lib/cassandra_object/types/date_type.rb
106
107
  - lib/cassandra_object/types/float_type.rb
107
108
  - lib/cassandra_object/types/hash_type.rb
108
109
  - lib/cassandra_object/types/integer_type.rb
109
- - lib/cassandra_object/types/set_type.rb
110
110
  - lib/cassandra_object/types/string_type.rb
111
111
  - lib/cassandra_object/types/time_type.rb
112
112
  - lib/cassandra_object/types/time_with_zone_type.rb
@@ -119,6 +119,7 @@ files:
119
119
  - test/callbacks_test.rb
120
120
  - test/connection_test.rb
121
121
  - test/consistency_test.rb
122
+ - test/dirty_test.rb
122
123
  - test/finder_methods_test.rb
123
124
  - test/identity/uuid_key_factory_test.rb
124
125
  - test/identity_test.rb
@@ -126,12 +127,12 @@ files:
126
127
  - test/test_helper.rb
127
128
  - test/timestamps_test.rb
128
129
  - test/types/array_type_test.rb
130
+ - test/types/base_type_test.rb
129
131
  - test/types/boolean_type_test.rb
130
132
  - test/types/date_type_test.rb
131
133
  - test/types/float_type_test.rb
132
134
  - test/types/hash_type_test.rb
133
135
  - test/types/integer_type_test.rb
134
- - test/types/set_type_test.rb
135
136
  - test/types/string_type_test.rb
136
137
  - test/types/time_type_test.rb
137
138
  - test/validations_test.rb
@@ -167,6 +168,7 @@ test_files:
167
168
  - test/callbacks_test.rb
168
169
  - test/connection_test.rb
169
170
  - test/consistency_test.rb
171
+ - test/dirty_test.rb
170
172
  - test/finder_methods_test.rb
171
173
  - test/identity/uuid_key_factory_test.rb
172
174
  - test/identity_test.rb
@@ -174,12 +176,12 @@ test_files:
174
176
  - test/test_helper.rb
175
177
  - test/timestamps_test.rb
176
178
  - test/types/array_type_test.rb
179
+ - test/types/base_type_test.rb
177
180
  - test/types/boolean_type_test.rb
178
181
  - test/types/date_type_test.rb
179
182
  - test/types/float_type_test.rb
180
183
  - test/types/hash_type_test.rb
181
184
  - test/types/integer_type_test.rb
182
- - test/types/set_type_test.rb
183
185
  - test/types/string_type_test.rb
184
186
  - test/types/time_type_test.rb
185
187
  - test/validations_test.rb
@@ -1,20 +0,0 @@
1
- module CassandraObject
2
- module Types
3
- class SetType
4
- def encode(set)
5
- if set.kind_of?(Set)
6
- set.to_json
7
- elsif set.kind_of?(Array)
8
- set.uniq.to_json
9
- else
10
- raise ArgumentError.new("#{self} requires an Array or Set")
11
- end
12
- end
13
-
14
- def decode(str)
15
- return str.to_a if str.kind_of?(Set)
16
- ActiveSupport::JSON.decode(str)
17
- end
18
- end
19
- end
20
- end
@@ -1,17 +0,0 @@
1
- require 'test_helper'
2
-
3
- class CassandraObject::Types::SetTypeTest < CassandraObject::Types::TestCase
4
- test 'encode' do
5
- assert_equal ['1', '2'].to_json, coder.encode(['1', '2'].to_set)
6
- assert_equal ['1', '2'].to_json, coder.encode(['1', '2', '2'])
7
-
8
- assert_raise ArgumentError do
9
- coder.encode('wtf')
10
- end
11
- end
12
-
13
- test 'decode' do
14
- assert_equal ['1', '2'], coder.decode(['1', '2'].to_set)
15
- assert_equal ['1', '2'], coder.decode(['1', '2'].to_json)
16
- end
17
- end