redisted 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,59 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ # Pick the frameworks you want:
4
+ # require "active_record/railtie"
5
+ require "action_controller/railtie"
6
+ require "action_mailer/railtie"
7
+ require "active_resource/railtie"
8
+ require "sprockets/railtie"
9
+ require "rails/test_unit/railtie"
10
+ require File.expand_path('../redis', __FILE__)
11
+
12
+ if defined?(Bundler)
13
+ # If you precompile assets before deploying to production, use this line
14
+ Bundler.require *Rails.groups(:assets => %w(development test))
15
+ # If you want your assets lazily compiled in production, use this line
16
+ # Bundler.require(:default, :assets, Rails.env)
17
+ end
18
+
19
+ module Redisted
20
+ class Application < Rails::Application
21
+ # Settings in config/environments/* take precedence over those specified here.
22
+ # Application configuration should go into files in config/initializers
23
+ # -- all .rb files in that directory are automatically loaded.
24
+
25
+ # Custom directories with classes and modules you want to be autoloadable.
26
+ # config.autoload_paths += %W(#{config.root}/extras)
27
+
28
+ # Only load the plugins named here, in the order given (default is alphabetical).
29
+ # :all can be used as a placeholder for all plugins not explicitly named.
30
+ # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
31
+
32
+ # Activate observers that should always be running.
33
+ # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
34
+
35
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
36
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
37
+ config.time_zone = 'UTC'
38
+
39
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
40
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
41
+ # config.i18n.default_locale = :de
42
+
43
+ # Configure the default encoding used in templates for Ruby 1.9.
44
+ config.encoding = "utf-8"
45
+
46
+ # Configure sensitive parameters which will be filtered from the log file.
47
+ config.filter_parameters += [:password]
48
+
49
+ # Enable the asset pipeline
50
+ config.assets.enabled = true
51
+
52
+ # Version of your assets, change this if you want to expire all your assets
53
+ config.assets.version = '1.0'
54
+
55
+
56
+ config.active_support.deprecation = :stderr
57
+
58
+ end
59
+ end
data/config/boot.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+
3
+ # Set up gems listed in the Gemfile.
4
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
5
+
6
+ require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
@@ -0,0 +1,7 @@
1
+ # Load the rails application
2
+ require File.expand_path('../application', __FILE__)
3
+
4
+ # Initialize the rails application
5
+ Redisted::Application.initialize!
6
+
7
+
data/config/redis.rb ADDED
@@ -0,0 +1,17 @@
1
+ #
2
+ # Setup Redis
3
+ #
4
+ require 'redis'
5
+ require 'redisted'
6
+ begin
7
+ $redis=Redis.new({
8
+ host: "localhost",
9
+ port: 6379,
10
+ timeout: 5,
11
+ })
12
+ $redis.select 15 # Database #15
13
+ Redisted::Base.redis=$redis
14
+ rescue =>err
15
+ puts "Redisted Test redis error: #{err}"
16
+ raise "Redisted Test redis error: #{err}"
17
+ end
data/config/redis.yml ADDED
File without changes
data/index.html ADDED
@@ -0,0 +1 @@
1
+ Test Page
@@ -0,0 +1,129 @@
1
+ #
2
+ #
3
+ # Creates the following Redis keys for a class named "Model"
4
+ #
5
+ # model:<id> -- HASH -- contains all attributes of the class
6
+ # model_id -- Last ID used (integer used with INCR command)
7
+ #
8
+ #
9
+ module Redisted
10
+ class Base
11
+ include ActiveModel::MassAssignmentSecurity
12
+ include ActiveModel::Validations
13
+ include ActiveModel::Serialization
14
+ #include ActiveModel::Dirty -- This model doesn't match very well...
15
+ extend ActiveModel::Callbacks
16
+ extend ActiveModel::Naming
17
+ extend ActiveModel::Translation
18
+
19
+ define_model_callbacks :create, :update, :save, :destroy
20
+
21
+ def initialize(attrs = nil,redis=nil)
22
+ @redis=redis||Base.redis
23
+ validate_redis
24
+ init_fields
25
+ init_attributes
26
+ init_indexes
27
+ init_references
28
+ self.attributes=attrs if attrs
29
+ self
30
+ end
31
+ def redis= conn=nil
32
+ @redis=conn||@@redis
33
+ validate_redis
34
+ @redis
35
+ end
36
+ def redis
37
+ validate_redis
38
+ @redis
39
+ end
40
+ def prefix
41
+ self.class.prefix
42
+ end
43
+ def id # NOTE: ID is read/only - it can only be set via the load method
44
+ @id
45
+ end
46
+ def to_attr_type key,value
47
+ raise InvalidField,"Unknown field: #{key}" if fields[key].nil?
48
+ return nil if value.nil?
49
+ case fields[key][:type]
50
+ when :string then value
51
+ when :symbol then value.to_sym
52
+ when :integer then value.to_i
53
+ when :datetime then value.to_datetime
54
+ else
55
+ value
56
+ end
57
+ end
58
+ def to_redis_type key,value
59
+ return nil if value.nil?
60
+ case fields[key][:type]
61
+ when :string then value
62
+ when :symbol then value.to_s
63
+ when :integer then value.to_i.to_s
64
+ when :datetime then value.utc.to_s
65
+ else
66
+ value
67
+ end
68
+ end
69
+ def method_missing(id, *args)
70
+ fields.each do |field,options|
71
+ return get_attr(field) if id==field
72
+ return set_attr(field,args[0]) if id.to_s==field.to_s+"="
73
+ end
74
+ references.each do |ref,options|
75
+ return get_reference(ref,options) if id==ref
76
+ return set_reference(ref,options,args[0]) if id.to_s==ref.to_s+"="
77
+ end
78
+ super
79
+ end
80
+
81
+ private
82
+ def validate_redis
83
+ raise RedisConnectionNotDefined if @redis.nil?
84
+ end
85
+
86
+ def generate_id
87
+ validate_redis
88
+ @@redis.incr "#{prefix}_id"
89
+ end
90
+
91
+
92
+ def get_obj_option key
93
+ self.class.get_obj_option key
94
+ end
95
+ def set_obj_option key,val
96
+ self.class.set_obj_option key,val
97
+ end
98
+ class << self
99
+ def get_obj_option key
100
+ @obj_options||={}
101
+ @obj_options[key]
102
+ end
103
+ def set_obj_option key,val
104
+ @obj_options||={}
105
+ @obj_options[key]=val
106
+ end
107
+ def is_redisted_model?
108
+ true
109
+ end
110
+ def redis= conn
111
+ @@redis=conn
112
+ end
113
+ def redis
114
+ @@redis
115
+ end
116
+ def prefix
117
+ ret=self.model_name.i18n_key
118
+ ret
119
+ end
120
+
121
+ private
122
+
123
+ def validate_redis
124
+ raise RedisConnectionNotDefined if @@redis.nil?
125
+ end
126
+
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,21 @@
1
+ module Redisted
2
+ class Base
3
+
4
+ def delete
5
+ raise Redisted::RecordInvalid,"Object is not persisted" if self.id.nil?
6
+ @redis.del "#{prefix}:#{self.id}"
7
+ id=nil
8
+ attributes={}
9
+ @attributes_status.clear
10
+ # LEELEE: Also handle indices
11
+ true
12
+ end
13
+ def destroy
14
+ # TODO: Run all the callbacks...
15
+ delete
16
+ # LEELEE: Follow destroy path...
17
+ true
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ module Redisted
2
+ class RedisConnectionNotDefined<Exception;end # No redis connection was found
3
+ class RedisSaveFailed<Exception;end
4
+ class RecordInvalid<Exception;end
5
+ class InvalidQuery<Exception;end
6
+ class InvalidReference<Exception;end
7
+ class ValueNotUnique<Exception;end
8
+ class MultiSessionConflict<Exception;end
9
+ class IsDirty<Exception;end
10
+ class InvalidIndex<Exception;end
11
+ class InvalidField<Exception;end
12
+ end
@@ -0,0 +1,59 @@
1
+ module Redisted
2
+ class Base
3
+ def fields
4
+ self.class.fields
5
+ end
6
+ def scopes
7
+ self.class.scopes
8
+ end
9
+ private
10
+ def init_fields
11
+ end
12
+ class << self
13
+ public
14
+ #
15
+ # Setup
16
+ #
17
+ def field value,options={}
18
+ options[:type]||=:string
19
+ fields[value]=options
20
+ end
21
+ def fields
22
+ @fields||={}
23
+ @fields
24
+ end
25
+ def fields= val
26
+ @fields=val
27
+ end
28
+ def scopes
29
+ @scopes||={}
30
+ @scopes
31
+ end
32
+ def scopes= val
33
+ @scopes=val
34
+ end
35
+ def scope name,options
36
+ scopes[name]=lambdafi_field(options)
37
+ end
38
+
39
+ private
40
+
41
+ def read_attribute_for_validation key
42
+ get_attr key
43
+ end
44
+
45
+ def lambdafi_field options
46
+ lambda do |*args|
47
+ if options.respond_to? :call
48
+ options.call(*args)
49
+ elsif options.is_a? Symbol
50
+ args[0].send(options,*args)
51
+ else
52
+ options # An integer or other constant value
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,220 @@
1
+ module Redisted
2
+ class Base
3
+ class << self
4
+ def always_cache_until_save val=true
5
+ set_obj_option :cache_until_save,val
6
+ end
7
+ def pre_cache_all opts={}
8
+ opts[:keys]=:all if opts[:keys].nil?
9
+ opts[:when]=:create if opts[:when].nil?
10
+ set_obj_option :pre_cache_all,opts
11
+ end
12
+ end
13
+ private
14
+ def init_attributes
15
+ @attributes_value={}
16
+ @attributes_status={}
17
+ @attributes_old={}
18
+ @attributes_old_status={}
19
+ @cache_preload=false
20
+ @cached_sets=false
21
+ @cached_sets=true if get_obj_option :cache_until_save
22
+ end
23
+ def pre_cache_values
24
+ return if @cache_preload
25
+ @cache_preload=true # Must be set first to prevent get_attr loop...
26
+ keys=get_obj_option(:pre_cache_all)[:keys]
27
+ except=get_obj_option(:pre_cache_all)[:except]
28
+ if keys==:all
29
+ fields.each do |k,v|
30
+ next if except and except.include? k
31
+ get_attr k
32
+ end
33
+ else
34
+ keys.each do |k|
35
+ next if except and except.include? k
36
+ get_attr k
37
+ end
38
+ end
39
+ end
40
+ public
41
+ def set_attr key,val
42
+ key=key.to_sym
43
+ val=to_redis_type key,val
44
+ if @cached_sets or !persisted?
45
+ if (@attributes_status[key]==:cached)
46
+ # If we have it, we save the old value when first marked dirty...
47
+ @attributes_old[key]=@attributes_value[key]
48
+ @attributes_old_status[key]=:cached
49
+ end
50
+ @attributes_value[key]=val
51
+ @attributes_status[key]=:dirty
52
+ else
53
+ index_process({key=>val}) do
54
+ @attributes_value[key]=val
55
+ @attributes_status[key]=:cached
56
+ @redis.hset "#{prefix}:#{@id}",key,val
57
+ @attributes_old[key]=nil
58
+ @attributes_old_status[key]=nil
59
+ end
60
+ end
61
+ end
62
+ def get_attr key
63
+ key=key.to_sym
64
+ return to_attr_type(key,@attributes_value[key]) if [:cached,:dirty].include?(@attributes_status[key])
65
+ return nil if !persisted?
66
+ ret=to_attr_type key,@redis.hget("#{prefix}:#{@id}",key)
67
+ pre_cache_values if get_obj_option(:pre_cache_all) and get_obj_option(:pre_cache_all)[:when]==:first_read and !@cache_preload
68
+ @attributes_value[key]=ret
69
+ @attributes_status[key]=:cached
70
+ ret
71
+ end
72
+
73
+ def clear key=nil
74
+ if key.nil?
75
+ self.class.fields.each do |key,val|
76
+ raise IsDirty,"#{key} is dirty" if (!key.nil?) and @attributes_status[key]==:dirty
77
+ end
78
+ end
79
+ setup_attributes
80
+ nil
81
+ end
82
+ def flush
83
+ fields.each do |key,val|
84
+ @attributes_status[key]=nil
85
+ end
86
+ end
87
+ def fill_cache keys=nil
88
+ if keys.nil?
89
+ keys=[]
90
+ fields.each do |key,val|
91
+ next if !@attributes_status[key].nil?
92
+ keys << key
93
+ end
94
+ end
95
+ if keys.size>0
96
+ ret=@redis.hmget "#{prefix}:#{@id}",*keys
97
+ idx=0
98
+ keys.each do |key|
99
+ key=key.to_sym
100
+ @attributes_value[key]=ret[idx]
101
+ @attributes_status[key]=:cached
102
+ idx+=1
103
+ end
104
+ end
105
+ self
106
+ end
107
+ def persisted?
108
+ !@id.nil?
109
+ end
110
+ def cached? key
111
+ return true if !persisted?
112
+ return [:cached,:dirty].include?(@attributes_status[key])
113
+ end
114
+ def dirty? key
115
+ return true if !persisted?
116
+ return @attributes_status[key]==:dirty
117
+ end
118
+ def saved?
119
+ return false if !persisted?
120
+ fields.each do |key,val|
121
+ return false if @attributes_status[key]==:dirty
122
+ end
123
+ return true
124
+ end
125
+ def cache
126
+ if block_given?
127
+ previous_cached_sets=nil
128
+ begin
129
+ previous_cached_sets=@cached_sets
130
+ @cached_sets=true
131
+ yield
132
+ save if !previous_cached_sets
133
+ @cached_sets=previous_cached_sets
134
+ rescue Exception
135
+ @cached_sets=previous_cached_sets
136
+ raise
137
+ end
138
+ else
139
+ @cached_sets=true
140
+ end
141
+ end
142
+ def cache! &proc
143
+ begin
144
+ @cached_sets=true
145
+ proc.call *attrs
146
+ save!
147
+ rescue Exception
148
+ @cached_sets=false
149
+ raise
150
+ end
151
+ end
152
+ def attributes= attrs
153
+ cache do
154
+ attrs.each do |key,value|
155
+ set_attr key,value
156
+ end
157
+ end
158
+ end
159
+ def attributes load_all=true
160
+ fill_cache if load_all
161
+ @attributes_value.merge id: @id
162
+ end
163
+
164
+ def save!
165
+ raise Redisted::RecordInvalid if !valid?
166
+ internal_save_with_callbacks
167
+ end
168
+
169
+ def save options={}
170
+ begin
171
+ if (options[:validate].nil? or options[:validate])
172
+ raise Redisted::RecordInvalid if !valid?
173
+ end
174
+ internal_save_with_callbacks
175
+ rescue Exception=>err
176
+ self.errors[:base] = err.to_s
177
+ return false
178
+ end
179
+ true
180
+ end
181
+
182
+ private
183
+ def internal_save_with_callbacks
184
+ cb_run=run_callbacks :save do
185
+ if persisted?
186
+ run_callbacks :update do
187
+ internal_save false
188
+ end
189
+ else
190
+ run_callbacks :create do
191
+ internal_save true
192
+ end
193
+ end
194
+ end
195
+ raise Redisted::RecordInvalid,"Callback link broken" if !cb_run
196
+ end
197
+ def internal_save is_create
198
+ @id=generate_id if is_create
199
+ params={}
200
+ params[:id]=@id if is_create
201
+ @attributes_status.each do |key,value|
202
+ next if value!=:dirty
203
+ params[key]=@attributes_value[key]
204
+ end
205
+ if params.size>0
206
+ index_process(params) do
207
+ @redis.hmset("#{prefix}:#{@id}",*(params.flatten))
208
+ @attributes_status.each do |key,value|
209
+ next if value!=:dirty
210
+ @attributes_status[key]=:cached
211
+ end
212
+ @attributes_old={}
213
+ @attributes_old_status={}
214
+ end
215
+ end
216
+ @hold_writes=false
217
+ self
218
+ end
219
+ end
220
+ end