cassiano-cassiano-model_lookup 0.1.5
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/README.rdoc +83 -0
- data/Rakefile +14 -0
- data/cassiano-model_lookup.gemspec +29 -0
- data/init.rb +25 -0
- data/lib/model_lookup.rb +227 -0
- metadata +65 -0
data/README.rdoc
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
= ModelLookup
|
2
|
+
|
3
|
+
Rails gem that implements the notion of a virtual (transient) lookup table inside Active Record (AR), allowing for the creation of belongs_to and has_many associations between these and physical (persistent) AR entities.
|
4
|
+
|
5
|
+
|
6
|
+
== Install
|
7
|
+
|
8
|
+
gem install cassiano-model_lookup --source http://gems.github.com
|
9
|
+
|
10
|
+
|
11
|
+
== Usage
|
12
|
+
|
13
|
+
Let's assume we want to map the 1 x N association between (US) _States_ and _Customers_:
|
14
|
+
|
15
|
+
class State < ModelLookup
|
16
|
+
set_domain_values [
|
17
|
+
# :id :name
|
18
|
+
# ---- --------------
|
19
|
+
[ 'CA', 'California' ],
|
20
|
+
[ 'FL', 'Florida' ],
|
21
|
+
[ 'GA', 'Georgia' ],
|
22
|
+
...
|
23
|
+
]
|
24
|
+
|
25
|
+
model_lookup_has_many :customers
|
26
|
+
end
|
27
|
+
|
28
|
+
class Customer < ActiveRecord::Base
|
29
|
+
model_lookup_belongs_to :state
|
30
|
+
has_many :contacts
|
31
|
+
|
32
|
+
validates_presence_of :name, :city, :state
|
33
|
+
end
|
34
|
+
|
35
|
+
Now you can do things such as:
|
36
|
+
|
37
|
+
c = Customer.create :name => 'West Inc', :city => 'San Jose', :state => State.find_by_id('CA')
|
38
|
+
=> #<Customer id: 1, name: "West Inc", city: "San Jose", state: "CA">
|
39
|
+
|
40
|
+
c.state
|
41
|
+
=> #<State:0x449ee14 @id="CA", @name="California">
|
42
|
+
|
43
|
+
c.state.name
|
44
|
+
=> "California"
|
45
|
+
|
46
|
+
c.state.id
|
47
|
+
=> "CA"
|
48
|
+
|
49
|
+
State.all
|
50
|
+
=> [#<State:0x449ee14 @id="CA", @name="California">, #<State:0x449ee15 @id="FL", @name="Florida">,
|
51
|
+
#<State:0x449ee16 @id="GA", @name="Georgia">]
|
52
|
+
|
53
|
+
s = State.first
|
54
|
+
=> #<State:0x449ee14 @id="CA", @name="California">
|
55
|
+
|
56
|
+
State.last
|
57
|
+
=> #<State:0x449ee16 @id="GA", @name="Georgia">
|
58
|
+
|
59
|
+
s.customers
|
60
|
+
=> [#<Customer id: 1, name: "West Inc", city: "San Jose", state: "CA">]
|
61
|
+
|
62
|
+
== License
|
63
|
+
|
64
|
+
Copyright (C) 2008 Tagview Tecnologia (Cassiano D'Andrea - cassiano.dandrea@tagview.com.br)
|
65
|
+
|
66
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
67
|
+
a copy of this software and associated documentation files (the
|
68
|
+
"Software"), to deal in the Software without restriction, including
|
69
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
70
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
71
|
+
permit persons to whom the Software is furnished to do so, subject to
|
72
|
+
the following conditions:
|
73
|
+
|
74
|
+
The above copyright notice and this permission notice shall be
|
75
|
+
included in all copies or substantial portions of the Software.
|
76
|
+
|
77
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
78
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
79
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
80
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
81
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
82
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
83
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('cassiano-model_lookup', '0.1.5') do |p|
|
6
|
+
p.description = "Implements the notion of a virtual (transient) lookup table inside Active Record (AR), allowing for the creation of belongs_to and has_many associations between these and physical (persistent) AR entities"
|
7
|
+
p.url = "http://github.com/cassiano/model_lookup"
|
8
|
+
p.author = "Cassiano D'Andrea"
|
9
|
+
p.email = "cassiano.dandrea@tagview.com.br"
|
10
|
+
p.ignore_pattern = ["tmp/*", "script/*"]
|
11
|
+
p.development_dependencies = []
|
12
|
+
end
|
13
|
+
|
14
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{cassiano-model_lookup}
|
3
|
+
s.version = "0.1.5"
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["Cassiano D'Andrea"]
|
7
|
+
s.date = %q{2008-11-13}
|
8
|
+
s.description = %q{Implements the notion of a virtual (transient) lookup table inside Active Record (AR), allowing for the creation of belongs_to and has_many associations between these and physical (persistent) AR entities}
|
9
|
+
s.email = %q{cassiano.dandrea@tagview.com.br}
|
10
|
+
s.extra_rdoc_files = ["lib/model_lookup.rb", "README.rdoc"]
|
11
|
+
s.files = ["cassiano-model_lookup.gemspec", "init.rb", "lib/model_lookup.rb", "Manifest", "model_lookup.gemspec", "Rakefile", "README.rdoc"]
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.homepage = %q{http://github.com/cassiano/model_lookup}
|
14
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Cassiano-model_lookup", "--main", "README.rdoc"]
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.rubyforge_project = %q{cassiano-model_lookup}
|
17
|
+
s.rubygems_version = %q{1.2.0}
|
18
|
+
s.summary = %q{Implements the notion of a virtual (transient) lookup table inside Active Record (AR), allowing for the creation of belongs_to and has_many associations between these and physical (persistent) AR entities}
|
19
|
+
|
20
|
+
if s.respond_to? :specification_version then
|
21
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
22
|
+
s.specification_version = 2
|
23
|
+
|
24
|
+
if current_version >= 3 then
|
25
|
+
else
|
26
|
+
end
|
27
|
+
else
|
28
|
+
end
|
29
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
################################################################################
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008 Tagview Tecnologia (Cassiano D'Andrea - cassiano.dandrea@tagview.com.br)
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
#
|
24
|
+
################################################################################
|
25
|
+
require 'model_lookup'
|
data/lib/model_lookup.rb
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
################################################################################
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008 Tagview Tecnologia (Cassiano D'Andrea - cassiano.dandrea@tagview.com.br)
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
# the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be
|
14
|
+
# included in all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
#
|
24
|
+
################################################################################
|
25
|
+
# Implements the notion of a virtual (transient) lookup table inside Active Record (AR), allowing for the creation of belongs_to and has_many
|
26
|
+
# associations between these and physical (persistent) AR entities.
|
27
|
+
class ModelLookup
|
28
|
+
################################################################################
|
29
|
+
attr_accessor :id, :name
|
30
|
+
|
31
|
+
################################################################################
|
32
|
+
def initialize(id, name)
|
33
|
+
@id = id
|
34
|
+
@name = name
|
35
|
+
end
|
36
|
+
|
37
|
+
################################################################################
|
38
|
+
def to_param
|
39
|
+
self.id
|
40
|
+
end
|
41
|
+
|
42
|
+
################################################################################
|
43
|
+
def ==(another_model_lookup_object)
|
44
|
+
self.id == another_model_lookup_object.id
|
45
|
+
end
|
46
|
+
|
47
|
+
################################################################################
|
48
|
+
# Class Methods
|
49
|
+
class << self
|
50
|
+
################################################################################
|
51
|
+
attr_writer :values
|
52
|
+
|
53
|
+
################################################################################
|
54
|
+
# Returns *all* instances of the model lookup table.
|
55
|
+
def all(options = {})
|
56
|
+
@all ||= {}
|
57
|
+
|
58
|
+
@all[options.inspect] ||=
|
59
|
+
returning(@values.map { |v| self.new *v }) do |collection|
|
60
|
+
if options[:order]
|
61
|
+
sort_attr, sort_dir = options[:order].to_s.split
|
62
|
+
|
63
|
+
asc = !sort_dir || sort_dir.downcase.to_sym == :asc
|
64
|
+
|
65
|
+
collection.sort! { |a, b| (asc ? a : b).__send__(sort_attr) <=> (asc ? b : a).__send__(sort_attr) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
################################################################################
|
71
|
+
# Returns the *first* instance of a model lookup table.
|
72
|
+
def first(options = {})
|
73
|
+
self.all(options).first
|
74
|
+
end
|
75
|
+
|
76
|
+
################################################################################
|
77
|
+
# Returns the *last* instance of a model lookup table.
|
78
|
+
def last(options = {})
|
79
|
+
self.all(options).last
|
80
|
+
end
|
81
|
+
|
82
|
+
################################################################################
|
83
|
+
# Finds a model lookup instance with a given ID. Throws _ActiveRecord::RecordNotFound_ if not found.
|
84
|
+
def find(param)
|
85
|
+
self.all.find { |v| v.to_param == param } || raise(ActiveRecord::RecordNotFound)
|
86
|
+
end
|
87
|
+
|
88
|
+
################################################################################
|
89
|
+
# Finds a model lookup instance with a given ID. Returns nil if not found.
|
90
|
+
def find_by_id(id)
|
91
|
+
self.all.find { |v| v.id == id }
|
92
|
+
end
|
93
|
+
|
94
|
+
################################################################################
|
95
|
+
# Finds a model lookup instance with a given name. Returns nil if not found.
|
96
|
+
def find_by_name(name)
|
97
|
+
self.all.find { |v| v.name == name }
|
98
|
+
end
|
99
|
+
|
100
|
+
################################################################################
|
101
|
+
# Returns a count/size of all model lookup instances.
|
102
|
+
def count
|
103
|
+
self.all.size
|
104
|
+
end
|
105
|
+
|
106
|
+
################################################################################
|
107
|
+
def model_lookup_has_many(association_id, options = {})
|
108
|
+
begin
|
109
|
+
options.reverse_merge!(
|
110
|
+
:class_name => association_id.to_s.classify.constantize
|
111
|
+
)
|
112
|
+
rescue NameError
|
113
|
+
end
|
114
|
+
|
115
|
+
options[:class_name] = options[:class_name].to_s.constantize if !options[:class_name].is_a?(Class)
|
116
|
+
|
117
|
+
options.reverse_merge!(
|
118
|
+
:foreign_key => self.to_s.foreign_key,
|
119
|
+
:virtual_attribute => false
|
120
|
+
)
|
121
|
+
|
122
|
+
options.reverse_merge!(
|
123
|
+
:method => options[:foreign_key].to_s.sub(/_id$/, '').to_sym
|
124
|
+
)
|
125
|
+
|
126
|
+
define_method association_id do |*args|
|
127
|
+
finder_options = args[0] || {}
|
128
|
+
|
129
|
+
finder_options.reverse_merge!(
|
130
|
+
:order => options[:order],
|
131
|
+
:conditions => options[:conditions],
|
132
|
+
:limit => options[:limit]
|
133
|
+
)
|
134
|
+
|
135
|
+
this = self
|
136
|
+
|
137
|
+
options[:class_name].class_eval do
|
138
|
+
with_scope :find => finder_options do
|
139
|
+
if options[:virtual_attribute]
|
140
|
+
if options[:optimal_conditions]
|
141
|
+
self.all :conditions => options[:optimal_conditions].gsub('?', this.id)
|
142
|
+
else
|
143
|
+
self.all.select { |e| e.__send__(options[:foreign_key]) == this.id }
|
144
|
+
end
|
145
|
+
else
|
146
|
+
self.all :conditions => { options[:method] => this.id }
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
################################################################################
|
154
|
+
def find_for_lookup_select(options = {}, finder_options = {})
|
155
|
+
self.all finder_options
|
156
|
+
end
|
157
|
+
|
158
|
+
################################################################################
|
159
|
+
protected
|
160
|
+
|
161
|
+
################################################################################
|
162
|
+
def set_domain_values(values)
|
163
|
+
@values = values
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
################################################################################
|
169
|
+
module ModelLookupAssociations
|
170
|
+
################################################################################
|
171
|
+
def self.included(base)
|
172
|
+
base.extend ClassMethods
|
173
|
+
end
|
174
|
+
|
175
|
+
################################################################################
|
176
|
+
module ClassMethods
|
177
|
+
################################################################################
|
178
|
+
def model_lookup_belongs_to(association_id, options = {})
|
179
|
+
begin
|
180
|
+
options.reverse_merge!(
|
181
|
+
:class_name => association_id.to_s.classify.constantize
|
182
|
+
)
|
183
|
+
rescue NameError
|
184
|
+
end
|
185
|
+
|
186
|
+
options[:class_name] = options[:class_name].to_s.constantize if !options[:class_name].is_a?(Class)
|
187
|
+
|
188
|
+
options.reverse_merge!(
|
189
|
+
:foreign_key => association_id.to_s.foreign_key
|
190
|
+
)
|
191
|
+
|
192
|
+
options.reverse_merge!(
|
193
|
+
:method => options[:foreign_key].to_s.sub(/_id$/, '').to_sym
|
194
|
+
)
|
195
|
+
|
196
|
+
# Include "referential integrity" validation.
|
197
|
+
self.validates_inclusion_of "#{association_id}_id", :in => options[:class_name].all.map(&:id), :allow_blank => true
|
198
|
+
|
199
|
+
# Define the getter (making it behave like if it were a proxy association).
|
200
|
+
define_method association_id do
|
201
|
+
association_value = self.__send__ "#{association_id}_id"
|
202
|
+
options[:class_name].find_by_id(association_value) if !association_value.blank?
|
203
|
+
end
|
204
|
+
|
205
|
+
# Define the setter.
|
206
|
+
define_method "#{association_id}=" do |new_association_id|
|
207
|
+
self.__send__ "#{association_id}_id=", new_association_id.to_param
|
208
|
+
end
|
209
|
+
|
210
|
+
# Define the "foreign key" getter.
|
211
|
+
define_method "#{association_id}_id" do
|
212
|
+
self.read_attribute options[:method]
|
213
|
+
end
|
214
|
+
|
215
|
+
# Define the "foreign key" setter.
|
216
|
+
define_method "#{association_id}_id=" do |new_id|
|
217
|
+
self.write_attribute options[:method], new_id
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
################################################################################
|
224
|
+
class ActiveRecord::Base
|
225
|
+
################################################################################
|
226
|
+
include ModelLookupAssociations
|
227
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cassiano-cassiano-model_lookup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cassiano D'Andrea
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-11-13 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Implements the notion of a virtual (transient) lookup table inside Active Record (AR), allowing for the creation of belongs_to and has_many associations between these and physical (persistent) AR entities
|
17
|
+
email: cassiano.dandrea@tagview.com.br
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- lib/model_lookup.rb
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- cassiano-model_lookup.gemspec
|
27
|
+
- init.rb
|
28
|
+
- lib/model_lookup.rb
|
29
|
+
- Manifest
|
30
|
+
- model_lookup.gemspec
|
31
|
+
- Rakefile
|
32
|
+
- README.rdoc
|
33
|
+
has_rdoc: true
|
34
|
+
homepage: http://github.com/cassiano/model_lookup
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options:
|
37
|
+
- --line-numbers
|
38
|
+
- --inline-source
|
39
|
+
- --title
|
40
|
+
- Cassiano-model_lookup
|
41
|
+
- --main
|
42
|
+
- README.rdoc
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "1.2"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project: cassiano-model_lookup
|
60
|
+
rubygems_version: 1.2.0
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: Implements the notion of a virtual (transient) lookup table inside Active Record (AR), allowing for the creation of belongs_to and has_many associations between these and physical (persistent) AR entities
|
64
|
+
test_files: []
|
65
|
+
|