cerealizer 0.0.1
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.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +24 -0
- data/LICENSE.txt +22 -0
- data/README.md +87 -0
- data/Rakefile +1 -0
- data/cerealizer.gemspec +21 -0
- data/lib/cerealizer/version.rb +3 -0
- data/lib/cerealizer.rb +78 -0
- metadata +72 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
cerealizer (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.1.3)
|
10
|
+
rspec (2.12.0)
|
11
|
+
rspec-core (~> 2.12.0)
|
12
|
+
rspec-expectations (~> 2.12.0)
|
13
|
+
rspec-mocks (~> 2.12.0)
|
14
|
+
rspec-core (2.12.2)
|
15
|
+
rspec-expectations (2.12.1)
|
16
|
+
diff-lcs (~> 1.1.3)
|
17
|
+
rspec-mocks (2.12.2)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
cerealizer!
|
24
|
+
rspec (>= 2.9.0)
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Brad Gessler
|
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,87 @@
|
|
1
|
+
# Cerealizer
|
2
|
+
|
3
|
+
Serialize and deserialize data between models and JSON.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'cerealizer'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install cerealizer
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Want to write a HATOAS API without a bunch of stuff between your model and the serializer? Consider the following code:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
class FruitSerializer < Cerealizer::Base
|
25
|
+
key :owner_href
|
26
|
+
hey :href
|
27
|
+
key :color
|
28
|
+
key :private_tasting_note
|
29
|
+
|
30
|
+
def href
|
31
|
+
"/fruits/#{object.id}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def href=(href)
|
35
|
+
_, object.id = href.split('/')
|
36
|
+
end
|
37
|
+
|
38
|
+
def owner_href
|
39
|
+
"/users/#{object.owner_id}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def owner_href=(href)
|
43
|
+
_, object.owner_id = href.split('/')
|
44
|
+
end
|
45
|
+
|
46
|
+
# Only the owner of the Fruit can change the owner key or the admin.
|
47
|
+
def has_writeable_owner_href?
|
48
|
+
object.id == scope.id or scope.is_admin?
|
49
|
+
end
|
50
|
+
|
51
|
+
# Only the owner of the fruit can read the private tasting note.
|
52
|
+
def has_readable_private_tasting_note?
|
53
|
+
object.id == scope.id
|
54
|
+
end
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
Now lets use it in some app code! Lets generate some hashes that our app can convert into JSON:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
user = User.new(:id => 3)
|
62
|
+
owner = User.new(:id => 12)
|
63
|
+
fruit = Fruit.new(:owner_id => 12, id: => 8, color: => 'Orange')
|
64
|
+
|
65
|
+
FruitSerializer.new(fruit, user).to_hash
|
66
|
+
# => { :owner_href => '/users/12', href: => '/fruits/8', color: => 'Orange' }
|
67
|
+
|
68
|
+
FruitSerializer.new(fruit, owner).to_hash
|
69
|
+
# => { :owner_href => '/users/12', href: => '/fruits/8', color: => 'Orange', :private_tasting_note => nil }
|
70
|
+
```
|
71
|
+
|
72
|
+
Meh, its OK. Lots of libraries already do this with minimal hacking. That's not why we wrote this lib; what we need is something that can deal with *writing* attributes back into the model.
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
FruitSerializer.new(fruit, user).write_keys(:owner_href => '/users/9000')
|
76
|
+
# => BOOM! Raise a Key::UnauthorizedWrite exception
|
77
|
+
```
|
78
|
+
|
79
|
+
Now we can implement authorization logic at a key level for our resources. Nifty!
|
80
|
+
|
81
|
+
## Contributing
|
82
|
+
|
83
|
+
1. Fork it
|
84
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
85
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
86
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
87
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/cerealizer.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cerealizer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "cerealizer"
|
8
|
+
gem.version = Cerealizer::VERSION
|
9
|
+
gem.authors = ["Brad Gessler"]
|
10
|
+
gem.email = ["brad@polleverywhere.com"]
|
11
|
+
gem.description = %q{Serialize and deserialize classes and JSON.}
|
12
|
+
gem.summary = %q{Dive into the nitty gritty details of serializing and deserializing between objects and a hash.}
|
13
|
+
gem.homepage = "http://github.com/polleverywhere/cerealizer"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_development_dependency 'rspec', '>= 2.9.0'
|
21
|
+
end
|
data/lib/cerealizer.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require "cerealizer/version"
|
2
|
+
|
3
|
+
module Cerealizer
|
4
|
+
# Encapsulates information about keys.
|
5
|
+
class Key
|
6
|
+
attr_reader :name
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Configure a serialize keys and deal with marshaling to and from JSON.
|
14
|
+
class Base
|
15
|
+
attr_reader :object, :scope
|
16
|
+
|
17
|
+
def initialize(object, scope)
|
18
|
+
@object, @scope = object, scope
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.key(key)
|
23
|
+
keys.push Key.new(key)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.keys
|
27
|
+
@keys ||= []
|
28
|
+
end
|
29
|
+
|
30
|
+
# Call methods on the object that's being presented and create a flat
|
31
|
+
# hash for these mofos.
|
32
|
+
def serializable_hash
|
33
|
+
self.class.keys.inject Hash.new do |hash, key|
|
34
|
+
hash[key.name] = proxy_reader(key.name) if readable?(key.name)
|
35
|
+
hash
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Update the attrs on zie model.
|
40
|
+
def update_attributes(attrs={})
|
41
|
+
attrs.each { |key, value| proxy_writer(key, value) if writeable?(key.name) }
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
# TODO - Should the default be writable?
|
47
|
+
def writeable?(key)
|
48
|
+
meth = "has_writable_#{key}?"
|
49
|
+
self.respond_to?(meth) ? self.send(meth) : true
|
50
|
+
end
|
51
|
+
|
52
|
+
# TODO - Should the default be writable?
|
53
|
+
def readable?(key)
|
54
|
+
meth = "has_readable_#{key}?"
|
55
|
+
self.respond_to?(meth) ? self.send(meth) : true
|
56
|
+
end
|
57
|
+
|
58
|
+
# Look for methods locally that we want to use to proxy data between
|
59
|
+
# the object and its JSON format.
|
60
|
+
def proxy_reader(key)
|
61
|
+
if self.respond_to? key
|
62
|
+
self.send(key)
|
63
|
+
else
|
64
|
+
object.send(key)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Proxy the writer to zie object.
|
69
|
+
def proxy_writer(key, *args)
|
70
|
+
meth = "#{key}="
|
71
|
+
if self.respond_to? meth
|
72
|
+
self.send(meth, *args)
|
73
|
+
else
|
74
|
+
object.send(meth, *args)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cerealizer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Brad Gessler
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.9.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 2.9.0
|
30
|
+
description: Serialize and deserialize classes and JSON.
|
31
|
+
email:
|
32
|
+
- brad@polleverywhere.com
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .gitignore
|
38
|
+
- Gemfile
|
39
|
+
- Gemfile.lock
|
40
|
+
- LICENSE.txt
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- cerealizer.gemspec
|
44
|
+
- lib/cerealizer.rb
|
45
|
+
- lib/cerealizer/version.rb
|
46
|
+
homepage: http://github.com/polleverywhere/cerealizer
|
47
|
+
licenses: []
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirements: []
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.8.23
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Dive into the nitty gritty details of serializing and deserializing between
|
70
|
+
objects and a hash.
|
71
|
+
test_files: []
|
72
|
+
has_rdoc:
|