rughetto-ar_object_pack 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Rue The Ghetto
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 ADDED
@@ -0,0 +1,40 @@
1
+ ar_object_pack
2
+ ==============
3
+
4
+ A Merb/Rails plugin for ActiveRecord that pack objects into text strings easy storage in the database.
5
+
6
+ Advances in ORMs like DataMapper have introduced data types that allow rich data objects to be packed into the database. From early on ActiveRecord came with the #serialize method, that adds this functionality via YAML. The implementation of YAML in Ruby is very slow, making serialization this way approximately 30 to 100 times slower that serializing via data marshaling, depending on the complexity of the object.
7
+
8
+ This plugin allows objects to be packaged into the database using Marshal, JSON, or YAML. In addition, marshaled objects can be encoded using base 64 to prevent problems with character sets in the query string.
9
+
10
+
11
+ INSTALLATION
12
+ ============
13
+ ar_object_pack is a gem hosted at github. To add github as a source for gems, run this on command:
14
+ gem sources -a http://gems.github.com
15
+ The gem can then be installed on the command line via
16
+ sudo gem install rughetto-ar_object_pack
17
+
18
+ If using Merb, adding the gem as a dependency will also load the required methods into ActiveRecord Base. For other frameworks, add to the application initialization the following lines of code:
19
+
20
+ require File.dirname(__FILE__) + PATH_TO_GEM_LIB_DIR +'/ar_object_pack/object_packer'
21
+ ActiveRecord::Base.send(:extend, ArObjectPack::ObjectPackager::ActiveRecordMethods)
22
+
23
+ PATH_TO_GEM_LIB_DIR above should be replaced by the relative path from the initialization file to the gem library. Hopefully soon a init.rb file will allow easy Rails plugin ability too.
24
+
25
+
26
+ USAGE
27
+ =====
28
+ ar_object_pack adds the #package method to ActiveRecord base. That means that in the model class definition, any text holding field can be specified as a packaged object.
29
+
30
+ class PackagedThing < ActiveRecord::Base
31
+ package :obj # defaults to :marshal
32
+ package :obj_marshal, :marshal
33
+ package :obj_yaml, :yaml
34
+ package :obj_json, :json
35
+ package :obj_marshal_64, :marshal_64
36
+ end
37
+
38
+ #package takes two arguments
39
+ 1) database_attribute: This can be of type either string or a symbol. If the text does not correspond to a model database attribute, an argument exception will be raised.
40
+ 2) package_method: This is an optional argument with the default value being :marshal. The value can also be passed as either a string or a symbol. Currently there are the values as seen in above example.
data/Rakefile ADDED
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'spec/rake/spectask'
4
+
5
+ require 'merb-core'
6
+ require 'merb-core/tasks/merb'
7
+
8
+ GEM_NAME = "ar_object_pack"
9
+ GEM_VERSION = "0.0.1"
10
+ AUTHOR = "Rue The Ghetto"
11
+ EMAIL = "ru_ghetto@rubyghetto.com"
12
+ HOMEPAGE = "http://github.com/ru_ghetto/ar_object_pack"
13
+ SUMMARY = "ActiveRecord plugin originally designed for Merb use that allows the packaging of objects into formats: marshal, json and yaml."
14
+
15
+ spec = Gem::Specification.new do |s|
16
+ s.rubyforge_project = 'merb'
17
+ s.name = GEM_NAME
18
+ s.version = GEM_VERSION
19
+ s.platform = Gem::Platform::RUBY
20
+ s.has_rdoc = true
21
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
22
+ s.summary = SUMMARY
23
+ s.description = s.summary
24
+ s.author = AUTHOR
25
+ s.email = EMAIL
26
+ s.homepage = HOMEPAGE
27
+
28
+ s.add_dependency('active_record')
29
+ s.add_dependency('json')
30
+
31
+ s.require_path = 'lib'
32
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
33
+ end
34
+
35
+ Rake::GemPackageTask.new(spec) do |pkg|
36
+ pkg.gem_spec = spec
37
+ end
38
+
39
+ desc "install the plugin as a gem"
40
+ task :install do
41
+ Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
42
+ end
43
+
44
+ desc "Uninstall the gem"
45
+ task :uninstall do
46
+ Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
47
+ end
48
+
49
+ desc "Create a gemspec file"
50
+ task :gemspec do
51
+ File.open("#{GEM_NAME}.gemspec", "w") do |file|
52
+ file.puts spec.to_ruby
53
+ end
54
+ end
55
+
56
+ Spec::Rake::SpecTask.new do |t|
57
+ t.warning = true
58
+ t.spec_opts = ["--format", "specdoc", "--colour"]
59
+ t.spec_files = Dir['spec/**/*_spec.rb'].sort
60
+ end
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+ TODO:
2
+
3
+ Add Rails plugin initialization file(s).
4
+ Think about validations, etc for packaging enumerable values and other useful objects from Datamapper
@@ -0,0 +1,95 @@
1
+ require 'json'
2
+ require 'yaml'
3
+
4
+ module ArObjectPack
5
+ module ObjectPackager
6
+ # these methods are added directly to the active record base
7
+ # for use like
8
+ # MyNewClass < ActiveRecord::Base
9
+ # package field_name, :marshall
10
+ # end
11
+ # arguments: meth
12
+ module ActiveRecordMethods
13
+ def package( meth, pack_type=:marshal )
14
+ raise ArgumentError, "#{meth} is not a database attribute " unless self.new.attributes.keys.include?( meth.to_s )
15
+ include ArObjectPack::ObjectPackager::InstanceMethods unless self.respond_to?(:do_pack)
16
+
17
+ pack_type = :marshal unless pack_formats.include?( pack_type )
18
+ self.class_eval %{
19
+ # create new reader
20
+ def #{meth}
21
+ unpack(self[:#{meth}], '#{pack_type}')
22
+ end
23
+
24
+ # create new writer
25
+ def #{meth}=(val)
26
+ begin
27
+ self[:#{meth}] = pack(val, '#{pack_type}')
28
+ rescue => e
29
+ raise ArgumentError, "Unable to package this object using #{pack_type}: message - " + e.message
30
+ end
31
+ end
32
+ }
33
+ end
34
+
35
+ private
36
+ def pack_formats
37
+ formats = [:marshal, :json, :yaml, :marshal_64]
38
+ formats | formats.collect(&:to_s)
39
+ end
40
+ end
41
+
42
+ module InstanceMethods
43
+ private
44
+ def unpack(p_object, pack_type)
45
+ if p_object.class == String
46
+ loaded = do_pack( pack_type ) do |klass, pack_encode|
47
+ # decode if required
48
+ decoded = pack_encode ? Base64.decode64( p_object ) : p_object
49
+ # use the class to load the data
50
+ decoded = klass.load( decoded )
51
+ return decoded
52
+ end
53
+ else
54
+ loaded = p_object
55
+ end
56
+ loaded
57
+ end
58
+
59
+ def pack(p_object, pack_type)
60
+ do_pack( pack_type ) do |klass, pack_encode|
61
+ # pack using class
62
+ if klass == JSON
63
+ JSON.dump( p_object)
64
+ end
65
+ dumped = klass.dump( p_object )
66
+ # encode if necessary
67
+ dumped = Base64.encode64( dumped ) if pack_encode
68
+ return dumped
69
+ end
70
+ end
71
+
72
+ def do_pack( pack_type )
73
+ # determine base pack type and encoding
74
+ pack_type = pack_type.to_s
75
+ pack_encode = false
76
+ if pack_type.include?( "64" )
77
+ pack_encode = true
78
+ pack_type = pack_type[0 .. pack_type.length-4]
79
+ end
80
+
81
+ case pack_type
82
+ when "json"
83
+ klass = JSON
84
+ when "yaml"
85
+ klass = YAML
86
+ else
87
+ klass = Marshal
88
+ end
89
+
90
+ yield( klass, pack_encode )
91
+ end
92
+ public
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,18 @@
1
+ # make sure we're running inside Merb
2
+ if defined?(Merb::Plugins)
3
+
4
+ # Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in your piece of it
5
+ Merb::Plugins.config[:ar_object_pack] = {}
6
+
7
+ Merb::BootLoader.before_app_loads do
8
+ # load ObjectPacker into AR Base
9
+ require File.dirname(__FILE__) + '/ar_object_pack/object_packer'
10
+ ActiveRecord::Base.send(:extend, ArObjectPack::ObjectPackager::ActiveRecordMethods)
11
+ end
12
+
13
+ Merb::BootLoader.after_app_loads do
14
+ # code that can be required after the application loads
15
+ end
16
+
17
+ # Merb::Plugins.add_rakefiles "ar_object_pack/merbtasks"
18
+ end
@@ -0,0 +1,188 @@
1
+ # helper
2
+ require File.dirname(__FILE__) + '/spec_helper'
3
+
4
+ # gems for testing
5
+ require 'rubygems'
6
+ require 'active_record'
7
+ require 'sqlite3'
8
+
9
+ # files for testing
10
+ require File.dirname(__FILE__) + '/../lib/ar_object_pack/object_packer'
11
+
12
+ # establish database and test classes
13
+ require File.dirname(__FILE__) + "/database_spec_setup"
14
+ include DatabaseSpecSetup
15
+
16
+ describe "ar_object_pack" do
17
+ describe "testing setup: " do
18
+ it "have all the needed gems and files to run" do
19
+ # before block should not throw error and the following should pass!
20
+ true.should == true
21
+ end
22
+
23
+ it "should save and retrieve test records normally" do
24
+ testing = Testing.new(:str => "my new string")
25
+ testing.should be_new_record
26
+ testing.save
27
+ testing.should_not be_new_record
28
+ testing.str.should == "my new string"
29
+ end
30
+ end
31
+
32
+ describe "Methods are added to ActiveRecord::Base, " do
33
+ it '#package is a method available in ActiveRecord::Base' do
34
+ ActiveRecord::Base.methods.include?( "package" ).should == true
35
+ end
36
+ end
37
+
38
+ describe 'packaging objects, ' do
39
+ before(:each) do
40
+ @object = ['1','2','3']
41
+ @instance = Package.new
42
+ end
43
+
44
+ it "using the AR package call should not raise errors" do
45
+ lambda {
46
+ instance = Package.new
47
+ }.should_not raise_error
48
+ end
49
+
50
+ describe "default pack method" do
51
+ it "should have private methods for pack, unpack and do_pack" do
52
+ @instance.private_methods.should include('pack')
53
+ @instance.private_methods.should include('unpack')
54
+ @instance.private_methods.should include('do_pack')
55
+ end
56
+
57
+ it "should pack a field attribute using Marshal if no pack method is defined" do
58
+ Marshal.should_receive(:dump).at_least(:once)
59
+ @instance.obj = @object
60
+ end
61
+
62
+ it "should unpack a field attribute using Marshal if no pack method is defined" do
63
+ Marshal.should_receive(:load).at_least(:once)
64
+ @instance.obj = @object
65
+ @instance.obj
66
+ end
67
+ end
68
+
69
+ describe "explicit Marshal packing" do
70
+ it "should pack a field attribute using Marshal when that option is specified" do
71
+ Marshal.should_receive(:dump).at_least(:once)
72
+ @instance.obj_marshal = @object
73
+ end
74
+
75
+ it "should unpack a field attribute using Marshal when that option is specified" do
76
+ Marshal.should_receive(:load).at_least(:once)
77
+ @instance.obj_marshal = @object
78
+ @instance.obj_marshal
79
+ end
80
+
81
+ it "an object should be the same after packing, saving and unpacking with Marshal method" do
82
+ @instance.obj_marshal = @object
83
+ @instance.save
84
+ @instance.reload
85
+ @instance.obj_marshal.should == @object
86
+ end
87
+ end
88
+
89
+ describe "YAML packing" do
90
+ it "should pack a field attribute using YAML when that option is specified" do
91
+ YAML.should_receive(:dump).at_least(:once)
92
+ @instance.obj_yaml = @object
93
+ end
94
+
95
+ it "should unpack a field attribute using YAML when that option is specified" do
96
+ YAML.should_receive(:load).at_least(:once)
97
+ @instance.obj_yaml = @object
98
+ @instance.obj_yaml
99
+ end
100
+
101
+ it "an object should be the same after packing and unpacking with YAML method" do
102
+ @instance.obj_yaml = @object
103
+ @instance.save
104
+ @instance.reload
105
+ @instance.obj_yaml.should == @object
106
+ end
107
+
108
+ it "object should not be packed in the same way as marshal" do
109
+ @instance.obj_yaml = @object
110
+ @instance.obj = @object
111
+ @instance[:obj_yaml].should_not == @instance[:obj]
112
+ end
113
+ end
114
+
115
+ describe "JSON packing" do
116
+ it "should pack a field attribute using JSON when that option is specified" do
117
+ JSON.should_receive(:dump).at_least(:once)
118
+ @instance.obj_json = @object
119
+ end
120
+
121
+ it "should unpack a field attribute using JSON when that option is specified" do
122
+ JSON.should_receive(:load).at_least(:once)
123
+ @instance.obj_json = @object
124
+ @instance.obj_json
125
+ end
126
+
127
+ it "an object should be the same after packing and unpacking with JSON method" do
128
+ @instance.obj_json = @object
129
+ @instance.save
130
+ @instance.reload
131
+ @instance.obj_json == @object
132
+ end
133
+
134
+ it "object should not be packed in the same way as marshal" do
135
+ @instance.obj_json = @object
136
+ @instance.obj = @object
137
+ @instance[:obj_json].should_not == @instance[:obj]
138
+ end
139
+ end
140
+
141
+ describe "Encoding with packing" do
142
+ it "should encode a field attribute when that option is specified in the pack_type" do
143
+ Base64.should_receive(:encode64).at_least(:once)
144
+ @instance.obj_marshal_64 = @object
145
+ end
146
+
147
+ it "should decode a field attribute when that option is specified in the pack_type" do
148
+ # This seems to be failing even though it is actually working.
149
+ # The error is bubbling up from the C code. If the should_receive directive is taken out
150
+ # of the mix no error is raised. So it may be some weirdness with the interaction between
151
+ # Marshal and rpsec ??
152
+ Base64.should_receive("decode64").at_least(:once)
153
+ @instance.obj_marshal_64 = @object
154
+ @instance.obj_marshal_64
155
+ end
156
+
157
+ it "an object should be the same after packing, saving and unpacking when using encoded data" do
158
+ @instance.obj_marshal_64 = @object
159
+ @instance.save
160
+ @instance.reload
161
+ @instance.obj_marshal_64.should == @object
162
+ end
163
+
164
+ it "object should not be packed in the same way as unencoded marshal" do
165
+ @instance.obj_marshal_64 = @object
166
+ @instance.obj = @object
167
+ @instance[:obj_marshal_64].should_not == @instance[:obj]
168
+ @instance[:obj_marshal_64].should_not == @object
169
+ end
170
+ end
171
+
172
+ describe "an exception should be thrown if" do
173
+ it "packaging method is unable to pack the object" do
174
+ lambda{
175
+ @instance.obj_json = {:something => :else}
176
+ }.should raise_error
177
+ end
178
+
179
+ it "package is called on the class for a method name that does not belong to a field attribute" do
180
+ lambda {
181
+ class Package
182
+ package :not_a_field
183
+ end
184
+ }.should raise_error
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,42 @@
1
+ module DatabaseSpecSetup
2
+ # remove the old database
3
+ File.delete("object_pack_tester.db") if File.file?("object_pack_tester.db")
4
+
5
+ # send methods to base
6
+ ActiveRecord::Base.send(:extend, ArObjectPack::ObjectPackager::ActiveRecordMethods)
7
+
8
+ # establish a connection to the sqlite database
9
+ ActiveRecord::Base.establish_connection(
10
+ :adapter => 'sqlite3',
11
+ :database => 'object_pack_tester.db'
12
+ )
13
+
14
+ # define a schema
15
+ ActiveRecord::Schema.define do
16
+ # table for testing different packages
17
+ create_table :packages, :force => true do |t|
18
+ t.column :obj, :text
19
+ t.column :obj_marshal, :text
20
+ t.column :obj_yaml, :text
21
+ t.column :obj_json, :text
22
+ t.column :obj_marshal_64, :text
23
+ end
24
+
25
+ # table for testing basic database writes and reads to ensure correct setup
26
+ create_table :testings, :force => true do |t|
27
+ t.column :str, :string
28
+ end
29
+ end
30
+
31
+ # Related classes
32
+ class Package < ActiveRecord::Base
33
+ package :obj
34
+ package :obj_marshal, :marshal
35
+ package :obj_yaml, :yaml
36
+ package :obj_json, :json
37
+ package :obj_marshal_64, :marshal_64
38
+ end
39
+
40
+ class Testing < ActiveRecord::Base; end
41
+
42
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This script is modified from one written by Erik Kastner,
4
+ # and a blog describing it's needs and usage can be found at
5
+ # http://metaatem.net/2007/04/20/fun-with-active_record-and-sqlite3
6
+ #
7
+ # It can be used for hands on quick and dirty testing to see how the library
8
+ # is working in an established class in IRB. It will open an IRB console with
9
+ # the database as specified below, plus the classes defined
10
+ #
11
+ # This file must be executable to work: [sudo] chmod 775 irb_tester.rb
12
+ #
13
+
14
+ require 'rubygems'
15
+ require 'active_record'
16
+ require 'sqlite3'
17
+ require 'irb'
18
+ require 'ruby-debug'
19
+
20
+ File.delete("irb_test.db") if File.file?("irb_test.db")
21
+
22
+ require File.dirname(__FILE__) + '/../lib/ar_object_pack/object_packer'
23
+ ActiveRecord::Base.send(:extend, ArObjectPack::ObjectPackager::ActiveRecordMethods)
24
+
25
+ require File.dirname(__FILE__) + "/database_spec_setup"
26
+ include DatabaseSpecSetup
27
+
28
+ IRB.start if __FILE__ == $0
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --backtrace
@@ -0,0 +1 @@
1
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rughetto-ar_object_pack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Rue The Ghetto
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-05 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: active_record
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: "0"
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: json
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: "0"
32
+ version:
33
+ description: "ActiveRecord plugin originally designed for Merb use that allows the packaging of objects into formats: marshal, json and yaml."
34
+ email: ru_ghetto@rubyghetto.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - README
41
+ - LICENSE
42
+ - TODO
43
+ files:
44
+ - LICENSE
45
+ - README
46
+ - Rakefile
47
+ - TODO
48
+ - lib/ar_object_pack
49
+ - lib/ar_object_pack/object_packer.rb
50
+ - lib/ar_object_pack.rb
51
+ - spec/ar_object_pack_spec.rb
52
+ - spec/database_spec_setup.rb
53
+ - spec/dbs
54
+ - spec/irb_tester.rb
55
+ - spec/spec.opts
56
+ - spec/spec_helper.rb
57
+ has_rdoc: true
58
+ homepage: http://github.com/ru_ghetto/ar_object_pack
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ requirements: []
77
+
78
+ rubyforge_project: merb
79
+ rubygems_version: 1.2.0
80
+ signing_key:
81
+ specification_version: 2
82
+ summary: "ActiveRecord plugin originally designed for Merb use that allows the packaging of objects into formats: marshal, json and yaml."
83
+ test_files: []
84
+