redis-column 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ spec/config/database.yml
6
+ *.log
7
+ *.sqlite3
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use --create 1.9.3@redis_column
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in redis-column.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ RedisColumn
2
+ ===========
3
+
4
+ Seamlessly extend your AR model with Redis
5
+
6
+ The RedisColumn gem allows for the seamless integration of Redis within your ActiveRecord model in order to store heavy objects away from tables with a lot of rows.
7
+
8
+ Installation
9
+ ------------
10
+
11
+ gem install redis-column
12
+
13
+ Usage
14
+ -----
15
+
16
+ Within an initializer:
17
+
18
+ RedisColumn.config = YAML.load_file(Rails.root.join('config/redis.yml'))[:development]
19
+
20
+
21
+ Within your model:
22
+
23
+ class Page < ActiveRecord::Base
24
+ redis_column :body
25
+ end
26
+
27
+
28
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,3 @@
1
+ module RedisColumn
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,92 @@
1
+ require "active_record"
2
+ require "redis"
3
+ require File.dirname(__FILE__) + "/redis-column/version"
4
+
5
+ module RedisColumn
6
+
7
+ # Returns the current Redis configuration
8
+ def self.config
9
+ @@config ||= {}
10
+ end
11
+
12
+ # Sets the Redis configuration
13
+ def self.config= hash
14
+ @@config = hash
15
+ end
16
+
17
+ # Active Redis connection
18
+ def self.redis_instance
19
+ @@redis_instance ||= Redis.new(config)
20
+ end
21
+
22
+ module Record
23
+ extend ActiveSupport::Concern
24
+
25
+ included do
26
+ # Set up the class attribute that must be available to all subclasses.
27
+ class_attribute :redis_columns
28
+ self.redis_columns = []
29
+ # Allow the instance access to this class attributes
30
+ delegate :redis_columns, :to => "self.class"
31
+ # Allow the instance access to RedisColumn.redis_instance
32
+ delegate :redis_instance, :to => "RedisColumn"
33
+ # Save the columns after
34
+ after_save :save_redis_columns!
35
+ # Boosh!
36
+ alias_method_chain :attributes, :redis_columns
37
+ end
38
+
39
+ module ClassMethods
40
+
41
+ # Setup a redis column
42
+ def redis_column column_name
43
+ self.redis_columns += [column_name]
44
+ attr_writer column_name
45
+ define_method column_name do # read the attribute or find from Redis and set to instance var
46
+ send(:instance_variable_get, "@#{column_name}") || send("#{column_name}=", read_redis_attribute(column_name))
47
+ end
48
+ end
49
+ alias_method :redis_col, :redis_column
50
+
51
+ end
52
+
53
+ module InstanceMethods
54
+
55
+ # Returns the key to be used in Redis
56
+ def redis_key column_name
57
+ "#{self.class.model_name.i18n_key}:#{self.id}:#{column_name}"
58
+ end
59
+
60
+ # Read from Redis and unserialise
61
+ def read_redis_attribute column_name
62
+ val = redis_instance.get(redis_key(column_name))
63
+ YAML.load(val) unless val.nil?
64
+ end
65
+
66
+ # Serialise and write to Redis
67
+ def write_redis_attribute column_name, val
68
+ redis_instance.set(redis_key(column_name), val.to_yaml) and return val
69
+ end
70
+
71
+ # Returns both the AR attributes and the Redis attributes in one hash
72
+ def attributes_with_redis_columns
73
+ _attributes = attributes_without_redis_columns.with_indifferent_access
74
+ redis_columns.inject(_attributes) do |res, column_name|
75
+ res.merge(column_name => send(column_name))
76
+ end
77
+ end
78
+
79
+ # Save all values back to Redis
80
+ def save_redis_columns!
81
+ redis_columns.each do |column_name|
82
+ write_redis_attribute column_name, send(column_name)
83
+ end
84
+ end
85
+
86
+ end
87
+ end
88
+ end
89
+
90
+ if defined?(ActiveRecord::Base)
91
+ ActiveRecord::Base.send :include, RedisColumn::Record
92
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "redis-column/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "redis-column"
7
+ s.version = RedisColumn::VERSION
8
+ s.authors = ["Alex Neill"]
9
+ s.email = ["alex.neill@gmail.com"]
10
+ s.homepage = "https://github.com/ajn/redis-column"
11
+ s.summary = %q{Seamlessly extend your AR model with Redis}
12
+ s.description = %q{The RedisColumn gem allows for the seamless integration of Redis within your ActiveRecord model in order to store heavy objects away from tables with a lot of rows.}
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_dependency "activerecord"
19
+ s.add_dependency "redis"
20
+ # specify any dependencies here; for example:
21
+ s.add_development_dependency "rspec"
22
+ s.add_development_dependency "autotest"
23
+ s.add_development_dependency "sqlite3"
24
+ s.add_development_dependency "fakeredis"
25
+ end
@@ -0,0 +1,19 @@
1
+ sqlite3:
2
+ adapter: sqlite3
3
+ database: redis_column.sqlite3
4
+
5
+ mysql:
6
+ adapter: mysql2
7
+ hostname: localhost
8
+ username: root
9
+ password:
10
+ database: redis_column
11
+ charset: utf8
12
+
13
+ postgresql:
14
+ adapter: postgresql
15
+ hostname: localhost
16
+ username: postgres
17
+ password:
18
+ database: redis_column
19
+ encoding: utf8
@@ -0,0 +1,6 @@
1
+ class TestModel < ActiveRecord::Base; end
2
+
3
+ class DescriptionInRedisModel < TestModel
4
+ redis_col :description
5
+ end
6
+
@@ -0,0 +1,12 @@
1
+ ActiveRecord::Schema.define :version => 0 do
2
+ create_table "test_models", :force => true do |t|
3
+ t.integer "integer"
4
+ t.datetime "created_at"
5
+ t.string "type", :default => 'TestModel'
6
+ t.string "string"
7
+ end
8
+
9
+ add_index "test_models", ["integer"], :name => "index_test_models_on_integer"
10
+ add_index "test_models", ["created_at"], :name => "index_test_models_on_created_at"
11
+ add_index "test_models", ["type"], :name => "index_test_models_on_type"
12
+ end
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+
3
+ describe TestModel do
4
+ it { TestModel.should respond_to(:redis_column) }
5
+ it { TestModel.should respond_to(:redis_col) }
6
+ it { TestModel.should respond_to(:redis_columns) }
7
+
8
+ describe 'redis_column' do
9
+ context 'with no arguments' do
10
+ it "should raise an argument error" do
11
+ lambda { TestModel.redis_column }.should raise_error(ArgumentError)
12
+ end
13
+ end
14
+
15
+ context "with a column_name" do
16
+ it "should add the column_name to the redis_columns array" do
17
+ TestModel.redis_columns.should == []
18
+ TestModel.redis_column :body
19
+ TestModel.redis_columns.should == [:body]
20
+ end
21
+
22
+ it "should add an accessor for the column_name" do
23
+ TestModel.redis_column :body
24
+ TestModel.new.should respond_to(:body)
25
+ TestModel.new.should respond_to(:body=)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ describe DescriptionInRedisModel do
32
+ it "should have a redis_column for the description attribute" do
33
+ DescriptionInRedisModel.redis_columns.should == [:description]
34
+ end
35
+
36
+ it "should have a default redis key of '<model_name>:<id>:<column_name>' for the description attribute" do
37
+ instance = DescriptionInRedisModel.create
38
+ instance.redis_key(:description).should == "description_in_redis_model:#{instance.id}:description"
39
+ end
40
+
41
+ context "before save" do
42
+ it "should not have stored the description in redis" do
43
+ instance = DescriptionInRedisModel.new(description: "A looong description")
44
+ RedisColumn.redis_instance.get("description_in_redis_model:#{instance.id}:description").should_not be("A looong description".to_yaml)
45
+ end
46
+ end
47
+
48
+ context "when saving" do
49
+ it "should store the description in redis, with the key '<model_name>:<id>:<column_name>'" do
50
+ instance = DescriptionInRedisModel.create!(description: "A looong description")
51
+ RedisColumn.redis_instance.get("description_in_redis_model:#{instance.id}:description").should == "A looong description".to_yaml
52
+ end
53
+ end
54
+
55
+ context "when saved" do
56
+ it "should retrive the description from redis, with the key '<model_name>:<id>:<column_name>'" do
57
+ instance = DescriptionInRedisModel.create!(description: "A looong description")
58
+ instance = DescriptionInRedisModel.find(instance.id)
59
+ instance.description.should == "A looong description"
60
+ end
61
+
62
+ it "should return the redis_columns within :attributes" do
63
+ instance = DescriptionInRedisModel.create!(string: "A string", description: "A looong description")
64
+ instance.attributes.should have_key('string')
65
+ instance.attributes.should have_key('description')
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,66 @@
1
+ $LOAD_PATH << "." unless $LOAD_PATH.include?(".")
2
+ require 'logger'
3
+
4
+ begin
5
+ require "rubygems"
6
+ require "bundler"
7
+
8
+ if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("0.9.5")
9
+ raise RuntimeError, "Your bundler version is too old." +
10
+ "Run `gem install bundler` to upgrade."
11
+ end
12
+
13
+ # Set up load paths for all bundled gems
14
+ Bundler.setup
15
+ rescue Bundler::GemNotFound
16
+ raise RuntimeError, "Bundler couldn't find some gems." +
17
+ "Did you run \`bundlee install\`?"
18
+ end
19
+
20
+ Bundler.require
21
+ require File.expand_path('../../lib/redis-column', __FILE__)
22
+ require "fakeredis"
23
+ db_name = ENV['DB'] || 'sqlite3'
24
+ database_yml = File.expand_path('../config/database.yml', __FILE__)
25
+
26
+ if File.exists?(database_yml)
27
+ active_record_configuration = YAML.load_file(database_yml)
28
+
29
+ ActiveRecord::Base.configurations = active_record_configuration
30
+ config = ActiveRecord::Base.configurations[db_name]
31
+
32
+ begin
33
+ ActiveRecord::Base.establish_connection(db_name)
34
+ ActiveRecord::Base.connection
35
+ rescue
36
+ case db_name
37
+ when /mysql/
38
+ ActiveRecord::Base.establish_connection(config.merge('database' => nil))
39
+ ActiveRecord::Base.connection.create_database(config['database'], {:charset => 'utf8', :collation => 'utf8_unicode_ci'})
40
+ when 'postgresql'
41
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
42
+ ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => 'utf8'))
43
+ end
44
+
45
+ ActiveRecord::Base.establish_connection(config)
46
+ end
47
+
48
+ ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "debug.log"))
49
+ ActiveRecord::Base.default_timezone = :utc
50
+
51
+ ActiveRecord::Base.silence do
52
+ ActiveRecord::Migration.verbose = false
53
+
54
+ load(File.dirname(__FILE__) + '/config/schema.rb')
55
+ load(File.dirname(__FILE__) + '/config/models.rb')
56
+ end
57
+
58
+ else
59
+ raise "Please create #{database_yml} first to configure your database. Take a look at: #{database_yml}.sample"
60
+ end
61
+
62
+ def clean_database!
63
+ ActiveRecord::Base.connection.execute "DELETE FROM test_models"
64
+ end
65
+
66
+ clean_database!
metadata ADDED
@@ -0,0 +1,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: redis-column
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alex Neill
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: &2152025520 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2152025520
25
+ - !ruby/object:Gem::Dependency
26
+ name: redis
27
+ requirement: &2152025060 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2152025060
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &2152024300 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2152024300
47
+ - !ruby/object:Gem::Dependency
48
+ name: autotest
49
+ requirement: &2152023600 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2152023600
58
+ - !ruby/object:Gem::Dependency
59
+ name: sqlite3
60
+ requirement: &2152022840 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2152022840
69
+ - !ruby/object:Gem::Dependency
70
+ name: fakeredis
71
+ requirement: &2152022260 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *2152022260
80
+ description: The RedisColumn gem allows for the seamless integration of Redis within
81
+ your ActiveRecord model in order to store heavy objects away from tables with a
82
+ lot of rows.
83
+ email:
84
+ - alex.neill@gmail.com
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - .gitignore
90
+ - .rspec
91
+ - .rvmrc
92
+ - Gemfile
93
+ - README.md
94
+ - Rakefile
95
+ - lib/redis-column.rb
96
+ - lib/redis-column/version.rb
97
+ - redis-column.gemspec
98
+ - spec/config/database.yml.sample
99
+ - spec/config/models.rb
100
+ - spec/config/schema.rb
101
+ - spec/redis_column_spec.rb
102
+ - spec/spec_helper.rb
103
+ homepage: https://github.com/ajn/redis-column
104
+ licenses: []
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ requirements: []
122
+ rubyforge_project:
123
+ rubygems_version: 1.8.10
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Seamlessly extend your AR model with Redis
127
+ test_files: []