sadie 0.0.52 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +2 -1
- data/README +76 -22
- data/Rakefile +41 -1
- data/TODO +2 -31
- data/bin/sadie +17 -0
- data/bin/sadie_query_server +15 -0
- data/bin/sadie_server +27 -0
- data/bin/sadie_server.rb +23 -0
- data/doc/v2 +161 -0
- data/lib/primer.rb +201 -0
- data/lib/sadie/version.rb +1 -1
- data/lib/sadie_server.rb +59 -0
- data/lib/sadie_session.rb +194 -0
- data/lib/sadie_storage_manager.rb +60 -0
- data/lib/sadie_storage_mechanism.rb +18 -0
- data/lib/storage/memory.rb +24 -0
- data/sadie.gemspec +6 -2
- data/spec/primer.rb +167 -0
- data/spec/sadie_server.rb +39 -0
- data/spec/sadie_server_lib.rb +31 -0
- data/spec/sadie_session.rb +99 -0
- data/spec/storage_manager.rb +58 -0
- data/spec/storage_mechanisms/memory.rb +28 -0
- data/test/v2/test_installation/primers/minimal.rb +5 -0
- data/test/v2/test_installation/primers/onelevel/twolevel/test_subdir.rb +5 -0
- data/test/v2/test_installation/primers/test_after_each.rb +14 -0
- data/test/v2/test_installation/primers/test_after_key.rb +14 -0
- data/test/v2/test_installation/primers/test_before_each.rb +14 -0
- data/test/v2/test_installation/primers/test_before_key.rb +14 -0
- data/test/v2/test_installation/primers/test_expires_after_n_secs.rb +6 -0
- data/test/v2/test_installation/primers/test_expires_on_get.rb +6 -0
- data/test/v2/test_installation/primers/test_refresh.rb +10 -0
- metadata +84 -49
- data/lib/sadie/debug.rb +0 -1
- data/lib/sadie/defaults.rb +0 -14
- data/lib/sadie/primer_plugins/DatabaseConnection.plugin.rb +0 -80
- data/lib/sadie/primer_plugins/IniFile.plugin.rb +0 -23
- data/lib/sadie/primer_plugins/Resource.plugin.rb +0 -7
- data/lib/sadie/primer_plugins/SQLQueryTo2DArray.plugin.rb +0 -39
- data/lib/sadie/primer_plugins/TemplateTextFile.plugin.rb +0 -13
- data/lib/sadie.rb +0 -1315
- data/test/README +0 -9
- data/test/tc_sadie_toplevel.rb +0 -43
- data/test/tc_sadie_twodeep.rb +0 -48
- data/test/test_primers/.gitignore +0 -1
- data/test/test_primers/onedeep/multiresult.res +0 -5
- data/test/test_primers/toplevel.ini +0 -5
- data/test/test_primers/toplevel.somegroup.somekey.each +0 -15
- data/test/test_primers/toplevel_destructonget.res.rb +0 -9
- data/test/test_primers/toplevel_double.oneprime.each +0 -14
- data/test/test_primers/toplevel_double.res.rb +0 -5
- data/test/test_primers/toplevel_single.res.rb +0 -3
- data/test/test_primers/toplevel_testeach.res.rb +0 -4
- data/test/test_primers/two/deep/conf.ini +0 -2
- data/test/test_primers/two/deep/expensive.res +0 -3
- data/test/test_primers/two/deep/test.dbi.conx +0 -4
- data/test/test_primers/two/deep/test_template.txt.tmpl +0 -10
- data/test/test_primers/two/deep/testquery.test.sql2ar +0 -1
- data/test/test_primers/two/deep/testquery.test.sql2ar.each +0 -16
- data/test/test_primers/two/deep/two_results.res +0 -8
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8e344594b19d7b7541c54600a79644071396458c
|
4
|
+
data.tar.gz: db4f2671448cea713c637315067a3449e9cd675a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ab2e088b58e59f8fbd6ae4fb4446954a73ff4bb8afa12084f92abecb0f7a09cbaa34531ba73df491a4aeafe72fe2ff481a90320a6a10cacf3f717925642f7e61
|
7
|
+
data.tar.gz: 56a214771d30d04eb93a59dc6b4bdfab76663be7578408a9fbf59c5b8161f682533dc95471bca3e5962eafa44aa324732d7657f4187dc81bd29ac48501935f42
|
data/CHANGELOG
CHANGED
@@ -24,4 +24,5 @@
|
|
24
24
|
[0.0.49] botched the upload...resubmitting
|
25
25
|
[0.0.50] fixed isset? bug (was only working for non-expensive keys)
|
26
26
|
[0.0.51] eacher bugfix. now correctly handles specific keys.
|
27
|
-
[0.0.52] code cleanup
|
27
|
+
[0.0.52] code cleanup
|
28
|
+
[0.1.01] ** ground-up rewrite, ignore everything before this line if you're not a historian **
|
data/README
CHANGED
@@ -1,34 +1,88 @@
|
|
1
1
|
==About Sadie
|
2
2
|
|
3
|
-
Sadie is a general-purpose data server written in Ruby
|
3
|
+
Sadie is a general-purpose data server written in Ruby for other Rubyists.
|
4
4
|
|
5
|
-
|
5
|
+
==Purpose
|
6
|
+
Imagine you work in the IT department of a cell phone company and your boss asks you to design a system that will:
|
7
|
+
* build a status page that shows a map with the operational status of all the cell towers and, for each one, the distance to the nearest field technician
|
8
|
+
* generate a shapefile and a spreadsheet of the same data that will be available and up-to-date on the company's intranet, 24/7
|
9
|
+
* when there's an outtage, send an SMS alert to the nearest field tech to the tower with the problem
|
6
10
|
|
7
|
-
|
11
|
+
This is all inter-related data and, for a developer, it's not all that difficult to start thinking about how to approach these problems.
|
8
12
|
|
9
|
-
|
10
|
-
.dbi.conx - simple access to database handles
|
11
|
-
.sql2ar - simple access to database data
|
12
|
-
.res, .res.rb - provides access to general-purpose, programatic manipulation of data (i.e. just use sadie instance for input and output of data)
|
13
|
-
.tmpl - simple templating engine for text-based file types
|
13
|
+
With that said, if your boss a week later decides that he also needs to have google map imagery on the alert page and charts showing tower availability over time and average response time of technicians over the past several weeks, then things get a little more complicated.
|
14
14
|
|
15
|
-
|
15
|
+
And if two weeks after that, he says he needs the technician availability data updated every ten minutes and the cell tower availability every five minutes, and, oh, the number of calls that come into customer care regarding a each tower's primary coverage area, it gets tough to imagine that the initial software engineering effort will have been robust enough to keep things sane.
|
16
|
+
|
17
|
+
This is the sort of problem that Sadie is intended to address.
|
18
|
+
|
19
|
+
==How it works
|
20
|
+
Sadie is a key/value store that uses <em>primers</em>--which are really just ruby files written using Sadie's primer DSL--to set the key/value pairs. These primers can be called on-demand (so no computational resources get expended until a request for a value is made) or they can be refreshed at certain intervals.
|
21
|
+
|
22
|
+
For data that changes often, it's possible to expire data after a set amount of time or, if necessary, just after it's accessed for a just-in-time computation.
|
23
|
+
|
24
|
+
Primers can also reference other primers so it's easy to hide complexity.
|
25
|
+
|
26
|
+
==How to use it
|
27
|
+
Create a directory for sadie to operate in, say /var/sadie.
|
28
|
+
|
29
|
+
Then create a directory in that called primers. <em>So, now there's a /var/sadie/primers</em>
|
30
|
+
|
31
|
+
In the primers directory, create files that end in .rb that look like:
|
32
|
+
|
33
|
+
require 'intersting_lib_that_does_neato_things'
|
34
|
+
require 'cool_notifier'
|
35
|
+
|
36
|
+
prime ["test.expires.nsecs"] do
|
16
37
|
|
17
|
-
|
38
|
+
expire :never
|
39
|
+
refresh 300 #generate this again every 5 minutes
|
40
|
+
|
41
|
+
after "test.expires.nsecs" do |key, val|
|
42
|
+
cool_notify 'ward@thecleavers.com', val
|
43
|
+
end
|
44
|
+
|
45
|
+
assign do
|
46
|
+
|
47
|
+
someothervar = session.get( "some.other.var" )
|
48
|
+
andanother = session.get( "yet.another.var" )
|
49
|
+
|
50
|
+
neat_val = awesome_whatzit( someothervar, andanother )
|
51
|
+
|
52
|
+
set neat_val
|
53
|
+
end
|
54
|
+
end
|
18
55
|
|
19
|
-
|
56
|
+
Have a look at other primers in test/v2/test_installation/primers for more information.
|
20
57
|
|
21
|
-
|
58
|
+
Now run the sadie server on whatever directory you set it up on:
|
59
|
+
|
60
|
+
bin/sadie_server.rb --framework-dirpath=/var/sadie
|
61
|
+
|
62
|
+
And you can make get requests on the keys,
|
63
|
+
|
64
|
+
wget http://localhost:4567/test.expires.nsecs -O /tmp/outputfile
|
22
65
|
|
23
|
-
|
66
|
+
Or, you can use the sadie session in your Ruby code like this:
|
67
|
+
|
68
|
+
@sadie_session = SadieSession.new( :primers_dirpath => '/var/sadie/primers' )
|
69
|
+
puts "test.expires.nsecs: #{@sadie_session.get('test.expires.nsecs')}"
|
70
|
+
|
71
|
+
That's it!
|
72
|
+
|
73
|
+
==Contribute
|
74
|
+
Do it! The github url for Sadie is at: [https://github.com/FredAtLandMetrics/sadie]
|
75
|
+
|
76
|
+
==Future versions
|
77
|
+
Future version of Sadie will:
|
78
|
+
* index on key string patterns
|
79
|
+
* make use of a redis storage mechanism to become scalable and distributed
|
80
|
+
|
81
|
+
==Where to get it
|
82
|
+
Sadie can be downloaded via its rubygems page[https://rubygems.org/gems/sadie] or from github[https://github.com/FredAtLandMetrics/sadie].
|
24
83
|
|
25
|
-
|
26
|
-
|
27
|
-
from many different sources are made into charts, graphs, tables and text before being
|
28
|
-
assembled into a single deliverable document. We used LaTeX, but html, xml, css, txt, etc.
|
29
|
-
would be just as easy.
|
84
|
+
==Support
|
85
|
+
Feel free to email me at fred@landmetrics.com
|
30
86
|
|
31
|
-
|
32
|
-
|
33
|
-
would make this very easy.
|
34
|
-
|
87
|
+
==How to say thanks
|
88
|
+
I accept thanks via email at fred@landmetrics.com. Beer from afar and lucrative consulting gigs are also welcomed.
|
data/Rakefile
CHANGED
@@ -11,10 +11,50 @@ task :test do
|
|
11
11
|
ruby "test/tc_sadie_twodeep.rb"
|
12
12
|
end
|
13
13
|
|
14
|
+
namespace :spec do
|
15
|
+
|
16
|
+
desc "test sadie server library"
|
17
|
+
task :sadie_server_lib do
|
18
|
+
system "rspec spec/sadie_server_lib.rb"
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :storage_mechanism do
|
22
|
+
desc "test the memory based storage mechanism"
|
23
|
+
task :memory do
|
24
|
+
system "rspec spec/storage_mechanisms/memory.rb"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "test primer"
|
29
|
+
task :primer do
|
30
|
+
system "rspec spec/primer.rb"
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "test storage manager"
|
34
|
+
task :storage_manager do
|
35
|
+
system "rspec spec/storage_manager.rb"
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "test session"
|
39
|
+
task :session do
|
40
|
+
system "rspec spec/sadie_session.rb"
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "test session with timers (slow)"
|
44
|
+
task :session_with_timers do
|
45
|
+
system "SADIE_SESSION_TEST_TIMERS=1 rspec spec/sadie_session.rb"
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "test RESTful server"
|
49
|
+
task :server do
|
50
|
+
system "rspec spec/sadie_server.rb"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
14
54
|
# increment version
|
55
|
+
desc "deploy a new gem"
|
15
56
|
task :deploy => 'inc_version' do
|
16
57
|
version = current_sadie_version
|
17
|
-
sh "git push"
|
18
58
|
sh "gem build sadie.gemspec"
|
19
59
|
sh "gem push sadie-#{version}.gem"
|
20
60
|
end
|
data/TODO
CHANGED
@@ -1,31 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
[threadedness] split getSadieInstance(sessionid] into getSadieInstanceSlave[sessionid]
|
5
|
-
where getSadieInstance will continute to bring up a normal Sadie
|
6
|
-
instance and getSadieInstanceSlave will perform reads in its own thread
|
7
|
-
but will prime in sync with the main instance thread (such that two
|
8
|
-
primers for the same key would never execute at the same time, rather,
|
9
|
-
the second one would simply block until the first completed). This
|
10
|
-
would allow for some concurrency within a session without. Rather than
|
11
|
-
calling getSadieInstanceSlave directly, a prgram could simple call a
|
12
|
-
new method, consider( key ) which would fire off a get in an instance
|
13
|
-
slave to allow for some background processing
|
14
|
-
|
15
|
-
[keyregexpmatch] instead of requiring that all keys must be known either as having been set
|
16
|
-
or having a known primer, a key could be matched against a regex.
|
17
|
-
This would make it possible to encode some useful priming information
|
18
|
-
in the key itself, enough that the primer could use it and divine the
|
19
|
-
desired result. So, where Sadie::prime takes an arg of containing
|
20
|
-
a list of keys that this primer "provides", it will alternatively take an
|
21
|
-
arg of "key-match" which will fire off the primer when the key matches.
|
22
|
-
|
23
|
-
[sampleapps] make a few simple apps with primer directories
|
24
|
-
|
25
|
-
[primer_path] currently defined via a path to a single directory, the toplevel primer
|
26
|
-
directory idea should be made into a collection of directories as spec'ed
|
27
|
-
in a colon-separated list, and it should check the environment, if
|
28
|
-
otherwise undefined. would make it easy to have multiple primer
|
29
|
-
repositories.
|
30
|
-
|
31
|
-
|
1
|
+
1) rewrite everything
|
2
|
+
2) re-document everything
|
data/bin/sadie
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'sinatra'
|
4
|
+
require 'sadie_server'
|
5
|
+
|
6
|
+
get '/:key' do
|
7
|
+
sadie_server_get params[:key]
|
8
|
+
end
|
9
|
+
|
10
|
+
post '/:key' do
|
11
|
+
sadie_server_set params[:key], params[:value]
|
12
|
+
end
|
13
|
+
|
14
|
+
post '/query' do
|
15
|
+
sadie_server_query params[:query]
|
16
|
+
end
|
17
|
+
|
data/bin/sadie_server
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'sinatra'
|
4
|
+
require 'server'
|
5
|
+
|
6
|
+
server = SadieServer.new( SadieServer::proc_args( ARGV ) )
|
7
|
+
|
8
|
+
get '/:key' do
|
9
|
+
server.get params[:key]
|
10
|
+
end
|
11
|
+
|
12
|
+
post '/:key' do
|
13
|
+
server.set params[:key], params[:value]
|
14
|
+
end
|
15
|
+
|
16
|
+
post '/setmultiple' do
|
17
|
+
server.set_multiple params[:data]
|
18
|
+
end
|
19
|
+
|
20
|
+
post '/getmultiple' do
|
21
|
+
server.set_multiple params[:keys]
|
22
|
+
end
|
23
|
+
|
24
|
+
post '/query' do
|
25
|
+
server.query params[:query]
|
26
|
+
end
|
27
|
+
|
data/bin/sadie_server.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
3
|
+
require 'sadie_server'
|
4
|
+
require 'pp'
|
5
|
+
arghash = SadieServer::proc_args( ARGV )
|
6
|
+
puts "arghash: #{arghash.pretty_inspect}"
|
7
|
+
require 'sinatra'
|
8
|
+
|
9
|
+
server = SadieServer.new( arghash )
|
10
|
+
|
11
|
+
get '/:key' do
|
12
|
+
server.get params[:key]
|
13
|
+
end
|
14
|
+
|
15
|
+
post '/:key' do
|
16
|
+
server.set params[:key], params[:value]
|
17
|
+
end
|
18
|
+
|
19
|
+
# FUTURE
|
20
|
+
# post '/query' do
|
21
|
+
# server.query params[:query]
|
22
|
+
# end
|
23
|
+
|
data/doc/v2
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
BIG UGLY PLANNING DOC
|
2
|
+
|
3
|
+
So, now that Sadie's been written and reasonably well tested, I'd like to see it change to something more ruby-esque.
|
4
|
+
|
5
|
+
I liked the idea of pluggable types, but I want to add RESTful services and they're just not going to work, so I think I'll go with constructors/destructors as an alternative.
|
6
|
+
|
7
|
+
I'm also going to move to the more rubyesque style of using method calls in primer definitions instead of parameters...it just looks better.
|
8
|
+
|
9
|
+
So, where in the old version I've got a primer that looks like:
|
10
|
+
|
11
|
+
Sadie::prime( "provides" => %w{ toplevel_double.oneprime
|
12
|
+
toplevel_double.twoprime } ) do |sadie|
|
13
|
+
sadie.set( "toplevel_double.oneprime", "primedthem" )
|
14
|
+
sadie.set( "toplevel_double.twoprime", "primedthem" )
|
15
|
+
end
|
16
|
+
|
17
|
+
and an eacher in a separate file that looks like:
|
18
|
+
|
19
|
+
|
20
|
+
Sadie::eacher( :when => Sadie::BEFORE ) do |sadie|
|
21
|
+
@testeach_topleveldouble = "blah"
|
22
|
+
sadie.debug! 10, ">>>>HERE!!!"
|
23
|
+
end
|
24
|
+
|
25
|
+
Sadie::eacher( :when => Sadie::AFTER,
|
26
|
+
:provides => ["toplevel_double.eachtest"] ) do |sadie,val|
|
27
|
+
|
28
|
+
@testeach_topleveldouble = "#{@testeach_topleveldouble}bloo"
|
29
|
+
sadie.set "toplevel_double.eachtest", @testeach_topleveldouble
|
30
|
+
sadie.debug! 10, ">>>>THERE!!!"
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
I'll now have a single file that looks like:
|
35
|
+
|
36
|
+
prime %w{ toplevel_double.oneprime toplevel_double.twoprime toplevel_double.eachtest } do
|
37
|
+
|
38
|
+
before :each do
|
39
|
+
@testeach_topleveldouble = "blah"
|
40
|
+
end
|
41
|
+
|
42
|
+
after :each do |val|
|
43
|
+
|
44
|
+
@testeach_topleveldouble = "#{@testeach_topleveldouble}bloo"
|
45
|
+
|
46
|
+
assign "toplevel_double.eachtest" do
|
47
|
+
set @testeach_topleveldouble
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
assign "toplevel_double.oneprime" do
|
53
|
+
set "primedthem"
|
54
|
+
end
|
55
|
+
|
56
|
+
assign "toplevel_double.twoprime" do
|
57
|
+
set "primedthem"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
But for a more interesting example of things to come:
|
63
|
+
|
64
|
+
prime %w{ shapefile.url } do
|
65
|
+
|
66
|
+
expire "shapefile.url", :after => 300
|
67
|
+
|
68
|
+
after "shapefile.url" do |value|
|
69
|
+
notify_admin_of_new_shapefile value
|
70
|
+
end
|
71
|
+
|
72
|
+
assign "shapefile.url" do
|
73
|
+
output = generate_shapefile(get('gis.points.array'))
|
74
|
+
set "http://#{GISHOST}/shapefiles/#{output}"
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
prime %w{ webview.image.url } do
|
80
|
+
|
81
|
+
expire :after => 30 # note that, if unspecified, expire applies to all names in prime array
|
82
|
+
|
83
|
+
assign do # note that, if unspecified, assign applies to all names in prime array
|
84
|
+
set build_webview_image(get('gis.points.array'))
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
prime %w{ gis.points.array } do
|
90
|
+
|
91
|
+
expire "gis.points.array", :immediately
|
92
|
+
|
93
|
+
assign "gis.points.array" do
|
94
|
+
set get_badguy_locations_from_drone
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
What's happening here is we have a bit of continually refreshable data called gis.points.array that is new every time we retrieve it. We're building an image using the gis points array for the web page that only changes every 60 seconds and we're building a new shapefile using the gis points array that only changes every 300 seconds. No look at this:
|
100
|
+
|
101
|
+
prime %w{ shapefile.url } do
|
102
|
+
|
103
|
+
expire "shapefile.url", :never
|
104
|
+
refresh 300
|
105
|
+
|
106
|
+
after "shapefile.url" do |value|
|
107
|
+
notify_admin_of_new_shapefile value
|
108
|
+
end
|
109
|
+
|
110
|
+
assign "shapefile.url" do
|
111
|
+
output = generate_shapefile(get('gis.points.array'))
|
112
|
+
set "http://#{GISHOST}/shapefiles/#{output}"
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
So, now, instead of being generated on demand, this becomes a background process via the refresh statement and a new shapefile will be generated every 300 seconds.
|
118
|
+
|
119
|
+
*** Index by key name such that a.b.c creates an entry in three indexes, a., b., and a.b.c.
|
120
|
+
|
121
|
+
this will facilitate an aggregate getter
|
122
|
+
|
123
|
+
*** Allow for a read-only query language that executes ruby code in safe mode level = 4 (and maybe runs in some sort of jailed process sandbox that only has access to the local sadie server via RESTful interface?)
|
124
|
+
|
125
|
+
It should also be possible to expire when some other key is set, like:
|
126
|
+
|
127
|
+
prime %w{ shapefile.url } do
|
128
|
+
|
129
|
+
expire "shapefile.url", :after => key_is_set("gis.points.array")
|
130
|
+
|
131
|
+
after "shapefile.url" do |value|
|
132
|
+
notify_admin_of_new_shapefile value
|
133
|
+
end
|
134
|
+
|
135
|
+
assign "shapefile.url" do
|
136
|
+
output = generate_shapefile(get('gis.points.array'))
|
137
|
+
set "http://#{GISHOST}/shapefiles/#{output}"
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
It should also be possible to expire when a file on the filesystem has changed:
|
143
|
+
|
144
|
+
prime ["gis.points.list_string"] do
|
145
|
+
expire :after => file_has_changed("/var/gisdata/someguys_points_file.csv")
|
146
|
+
assign do
|
147
|
+
set "gis.points.list_string", File.open("/var/gisdata/someguys_points_file.csv", 'rb') { |f| f.read }
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
It should be possible to choose the method of storage for an item
|
152
|
+
|
153
|
+
prime ["gis.points.list_string"] do
|
154
|
+
expire :after => file_has_changed("/var/gisdata/someguys_points_file.csv")
|
155
|
+
store_in :redis (or :memory, :file)
|
156
|
+
assign do
|
157
|
+
set "gis.points.list_string", File.open("/var/gisdata/someguys_points_file.csv", 'rb') { |f| f.read }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
|
data/lib/primer.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
class Primer
|
2
|
+
|
3
|
+
attr_accessor :keys, :mode, :session, :storage_mechanism, :assign_keys, :filepath, :refresh_rate
|
4
|
+
|
5
|
+
def initialize( params=nil )
|
6
|
+
self.storage_mechanism = :memory
|
7
|
+
self.refresh_rate = nil
|
8
|
+
@before_block = {}
|
9
|
+
@after_block = {}
|
10
|
+
expire(:never)
|
11
|
+
unless params.nil?
|
12
|
+
if params.is_a? Hash
|
13
|
+
if params.has_key?( :session )
|
14
|
+
self.session = params[:session]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def refresh( rsecs )
|
21
|
+
self.refresh_rate = rsecs
|
22
|
+
end
|
23
|
+
|
24
|
+
def refreshes?
|
25
|
+
( ! refresh_rate.nil? )
|
26
|
+
end
|
27
|
+
|
28
|
+
def expire( val=nil )
|
29
|
+
unless val.nil?
|
30
|
+
@expire = val
|
31
|
+
end
|
32
|
+
@expire
|
33
|
+
end
|
34
|
+
|
35
|
+
def decorate( primer_filepath )
|
36
|
+
if File.exists?( primer_filepath )
|
37
|
+
self.instance_eval File.open(primer_filepath, 'rb') { |f| f.read }
|
38
|
+
self.filepath = primer_filepath
|
39
|
+
else
|
40
|
+
raise ArgumentError, "#{primer_filepath} not found"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def before( arg, &block )
|
45
|
+
if arg == :each
|
46
|
+
if block_given?
|
47
|
+
@before_block[:each] = block
|
48
|
+
end
|
49
|
+
elsif arg.is_a? String
|
50
|
+
if self.keys.index( arg ).nil?
|
51
|
+
raise 'key passed as argument to before must be declared in the prime directive'
|
52
|
+
else
|
53
|
+
@before_block[arg] = block
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def after( arg, &block )
|
59
|
+
if arg == :each
|
60
|
+
if block_given?
|
61
|
+
@after_block[:each] = block
|
62
|
+
end
|
63
|
+
elsif arg.is_a? String
|
64
|
+
if self.keys.index( arg ).nil?
|
65
|
+
raise 'key passed as argument to after must be declared in the prime directive'
|
66
|
+
else
|
67
|
+
@after_block[arg] = block
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def prime( k=nil )
|
73
|
+
self.keys = Array(k) if _validate_key_arg(k)
|
74
|
+
yield if block_given?
|
75
|
+
end
|
76
|
+
|
77
|
+
def assign( keys = nil )
|
78
|
+
if keys.nil?
|
79
|
+
self.assign_keys = self.keys
|
80
|
+
elsif _validate_key_arg(keys)
|
81
|
+
unless (Array( keys ) - self.keys).empty?
|
82
|
+
raise 'assigning keys that are not given as arguments to prime is not permitted'
|
83
|
+
end
|
84
|
+
self.assign_keys = Array(keys)
|
85
|
+
end
|
86
|
+
unless mode == :registration
|
87
|
+
yield if block_given?
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def set( keys=nil, value=nil)
|
92
|
+
if value.nil?
|
93
|
+
_set1(keys)
|
94
|
+
else
|
95
|
+
_set2(keys,value)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def store_in( mech )
|
100
|
+
self.storage_mechanism = mech
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def _set2( keys=nil, value )
|
106
|
+
if keys.nil?
|
107
|
+
_set1(value)
|
108
|
+
elsif _validate_key_arg(keys)
|
109
|
+
unless (Array( keys ) - self.assign_keys).empty?
|
110
|
+
raise 'assigning keys that are not given as arguments to assign (or to prime, if assign was given no keys as arguments) is not permitted'
|
111
|
+
end
|
112
|
+
|
113
|
+
if @before_block.has_key?(:each) && ! @before_block[:each].nil?
|
114
|
+
|
115
|
+
Array(keys).each do |key|
|
116
|
+
@before_block[:each].call(key)
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
Array(keys).each do |key|
|
122
|
+
if @before_block.has_key?(key) && ! @before_block[key].nil?
|
123
|
+
|
124
|
+
@before_block[key].call(key)
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
self.session.set( Array(keys), value, :mechanism => self.storage_mechanism,
|
130
|
+
:expire => self.expire )
|
131
|
+
|
132
|
+
if @after_block.has_key?(:each) && ! @after_block[:each].nil?
|
133
|
+
|
134
|
+
Array(keys).each do |key|
|
135
|
+
@after_block[:each].call(key,value)
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
Array(keys).each do |key|
|
141
|
+
if @after_block.has_key?(key) && ! @after_block[key].nil?
|
142
|
+
|
143
|
+
@after_block[key].call(key,value)
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def _set1( value )
|
151
|
+
unless @before_block[:each].nil?
|
152
|
+
|
153
|
+
Array(keys).each do |key|
|
154
|
+
@before_block[:each].call(key)
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
Array(self.assign_keys).each do |key|
|
159
|
+
if @before_block.has_key?(key) && ! @before_block[key].nil?
|
160
|
+
|
161
|
+
@before_block[key].call(key)
|
162
|
+
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
self.session.set( Array(keys), value, :mechanism => self.storage_mechanism,
|
167
|
+
:expire => self.expire )
|
168
|
+
|
169
|
+
if @after_block.has_key?(:each) && ! @after_block[:each].nil?
|
170
|
+
|
171
|
+
Array(keys).each do |key|
|
172
|
+
@after_block[:each].call(key,value)
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
Array(keys).each do |key|
|
178
|
+
if @after_block.has_key?(key) && ! @after_block[key].nil?
|
179
|
+
|
180
|
+
@after_block[key].call(key,value)
|
181
|
+
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def _validate_key_arg( k=nil )
|
187
|
+
if k.is_a?(String)
|
188
|
+
true
|
189
|
+
elsif k.is_a?( Array )
|
190
|
+
k.each do |key|
|
191
|
+
unless key.is_a?( String )
|
192
|
+
raise 'keys must be string or array or strings'
|
193
|
+
end
|
194
|
+
end
|
195
|
+
else
|
196
|
+
raise 'keys must be string or array or strings'
|
197
|
+
end
|
198
|
+
true
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
data/lib/sadie/version.rb
CHANGED