jqr-versionable 0.0.3
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/CHANGELOG +5 -0
- data/Manifest +10 -0
- data/README.rdoc +54 -0
- data/Rakefile +21 -0
- data/init.rb +1 -0
- data/lib/versionable.rb +81 -0
- data/spec/fake_cache.rb +16 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/versionable.spec +48 -0
- data/versionable.gemspec +34 -0
- metadata +77 -0
data/CHANGELOG
ADDED
data/Manifest
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= Versionable
|
2
|
+
|
3
|
+
Super fast and easy versioning for models and associations. Do cache lookups
|
4
|
+
using this fast version number instead of managing complex cache expiry.
|
5
|
+
|
6
|
+
Versionable is intended for versioning of a model or an association and doesn't
|
7
|
+
currently provide any means of caching version numbers for normal model
|
8
|
+
instances.
|
9
|
+
|
10
|
+
== Examples
|
11
|
+
|
12
|
+
# A simple User model with a User.cached_all method that returns all users
|
13
|
+
# in the application. This method is cached and will automatically "expire"
|
14
|
+
# whenever a record is saved or you call User.new_version.
|
15
|
+
|
16
|
+
class User < ActiveRecord::Base
|
17
|
+
versionable :cache => Rails.cache
|
18
|
+
|
19
|
+
after_save { new_version }
|
20
|
+
|
21
|
+
def self.cached_all
|
22
|
+
# reference version in cache keys
|
23
|
+
Rails.cache.fetch("User.cached_all:#{version}") { all }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
>> User.cached_all # initial cache miss and cache fill
|
28
|
+
>> User.cached_all # cache hit
|
29
|
+
|
30
|
+
>> User.new_version # => 1224985243
|
31
|
+
>> User.cached_all # new cache miss and cache fill
|
32
|
+
|
33
|
+
>> User.first.save # causing new_version to be called from after_save
|
34
|
+
>> User.cached_all # new cache miss and cache fill
|
35
|
+
|
36
|
+
|
37
|
+
You can also use it on associations...
|
38
|
+
|
39
|
+
|
40
|
+
== Install
|
41
|
+
|
42
|
+
As a Rails plugin.
|
43
|
+
|
44
|
+
./script/plugin install git://github.com/jqr/versionable.git
|
45
|
+
|
46
|
+
Prefer gems? Add this to your environment.rb and run the following command.
|
47
|
+
|
48
|
+
config.gem 'jqr-versionable', :lib => 'versionable', :source => 'http://gems.github.com'
|
49
|
+
|
50
|
+
$ rake gems:install
|
51
|
+
|
52
|
+
|
53
|
+
Homepage:: http://github.com/jqr/versionable/tree/master
|
54
|
+
License:: Copyright (c) 2008 Elijah Miller <mailto:elijah.miller@gmail.com>, released under the MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec/rake/spectask'
|
2
|
+
|
3
|
+
require 'echoe'
|
4
|
+
Echoe.new 'versionable' do |p|
|
5
|
+
p.description = "Simple versioning for Ruby objects using only the Rails cache."
|
6
|
+
# p.url = "http://versionable.rubyforge.org"
|
7
|
+
p.author = "Elijah Miller"
|
8
|
+
p.email = "elijah.miller@gmail.com"
|
9
|
+
p.retain_gemspec = true
|
10
|
+
p.need_tar_gz = false
|
11
|
+
p.extra_deps = [
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
desc 'Default: run specs'
|
16
|
+
task :default => :spec
|
17
|
+
Spec::Rake::SpecTask.new do |t|
|
18
|
+
t.spec_files = FileList["spec/**/*_spec.rb"]
|
19
|
+
end
|
20
|
+
|
21
|
+
task :test => :spec
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'versionable'
|
data/lib/versionable.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
class Object
|
2
|
+
# For extending models and assocations to provide an time based version number
|
3
|
+
# for cache expiration by changing part of the key we lookup the cache by.
|
4
|
+
def versionable(options = {})
|
5
|
+
default_options = {
|
6
|
+
# :cache => Rails.cache,
|
7
|
+
:ttl => 0
|
8
|
+
}
|
9
|
+
instance_eval "
|
10
|
+
class << self
|
11
|
+
attr_accessor :versionable_options
|
12
|
+
end
|
13
|
+
"
|
14
|
+
self.versionable_options = default_options.merge(options)
|
15
|
+
|
16
|
+
include Versionable
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Versionable
|
21
|
+
|
22
|
+
def self.included(base)
|
23
|
+
base.extend ClassMethods
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
# Returns the current version of the assocation. Likely to be nil.
|
28
|
+
def version
|
29
|
+
versionable_options[:cache].read(version_cache_key)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Sets the version of this assocation to the current time in integer form.
|
33
|
+
def new_version
|
34
|
+
# the expiry needs to be longer than any page that might use this as a
|
35
|
+
# cache key.
|
36
|
+
time = Time.now.to_i
|
37
|
+
versionable_options[:cache].write(version_cache_key, time, :expires_in => versionable_options[:ttl])
|
38
|
+
time
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns the association version key.
|
42
|
+
def version_cache_key
|
43
|
+
parts =
|
44
|
+
if object.class == Class
|
45
|
+
[object]
|
46
|
+
else
|
47
|
+
[object.class, object.id]
|
48
|
+
end
|
49
|
+
|
50
|
+
parts << version_name
|
51
|
+
parts * ':'
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the object that version applies to.
|
55
|
+
def object
|
56
|
+
if inside_association?
|
57
|
+
proxy_owner
|
58
|
+
else
|
59
|
+
self
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns the name portion of the version cache key
|
64
|
+
def version_name
|
65
|
+
if inside_association?
|
66
|
+
"#{proxy_reflection.name}_version"
|
67
|
+
else
|
68
|
+
"version"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Returns true if this is called with the context available to an
|
75
|
+
# assocation.
|
76
|
+
def inside_association?
|
77
|
+
# TODO: see if we can memoize
|
78
|
+
self.respond_to?(:proxy_owner)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/spec/fake_cache.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe Versionable do
|
4
|
+
describe "initializing" do
|
5
|
+
it "should allow initializing without any options" do
|
6
|
+
lambda {
|
7
|
+
class DefaultListy
|
8
|
+
versionable
|
9
|
+
end
|
10
|
+
}.should_not raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should store options in Class.versionable_options" do
|
14
|
+
class TTLListy
|
15
|
+
versionable :ttl => 60
|
16
|
+
end
|
17
|
+
|
18
|
+
TTLListy.versionable_options.should == { :ttl => 60 }
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "versioning" do
|
24
|
+
before(:each) do
|
25
|
+
class Listy
|
26
|
+
versionable :cache => FakeCache.new, :ttl => 30
|
27
|
+
end
|
28
|
+
@cache = Listy.versionable_options[:cache]
|
29
|
+
@ttl = Listy.versionable_options[:ttl]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should start off with a nil version" do
|
33
|
+
Listy.version.should == nil
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should have a version after calling new_version" do
|
37
|
+
Listy.new_version
|
38
|
+
Listy.new_version.should_not be_nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should set the version with the TTL from the options" do
|
42
|
+
@cache.should_receive(:write).with(anything, anything, hash_including(:expires_in => 30))
|
43
|
+
Listy.new_version
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/versionable.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{versionable}
|
5
|
+
s.version = "0.0.3"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Elijah Miller"]
|
9
|
+
s.date = %q{2009-02-09}
|
10
|
+
s.description = %q{Simple versioning for Ruby objects using only the Rails cache.}
|
11
|
+
s.email = %q{elijah.miller@gmail.com}
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/versionable.rb", "README.rdoc"]
|
13
|
+
s.files = ["CHANGELOG", "init.rb", "lib/versionable.rb", "Manifest", "Rakefile", "README.rdoc", "spec/fake_cache.rb", "spec/spec_helper.rb", "spec/versionable.spec", "versionable.gemspec"]
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.homepage = %q{}
|
16
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Versionable", "--main", "README.rdoc"]
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
s.rubyforge_project = %q{versionable}
|
19
|
+
s.rubygems_version = %q{1.3.1}
|
20
|
+
s.summary = %q{Simple versioning for Ruby objects using only the Rails cache.}
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 2
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_development_dependency(%q<echoe>, [">= 0"])
|
28
|
+
else
|
29
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
30
|
+
end
|
31
|
+
else
|
32
|
+
s.add_dependency(%q<echoe>, [">= 0"])
|
33
|
+
end
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jqr-versionable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elijah Miller
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-09 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: echoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
description: Simple versioning for Ruby objects using only the Rails cache.
|
25
|
+
email: elijah.miller@gmail.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- CHANGELOG
|
32
|
+
- lib/versionable.rb
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- CHANGELOG
|
36
|
+
- init.rb
|
37
|
+
- lib/versionable.rb
|
38
|
+
- Manifest
|
39
|
+
- Rakefile
|
40
|
+
- README.rdoc
|
41
|
+
- spec/fake_cache.rb
|
42
|
+
- spec/spec_helper.rb
|
43
|
+
- spec/versionable.spec
|
44
|
+
- versionable.gemspec
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: ""
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options:
|
49
|
+
- --line-numbers
|
50
|
+
- --inline-source
|
51
|
+
- --title
|
52
|
+
- Versionable
|
53
|
+
- --main
|
54
|
+
- README.rdoc
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "1.2"
|
68
|
+
version:
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project: versionable
|
72
|
+
rubygems_version: 1.2.0
|
73
|
+
signing_key:
|
74
|
+
specification_version: 2
|
75
|
+
summary: Simple versioning for Ruby objects using only the Rails cache.
|
76
|
+
test_files: []
|
77
|
+
|