ruby-serializer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +25 -0
- data/LICENSE +20 -0
- data/Rakefile +10 -0
- data/lib/ruby_serializer/base.rb +62 -0
- data/lib/ruby_serializer/dsl.rb +27 -0
- data/lib/ruby_serializer/field.rb +55 -0
- data/lib/ruby_serializer.rb +46 -0
- data/readme.md +110 -0
- data/ruby-serializer.gemspec +31 -0
- data/test/basic_test.rb +95 -0
- data/test/expose_test.rb +197 -0
- data/test/test_case.rb +19 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 76d0570d6c6888182f54fad8d93447115da9b15d
|
4
|
+
data.tar.gz: fadc5ff494af8792ba60f1c76b90cc822ed90f4c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0d35417352d902d4e46cd7de29e7151fe6024b784f6b46a0029bf38cd4db8545c8e559f6f71a82e9d75dbcefadf3411eab517a7b60ab4dc39baa23aeaae2313a
|
7
|
+
data.tar.gz: 5a0ea330adc5f8ad4cdac778524677342547f30888fadadae3f527b2a685070e6f32557a8854d6a759647747638a6f60593a9224967241cda736521663ed6c35
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ruby-serializer (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: http://rubygems.org/
|
8
|
+
specs:
|
9
|
+
awesome_print (1.7.0)
|
10
|
+
byebug (9.0.5)
|
11
|
+
minitest (5.9.0)
|
12
|
+
rake (11.2.2)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
awesome_print (~> 1.7)
|
19
|
+
byebug (~> 9.0)
|
20
|
+
minitest (~> 5.9)
|
21
|
+
rake (~> 11.0)
|
22
|
+
ruby-serializer!
|
23
|
+
|
24
|
+
BUNDLED WITH
|
25
|
+
1.12.3
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2016, Jake Gordon and contributors
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
20
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
#------------------------------------------------------------------------------
|
4
|
+
|
5
|
+
Rake::TestTask.new do |t|
|
6
|
+
t.test_files = FileList['test/**/*_test.rb']
|
7
|
+
t.verbose = true
|
8
|
+
end
|
9
|
+
|
10
|
+
#------------------------------------------------------------------------------
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module RubySerializer
|
2
|
+
class Base
|
3
|
+
|
4
|
+
extend RubySerializer::Dsl
|
5
|
+
|
6
|
+
attr_reader :options, :include # only populated during #serialize and (temporarily) stores the #serialize options to make
|
7
|
+
# them available to any potential :value, :only and :unless lambdas in the derived serializer
|
8
|
+
|
9
|
+
def initialize(resource)
|
10
|
+
@resource = resource
|
11
|
+
end
|
12
|
+
|
13
|
+
def as_json(options = {})
|
14
|
+
json = serialize(options)
|
15
|
+
json = { options[:root] => json } if options[:root]
|
16
|
+
json
|
17
|
+
end
|
18
|
+
|
19
|
+
#----------------------------------------------------------------------------------------------
|
20
|
+
# PRIVATE implementation
|
21
|
+
#----------------------------------------------------------------------------------------------
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :resource
|
26
|
+
|
27
|
+
def serialize(options = {})
|
28
|
+
if resource.respond_to? :to_ary
|
29
|
+
serialize_array(options)
|
30
|
+
else
|
31
|
+
serialize_object(options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def serialize_array(options)
|
36
|
+
resource.map do |item|
|
37
|
+
serializer = RubySerializer.build(item)
|
38
|
+
serializer.send :serialize, options.merge(root: nil)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def serialize_object(options)
|
43
|
+
@options = options
|
44
|
+
json = {}
|
45
|
+
json[:errors] = resource.errors if resource.respond_to?(:valid?) && !resource.valid?
|
46
|
+
self.class.fields.each do |field|
|
47
|
+
next unless field.present?(resource, self)
|
48
|
+
key = field.as
|
49
|
+
ns = namespace(field, json)
|
50
|
+
ns[key] = field.serialize(resource, self)
|
51
|
+
end
|
52
|
+
json
|
53
|
+
end
|
54
|
+
|
55
|
+
def namespace(field, json)
|
56
|
+
field.namespace.reduce(json) { |ns, name| ns[name] ||= {} }
|
57
|
+
end
|
58
|
+
|
59
|
+
#----------------------------------------------------------------------------------------------
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RubySerializer
|
2
|
+
module Dsl
|
3
|
+
|
4
|
+
def serializes(name)
|
5
|
+
define_method(name) do # provide a friendly-name accessor to the underlying resource
|
6
|
+
resource
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def expose(field, options = {})
|
11
|
+
fields << Field.new(field, namespace, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def fields
|
15
|
+
@fields ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
def namespace(ns = nil, &block)
|
19
|
+
@namespace ||= []
|
20
|
+
return @namespace if ns.nil? # this method acts as both getter (this line) and setter (subsequent)
|
21
|
+
@namespace.push(ns)
|
22
|
+
block.call(binding)
|
23
|
+
@namespace.pop
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module RubySerializer
|
2
|
+
class Field
|
3
|
+
|
4
|
+
attr_reader :field, :as, :from, :value, :namespace
|
5
|
+
|
6
|
+
def initialize(field, namespace, options)
|
7
|
+
@field = field.to_sym
|
8
|
+
@as = options[:as] || field
|
9
|
+
@from = options[:from] || field
|
10
|
+
@value = options[:value]
|
11
|
+
@only = options[:only]
|
12
|
+
@unless = options[:unless]
|
13
|
+
@namespace = namespace.dup
|
14
|
+
end
|
15
|
+
|
16
|
+
def serialize(resource, serializer)
|
17
|
+
case value
|
18
|
+
when nil then resource.send(from)
|
19
|
+
when Symbol then resource.send(value)
|
20
|
+
when Proc then serializer.instance_exec(&value)
|
21
|
+
else
|
22
|
+
value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def present?(resource, serializer)
|
27
|
+
only?(resource, serializer) && !unless?(resource, serializer)
|
28
|
+
end
|
29
|
+
|
30
|
+
def only?(resource, serializer)
|
31
|
+
case @only
|
32
|
+
when nil then true
|
33
|
+
when true then true
|
34
|
+
when false then false
|
35
|
+
when Symbol then resource.send(@only)
|
36
|
+
when Proc then serializer.instance_exec(&@only)
|
37
|
+
else
|
38
|
+
raise ArgumentError, "unexpected #{@only}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def unless?(resource, serializer)
|
43
|
+
case @unless
|
44
|
+
when nil then false
|
45
|
+
when true then true
|
46
|
+
when false then false
|
47
|
+
when Symbol then resource.send(@unless)
|
48
|
+
when Proc then serializer.instance_exec(&@unless)
|
49
|
+
else
|
50
|
+
raise ArgumentError, "unexpected #{@unless}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module RubySerializer
|
2
|
+
|
3
|
+
#------------------------------------------------------------------------------------------------
|
4
|
+
|
5
|
+
VERSION = '0.0.1'
|
6
|
+
SUMMARY = 'Serialize POROs to JSON'
|
7
|
+
DESCRIPTION = 'A general purpose library for serializing plain old ruby objects (POROs) into JSON using a declarative DSL'
|
8
|
+
LIB = File.dirname(__FILE__)
|
9
|
+
|
10
|
+
#------------------------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
autoload :Dsl, File.join(LIB, 'ruby_serializer/dsl')
|
13
|
+
autoload :Base, File.join(LIB, 'ruby_serializer/base')
|
14
|
+
autoload :Field, File.join(LIB, 'ruby_serializer/field')
|
15
|
+
|
16
|
+
#------------------------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
def self.build(resource, options = {})
|
19
|
+
serializer_class = options[:with] || options[:serializer] || detect_serializer(resource)
|
20
|
+
serializer_class.new(resource)
|
21
|
+
end
|
22
|
+
|
23
|
+
#------------------------------------------------------------------------------------------------
|
24
|
+
|
25
|
+
def self.as_json(resource, options = {})
|
26
|
+
build_options = {
|
27
|
+
with: options.delete(:with),
|
28
|
+
serializer: options.delete(:serializer)
|
29
|
+
}
|
30
|
+
build(resource, build_options).as_json(options)
|
31
|
+
end
|
32
|
+
|
33
|
+
#------------------------------------------------------------------------------------------------
|
34
|
+
|
35
|
+
def self.detect_serializer(resource)
|
36
|
+
return RubySerializer::Base if resource.respond_to?(:to_ary)
|
37
|
+
namespace = resource.class.name.split("::")
|
38
|
+
scope = Kernel.const_get namespace[0...-1].join("::") if namespace.length > 1
|
39
|
+
scope ||= Kernel
|
40
|
+
name = namespace.last
|
41
|
+
scope.const_get "#{name}Serializer"
|
42
|
+
end
|
43
|
+
|
44
|
+
#------------------------------------------------------------------------------------------------
|
45
|
+
|
46
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# Ruby Serializer (v0.0.1)
|
2
|
+
|
3
|
+
A general purpose library for serializing models (e.g, an ActiveModel or a PORO)
|
4
|
+
into JSON using a declarative DSL.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
```bash
|
9
|
+
$ gem install ruby-serializer # ... or add to your Gemfile as appropriate
|
10
|
+
```
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
Assuming you have a model similar to...
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
class Shape
|
18
|
+
attr :size, :color, :shape, ...
|
19
|
+
end
|
20
|
+
```
|
21
|
+
|
22
|
+
You can declare a serializer as follows...
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
class ShapeSerializer < RubySerializer::Base
|
26
|
+
expose :size
|
27
|
+
expose :color
|
28
|
+
expose :shape
|
29
|
+
end
|
30
|
+
```
|
31
|
+
|
32
|
+
And serialize using...
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
shape = Shape.new(size: 'large', color: 'red', shape: 'square') # load as appropriate
|
36
|
+
json = RubySerializer.as_json shape
|
37
|
+
|
38
|
+
# { size: 'large', color: 'red', shape: 'square' }
|
39
|
+
```
|
40
|
+
|
41
|
+
## Beyond the basics
|
42
|
+
|
43
|
+
Ok, that was very basic, but with RubySerializer you can also:
|
44
|
+
|
45
|
+
* expose attributes `:as` another name
|
46
|
+
* expose attributes with a custom `:value`
|
47
|
+
* expose attributes conditionally with `:only` and `:unless`
|
48
|
+
* expose attributes within a nested `:namespace`
|
49
|
+
* expose model `:errors` if `!model.valid?`
|
50
|
+
* `:include` nested `:belongs_to` associated models
|
51
|
+
* `:include` nested `:has_one` associated models
|
52
|
+
* `:include` nested `:has_many` associated models
|
53
|
+
* serialize an array of models
|
54
|
+
* add `ActionController` integration for easy API serialization
|
55
|
+
|
56
|
+
### Exposing attributes with another name
|
57
|
+
|
58
|
+
>> _TODO_
|
59
|
+
|
60
|
+
### Exposing attributes with custom values
|
61
|
+
|
62
|
+
>> _TODO_
|
63
|
+
|
64
|
+
### Exposing attributes conditionally
|
65
|
+
|
66
|
+
>> _TODO_
|
67
|
+
|
68
|
+
### Exposing attributes within a namespace
|
69
|
+
|
70
|
+
>> _TODO_
|
71
|
+
|
72
|
+
### Exposing model validation errors
|
73
|
+
|
74
|
+
>> _TODO_
|
75
|
+
|
76
|
+
### Exposing associations
|
77
|
+
|
78
|
+
>> _TODO_
|
79
|
+
|
80
|
+
### Serializing arrays
|
81
|
+
|
82
|
+
>> _TODO_
|
83
|
+
|
84
|
+
### ActionController integration
|
85
|
+
|
86
|
+
>> _TODO_
|
87
|
+
|
88
|
+
# TODO
|
89
|
+
|
90
|
+
* :belongs_to
|
91
|
+
* :has_one
|
92
|
+
* :has_many
|
93
|
+
* :includes
|
94
|
+
* ActionController integration
|
95
|
+
* documentation
|
96
|
+
|
97
|
+
# Roadmap
|
98
|
+
|
99
|
+
* Extensibility with custom Field types
|
100
|
+
|
101
|
+
# License
|
102
|
+
|
103
|
+
See [LICENSE](https://github.com/jakesgordon/ruby-serializer/blob/master/LICENSE) file.
|
104
|
+
|
105
|
+
# Contact
|
106
|
+
|
107
|
+
If you have any ideas, feedback, requests or bug reports, you can reach me at
|
108
|
+
[jake@codeincomplete.com](mailto:jake@codeincomplete.com), or via
|
109
|
+
my website: [Code inComplete](http://codeincomplete.com).
|
110
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require_relative 'lib/ruby_serializer'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
|
6
|
+
s.name = "ruby-serializer"
|
7
|
+
s.version = RubySerializer::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jake Gordon"]
|
10
|
+
s.email = ["jake@codeincomplete.com"]
|
11
|
+
s.homepage = "https://github.com/jakesgordon/ruby-serializer"
|
12
|
+
s.summary = RubySerializer::SUMMARY
|
13
|
+
s.description = RubySerializer::DESCRIPTION
|
14
|
+
s.licenses = [ 'MIT' ]
|
15
|
+
|
16
|
+
s.required_ruby_version = '~> 2.3'
|
17
|
+
|
18
|
+
s.add_development_dependency 'rake', '~> 11.0'
|
19
|
+
s.add_development_dependency 'minitest', '~> 5.9'
|
20
|
+
s.add_development_dependency 'awesome_print', '~> 1.7'
|
21
|
+
s.add_development_dependency 'byebug', '~> 9.0'
|
22
|
+
|
23
|
+
s.has_rdoc = false
|
24
|
+
s.extra_rdoc_files = ["readme.md"]
|
25
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
26
|
+
s.files = `git ls-files `.split("\n")
|
27
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
28
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
29
|
+
s.require_paths = ["lib"]
|
30
|
+
|
31
|
+
end
|
data/test/basic_test.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require_relative 'test_case'
|
2
|
+
|
3
|
+
module RubySerializer
|
4
|
+
class BasicTest < TestCase
|
5
|
+
|
6
|
+
#----------------------------------------------------------------------------------------------
|
7
|
+
|
8
|
+
def test_gem_information
|
9
|
+
assert_equal '0.0.1', VERSION
|
10
|
+
assert_equal 'Serialize POROs to JSON', SUMMARY
|
11
|
+
assert_match 'A general purpose library for', DESCRIPTION
|
12
|
+
end
|
13
|
+
|
14
|
+
#----------------------------------------------------------------------------------------------
|
15
|
+
|
16
|
+
Shape = Struct.new(:color, :shape)
|
17
|
+
Car = Struct.new(:make, :model)
|
18
|
+
|
19
|
+
class ShapeSerializer < RubySerializer::Base
|
20
|
+
expose :color
|
21
|
+
expose :shape
|
22
|
+
end
|
23
|
+
|
24
|
+
class CarSerializer < RubySerializer::Base
|
25
|
+
expose :make
|
26
|
+
expose :model
|
27
|
+
end
|
28
|
+
|
29
|
+
#----------------------------------------------------------------------------------------------
|
30
|
+
|
31
|
+
def test_basic_serialization
|
32
|
+
|
33
|
+
json = RubySerializer.as_json Shape.new(:red, :square)
|
34
|
+
assert_set [ :color, :shape ], json.keys
|
35
|
+
assert_equal :red, json[:color]
|
36
|
+
assert_equal :square, json[:shape]
|
37
|
+
|
38
|
+
json = RubySerializer.as_json Car.new(:honda, :civic)
|
39
|
+
assert_set [ :make, :model ], json.keys
|
40
|
+
assert_equal :honda, json[:make]
|
41
|
+
assert_equal :civic, json[:model]
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
#----------------------------------------------------------------------------------------------
|
46
|
+
|
47
|
+
def test_array_serialization
|
48
|
+
resources = [
|
49
|
+
Shape.new(:red, :square),
|
50
|
+
Shape.new(:blue, :circle),
|
51
|
+
Car.new(:honda, :civic),
|
52
|
+
Car.new(:jeep, :wrangler)
|
53
|
+
]
|
54
|
+
json = RubySerializer.as_json resources
|
55
|
+
assert_equal resources.length, json.length
|
56
|
+
assert_set [ :color, :shape ], json[0].keys
|
57
|
+
assert_equal :red, json[0][:color]
|
58
|
+
assert_equal :square, json[0][:shape]
|
59
|
+
assert_equal [ :color, :shape ], json[1].keys
|
60
|
+
assert_equal :blue, json[1][:color]
|
61
|
+
assert_equal :circle, json[1][:shape]
|
62
|
+
assert_equal [ :make, :model ], json[2].keys
|
63
|
+
assert_equal :honda, json[2][:make]
|
64
|
+
assert_equal :civic, json[2][:model]
|
65
|
+
assert_equal [ :make, :model ], json[3].keys
|
66
|
+
assert_equal :jeep, json[3][:make]
|
67
|
+
assert_equal :wrangler, json[3][:model]
|
68
|
+
end
|
69
|
+
|
70
|
+
#----------------------------------------------------------------------------------------------
|
71
|
+
|
72
|
+
def test_serialize_with_root
|
73
|
+
json = RubySerializer.as_json Car.new(:honda, :civic), root: :car
|
74
|
+
assert_set [ :car ], json.keys
|
75
|
+
assert_equal :honda, json[:car][:make]
|
76
|
+
assert_equal :civic, json[:car][:model]
|
77
|
+
end
|
78
|
+
|
79
|
+
#----------------------------------------------------------------------------------------------
|
80
|
+
|
81
|
+
def test_serialize_with_errors
|
82
|
+
resource = OpenStruct.new(color: :red, shape: :sausages, valid?: false, errors: { shape: 'is invalid' })
|
83
|
+
json = RubySerializer.as_json resource, with: ShapeSerializer
|
84
|
+
expected = [ :color, :shape, :errors ]
|
85
|
+
assert_set expected, json.keys
|
86
|
+
assert_equal :red, json[:color]
|
87
|
+
assert_equal :sausages, json[:shape]
|
88
|
+
assert_set [ :shape ], json[:errors].keys
|
89
|
+
assert_equal 'is invalid', json[:errors][:shape]
|
90
|
+
end
|
91
|
+
|
92
|
+
#----------------------------------------------------------------------------------------------
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
data/test/expose_test.rb
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
require_relative 'test_case'
|
2
|
+
|
3
|
+
module RubySerializer
|
4
|
+
class ExposeTest < TestCase
|
5
|
+
|
6
|
+
#----------------------------------------------------------------------------------------------
|
7
|
+
|
8
|
+
ID = 42
|
9
|
+
NAME = 'Name'
|
10
|
+
EMAIL = 'Email'
|
11
|
+
SECRET = 'Secret'
|
12
|
+
|
13
|
+
Resource = OpenStruct
|
14
|
+
|
15
|
+
#==============================================================================================
|
16
|
+
# Sample Serializers
|
17
|
+
#==============================================================================================
|
18
|
+
|
19
|
+
class BasicSerializer < RubySerializer::Base
|
20
|
+
expose :id
|
21
|
+
expose :name
|
22
|
+
expose :email
|
23
|
+
end
|
24
|
+
|
25
|
+
#----------------------------------------------------------------------------------------------
|
26
|
+
|
27
|
+
class RenamingSerializer < RubySerializer::Base
|
28
|
+
expose :id
|
29
|
+
expose :name, as: :user_name
|
30
|
+
expose :user_email, from: :email
|
31
|
+
end
|
32
|
+
|
33
|
+
#----------------------------------------------------------------------------------------------
|
34
|
+
|
35
|
+
class NamespaceSerializer < RubySerializer::Base
|
36
|
+
expose :id
|
37
|
+
namespace :user do
|
38
|
+
expose :name
|
39
|
+
expose :email
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#----------------------------------------------------------------------------------------------
|
44
|
+
|
45
|
+
class CustomValueSerializer < RubySerializer::Base
|
46
|
+
expose :id
|
47
|
+
expose :static, value: 'static value'
|
48
|
+
expose :method, value: :method_value
|
49
|
+
expose :dynamic, value: -> { "dynamic value (#{resource.name})" }
|
50
|
+
expose :empty, value: nil
|
51
|
+
end
|
52
|
+
|
53
|
+
#----------------------------------------------------------------------------------------------
|
54
|
+
|
55
|
+
class ConditionalSerializer < RubySerializer::Base
|
56
|
+
expose :id
|
57
|
+
expose :only_true, value: 'only true', only: true
|
58
|
+
expose :only_false, value: 'only false', only: false
|
59
|
+
expose :only_method, value: 'only method', only: :show
|
60
|
+
expose :only_dynamic, value: 'only dynamic', only: -> { resource.show }
|
61
|
+
expose :unless_true, value: 'unless true', unless: true
|
62
|
+
expose :unless_false, value: 'unless false', unless: false
|
63
|
+
expose :unless_method, value: 'unless method', unless: :show
|
64
|
+
expose :unless_dynamic, value: 'unless dynamic', unless: -> { resource.show }
|
65
|
+
end
|
66
|
+
|
67
|
+
#----------------------------------------------------------------------------------------------
|
68
|
+
|
69
|
+
class CustomResourceNameSerializer < RubySerializer::Base
|
70
|
+
serializes :user
|
71
|
+
expose :id
|
72
|
+
expose :value, value: -> { "value is #{user.value}" }
|
73
|
+
expose :show_only, value: 'show only', only: -> { user.show }
|
74
|
+
expose :show_unless, value: 'show unless', unless: -> { user.show }
|
75
|
+
end
|
76
|
+
|
77
|
+
#----------------------------------------------------------------------------------------------
|
78
|
+
|
79
|
+
class CustomOptionsSerializer < RubySerializer::Base
|
80
|
+
expose :id
|
81
|
+
expose :value, value: -> { "value is #{options[:value]}" }
|
82
|
+
expose :show_only, value: 'show only', only: -> { options[:show] }
|
83
|
+
expose :show_unless, value: 'show unless', unless: -> { options[:show] }
|
84
|
+
end
|
85
|
+
|
86
|
+
#==============================================================================================
|
87
|
+
# TESTS
|
88
|
+
#==============================================================================================
|
89
|
+
|
90
|
+
def test_expose_attributes_unchanged
|
91
|
+
resource = Resource.new(id: ID, name: NAME, email: EMAIL, secret: SECRET)
|
92
|
+
json = RubySerializer.as_json resource, with: BasicSerializer
|
93
|
+
expected = [ :id, :name, :email ]
|
94
|
+
assert_set expected, json.keys
|
95
|
+
assert_equal ID, json[:id]
|
96
|
+
assert_equal NAME, json[:name]
|
97
|
+
assert_equal EMAIL, json[:email]
|
98
|
+
end
|
99
|
+
|
100
|
+
#----------------------------------------------------------------------------------------------
|
101
|
+
|
102
|
+
def test_expose_renamed_attributes
|
103
|
+
resource = Resource.new(id: ID, name: NAME, email: EMAIL, secret: SECRET)
|
104
|
+
json = RubySerializer.as_json resource, with: RenamingSerializer
|
105
|
+
expected = [ :id, :user_name, :user_email ]
|
106
|
+
assert_set expected, json.keys
|
107
|
+
assert_equal ID, json[:id]
|
108
|
+
assert_equal NAME, json[:user_name]
|
109
|
+
assert_equal EMAIL, json[:user_email]
|
110
|
+
end
|
111
|
+
|
112
|
+
#----------------------------------------------------------------------------------------------
|
113
|
+
|
114
|
+
def test_expose_namespaced_attributes
|
115
|
+
resource = Resource.new(id: ID, name: NAME, email: EMAIL, secret: SECRET)
|
116
|
+
json = RubySerializer.as_json resource, with: NamespaceSerializer
|
117
|
+
expected = [ :id, :user ]
|
118
|
+
assert_set expected, json.keys
|
119
|
+
assert_equal ID, json[:id]
|
120
|
+
assert_equal NAME, json[:user][:name]
|
121
|
+
assert_equal EMAIL, json[:user][:email]
|
122
|
+
assert_equal [ :name, :email ], json[:user].keys
|
123
|
+
end
|
124
|
+
|
125
|
+
#----------------------------------------------------------------------------------------------
|
126
|
+
|
127
|
+
def test_expose_attributes_with_custom_values
|
128
|
+
resource = Resource.new(id: ID, name: NAME, method_value: 'method value')
|
129
|
+
json = RubySerializer.as_json resource, with: CustomValueSerializer
|
130
|
+
expected = [ :id, :static, :dynamic, :method, :empty ]
|
131
|
+
assert_set expected, json.keys
|
132
|
+
assert_equal ID, json[:id]
|
133
|
+
assert_equal 'static value', json[:static]
|
134
|
+
assert_equal 'dynamic value (Name)', json[:dynamic]
|
135
|
+
assert_equal 'method value', json[:method]
|
136
|
+
assert_equal nil, json[:empty]
|
137
|
+
end
|
138
|
+
|
139
|
+
#----------------------------------------------------------------------------------------------
|
140
|
+
|
141
|
+
def test_expose_attributes_conditionally
|
142
|
+
show = RubySerializer.as_json Resource.new(id: ID, show: true), with: ConditionalSerializer
|
143
|
+
noshow = RubySerializer.as_json Resource.new(id: ID, show: false), with: ConditionalSerializer
|
144
|
+
unspecified = RubySerializer.as_json Resource.new(id: ID), with: ConditionalSerializer
|
145
|
+
assert_set [ :id, :only_true, :unless_false, :only_method, :only_dynamic ], show.keys
|
146
|
+
assert_set [ :id, :only_true, :unless_false, :unless_method, :unless_dynamic ], noshow.keys
|
147
|
+
assert_set [ :id, :only_true, :unless_false, :unless_method, :unless_dynamic ], unspecified.keys
|
148
|
+
end
|
149
|
+
|
150
|
+
#----------------------------------------------------------------------------------------------
|
151
|
+
|
152
|
+
def test_expose_attributes_using_custom_resource_name
|
153
|
+
|
154
|
+
resource = Resource.new(id: ID, value: 42, show: false)
|
155
|
+
json = RubySerializer.as_json resource, with: CustomResourceNameSerializer
|
156
|
+
expected = [ :id, :value, :show_unless ]
|
157
|
+
assert_set expected, json.keys
|
158
|
+
assert_equal ID, json[:id]
|
159
|
+
assert_equal "value is 42", json[:value]
|
160
|
+
assert_equal "show unless", json[:show_unless]
|
161
|
+
|
162
|
+
resource = Resource.new(id: ID, value: 99, show: true)
|
163
|
+
json = RubySerializer.as_json resource, with: CustomResourceNameSerializer
|
164
|
+
expected = [ :id, :value, :show_only ]
|
165
|
+
assert_set expected, json.keys
|
166
|
+
assert_equal ID, json[:id]
|
167
|
+
assert_equal "value is 99", json[:value]
|
168
|
+
assert_equal "show only", json[:show_only]
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
#----------------------------------------------------------------------------------------------
|
173
|
+
|
174
|
+
def test_expose_attributes_using_arbitrary_options_passed_into_serializer
|
175
|
+
|
176
|
+
resource = Resource.new(id: ID)
|
177
|
+
|
178
|
+
json = RubySerializer.as_json resource, value: 42, show: false, with: CustomOptionsSerializer
|
179
|
+
expected = [ :id, :value, :show_unless ]
|
180
|
+
assert_set expected, json.keys
|
181
|
+
assert_equal ID, json[:id]
|
182
|
+
assert_equal "value is 42", json[:value]
|
183
|
+
assert_equal "show unless", json[:show_unless]
|
184
|
+
|
185
|
+
json = RubySerializer.as_json resource, value: 99, show: true, with: CustomOptionsSerializer
|
186
|
+
expected = [ :id, :value, :show_only ]
|
187
|
+
assert_set expected, json.keys
|
188
|
+
assert_equal ID, json[:id]
|
189
|
+
assert_equal "value is 99", json[:value]
|
190
|
+
assert_equal "show only", json[:show_only]
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
#----------------------------------------------------------------------------------------------
|
195
|
+
|
196
|
+
end
|
197
|
+
end
|
data/test/test_case.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative '../lib/ruby_serializer'
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/pride'
|
5
|
+
require 'byebug'
|
6
|
+
|
7
|
+
module RubySerializer
|
8
|
+
class TestCase < Minitest::Test
|
9
|
+
|
10
|
+
#----------------------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
def assert_set(expected, actual, message = nil)
|
13
|
+
assert_equal Set.new(expected), Set.new(actual), message
|
14
|
+
end
|
15
|
+
|
16
|
+
#----------------------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-serializer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jake Gordon
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-07-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '11.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '11.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.9'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.9'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: awesome_print
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.7'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.7'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: byebug
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '9.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '9.0'
|
69
|
+
description: A general purpose library for serializing plain old ruby objects (POROs)
|
70
|
+
into JSON using a declarative DSL
|
71
|
+
email:
|
72
|
+
- jake@codeincomplete.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files:
|
76
|
+
- readme.md
|
77
|
+
files:
|
78
|
+
- ".gitignore"
|
79
|
+
- Gemfile
|
80
|
+
- Gemfile.lock
|
81
|
+
- LICENSE
|
82
|
+
- Rakefile
|
83
|
+
- lib/ruby_serializer.rb
|
84
|
+
- lib/ruby_serializer/base.rb
|
85
|
+
- lib/ruby_serializer/dsl.rb
|
86
|
+
- lib/ruby_serializer/field.rb
|
87
|
+
- readme.md
|
88
|
+
- ruby-serializer.gemspec
|
89
|
+
- test/basic_test.rb
|
90
|
+
- test/expose_test.rb
|
91
|
+
- test/test_case.rb
|
92
|
+
homepage: https://github.com/jakesgordon/ruby-serializer
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options:
|
98
|
+
- "--charset=UTF-8"
|
99
|
+
require_paths:
|
100
|
+
- lib
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - "~>"
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '2.3'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 2.5.1
|
114
|
+
signing_key:
|
115
|
+
specification_version: 4
|
116
|
+
summary: Serialize POROs to JSON
|
117
|
+
test_files: []
|