serialized_attributes 0.1.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/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+ gem 'rails', "~> 3.0.0"
3
+
4
+ # Add dependencies to develop your gem here.
5
+ # Include everything needed to run rake, tests, features, etc.
6
+ group :development do
7
+ gem "bundler", "~> 1.0.7"
8
+ gem "jeweler", "~> 1.5.2"
9
+ gem "sqlite3"
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,80 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.5)
6
+ actionpack (= 3.0.5)
7
+ mail (~> 2.2.15)
8
+ actionpack (3.0.5)
9
+ activemodel (= 3.0.5)
10
+ activesupport (= 3.0.5)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.4)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.13)
16
+ rack-test (~> 0.5.7)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.5)
19
+ activesupport (= 3.0.5)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.4)
22
+ activerecord (3.0.5)
23
+ activemodel (= 3.0.5)
24
+ activesupport (= 3.0.5)
25
+ arel (~> 2.0.2)
26
+ tzinfo (~> 0.3.23)
27
+ activeresource (3.0.5)
28
+ activemodel (= 3.0.5)
29
+ activesupport (= 3.0.5)
30
+ activesupport (3.0.5)
31
+ arel (2.0.9)
32
+ builder (2.1.2)
33
+ erubis (2.6.6)
34
+ abstract (>= 1.0.0)
35
+ git (1.2.5)
36
+ i18n (0.5.0)
37
+ jeweler (1.5.2)
38
+ bundler (~> 1.0.0)
39
+ git (>= 1.2.5)
40
+ rake
41
+ mail (2.2.15)
42
+ activesupport (>= 2.3.6)
43
+ i18n (>= 0.4.0)
44
+ mime-types (~> 1.16)
45
+ treetop (~> 1.4.8)
46
+ mime-types (1.16)
47
+ polyglot (0.3.1)
48
+ rack (1.2.1)
49
+ rack-mount (0.6.13)
50
+ rack (>= 1.0.0)
51
+ rack-test (0.5.7)
52
+ rack (>= 1.0)
53
+ rails (3.0.5)
54
+ actionmailer (= 3.0.5)
55
+ actionpack (= 3.0.5)
56
+ activerecord (= 3.0.5)
57
+ activeresource (= 3.0.5)
58
+ activesupport (= 3.0.5)
59
+ bundler (~> 1.0)
60
+ railties (= 3.0.5)
61
+ railties (3.0.5)
62
+ actionpack (= 3.0.5)
63
+ activesupport (= 3.0.5)
64
+ rake (>= 0.8.7)
65
+ thor (~> 0.14.4)
66
+ rake (0.8.7)
67
+ sqlite3 (1.3.3)
68
+ thor (0.14.6)
69
+ treetop (1.4.9)
70
+ polyglot (>= 0.3.1)
71
+ tzinfo (0.3.24)
72
+
73
+ PLATFORMS
74
+ ruby
75
+
76
+ DEPENDENCIES
77
+ bundler (~> 1.0.7)
78
+ jeweler (~> 1.5.2)
79
+ rails (~> 3.0.0)
80
+ sqlite3
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Emma Persky
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,72 @@
1
+ serialized_attributes
2
+ =====================
3
+
4
+ This is a very cool lib, allows to define dynamic serialized fields in your AR model, which acts as normal rails db columns.
5
+ It give you full power of rails to your virtual columns: validations, rails forms, error messages, type casting
6
+ (integer, date/time), type safety, :dirty? s, etc.. STI is supported! Basic associations is working too!
7
+
8
+ Now updated for Rails 3
9
+
10
+ Example of usage
11
+ ----------------
12
+
13
+ ### STI table def
14
+
15
+ create_table :documents do |t|
16
+ t.string :type
17
+ t.text :serialized_attributes # <--- here all your dynamic fields will be saved
18
+ t.integer :reference_id # <--- you can also define any sql columns for your indexes
19
+ t.timestamps
20
+ end
21
+
22
+ ### STI base model
23
+
24
+ class Document < ActiveRecord::Base
25
+ include SerializedAttributes
26
+ end
27
+
28
+ ### Other models..
29
+
30
+ class Post < Document
31
+ attribute :title, String
32
+ attribute :body, String
33
+ attribute :is_published, Boolean, :default => false
34
+
35
+ attribute :comment_ids, Array # <--- serialized Array of ids of associated comments
36
+ has_references_to :comments
37
+
38
+ validates_presence_of :title, :body
39
+ end
40
+
41
+ class Comment < Document
42
+ attribute :body, String, :requied => true # <--- validates_presence_of :body
43
+ attribute :post_id, Integer
44
+ belongs_to :post
45
+ end
46
+
47
+ IRB fun
48
+ -------
49
+
50
+ post = Post.create(:title => "First Post", :body => "Lorem ...")
51
+ assert !post.new_record?
52
+ post.comments = [Comment.create(:body => "this is a comment")]
53
+ post.comments << Comment.create(:body => "this is second comment")
54
+ assert_equal Comment.all.map(&:id), post.comment_ids
55
+ post.save
56
+ assert post.reload.comments.length == 2
57
+
58
+ # Mass Assignment and Protect Attributes
59
+ class Widget < ActiveRecord::Base
60
+ include SerializedAttributes
61
+
62
+ #protect other attributes from mass assignment
63
+ attr_accessible :name
64
+
65
+ #specifically permit a given serialized attribute to be mass assigned
66
+ accessible_attribute :creator, String
67
+ end
68
+
69
+
70
+ # limitations
71
+ - has-references-to association dont update reverse association
72
+ - serialized-attributes column saved every time you call :save without depending on what is actually changed
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "serialized_attributes"
16
+ gem.homepage = "http://github.com/emmapersky/serialized_attributes"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Simple serialization of row level attributes}
19
+ gem.description = %Q{Serialize model attributes to a single database column instead}
20
+ gem.email = "emma.persky@gmail.com"
21
+ gem.authors = ["Emma Persky"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/*.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ # require 'rcov/rcovtask'
37
+ # Rcov::RcovTask.new do |test|
38
+ # test.libs << 'test'
39
+ # test.pattern = 'test/**/*.rb'
40
+ # test.verbose = true
41
+ # end
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "foo #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + '/lib/has_references_to'
2
+ require File.dirname(__FILE__) + '/lib/serialized_attributes'
@@ -0,0 +1,70 @@
1
+ module ActiveRecord
2
+ module Associations
3
+
4
+ class HasReferencesToAssociation < HasManyAssociation
5
+ def ids
6
+ (@owner["#{@reflection.name.to_s.singularize}_ids"] ||= []).map(&:to_i)
7
+ end
8
+
9
+ def ids=(array = [])
10
+ @owner["#{@reflection.name.to_s.singularize}_ids"] = array.map(&:to_i)
11
+ end
12
+
13
+ def construct_sql
14
+ @finder_sql = "#{@reflection.quoted_table_name}.id IN (#{ids * ', '})"
15
+ @finder_sql << " AND (#{conditions})" if conditions
16
+ @counter_sql = @finder_sql
17
+ end
18
+
19
+ def insert_record(record, force = false, validate = true)
20
+ load_target
21
+ set_belongs_to_association_for(record)
22
+ result = !record.new_record? || (force ? record.save! : record.save(:validate => validate))
23
+ self.ids = (ids + [record.id]) if result
24
+ result
25
+ end
26
+
27
+ def delete_records(records)
28
+ self.ids = ids - records.map(&:id)
29
+ end
30
+
31
+ def create(attrs = {})
32
+ if attrs.is_a?(Array)
33
+ attrs.collect { |attr| create(attr) }
34
+ else
35
+ create_record(attrs) do |record|
36
+ yield(record) if block_given?
37
+ self.ids = (ids << record.id) if record.save
38
+ end
39
+ end
40
+ end
41
+
42
+ def create!(attrs = {})
43
+ create_record(attrs) do |record|
44
+ yield(record) if block_given?
45
+ record.save!
46
+ self.ids = (ids << record.id)
47
+ end
48
+ end
49
+ end
50
+
51
+ module ClassMethods
52
+ def create_has_references_to_reflection(association_id, options, &extension)
53
+ #options.assert_valid_keys(valid_keys_for_has_many_association)
54
+ options[:extend] = create_extension_modules(association_id, extension, options[:extend])
55
+ reflection = ActiveRecord::Reflection::AssociationReflection.new(:has_many, association_id, options, self)
56
+ write_inheritable_hash :reflections, name => reflection
57
+ reflection
58
+ end
59
+
60
+ def has_references_to(association_id, options = {}, &extension)
61
+ reflection = create_has_references_to_reflection(association_id, options, &extension)
62
+ configure_dependency_for_has_many(reflection)
63
+ add_association_callbacks(reflection.name, reflection.options)
64
+
65
+ collection_accessor_methods(reflection, HasReferencesToAssociation)
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,89 @@
1
+ module SerializedAttributes
2
+ def self.included(base)
3
+ return if base.respond_to?(:serialized_attributes_definition)
4
+
5
+ base.class_eval do
6
+ class_inheritable_hash :serialized_attributes_definition
7
+ write_inheritable_attribute(:serialized_attributes_definition, {})
8
+ cattr_accessor :serialized_attributes_column
9
+ self.serialized_attributes_column = :serialized_attributes
10
+
11
+ serialize serialized_attributes_column, Hash
12
+
13
+
14
+ base.extend ClassMethods
15
+ include InstanceMethods
16
+ end
17
+ end
18
+
19
+ module ClassMethods
20
+ def serialized_attributes_definition
21
+ read_inheritable_attribute(:serialized_attributes_definition)
22
+ end
23
+
24
+ def instantiate(record)
25
+ object = super(record)
26
+ object.unpack_serialized_attributes!
27
+ object
28
+ end
29
+
30
+ def accessible_attribute(name, type, opts = {})
31
+ attribute(name, type, opts.merge({:attr_accessible => true}))
32
+ end
33
+
34
+ def attribute(name, type, opts = {})
35
+ name = name.to_s
36
+ type = SerializedAttributes.type_to_sqltype(type)
37
+ serialized_attributes_definition[name] = ActiveRecord::ConnectionAdapters::Column.new(name.to_s, opts[:default], type.to_s, nil)
38
+
39
+ define_method("#{name.to_s}=".to_sym) { |value| @attributes[name] = value }
40
+ define_method(name) { self.class.serialized_attributes_definition[name].type_cast(@attributes[name]) }
41
+
42
+ attr_accessible name if opts[:attr_accessible]
43
+ end
44
+ end
45
+
46
+ module InstanceMethods
47
+ def create_or_update
48
+ pack_serialized_attributes!
49
+ super
50
+ end
51
+
52
+ def unpack_serialized_attributes!
53
+ if @attributes.has_key?(serialized_attributes_column.to_s) && attributes = (self[serialized_attributes_column] || {})
54
+ serialized_attributes_definition.each do |key, column|
55
+ loaded_value = attributes.has_key?(key) ? attributes[key] : column.default
56
+ @attributes[key] = attributes.has_key?(key) ? attributes[key] : column.default
57
+ end
58
+ attributes.slice!(*serialized_attributes_definition.keys)
59
+ end
60
+ end
61
+
62
+ def pack_serialized_attributes!
63
+ if @attributes.has_key?(serialized_attributes_column.to_s)
64
+ attributes = self[serialized_attributes_column] ||= {}
65
+ serialized_attributes_definition.each do |key, column|
66
+ attributes[key] = self.send key
67
+ end
68
+ end
69
+ attributes.slice!(*serialized_attributes_definition.keys)
70
+ end
71
+ end
72
+
73
+ def to_variable(sym)
74
+ "@#{sym.to_s}".to_sym
75
+ end
76
+
77
+ def self.type_to_sqltype(type)
78
+ return type if type.is_a?(Symbol)
79
+ {
80
+ String => :string, Boolean => :boolean,
81
+ Fixnum => :integer, Integer => :integer, BigDecimal => :decimal, Float => :float,
82
+ Date => :date, Time => :time, DateTime => :time
83
+ }[type] || type
84
+ end
85
+
86
+ module Boolean
87
+ end
88
+
89
+ end
@@ -0,0 +1,130 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'active_record'
4
+ require 'logger'
5
+
6
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
7
+
8
+ require File.dirname(__FILE__) + "/../init" # load plugin
9
+
10
+ class DocumentsSchema < ActiveRecord::Migration
11
+ def self.up
12
+ create_table :documents do |t|
13
+ t.text :serialized_attributes # <--- here all your dynamic fields will be saved
14
+ t.string :type
15
+ t.integer :reference_id # <--- you can also define any sql columns for your indexes
16
+ t.timestamps
17
+ end
18
+
19
+ create_table :widgets do |t|
20
+ t.string :name
21
+ t.boolean :active
22
+ t.text :serialized_attributes
23
+ t.timestamps
24
+ end
25
+ end
26
+ end
27
+
28
+ class Document < ActiveRecord::Base
29
+ include SerializedAttributes
30
+ end
31
+
32
+ class Post < Document
33
+ attribute :title, String
34
+ attribute :body, String
35
+ attribute :is_published, Boolean, :default => false
36
+
37
+ attribute :comment_ids, Array # <--- serialized Array of ids of associated comments
38
+ has_references_to :comments
39
+
40
+ validates_presence_of :title, :body
41
+
42
+ end
43
+
44
+ class Comment < Document
45
+ attribute :body, String
46
+ attribute :post_id, Integer
47
+ belongs_to :post
48
+
49
+ validates_presence_of :body
50
+
51
+ end
52
+
53
+ class ModelBefore < ActiveRecord::Base
54
+ set_table_name :documents
55
+ end
56
+
57
+ class ModelAfter < ActiveRecord::Base
58
+ set_table_name :documents
59
+ include SerializedAttributes
60
+ attribute :custom_field, String, :default => 'default value'
61
+ end
62
+
63
+ class ModelSecond < ActiveRecord::Base
64
+ set_table_name :documents
65
+ include SerializedAttributes
66
+ attribute :custom_field_renamed, String, :default => 'new default value'
67
+ end
68
+
69
+ class Widget < ActiveRecord::Base
70
+ include SerializedAttributes
71
+
72
+ #white list the name attribute, others may not be mass assigned
73
+ attr_accessible :name, String
74
+ end
75
+
76
+ class Sprocket < Widget
77
+ #we want the attribute in_motion, but it may not be mass assigned
78
+ attribute :in_motion, Boolean
79
+
80
+ #we want to allow the size attribute to be mass assigned
81
+ accessible_attribute :size, Integer
82
+ end
83
+
84
+
85
+ class SimpleTest < Test::Unit::TestCase
86
+ #ActiveRecord::Base.logger = Logger.new(STDOUT)
87
+ DocumentsSchema.suppress_messages{ DocumentsSchema.migrate(:up) }
88
+
89
+ def test_simple
90
+ post = Post.create(:title => "First Post", :body => "Lorem ...")
91
+ assert !post.new_record?
92
+ post.comments << Comment.new(:body => "this is a comment")
93
+ post.comments << Comment.create(:body => "this is second comment")
94
+ post.comments.create(:body => "one more")
95
+
96
+ assert_equal Comment.all.map(&:id), post.comment_ids
97
+ post.save
98
+
99
+ assert_equal 3, post.reload.comments.size
100
+ end
101
+
102
+
103
+ # => it should initialize attributes on objects even if they were serialized before that attribute existed
104
+ def test_null_serialized_attributes_column_on_already_exists_records
105
+ # => to test this, we create a model (ModelBefore) that has no attributes (but has an attributes column)
106
+ # => then we create second model (ModelAfter) which we force to use the same table as ModelBefore (set_table_name)
107
+ # => We create an object using ModelBefore and then try to load it using ModelAfter.
108
+ model_before = ModelBefore.create
109
+ model_after = ModelAfter.find(model_before.id)
110
+
111
+ assert_equal model_after.custom_field, 'default value'
112
+ end
113
+
114
+ # => it should not unpack custom attributes on objects if they have been removed
115
+ def test_removed_custom_field
116
+ # => to test this, we use a similar method to the prior test, but change (or remove) an attribute
117
+ model1 = ModelAfter.create
118
+ model2 = ModelSecond.find(model1.id)
119
+ model2.save!
120
+ model2.reload
121
+
122
+ assert_equal model2.serialized_attributes.keys.include?('custom_field'), false
123
+ end
124
+
125
+ # => it should create attributes as whitelisted and allow their mass assignment
126
+ def test_accessible_attributes_are_created
127
+ sprocket = Sprocket.create(:name => "Spacely's Space Sprocket", :size => 99)
128
+ assert sprocket.size == 99
129
+ end
130
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: serialized_attributes
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
+ - Emma Persky
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-03 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ type: :runtime
23
+ prerelease: false
24
+ name: rails
25
+ version_requirements: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 7
31
+ segments:
32
+ - 3
33
+ - 0
34
+ - 0
35
+ version: 3.0.0
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ type: :development
39
+ prerelease: false
40
+ name: bundler
41
+ version_requirements: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ hash: 25
47
+ segments:
48
+ - 1
49
+ - 0
50
+ - 7
51
+ version: 1.0.7
52
+ requirement: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ type: :development
55
+ prerelease: false
56
+ name: jeweler
57
+ version_requirements: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ hash: 7
63
+ segments:
64
+ - 1
65
+ - 5
66
+ - 2
67
+ version: 1.5.2
68
+ requirement: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ type: :development
71
+ prerelease: false
72
+ name: sqlite3
73
+ version_requirements: &id004 !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 3
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ requirement: *id004
83
+ description: Serialize model attributes to a single database column instead
84
+ email: emma.persky@gmail.com
85
+ executables: []
86
+
87
+ extensions: []
88
+
89
+ extra_rdoc_files:
90
+ - LICENSE.txt
91
+ - README.md
92
+ files:
93
+ - Gemfile
94
+ - Gemfile.lock
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - VERSION
99
+ - init.rb
100
+ - lib/has_references_to.rb
101
+ - lib/serialized_attributes.rb
102
+ - test/simple_test.rb
103
+ has_rdoc: true
104
+ homepage: http://github.com/emmapersky/serialized_attributes
105
+ licenses:
106
+ - MIT
107
+ post_install_message:
108
+ rdoc_options: []
109
+
110
+ require_paths:
111
+ - lib
112
+ required_ruby_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ required_rubygems_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ hash: 3
127
+ segments:
128
+ - 0
129
+ version: "0"
130
+ requirements: []
131
+
132
+ rubyforge_project:
133
+ rubygems_version: 1.3.7
134
+ signing_key:
135
+ specification_version: 3
136
+ summary: Simple serialization of row level attributes
137
+ test_files:
138
+ - test/simple_test.rb