frivol 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +64 -3
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/doc/classes/Frivol.html +303 -0
- data/doc/classes/Frivol.src/M000003.html +22 -0
- data/doc/classes/Frivol.src/M000004.html +23 -0
- data/doc/classes/Frivol.src/M000005.html +19 -0
- data/doc/classes/Frivol.src/M000006.html +18 -0
- data/doc/classes/Frivol/ClassMethods.html +178 -0
- data/doc/classes/Frivol/ClassMethods.src/M000007.html +18 -0
- data/doc/classes/Frivol/ClassMethods.src/M000008.html +18 -0
- data/doc/classes/Frivol/Config.html +230 -0
- data/doc/classes/Frivol/Config.src/M000009.html +18 -0
- data/doc/classes/Frivol/Config.src/M000010.html +18 -0
- data/doc/classes/Frivol/Config.src/M000011.html +19 -0
- data/doc/classes/Time.html +191 -0
- data/doc/classes/Time.src/M000001.html +21 -0
- data/doc/classes/Time.src/M000002.html +18 -0
- data/doc/created.rid +1 -0
- data/doc/files/lib/frivol_rb.html +204 -0
- data/doc/fr_class_index.html +30 -0
- data/doc/fr_file_index.html +27 -0
- data/doc/fr_method_index.html +38 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/frivol.gemspec +33 -5
- data/lib/frivol.rb +128 -2
- data/test/fake_redis.rb +6 -0
- data/test/helper.rb +1 -1
- data/test/test_frivol.rb +10 -3
- metadata +64 -8
@@ -0,0 +1,30 @@
|
|
1
|
+
|
2
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
3
|
+
<!DOCTYPE html
|
4
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
5
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
6
|
+
|
7
|
+
<!--
|
8
|
+
|
9
|
+
Classes
|
10
|
+
|
11
|
+
-->
|
12
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
13
|
+
<head>
|
14
|
+
<title>Classes</title>
|
15
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
16
|
+
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
|
17
|
+
<base target="docwin" />
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<div id="index">
|
21
|
+
<h1 class="section-bar">Classes</h1>
|
22
|
+
<div id="index-entries">
|
23
|
+
<a href="classes/Frivol.html">Frivol</a><br />
|
24
|
+
<a href="classes/Frivol/ClassMethods.html">Frivol::ClassMethods</a><br />
|
25
|
+
<a href="classes/Frivol/Config.html">Frivol::Config</a><br />
|
26
|
+
<a href="classes/Time.html">Time</a><br />
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
</body>
|
30
|
+
</html>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
3
|
+
<!DOCTYPE html
|
4
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
5
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
6
|
+
|
7
|
+
<!--
|
8
|
+
|
9
|
+
Files
|
10
|
+
|
11
|
+
-->
|
12
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
13
|
+
<head>
|
14
|
+
<title>Files</title>
|
15
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
16
|
+
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
|
17
|
+
<base target="docwin" />
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<div id="index">
|
21
|
+
<h1 class="section-bar">Files</h1>
|
22
|
+
<div id="index-entries">
|
23
|
+
<a href="files/lib/frivol_rb.html">lib/frivol.rb</a><br />
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
</body>
|
27
|
+
</html>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
3
|
+
<!DOCTYPE html
|
4
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
5
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
6
|
+
|
7
|
+
<!--
|
8
|
+
|
9
|
+
Methods
|
10
|
+
|
11
|
+
-->
|
12
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
13
|
+
<head>
|
14
|
+
<title>Methods</title>
|
15
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
16
|
+
<link rel="stylesheet" href="rdoc-style.css" type="text/css" />
|
17
|
+
<base target="docwin" />
|
18
|
+
</head>
|
19
|
+
<body>
|
20
|
+
<div id="index">
|
21
|
+
<h1 class="section-bar">Methods</h1>
|
22
|
+
<div id="index-entries">
|
23
|
+
<a href="classes/Frivol.html#M000005">delete_storage (Frivol)</a><br />
|
24
|
+
<a href="classes/Frivol.html#M000006">expire_storage (Frivol)</a><br />
|
25
|
+
<a href="classes/Frivol/Config.html#M000012">include_in (Frivol::Config)</a><br />
|
26
|
+
<a href="classes/Time.html#M000002">json_create (Time)</a><br />
|
27
|
+
<a href="classes/Frivol/Config.html#M000011">redis (Frivol::Config)</a><br />
|
28
|
+
<a href="classes/Frivol/Config.html#M000010">redis_config= (Frivol::Config)</a><br />
|
29
|
+
<a href="classes/Frivol.html#M000004">retrieve (Frivol)</a><br />
|
30
|
+
<a href="classes/Frivol/ClassMethods.html#M000008">storage_expires_in (Frivol::ClassMethods)</a><br />
|
31
|
+
<a href="classes/Frivol/ClassMethods.html#M000009">storage_expiry (Frivol::ClassMethods)</a><br />
|
32
|
+
<a href="classes/Frivol.html#M000007">storage_key (Frivol)</a><br />
|
33
|
+
<a href="classes/Frivol.html#M000003">store (Frivol)</a><br />
|
34
|
+
<a href="classes/Time.html#M000001">to_json (Time)</a><br />
|
35
|
+
</div>
|
36
|
+
</div>
|
37
|
+
</body>
|
38
|
+
</html>
|
data/doc/index.html
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
|
5
|
+
|
6
|
+
<!--
|
7
|
+
|
8
|
+
Frivol - Frivolously simple temporary storage backed by Redis
|
9
|
+
|
10
|
+
-->
|
11
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
12
|
+
<head>
|
13
|
+
<title>Frivol - Frivolously simple temporary storage backed by Redis</title>
|
14
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
15
|
+
</head>
|
16
|
+
<frameset rows="20%, 80%">
|
17
|
+
<frameset cols="25%,35%,45%">
|
18
|
+
<frame src="fr_file_index.html" title="Files" name="Files" />
|
19
|
+
<frame src="fr_class_index.html" name="Classes" />
|
20
|
+
<frame src="fr_method_index.html" name="Methods" />
|
21
|
+
</frameset>
|
22
|
+
<frame src="files/lib/frivol_rb.html" name="docwin" />
|
23
|
+
</frameset>
|
24
|
+
</html>
|
data/doc/rdoc-style.css
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
|
2
|
+
body {
|
3
|
+
font-family: Verdana,Arial,Helvetica,sans-serif;
|
4
|
+
font-size: 90%;
|
5
|
+
margin: 0;
|
6
|
+
margin-left: 40px;
|
7
|
+
padding: 0;
|
8
|
+
background: white;
|
9
|
+
}
|
10
|
+
|
11
|
+
h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
|
12
|
+
h1 { font-size: 150%; }
|
13
|
+
h2,h3,h4 { margin-top: 1em; }
|
14
|
+
|
15
|
+
a { background: #eef; color: #039; text-decoration: none; }
|
16
|
+
a:hover { background: #039; color: #eef; }
|
17
|
+
|
18
|
+
/* Override the base stylesheet's Anchor inside a table cell */
|
19
|
+
td > a {
|
20
|
+
background: transparent;
|
21
|
+
color: #039;
|
22
|
+
text-decoration: none;
|
23
|
+
}
|
24
|
+
|
25
|
+
/* and inside a section title */
|
26
|
+
.section-title > a {
|
27
|
+
background: transparent;
|
28
|
+
color: #eee;
|
29
|
+
text-decoration: none;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* === Structural elements =================================== */
|
33
|
+
|
34
|
+
div#index {
|
35
|
+
margin: 0;
|
36
|
+
margin-left: -40px;
|
37
|
+
padding: 0;
|
38
|
+
font-size: 90%;
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
div#index a {
|
43
|
+
margin-left: 0.7em;
|
44
|
+
}
|
45
|
+
|
46
|
+
div#index .section-bar {
|
47
|
+
margin-left: 0px;
|
48
|
+
padding-left: 0.7em;
|
49
|
+
background: #ccc;
|
50
|
+
font-size: small;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
div#classHeader, div#fileHeader {
|
55
|
+
width: auto;
|
56
|
+
color: white;
|
57
|
+
padding: 0.5em 1.5em 0.5em 1.5em;
|
58
|
+
margin: 0;
|
59
|
+
margin-left: -40px;
|
60
|
+
border-bottom: 3px solid #006;
|
61
|
+
}
|
62
|
+
|
63
|
+
div#classHeader a, div#fileHeader a {
|
64
|
+
background: inherit;
|
65
|
+
color: white;
|
66
|
+
}
|
67
|
+
|
68
|
+
div#classHeader td, div#fileHeader td {
|
69
|
+
background: inherit;
|
70
|
+
color: white;
|
71
|
+
}
|
72
|
+
|
73
|
+
|
74
|
+
div#fileHeader {
|
75
|
+
background: #057;
|
76
|
+
}
|
77
|
+
|
78
|
+
div#classHeader {
|
79
|
+
background: #048;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
.class-name-in-header {
|
84
|
+
font-size: 180%;
|
85
|
+
font-weight: bold;
|
86
|
+
}
|
87
|
+
|
88
|
+
|
89
|
+
div#bodyContent {
|
90
|
+
padding: 0 1.5em 0 1.5em;
|
91
|
+
}
|
92
|
+
|
93
|
+
div#description {
|
94
|
+
padding: 0.5em 1.5em;
|
95
|
+
background: #efefef;
|
96
|
+
border: 1px dotted #999;
|
97
|
+
}
|
98
|
+
|
99
|
+
div#description h1,h2,h3,h4,h5,h6 {
|
100
|
+
color: #125;;
|
101
|
+
background: transparent;
|
102
|
+
}
|
103
|
+
|
104
|
+
div#validator-badges {
|
105
|
+
text-align: center;
|
106
|
+
}
|
107
|
+
div#validator-badges img { border: 0; }
|
108
|
+
|
109
|
+
div#copyright {
|
110
|
+
color: #333;
|
111
|
+
background: #efefef;
|
112
|
+
font: 0.75em sans-serif;
|
113
|
+
margin-top: 5em;
|
114
|
+
margin-bottom: 0;
|
115
|
+
padding: 0.5em 2em;
|
116
|
+
}
|
117
|
+
|
118
|
+
|
119
|
+
/* === Classes =================================== */
|
120
|
+
|
121
|
+
table.header-table {
|
122
|
+
color: white;
|
123
|
+
font-size: small;
|
124
|
+
}
|
125
|
+
|
126
|
+
.type-note {
|
127
|
+
font-size: small;
|
128
|
+
color: #DEDEDE;
|
129
|
+
}
|
130
|
+
|
131
|
+
.xxsection-bar {
|
132
|
+
background: #eee;
|
133
|
+
color: #333;
|
134
|
+
padding: 3px;
|
135
|
+
}
|
136
|
+
|
137
|
+
.section-bar {
|
138
|
+
color: #333;
|
139
|
+
border-bottom: 1px solid #999;
|
140
|
+
margin-left: -20px;
|
141
|
+
}
|
142
|
+
|
143
|
+
|
144
|
+
.section-title {
|
145
|
+
background: #79a;
|
146
|
+
color: #eee;
|
147
|
+
padding: 3px;
|
148
|
+
margin-top: 2em;
|
149
|
+
margin-left: -30px;
|
150
|
+
border: 1px solid #999;
|
151
|
+
}
|
152
|
+
|
153
|
+
.top-aligned-row { vertical-align: top }
|
154
|
+
.bottom-aligned-row { vertical-align: bottom }
|
155
|
+
|
156
|
+
/* --- Context section classes ----------------------- */
|
157
|
+
|
158
|
+
.context-row { }
|
159
|
+
.context-item-name { font-family: monospace; font-weight: bold; color: black; }
|
160
|
+
.context-item-value { font-size: small; color: #448; }
|
161
|
+
.context-item-desc { color: #333; padding-left: 2em; }
|
162
|
+
|
163
|
+
/* --- Method classes -------------------------- */
|
164
|
+
.method-detail {
|
165
|
+
background: #efefef;
|
166
|
+
padding: 0;
|
167
|
+
margin-top: 0.5em;
|
168
|
+
margin-bottom: 1em;
|
169
|
+
border: 1px dotted #ccc;
|
170
|
+
}
|
171
|
+
.method-heading {
|
172
|
+
color: black;
|
173
|
+
background: #ccc;
|
174
|
+
border-bottom: 1px solid #666;
|
175
|
+
padding: 0.2em 0.5em 0 0.5em;
|
176
|
+
}
|
177
|
+
.method-signature { color: black; background: inherit; }
|
178
|
+
.method-name { font-weight: bold; }
|
179
|
+
.method-args { font-style: italic; }
|
180
|
+
.method-description { padding: 0 0.5em 0 0.5em; }
|
181
|
+
|
182
|
+
/* --- Source code sections -------------------- */
|
183
|
+
|
184
|
+
a.source-toggle { font-size: 90%; }
|
185
|
+
div.method-source-code {
|
186
|
+
background: #262626;
|
187
|
+
color: #ffdead;
|
188
|
+
margin: 1em;
|
189
|
+
padding: 0.5em;
|
190
|
+
border: 1px dashed #999;
|
191
|
+
overflow: hidden;
|
192
|
+
}
|
193
|
+
|
194
|
+
div.method-source-code pre { color: #ffdead; overflow: hidden; }
|
195
|
+
|
196
|
+
/* --- Ruby keyword styles --------------------- */
|
197
|
+
|
198
|
+
.standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
|
199
|
+
|
200
|
+
.ruby-constant { color: #7fffd4; background: transparent; }
|
201
|
+
.ruby-keyword { color: #00ffff; background: transparent; }
|
202
|
+
.ruby-ivar { color: #eedd82; background: transparent; }
|
203
|
+
.ruby-operator { color: #00ffee; background: transparent; }
|
204
|
+
.ruby-identifier { color: #ffdead; background: transparent; }
|
205
|
+
.ruby-node { color: #ffa07a; background: transparent; }
|
206
|
+
.ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
|
207
|
+
.ruby-regexp { color: #ffa07a; background: transparent; }
|
208
|
+
.ruby-value { color: #7fffd4; background: transparent; }
|
data/frivol.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{frivol}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Marc Heiligers"]
|
12
|
-
s.date = %q{2010-08-
|
12
|
+
s.date = %q{2010-08-22}
|
13
13
|
s.description = %q{Simple Redis backed temporary storage intended primarily for use with ActiveRecord models to provide caching}
|
14
14
|
s.email = %q{marc@eternal.co.za}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -23,6 +23,28 @@ Gem::Specification.new do |s|
|
|
23
23
|
"README.rdoc",
|
24
24
|
"Rakefile",
|
25
25
|
"VERSION",
|
26
|
+
"doc/classes/Frivol.html",
|
27
|
+
"doc/classes/Frivol.src/M000003.html",
|
28
|
+
"doc/classes/Frivol.src/M000004.html",
|
29
|
+
"doc/classes/Frivol.src/M000005.html",
|
30
|
+
"doc/classes/Frivol.src/M000006.html",
|
31
|
+
"doc/classes/Frivol/ClassMethods.html",
|
32
|
+
"doc/classes/Frivol/ClassMethods.src/M000007.html",
|
33
|
+
"doc/classes/Frivol/ClassMethods.src/M000008.html",
|
34
|
+
"doc/classes/Frivol/Config.html",
|
35
|
+
"doc/classes/Frivol/Config.src/M000009.html",
|
36
|
+
"doc/classes/Frivol/Config.src/M000010.html",
|
37
|
+
"doc/classes/Frivol/Config.src/M000011.html",
|
38
|
+
"doc/classes/Time.html",
|
39
|
+
"doc/classes/Time.src/M000001.html",
|
40
|
+
"doc/classes/Time.src/M000002.html",
|
41
|
+
"doc/created.rid",
|
42
|
+
"doc/files/lib/frivol_rb.html",
|
43
|
+
"doc/fr_class_index.html",
|
44
|
+
"doc/fr_file_index.html",
|
45
|
+
"doc/fr_method_index.html",
|
46
|
+
"doc/index.html",
|
47
|
+
"doc/rdoc-style.css",
|
26
48
|
"frivol.gemspec",
|
27
49
|
"lib/frivol.rb",
|
28
50
|
"test/fake_redis.rb",
|
@@ -45,12 +67,18 @@ Gem::Specification.new do |s|
|
|
45
67
|
s.specification_version = 3
|
46
68
|
|
47
69
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
48
|
-
s.
|
70
|
+
s.add_runtime_dependency(%q<json>, [">= 1.2.0"])
|
71
|
+
s.add_runtime_dependency(%q<redis>, [">= 0.1.2"])
|
72
|
+
s.add_development_dependency(%q<shoulda>, [">= 2.11.1"])
|
49
73
|
else
|
50
|
-
s.add_dependency(%q<
|
74
|
+
s.add_dependency(%q<json>, [">= 1.2.0"])
|
75
|
+
s.add_dependency(%q<redis>, [">= 0.1.2"])
|
76
|
+
s.add_dependency(%q<shoulda>, [">= 2.11.1"])
|
51
77
|
end
|
52
78
|
else
|
53
|
-
s.add_dependency(%q<
|
79
|
+
s.add_dependency(%q<json>, [">= 1.2.0"])
|
80
|
+
s.add_dependency(%q<redis>, [">= 0.1.2"])
|
81
|
+
s.add_dependency(%q<shoulda>, [">= 2.11.1"])
|
54
82
|
end
|
55
83
|
end
|
56
84
|
|
data/lib/frivol.rb
CHANGED
@@ -1,7 +1,81 @@
|
|
1
|
+
# = Frivol - Frivolously simple temporary storage backed by Redis
|
2
|
+
# A really simple Redis-backed temporary storage mechanism intended to be used with ActiveRecord,
|
3
|
+
# but will work with other ORM's or any classes really.
|
4
|
+
#
|
5
|
+
# I developed Frivol secifically for use in Mad Mimi (http://madmimi.com) to help with caching
|
6
|
+
# of data which requires fairly long running (multi-second) database queries, and also to aid
|
7
|
+
# with communication of status from background Resque jobs running on the workers to the front
|
8
|
+
# end web servers. Redis was chosen because we already had Resque, which is Redis-backed. Also,
|
9
|
+
# unlike memcached, Redis persists it's data to disk, meaning there is far less warmup required
|
10
|
+
# when a hot system is restarted. Frivol's design is such that it solves our problem, but I
|
11
|
+
# believe it is generic enough to be used in many Rails web projects and even in other types of
|
12
|
+
# projects altogether.
|
13
|
+
#
|
14
|
+
# == Usage
|
15
|
+
# Configure Frivol in your configuration, for example in an initializer or in environment.rb
|
16
|
+
# REDIS_CONFIG = {
|
17
|
+
# :host => "localhost",
|
18
|
+
# :port => 6379
|
19
|
+
# }
|
20
|
+
# Frivol::Config.redis_config = REDIS_CONFIG
|
21
|
+
# Now include Frivol in whichever classes you'd like to make use of temporary storage. You can optionally
|
22
|
+
# call the <tt>storage_expires_in(time)</tt> class method to set a default expiry. In your methods you can
|
23
|
+
# now call the <tt>store(keys_and_values)</tt> and <tt>retrieve(keys_and_defaults)</tt> methods.
|
24
|
+
#
|
25
|
+
# Defaults in the +retrieve+ method can be symbols, in which case Frivol will check if the class <tt>respond_to?</tt>
|
26
|
+
# a method by that name to get the default.
|
27
|
+
#
|
28
|
+
# The <tt>expire_storage(time)</tt> method can be used to set the expiry time in seconds of the temporary storage.
|
29
|
+
# The default is not to expire the storage, in which case it will live for as long as Redis keeps it.
|
30
|
+
# <tt>delete_storage</tt>, as the name suggests will immediately delete the storage.
|
31
|
+
#
|
32
|
+
# Frivol uses the +storage_key+ method to create a base key for storage in Redis. The current implementation uses
|
33
|
+
# <tt>"#{self.class.name}-#{id}"</tt> so you'll want to override that method if you have classes that don't
|
34
|
+
# respond to id.
|
35
|
+
#
|
36
|
+
# Frivol also extends Time to allow it to be (de)serialized to JSON, which currently used to store
|
37
|
+
# data in Redis.
|
38
|
+
# == Example
|
39
|
+
# class BigComplexCalcer
|
40
|
+
# include Frivol
|
41
|
+
# storage_expires_in 600 # temporary storage expires in 10 minutes.
|
42
|
+
#
|
43
|
+
# def initialize(key)
|
44
|
+
# @key = key
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# def storage_key
|
48
|
+
# "frivol-test-#{key}" # override the storage key because we don't respond_to? id
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# def big_complex_calc
|
52
|
+
# retrieve :complex => :do_big_complex_calc # do_big_complex_calc is the method to get the default from
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
# def last_calc_done
|
56
|
+
# last = retrieve :last => nil # default is nil
|
57
|
+
# return "never" if last.nil?
|
58
|
+
# return "#{Time.now - last} seconds ago"
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# def do_big_complex_calc
|
62
|
+
# # Wee! Do some really hard work here...
|
63
|
+
# # ...still working...
|
64
|
+
# store :complex => result, :last => Time.now # ...and let's keep the result for at least 10 minutes, as well as the last time we did it
|
65
|
+
# end
|
66
|
+
# end
|
1
67
|
require "json"
|
2
68
|
require "redis"
|
3
69
|
|
70
|
+
# == Frivol
|
4
71
|
module Frivol
|
72
|
+
# Store a hash of keys and values.
|
73
|
+
#
|
74
|
+
# The hash need not be the complete hash of all things stored, just those you want to change.
|
75
|
+
# For example, you may call <tt>store :value1 => 1</tt> and then later call <tt>store :value2 => 2</tt>
|
76
|
+
# and Frivol will now have stored <tt>{ :value1 => 1, :value => 2 }</tt>. How Frivol stores or retrieves data
|
77
|
+
# is intended to be hidden and while it is true that it currently uses a <tt>Hash#to_json</tt> you should not
|
78
|
+
# rely on this.
|
5
79
|
def store(keys_and_values)
|
6
80
|
Frivol::Helpers.retrieve_hash self
|
7
81
|
keys_and_values.each do |key, value|
|
@@ -10,6 +84,15 @@ module Frivol
|
|
10
84
|
Frivol::Helpers.store_hash self
|
11
85
|
end
|
12
86
|
|
87
|
+
# Retrieve stored values, or defaults.
|
88
|
+
#
|
89
|
+
# If you retrieve a single key just that value is returned. If you retrieve multiple keys an array of
|
90
|
+
# values is returned. You might do:
|
91
|
+
# name = retrieve :name => "Marc Heiligers"
|
92
|
+
# first_name, last_name = retrieve :first_name => "Marc", :last_name => "Heiligers"
|
93
|
+
#
|
94
|
+
# If the default is a symbol, Frivol will attempt to get the default from a method named after that symbol.
|
95
|
+
# If the class does not <tt>respond_to?</tt> a method by that name, the symbol will assumed to be the default.
|
13
96
|
def retrieve(keys_and_defaults)
|
14
97
|
Frivol::Helpers.retrieve_hash self
|
15
98
|
result = keys_and_defaults.map do |key, default|
|
@@ -19,31 +102,60 @@ module Frivol
|
|
19
102
|
result
|
20
103
|
end
|
21
104
|
|
105
|
+
# Deletes the stored values.
|
106
|
+
def delete_storage
|
107
|
+
Frivol::Helpers.delete_hash self
|
108
|
+
end
|
109
|
+
|
110
|
+
# Expire the stored data in +time+ seconds.
|
22
111
|
def expire_storage(time)
|
23
112
|
return if time.nil?
|
24
113
|
Frivol::Config.redis.expire storage_key, time
|
25
114
|
end
|
26
115
|
|
116
|
+
# The base key used for storage in Redis.
|
117
|
+
#
|
118
|
+
# This method has been implemented for use with ActiveRecord and uses <tt>"#{self.class.name}-#{id}"</tt>
|
119
|
+
# If you are not using ActiveRecord, or using classes that don't respond to id, you should override
|
120
|
+
# this method in your class.
|
27
121
|
def storage_key
|
28
122
|
@frivol_key ||= "#{self.class.name}-#{id}"
|
29
123
|
end
|
30
124
|
|
125
|
+
# == Frivol::Config
|
126
|
+
# Sets the Frivol configuration (currently only the Redis config), allows access to the configured Redis instance,
|
127
|
+
# and has a helper method to include Frivol in a class with an optional storage expiry parameter
|
31
128
|
module Config
|
129
|
+
# Set the Redis configuration.
|
130
|
+
#
|
131
|
+
# Expects a hash such as
|
132
|
+
# REDIS_CONFIG = {
|
133
|
+
# :host => "localhost",
|
134
|
+
# :port => 6379
|
135
|
+
# }
|
136
|
+
# Frivol::Config.redis_config = REDIS_CONFIG
|
32
137
|
def self.redis_config=(config)
|
33
138
|
@@redis = Redis.new(config)
|
34
139
|
end
|
35
140
|
|
141
|
+
# Returns the configured Redis instance
|
36
142
|
def self.redis
|
37
143
|
@@redis
|
38
144
|
end
|
39
145
|
|
146
|
+
# A convenience method to include Frivol in a class, with an optional storage expiry parameter.
|
147
|
+
#
|
148
|
+
# For example, you might have the following in environment.rb:
|
149
|
+
# Frivol::Config.redis_config = REDIS_CONFIG
|
150
|
+
# Frivol::Config.include_in ActiveRecord::Base, 600
|
151
|
+
# Which would include Frivol in ActiveRecord::Base and set the default storage expiry to 10 minutes
|
40
152
|
def self.include_in(host_class, storage_expires_in = nil)
|
41
153
|
host_class.send(:include, Frivol)
|
42
154
|
host_class.storage_expires_in storage_expires_in if storage_expires_in
|
43
155
|
end
|
44
156
|
end
|
45
157
|
|
46
|
-
module Helpers
|
158
|
+
module Helpers #:nodoc:
|
47
159
|
def self.store_hash(instance)
|
48
160
|
hash = instance.instance_variable_get(:@frivol_hash)
|
49
161
|
is_new = instance.instance_variable_get(:@frivol_is_new)
|
@@ -64,24 +176,37 @@ module Frivol
|
|
64
176
|
instance.instance_variable_set :@frivol_hash, hash
|
65
177
|
hash
|
66
178
|
end
|
179
|
+
|
180
|
+
def self.delete_hash(instance)
|
181
|
+
key = instance.send(:storage_key)
|
182
|
+
Frivol::Config.redis.del key
|
183
|
+
instance.instance_variable_set :@frivol_hash, {}
|
184
|
+
end
|
67
185
|
end
|
68
186
|
|
187
|
+
# == Frivol::ClassMethods
|
188
|
+
# These methods are available on the class level when Frivol is included in the class.
|
69
189
|
module ClassMethods
|
190
|
+
# Set the storage expiry time in seconds.
|
70
191
|
def storage_expires_in(time)
|
71
192
|
@frivol_storage_expiry = time
|
72
193
|
end
|
73
194
|
|
195
|
+
# Get the storage expiry time in seconds.
|
74
196
|
def storage_expiry
|
75
197
|
@frivol_storage_expiry
|
76
198
|
end
|
77
199
|
end
|
78
200
|
|
79
|
-
def self.included(host)
|
201
|
+
def self.included(host) #:nodoc:
|
80
202
|
host.extend(ClassMethods)
|
81
203
|
end
|
82
204
|
end
|
83
205
|
|
206
|
+
# == Time
|
207
|
+
# An extension to the Time class which allows Time instances to be serialized by <tt>#to_json</tt> and deserialized by <tt>JSON#parse</tt>.
|
84
208
|
class Time
|
209
|
+
# Serialize to JSON
|
85
210
|
def to_json(*a)
|
86
211
|
{
|
87
212
|
'json_class' => self.class.name,
|
@@ -89,6 +214,7 @@ class Time
|
|
89
214
|
}.to_json(*a)
|
90
215
|
end
|
91
216
|
|
217
|
+
# Deserialize from JSON
|
92
218
|
def self.json_create(o)
|
93
219
|
Time.parse(*o['data'])
|
94
220
|
end
|