csun-student-affairs-supermodel 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/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ dump.db
2
+ test.rb
3
+ redis_test.rb
4
+ pkg
5
+ lib/supermodel/cassandra.rb
6
+ *.gem
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Alexander MacCaw (info@eribium.org)
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,64 @@
1
+
2
+ Simple in-memory database using ActiveModel.
3
+
4
+ Primarily developed for Bowline applications.
5
+ http://github.com/maccman/bowline
6
+
7
+ Supports:
8
+ * Serialisation
9
+ * Validations
10
+ * Callbacks
11
+ * Observers
12
+ * Dirty (Changes)
13
+ * Ruby Marshalling to disk
14
+ * Redis
15
+
16
+ Examples:
17
+
18
+ require "supermodel"
19
+
20
+ class Test < SuperModel::Base
21
+ end
22
+
23
+ t = Test.new
24
+ t.name = "foo"
25
+ t.save #=> true
26
+
27
+ Test.all
28
+ Test.first
29
+ Test.last
30
+ Test.find_by_name('foo)
31
+
32
+ You can use a random ID rather than the object ID:
33
+
34
+ class Test < SuperModel::Base
35
+ include SuperModel::RandomID
36
+ end
37
+
38
+ t = Test.create(:name => "test")
39
+ t.id #=> "7ee935377bb4aecc54ad4f9126"
40
+
41
+ You can marshal objects to disk on startup/shutdown
42
+
43
+ class Test < SuperModel::Base
44
+ include SuperModel::Marshal::Model
45
+ end
46
+
47
+ SuperModel::Marshal.path = "dump.db"
48
+ SuperModel::Marshal.load
49
+
50
+ at_exit {
51
+ SuperModel::Marshal.dump
52
+ }
53
+
54
+ You can use Redis, you need the Redis gem installed:
55
+
56
+ require "redis"
57
+ class Test < SuperModel::Base
58
+ include SuperModel::Redis::Model
59
+
60
+ attributes :name
61
+ indexes :name
62
+ end
63
+
64
+ Test.find_or_create_by_name("foo")
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "supermodel"
5
+ gemspec.summary = "In memory DB using ActiveModel"
6
+ gemspec.email = "info@eribium.org"
7
+ gemspec.homepage = "http://github.com/maccman/supermodel"
8
+ gemspec.description = "In memory DB using ActiveModel"
9
+ gemspec.authors = ["Alex MacCaw"]
10
+ gemspec.add_dependency("activemodel", "~> 3.0.0")
11
+ end
12
+ rescue LoadError
13
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
14
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.4
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), "supermodel")
data/lib/supermodel.rb ADDED
@@ -0,0 +1,42 @@
1
+ gem "activesupport"
2
+ gem "activemodel"
3
+
4
+ require "active_support/core_ext/class/attribute_accessors"
5
+ require "active_support/core_ext/class/inheritable_attributes"
6
+ require "active_support/core_ext/hash/indifferent_access"
7
+ require "active_support/core_ext/kernel/reporting"
8
+ require "active_support/core_ext/module/attr_accessor_with_default"
9
+ require "active_support/core_ext/module/delegation"
10
+ require "active_support/core_ext/module/aliasing"
11
+ require "active_support/core_ext/object/blank"
12
+ require "active_support/core_ext/object/try"
13
+ require "active_support/core_ext/object/to_query"
14
+ require "active_support/json"
15
+
16
+ require "active_model"
17
+
18
+ module SuperModel
19
+ class SuperModelError < StandardError; end
20
+ class UnknownRecord < SuperModelError; end
21
+ class InvalidRecord < SuperModelError; end
22
+ end
23
+
24
+ $:.unshift(File.dirname(__FILE__))
25
+ require "supermodel/ext/array"
26
+
27
+ module SuperModel
28
+ autoload :Association, "supermodel/association"
29
+ autoload :Callbacks, "supermodel/callbacks"
30
+ autoload :Observing, "supermodel/observing"
31
+ autoload :Marshal, "supermodel/marshal"
32
+ autoload :RandomID, "supermodel/random_id"
33
+ autoload :Timestamp, "supermodel/timestamp"
34
+ autoload :Validations, "supermodel/validations"
35
+ autoload :Dirty, "supermodel/dirty"
36
+ autoload :Redis, "supermodel/redis"
37
+ autoload :Base, "supermodel/base"
38
+ end
39
+
40
+ module ActiveModel
41
+ autoload :SerializeOptions, "active_model/serialize_options"
42
+ end
@@ -0,0 +1,51 @@
1
+ require "active_support/core_ext/string/inflections.rb"
2
+
3
+ module SuperModel
4
+ module Association
5
+ module ClassMethods
6
+ def belongs_to(to_model, options = {})
7
+ to_model = to_model.to_s
8
+ class_name = options[:class_name] || to_model.classify
9
+ foreign_key = options[:foreign_key] || "#{to_model}_id"
10
+ primary_key = options[:primary_key] || "id"
11
+
12
+ attributes foreign_key
13
+
14
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
15
+ def #{to_model} # def user
16
+ #{foreign_key} && #{class_name}.find(#{foreign_key}) # user_id && User.find(user_id)
17
+ end # end
18
+ #
19
+ def #{to_model}? # def user?
20
+ #{foreign_key} && #{class_name}.exists?(#{foreign_key}) # user_id && User.exists?(user_id)
21
+ end # end
22
+ #
23
+ def #{to_model}=(object) # def user=(model)
24
+ self.#{foreign_key} = (object && object.#{primary_key}) # self.user_id = (model && model.id)
25
+ end # end
26
+ EOS
27
+ end
28
+
29
+ def has_many(to_model, options = {})
30
+ to_model = to_model.to_s
31
+ class_name = options[:class_name] || to_model.classify
32
+ foreign_key = options[:foreign_key] || "#{model_name.singular}_id"
33
+ primary_key = options[:primary_key] || "id"
34
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
35
+ def #{to_model} # def user
36
+ #{class_name}.find_all_by_attribute( # User.find_all_by_attribute(
37
+ :#{foreign_key}, # :task_id,
38
+ #{primary_key} # id
39
+ ) # )
40
+ end # end
41
+ EOS
42
+ end
43
+ end
44
+
45
+ module Model
46
+ def self.included(base)
47
+ base.extend(ClassMethods)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,309 @@
1
+ module SuperModel
2
+ class Base
3
+ class_inheritable_array :known_attributes
4
+ self.known_attributes = []
5
+
6
+ class << self
7
+ attr_accessor_with_default(:primary_key, 'id') #:nodoc:
8
+
9
+ def collection(&block)
10
+ @collection ||= Class.new(Array)
11
+ @collection.class_eval(&block) if block_given?
12
+ @collection
13
+ end
14
+
15
+ def attributes(*attributes)
16
+ self.known_attributes += attributes.map(&:to_s)
17
+ end
18
+
19
+ def records
20
+ @records ||= {}
21
+ end
22
+
23
+ def find_by_attribute(name, value) #:nodoc:
24
+ item = records.values.find {|r| r.send(name) == value }
25
+ item && item.dup
26
+ end
27
+
28
+ def find_all_by_attribute(name, value) #:nodoc:
29
+ items = records.values.select {|r| r.send(name) == value }
30
+ collection.new(items.deep_dup)
31
+ end
32
+
33
+ def raw_find(id) #:nodoc:
34
+ records[id] || raise(UnknownRecord, "Couldn't find #{self.name} with ID=#{id}")
35
+ end
36
+
37
+ # Find record by ID, or raise.
38
+ def find(id)
39
+ item = raw_find(id)
40
+ item && item.dup
41
+ end
42
+ alias :[] :find
43
+
44
+ def first
45
+ item = records.values[0]
46
+ item && item.dup
47
+ end
48
+
49
+ def last
50
+ item = records.values[-1]
51
+ item && item.dup
52
+ end
53
+
54
+ def exists?(id)
55
+ records.has_key?(id)
56
+ end
57
+
58
+ def count
59
+ records.length
60
+ end
61
+
62
+ def all
63
+ collection.new(records.values.deep_dup)
64
+ end
65
+
66
+ def select(&block)
67
+ collection.new(records.values.select(&block).deep_dup)
68
+ end
69
+
70
+ def update(id, atts)
71
+ find(id).update_attributes(atts)
72
+ end
73
+
74
+ def destroy(id)
75
+ find(id).destroy
76
+ end
77
+
78
+ # Removes all records and executes
79
+ # destory callbacks.
80
+ def destroy_all
81
+ all.each {|r| r.destroy }
82
+ end
83
+
84
+ # Removes all records without executing
85
+ # destroy callbacks.
86
+ def delete_all
87
+ records.clear
88
+ end
89
+
90
+ # Create a new record.
91
+ # Example:
92
+ # create(:name => "foo", :id => 1)
93
+ def create(atts = {})
94
+ rec = self.new(atts)
95
+ rec.save && rec
96
+ end
97
+
98
+ def create!(*args)
99
+ create(*args) || raise(InvalidRecord)
100
+ end
101
+
102
+ def method_missing(method_symbol, *args) #:nodoc:
103
+ method_name = method_symbol.to_s
104
+
105
+ if method_name =~ /^find_by_(\w+)!/
106
+ send("find_by_#{$1}", *args) || raise(UnknownRecord)
107
+ elsif method_name =~ /^find_by_(\w+)/
108
+ find_by_attribute($1, args.first)
109
+ elsif method_name =~ /^find_or_create_by_(\w+)/
110
+ send("find_by_#{$1}", *args) || create($1 => args.first)
111
+ elsif method_name =~ /^find_all_by_(\w+)/
112
+ find_all_by_attribute($1, args.first)
113
+ else
114
+ super
115
+ end
116
+ end
117
+ end
118
+
119
+ attr_accessor :attributes
120
+ attr_writer :new_record
121
+
122
+ def known_attributes
123
+ self.class.known_attributes + self.attributes.keys.map(&:to_s)
124
+ end
125
+
126
+ def initialize(attributes = {})
127
+ @new_record = true
128
+ @attributes = {}.with_indifferent_access
129
+ @attributes.merge!(known_attributes.inject({}) {|h, n| h[n] = nil; h })
130
+ @changed_attributes = {}
131
+ load(attributes)
132
+ end
133
+
134
+ def clone
135
+ cloned = attributes.reject {|k,v| k == self.class.primary_key }
136
+ cloned = cloned.inject({}) do |attrs, (k, v)|
137
+ attrs[k] = v.clone
138
+ attrs
139
+ end
140
+ self.class.new(cloned)
141
+ end
142
+
143
+ def new?
144
+ @new_record || false
145
+ end
146
+ alias :new_record? :new?
147
+
148
+ # Gets the <tt>\id</tt> attribute of the item.
149
+ def id
150
+ attributes[self.class.primary_key]
151
+ end
152
+
153
+ # Sets the <tt>\id</tt> attribute of the item.
154
+ def id=(id)
155
+ attributes[self.class.primary_key] = id
156
+ end
157
+
158
+ def ==(other)
159
+ other.equal?(self) || (other.instance_of?(self.class) && other.id == id)
160
+ end
161
+
162
+ # Tests for equality (delegates to ==).
163
+ def eql?(other)
164
+ self == other
165
+ end
166
+
167
+ def hash
168
+ id.hash
169
+ end
170
+
171
+ def dup
172
+ self.class.new.tap do |base|
173
+ base.attributes = attributes
174
+ base.new_record = new_record?
175
+ end
176
+ end
177
+
178
+ def save
179
+ new? ? create : update
180
+ end
181
+
182
+ def save!
183
+ save || raise(InvalidRecord)
184
+ end
185
+
186
+ def exists?
187
+ !new?
188
+ end
189
+ alias_method :persisted?, :exists?
190
+
191
+ def load(attributes) #:nodoc:
192
+ return unless attributes
193
+ attributes.each do |(name, value)|
194
+ self.send("#{name}=".to_sym, value)
195
+ end
196
+ end
197
+
198
+ def reload
199
+ return self if new?
200
+ item = self.class.find(id)
201
+ load(item.attributes)
202
+ return self
203
+ end
204
+
205
+ def update_attribute(name, value)
206
+ self.send("#{name}=".to_sym, value)
207
+ self.save
208
+ end
209
+
210
+ def update_attributes(attributes)
211
+ load(attributes) && save
212
+ end
213
+
214
+ def update_attributes!(attributes)
215
+ update_attributes(attributes) || raise(InvalidRecord)
216
+ end
217
+
218
+ def has_attribute?(name)
219
+ @attributes.has_key?(name)
220
+ end
221
+
222
+ alias_method :respond_to_without_attributes?, :respond_to?
223
+
224
+ def respond_to?(method, include_priv = false)
225
+ method_name = method.to_s
226
+ if attributes.nil?
227
+ super
228
+ elsif known_attributes.include?(method_name)
229
+ true
230
+ elsif method_name =~ /(?:=|\?)$/ && attributes.include?($`)
231
+ true
232
+ else
233
+ super
234
+ end
235
+ end
236
+
237
+ def destroy
238
+ raw_destroy
239
+ self
240
+ end
241
+
242
+ protected
243
+ def read_attribute(name)
244
+ @attributes[name]
245
+ end
246
+
247
+ def write_attribute(name, value)
248
+ @attributes[name] = value
249
+ end
250
+
251
+ def generate_id
252
+ object_id
253
+ end
254
+
255
+ def raw_destroy
256
+ self.class.records.delete(self.id)
257
+ end
258
+
259
+ def raw_create
260
+ self.class.records[self.id] = self.dup
261
+ end
262
+
263
+ def create
264
+ self.id ||= generate_id
265
+ self.new_record = false
266
+ raw_create
267
+ self.id
268
+ end
269
+
270
+ def raw_update
271
+ item = self.class.raw_find(id)
272
+ item.load(attributes)
273
+ end
274
+
275
+ def update
276
+ raw_update
277
+ true
278
+ end
279
+
280
+ private
281
+
282
+ def method_missing(method_symbol, *arguments) #:nodoc:
283
+ method_name = method_symbol.to_s
284
+
285
+ if method_name =~ /(=|\?)$/
286
+ case $1
287
+ when "="
288
+ attribute_will_change!($`)
289
+ attributes[$`] = arguments.first
290
+ when "?"
291
+ attributes[$`]
292
+ end
293
+ else
294
+ return attributes[method_name] if attributes.include?(method_name)
295
+ return nil if known_attributes.include?(method_name)
296
+ super
297
+ end
298
+ end
299
+ end
300
+
301
+ class Base
302
+ extend ActiveModel::Naming
303
+ include ActiveModel::Conversion
304
+ include ActiveModel::Serializers::JSON
305
+ include ActiveModel::Serializers::Xml
306
+ include Dirty, Observing, Callbacks, Validations
307
+ include Association::Model
308
+ end
309
+ end
@@ -0,0 +1,23 @@
1
+ module SuperModel
2
+ module Callbacks
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ instance_eval do
7
+ extend ActiveModel::Callbacks
8
+ define_model_callbacks :create, :save, :update, :destroy
9
+ end
10
+
11
+ %w( create save update destroy ).each do |method|
12
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
13
+ def #{method}_with_callbacks(*args, &block)
14
+ _run_#{method}_callbacks do
15
+ #{method}_without_callbacks(*args, &block)
16
+ end
17
+ end
18
+ EOS
19
+ alias_method_chain(method, :callbacks)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ module SuperModel
2
+ module Dirty
3
+ extend ActiveSupport::Concern
4
+ include ActiveModel::Dirty
5
+
6
+ included do
7
+ %w( create update ).each do |method|
8
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
9
+ def #{method}_with_dirty(*args, &block)
10
+ result = #{method}_without_dirty(*args, &block)
11
+ save_previous_changes
12
+ result
13
+ end
14
+ EOS
15
+ alias_method_chain(method, :dirty)
16
+ end
17
+ end
18
+
19
+ def save_previous_changes
20
+ @previously_changed = changes
21
+ @changed_attributes.clear
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ class Array
2
+ unless defined?(deep_dup)
3
+ def deep_dup
4
+ Marshal.load(Marshal.dump(self))
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,91 @@
1
+ require "tempfile"
2
+ require "fileutils"
3
+
4
+ module SuperModel
5
+ module Marshal
6
+ def path
7
+ @path || raise("Provide a path")
8
+ end
9
+
10
+ def path=(p)
11
+ @path = p
12
+ end
13
+
14
+ def klasses
15
+ @klasses ||= []
16
+ end
17
+
18
+ def load
19
+ return unless path
20
+ return unless File.exist?(path)
21
+ data = []
22
+ File.open(path, "rb") do |file|
23
+ begin
24
+ data = ::Marshal.load(file)
25
+ rescue => e
26
+ if defined?(Bowline)
27
+ Bowline::Logging.log_error(e)
28
+ end
29
+ # Lots of errors can occur during
30
+ # marshaling - such as EOF etc
31
+ return false
32
+ end
33
+ end
34
+ data.each do |klass, records|
35
+ klass.marshal_records = records
36
+ end
37
+ true
38
+ end
39
+
40
+ def dump
41
+ return unless path
42
+ tmp_file = Tempfile.new("rbdump")
43
+ tmp_file.binmode
44
+ data = klasses.inject({}) {|hash, klass|
45
+ hash[klass] = klass.marshal_records
46
+ hash
47
+ }
48
+ ::Marshal.dump(data, tmp_file)
49
+ tmp_file.close
50
+ # Atomic serialization - so we never corrupt the db
51
+ FileUtils.mv(tmp_file.path, path)
52
+ true
53
+ end
54
+
55
+ extend self
56
+
57
+ module Model
58
+ def self.included(base)
59
+ base.extend ClassMethods
60
+ Marshal.klasses << base
61
+ end
62
+
63
+ def marshal_dump
64
+ serializable_hash(self.class.marshal)
65
+ end
66
+
67
+ def marshal_load(atts)
68
+ # Can't call load, since class
69
+ # isn't setup properly
70
+ @attributes = atts.with_indifferent_access
71
+ @changed_attributes = {}
72
+ end
73
+
74
+ module ClassMethods
75
+ def marshal(options = nil)
76
+ @marshal = options if options
77
+ @marshal ||= {}
78
+ end
79
+ alias_method :marshal=, :marshal
80
+
81
+ def marshal_records=(records)
82
+ @records = records
83
+ end
84
+
85
+ def marshal_records
86
+ @records
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,21 @@
1
+ module SuperModel
2
+ module Observing
3
+ extend ActiveSupport::Concern
4
+ include ActiveModel::Observing
5
+
6
+ included do
7
+ %w( create save update destroy ).each do |method|
8
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
9
+ def #{method}_with_notifications(*args, &block)
10
+ notify_observers(:before_#{method})
11
+ if result = #{method}_without_notifications(*args, &block)
12
+ notify_observers(:after_#{method})
13
+ end
14
+ result
15
+ end
16
+ EOS
17
+ alias_method_chain(method, :notifications)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ module SuperModel
2
+ module RandomID
3
+ protected
4
+ def generate_id
5
+ ActiveSupport::SecureRandom.hex(13)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,167 @@
1
+ module SuperModel
2
+ module Redis
3
+ module ClassMethods
4
+ def self.extended(base)
5
+ base.class_eval do
6
+ class_inheritable_array :indexed_attributes
7
+ self.indexed_attributes = []
8
+
9
+ class_inheritable_hash :redis_options
10
+ self.redis_options = {}
11
+ end
12
+ end
13
+
14
+ def namespace
15
+ @namespace ||= self.name.downcase
16
+ end
17
+
18
+ def namespace=(namespace)
19
+ @namespace = namespace
20
+ end
21
+
22
+ def redis
23
+ @redis ||= ::Redis.connect(redis_options)
24
+ end
25
+
26
+ def indexes(*indexes)
27
+ self.indexed_attributes += indexes.map(&:to_s)
28
+ end
29
+
30
+ def redis_key(*args)
31
+ args.unshift(self.namespace)
32
+ args.join(":")
33
+ end
34
+
35
+ def find(id)
36
+ if redis.sismember(redis_key, id.to_s)
37
+ existing(:id => id)
38
+ else
39
+ raise UnknownRecord, "Couldn't find #{self.name} with ID=#{id}"
40
+ end
41
+ end
42
+
43
+ def first
44
+ item_ids = redis.sort(redis_key, :order => "ASC", :limit => [0, 1])
45
+ item_id = item_ids.first
46
+ item_id && existing(:id => item_id)
47
+ end
48
+
49
+ def last
50
+ item_ids = redis.sort(redis_key, :order => "DESC", :limit => [0, 1])
51
+ item_id = item_ids.first
52
+ item_id && existing(:id => item_id)
53
+ end
54
+
55
+ def exists?(id)
56
+ redis.sismember(redis_key, id.to_s)
57
+ end
58
+
59
+ def count
60
+ redis.scard(redis_key)
61
+ end
62
+
63
+ def all
64
+ from_ids(redis.sort(redis_key))
65
+ end
66
+
67
+ def select
68
+ raise "Not implemented"
69
+ end
70
+
71
+ def delete_all
72
+ raise "Not implemented"
73
+ end
74
+
75
+ def find_by_attribute(key, value)
76
+ item_ids = redis.sort(redis_key(key, value.to_s))
77
+ item_id = item_ids.first
78
+ item_id && existing(:id => item_id)
79
+ end
80
+
81
+ def find_all_by_attribute(key, value)
82
+ from_ids(redis.sort(redis_key(key, value.to_s)))
83
+ end
84
+
85
+ protected
86
+ def from_ids(ids)
87
+ ids.map {|id| existing(:id => id) }
88
+ end
89
+
90
+ def existing(atts = {})
91
+ item = self.new(atts)
92
+ item.new_record = false
93
+ item.redis_get
94
+ item
95
+ end
96
+ end
97
+
98
+ module InstanceMethods
99
+ protected
100
+ def raw_destroy
101
+ return if new?
102
+
103
+ destroy_indexes
104
+ redis.srem(self.class.redis_key, self.id)
105
+ redis.del(redis_key)
106
+ end
107
+
108
+ def destroy_indexes
109
+ indexed_attributes.each do |index|
110
+ old_attribute = changes[index].try(:first) || send(index)
111
+ redis.srem(self.class.redis_key(index, old_attribute), id)
112
+ end
113
+ end
114
+
115
+ def create_indexes
116
+ indexed_attributes.each do |index|
117
+ new_attribute = send(index)
118
+ redis.sadd(self.class.redis_key(index, new_attribute), id)
119
+ end
120
+ end
121
+
122
+ def generate_id
123
+ redis.incr(self.class.redis_key(:uid))
124
+ end
125
+
126
+ def indexed_attributes
127
+ attributes.keys & self.class.indexed_attributes
128
+ end
129
+
130
+ def redis
131
+ self.class.redis
132
+ end
133
+
134
+ def redis_key(*args)
135
+ self.class.redis_key(id, *args)
136
+ end
137
+
138
+ def redis_set
139
+ redis.set(redis_key, serializable_hash.to_json)
140
+ end
141
+
142
+ def redis_get
143
+ load(ActiveSupport::JSON.decode(redis.get(redis_key)))
144
+ end
145
+ public :redis_get
146
+
147
+ def raw_create
148
+ redis_set
149
+ create_indexes
150
+ redis.sadd(self.class.redis_key, self.id)
151
+ end
152
+
153
+ def raw_update
154
+ destroy_indexes
155
+ redis_set
156
+ create_indexes
157
+ end
158
+ end
159
+
160
+ module Model
161
+ def self.included(base)
162
+ base.send :include, InstanceMethods
163
+ base.send :extend, ClassMethods
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,53 @@
1
+ module SuperModel
2
+ module Timestamp
3
+ module Model
4
+ def self.included(base)
5
+ base.class_eval do
6
+ attributes :created_at, :updated_at
7
+
8
+ before_create :set_created_at
9
+ before_save :set_updated_at
10
+ end
11
+ end
12
+
13
+ def touch
14
+ set_updated_at
15
+ save!
16
+ end
17
+
18
+ def created_at=(time)
19
+ write_attribute(:created_at, parse_time(time))
20
+ end
21
+
22
+ def updated_at=(time)
23
+ write_attribute(:updated_at, parse_time(time))
24
+ end
25
+
26
+ private
27
+ def parse_time(time)
28
+ return time unless time.is_a?(String)
29
+ if Time.respond_to?(:zone) && Time.zone
30
+ Time.zone.parse(time)
31
+ else
32
+ Time.parse(time)
33
+ end
34
+ end
35
+
36
+ def current_time
37
+ if Time.respond_to?(:current)
38
+ Time.current
39
+ else
40
+ Time.now
41
+ end
42
+ end
43
+
44
+ def set_created_at
45
+ self.created_at = current_time
46
+ end
47
+
48
+ def set_updated_at
49
+ self.updated_at = current_time
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,32 @@
1
+ module SuperModel
2
+ module Validations
3
+ extend ActiveSupport::Concern
4
+ include ActiveModel::Validations
5
+
6
+ included do
7
+ alias_method_chain :save, :validation
8
+ end
9
+
10
+ def save_with_validation(options = nil)
11
+ perform_validation = case options
12
+ when Hash
13
+ options[:validate] != false
14
+ when NilClass
15
+ true
16
+ else
17
+ options
18
+ end
19
+
20
+ if perform_validation && valid? || !perform_validation
21
+ save_without_validation
22
+ true
23
+ else
24
+ false
25
+ end
26
+ rescue InvalidRecord => error
27
+ false
28
+ end
29
+ end
30
+ end
31
+
32
+ require "supermodel/validations/uniqueness"
@@ -0,0 +1,40 @@
1
+ module SuperModel
2
+ module Validations
3
+ class UniquenessValidator < ActiveModel::EachValidator
4
+ attr_reader :klass
5
+
6
+ def validate_each(record, attribute, value)
7
+ alternate = klass.find_by_attribute(attribute, value)
8
+ return unless alternate
9
+ record.errors.add(attribute, "must be unique", :default => options[:message])
10
+ end
11
+
12
+ def setup(klass)
13
+ @klass = klass
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+
19
+ # Validates that the specified attribute is unique.
20
+ # class Person < ActiveRecord::Base
21
+ # validates_uniquness_of :essay
22
+ # end
23
+ #
24
+ # Configuration options:
25
+ # * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
26
+ # * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
27
+ # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
28
+ # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
29
+ # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
30
+ # occur (e.g. <tt>:if => :allow_validation</tt>, or <tt>:if => Proc.new { |user| user.signup_step > 2 }</tt>). The
31
+ # method, proc or string should return or evaluate to a true or false value.
32
+ # * <tt>:unless</tt> - Specifies a method, proc or string to call to determine if the validation should
33
+ # not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
34
+ # method, proc or string should return or evaluate to a true or false value.
35
+ def validates_uniqueness_of(*attr_names)
36
+ validates_with UniquenessValidator, _merge_attributes(attr_names)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,58 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{csun-student-affairs-supermodel}
8
+ s.version = "0.1.5"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Alex MacCaw", "Mani Tadayon"]
12
+ s.date = %q{2010-08-30}
13
+ s.description = %q{In memory DB using ActiveModel}
14
+ s.email = %q{info@eribium.org}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "MIT-LICENSE",
21
+ "README",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "lib/super_model.rb",
25
+ "lib/supermodel.rb",
26
+ "lib/supermodel/association.rb",
27
+ "lib/supermodel/base.rb",
28
+ "lib/supermodel/callbacks.rb",
29
+ "lib/supermodel/dirty.rb",
30
+ "lib/supermodel/ext/array.rb",
31
+ "lib/supermodel/marshal.rb",
32
+ "lib/supermodel/observing.rb",
33
+ "lib/supermodel/random_id.rb",
34
+ "lib/supermodel/redis.rb",
35
+ "lib/supermodel/timestamp.rb",
36
+ "lib/supermodel/validations.rb",
37
+ "lib/supermodel/validations/uniqueness.rb",
38
+ "supermodel.gemspec"
39
+ ]
40
+ s.homepage = %q{https://github.com/csun-student-affairs/supermodel}
41
+ s.rdoc_options = ["--charset=UTF-8"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.7}
44
+ s.summary = %q{In memory DB using ActiveModel}
45
+
46
+ if s.respond_to? :specification_version then
47
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
+ s.specification_version = 3
49
+
50
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
51
+ s.add_runtime_dependency(%q<activemodel>, ["~> 3.0.0"])
52
+ else
53
+ s.add_dependency(%q<activemodel>, ["~> 3.0.0"])
54
+ end
55
+ else
56
+ s.add_dependency(%q<activemodel>, ["~> 3.0.0"])
57
+ end
58
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: csun-student-affairs-supermodel
3
+ version: !ruby/object:Gem::Version
4
+ hash: 17
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 5
10
+ version: 0.1.5
11
+ platform: ruby
12
+ authors:
13
+ - Alex MacCaw
14
+ - Mani Tadayon
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-08-30 00:00:00 -07:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: activemodel
24
+ prerelease: false
25
+ requirement: &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
+ type: :runtime
37
+ version_requirements: *id001
38
+ description: In memory DB using ActiveModel
39
+ email: info@eribium.org
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files:
45
+ - README
46
+ files:
47
+ - .gitignore
48
+ - MIT-LICENSE
49
+ - README
50
+ - Rakefile
51
+ - VERSION
52
+ - lib/super_model.rb
53
+ - lib/supermodel.rb
54
+ - lib/supermodel/association.rb
55
+ - lib/supermodel/base.rb
56
+ - lib/supermodel/callbacks.rb
57
+ - lib/supermodel/dirty.rb
58
+ - lib/supermodel/ext/array.rb
59
+ - lib/supermodel/marshal.rb
60
+ - lib/supermodel/observing.rb
61
+ - lib/supermodel/random_id.rb
62
+ - lib/supermodel/redis.rb
63
+ - lib/supermodel/timestamp.rb
64
+ - lib/supermodel/validations.rb
65
+ - lib/supermodel/validations/uniqueness.rb
66
+ - supermodel.gemspec
67
+ has_rdoc: true
68
+ homepage: https://github.com/csun-student-affairs/supermodel
69
+ licenses: []
70
+
71
+ post_install_message:
72
+ rdoc_options:
73
+ - --charset=UTF-8
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ requirements: []
95
+
96
+ rubyforge_project:
97
+ rubygems_version: 1.3.7
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: In memory DB using ActiveModel
101
+ test_files: []
102
+