serialbox 1.0.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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +41 -0
- data/LICENSE.txt +20 -0
- data/README.md +100 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/serialbox.rb +191 -0
- data/lib/serializers/json.rb +65 -0
- data/serialbox.gemspec +70 -0
- data/spec/json_spec.rb +73 -0
- data/spec/spec_helper.rb +67 -0
- metadata +176 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm 1.8.7@serialbox --create
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
activesupport (3.2.10)
|
5
|
+
i18n (~> 0.6)
|
6
|
+
multi_json (~> 1.0)
|
7
|
+
diff-lcs (1.1.3)
|
8
|
+
git (1.2.5)
|
9
|
+
i18n (0.6.1)
|
10
|
+
jeweler (1.8.4)
|
11
|
+
bundler (~> 1.0)
|
12
|
+
git (>= 1.2.5)
|
13
|
+
rake
|
14
|
+
rdoc
|
15
|
+
json (1.7.6)
|
16
|
+
multi_json (1.5.0)
|
17
|
+
rake (10.0.3)
|
18
|
+
rdoc (3.12)
|
19
|
+
json (~> 1.4)
|
20
|
+
redcarpet (2.2.2)
|
21
|
+
rspec (2.12.0)
|
22
|
+
rspec-core (~> 2.12.0)
|
23
|
+
rspec-expectations (~> 2.12.0)
|
24
|
+
rspec-mocks (~> 2.12.0)
|
25
|
+
rspec-core (2.12.2)
|
26
|
+
rspec-expectations (2.12.1)
|
27
|
+
diff-lcs (~> 1.1.3)
|
28
|
+
rspec-mocks (2.12.1)
|
29
|
+
yard (0.8.3)
|
30
|
+
|
31
|
+
PLATFORMS
|
32
|
+
ruby
|
33
|
+
|
34
|
+
DEPENDENCIES
|
35
|
+
activesupport
|
36
|
+
bundler
|
37
|
+
jeweler
|
38
|
+
json
|
39
|
+
redcarpet
|
40
|
+
rspec
|
41
|
+
yard
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2013 Tim Morgan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# SerialBox
|
2
|
+
|
3
|
+
Provides a simple, well-defined way to specify how your objects are serialized
|
4
|
+
and deserialized into primitive types (say, for JSON serialization). Here's an
|
5
|
+
example object:
|
6
|
+
|
7
|
+
```` ruby
|
8
|
+
class Car
|
9
|
+
attr_accessor :seats, :color
|
10
|
+
|
11
|
+
include SerialBox
|
12
|
+
serialize_with :JSON
|
13
|
+
serialize_fields do |s|
|
14
|
+
s.serialize :seats
|
15
|
+
s.serialize :color
|
16
|
+
end
|
17
|
+
end
|
18
|
+
````
|
19
|
+
|
20
|
+
By calling `serialize_with :JSON`, your class now gets `#to_json`, `#as_json`,
|
21
|
+
and `.json_create` methods making it work seamlessly with the `json` gem. If you
|
22
|
+
have more complicated data structures or accessors, this gem works with that
|
23
|
+
too:
|
24
|
+
|
25
|
+
```` ruby
|
26
|
+
class Color
|
27
|
+
attr_accessor :r, :g, :b
|
28
|
+
|
29
|
+
include SerialBox
|
30
|
+
serialize_with :JSON
|
31
|
+
serialize_fields do |s|
|
32
|
+
s.serialize :r, :g, :b
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Car
|
37
|
+
attr_accessor :color # string
|
38
|
+
|
39
|
+
include SerialBox
|
40
|
+
serialize_with :JSON
|
41
|
+
serialize_fields do |s|
|
42
|
+
s.serializer 'color', :get_color
|
43
|
+
s.deserializer 'color', :set_color
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_color
|
47
|
+
if color.r == 255 && color.g == 0 && color.b == 0
|
48
|
+
'red'
|
49
|
+
elsif color.r == 0 && color.g == 255 && color.b == 0
|
50
|
+
'green'
|
51
|
+
elsif color.r == 0 && color.g == 0 && color.b == 255
|
52
|
+
'blue'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def set_color(name)
|
57
|
+
case name
|
58
|
+
when 'red' then Color.new(255, 0, 0)
|
59
|
+
when 'green' then Color.new(0, 255, 0)
|
60
|
+
when 'blue' then Color.new(0, 0, 255)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
````
|
65
|
+
|
66
|
+
The `.serialize_fields` method lets you define serializers and deserializers
|
67
|
+
using simple to complex syntax, depending on your needs. Here are the supported
|
68
|
+
syntaxes:
|
69
|
+
|
70
|
+
```` ruby
|
71
|
+
serialize_fields do |s|
|
72
|
+
s.serialize :foo # uses #foo and #foo=, JSON field named "foo"
|
73
|
+
s.serialize :foo, :into => 'bar' # uses #foo and #foo=, JSON field named "bar"
|
74
|
+
s.serialize :@foo # reads and writes directly using @foo
|
75
|
+
|
76
|
+
s.serializer 'foo', :bar # the JSON field "foo" will have the value returned by #bar
|
77
|
+
s.deserializer 'foo', :bar= # the value in JSON field "foo" will be sent to #bar=
|
78
|
+
|
79
|
+
s.serializer('foo') { bar.to_s } # the JSON field "foo" will have the value returned by the block
|
80
|
+
s.deserializer('foo') { |value| self.bar = value.to_sym } # the block will be passed the value stored in JSON field "foo"; you must write it to your object
|
81
|
+
end
|
82
|
+
````
|
83
|
+
|
84
|
+
**Important Note:** Right now the only serializer implemented is `:JSON`. Other
|
85
|
+
serializers should be easy to write by following its example.
|
86
|
+
|
87
|
+
## Installation
|
88
|
+
|
89
|
+
To use, add this gem to your Gemfile:
|
90
|
+
|
91
|
+
```` ruby
|
92
|
+
gem 'serialbox'
|
93
|
+
````
|
94
|
+
|
95
|
+
then include the `SerialBox` module in your class, following one of the examples
|
96
|
+
above.
|
97
|
+
|
98
|
+
## Documentation
|
99
|
+
|
100
|
+
Comprehensive documentation is available by running `rake doc`.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "serialbox"
|
18
|
+
gem.homepage = "http://github.com/riscfuture/serialbox"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Define how your object is serialized and deserialized, and this gem handles the rest.}
|
21
|
+
gem.description = %Q{This gem allows you to define how your object is serialized and deserialized. Then it's a simple matter of telling it which formats you want to support, and the serialization methods are automatically created for you.}
|
22
|
+
gem.email = "rubygems@timothymorgan.info"
|
23
|
+
gem.authors = ["Tim Morgan"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
task :default => :spec
|
35
|
+
|
36
|
+
require 'yard'
|
37
|
+
|
38
|
+
# bring sexy back (sexy == tables)
|
39
|
+
module YARD::Templates::Helpers::HtmlHelper
|
40
|
+
def html_markup_markdown(text)
|
41
|
+
markup_class(:markdown).new(text, :gh_blockcode, :fenced_code, :autolink, :tables).to_html
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
YARD::Rake::YardocTask.new('doc') do |doc|
|
46
|
+
doc.options << '-m' << 'markdown' << '-M' << 'redcarpet'
|
47
|
+
doc.options << '--protected' << '--no-private'
|
48
|
+
doc.options << '-r' << 'README.md'
|
49
|
+
doc.options << '-o' << 'doc'
|
50
|
+
doc.options << '--title' << "SerialBox Documentation"
|
51
|
+
|
52
|
+
doc.files = %w( lib/**/*.rb README.md )
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/lib/serialbox.rb
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require 'active_support/core_ext/array/extract_options'
|
3
|
+
Dir.glob(File.dirname(__FILE__) + '/serializers/*').each { |f| require f }
|
4
|
+
|
5
|
+
# Mixin that adds the ability for you to define a serializable representation of
|
6
|
+
# your object. `include` this module into your class and call
|
7
|
+
# {ClassMethods#serialize_fields} and {ClassMethods#serialize_with} to
|
8
|
+
# configure.
|
9
|
+
|
10
|
+
module SerialBox
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
# Methods added to the class that this module is mixed into.
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
|
17
|
+
# Call this method to define how your object is serialized. This method
|
18
|
+
# yields an object on which you call methods to define your serialization.
|
19
|
+
#
|
20
|
+
# @yield [serializer] A block where you can define how your object is
|
21
|
+
# serialized.
|
22
|
+
# @yieldparam [SerialBox::Serializer] serializer An object you can use to
|
23
|
+
# define your serialization strategy.
|
24
|
+
|
25
|
+
def serialize_fields
|
26
|
+
@_serialbox_serializer = Serializer.new(self)
|
27
|
+
yield @_serialbox_serializer
|
28
|
+
end
|
29
|
+
|
30
|
+
# @overload serialize_with(serializer, ...)
|
31
|
+
# Call this method to specify which serialization formats to use.
|
32
|
+
#
|
33
|
+
# @param [Symbol, Class] serializer A serialization format adapter or the
|
34
|
+
# name of such adapter under the `SerialBox::Serializers` namespace. See
|
35
|
+
# the classes under {SerialBox::Serializers} for a list of possible
|
36
|
+
# values.
|
37
|
+
|
38
|
+
def serialize_with(*serializers)
|
39
|
+
serializers.map! do |s|
|
40
|
+
case s
|
41
|
+
when Class
|
42
|
+
s
|
43
|
+
when Symbol, String
|
44
|
+
SerialBox::Serializers.const_get(s.to_sym)
|
45
|
+
else
|
46
|
+
raise ArgumentError, "Unknown serializer #{s.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
serializers.each { |serializer| include serializer }
|
51
|
+
end
|
52
|
+
|
53
|
+
# @private
|
54
|
+
def _serialbox_serializer() @_serialbox_serializer end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# An object that is used to define how a class is serialized. The methods of
|
59
|
+
# this object can be called within a block given to
|
60
|
+
# {SerialBox::ClassMethods#serialize_fields}.
|
61
|
+
|
62
|
+
class Serializer
|
63
|
+
# @private
|
64
|
+
attr_reader :serialization_operations, :deserialization_operations, :object
|
65
|
+
|
66
|
+
# @private
|
67
|
+
def initialize(object)
|
68
|
+
@serialization_operations = Array.new
|
69
|
+
@deserialization_operations = Array.new
|
70
|
+
@object = object
|
71
|
+
end
|
72
|
+
|
73
|
+
# @overload serialize(field, ..., options={})
|
74
|
+
#
|
75
|
+
# Specifies that one or more fields should be serialized in the most
|
76
|
+
# obvious manner. This is suitable when serializing a simple getter/setter
|
77
|
+
# pair or an instance variable.
|
78
|
+
#
|
79
|
+
# @param [Symbol] field The name of a method (or instance variable with
|
80
|
+
# "@" sigil) that will be serialized.
|
81
|
+
# @param [Hash] options Additional options controlling how the field is
|
82
|
+
# serialized.
|
83
|
+
# @option options [String] :into If given, specifies that the field should
|
84
|
+
# be serialized into a key with a different name. Can only be provided
|
85
|
+
# if a single field is given.
|
86
|
+
|
87
|
+
def serialize(*fields)
|
88
|
+
options = fields.extract_options!
|
89
|
+
if options[:into] && fields.size > 1
|
90
|
+
raise ArgumentError, "Can't specify :into option with multiple fields"
|
91
|
+
end
|
92
|
+
|
93
|
+
fields.each do |field|
|
94
|
+
if field.to_s[0, 1] == '@'
|
95
|
+
field = field.to_s[1..-1]
|
96
|
+
json_field = options[:into] || field
|
97
|
+
serializer(json_field) { instance_variable_get :"@#{field}" }
|
98
|
+
deserializer(json_field) { |value| instance_variable_set :"@#{field}", value }
|
99
|
+
else
|
100
|
+
json_field = options[:into] || field
|
101
|
+
serializer json_field, field
|
102
|
+
deserializer json_field, :"#{field}="
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Defines how a field is handled when an object is prepared for
|
108
|
+
# serialization.
|
109
|
+
#
|
110
|
+
# @overload serializer(json_field, object_method)
|
111
|
+
# Specifies that the method `object_method` should be called and its
|
112
|
+
# result should be stored in a field named `json_field` as part of
|
113
|
+
# serialization.
|
114
|
+
# @param [String] json_field The field to store the resulting value in.
|
115
|
+
# @param [Symbol] object_method The method to call to retrieve a value.
|
116
|
+
#
|
117
|
+
# @overload serializer(json_field)
|
118
|
+
# Specifies that a block should be called in the context of the instance
|
119
|
+
# being serialized, and the result should be stored in a field named
|
120
|
+
# `json_field`.
|
121
|
+
# @param [String] json_field The field to store the resulting value in in
|
122
|
+
# the JSON representation.
|
123
|
+
# @yield A block that returns the value to serialize.
|
124
|
+
# @yieldreturn The value to serialize into `json_field`.
|
125
|
+
|
126
|
+
def serializer(json_field, object_method=nil, &block)
|
127
|
+
if block_given?
|
128
|
+
@serialization_operations << BlockSerialization.new(json_field, block)
|
129
|
+
elsif object_method
|
130
|
+
@serialization_operations << BlockSerialization.new(json_field, lambda { send object_method })
|
131
|
+
else
|
132
|
+
raise ArgumentError, "Must provide the name of a method or a block that returns a value to serialize"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Defines how a field is handled when an object is deserialized from its
|
137
|
+
# primitive representation.
|
138
|
+
#
|
139
|
+
# @overload deserializer(json_field, object_method)
|
140
|
+
# Specifies that the value in `json_field` should be passed to
|
141
|
+
# `object_method` during deserialization.
|
142
|
+
# @param [String] json_field The field to retrieve the value from.
|
143
|
+
# @param [Symbol] object_method The method to call to store the value
|
144
|
+
# into the object.
|
145
|
+
#
|
146
|
+
# @overload deserializer(json_field)
|
147
|
+
# Specifies that the value stored in `json_field` should be passed to the
|
148
|
+
# block provided, which will store that value into the object being
|
149
|
+
# deserialized.
|
150
|
+
# @param [String] json_field The field to retrieve the value from in the
|
151
|
+
# JSON representation.
|
152
|
+
# @yield [value] A block that stores the value into the object. This block
|
153
|
+
# is executed in the context of the object.
|
154
|
+
# @yieldparam value The value to store.
|
155
|
+
|
156
|
+
def deserializer(json_field, object_method=nil, &block)
|
157
|
+
if block_given?
|
158
|
+
@deserialization_operations << BlockDeserialization.new(json_field, block, object)
|
159
|
+
elsif object_method
|
160
|
+
@deserialization_operations << BlockDeserialization.new(json_field, lambda { |value| send object_method, value }, object)
|
161
|
+
else
|
162
|
+
raise ArgumentError, "Must provide the name of a method or a block that sets a field from a deserialized value"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# @private
|
167
|
+
class BlockSerialization
|
168
|
+
def initialize(field, block)
|
169
|
+
@field = field
|
170
|
+
@block = block
|
171
|
+
end
|
172
|
+
|
173
|
+
def apply(caller, json)
|
174
|
+
json[@field] = caller.instance_eval(&@block)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# @private
|
179
|
+
class BlockDeserialization
|
180
|
+
def initialize(field, block, klass)
|
181
|
+
@field = field
|
182
|
+
@method_name = "_block_deserialization_#{object_id}"
|
183
|
+
klass.send :define_method, @method_name, &block
|
184
|
+
end
|
185
|
+
|
186
|
+
def apply(caller, json)
|
187
|
+
caller.send @method_name, json[@field.to_s]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module SerialBox
|
4
|
+
|
5
|
+
# Container module for all {SerialBox} serializers.
|
6
|
+
|
7
|
+
module Serializers
|
8
|
+
|
9
|
+
# JSON adapter for {SerialBox}. Defines the following methods when included
|
10
|
+
# in a class:
|
11
|
+
#
|
12
|
+
# * `#as_json`
|
13
|
+
# * `#to_json`
|
14
|
+
# * `.json_create`
|
15
|
+
#
|
16
|
+
# This gives the class total ability to work with `JSON.parse` and
|
17
|
+
# `#to_json`.
|
18
|
+
|
19
|
+
module JSON
|
20
|
+
extend ActiveSupport::Concern
|
21
|
+
|
22
|
+
# @private
|
23
|
+
JSON_CREATE_ID = JSON.respond_to?(:create_id) ? JSON.create_id : 'json_class'
|
24
|
+
|
25
|
+
# Converts this object into primitives suitable for JSON serialization.
|
26
|
+
#
|
27
|
+
# @return [Hash, Array] A JSON-serializable object.
|
28
|
+
|
29
|
+
def as_json(*)
|
30
|
+
hsh = {SerialBox::Serializers::JSON::JSON_CREATE_ID => self.class.name}
|
31
|
+
self.class._serialbox_serializer.serialization_operations.each do |operation|
|
32
|
+
operation.apply self, hsh
|
33
|
+
end
|
34
|
+
return hsh
|
35
|
+
end
|
36
|
+
|
37
|
+
# Serializes this object as JSON.
|
38
|
+
#
|
39
|
+
# @return [String] The JSON representation of this object.
|
40
|
+
|
41
|
+
def to_json(*args) as_json.to_json(*args) end
|
42
|
+
|
43
|
+
module ClassMethods
|
44
|
+
|
45
|
+
# Converts a primitive object (deserialized from JSON) into an instance
|
46
|
+
# of this class.
|
47
|
+
#
|
48
|
+
# **Note:** You should not call this method directly. You should use
|
49
|
+
# `JSON.parse` to ensure recursive deserialization works properly.
|
50
|
+
#
|
51
|
+
# @param [Array, Hash] object The JSON-ready primitive represnetation of
|
52
|
+
# an instance of this class.
|
53
|
+
# @return An instance of this class derived from the JSON.
|
54
|
+
|
55
|
+
def json_create(object)
|
56
|
+
instance = allocate
|
57
|
+
_serialbox_serializer.deserialization_operations.each do |operation|
|
58
|
+
operation.apply instance, object
|
59
|
+
end
|
60
|
+
return instance
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/serialbox.gemspec
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "serialbox"
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Tim Morgan"]
|
12
|
+
s.date = "2013-01-08"
|
13
|
+
s.description = "This gem allows you to define how your object is serialized and deserialized. Then it's a simple matter of telling it which formats you want to support, and the serialization methods are automatically created for you."
|
14
|
+
s.email = "rubygems@timothymorgan.info"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
".rvmrc",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"lib/serialbox.rb",
|
30
|
+
"lib/serializers/json.rb",
|
31
|
+
"spec/json_spec.rb",
|
32
|
+
"spec/spec_helper.rb"
|
33
|
+
]
|
34
|
+
s.homepage = "http://github.com/riscfuture/serialbox"
|
35
|
+
s.licenses = ["MIT"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = "1.8.24"
|
38
|
+
s.summary = "Define how your object is serialized and deserialized, and this gem handles the rest."
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
s.specification_version = 3
|
42
|
+
|
43
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
44
|
+
s.add_runtime_dependency(%q<json>, [">= 0"])
|
45
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
46
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
47
|
+
s.add_development_dependency(%q<yard>, [">= 0"])
|
48
|
+
s.add_development_dependency(%q<redcarpet>, [">= 0"])
|
49
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
50
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
51
|
+
else
|
52
|
+
s.add_dependency(%q<json>, [">= 0"])
|
53
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
54
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
55
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
56
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
57
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
58
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<json>, [">= 0"])
|
62
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
63
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
64
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
65
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
66
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
67
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
data/spec/json_spec.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
generate_tester_classes 'JSON', :JSON
|
4
|
+
|
5
|
+
describe SerialBox::Serializers::JSON do
|
6
|
+
context "[basic schema]" do
|
7
|
+
it "should serialize using #serialize with a method" do
|
8
|
+
obj = JSONSerializeMethodTester.new('value')
|
9
|
+
JSON.parse(obj.to_json, :create_additions => false).should eql({'json_class' => 'JSONSerializeMethodTester', 'var' => 'value'})
|
10
|
+
|
11
|
+
obj = JSON.parse('{"json_class":"JSONSerializeMethodTester","var":"value"}')
|
12
|
+
obj.var.should eql('value')
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should serialize using #serialize with an instance variable" do
|
16
|
+
obj = JSONSerializeIvarTester.new('value')
|
17
|
+
JSON.parse(obj.to_json, :create_additions => false).should eql({'json_class' => 'JSONSerializeIvarTester', 'var' => 'value'})
|
18
|
+
|
19
|
+
obj = JSON.parse('{"json_class":"JSONSerializeIvarTester","var":"value"}')
|
20
|
+
obj.instance_variable_get(:@var).should eql('value')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should serialize into a custom JSON key" do
|
24
|
+
obj = JSONSerializeIntoTester.new('value')
|
25
|
+
JSON.parse(obj.to_json, :create_additions => false).should eql({'json_class' => 'JSONSerializeIntoTester', 'custom' => 'value'})
|
26
|
+
|
27
|
+
obj = JSON.parse('{"json_class":"JSONSerializeIntoTester","custom":"value"}')
|
28
|
+
obj.var.should eql('value')
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should serialize using #serializer and #deserializer with object methods" do
|
32
|
+
obj = JSONSerializerMethodTester.new('value')
|
33
|
+
JSON.parse(obj.to_json, :create_additions => false).should eql({'json_class' => 'JSONSerializerMethodTester', 'var_json' => 'value'})
|
34
|
+
|
35
|
+
obj = JSON.parse('{"json_class":"JSONSerializerMethodTester","var_json":"value"}')
|
36
|
+
obj.var_getter.should eql('value')
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should serialize using #serializer and #deserializer with blocks" do
|
40
|
+
obj = JSONSerializerBlockTester.new('value')
|
41
|
+
JSON.parse(obj.to_json, :create_additions => false).should eql({'json_class' => 'JSONSerializerBlockTester', 'var_json' => 'value'})
|
42
|
+
|
43
|
+
obj = JSON.parse('{"json_class":"JSONSerializerBlockTester","var_json":"value"}')
|
44
|
+
obj.instance_variable_get(:@var).should eql('value')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "[sub-objects]" do
|
49
|
+
it "should correctly serialize and deserialize sub-objects" do
|
50
|
+
subobj = JSONSerializeMethodTester.new('value')
|
51
|
+
obj = JSONSerializeMethodTester.new(subobj)
|
52
|
+
JSON.parse(obj.to_json, :create_additions => false).should eql({
|
53
|
+
'json_class' => 'JSONSerializeMethodTester',
|
54
|
+
'var' => {'json_class' => 'JSONSerializeMethodTester',
|
55
|
+
'var' => 'value'}})
|
56
|
+
|
57
|
+
obj = JSON.parse('{"json_class":"JSONSerializeMethodTester","var":{"json_class":"JSONSerializeMethodTester","var":"value"}}')
|
58
|
+
obj.var.should be_kind_of(JSONSerializeMethodTester)
|
59
|
+
obj.var.var.should eql('value')
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should correctly serialize and deserialize special objects in generic objects" do
|
63
|
+
obj = [JSONSerializeMethodTester.new('value')]
|
64
|
+
JSON.parse(obj.to_json, :create_additions => false).should eql([{'json_class' => 'JSONSerializeMethodTester',
|
65
|
+
'var' => 'value'}])
|
66
|
+
|
67
|
+
obj = JSON.parse('[{"json_class":"JSONSerializeMethodTester","var":"value"}]')
|
68
|
+
obj.should be_kind_of(Array)
|
69
|
+
obj.first.should be_kind_of(JSONSerializeMethodTester)
|
70
|
+
obj.first.var.should eql('value')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'serialbox'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate_tester_classes(prefix, serialize_with)
|
15
|
+
eval <<-RUBY
|
16
|
+
class #{prefix}SerializeMethodTester
|
17
|
+
attr_accessor :var
|
18
|
+
def initialize(var) self.var = var end
|
19
|
+
|
20
|
+
include SerialBox
|
21
|
+
serialize_with #{serialize_with.inspect}
|
22
|
+
serialize_fields { |s| s.serialize :var }
|
23
|
+
end
|
24
|
+
|
25
|
+
class #{prefix}SerializeIvarTester
|
26
|
+
def initialize(var) @var = var end
|
27
|
+
|
28
|
+
include SerialBox
|
29
|
+
serialize_with #{serialize_with.inspect}
|
30
|
+
serialize_fields { |s| s.serialize :@var }
|
31
|
+
end
|
32
|
+
|
33
|
+
class #{prefix}SerializeIntoTester
|
34
|
+
attr_accessor :var
|
35
|
+
def initialize(var) self.var = var end
|
36
|
+
|
37
|
+
include SerialBox
|
38
|
+
serialize_with #{serialize_with.inspect}
|
39
|
+
serialize_fields { |s| s.serialize :var, :into => :custom }
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
class #{prefix}SerializerMethodTester
|
44
|
+
def initialize(var) @var = var end
|
45
|
+
def var_setter(val) @var = val end
|
46
|
+
def var_getter() @var end
|
47
|
+
|
48
|
+
include SerialBox
|
49
|
+
serialize_with #{serialize_with.inspect}
|
50
|
+
serialize_fields do |s|
|
51
|
+
s.serializer 'var_json', :var_getter
|
52
|
+
s.deserializer 'var_json', :var_setter
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class #{prefix}SerializerBlockTester
|
57
|
+
def initialize(var) @var = var end
|
58
|
+
|
59
|
+
include SerialBox
|
60
|
+
serialize_with #{serialize_with.inspect}
|
61
|
+
serialize_fields do |s|
|
62
|
+
s.serializer('var_json') { @var }
|
63
|
+
s.deserializer('var_json') { |val| @var = val }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
RUBY
|
67
|
+
end
|
metadata
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: serialbox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Tim Morgan
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2013-01-08 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
22
|
+
none: false
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
hash: 3
|
27
|
+
segments:
|
28
|
+
- 0
|
29
|
+
version: "0"
|
30
|
+
version_requirements: *id001
|
31
|
+
name: json
|
32
|
+
prerelease: false
|
33
|
+
type: :runtime
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
hash: 3
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
version_requirements: *id002
|
45
|
+
name: activesupport
|
46
|
+
prerelease: false
|
47
|
+
type: :runtime
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
hash: 3
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
version_requirements: *id003
|
59
|
+
name: rspec
|
60
|
+
prerelease: false
|
61
|
+
type: :development
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
hash: 3
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
version: "0"
|
72
|
+
version_requirements: *id004
|
73
|
+
name: yard
|
74
|
+
prerelease: false
|
75
|
+
type: :development
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
version_requirements: *id005
|
87
|
+
name: redcarpet
|
88
|
+
prerelease: false
|
89
|
+
type: :development
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
hash: 3
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
version: "0"
|
100
|
+
version_requirements: *id006
|
101
|
+
name: bundler
|
102
|
+
prerelease: false
|
103
|
+
type: :development
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: 3
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
version: "0"
|
114
|
+
version_requirements: *id007
|
115
|
+
name: jeweler
|
116
|
+
prerelease: false
|
117
|
+
type: :development
|
118
|
+
description: This gem allows you to define how your object is serialized and deserialized. Then it's a simple matter of telling it which formats you want to support, and the serialization methods are automatically created for you.
|
119
|
+
email: rubygems@timothymorgan.info
|
120
|
+
executables: []
|
121
|
+
|
122
|
+
extensions: []
|
123
|
+
|
124
|
+
extra_rdoc_files:
|
125
|
+
- LICENSE.txt
|
126
|
+
- README.md
|
127
|
+
files:
|
128
|
+
- .document
|
129
|
+
- .rspec
|
130
|
+
- .rvmrc
|
131
|
+
- Gemfile
|
132
|
+
- Gemfile.lock
|
133
|
+
- LICENSE.txt
|
134
|
+
- README.md
|
135
|
+
- Rakefile
|
136
|
+
- VERSION
|
137
|
+
- lib/serialbox.rb
|
138
|
+
- lib/serializers/json.rb
|
139
|
+
- serialbox.gemspec
|
140
|
+
- spec/json_spec.rb
|
141
|
+
- spec/spec_helper.rb
|
142
|
+
homepage: http://github.com/riscfuture/serialbox
|
143
|
+
licenses:
|
144
|
+
- MIT
|
145
|
+
post_install_message:
|
146
|
+
rdoc_options: []
|
147
|
+
|
148
|
+
require_paths:
|
149
|
+
- lib
|
150
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
hash: 3
|
156
|
+
segments:
|
157
|
+
- 0
|
158
|
+
version: "0"
|
159
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
|
+
none: false
|
161
|
+
requirements:
|
162
|
+
- - ">="
|
163
|
+
- !ruby/object:Gem::Version
|
164
|
+
hash: 3
|
165
|
+
segments:
|
166
|
+
- 0
|
167
|
+
version: "0"
|
168
|
+
requirements: []
|
169
|
+
|
170
|
+
rubyforge_project:
|
171
|
+
rubygems_version: 1.8.24
|
172
|
+
signing_key:
|
173
|
+
specification_version: 3
|
174
|
+
summary: Define how your object is serialized and deserialized, and this gem handles the rest.
|
175
|
+
test_files: []
|
176
|
+
|