frivol 0.1.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.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Marc Heiligers
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,19 @@
1
+ = Frivol
2
+
3
+ A really simple Redis-backed temporary storage mechanism.
4
+
5
+ Also extends Time to allow it to be (de)serialized to JSON.
6
+
7
+ == Note on Patches/Pull Requests
8
+
9
+ * Fork the project.
10
+ * Make your feature addition or bug fix.
11
+ * Add tests for it. This is important so I don't break it in a
12
+ future version unintentionally.
13
+ * Commit, do not mess with rakefile, version, or history.
14
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
15
+ * Send me a pull request. Bonus points for topic branches.
16
+
17
+ == Copyright
18
+
19
+ Copyright (c) 2010 Marc Heiligers. See LICENSE for details.
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "frivol"
8
+ gem.summary = %Q{Simple Redis backed temporary storage}
9
+ gem.description = %Q{Simple Redis backed temporary storage intended primarily for use with ActiveRecord models to provide caching}
10
+ gem.email = "marc@eternal.co.za"
11
+ gem.homepage = "http://github.com/marcheiligers/frivol"
12
+ gem.authors = ["Marc Heiligers"]
13
+ gem.add_development_dependency "shoulda", ">= 2"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "frivol #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,56 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{frivol}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Marc Heiligers"]
12
+ s.date = %q{2010-08-20}
13
+ s.description = %q{Simple Redis backed temporary storage intended primarily for use with ActiveRecord models to provide caching}
14
+ s.email = %q{marc@eternal.co.za}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "frivol.gemspec",
27
+ "lib/frivol.rb",
28
+ "test/fake_redis.rb",
29
+ "test/helper.rb",
30
+ "test/test_frivol.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/marcheiligers/frivol}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.7}
36
+ s.summary = %q{Simple Redis backed temporary storage}
37
+ s.test_files = [
38
+ "test/fake_redis.rb",
39
+ "test/helper.rb",
40
+ "test/test_frivol.rb"
41
+ ]
42
+
43
+ if s.respond_to? :specification_version then
44
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
45
+ s.specification_version = 3
46
+
47
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
48
+ s.add_development_dependency(%q<shoulda>, [">= 2"])
49
+ else
50
+ s.add_dependency(%q<shoulda>, [">= 2"])
51
+ end
52
+ else
53
+ s.add_dependency(%q<shoulda>, [">= 2"])
54
+ end
55
+ end
56
+
@@ -0,0 +1,95 @@
1
+ require "json"
2
+ require "redis"
3
+
4
+ module Frivol
5
+ def store(keys_and_values)
6
+ Frivol::Helpers.retrieve_hash self
7
+ keys_and_values.each do |key, value|
8
+ @frivol_hash[key.to_s] = value
9
+ end
10
+ Frivol::Helpers.store_hash self
11
+ end
12
+
13
+ def retrieve(keys_and_defaults)
14
+ Frivol::Helpers.retrieve_hash self
15
+ result = keys_and_defaults.map do |key, default|
16
+ @frivol_hash[key.to_s] || (respond_to?(default) && send(default)) || default
17
+ end
18
+ return result.first if result.size == 1
19
+ result
20
+ end
21
+
22
+ def expire_storage(time)
23
+ return if time.nil?
24
+ Frivol::Config.redis.expire storage_key, time
25
+ end
26
+
27
+ def storage_key
28
+ @frivol_key ||= "#{self.class.name}-#{id}"
29
+ end
30
+
31
+ module Config
32
+ def self.redis_config=(config)
33
+ @@redis = Redis.new(config)
34
+ end
35
+
36
+ def self.redis
37
+ @@redis
38
+ end
39
+
40
+ def self.include_in(host_class, storage_expires_in = nil)
41
+ host_class.send(:include, Frivol)
42
+ host_class.storage_expires_in storage_expires_in if storage_expires_in
43
+ end
44
+ end
45
+
46
+ module Helpers
47
+ def self.store_hash(instance)
48
+ hash = instance.instance_variable_get(:@frivol_hash)
49
+ is_new = instance.instance_variable_get(:@frivol_is_new)
50
+ key = instance.send(:storage_key)
51
+ Frivol::Config.redis[key] = hash.to_json
52
+ if is_new
53
+ instance.expire_storage instance.class.storage_expiry
54
+ instance.instance_variable_set :@frivol_is_new, false
55
+ end
56
+ end
57
+
58
+ def self.retrieve_hash(instance)
59
+ return instance.instance_variable_get(:@frivol_hash) if instance.instance_variable_defined? :@frivol_hash
60
+ key = instance.send(:storage_key)
61
+ json = Frivol::Config.redis[key]
62
+ instance.instance_variable_set :@frivol_is_new, json.nil?
63
+ hash = json.nil? ? {} : JSON.parse(json)
64
+ instance.instance_variable_set :@frivol_hash, hash
65
+ hash
66
+ end
67
+ end
68
+
69
+ module ClassMethods
70
+ def storage_expires_in(time)
71
+ @frivol_storage_expiry = time
72
+ end
73
+
74
+ def storage_expiry
75
+ @frivol_storage_expiry
76
+ end
77
+ end
78
+
79
+ def self.included(host)
80
+ host.extend(ClassMethods)
81
+ end
82
+ end
83
+
84
+ class Time
85
+ def to_json(*a)
86
+ {
87
+ 'json_class' => self.class.name,
88
+ 'data' => self.to_s
89
+ }.to_json(*a)
90
+ end
91
+
92
+ def self.json_create(o)
93
+ Time.parse(*o['data'])
94
+ end
95
+ end
@@ -0,0 +1,20 @@
1
+ class Redis
2
+ def initialize(config)
3
+ @storage = {}
4
+ end
5
+
6
+ def [](key)
7
+ # puts "retrieve #{key}"
8
+ @storage[key]
9
+ end
10
+
11
+ def []=(key, value)
12
+ # puts "store #{key}"
13
+ @storage[key] = value
14
+ end
15
+
16
+ def expire(key, time)
17
+ # Hmm, let's not do anything here
18
+ # puts "expiring #{key} in #{time}"
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'frivol'
9
+
10
+ class Test::Unit::TestCase
11
+ def fake_redis
12
+ require 'fake_redis'
13
+ end
14
+ end
15
+
16
+ class TestClass
17
+ include Frivol
18
+
19
+ def id
20
+ 1
21
+ end
22
+
23
+ def save
24
+ store :value => "value"
25
+ end
26
+
27
+ def load
28
+ retrieve :value => "junk"
29
+ end
30
+ end
@@ -0,0 +1,113 @@
1
+ require 'helper'
2
+
3
+ class TestFrivol < Test::Unit::TestCase
4
+ def setup
5
+ fake_redis
6
+ Frivol::Config.redis_config = {}
7
+ end
8
+
9
+ should "have a default storage key made up of the class name and id" do
10
+ t = TestClass.new
11
+ assert_equal "TestClass-1", t.storage_key
12
+ end
13
+
14
+ should "store and retrieve data" do
15
+ t = TestClass.new
16
+ t.save
17
+ assert_equal "value", t.load
18
+ end
19
+
20
+ should "return a default for a value that's not in storage" do
21
+ t = TestClass.new
22
+ assert_equal "junk", t.load
23
+ end
24
+
25
+ should "save and retrieve multiple values" do
26
+ class MultiTestClass < TestClass
27
+ def save
28
+ store :val1 => 1, :val2 => 2
29
+ end
30
+
31
+ def load
32
+ retrieve :val1 => nil, :val2 => nil
33
+ end
34
+ end
35
+
36
+ t = MultiTestClass.new
37
+ t.save
38
+ assert_equal [ 1, 2 ], t.load
39
+ end
40
+
41
+ should "get defaults from instance methods if defined" do
42
+ class DefaultsTestClass < TestClass
43
+ def load
44
+ retrieve :value => nil, :value2 => :value2_default
45
+ end
46
+
47
+ def value2_default
48
+ "value2"
49
+ end
50
+ end
51
+
52
+ t = DefaultsTestClass.new
53
+ t.save
54
+ assert_equal [ "value", "value2" ], t.load
55
+ end
56
+
57
+ should "be able to override the key method" do
58
+ class OverrideKeyTestClass < TestClass
59
+ def storage_key
60
+ "my_storage"
61
+ end
62
+ end
63
+
64
+ t = OverrideKeyTestClass.new
65
+ t.save
66
+ assert_equal "value", t.load
67
+ assert Frivol::Config.redis["my_storage"]
68
+ end
69
+
70
+ should "retain Times as Times" do
71
+ class TimeTestClass < TestClass
72
+ def save
73
+ store :t => Time.local(2010, 8, 20)
74
+ end
75
+
76
+ def load
77
+ retrieve :t => nil
78
+ end
79
+ end
80
+
81
+ t = TimeTestClass.new
82
+ t.save
83
+ assert_equal Time.local(2010, 8, 20), t.load
84
+ end
85
+
86
+ should "expire storage the first time it's stored" do
87
+ class ExpiryTestClass < TestClass
88
+ storage_expires_in 60
89
+ end
90
+
91
+ Frivol::Config.redis.expects(:expire).once
92
+ t = ExpiryTestClass.new
93
+ t.load
94
+ t.save
95
+ t.save
96
+ end
97
+
98
+ should "be able to include in other classes with storage expiry" do
99
+ class BlankTestClass
100
+ end
101
+ Frivol::Config.include_in(BlankTestClass, 30)
102
+ t = BlankTestClass.new
103
+ assert t.respond_to? :store
104
+ assert_equal 30, BlankTestClass.storage_expiry
105
+ end
106
+
107
+ should "return the already loaded hash if it's already loaded" do
108
+ Frivol::Config.redis.expects(:[]).once
109
+ t = TestClass.new
110
+ t.load
111
+ t.load
112
+ end
113
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: frivol
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Marc Heiligers
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-20 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: shoulda
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 2
32
+ version: "2"
33
+ type: :development
34
+ version_requirements: *id001
35
+ description: Simple Redis backed temporary storage intended primarily for use with ActiveRecord models to provide caching
36
+ email: marc@eternal.co.za
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.rdoc
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.rdoc
49
+ - Rakefile
50
+ - VERSION
51
+ - frivol.gemspec
52
+ - lib/frivol.rb
53
+ - test/fake_redis.rb
54
+ - test/helper.rb
55
+ - test/test_frivol.rb
56
+ has_rdoc: true
57
+ homepage: http://github.com/marcheiligers/frivol
58
+ licenses: []
59
+
60
+ post_install_message:
61
+ rdoc_options:
62
+ - --charset=UTF-8
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
73
+ version: "0"
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
82
+ version: "0"
83
+ requirements: []
84
+
85
+ rubyforge_project:
86
+ rubygems_version: 1.3.7
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: Simple Redis backed temporary storage
90
+ test_files:
91
+ - test/fake_redis.rb
92
+ - test/helper.rb
93
+ - test/test_frivol.rb