sadie 0.0.52 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +2 -1
  3. data/README +76 -22
  4. data/Rakefile +41 -1
  5. data/TODO +2 -31
  6. data/bin/sadie +17 -0
  7. data/bin/sadie_query_server +15 -0
  8. data/bin/sadie_server +27 -0
  9. data/bin/sadie_server.rb +23 -0
  10. data/doc/v2 +161 -0
  11. data/lib/primer.rb +201 -0
  12. data/lib/sadie/version.rb +1 -1
  13. data/lib/sadie_server.rb +59 -0
  14. data/lib/sadie_session.rb +194 -0
  15. data/lib/sadie_storage_manager.rb +60 -0
  16. data/lib/sadie_storage_mechanism.rb +18 -0
  17. data/lib/storage/memory.rb +24 -0
  18. data/sadie.gemspec +6 -2
  19. data/spec/primer.rb +167 -0
  20. data/spec/sadie_server.rb +39 -0
  21. data/spec/sadie_server_lib.rb +31 -0
  22. data/spec/sadie_session.rb +99 -0
  23. data/spec/storage_manager.rb +58 -0
  24. data/spec/storage_mechanisms/memory.rb +28 -0
  25. data/test/v2/test_installation/primers/minimal.rb +5 -0
  26. data/test/v2/test_installation/primers/onelevel/twolevel/test_subdir.rb +5 -0
  27. data/test/v2/test_installation/primers/test_after_each.rb +14 -0
  28. data/test/v2/test_installation/primers/test_after_key.rb +14 -0
  29. data/test/v2/test_installation/primers/test_before_each.rb +14 -0
  30. data/test/v2/test_installation/primers/test_before_key.rb +14 -0
  31. data/test/v2/test_installation/primers/test_expires_after_n_secs.rb +6 -0
  32. data/test/v2/test_installation/primers/test_expires_on_get.rb +6 -0
  33. data/test/v2/test_installation/primers/test_refresh.rb +10 -0
  34. metadata +84 -49
  35. data/lib/sadie/debug.rb +0 -1
  36. data/lib/sadie/defaults.rb +0 -14
  37. data/lib/sadie/primer_plugins/DatabaseConnection.plugin.rb +0 -80
  38. data/lib/sadie/primer_plugins/IniFile.plugin.rb +0 -23
  39. data/lib/sadie/primer_plugins/Resource.plugin.rb +0 -7
  40. data/lib/sadie/primer_plugins/SQLQueryTo2DArray.plugin.rb +0 -39
  41. data/lib/sadie/primer_plugins/TemplateTextFile.plugin.rb +0 -13
  42. data/lib/sadie.rb +0 -1315
  43. data/test/README +0 -9
  44. data/test/tc_sadie_toplevel.rb +0 -43
  45. data/test/tc_sadie_twodeep.rb +0 -48
  46. data/test/test_primers/.gitignore +0 -1
  47. data/test/test_primers/onedeep/multiresult.res +0 -5
  48. data/test/test_primers/toplevel.ini +0 -5
  49. data/test/test_primers/toplevel.somegroup.somekey.each +0 -15
  50. data/test/test_primers/toplevel_destructonget.res.rb +0 -9
  51. data/test/test_primers/toplevel_double.oneprime.each +0 -14
  52. data/test/test_primers/toplevel_double.res.rb +0 -5
  53. data/test/test_primers/toplevel_single.res.rb +0 -3
  54. data/test/test_primers/toplevel_testeach.res.rb +0 -4
  55. data/test/test_primers/two/deep/conf.ini +0 -2
  56. data/test/test_primers/two/deep/expensive.res +0 -3
  57. data/test/test_primers/two/deep/test.dbi.conx +0 -4
  58. data/test/test_primers/two/deep/test_template.txt.tmpl +0 -10
  59. data/test/test_primers/two/deep/testquery.test.sql2ar +0 -1
  60. data/test/test_primers/two/deep/testquery.test.sql2ar.each +0 -16
  61. 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 and it's intended to be used by a Rubie developer to simplify access to inter-related data sets.
3
+ Sadie is a general-purpose data server written in Ruby for other Rubyists.
4
4
 
5
- It is designed to provide handle-based access to data of all types, much like a simple hash. Unlike a hash, a sadie instance is created with a pathname which points to a directory of primers which tell sadie how to determine what the value of a given hash key should be, but values are not assigned until the hash keys are requested. In this way, only necessary data transformations and/or accesses are performed.
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
- Valid primers currently are:
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
- .ini - provide access to section, key, value data in ini-style-files
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
- There's also another file type that can be found in the primer directory called "eacher files". These are simple files which allow for certain tasks to be performed before, after and during the priming of a key/value pair. Currently, the only plugin that makes effective use of eachers is sql2ar and it provides a way for developers to iterate on the rows of a query result as it is initially processed into the resultant array.
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
- It's very simple to add new primer types, so it would be simple to create primers for html, xml, csv, xls, pointers to all of the above on remote machines, or any- and everything else.
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
- At Landmetrics, we use a predecessor to Sadie to power perimetercomps[http://perimetercomps.com], producing each 50+ page report with charts, graphs and tables with only 12 queries to the database.
56
+ Have a look at other primers in test/v2/test_installation/primers for more information.
20
57
 
21
- Sadie can be downloaded via its rubygems page[https://rubygems.org/gems/sadie] or from github[https://github.com/FredAtLandMetrics/sadie].
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
- USE CASES
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
- [templating] As noted above, perimetercomps[http://perimetercomps.com] is an example of how one might
26
- use sadie to to create a templating engine wherein many pieces of related information
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
- [data import] Tasks involving grabbing data from different places in different formats and
32
- massaging the data into a consistent and useful format. A few simple primer plugins
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
- [setDestroyTimer] this will accept either a quantity of time or a specific date and
2
- will destroy the data at that time, causing a "reprime" event
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
+
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sinatra'
4
+ require 'sadie_server'
5
+
6
+ sadie_server_proc_args ARGV
7
+
8
+ get '/:key' do
9
+ sadie_server_get params[:key]
10
+ end
11
+
12
+ post '/query' do
13
+ sadie_server_query params[:query]
14
+ end
15
+
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
+
@@ -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
@@ -1,3 +1,3 @@
1
1
  class Sadie
2
- VERSION = "0.0.52"
2
+ VERSION = "0.1.6"
3
3
  end