frivol 0.1.3 → 0.1.4
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/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
|