ruby-serial 1.0.0.20130705

Sign up to get free protection for your applications and to get access to all the features.
data/AUTHORS ADDED
@@ -0,0 +1,3 @@
1
+ = Muriel Salvan (muriel@x-aeon.com)
2
+
3
+ * 1.0.0.20130705
@@ -0,0 +1,5 @@
1
+ = Ruby-Serial Release History
2
+
3
+ == 1.0.0.20130705 (Beta)
4
+
5
+ * Initial public release.
data/Credits ADDED
@@ -0,0 +1,11 @@
1
+ = Projects used by RubySerial
2
+
3
+ == MessagePack
4
+ * Furuhashi Sadayuki (http://twitter.com/frsyuki)
5
+ * http://msgpack.org/
6
+ * Ruby binding used to serialize data in a JSON way
7
+
8
+ == Ruby
9
+ * Yukihiro « matz » Matsumoto (http://www.rubyist.net/~matz/)
10
+ * http://www.ruby-lang.org/
11
+ * Thanks a lot Matz for this truly wonderful language !
data/LICENSE ADDED
@@ -0,0 +1,31 @@
1
+
2
+ The license stated herein is a copy of the BSD License (modified on July 1999).
3
+ The AUTHOR mentionned below refers to the list of people involved in the
4
+ creation and modification of any file included in the delivered package.
5
+ This list is found in the file named AUTHORS.
6
+ The AUTHORS and LICENSE files have to be included in any release of software
7
+ embedding source code of this package, or using it as a derivative software.
8
+
9
+ Copyright (c) 2012 - 2013 Muriel Salvan (muriel@x-aeon.com)
10
+
11
+ Redistribution and use in source and binary forms, with or without
12
+ modification, are permitted provided that the following conditions are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright notice,
15
+ this list of conditions and the following disclaimer.
16
+ 2. Redistributions in binary form must reproduce the above copyright notice,
17
+ this list of conditions and the following disclaimer in the documentation
18
+ and/or other materials provided with the distribution.
19
+ 3. The name of the author may not be used to endorse or promote products
20
+ derived from this software without specific prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
25
+ EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31
+ OF SUCH DAMAGE.
data/README ADDED
@@ -0,0 +1,15 @@
1
+ = Ruby Serial
2
+
3
+ Optimized serialization library for Ruby objects.
4
+
5
+ == Where is the documentation ?
6
+
7
+ Check the website at http://ruby-serial.sourceforge.net
8
+
9
+ == Who wrote it ?
10
+
11
+ Check the AUTHORS[link:AUTHORS.html] file.
12
+
13
+ == What is the license ?
14
+
15
+ You can find out in the LICENSE[link:LICENSE.html] file.
@@ -0,0 +1,16 @@
1
+ RubySerial
2
+ =============
3
+
4
+ **Optimized serialization library for Ruby objects.**
5
+
6
+ Library serializing Ruby objects, optimized in many ways:
7
+ * Space efficient: Use MessagePack (binary compact storage) and don't serialize twice the same object
8
+ * Keep shared objects: if an object is shared by others, serialization still keeps the reference and does not duplicate objects in memory
9
+ * Gives the ability to fine tune which attributes of your objects are to be serialized
10
+ * Keeps backward compatibility with previously serialized versions
11
+
12
+ [See documentation here!](http://ruby-serial.sourceforge.net)
13
+
14
+ ## Contact
15
+
16
+ Want to contribute? Have any questions? [Contact Muriel!](mailto:muriel@x-aeon.com)
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+
3
+ task :test do |t|
4
+ load("#{File.dirname(__FILE__)}/test/run.rb")
5
+ end
6
+
7
+ task :default => :test
@@ -0,0 +1,8 @@
1
+
2
+ # This file has been generated by RubyPackager during a delivery.
3
+ # More info about RubyPackager: http://rubypackager.sourceforge.net
4
+ {
5
+ :version => '1.0.0.20130705',
6
+ :tags => [ 'Beta' ],
7
+ :dev_status => 'Beta'
8
+ }
@@ -0,0 +1,32 @@
1
+ require 'msgpack'
2
+ require 'ruby-serial/_class'
3
+ require 'ruby-serial/_object'
4
+ require 'ruby-serial/common'
5
+ require 'ruby-serial/serializer'
6
+ require 'ruby-serial/deserializer'
7
+
8
+ module RubySerial
9
+
10
+ # Serialize an object into a String
11
+ #
12
+ # Parameters::
13
+ # * *obj* (_Object_): Object to serialize
14
+ # * *options* (<em>map<Symbol,Object></em>): Options [default = {}]
15
+ # * *:version* (_String_): The version to be used to encode
16
+ # Result::
17
+ # * _String_: Serialized object
18
+ def self.dump(obj, options = {})
19
+ return Serializer.new(obj, options).dump
20
+ end
21
+
22
+ # Deserialize an object from a String
23
+ #
24
+ # Parameters::
25
+ # * *data* (_String_): Data to deserialize
26
+ # Result::
27
+ # * _Object_: Corresponding Ruby object
28
+ def self.load(data)
29
+ return Deserializer.new(data).load
30
+ end
31
+
32
+ end
@@ -0,0 +1,28 @@
1
+ class Class
2
+
3
+ attr_reader :dont_rubyserial_lst
4
+ attr_reader :rubyserial_only_lst
5
+
6
+ # Mark some attributes to not be serialized
7
+ #
8
+ # Parameters::
9
+ # * *lst* (<em>list<Symbol></em>): List of attributes symbols
10
+ def dont_rubyserial(*lst)
11
+ lst = [lst] if (!lst.is_a?(Array))
12
+ @dont_rubyserial_lst = [] if (!defined?(@dont_rubyserial_lst))
13
+ @dont_rubyserial_lst.concat(lst.map { |var_name| "@#{var_name.to_s}".to_sym })
14
+ @dont_rubyserial_lst.uniq!
15
+ end
16
+
17
+ # Mark some attributes to be serialized
18
+ #
19
+ # Parameters::
20
+ # * *lst* (<em>list<Symbol></em>): List of attributes symbols
21
+ def rubyserial_only(*lst)
22
+ lst = [lst] if (!lst.is_a?(Array))
23
+ @rubyserial_only_lst = [] if (!defined?(@rubyserial_only_lst))
24
+ @rubyserial_only_lst.concat(lst.map { |var_name| "@#{var_name.to_s}".to_sym })
25
+ @rubyserial_only_lst.uniq!
26
+ end
27
+
28
+ end
@@ -0,0 +1,40 @@
1
+ class Object
2
+
3
+ # Get the list of instance variables that are meant to be serialized
4
+ #
5
+ # Result::
6
+ # * <em>map<String,Object></em>: Set of instance variables, per name
7
+ def get_instance_vars_to_rubyserial
8
+ # Compute the list of attributes to serialize
9
+ instance_var_names = []
10
+ klass = self.class
11
+ if (klass.rubyserial_only_lst != nil)
12
+ if (klass.dont_rubyserial_lst != nil)
13
+ instance_var_names = klass.rubyserial_only_lst - klass.dont_rubyserial_lst
14
+ else
15
+ instance_var_names = klass.rubyserial_only_lst
16
+ end
17
+ elsif (klass.dont_rubyserial_lst != nil)
18
+ instance_var_names = self.instance_variables - klass.dont_rubyserial_lst
19
+ else
20
+ instance_var_names = self.instance_variables
21
+ end
22
+ # Compute the resulting map
23
+ instance_vars = {}
24
+ instance_var_names.each do |sym_var|
25
+ instance_vars[sym_var.to_s] = self.instance_variable_get(sym_var)
26
+ end
27
+ return instance_vars
28
+ end
29
+
30
+ # Set the list of instance variables that were serialized
31
+ #
32
+ # Parameters::
33
+ # * *instance_vars* (<em>map<String,Object></em>): Set of instance variables, per name
34
+ def set_instance_vars_from_rubyserial(instance_vars)
35
+ instance_vars.each do |var_name, value|
36
+ self.instance_variable_set(var_name.to_sym, value)
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,10 @@
1
+ module RubySerial
2
+
3
+ # Find shortest strings that are unlikely to get in functional Hashes' keys
4
+ # !!! Use UTF-8 encoding as otherwise MessagePack won't be able to read data correctly
5
+ OBJECT_ID_REFERENCE = "\x00\xA0".force_encoding(Encoding::UTF_8)
6
+ OBJECT_CONTENT_REFERENCE = "\x00\xF1".force_encoding(Encoding::UTF_8)
7
+ OBJECT_CLASSNAME_REFERENCE = "\x00\xBB".force_encoding(Encoding::UTF_8)
8
+ SYMBOL_ID = "\x00\xEE".force_encoding(Encoding::UTF_8)
9
+
10
+ end
@@ -0,0 +1,38 @@
1
+ module RubySerial
2
+
3
+ # Deserialize data previously serialized using Serializer
4
+ class Deserializer
5
+
6
+ # Constructor
7
+ #
8
+ # Parameters::
9
+ # * *data* (_String_): Serialized data (should be BINARY encoding only)
10
+ def initialize(data)
11
+ @data = data
12
+ end
13
+
14
+ # Load the serialized object
15
+ #
16
+ # Result::
17
+ # * _Object_: The deserialized object
18
+ def load
19
+ # Find the version
20
+ idx_data_separator = @data.index("\x00")
21
+ raise 'Unknown format of data. It appears this data has not been serialized using RubySerial.' if (idx_data_separator == nil)
22
+ version = @data[0..idx_data_separator-1]
23
+ data = @data[idx_data_separator+1..-1]
24
+
25
+ deserializer = nil
26
+ begin
27
+ require "ruby-serial/versions/#{version}/deserializer"
28
+ deserializer = eval("RubySerial::Deserializer::Versions::Version_#{version}")::Deserializer.new
29
+ rescue
30
+ raise "Unknown deserializer version #{version}. Please use a most recent version of RubySerial to decode your data. #{$!}"
31
+ end
32
+
33
+ return deserializer.unpack_data(data)
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,42 @@
1
+ module RubySerial
2
+
3
+ class Serializer
4
+
5
+ # Default encoding version (should be the last one)
6
+ DEFAULT_VERSION = '1'
7
+
8
+ # Constructor
9
+ #
10
+ # Parameters::
11
+ # * *obj* (_Object_): Ruby object to serialize
12
+ # * *options* (<em>map<Symbol,Object></em>): Options [default = {}]
13
+ # * *:version* (_String_): The version to be used to encode
14
+ def initialize(obj, options = {})
15
+ @version = (options[:version] || DEFAULT_VERSION)
16
+ @obj = obj
17
+ # Map of objects ID, with their corresponding number of shared objects among their descendants (those having 0 share nothing)
18
+ # map< ObjectID, NbrSharedObjects >
19
+ @objs = {}
20
+ # Map of shared objects' associated to a boolean indicating whether they have already been serialized or not
21
+ @shared_objs = {}
22
+ end
23
+
24
+ # Serialize the object
25
+ #
26
+ # Result::
27
+ # * _String_: The object serialized
28
+ def dump
29
+ serializer = nil
30
+ begin
31
+ require "ruby-serial/versions/#{@version}/serializer"
32
+ serializer = eval("RubySerial::Serializer::Versions::Version_#{@version}")::Serializer.new
33
+ rescue
34
+ raise "Unknown serializer version #{@version}: #{$!}"
35
+ end
36
+
37
+ return "#{@version}\x00#{serializer.pack_data(@obj)}".force_encoding(Encoding::BINARY)
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,99 @@
1
+ module RubySerial
2
+
3
+ class Deserializer
4
+
5
+ module Versions
6
+
7
+ module Version_1
8
+
9
+ class Deserializer
10
+
11
+ # Unpack data
12
+ #
13
+ # Parameters::
14
+ # * *data* (_String_): Data to deserialize
15
+ # Result::
16
+ # * _Object_: The unpacked data
17
+ def unpack_data(data)
18
+ decoded_data = MessagePack::unpack(data)
19
+ if (decoded_data['shared_objs'].empty?)
20
+ return get_original_rec(decoded_data['obj'])
21
+ else
22
+ # We need to replace some data before
23
+ @serialized_shared_objs = decoded_data['shared_objs']
24
+ @decoded_shared_objs = {}
25
+ return get_original_rec(decoded_data['obj'])
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ # Convert back a deserialized object using MessagePack to the original object
32
+ #
33
+ # Parameters::
34
+ # * *obj* (_Object_): The decoded object
35
+ # * *container_to_fill* (_Object_): The container to fill with the decoded data. If nil, a new object will be created. [default = nil]
36
+ # Result::
37
+ # * _Object_: The original object
38
+ def get_original_rec(decoded_obj, container_to_fill = nil)
39
+ if (decoded_obj.is_a?(Array))
40
+ if (container_to_fill == nil)
41
+ return decoded_obj.map { |serialized_item| get_original_rec(serialized_item) }
42
+ else
43
+ decoded_obj.each do |item|
44
+ container_to_fill << get_original_rec(item)
45
+ end
46
+ return container_to_fill
47
+ end
48
+ elsif (decoded_obj.is_a?(Hash))
49
+ # Check for special hashes
50
+ if (decoded_obj[OBJECT_ID_REFERENCE] == nil)
51
+ if (decoded_obj[OBJECT_CLASSNAME_REFERENCE] == SYMBOL_ID)
52
+ return decoded_obj[OBJECT_CONTENT_REFERENCE].to_sym
53
+ elsif (decoded_obj[OBJECT_CLASSNAME_REFERENCE] == nil)
54
+ # Normal hash
55
+ hash_obj = ((container_to_fill == nil) ? {} : container_to_fill)
56
+ decoded_obj.each do |serialized_key, serialized_value|
57
+ hash_obj[get_original_rec(serialized_key)] = get_original_rec(serialized_value)
58
+ end
59
+ return hash_obj
60
+ else
61
+ # We deserialize a home-made object
62
+ # Instantiate the needed class
63
+ new_obj = ((container_to_fill == nil) ? eval(decoded_obj[OBJECT_CLASSNAME_REFERENCE]).new : container_to_fill)
64
+ instance_vars = {}
65
+ decoded_obj[OBJECT_CONTENT_REFERENCE].each do |var_name, serialized_value|
66
+ instance_vars[var_name] = get_original_rec(serialized_value)
67
+ end
68
+ new_obj.set_instance_vars_from_rubyserial(instance_vars)
69
+ return new_obj
70
+ end
71
+ else
72
+ # We have a reference to a shared object
73
+ obj_id = decoded_obj[OBJECT_ID_REFERENCE]
74
+ if (@decoded_shared_objs[obj_id] == nil)
75
+ # Instantiate it already for cyclic decoding (avoids infinite loops)
76
+ @decoded_shared_objs[obj_id] = eval(@serialized_shared_objs[obj_id][0]).new
77
+ get_original_rec(@serialized_shared_objs[obj_id][1], @decoded_shared_objs[obj_id])
78
+ end
79
+ return @decoded_shared_objs[obj_id]
80
+ end
81
+ elsif (container_to_fill == nil)
82
+ # Should be only String
83
+ return decoded_obj
84
+ else
85
+ # Should be only String
86
+ container_to_fill.replace(decoded_obj)
87
+ return container_to_fill
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+
99
+ end
@@ -0,0 +1,140 @@
1
+ module RubySerial
2
+
3
+ class Serializer
4
+
5
+ module Versions
6
+
7
+ module Version_1
8
+
9
+ class Serializer
10
+
11
+ # Get data
12
+ #
13
+ # Parameters::
14
+ # * *obj* (_Object_): Object to pack
15
+ # Result::
16
+ # * _String_: The serialized data
17
+ def pack_data(obj)
18
+ # First look for shared objects
19
+ # Set of objects parsed, per object_id
20
+ @objs = {}
21
+ # Set of shared object_id, with a boolean indicating whether they have been serialized already or not
22
+ @shared_objs = {}
23
+ gather_ids_rec(obj)
24
+ @shared_objs_to_store = {}
25
+ @shared_objs.each do |object_id, false_value|
26
+ @shared_objs_to_store[object_id] = [
27
+ @objs[object_id].class.name,
28
+ get_msgpack_compatible_rec(@objs[object_id], false)
29
+ ]
30
+ end
31
+ #puts "Found #{@shared_objs_to_store.size} shared objects to be stored"
32
+ return {
33
+ 'obj' => get_msgpack_compatible_rec(obj),
34
+ 'shared_objs' => @shared_objs_to_store
35
+ }.to_msgpack.force_encoding(Encoding::BINARY)
36
+ end
37
+
38
+ private
39
+
40
+ # Gather all shared objects in @shared_objs, tracking which ones have already been parsed in @objs.
41
+ # Called recursively on all objects contained in obj.
42
+ #
43
+ # Parameters::
44
+ # * *obj* (_Object_): The object to inspect
45
+ def gather_ids_rec(obj)
46
+ if ((!obj.is_a?(Fixnum)) and
47
+ (!obj.is_a?(Bignum)) and
48
+ (!obj.is_a?(Float)) and
49
+ (!obj.is_a?(Symbol)) and
50
+ (obj != nil) and
51
+ (obj != true) and
52
+ (obj != false))
53
+ # Check if obj id is shared
54
+ if (@objs[obj.object_id] == nil)
55
+ # First time we encounter this object
56
+ @objs[obj.object_id] = obj
57
+ # See other references
58
+ if (obj.is_a?(Array))
59
+ obj.each_with_index do |item, idx|
60
+ gather_ids_rec(item)
61
+ end
62
+ elsif (obj.is_a?(Hash))
63
+ obj.each do |key, value|
64
+ gather_ids_rec(value)
65
+ gather_ids_rec(key)
66
+ end
67
+ else
68
+ # Handle other objects
69
+ obj.get_instance_vars_to_rubyserial.each do |var_name, var|
70
+ gather_ids_rec(var)
71
+ end
72
+ end
73
+ else
74
+ # This object is shared.
75
+ @shared_objs[obj.object_id] = false
76
+ end
77
+ end
78
+ end
79
+
80
+ # Convert the object (and all its descendants) to be serializable using to_msgpack without loosing information.
81
+ #
82
+ # Parameters::
83
+ # * *obj* (_Object_): Object to convert
84
+ # * *check_shared* (_Boolean_): Do we check whether this object is shared? [default = true]
85
+ # Result::
86
+ # * _Object_: The object ready to be serialized
87
+ def get_msgpack_compatible_rec(obj, check_shared = true)
88
+ if ((obj.is_a?(Fixnum)) or
89
+ (obj.is_a?(Bignum)) or
90
+ (obj.is_a?(Float)) or
91
+ (obj == nil) or
92
+ (obj == true) or
93
+ (obj == false))
94
+ return obj
95
+ elsif (obj.is_a?(Symbol))
96
+ # TODO (MessagePack): Remove this if MessagePack handles Symbols one day
97
+ return {
98
+ OBJECT_CLASSNAME_REFERENCE => SYMBOL_ID,
99
+ OBJECT_CONTENT_REFERENCE => obj.to_s
100
+ }
101
+ elsif (check_shared and
102
+ (@shared_objs[obj.object_id] != nil))
103
+ # This object is shared: store its object_id only
104
+ return {
105
+ OBJECT_ID_REFERENCE => obj.object_id
106
+ }
107
+ elsif (obj.is_a?(Array))
108
+ # First serialize its items
109
+ return obj.map { |item| get_msgpack_compatible_rec(item) }
110
+ elsif (obj.is_a?(Hash))
111
+ # First serialize its items
112
+ hash_to_store = {}
113
+ obj.each do |key, value|
114
+ hash_to_store[get_msgpack_compatible_rec(key)] = get_msgpack_compatible_rec(value)
115
+ end
116
+ return hash_to_store
117
+ elsif (obj.is_a?(String))
118
+ return obj
119
+ else
120
+ # Handle other objects
121
+ serialized_instance_vars = {}
122
+ obj.get_instance_vars_to_rubyserial.each do |var_name, value|
123
+ serialized_instance_vars[var_name] = get_msgpack_compatible_rec(value)
124
+ end
125
+ return {
126
+ OBJECT_CLASSNAME_REFERENCE => obj.class.name,
127
+ OBJECT_CONTENT_REFERENCE => serialized_instance_vars
128
+ }
129
+ end
130
+ end
131
+
132
+ end
133
+
134
+ end
135
+
136
+ end
137
+
138
+ end
139
+
140
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-serial
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0.20130705
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Muriel Salvan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-07-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: msgpack
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ description: ! 'Library serializing Ruby objects, optimized in many ways:
31
+
32
+ * Space efficient: Use MessagePack (binary compact storage) and don''t serialize
33
+ twice the same object
34
+
35
+ * Keep shared objects: if an object is shared by others, serialization still keeps
36
+ the reference and does not duplicate objects in memory
37
+
38
+ * Gives the ability to fine tune which attributes of your objects are to be serialized
39
+
40
+ * Keeps backward compatibility with previously serialized versionsRuby library giving
41
+ block-buffered and cached read over IO objects with a String-like interface. Ideal
42
+ to parse big files as Strings, limiting memory consumption.'
43
+ email: muriel@x-aeon.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - AUTHORS
49
+ - ChangeLog
50
+ - Credits
51
+ - lib/ruby-serial/common.rb
52
+ - lib/ruby-serial/deserializer.rb
53
+ - lib/ruby-serial/serializer.rb
54
+ - lib/ruby-serial/versions/1/deserializer.rb
55
+ - lib/ruby-serial/versions/1/serializer.rb
56
+ - lib/ruby-serial/_class.rb
57
+ - lib/ruby-serial/_object.rb
58
+ - lib/ruby-serial.rb
59
+ - LICENSE
60
+ - Rakefile
61
+ - README
62
+ - README.md
63
+ - ReleaseInfo
64
+ homepage: http://ruby-serial.sourceforge.net
65
+ licenses: []
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubyforge_project: ruby-serial
84
+ rubygems_version: 1.8.24
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Optimized serialization library for Ruby objects.
88
+ test_files: []