jackdempsey-sequel_polymorphic 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) 2008 Jack Dempsey
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,112 @@
1
+ Sequel Polymorphic
2
+ ==================
3
+
4
+ A simple plugin for Sequel::Model's that lets you easily create polymorphic associations.
5
+
6
+ ActiveRecord Style
7
+ ------------------
8
+
9
+ class Asset < ActiveRecord::Base
10
+ belongs_to :attachable, :polymorphic => true
11
+ end
12
+
13
+ class Post < ActiveRecord::Base
14
+ has_many :assets, :as => :attachable
15
+ end
16
+
17
+ class Note < ActiveRecord::Base
18
+ has_many :assets, :as => :attachable
19
+ end
20
+
21
+ @asset.attachable = @post
22
+ @asset.attachable = @note
23
+
24
+ In Sequel you would do the following:
25
+
26
+ class Asset < Sequel::Model
27
+ many_to_one :attachable, :reciprocal=>:assets, \
28
+ :dataset=>(proc do
29
+ klass = attachable_type.constantize
30
+ klass.filter(klass.primary_key=>attachable_id)
31
+ end), \
32
+ :eager_loader=>(proc do |key_hash, assets, associations|
33
+ id_map = {}
34
+ assets.each do |asset|
35
+ asset.associations[:attachable] = nil
36
+ ((id_map[asset.attachable_type] ||= {})[asset.attachable_id] ||= []) << asset
37
+ end
38
+ id_map.each do |klass_name, id_map|
39
+ klass = klass_name.constantize
40
+ klass.filter(klass.primary_key=>id_map.keys).all do |attach|
41
+ id_map[attach.pk].each do |asset|
42
+ asset.associations[:attachable] = attach
43
+ end
44
+ end
45
+ end
46
+ end)
47
+
48
+ private
49
+
50
+ def _attachable=(attachable)
51
+ self[:attachable_id] = (attachable.pk if attachable)
52
+ self[:attachable_type] = (attachable.class.name if attachable)
53
+ end
54
+ end
55
+
56
+ class Post < Sequel::Model
57
+ one_to_many :assets, :key=>:attachable_id do |ds|
58
+ ds.filter(:attachable_type=>'Post')
59
+ end
60
+
61
+ private
62
+
63
+ def _add_asset(asset)
64
+ asset.attachable_id = pk
65
+ asset.attachable_type = 'Post'
66
+ asset.save
67
+ end
68
+ def _remove_asset(asset)
69
+ asset.attachable_id = nil
70
+ asset.attachable_type = nil
71
+ asset.save
72
+ end
73
+ def _remove_all_assets
74
+ Asset.filter(:attachable_id=>pk, :attachable_type=>'Post')\
75
+ .update(:attachable_id=>nil, :attachable_type=>nil)
76
+ end
77
+ end
78
+
79
+ class Note < Sequel::Model
80
+ one_to_many :assets, :key=>:attachable_id do |ds|
81
+ ds.filter(:attachable_type=>'Note')
82
+ end
83
+
84
+ private
85
+
86
+ def _add_asset(asset)
87
+ asset.attachable_id = pk
88
+ asset.attachable_type = 'Note'
89
+ asset.save
90
+ end
91
+ def _remove_asset(asset)
92
+ asset.attachable_id = nil
93
+ asset.attachable_type = nil
94
+ asset.save
95
+ end
96
+ def _remove_all_assets
97
+ Asset.filter(:attachable_id=>pk, :attachable_type=>'Note')\
98
+ .update(:attachable_id=>nil, :attachable_type=>nil)
99
+ end
100
+ end
101
+
102
+ @asset.attachable = @post
103
+ @asset.attachable = @note
104
+
105
+
106
+ Thats quite a bit of code. With sequel_polymorphic you can now do:
107
+
108
+ class Note < Sequel::Model
109
+ is :polymorphic, :as => :attachable
110
+ end
111
+
112
+ voila!
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'date'
5
+ require 'spec/rake/spectask'
6
+
7
+ GEM = "sequel_polymorphic"
8
+ GEM_VERSION = "0.0.1"
9
+ AUTHOR = "Jack Dempsey"
10
+ EMAIL = "jack.dempsey@gmail.com"
11
+ HOMEPAGE = "http://jackndempsey.blogspot.com"
12
+ SUMMARY = "A gem that provides Sequel::Models with polymorphic association capabilities"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = GEM
16
+ s.version = GEM_VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.has_rdoc = false
19
+ s.extra_rdoc_files = ["README", "LICENSE", 'TODO']
20
+ s.summary = SUMMARY
21
+ s.description = s.summary
22
+ s.author = AUTHOR
23
+ s.email = EMAIL
24
+ s.homepage = HOMEPAGE
25
+
26
+ # Uncomment this to add a dependency
27
+ # s.add_dependency "foo"
28
+
29
+ s.require_path = 'lib'
30
+ s.autorequire = GEM
31
+ s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
32
+ end
33
+
34
+ task :default => :spec
35
+
36
+ desc "Run specs"
37
+ Spec::Rake::SpecTask.new do |t|
38
+ t.spec_files = FileList['spec/**/*_spec.rb']
39
+ t.spec_opts = %w(-fs --color)
40
+ end
41
+
42
+
43
+ Rake::GemPackageTask.new(spec) do |pkg|
44
+ pkg.gem_spec = spec
45
+ end
46
+
47
+ desc "install the gem locally"
48
+ task :install => [:package] do
49
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
50
+ end
51
+
52
+ desc "create a gemspec file"
53
+ task :make_spec do
54
+ File.open("#{GEM}.gemspec", "w") do |file|
55
+ file.puts spec.to_ruby
56
+ end
57
+ end
data/TODO ADDED
@@ -0,0 +1 @@
1
+ Add support for many_to_many polymorphic
@@ -0,0 +1,4 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'sequel_polymorphic/sequel_polymorphic'
@@ -0,0 +1,123 @@
1
+ module Sequel
2
+ module Plugins
3
+ module Polymorphic
4
+ # Apply the plugin to the model.
5
+ def self.apply(model, options = {})
6
+ end
7
+
8
+ module InstanceMethods
9
+
10
+ end
11
+
12
+ module ClassMethods
13
+ def many_to_one(*args, &block)
14
+ able, options = *args
15
+ options ||= {}
16
+ if options[:polymorphic]
17
+ model = self.class.to_s.downcase
18
+ plural_model = model.pluralize
19
+ singular_model = model.singularize
20
+ self.class_eval %{
21
+ associate(:many_to_one, :#{able}, :reciprocal=>:#{plural_model},
22
+ :dataset=>(proc { klass = #{able}_type.constantize; klass.filter(klass.primary_key=>#{able}_id) }),
23
+ :eager_loader=>(proc do |key_hash, #{plural_model}, associations|
24
+ id_map = {}
25
+ #{plural_model}.each do |#{singular_model}|
26
+ #{singular_model}.associations[:#{able}] = nil;
27
+ ((id_map[#{singular_model}.#{able}_type] ||= {})[#{singular_model}.#{able}_id] ||= []) << #{singular_model}
28
+ end
29
+ id_map.each do |klass_name, id_map|
30
+ klass = klass_name.constantize
31
+ klass.filter(klass.primary_key=>id_map.keys).all do |related_obj|
32
+ id_map[related_obj.pk].each { |#{singular_model}| #{singular_model}.associations[:#{able}] = related_obj }
33
+ end
34
+ end
35
+ end)
36
+ )
37
+
38
+ private
39
+
40
+ def _#{able}=(#{able})
41
+ self[:#{able}_id] = (#{able}.pk if #{able})
42
+ self[:#{able}_type] = (#{able}.class.name if #{able})
43
+ end
44
+ }
45
+ else
46
+ associate(:many_to_one, *args, &block)
47
+ end
48
+ end
49
+
50
+ alias :belongs_to :many_to_one
51
+
52
+ def one_to_many(*args, &block)
53
+ many_of_class, options = *args
54
+ options ||= {}
55
+ many_class = many_of_class.to_s.singularize
56
+ if able = options[:as]
57
+ associate(:one_to_many, many_of_class, :key=>"#{able}_id".to_sym) do |ds|
58
+ ds.filter("#{able}_type".to_sym => self.class.to_s)
59
+ end
60
+
61
+ method_definitions = %{
62
+ private
63
+
64
+ def _add_#{many_class}(#{many_class})
65
+ #{many_class}.#{able}_id = pk
66
+ #{many_class}.#{able}_type = '#{self}'
67
+ #{many_class}.save
68
+ end
69
+ def _remove_#{many_class}(#{many_class})
70
+ #{many_class}.#{able}_id = nil
71
+ #{many_class}.#{able}_type = nil
72
+ #{many_class}.save
73
+ end
74
+ def _remove_all_#{many_of_class}
75
+ #{many_class.capitalize}.filter(:#{able}_id=>pk, :#{able}_type=>'#{self}').update(:#{able}_id=>nil, :#{able}_type=>nil)
76
+ end
77
+ }
78
+ self.class_eval method_definitions
79
+ else
80
+ associate(:one_to_many, *args, &block)
81
+ end
82
+ end
83
+
84
+ alias :has_many :one_to_many
85
+
86
+ #example: many_to_many :tags, :through => :taggings, :as => :taggable
87
+ def many_to_many(*args, &block)
88
+ many_to_class, options = *args # => :tags, :through => :taggings, :as => :taggable
89
+ many_class = many_to_class.to_s.singularize # => tag
90
+ options ||= {}
91
+ if through = (options[:through] or options[:join_table]) and able = options[:as]
92
+ through_klass = through.to_s.singularize.capitalize # => Tagging
93
+ # self in the block passed to associate is an instance of the class, hence the self.class call
94
+ associate(:many_to_many, many_to_class,
95
+ :left_key => "#{able}_id".to_sym,
96
+ :join_table => through) { |ds| ds.filter("#{able}_type".to_sym => self.class.to_s) }
97
+
98
+ method_string = %{
99
+ private
100
+
101
+ def _add_#{many_class}(#{many_class})
102
+ #{through_klass}.create(:#{many_class}_id => #{many_class}.pk, :#{able}_id => pk, :#{able}_type => '#{self}')
103
+ end
104
+
105
+ def _remove_#{many_class}(#{many_class})
106
+ #{through_klass}.filter(:#{many_class}_id => #{many_class}.pk, :#{able}_id => pk, :#{able}_type => '#{self}').delete
107
+ end
108
+
109
+ def _remove_all_#{many_to_class}
110
+ #{through_klass}.filter(:#{able}_id=>pk, :#{able}_type=>'#{self}').delete
111
+ end
112
+ }
113
+ self.class_eval method_string
114
+ else
115
+ associate(:many_to_many, *args, &block)
116
+ end
117
+ end
118
+ end # ClassMethods
119
+ end # Polymorphic
120
+ end # Plugins
121
+ end # Sequel
122
+
123
+
@@ -0,0 +1,36 @@
1
+ DB = Sequel.sqlite
2
+
3
+ class Asset < Sequel::Model
4
+ set_schema do
5
+ primary_key :id
6
+ varchar :name
7
+ integer :attachable_id
8
+ varchar :attachable_type
9
+ end
10
+
11
+ is :polymorphic, :belongs_to => :attachable
12
+
13
+ end
14
+
15
+ class Post < Sequel::Model
16
+ set_schema do
17
+ primary_key :id
18
+ varchar :name
19
+ end
20
+
21
+ is :polymorphic, :has_many => :assets, :as => :attachable
22
+
23
+ end
24
+
25
+
26
+ class Note < Sequel::Model
27
+ set_schema do
28
+ primary_key :id
29
+ varchar :name
30
+ end
31
+
32
+ is :polymorphic, :has_many => :assets, :as => :attachable
33
+
34
+ end
35
+
36
+ [Asset, Post, Note].each {|klass| klass.create_table!}
@@ -0,0 +1,12 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ # Models we have: Post(name), Note(name), Asset(name)
4
+ describe Sequel::Plugins::Polymorphic do
5
+ it "should add :as to has_many/one_to_many" do
6
+
7
+ end
8
+
9
+ it "should add :polymorphic => true to belongs_to" do
10
+
11
+ end
12
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,12 @@
1
+ $TESTING=true
2
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
+
4
+ require 'rubygems'
5
+ require 'spec'
6
+ require 'sequel'
7
+
8
+ require File.dirname(__FILE__) + '/sequel-setup'
9
+ require File.dirname(__FILE__) + '/../lib/sequel_polymorphic'
10
+
11
+
12
+
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jackdempsey-sequel_polymorphic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jack Dempsey
8
+ autorequire: sequel_polymorphic
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-12-08 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: A gem that provides Sequel::Models with polymorphic association capabilities
17
+ email: jack.dempsey@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ - LICENSE
25
+ - TODO
26
+ files:
27
+ - LICENSE
28
+ - README
29
+ - Rakefile
30
+ - TODO
31
+ - lib/sequel_polymorphic
32
+ - lib/sequel_polymorphic/sequel_polymorphic.rb
33
+ - lib/sequel_polymorphic.rb
34
+ - spec/sequel-setup.rb
35
+ - spec/sequel_polymorphic
36
+ - spec/sequel_polymorphic/sequel_polymorphic_spec.rb
37
+ - spec/spec.opts
38
+ - spec/spec_helper.rb
39
+ has_rdoc: false
40
+ homepage: http://jackndempsey.blogspot.com
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.2.0
62
+ signing_key:
63
+ specification_version: 2
64
+ summary: A gem that provides Sequel::Models with polymorphic association capabilities
65
+ test_files: []
66
+