knuckles 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.rubocop.yml +33 -0
- data/.travis.yml +10 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +77 -0
- data/Rakefile +9 -0
- data/bench/bench_helper.rb +48 -0
- data/bench/fixtures/serializers.rb +93 -0
- data/bench/fixtures/submissions.json +1 -0
- data/bench/profiling.rb +14 -0
- data/bench/realistic.rb +9 -0
- data/bench/simple.rb +25 -0
- data/bin/rspec +16 -0
- data/knuckles.gemspec +24 -0
- data/lib/knuckles/combiner.rb +26 -0
- data/lib/knuckles/dumper.rb +21 -0
- data/lib/knuckles/fetcher.rb +30 -0
- data/lib/knuckles/hydrator.rb +29 -0
- data/lib/knuckles/keygen.rb +13 -0
- data/lib/knuckles/pipeline.rb +56 -0
- data/lib/knuckles/renderer.rb +27 -0
- data/lib/knuckles/version.rb +3 -0
- data/lib/knuckles/view.rb +28 -0
- data/lib/knuckles/writer.rb +41 -0
- data/lib/knuckles.rb +50 -0
- data/spec/knuckles/combiner_spec.rb +36 -0
- data/spec/knuckles/dumper_spec.rb +33 -0
- data/spec/knuckles/fetcher_spec.rb +32 -0
- data/spec/knuckles/hydrator_spec.rb +22 -0
- data/spec/knuckles/keygen_spec.rb +19 -0
- data/spec/knuckles/pipeline_spec.rb +96 -0
- data/spec/knuckles/renderer_spec.rb +32 -0
- data/spec/knuckles/view_spec.rb +38 -0
- data/spec/knuckles/writer_spec.rb +41 -0
- data/spec/knuckles_spec.rb +33 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support/models.rb +11 -0
- data/spec/support/views.rb +27 -0
- metadata +154 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bb83d5d1b1dd47e62ea44595951f957304215bc2
|
4
|
+
data.tar.gz: a7ca90254ffad1b2a5c7d901ffb00bd18a0cce07
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3f705fab0c4141190600d8c7179cb0f5ef9db0fd408fa978377ec0fb8c8e01bcb6d9b266049ba7c86bc30753eb6d4afa4586fa099396792609375122be967e4b
|
7
|
+
data.tar.gz: df014c860e15f578d98c9cdb5f6a5ab264da0451923b3647f17eca26d6ebe440f7d88f1b51c8ca61fb4a32936fbd7a2b55821f176d4d583549f87f322b8277a1
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'bench/**/*'
|
4
|
+
- 'bin/*'
|
5
|
+
- 'tmp/**/*'
|
6
|
+
- 'vendor/**/*'
|
7
|
+
|
8
|
+
Style/IfUnlessModifier:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
# Documentation is coming
|
12
|
+
Style/Documentation:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
# Extend self preserves private methods
|
16
|
+
Style/ModuleFunction:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
Style/PredicateName:
|
20
|
+
NamePrefix:
|
21
|
+
- is_
|
22
|
+
NamePrefixBlacklist:
|
23
|
+
- is_
|
24
|
+
|
25
|
+
Style/StringLiterals:
|
26
|
+
EnforcedStyle: double_quotes
|
27
|
+
|
28
|
+
Style/SpaceInsideHashLiteralBraces:
|
29
|
+
EnforcedStyle: no_space
|
30
|
+
EnforcedStyleForEmptyBraces: no_space
|
31
|
+
|
32
|
+
Style/IndentArray:
|
33
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Parker Selbert
|
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,77 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/sorentwo/knuckles.svg?branch=master)](https://travis-ci.org/sorentwo/knuckles)
|
2
|
+
[![Coverage Status](https://coveralls.io/repos/github/sorentwo/knuckles/badge.svg?branch=master)](https://coveralls.io/github/sorentwo/knuckles?branch=master)
|
3
|
+
[![Code Climate](https://codeclimate.com/github/sorentwo/knuckles/badges/gpa.svg)](https://codeclimate.com/github/sorentwo/knuckles)
|
4
|
+
|
5
|
+
# Knuckles (Because Sonic was Taken)
|
6
|
+
|
7
|
+
What's it all about?
|
8
|
+
|
9
|
+
* Emphasis on caching as a composable operation
|
10
|
+
* Reduced object instantiation
|
11
|
+
* Complete instrumentation of every discrete operation
|
12
|
+
* Entirely agnostic, can be dropped into any project and integrated over time
|
13
|
+
* Minimal runtime dependencies
|
14
|
+
* Explicit serializer view API with as little overhead and no DSL
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem "knuckles"
|
22
|
+
```
|
23
|
+
|
24
|
+
## Configuration
|
25
|
+
|
26
|
+
There isn't a hard dependency on `Oj` or `Readthis`, but you'll find they are
|
27
|
+
drastically more performant.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require "activesupport"
|
31
|
+
require "oj"
|
32
|
+
require "readthis"
|
33
|
+
|
34
|
+
Knuckles.configure do |config|
|
35
|
+
config.cache = Readthis::Cache.new(
|
36
|
+
marshal: Oj,
|
37
|
+
compress: true,
|
38
|
+
driver: :hiredis
|
39
|
+
)
|
40
|
+
|
41
|
+
config.keygen = Readthis::Expanders
|
42
|
+
config.serializer = Oj
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
With the top level module configured it is simple to jump right into rendering,
|
47
|
+
but we'll look at configuring the pipeline first.
|
48
|
+
|
49
|
+
## Defining Views
|
50
|
+
|
51
|
+
The interface for defining serializers is largely based on Active Model
|
52
|
+
Serializers, but with a few key differences.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
class ScoutSerializer
|
56
|
+
include Knuckles::Serializer
|
57
|
+
|
58
|
+
root 'scout'
|
59
|
+
|
60
|
+
attributes :id, :email, :display_name
|
61
|
+
|
62
|
+
has_one :thing, serializer: ThingSerializer
|
63
|
+
has_many :other, serializer: OtherThingSerializer
|
64
|
+
|
65
|
+
def display_name(object, options)
|
66
|
+
"#{object.first_name} #{object.last_name}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
## Contributing
|
72
|
+
|
73
|
+
1. Fork it ( https://github.com/sorentwo/knuckles/fork )
|
74
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
75
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
76
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
77
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require "bundler"
|
2
|
+
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
require "active_support/cache"
|
6
|
+
require "benchmark/ips"
|
7
|
+
require "json"
|
8
|
+
require "knuckles"
|
9
|
+
require_relative "fixtures/serializers"
|
10
|
+
|
11
|
+
class BenchModel
|
12
|
+
attr_reader :key
|
13
|
+
|
14
|
+
def initialize(key, attributes)
|
15
|
+
attributes.each do |key, value|
|
16
|
+
self.class.send(:define_method, key) { value }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def cache_key
|
21
|
+
"#{key}/#{id}/#{updated_at}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module BenchHelper
|
26
|
+
extend self
|
27
|
+
|
28
|
+
def submissions
|
29
|
+
mapping = %w[scout responses tags]
|
30
|
+
loaded = JSON.load(IO.read("bench/fixtures/submissions.json"))
|
31
|
+
|
32
|
+
loaded.map do |object|
|
33
|
+
mapping.each do |key|
|
34
|
+
object[key] = structify(key, object[key])
|
35
|
+
end
|
36
|
+
|
37
|
+
structify('submissions', object)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def structify(key, object)
|
42
|
+
if object.is_a?(Array)
|
43
|
+
object.map { |obj| BenchModel.new(key, obj) }
|
44
|
+
else
|
45
|
+
BenchModel.new(key, object)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module ScoutView
|
2
|
+
extend Knuckles::View
|
3
|
+
|
4
|
+
def self.root
|
5
|
+
:scouts
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.data(object, _)
|
9
|
+
{ id: object.id,
|
10
|
+
first_name: object.first_name,
|
11
|
+
gender: object.gender,
|
12
|
+
city: object.city,
|
13
|
+
state: object.state,
|
14
|
+
country: object.country,
|
15
|
+
education: object.education,
|
16
|
+
employment_status: object.employment_status,
|
17
|
+
ethnicity: object.ethnicity,
|
18
|
+
household_composition: object.household_composition,
|
19
|
+
household_income: object.household_income,
|
20
|
+
industry: object.industry,
|
21
|
+
created_at: object.created_at,
|
22
|
+
updated_at: object.updated_at }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module ResponseView
|
27
|
+
extend Knuckles::View
|
28
|
+
|
29
|
+
def self.root
|
30
|
+
:responses
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.data(object, _)
|
34
|
+
{ id: object.id,
|
35
|
+
answers: object.answers,
|
36
|
+
question_id: object.question_id,
|
37
|
+
respondable_id: object.respondable_id,
|
38
|
+
longitude: object.longitude,
|
39
|
+
latitude: object.latitude,
|
40
|
+
time_zone: object.time_zone,
|
41
|
+
answered_at: object.answered_at,
|
42
|
+
created_at: object.created_at,
|
43
|
+
updated_at: object.updated_at }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module TagView
|
48
|
+
extend Knuckles::View
|
49
|
+
|
50
|
+
def self.root
|
51
|
+
:tags
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.data(object, _)
|
55
|
+
{ id: object.id,
|
56
|
+
parent_id: object.parent_id,
|
57
|
+
name: object.name,
|
58
|
+
group: object.group,
|
59
|
+
auto_tag: object.auto_tag,
|
60
|
+
keywords: object.keywords,
|
61
|
+
created_at: object.created_at,
|
62
|
+
updated_at: object.updated_at }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module SubmissionView
|
67
|
+
extend Knuckles::View
|
68
|
+
|
69
|
+
def self.root
|
70
|
+
:submissions
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.data(object, _)
|
74
|
+
{ id: object.id,
|
75
|
+
screener_id: object.screener_id,
|
76
|
+
rating: object.rating,
|
77
|
+
latitude: object.latitude,
|
78
|
+
longitude: object.longitude,
|
79
|
+
source: object.source,
|
80
|
+
time_zone: object.time_zone,
|
81
|
+
bookmarks_count: object.bookmarks_count,
|
82
|
+
notes_count: object.notes_count,
|
83
|
+
finished_at: object.finished_at,
|
84
|
+
created_at: object.created_at,
|
85
|
+
updated_at: object.updated_at }
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.relations(object, _)
|
89
|
+
{ scouts: has_one(object.scout, ScoutView),
|
90
|
+
responses: has_many(object.responses, ResponseView),
|
91
|
+
tags: has_many(object.tags, TagView) }
|
92
|
+
end
|
93
|
+
end
|