api_view 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,7 @@
1
+ :directories:
2
+ - lib
3
+ :excludes:
4
+ - test
5
+ - .direnv
6
+ :single_line_report: true
7
+ :show_link_in_terminal: true
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
4
+
5
+ before_install:
6
+ - gem update --system
7
+ - gem --version
8
+ - gem install bundler
9
+
10
+ script: sh/test
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in api_view.gemspec
4
+ gemspec
5
+
6
+ gem 'codecov', :require => false, :group => :test
@@ -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.
@@ -0,0 +1,119 @@
1
+ # ApiView
2
+
3
+ [![Build Status](https://travis-ci.org/mindreframer/api_view.svg?branch=master)](http://travis-ci.org/mindreframer/api_view)
4
+ [![codecov.io](https://codecov.io/github/mindreframer/api_view/coverage.svg?branch=master)](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
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -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,7 @@
1
+ class BoxScore < Model
2
+ attr_reader :attendance,
3
+ :has_statistics,
4
+ :last_play,
5
+ :progress,
6
+ :referees
7
+ 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,11 @@
1
+ class Model
2
+ def initialize(attributes={})
3
+ attributes.each do |attribute, value|
4
+ instance_variable_set("@#{attribute}", value)
5
+ end
6
+ end
7
+
8
+ def read_attribute_for_serialization(attribute)
9
+ send(attribute)
10
+ end
11
+ end
@@ -0,0 +1,7 @@
1
+ class PlayByPlayRecord < Model
2
+ attr_reader :points_type,
3
+ :player_fouls,
4
+ :player_score,
5
+ :record_type,
6
+ :seconds
7
+ end
@@ -0,0 +1,7 @@
1
+ class Team < Model
2
+ attr_reader :abbreviation,
3
+ :full_name,
4
+ :location,
5
+ :medium_name,
6
+ :short_name
7
+ 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
+
@@ -0,0 +1,11 @@
1
+ class BasketballBoxScoreApiView < BoxScoreApiView
2
+
3
+ attributes :attendance, :referees
4
+ main_object :box_score
5
+
6
+
7
+ def instance_convert
8
+ field :last_play, box_score.last_play, via: BasketballPlayByPlayRecordApiView
9
+ end
10
+
11
+ end