redisted 0.0.1

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/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