api_view 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.coco.yml +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +10 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +119 -0
- data/Rakefile +2 -0
- data/api_view.gemspec +36 -0
- data/benchmark_results.md +13 -0
- data/example/benchmark.rb +43 -0
- data/example/models/box_score.rb +7 -0
- data/example/models/event.rb +20 -0
- data/example/models/event_factory.rb +61 -0
- data/example/models/model.rb +11 -0
- data/example/models/play_by_play_record.rb +7 -0
- data/example/models/team.rb +7 -0
- data/example/require_models.rb +15 -0
- data/example/views/basketball/box_score.rb +11 -0
- data/example/views/basketball/event.rb +15 -0
- data/example/views/basketball/play_by_play_record.rb +4 -0
- data/example/views/basketball/team.rb +3 -0
- data/example/views/box_score.rb +5 -0
- data/example/views/event.rb +11 -0
- data/example/views/event_summary.rb +11 -0
- data/example/views/team.rb +4 -0
- data/lib/api_view.rb +5 -0
- data/lib/api_view/base.rb +88 -0
- data/lib/api_view/default.rb +20 -0
- data/lib/api_view/engine.rb +116 -0
- data/lib/api_view/registry.rb +20 -0
- data/lib/api_view/version.rb +3 -0
- data/sh/c +1 -0
- data/sh/env.rb +5 -0
- data/sh/test +19 -0
- data/sh/update_benchmark +33 -0
- data/test/base_test.rb +119 -0
- data/test/default_test.rb +30 -0
- data/test/engine_test.rb +42 -0
- data/test/registry_test.rb +24 -0
- data/test/test_helper.rb +32 -0
- metadata +285 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 474ae37f4261ac132bcca7331d12e3eac1c56a62
|
4
|
+
data.tar.gz: a794b2806e37db11ae671fd870e88f905f61025d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9461e48f8d5e2cfd3f4a71217d9143cbae4577f67693167e52939eda282fbf8acdb3afe2e26ca70575102d26211bf27430e03e52d092bb936fbe2b51bfa6f0ed
|
7
|
+
data.tar.gz: f8b2ec2d180baa84d3933d8e603cd08e3e3717e0688cbed49730078da2576879e1ca8f3eca7d20b311b0e0a3f0d69886aba907c35a8ef065d64c89fbab0565a4
|
data/.coco.yml
ADDED
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Roman Heinrich
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# ApiView
|
2
|
+
|
3
|
+
[](http://travis-ci.org/mindreframer/api_view)
|
4
|
+
[](https://codecov.io/github/mindreframer/api_view?branch=master)
|
5
|
+
|
6
|
+
a small and very performance focused serializer for complex nested objects. The initial code was taken from `chetan` and was wrapped into a gem with unit-tests and a bit more convenient API. The original links are below:
|
7
|
+
- http://techblog.thescore.com/benchmarking-json-generation-in-ruby/#comment-1678429451
|
8
|
+
- https://github.com/chetan/json_serialization_benchmark/tree/api_view
|
9
|
+
- https://gist.github.com/chetan/d613e8f7d45600e1ca34
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
### Why should you even care? Is (... insert your favourite ruby serializer ... ) not good enough?
|
14
|
+
|
15
|
+
- you want great performance
|
16
|
+
- you care about object allocations (less garbage to collect for the Ruby VM)
|
17
|
+
- you want **blazing** fast test suite, so that you can switch globally the serialization off and test just the shape of the resulting Hash object
|
18
|
+
-> no converting to JSON, then parsing JSON back and checking values on it, that sux!
|
19
|
+
- really small and clean codebase
|
20
|
+
- unit-tested and with test 100% coverage
|
21
|
+
|
22
|
+
ApiView gives you all that and stays very small doing that.
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
## Add this line to your application's Gemfile:
|
27
|
+
gem 'api_view'
|
28
|
+
|
29
|
+
|
30
|
+
## And then execute:
|
31
|
+
$ bundle
|
32
|
+
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
- you inherit from ApiView::Base
|
37
|
+
- you say, what model should be serialized by default with this serializer (optional)
|
38
|
+
- you specify an array of attributes, that will be copied from the object in serializer
|
39
|
+
- you tell how you main object is called (defaults to `object` / `obj`)
|
40
|
+
- you implement `instance_convert`-method for further customization of the serialization
|
41
|
+
-> `field` - a setter method, that also accepts `via: SomeSerializerApiView`
|
42
|
+
|
43
|
+
|
44
|
+
class EventApiView < EventSummaryApiView
|
45
|
+
# default serializer for BoxScore, will be picked, if none other was given
|
46
|
+
for_model ::Event
|
47
|
+
|
48
|
+
# the attributes to copy from the object
|
49
|
+
attributes :share_url, :sport_name
|
50
|
+
|
51
|
+
# the name of your main object, optional
|
52
|
+
main_object :event
|
53
|
+
|
54
|
+
# the method to add additional logic + fields
|
55
|
+
def instance_convert
|
56
|
+
# just a setter method with optional serializer for that sub-object
|
57
|
+
field :box_score, event.box_score, via: BasketballBoxScoreApiView
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
For more examples take a look into the `example/`-folder and run the benchmark script via `ruby example/benchmark.rb`.
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
## Developement
|
67
|
+
|
68
|
+
# run tests
|
69
|
+
$ sh/test
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
## Contributing
|
75
|
+
|
76
|
+
1. Fork it ( https://github.com/[my-github-username]/api_view/fork )
|
77
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
78
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
79
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
80
|
+
5. Create a new Pull Request
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
## Benchmark numbers (ApiView vs the rest of the pack)
|
85
|
+
|
86
|
+
user system total real allocations memsize
|
87
|
+
RABL Ultra Simple 4.860000 0.620000 5.480000 ( 5.493406) 664 25787
|
88
|
+
AMS Ultra Simple 0.220000 0.000000 0.220000 ( 0.220079) 26 650
|
89
|
+
Presenters Ultra Simple 0.140000 0.000000 0.140000 ( 0.152729) 24 650
|
90
|
+
ApiView Ultra Simple 0.190000 0.000000 0.190000 ( 0.193124) 12 842
|
91
|
+
-------------------------------------------------------------------------------------------------------------------
|
92
|
+
RABL Simple 21.470000 3.330000 24.800000 ( 25.147988) 2265 114051
|
93
|
+
AMS Simple 1.060000 0.000000 1.060000 ( 1.066668) 105 2726
|
94
|
+
Presenters Simple 0.610000 0.000000 0.610000 ( 0.611980) 98 2918
|
95
|
+
ApiView Simple 0.280000 0.010000 0.290000 ( 0.292290) 17 2246
|
96
|
+
-------------------------------------------------------------------------------------------------------------------
|
97
|
+
RABL Complex 43.930000 6.850000 50.780000 ( 51.574975) 4325 248000
|
98
|
+
AMS Complex 2.150000 0.000000 2.150000 ( 2.160445) 209 5851
|
99
|
+
Presenters Complex 1.210000 0.010000 1.220000 ( 1.220806) 201 7395
|
100
|
+
ApiView Complex 0.270000 0.000000 0.270000 ( 0.270517) 21 1504
|
101
|
+
|
102
|
+
|
103
|
+
Collection tests:
|
104
|
+
|
105
|
+
user system total real allocations memsize
|
106
|
+
RABL Ultra Simple: Collection 3.560000 0.600000 4.160000 ( 4.182852) 43102 1977224
|
107
|
+
AMS Ultra Simple: Collection 0.120000 0.000000 0.120000 ( 0.124631) 1914 47786
|
108
|
+
Presenters Ultra Simple: Collection 0.100000 0.010000 0.110000 ( 0.109781) 3508 67594
|
109
|
+
ApiView Ultra Simple: Collection 0.050000 0.000000 0.050000 ( 0.050875) 311 46986
|
110
|
+
-------------------------------------------------------------------------------------------------------------------
|
111
|
+
RABL Simple: Collection 18.720000 3.150000 21.870000 ( 21.924020) 202905 11255130
|
112
|
+
AMS Simple: Collection 0.870000 0.010000 0.880000 ( 0.890479) 9714 236186
|
113
|
+
Presenters Simple: Collection 0.540000 0.000000 0.540000 ( 0.542100) 16108 380794
|
114
|
+
ApiView Simple: Collection 0.160000 0.000000 0.160000 ( 0.166484) 812 187386
|
115
|
+
-------------------------------------------------------------------------------------------------------------------
|
116
|
+
RABL Complex: Collection 41.190000 6.680000 47.870000 ( 48.438854) 408015 25251570
|
117
|
+
AMS Complex: Collection 2.170000 0.030000 2.200000 ( 2.211721) 20114 548686
|
118
|
+
Presenters Complex: Collection 1.380000 0.010000 1.390000 ( 1.389608) 34408 960494
|
119
|
+
ApiView Complex: Collection 0.150000 0.000000 0.150000 ( 0.145595) 1212 113186
|
data/Rakefile
ADDED
data/api_view.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'api_view/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "api_view"
|
8
|
+
spec.version = ApiView::VERSION
|
9
|
+
spec.authors = ["Roman Heinrich"]
|
10
|
+
spec.email = ["roman.heinrich@gmail.com"]
|
11
|
+
spec.summary = %q{A fast and nimble object serializer}
|
12
|
+
spec.description = %q{A fast and nimble object serializer}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "require_pattern"
|
24
|
+
spec.add_development_dependency "minitest", '~> 5.4.3'
|
25
|
+
spec.add_development_dependency "mocha"
|
26
|
+
spec.add_development_dependency "minitest-reporters"
|
27
|
+
spec.add_development_dependency "oj"
|
28
|
+
spec.add_development_dependency "multi_json"
|
29
|
+
spec.add_development_dependency "ffaker"
|
30
|
+
spec.add_development_dependency "pry"
|
31
|
+
spec.add_development_dependency "ruby-prof"
|
32
|
+
spec.add_development_dependency "allocation_stats"
|
33
|
+
spec.add_development_dependency "bixby-bench"
|
34
|
+
spec.add_development_dependency "coco"
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
Object tests:
|
3
|
+
user system total real allocations memsize
|
4
|
+
ApiView Ultra Simple 0.180000 0.000000 0.180000 ( 0.184020) 13 648
|
5
|
+
ApiView Simple 0.310000 0.010000 0.320000 ( 0.318673) 17 2251
|
6
|
+
ApiView Complex 0.350000 0.000000 0.350000 ( 0.352970) 17 1501
|
7
|
+
|
8
|
+
|
9
|
+
Collection tests:
|
10
|
+
user system total real allocations memsize
|
11
|
+
ApiView Ultra Simple: Collection 0.030000 0.000000 0.030000 ( 0.028780) 113 46882
|
12
|
+
ApiView Simple: Collection 0.140000 0.010000 0.150000 ( 0.144577) 712 187886
|
13
|
+
ApiView Complex: Collection 0.140000 0.000000 0.140000 ( 0.140050) 712 112886
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require './example/require_models'
|
2
|
+
# require 'ruby-prof'
|
3
|
+
# require 'allocation_stats'
|
4
|
+
require 'bixby/bench'
|
5
|
+
|
6
|
+
module SerializationBenchmark
|
7
|
+
collection_size = 100
|
8
|
+
event = EventFactory.build_event
|
9
|
+
team = event.home_team
|
10
|
+
|
11
|
+
event_collection = collection_size.times.map { event }
|
12
|
+
team_collection = collection_size.times.map { EventFactory.home_team }
|
13
|
+
|
14
|
+
puts "\nObject tests:\n"
|
15
|
+
Bixby::Bench.run(10_000) do |b|
|
16
|
+
b.sample('ApiView Ultra Simple') do
|
17
|
+
ApiView::Engine.render(team)
|
18
|
+
end
|
19
|
+
|
20
|
+
b.sample('ApiView Simple') do
|
21
|
+
EventSummaryApiView.render(event)
|
22
|
+
end
|
23
|
+
|
24
|
+
b.sample('ApiView Complex') do
|
25
|
+
BasketballEventApiView.render(event)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
puts "\n\nCollection tests:\n"
|
30
|
+
Bixby::Bench.run(100) do |b|
|
31
|
+
b.sample('ApiView Ultra Simple: Collection') do
|
32
|
+
ApiView::Engine.render(team_collection)
|
33
|
+
end
|
34
|
+
|
35
|
+
b.sample('ApiView Simple: Collection') do
|
36
|
+
EventSummaryApiView.render(event_collection)
|
37
|
+
end
|
38
|
+
|
39
|
+
b.sample('ApiView Complex: Collection') do
|
40
|
+
BasketballEventApiView.render(event_collection)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Event < Model
|
2
|
+
attr_reader :away_ranking,
|
3
|
+
:away_region,
|
4
|
+
:away_team,
|
5
|
+
:box_score,
|
6
|
+
:game_date,
|
7
|
+
:game_type,
|
8
|
+
:home_ranking,
|
9
|
+
:home_region,
|
10
|
+
:home_team,
|
11
|
+
:important,
|
12
|
+
:location,
|
13
|
+
:share_url,
|
14
|
+
:sport_name,
|
15
|
+
:status
|
16
|
+
|
17
|
+
def ncaa?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'ffaker'
|
2
|
+
class EventFactory
|
3
|
+
def self.build_event
|
4
|
+
Event.new(
|
5
|
+
away_team: away_team,
|
6
|
+
box_score: box_score,
|
7
|
+
home_team: home_team,
|
8
|
+
away_ranking: 10,
|
9
|
+
away_region: 'Pac-12',
|
10
|
+
game_date: Date.today,
|
11
|
+
game_type: 'Regular Season',
|
12
|
+
home_ranking: 15,
|
13
|
+
home_region: 'Top 25',
|
14
|
+
important: true,
|
15
|
+
location: 'Washington, DC',
|
16
|
+
share_url: 'http://thesco.re/123',
|
17
|
+
sport_name: 'basketball',
|
18
|
+
status: 'Final'
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.last_play
|
23
|
+
PlayByPlayRecord.new(
|
24
|
+
points_type: 'Field Goal',
|
25
|
+
player_fouls: 10,
|
26
|
+
player_score: 15,
|
27
|
+
record_type: 'Postseason',
|
28
|
+
seconds: 100
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.box_score
|
33
|
+
BoxScore.new(
|
34
|
+
last_play: last_play,
|
35
|
+
attendance: '21,307',
|
36
|
+
has_statistics: true,
|
37
|
+
progress: '11:23 2nd',
|
38
|
+
referees: 'Thuva, Nate, Roel'
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.away_team
|
43
|
+
Team.new(
|
44
|
+
abbreviation: 'MIA',
|
45
|
+
full_name: Faker::Name.name,
|
46
|
+
location: Faker::AddressUS.state,
|
47
|
+
meidum_name: 'Miami',
|
48
|
+
short_name: 'Heats'
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.home_team
|
53
|
+
Team.new(
|
54
|
+
abbreviation: 'TOR',
|
55
|
+
full_name: Faker::Name.name,
|
56
|
+
location: Faker::AddressUS.state,
|
57
|
+
medium_name: Faker::AddressUS.state,
|
58
|
+
short_name: 'Raptors'
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.setup
|
3
|
+
require 'benchmark'
|
4
|
+
require 'api_view'
|
5
|
+
|
6
|
+
require 'multi_json'
|
7
|
+
require 'oj'
|
8
|
+
require 'pry'
|
9
|
+
Oj.mimic_JSON() # this will speedup benchmarks using #to_json
|
10
|
+
|
11
|
+
|
12
|
+
require 'require_pattern'
|
13
|
+
require_relative_pattern 'models/**/**.rb'
|
14
|
+
require_relative_pattern 'views/**/**.rb'
|
15
|
+
|