portable-hole 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
3
+
data/Gemfile.lock ADDED
@@ -0,0 +1,91 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ portable-hole (0.0.1)
5
+ rails (>= 3.1.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ actionmailer (3.2.6)
11
+ actionpack (= 3.2.6)
12
+ mail (~> 2.4.4)
13
+ actionpack (3.2.6)
14
+ activemodel (= 3.2.6)
15
+ activesupport (= 3.2.6)
16
+ builder (~> 3.0.0)
17
+ erubis (~> 2.7.0)
18
+ journey (~> 1.0.1)
19
+ rack (~> 1.4.0)
20
+ rack-cache (~> 1.2)
21
+ rack-test (~> 0.6.1)
22
+ sprockets (~> 2.1.3)
23
+ activemodel (3.2.6)
24
+ activesupport (= 3.2.6)
25
+ builder (~> 3.0.0)
26
+ activerecord (3.2.6)
27
+ activemodel (= 3.2.6)
28
+ activesupport (= 3.2.6)
29
+ arel (~> 3.0.2)
30
+ tzinfo (~> 0.3.29)
31
+ activeresource (3.2.6)
32
+ activemodel (= 3.2.6)
33
+ activesupport (= 3.2.6)
34
+ activesupport (3.2.6)
35
+ i18n (~> 0.6)
36
+ multi_json (~> 1.0)
37
+ arel (3.0.2)
38
+ builder (3.0.0)
39
+ erubis (2.7.0)
40
+ hike (1.2.1)
41
+ i18n (0.6.0)
42
+ journey (1.0.4)
43
+ json (1.7.3)
44
+ mail (2.4.4)
45
+ i18n (>= 0.4.0)
46
+ mime-types (~> 1.16)
47
+ treetop (~> 1.4.8)
48
+ mime-types (1.19)
49
+ multi_json (1.3.6)
50
+ polyglot (0.3.3)
51
+ rack (1.4.1)
52
+ rack-cache (1.2)
53
+ rack (>= 0.4)
54
+ rack-ssl (1.3.2)
55
+ rack
56
+ rack-test (0.6.1)
57
+ rack (>= 1.0)
58
+ rails (3.2.6)
59
+ actionmailer (= 3.2.6)
60
+ actionpack (= 3.2.6)
61
+ activerecord (= 3.2.6)
62
+ activeresource (= 3.2.6)
63
+ activesupport (= 3.2.6)
64
+ bundler (~> 1.0)
65
+ railties (= 3.2.6)
66
+ railties (3.2.6)
67
+ actionpack (= 3.2.6)
68
+ activesupport (= 3.2.6)
69
+ rack-ssl (~> 1.3.2)
70
+ rake (>= 0.8.7)
71
+ rdoc (~> 3.4)
72
+ thor (>= 0.14.6, < 2.0)
73
+ rake (0.9.2.2)
74
+ rdoc (3.12)
75
+ json (~> 1.4)
76
+ sprockets (2.1.3)
77
+ hike (~> 1.2)
78
+ rack (~> 1.0)
79
+ tilt (~> 1.1, != 1.3.0)
80
+ thor (0.15.4)
81
+ tilt (1.3.3)
82
+ treetop (1.4.10)
83
+ polyglot
84
+ polyglot (>= 0.3.1)
85
+ tzinfo (0.3.33)
86
+
87
+ PLATFORMS
88
+ ruby
89
+
90
+ DEPENDENCIES
91
+ portable-hole!
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Lantirn, Inc
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,4 @@
1
+ Portable Hole
2
+ =============
3
+
4
+ Portable Hole is an extension to ActiveRecord that adds EAV functionality to a model via a polymorphic association with an EAV table.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the gem'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'PortableHole'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
@@ -0,0 +1,50 @@
1
+ module Reamaze
2
+ module PortableHole
3
+ module AssociationExtensions
4
+ def save
5
+ do_save(false)
6
+ end
7
+
8
+ def save!
9
+ do_save(true)
10
+ end
11
+
12
+ def []=(name, value)
13
+ @association.owner.set_preferential(@association.reflection.name, name, value)
14
+ end
15
+
16
+ def [](name)
17
+ @association.owner.get_preferential(@association.reflection.name, name)
18
+ end
19
+
20
+ def valid?
21
+ valid = true
22
+ proxy_target.each do |thing|
23
+ thing.model_cache = @association.owner
24
+ unless thing.valid?
25
+ thing.errors.each{ |attr, msg| @association.owner.errors.add(@association.reflection.name, msg) }
26
+ valid = false
27
+ end
28
+ end
29
+ valid
30
+ end
31
+
32
+ # Private Methods
33
+ private
34
+ def do_save(with_bang)
35
+ success = true
36
+ proxy_target.each do |thing|
37
+ thing.model_cache = @association.owner
38
+ if with_bang
39
+ thing.save!
40
+ elsif thing.save == false
41
+ # Delegate the errors to the proxy owner
42
+ thing.errors.each { |attr,msg| @association.owner.errors.add(@association.reflection.name, msg) }
43
+ success = false
44
+ end
45
+ end
46
+ success
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,29 @@
1
+ module Reamaze
2
+ module PortableHole
3
+ class PrefHash < Hash
4
+ def initialize(owner, preferential)
5
+ @owner = owner
6
+ @preferential = preferential
7
+ end
8
+
9
+ def [] key
10
+ @owner.get_preferential @preferential, key.to_s, true
11
+ end
12
+
13
+ def []= key, value
14
+ @owner.set_preferential @preferential, key.to_s, value, true
15
+ super key.to_s, value
16
+ end
17
+
18
+ def method_missing(id, *args, &block)
19
+ match = /(.+)=$/.match id.to_s
20
+ return self[match[1]] = args[0] if match
21
+
22
+ match = /(.+)\?$/.match id.to_s
23
+ return !!self[match[1]] if match
24
+
25
+ self[id]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ module Reamaze
2
+ module PortableHole
3
+ module Helpers
4
+ # Converts give symbol to string and downcases it
5
+ def self.normalize(symbol)
6
+ symbol.to_s.downcase
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,126 @@
1
+ require 'portable-hole/helpers'
2
+ require 'portable-hole/association_extensions'
3
+ require 'portable-hole/hash'
4
+ require 'portable-value'
5
+
6
+ module Reamaze
7
+ module PortableHole
8
+ def self.included(base)
9
+ base.send :extend, ClassMethods
10
+ end
11
+
12
+ # Make methods available to ActiveRecord in the class context
13
+ module ClassMethods
14
+ def portable_hole(eav = :data, options = {})
15
+ send :include, InstanceMethods
16
+
17
+ eav = Helpers.normalize(eav)
18
+
19
+ # Create accessor methods to our configuration info
20
+ class << self
21
+ attr_accessor :eav_configuration unless method_defined?(:eav_configuration)
22
+ end
23
+
24
+ # Initialize the configuration to an empty hash
25
+ self.eav_configuration = {} if self.eav_configuration.nil?
26
+
27
+ # Redefining a configuration once defined should not be allowed
28
+ raise ArgumentError, "#{self} class already has a portal_hole :#{eav} defined" if self.eav_configuration.has_key?(eav)
29
+
30
+ eav_configuration[eav] = options
31
+
32
+ class_eval <<-end_eval
33
+ # Define the has_many relationship
34
+ has_many :_#{eav}, :class_name => 'PortableValue',
35
+ :as => :model,
36
+ :conditions => {:context => '#{eav}'},
37
+ :extend => AssociationExtensions,
38
+ :inverse_of => :model,
39
+ :dependent => :destroy
40
+
41
+ accepts_nested_attributes_for :_#{eav}, :allow_destroy => true
42
+
43
+ def #{eav}
44
+ h = Reamaze::PortableHole::PrefHash.new self, "_#{eav}"
45
+ values = self._#{eav}
46
+ values.each do |v|
47
+ h[v.key] = v.value
48
+ end
49
+ h
50
+ end
51
+
52
+ def #{eav}=(hash)
53
+ array = []
54
+
55
+ deletables = self._#{eav}.reject {|x| hash.keys.include? x.key}
56
+
57
+ hash.each do |k, v|
58
+ current = self._#{eav}.detect {|x| x.key == k}
59
+ if current.present?
60
+ if v == '_destroy'
61
+ array << {:id => current.id, :key => k, :value => v, :_destroy => true}
62
+ else
63
+ array << {:id => current.id, :key => k, :value => v}
64
+ end
65
+ else
66
+ array << {:key => k, :value => v}
67
+ end
68
+ end
69
+
70
+ deletables.each do |x|
71
+ array << {:id => x.id, :_destroy => true}
72
+ end
73
+
74
+ self._#{eav}_attributes = array
75
+ hash
76
+ end
77
+ end_eval
78
+ end
79
+ end
80
+
81
+ # Make methods available to ActiveRecord models in the instance context
82
+ module InstanceMethods
83
+ def set_preferential(preferential, name, value, do_preprocess = false)
84
+ preferential = Helpers.normalize(preferential)
85
+ name = Helpers.normalize(name)
86
+
87
+ # Invoke the association
88
+ prefs = send(preferential)
89
+
90
+ # If pref already exists, update it, otherwise add a new one
91
+ pref = prefs.detect { |pref| pref.key == name }
92
+
93
+ if pref.blank?
94
+ pref = prefs.build :key => name,
95
+ :value => value
96
+ else
97
+ pref.value = value
98
+ end
99
+
100
+ pref.value
101
+ end
102
+
103
+ def get_preferential(preferential, name, do_postprocess = false)
104
+ preferential = Helpers.normalize(preferential)
105
+ name = Helpers.normalize(name)
106
+
107
+ # Invoke the association
108
+ prefs = send(preferential)
109
+
110
+ # Try to find what they are looking for
111
+ pref = prefs.detect{ |pref| pref.key == name }
112
+
113
+ # If the pref isn't found, try to fallback on a default
114
+ if pref.blank?
115
+ value = nil
116
+ else
117
+ value = pref.value
118
+ end
119
+
120
+ value
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ ActiveRecord::Base.send :include, Reamaze::PortableHole
@@ -0,0 +1,15 @@
1
+ class PortableValue < ActiveRecord::Base
2
+ belongs_to :model, :polymorphic => true
3
+ belongs_to :group, :polymorphic => true
4
+
5
+ before_validation :set_group
6
+
7
+ def set_group
8
+ config = eval(self.model_type).eav_configuration
9
+ if config[self.context].present?
10
+ if config[self.context][:group].present?
11
+ self.group = model.send(config[self.context][:group])
12
+ end
13
+ end
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: portable-hole
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Lu Wang
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-07-16 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rails
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 3
31
+ - 1
32
+ - 0
33
+ version: 3.1.0
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ description:
37
+ email:
38
+ - lwang@reamaze.com
39
+ executables: []
40
+
41
+ extensions: []
42
+
43
+ extra_rdoc_files: []
44
+
45
+ files:
46
+ - lib/portable-hole/association_extensions.rb
47
+ - lib/portable-hole/hash.rb
48
+ - lib/portable-hole/helpers.rb
49
+ - lib/portable-hole.rb
50
+ - lib/portable-value.rb
51
+ - MIT-LICENSE
52
+ - README.md
53
+ - Gemfile
54
+ - Gemfile.lock
55
+ - Rakefile
56
+ homepage: http://github.com/lunaru/portable-hole
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ hash: 23
79
+ segments:
80
+ - 1
81
+ - 3
82
+ - 6
83
+ version: 1.3.6
84
+ requirements: []
85
+
86
+ rubyforge_project:
87
+ rubygems_version: 1.8.10
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Portable Hole is an extension to ActiveRecord that adds EAV functionality to a model via a polymorphic association with an EAV table.
91
+ test_files: []
92
+