mccraigmccraig-better_serialization 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [name of plugin creator]
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.
@@ -0,0 +1,102 @@
1
+ === Faster, Smaller, Gzip-able
2
+
3
+ This adds +marshal_serialize+ and +json_serialize+ to ActiveRecord::Base (class methods), which act similar to rails' own +serialize+ except they don't use yaml, which is slooooow and biiiiig (byte-wise). Also supports adding gzip to the serialization process for really large stuff (can save a ton of database memory with minimal added insert time). Note that gzip columns must be of type "binary", "blob", etc (not text).
4
+
5
+ Note that there's a limitation with the plugin: you can't call destructive actions on attributes using better_serialization (ex. << for an array), and update_attribute etc won't work. See TODO for an explanation.
6
+
7
+ === Example
8
+
9
+ see tests, but here's the gist:
10
+
11
+ class OrderLog < ActiveRecord::Base
12
+ marshal_serialize :line_items_cache, :gzip => true
13
+ marshal_serialize :product_cache
14
+ json_serialize :customer_cache
15
+ end
16
+
17
+ order_log = OrderLog.new
18
+ product = Product.new(:name => "Woot")
19
+ order_log.product_cache = product
20
+
21
+ order_log.product_cache # => normal
22
+ order_log[:product_cache] # => raw Marshal.dump of product
23
+
24
+ === Notes for json_serialize
25
+
26
+ JSON serialization is faster and smaller, but needs more configuration. This is because Marshal and the default YAML serialization dump the whole object, instance variables and all. JSON just stores an instances' attribute values. Thus, you need to tell it what class to instantiate, or tell it not to instantiate anything at all for storing a hash or array of data.
27
+
28
+ Also, when serializing ActiveRecord objects, if <code>ActiveRecord::Base.include_root_in_json == true</code> (the new rails defalut), it'll all 'just work'. Otherwise, you will need to use the :class_name option if it's not inferable by the association name, and will probably want modify that class's to_json to include the id.
29
+
30
+ === The Problem With YAML Serialization: speed and size
31
+
32
+ [NOTE: this code does not represent the BetterSerialization api, but rather the underlying ideas]
33
+
34
+ The following examples came from the real-world objects that inspired the plugin.
35
+
36
+ +lis+ is an 18-member array of line items that have many associations loaded into memory,
37
+ the point being that they're relatively big objects.
38
+
39
+ marshal_data, yaml_data, json_data = nil
40
+
41
+ Benchmark.bm(7) do |x|
42
+ x.report("Marshal") { marshal_data = Marshal.dump(lis) }
43
+ x.report("to_yaml") { yaml_data = lis.to_yaml }
44
+ x.report('to_json') { json_data = lis.to_json }
45
+ end
46
+
47
+ user system total real
48
+ Marshal 0.590000 0.000000 0.590000 ( 0.605567)
49
+ to_yaml 11.730000 0.010000 11.740000 ( 12.179310)
50
+ to_json 0.010000 0.000000 0.010000 ( 0.006129)
51
+
52
+ The reason JSON is so fast is that rails' ActiveRecord::Base#to_json only jsonifies the attributes hash, not the actual ruby object. If you want the full object though, Marshal is waaaaay faster than to_yaml, and it *is* representing the full ruby object.
53
+
54
+ Marshal is also a lot smaller than yaml:
55
+
56
+ >> marshal_data.size
57
+ => 1119279
58
+ >> yaml_data.size
59
+ => 1958610
60
+ >> json_data.size
61
+ => 7886
62
+
63
+ Whammy. What about deserialization?
64
+
65
+ Benchmark.bm(7) do |x|
66
+ x.report("Marshal") { Marshal.load(marshal_data) }
67
+ x.report("to_yaml") { YAML::load(yaml_data) }
68
+ x.report('to_json') { ActiveSupport::JSON.decode(json_data).collect {|hash| BuylistLineItem.new(hash)} }
69
+ end
70
+
71
+ user system total real
72
+ Marshal 0.040000 0.000000 0.040000 ( 0.046616)
73
+ to_yaml 0.380000 0.000000 0.380000 ( 0.380686)
74
+ to_json 0.020000 0.000000 0.020000 ( 0.019096)
75
+
76
+ With json you can't just unmarshal it 'cuz it's just representing an attribute array, but even compensating with object creation it's still the fastest.
77
+
78
+ Finally, if you need to save some space, you can use gzip with the serialization:
79
+
80
+ >> Benchmark.measure {gz_marshal_data = Zlib::Deflate.deflate(marshal_data)}
81
+ => #<Benchmark::Tms:0x10a7ee54 @utime=0.0300000000000011, @cstime=0.0, @cutime=0.0, @total=0.0300000000000011, @label="", @stime=0.0, @real=0.0292189121246338>
82
+ >> marshal_data.size - gz_marshal_data.size
83
+ => 1036979
84
+ >> Benchmark.measure {Zlib::Inflate.inflate(marshal_data)}
85
+ => #<Benchmark::Tms:0x10a8db98 @utime=0.0, @cstime=0.0, @cutime=0.0, @total=0.0, @label="", @stime=0.0, @real=0.00509905815124512>
86
+
87
+ So on this machine it would add 30ms on insert and 5ms on load, but save ~1mb of database space. Seems worth it if you're saving this much stuff.
88
+
89
+ [EDIT: Also note that from personal experience, gzipping json will still use 1/10th the overall space with ~.5ms performance hit - WIN]
90
+
91
+ === Summary
92
+
93
+ If you want speed/small data and don't need to flash-freeze the whole object, use json. Otherwise, use Marshal. If you want to use minimal database space, add gzip to those (adds a relatively small performance hit). Use the default yaml if you really, really *need* to save the whole object and also have a more human-readable datastore... eh, actually, don't use yaml.
94
+
95
+ === TODO
96
+
97
+ * deserialization should be cached, and it would be nice if the deserialized value was stored in the attributes hash.
98
+ * Allow destructive actions
99
+ * The problem is that serializing and de-serializing creates new objects, so if you do object.array_attribute << "blah", you will have deserialized a new object, destructively added a value to it, and thrown the new object away. ActiveRecord avoids this issue by calling to_yaml as a catch-all on the result of read_attribute in activerecord/lib/active_record/connection_adapters/abstract/quoting.rb#quote (as of 2.3.4). What we need is something like being able to specify what AR's catch-all case is (although that wouldn't work for some option/value combos, ex. gzip option on a string or date). Gratefully accepting ideas :)
100
+ * Also, just thought of another way. have the raw data be in the raw_#{attribute} column, and object.attribute be a method that loads raw_#{attribute}. That + save hooks = win.
101
+
102
+ Copyright (c) 2009 Woody Peterson, released under the MIT license
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "mccraigmccraig-better_serialization"
8
+ gem.summary = %Q{json and zlib serialization for activerecord attributes}
9
+ gem.description = %Q{serialize and deserialize activerecord attributes using json or zlib}
10
+ gem.email = "mccraigmccraig@googlemail.com"
11
+ gem.homepage = "http://github.com/trampoline/better_serialization"
12
+ gem.authors = ["http://github.com/crystalcommerce", "http://github.com/rhburrows", "http://github.com/mccraigmccraig"]
13
+ gem.add_dependency "activerecord", ">= 2.3.8"
14
+ gem.add_development_dependency "rspec", ">= 1.2.8"
15
+ gem.add_development_dependency "sqlite3-ruby", ">= 1.3.1"
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
+ end
22
+
23
+ require 'spec/rake/spectask'
24
+ Spec::Rake::SpecTask.new(:spec) do |spec|
25
+ spec.libs << 'lib' << 'spec'
26
+ spec.spec_files = FileList['spec/**/*_spec.rb']
27
+ end
28
+
29
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
30
+ spec.libs << 'lib' << 'spec'
31
+ spec.pattern = 'spec/**/*_spec.rb'
32
+ spec.rcov = true
33
+ end
34
+
35
+ task :spec => :check_dependencies
36
+
37
+ task :default => :spec
38
+
39
+ require 'rake/rdoctask'
40
+ Rake::RDocTask.new do |rdoc|
41
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "better_serialization #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ # Include hook code here
2
+ require 'better_serialization'
@@ -0,0 +1,125 @@
1
+ require 'zlib'
2
+
3
+ module BetterSerialization
4
+ class JsonSerializer
5
+ attr_reader :options
6
+
7
+ def initialize(options)
8
+ @options = options
9
+ end
10
+
11
+ def to_json(object)
12
+ json = object.to_json
13
+ json = Zlib::Deflate.deflate(json) if options[:gzip]
14
+ json
15
+ end
16
+
17
+ def from_json(attribute)
18
+ return options[:default].try(:call) if attribute.nil?
19
+
20
+ json = options[:gzip] ? Zlib::Inflate.inflate(attribute) : attribute
21
+ decoded = ActiveSupport::JSON.decode(json)
22
+
23
+ if options[:with_indifferent_access]
24
+ return decoded.respond_to?(:with_indifferent_access) ? decoded.with_indifferent_access : decoded
25
+ end
26
+ return decoded if !options[:instantiate]
27
+
28
+ result = deserialize(attribute, [decoded].flatten)
29
+ return decoded.is_a?(Array) ? result : result.first
30
+ end
31
+
32
+ private
33
+
34
+ def deserialize(attribute, attribute_hashes)
35
+ class_name = options[:class_name]
36
+ attribute_hashes.inject([]) do |result, attr_hash|
37
+ if class_name.blank? || class_included?(class_name)
38
+ class_name = attr_hash.keys.first.camelcase
39
+ attr_hash = attr_hash.values.first
40
+ end
41
+ class_name ||= attribute.to_s.singularize.camelize
42
+
43
+ result << create(class_name.constantize, attr_hash.with_indifferent_access)
44
+ end
45
+ end
46
+
47
+ def active_record?(klass)
48
+ k = klass.superclass
49
+ while k != Object
50
+ return true if k == ActiveRecord::Base
51
+ k = k.superclass
52
+ end
53
+ false
54
+ end
55
+
56
+ def class_included?(class_name)
57
+ class_name.present? &&
58
+ active_record?(class_name.constantize) &&
59
+ ActiveRecord::Base.include_root_in_json
60
+ end
61
+
62
+ def create(klass, attr_hash)
63
+ if active_record?(klass)
64
+ klass.send(:instantiate, attr_hash)
65
+ else
66
+ klass.send(:new, attr_hash)
67
+ end
68
+ end
69
+ end
70
+
71
+ # === Options
72
+ # * +gzip+ - uses gzip before marshalling and unmarshalling. Slight speed hit,
73
+ # but can save a lot of hard drive space.
74
+ def marshal_serialize(*attrs)
75
+ options = attrs.last.is_a?(Hash) ? attrs.pop : {}
76
+
77
+ attrs.each do |attribute|
78
+ define_method "#{attribute}=" do |value|
79
+ marshalled_value = Marshal.dump(value)
80
+ marshalled_value = Zlib::Deflate.deflate(marshalled_value) if options[:gzip]
81
+ super(marshalled_value)
82
+ end
83
+
84
+ define_method attribute do
85
+ return nil if self[attribute].nil?
86
+
87
+ value = Zlib::Inflate.inflate(self[attribute]) if options[:gzip]
88
+ Marshal.load(value || self[attribute])
89
+ end
90
+ end
91
+ end
92
+
93
+ # === Options
94
+ # options is the last parameter (a hash):
95
+ # * +:gzip+ - uses gzip before and after serialization. Slight speed hit,
96
+ # but can save a lot of hard drive space.
97
+ # * +:instantiate+ - if false, it will return the raw decoded json and not attempt to
98
+ # instantiate ActiveRecord objects. Defaults to true.
99
+ # * +:with_indifferent_access+ - if true, it will return the raw decoded json as
100
+ # a hash with indifferent access. This can be handy because json doesn't have a concept
101
+ # of symbols, so it gets annoying when you're using a field as a key-value store
102
+ # * +:default+ - A proc that gets called when the field is null
103
+ # * +:class_name+ - If ActiveRecord::Base.include_root_in_json is false, you
104
+ # will need this option so that we can figure out which AR class to instantiate
105
+ # (not applicable if +raw+ is true)
106
+ def json_serialize(*attrs)
107
+ options = attrs.last.is_a?(Hash) ? attrs.pop : {}
108
+ options = {:instantiate => true}.merge(options)
109
+
110
+ attrs.each do |attribute|
111
+ define_method "#{attribute}=" do |value|
112
+ super(JsonSerializer.new(options).to_json(value))
113
+ end
114
+
115
+ define_method attribute do
116
+ JsonSerializer.new(options).from_json(self[attribute])
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ class ActiveRecord::Base
123
+ extend BetterSerialization
124
+ end
125
+
@@ -0,0 +1,122 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe BetterSerialization do
4
+ before do
5
+ @order_log = OrderLog.new
6
+ @li = LineItem.new
7
+ @product = Product.new(:name => "Woot", :line_items => [@li])
8
+ @li.product = @product
9
+ end
10
+
11
+ describe "json serialization" do
12
+ before do
13
+ @customer = Customer.new(:name => "John Spartan")
14
+ @order_log.customer_cache = @customer
15
+ @serialized_customer = @customer.to_json
16
+ end
17
+
18
+ it "serializes the attribute" do
19
+ @order_log[:customer_cache].should == @serialized_customer
20
+ end
21
+
22
+ it "deserializes the attribute" do
23
+ @order_log.customer_cache.attributes.should == @customer.attributes
24
+ end
25
+
26
+ it "works with arrays (and gzip)" do
27
+ OrderLog.json_serialize :line_items_cache, :class_name => "LineItem", :gzip => true
28
+ @order_log.line_items_cache = [@li]
29
+ @serialized_gzip_li = Zlib::Deflate.deflate([@li].to_json)
30
+
31
+ @order_log.save
32
+ @order_log.reload
33
+ @order_log[:line_items_cache].should == @serialized_gzip_li
34
+ @order_log.line_items_cache.first.attributes.should == @li.attributes
35
+
36
+ OrderLog.marshal_serialize :line_items_cache, :gzip => true
37
+ end
38
+
39
+ it "works with ActiveRecord::Base.include_root_in_json == true" do
40
+ ActiveRecord::Base.include_root_in_json = true
41
+
42
+ @order_log.customer_cache = @customer
43
+ @serialized_customer = @customer.to_json
44
+
45
+ @order_log[:customer_cache].should == @serialized_customer
46
+ @order_log.customer_cache.attributes.should == @customer.attributes
47
+ end
48
+
49
+ it "includes :id in serialization" do
50
+ @customer.save
51
+
52
+ @order_log.customer_cache = @customer
53
+ @serialized_customer = @customer.to_json
54
+
55
+ @order_log.customer_cache.attributes.should == @customer.attributes
56
+ @order_log.customer_cache.id.should == @customer.id
57
+ end
58
+
59
+ it "includes :id in a subclass of a subclass of ActiveRecord::Base" do
60
+ context "STI" do
61
+ before do
62
+ $DBG = true
63
+ @customer = PreferredCustomer.new(:name => "Lt. Lenina Huxley")
64
+ @order_log = OrderLog.new
65
+ end
66
+
67
+ it "includes :id when deserialized" do
68
+ @customer.save
69
+
70
+ @order_log.customer_cache = @customer
71
+ @order_log.customer_cache.id.should == @customer.id
72
+ $DBG = false
73
+ end
74
+ end
75
+ end
76
+
77
+ context "on a non-ActiveRecord object" do
78
+ let(:directory){ Directory.new }
79
+
80
+ it "unserializes the same" do
81
+ person = Person.new(:name => "Simon Phoenix", :age => 75)
82
+ directory.people = [person]
83
+ directory.people.first.should == person
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "Marshal serialization" do
89
+ before do
90
+ @order_log.product_cache = @product
91
+ @serialized_product = Marshal.dump(@product)
92
+ end
93
+
94
+ it "serializes the input of attribute=" do
95
+ @order_log[:product_cache].should == @serialized_product
96
+ end
97
+
98
+ it "deserializes the input of attribute=" do
99
+ # can't compare them directly 'cuz they have different object ids
100
+ @order_log.product_cache.attributes.should == @product.attributes
101
+ end
102
+ end
103
+
104
+ describe "Marshal serialization with gzip" do
105
+ before do
106
+ @order_log.line_items_cache = [@li]
107
+ @serialized_gzip_li = Zlib::Deflate.deflate(Marshal.dump([@li]))
108
+
109
+ # testing putting binary data in the database
110
+ @order_log.save
111
+ @order_log.reload
112
+ end
113
+
114
+ it "serializes the input of attribute=" do
115
+ @order_log[:line_items_cache].should == @serialized_gzip_li
116
+ end
117
+
118
+ it "deserializes the input of attribute=" do
119
+ @order_log.line_items_cache.first.attributes.should == @li.attributes
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,6 @@
1
+ class Customer < ActiveRecord::Base
2
+ has_many :line_items
3
+ end
4
+
5
+ class PreferredCustomer < Customer
6
+ end
@@ -0,0 +1,3 @@
1
+ class Directory < ActiveRecord::Base
2
+ json_serialize :people, :class_name => 'Person'
3
+ end
@@ -0,0 +1,4 @@
1
+ class LineItem < ActiveRecord::Base
2
+ belongs_to :product
3
+ belongs_to :customer
4
+ end
@@ -0,0 +1,5 @@
1
+ class OrderLog < ActiveRecord::Base
2
+ marshal_serialize :line_items_cache, :gzip => true
3
+ marshal_serialize :product_cache
4
+ json_serialize :customer_cache, :class_name => "Customer"
5
+ end
@@ -0,0 +1,12 @@
1
+ # Non-active record model to test
2
+ class Person
3
+ attr_accessor :name, :age
4
+
5
+ def initialize(attr)
6
+ @name, @age = attr[:name], attr[:age]
7
+ end
8
+
9
+ def ==(other)
10
+ other.is_a?(Person) && other.name == name && other.age == age
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ class Product < ActiveRecord::Base
2
+ has_many :line_items
3
+ end
@@ -0,0 +1,24 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table :order_logs do |t|
3
+ t.text "customer_cache"
4
+ t.text "product_cache"
5
+ t.binary "line_items_cache"
6
+ end
7
+
8
+ create_table :customers do |t|
9
+ t.string "name"
10
+ end
11
+
12
+ create_table :products do |t|
13
+ t.string "name"
14
+ end
15
+
16
+ create_table :line_items do |t|
17
+ t.integer "product_id"
18
+ t.integer "customer_id"
19
+ end
20
+
21
+ create_table :directories do |t|
22
+ t.binary "people"
23
+ end
24
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,30 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'rubygems'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+ require 'activerecord'
7
+ require 'better_serialization'
8
+
9
+ Spec::Runner.configure do |config|
10
+
11
+ end
12
+
13
+ RAILS_ENV="test"
14
+ ActiveRecord::Base.logger = Logger.new(StringIO.new) # make it think it has a logger
15
+
16
+ ActiveRecord::Base.configurations = {
17
+ "test" => {
18
+ :adapter => 'sqlite3',
19
+ :database => ":memory:"
20
+ }
21
+ }
22
+ ActiveRecord::Base.establish_connection
23
+ silence_stream(STDOUT) {require 'schema'}
24
+
25
+ require "models/order_log"
26
+ require "models/customer"
27
+ require "models/line_item"
28
+ require "models/product"
29
+ require "models/person"
30
+ require "models/directory"
metadata ADDED
@@ -0,0 +1,141 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mccraigmccraig-better_serialization
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - http://github.com/crystalcommerce
14
+ - http://github.com/rhburrows
15
+ - http://github.com/mccraigmccraig
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2010-07-15 00:00:00 +01:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ name: activerecord
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ hash: 19
32
+ segments:
33
+ - 2
34
+ - 3
35
+ - 8
36
+ version: 2.3.8
37
+ type: :runtime
38
+ version_requirements: *id001
39
+ - !ruby/object:Gem::Dependency
40
+ name: rspec
41
+ prerelease: false
42
+ requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ hash: 15
48
+ segments:
49
+ - 1
50
+ - 2
51
+ - 8
52
+ version: 1.2.8
53
+ type: :development
54
+ version_requirements: *id002
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3-ruby
57
+ prerelease: false
58
+ requirement: &id003 !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 25
64
+ segments:
65
+ - 1
66
+ - 3
67
+ - 1
68
+ version: 1.3.1
69
+ type: :development
70
+ version_requirements: *id003
71
+ description: serialize and deserialize activerecord attributes using json or zlib
72
+ email: mccraigmccraig@googlemail.com
73
+ executables: []
74
+
75
+ extensions: []
76
+
77
+ extra_rdoc_files:
78
+ - README.rdoc
79
+ files:
80
+ - .document
81
+ - .gitignore
82
+ - MIT-LICENSE
83
+ - README.rdoc
84
+ - Rakefile
85
+ - VERSION
86
+ - init.rb
87
+ - lib/better_serialization.rb
88
+ - spec/better_serialization_spec.rb
89
+ - spec/models/customer.rb
90
+ - spec/models/directory.rb
91
+ - spec/models/line_item.rb
92
+ - spec/models/order_log.rb
93
+ - spec/models/person.rb
94
+ - spec/models/product.rb
95
+ - spec/schema.rb
96
+ - spec/spec.opts
97
+ - spec/spec_helper.rb
98
+ has_rdoc: true
99
+ homepage: http://github.com/trampoline/better_serialization
100
+ licenses: []
101
+
102
+ post_install_message:
103
+ rdoc_options:
104
+ - --charset=UTF-8
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ hash: 3
113
+ segments:
114
+ - 0
115
+ version: "0"
116
+ required_rubygems_version: !ruby/object:Gem::Requirement
117
+ none: false
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ hash: 3
122
+ segments:
123
+ - 0
124
+ version: "0"
125
+ requirements: []
126
+
127
+ rubyforge_project:
128
+ rubygems_version: 1.3.7
129
+ signing_key:
130
+ specification_version: 3
131
+ summary: json and zlib serialization for activerecord attributes
132
+ test_files:
133
+ - spec/better_serialization_spec.rb
134
+ - spec/models/customer.rb
135
+ - spec/models/directory.rb
136
+ - spec/models/line_item.rb
137
+ - spec/models/order_log.rb
138
+ - spec/models/person.rb
139
+ - spec/models/product.rb
140
+ - spec/schema.rb
141
+ - spec/spec_helper.rb