supermodel 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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