supermodel 0.0.5 → 0.0.6

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 CHANGED
@@ -1,3 +1,4 @@
1
1
  dump.db
2
2
  test.rb
3
+ redis_test.rb
3
4
  pkg
data/README CHANGED
@@ -10,7 +10,8 @@ Supports:
10
10
  * Callbacks
11
11
  * Observers
12
12
  * Dirty (Changes)
13
- * Persistance
13
+ * Ruby Marshalling to disk
14
+ * Redis
14
15
 
15
16
  Examples:
16
17
 
@@ -37,15 +38,25 @@ You can use a random ID rather than the object ID:
37
38
  t = Test.create(:name => "test")
38
39
  t.id #=> "7ee935377bb4aecc54ad4f9126"
39
40
 
40
- You can persist objects to disk on startup/shutdown
41
+ You can marshal objects to disk on startup/shutdown
41
42
 
42
43
  class Test < SuperModel::Base
43
- include SuperModel::Persist::Model
44
+ include SuperModel::Marshal::Model
44
45
  end
45
46
 
46
- SuperModel::Persist.path = "dump.db"
47
- SuperModel::Persist.load
47
+ SuperModel::Marshal.path = "dump.db"
48
+ SuperModel::Marshal.load
48
49
 
49
50
  at_exit {
50
- SuperModel::Persist.dump
51
- }
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::Redis
58
+ attributes :name
59
+ indexes :name
60
+ end
61
+
62
+ Test.find_or_create_by_name("foo")
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.5
1
+ 0.0.6
@@ -57,7 +57,7 @@ module SuperModel
57
57
  # Removes all records and executes
58
58
  # destory callbacks.
59
59
  def destroy_all
60
- records.dup.each {|r| r.destroy }
60
+ all.each {|r| r.destroy }
61
61
  end
62
62
 
63
63
  # Removes all records without executing
@@ -74,13 +74,17 @@ module SuperModel
74
74
  rec.save && rec
75
75
  end
76
76
 
77
+ def find_by_attribute(name, value) #:nodoc:
78
+ records.find {|r| r.name == value }
79
+ end
80
+
77
81
  def method_missing(method_symbol, *args) #:nodoc:
78
82
  method_name = method_symbol.to_s
79
83
 
80
84
  if method_name =~ /^find_by_(\w+)!/
81
85
  send("find_by_#{$1}", *args) || raise(UnknownRecord)
82
86
  elsif method_name =~ /^find_by_(\w+)/
83
- records.find {|r| r.send($1) == args.first }
87
+ find_by_attribute($1, args.first)
84
88
  elsif method_name =~ /^find_or_create_by_(\w+)/
85
89
  send("find_by_#{$1}", *args) || create($1 => args.first)
86
90
  else
@@ -156,7 +160,9 @@ module SuperModel
156
160
  end
157
161
 
158
162
  def load(attributes) #:nodoc:
159
- @attributes.merge!(attributes)
163
+ attributes.each {|(name, value)|
164
+ self.send("#{name}=".to_sym, value)
165
+ }
160
166
  end
161
167
 
162
168
  def update_attribute(name, value)
@@ -2,7 +2,7 @@ require "tempfile"
2
2
  require "fileutils"
3
3
 
4
4
  module SuperModel
5
- module Persist
5
+ module Marshal
6
6
  def path
7
7
  @path || raise("Provide a path")
8
8
  end
@@ -20,7 +20,7 @@ module SuperModel
20
20
  return unless File.exist?(path)
21
21
  records = []
22
22
  File.open(path, "rb") {|file|
23
- records = Marshal.load(file)
23
+ records = ::Marshal.load(file)
24
24
  }
25
25
  records.each {|r| r.class.records << r }
26
26
  true
@@ -31,7 +31,7 @@ module SuperModel
31
31
  tmp_file = Tempfile.new("rbdump")
32
32
  tmp_file.binmode
33
33
  records = klasses.map {|k| k.records }.flatten
34
- Marshal.dump(records, tmp_file)
34
+ ::Marshal.dump(records, tmp_file)
35
35
  # Atomic serialization - so we never corrupt the db
36
36
  FileUtils.mv(tmp_file.path, path)
37
37
  true
@@ -41,7 +41,7 @@ module SuperModel
41
41
 
42
42
  module Model
43
43
  def self.included(base)
44
- Persist.klasses << base
44
+ Marshal.klasses << base
45
45
  end
46
46
 
47
47
  def marshal_dump
@@ -0,0 +1,162 @@
1
+ module SuperModel
2
+ class Redis < Base
3
+ class << self
4
+ def redis
5
+ @redis ||= ::Redis.new
6
+ end
7
+
8
+ def indexes(*indexes)
9
+ @known_indexes = indexes.map(&:to_s)
10
+ end
11
+
12
+ def known_indexes
13
+ @known_indexes ||= []
14
+ end
15
+
16
+ def serialize(*attributes)
17
+ @serialized_attributes = attributes.map(&:to_s)
18
+ end
19
+
20
+ def serialized_attributes
21
+ @serialized_attributes ||= []
22
+ end
23
+
24
+ def redis_key(*args)
25
+ args.unshift(self.name.downcase)
26
+ args.join(":")
27
+ end
28
+
29
+ def find(id)
30
+ if redis.set_member?(redis_key, id)
31
+ res = self.new(:id => id)
32
+ res.redis_get
33
+ res
34
+ else
35
+ raise(UnknownRecord)
36
+ end
37
+ end
38
+
39
+ def first
40
+ all.first
41
+ end
42
+
43
+ def last
44
+ all.last
45
+ end
46
+
47
+ def count
48
+ redis.set_count(redis_key)
49
+ end
50
+
51
+ def all
52
+ from_ids(redis.set_members(redis_key))
53
+ end
54
+
55
+ def delete_all
56
+ raise "Not implemented"
57
+ end
58
+
59
+ def find_by_attribute(key, value)
60
+ item_ids = redis.set_members(redis_key(key, value))
61
+ return if item_ids.empty?
62
+ res = self.new(:id => item_ids.first)
63
+ res.redis_get
64
+ res
65
+ end
66
+
67
+ protected
68
+ def from_ids(ids)
69
+ ids.map do |id|
70
+ res = self.new(:id => id)
71
+ res.redis_get
72
+ res
73
+ end
74
+ end
75
+ end
76
+
77
+ def destroy
78
+ return if new?
79
+
80
+ destroy_indexes
81
+ redis.set_delete(self.class.redis_key, self.id)
82
+
83
+ attributes.keys.each do |key|
84
+ redis.delete(redis_key(key))
85
+ end
86
+ end
87
+
88
+ protected
89
+ def destroy_indexes
90
+ known_indexes.each do |index|
91
+ old_attribute = changes[index].try(:first) || send(index)
92
+ redis.set_delete(self.class.redis_key(index, old_attribute), id)
93
+ end
94
+ end
95
+
96
+ def create_indexes
97
+ known_indexes.each do |index|
98
+ new_attribute = send(index)
99
+ redis.set_add(self.class.redis_key(index, new_attribute), id)
100
+ end
101
+ end
102
+
103
+ def generate_id
104
+ redis.incr(self.class.redis_key(:uid))
105
+ end
106
+
107
+ def known_indexes
108
+ attributes.keys & self.class.known_indexes
109
+ end
110
+
111
+ def redis
112
+ self.class.redis
113
+ end
114
+
115
+ def redis_key(*args)
116
+ self.class.redis_key(id, *args)
117
+ end
118
+
119
+ def serialized_attributes
120
+ self.class.serialized_attributes
121
+ end
122
+
123
+ def serialize_attribute(key, value)
124
+ return value unless serialized_attributes.include?(key)
125
+ value.to_json
126
+ end
127
+
128
+ def deserialize_attribute(key, value)
129
+ return value unless serialized_attributes.include?(key)
130
+ JSON.parse(value)
131
+ end
132
+
133
+ def redis_set
134
+ attributes.each do |(key, value)|
135
+ redis.set(redis_key(key), serialize_attribute(key, value))
136
+ end
137
+ end
138
+
139
+ def redis_get
140
+ known_attributes.each do |key|
141
+ result = deserialize_attribute(key, redis.get(redis_key(key)))
142
+ send("#{key}=", result)
143
+ end
144
+ end
145
+ public :redis_get
146
+
147
+ def create
148
+ self.id ||= generate_id
149
+ redis_set
150
+ create_indexes
151
+ redis.set_add(self.class.redis_key, self.id)
152
+ save_previous_changes
153
+ end
154
+
155
+ def update
156
+ destroy_indexes
157
+ redis_set
158
+ create_indexes
159
+ save_previous_changes
160
+ end
161
+ end
162
+ end
@@ -68,7 +68,11 @@ module SuperModel
68
68
  end
69
69
 
70
70
  def record(type, data = nil)
71
- ::Scriber.record(self, type, data)
71
+ ::Scriber.record(
72
+ :klass => self,
73
+ :type => type,
74
+ :data => data
75
+ )
72
76
  end
73
77
  end
74
78
  end
data/lib/supermodel.rb CHANGED
@@ -22,12 +22,13 @@ module SuperModel
22
22
  class InvalidRecord < SuperModelError; end
23
23
  end
24
24
 
25
- $: << File.dirname(__FILE__)
25
+ $:.unshift(File.dirname(__FILE__))
26
26
 
27
27
  require "supermodel/callbacks"
28
28
  require "supermodel/observing"
29
- require "supermodel/persist"
29
+ require "supermodel/marshal"
30
30
  require "supermodel/random_id"
31
31
  require "supermodel/scriber"
32
32
  require "supermodel/validations"
33
- require "supermodel/base"
33
+ require "supermodel/base"
34
+ require "supermodel/redis"
data/supermodel.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{supermodel}
8
- s.version = "0.0.5"
8
+ s.version = "0.0.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Alex MacCaw"]
@@ -24,9 +24,10 @@ Gem::Specification.new do |s|
24
24
  "lib/supermodel.rb",
25
25
  "lib/supermodel/base.rb",
26
26
  "lib/supermodel/callbacks.rb",
27
+ "lib/supermodel/marshal.rb",
27
28
  "lib/supermodel/observing.rb",
28
- "lib/supermodel/persist.rb",
29
29
  "lib/supermodel/random_id.rb",
30
+ "lib/supermodel/redis.rb",
30
31
  "lib/supermodel/scriber.rb",
31
32
  "lib/supermodel/validations.rb",
32
33
  "supermodel.gemspec"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: supermodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex MacCaw
@@ -39,9 +39,10 @@ files:
39
39
  - lib/supermodel.rb
40
40
  - lib/supermodel/base.rb
41
41
  - lib/supermodel/callbacks.rb
42
+ - lib/supermodel/marshal.rb
42
43
  - lib/supermodel/observing.rb
43
- - lib/supermodel/persist.rb
44
44
  - lib/supermodel/random_id.rb
45
+ - lib/supermodel/redis.rb
45
46
  - lib/supermodel/scriber.rb
46
47
  - lib/supermodel/validations.rb
47
48
  - supermodel.gemspec