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
data/lib/sadie.rb DELETED
@@ -1,1315 +0,0 @@
1
- # this requires the gem: ini
2
- require 'rubygems'
3
- require "bundler/setup"
4
- require 'bundler'
5
- Bundler.require(:default)
6
- require 'sadie/defaults'
7
- require 'sadie/version'
8
- require 'erb'
9
-
10
- # ==Description: Sadie
11
- # Sadie is a data framework intended to ease the pain of constructing, accessing, and
12
- # managing the resources required by large stores of inter-related data. It supports
13
- # sessions, lazy, on-demand, one-time evaluation and file-based storage/retrieval
14
- # operations for resource-heavy data.
15
- #
16
- # New types of data primers can be added by calling addPrimerPluginsDirPath with a
17
- # directory containing plugin definitions
18
- #
19
-
20
- def S( key )
21
- instance = Sadie::getCurrentSadieInstance
22
- return instance.get( key )
23
- end
24
-
25
- class Sadie
26
-
27
-
28
- BEFORE = 1
29
- AFTER = 2
30
- EACH = 3
31
-
32
- # ==method: Sadie::getSadieInstance
33
- #
34
- # returns a new Sadie instance. Options match those of Sadie's constructor method
35
- def self.getSadieInstance( options )
36
- Sadie.new(options)
37
- end
38
-
39
- # ==method: Sadie::setCurrentSadieInstance
40
- #
41
- # this is called just prior to calling a primer plugin to handle a primer to provide
42
- # a current sadie instance for Sadie::getCurrentSadieInstance to return
43
- def self.setCurrentSadieInstance ( instance )
44
- @current_sadie_instance = instance
45
- end
46
-
47
- # ==method: Sadie::getCurrentSadieInstance
48
- #
49
- # called by plugin handlers to get access to the current Sadie instance
50
- def self.getCurrentSadieInstance
51
- @current_sadie_instance
52
- end
53
-
54
- # ==method: Sadie::Prime
55
- #
56
- # called by the .res files to register the keys the .res will prime for
57
- #
58
- # accepts as an argument a hash and a block. The hash must include the key:
59
- # 'provides' and it must define an array
60
- # of keys that the calling resource (.res) file will have provided after the block is
61
- # evaluated
62
- def self.prime ( primer_definition, &block )
63
- current_sadie_instance = Sadie::getCurrentSadieInstance
64
- current_sadie_instance.prime( primer_definition, &block )
65
- end
66
-
67
- # ==method: Sadie::eacher
68
- #
69
- # called by eacher files to hook into priming operations and calls to set method
70
- def self.eacher( eacher_params, &block )
71
- current_sadie_instance = Sadie::getCurrentSadieInstance
72
- current_sadie_instance.eacher( eacher_params, &block )
73
- end
74
-
75
- # ==method: Sadie::eacherFrame
76
- #
77
- # eacherFrame is called by get and set methods and is available to primer plugins
78
- # as well. when eacher primer files call eacher, they are registering code to
79
- # be run either BEFORE or AFTER the key/value store is set. Note that the BEFORE
80
- # eacherFrame runs just before priming when a primer exists and just before set
81
- # for keys set without primers. EACH eacherFrames are called as the data is being
82
- # assembled, if such a thing makes sense. The included SQLQueryTo2DArray plugin
83
- # tries to call any eacherFrame with an EACH occurAt parameter with each row and
84
- # the registering an EACH eacher might make sense for any number of incrementally
85
- # built data types
86
- #
87
- def self.eacherFrame( sadiekey, occur_at, param=nil )
88
- current_sadie_instance = Sadie::getCurrentSadieInstance
89
- current_sadie_instance.eacherFrame( sadiekey, occur_at, param )
90
- end
91
-
92
- # ==method: Sadie::registerPrimerPlugin
93
- #
94
- # this method is called in the .plugin.rb files to register new plugin types
95
- #
96
- def self.registerPrimerPlugin ( arghash, &block )
97
- current_sadie_instance = Sadie::getCurrentSadieInstance
98
- current_sadie_instance.registerPrimerPlugin( arghash, &block )
99
- end
100
-
101
- # ==method: Sadie::iniFileToHash
102
- #
103
- # utility class method. accepts a filepath. digests ini file and returns hash of hashes.
104
- #
105
- def self.iniFileToHash ( filepath )
106
- section = nil
107
- ret = Hash.new
108
- File.open( filepath, "r" ).each do |f|
109
- f.each_line do |line|
110
- next if line.match(/^;/) # skip comments
111
- if matches = line.match(/\[([^\]]+)\]/)
112
- section = matches[1]
113
- ret[section] = Hash.new
114
- elsif matches = line.match(/^\s*([^\s\=]+)\s*\=\s*([^\s]+.*)\s*$/)
115
- key = matches[1]
116
- value = matches[2]
117
-
118
- # strip quotes
119
- if qmatches = value.match(/[\'\"](.*)[\'\"]/)
120
- value = qmatches[1]
121
- end
122
-
123
- if defined? section
124
- ret[section][key] = value
125
- end
126
- end
127
- end
128
- end
129
- ret.empty? and return nil
130
- return ret
131
- end
132
-
133
- # ==method: Sadie::templatedFileToString
134
- #
135
- # utility class method. accepts a filepath. digests a template and returns
136
- # a string containing processed template output
137
- #
138
- def self.templatedFileToString( filepath, binding=nil )
139
-
140
- template = ERB.new File.new(filepath).read
141
- current_sadie_instance = Sadie::getCurrentSadieInstance
142
- if defined? binding
143
- template.result binding
144
- else
145
- template.result self
146
- end
147
-
148
- end
149
-
150
-
151
-
152
- # ==method: constructor
153
- # options can include any kay, value pairs but the following key values bear mention:
154
- # REQUIRED
155
- #
156
- # sadie.sessions_dirpath
157
- # or
158
- # sadie.session_id
159
- # or
160
- # sadie.session_filepath <- this is probably a bad call, use with caution
161
- #
162
- # and
163
- #
164
- # sadie.primers_dirpath
165
- #
166
- # and
167
- # sadie.primer_plugins_dirpath
168
- def initialize( options )
169
-
170
- # check instance sanity
171
- _checkInstanceSanity
172
- _checkClassSanity
173
-
174
- Sadie::setCurrentSadieInstance( self )
175
-
176
- # internalize defaults to shortterm
177
- DEFAULTS.each do |key, value|
178
- _set( key, value )
179
- end
180
-
181
- # iterate over constructor args, but do primers_dirpath last since it
182
- # causes a call to initializePrimers
183
- options.each do |key, value|
184
- set( key, value )
185
- end
186
-
187
- # if a path to a session is given, init using session file
188
- if options.has_key?( "sadie.session_filepath" )
189
- set( "sadie.session_filepath", options["sadie.session_filepath"] )
190
- _initializeWithSessionFilePath( get("sadie.session_filepath") )
191
- elsif options.has_key?( "sadie.session_id" )
192
- set( "sadie.session_id", options["sadie.session_id"] )
193
- _initializeWithSessionId( get( "sadie.session_id" ) )
194
- else
195
- set( "sadie.session_id", _generateNewSessionId )
196
- end
197
-
198
- # add the default sadie plugins dir
199
- plugins_dirpath = "lib/sadie/primer_plugins" # for dev
200
- if ! File.exists? plugins_dirpath
201
- plugins_dirpath = File.join(
202
- ENV['GEM_HOME'],
203
- "gems/sadie-#{Sadie::VERSION}",
204
- "lib/sadie/primer_plugins"
205
- )
206
-
207
- if ! File.exists? plugins_dirpath
208
- plugins_dirpath = File.expand_path "../sadie/lib/sadie/primer_plugins"
209
- end
210
-
211
- end
212
- addPrimerPluginsDirPath plugins_dirpath
213
-
214
- end
215
-
216
- # ==method: setDebugLevel
217
- #
218
- # from 0 to 10 with 0 being no debugging messages and 10 being all debugging messages
219
- #
220
- def setDebugLevel( lvl )
221
- lvl > 10 and lvl = 10
222
- lvl < 0 and lvl = 0
223
- @debug_level = lvl.to_i
224
- end
225
-
226
- # ==method: getDebugLevel
227
- #
228
- # return current debug level (default is 10)
229
- #
230
- def getDebugLevel
231
- defined? @debug_level or @debug_level = 10
232
- @debug_level
233
- end
234
-
235
- # ==method: getDebugLevel
236
- #
237
- # will print a debugging message if the current debug level is greater than
238
- # or equal to lvl
239
- #
240
- def debug!( lvl, msg )
241
- defined? @debug_level or @debug_level = 10
242
- (lvl <= @debug_level) and puts "SADIE(#{lvl}): #{msg}"
243
- end
244
-
245
- # ==method: eacher
246
- #
247
- # ( usually this will be called by the class method...it looks better )
248
- #
249
- # see class method eacher for an explanation
250
- #
251
- def eacher( params, &block )
252
- filepath = getCurrentPrimerFilepath
253
- key_prefix = getCurrentPrimerKeyPrefix
254
- occur_at = params[:when]
255
-
256
- # gen sadie key
257
- basefilename = filepath.gsub(/^.*\//,"")
258
- sadiekey = key_prefix + "." + basefilename.gsub(/\.each(?:\..*)*$/,"")
259
- sadiekey = sadiekey.gsub( /^\.+/,"" )
260
- if params.has_key? :sadiekey
261
- sadiekey = params[:sadiekey]
262
- end
263
-
264
-
265
- whichEacherFrame != Sadie::EACH and debug! 10, "whicheacherframe: #{whichEacherFrame}, occur_at: #{occur_at}"
266
-
267
- if midEacherInit?
268
-
269
- debug! 10, "in mid eacher init (#{sadiekey})"
270
-
271
- memorizeEacherFileLocation( sadiekey, filepath )
272
-
273
- if params.has_key? :provides
274
-
275
- # make sure we're passing an array
276
- provide_array = params[:provides]
277
- provide_array.respond_to? "each" or provide_array = [provide_array]
278
-
279
- # tell sadie that the sadiekey primer also provides everything in the provide array
280
- setEachersProvidedByPrimer( sadiekey, provide_array )
281
-
282
- end
283
-
284
- elsif whichEacherFrame == occur_at
285
-
286
- # bugfix: running eachers that aren't supposed to be run because they're
287
- # in the same eacher file
288
- #puts "sadiekey: #{sadiekey}, getEacherKey: #{getEacherKey}"
289
- #return if sadiekey != getEacherKey
290
-
291
- occur_at != Sadie::EACH and debug! 10, "pre-yield for skey: #{sadiekey}, #{occur_at}"
292
-
293
- if block.arity == 0
294
- yield self
295
- else
296
- yield self, getEacherParam
297
- end
298
-
299
- occur_at != Sadie::EACH and debug! 10, "post-yield for skey: #{sadiekey}, #{occur_at}"
300
- end
301
- end
302
-
303
- # ==method: eacherFrame
304
- #
305
- # ( usually this will be called by the class method...it looks better )
306
- #
307
- # see class method eacherFrame for an explanation
308
- #
309
- def eacherFrame( sadiekey, occur_at, param=nil )
310
-
311
- occur_at != Sadie::EACH and debug! 8, "eacherFrame(#{occur_at}): #{sadiekey}"
312
-
313
- setEacherFrame( occur_at )
314
- defined? param and setEacherParam( param )
315
- setEacherKey sadiekey
316
- if filepaths = eacherFilepaths( sadiekey )
317
- filepaths.each do |filepath|
318
- occur_at != Sadie::EACH and debug! 8, "eacher frame loading: #{filepath} for sadiekey: #{sadiekey}"
319
- load filepath
320
- end
321
- end
322
- unsetEacherParam
323
- unsetEacherFrame
324
- unsetEacherKey
325
- end
326
-
327
-
328
- # ==method: addPrimerPluginsDirPath
329
- #
330
- # addPrimerPluginsDirPath adds a directory which will be scanned for plugins to
331
- # register just before initializePrimers looks for primers to initialize
332
- #
333
- def addPrimerPluginsDirPath( path )
334
-
335
- exppath = File.expand_path(path)
336
-
337
- # add the path to the system load path
338
- $LOAD_PATH.include?(exppath) \
339
- or $LOAD_PATH.unshift(exppath)
340
-
341
- # add the path to the pluginsdir array
342
- defined? @plugins_dir_paths \
343
- or @plugins_dir_paths = Array.new
344
- @plugins_dir_paths.include?(exppath) \
345
- or @plugins_dir_paths.unshift(exppath)
346
-
347
- @primer_plugins_initialized = nil
348
- return self
349
- end
350
-
351
- # ==method: prime
352
- #
353
- # ( usually this will be called by the class method...it looks better )
354
- #
355
- # see class method prime for an explanation
356
- #
357
- def prime( primer_definition, &block )
358
- # validate params
359
- defined? primer_definition \
360
- or raise "Prime called without parameters"
361
- primer_definition.is_a? Hash \
362
- or raise "Prime called without hash parameters"
363
- defined? primer_definition["provides"] \
364
- or raise "Prime called without provides parameter"
365
-
366
- # if initializing primers, just remember how to get back to the primer later,
367
- # otherwise, prime
368
- if midPrimerInit?
369
-
370
- # mid primer init, just memorize primer location
371
- memorizePrimerLocation( @mid_primer_filepath, getCurrentPrimerPluginFilepath, primer_definition["provides"] )
372
- else
373
-
374
- # run code block with the current sadie instance
375
- block.call( self )
376
-
377
- # loop thru all primer provides, ensuring each primed
378
- current_primer_filepath = getCurrentPrimerFilepath
379
- primer_definition["provides"].each do | key |
380
-
381
- # skip blank lines
382
- next if key.match /^\s*$/
383
-
384
- # key primed or raise error
385
- primed? key \
386
- or raise "primer definition file: #{current_primer_filepath} was supposed to define #{key}, but did not"
387
- end
388
- end
389
-
390
- end
391
-
392
- # ==method: registerPrimerPlugin
393
- #
394
- # ( usually this will be called by the class method...it looks better )
395
- #
396
- # see class method registerPrimerPlugin for an explanation
397
- #
398
- def registerPrimerPlugin ( arghash, &block )
399
-
400
- # if mid plugin init is set, we're registering the plugin
401
- # init mode, just store arghash info
402
- accepts_block = arghash.has_key?( "accepts-block" ) && arghash["accepts-block"] ? true : false
403
- prime_on_init = arghash.has_key?( "prime-on-init" ) && arghash["prime-on-init"] ? true : false
404
-
405
- # if mid plugin init, register the plugin params with the match
406
- if midPluginInit?
407
-
408
- regPluginMatch( arghash["match"], @mid_plugin_filepath, accepts_block, prime_on_init )
409
-
410
- # midplugininit returned false, we're actually in the process of either initializing
411
- # a primer or actually priming
412
- else
413
- yield self, getCurrentPrimerKeyPrefix, getCurrentPrimerFilepath
414
- end
415
- end
416
-
417
-
418
-
419
- # ==method: get
420
- #
421
- # a standard getter which primes the unprimed and recalls "expensive" facts from files
422
- # completely behind-the-scenes as directed by the resource (.res) files
423
- def get( k )
424
-
425
- debug! 10, "get(#{k})"
426
-
427
- defined? @eacher_frame_redirect or @eacher_frame_redirect = Hash.new
428
-
429
- if ! isset?( k )
430
- debug! 10, "#{k} is not set"
431
- if isEacherKey?( k )
432
- debug! 10, "sadiekey: #[k} is eacher, fetching: #{@eacher_frame_redirect[k]}"
433
- get @eacher_frame_redirect[k]
434
-
435
- elsif primeable?( k )
436
-
437
- debug! 10, "calling eacher from get method for #{k}"
438
- setUnbalancedEacher k
439
- Sadie::eacherFrame( k, BEFORE )
440
-
441
- # prime if not yet primed
442
- primed?( k ) or _prime( k )
443
- end
444
- end
445
-
446
- return _recallExpensive( k ) if expensive?( k )
447
-
448
- # if it's already set, return known answer
449
- if isset?( k )
450
-
451
- # _get the return value
452
- return_value = _get( k )
453
-
454
- # unset and unprime if destructOnGet?
455
- destroyOnGet?( k ) \
456
- and destroy! k
457
-
458
- return return_value
459
- end
460
-
461
- end
462
-
463
- # ==method: output
464
- #
465
- # an alias for get. intended for use with primers that produce an output beyond their return value
466
- def output( k )
467
- return get( k )
468
- end
469
-
470
- # ==method: isset?
471
- #
472
- # returns true if sadie has a value for the key
473
- def isset?( key )
474
- return true if @shortterm.has_key?( key )
475
- return true if expensive?( key )
476
- false
477
- end
478
-
479
- # ==method: setDestroyOnGet
480
- #
481
- # key value will go away and key will be unprimed and unset after next get
482
- #
483
- # NOTE: this doesn't make sense with keys that were set via setExpensive
484
- # so it can be set, but nothing's going to happen differently
485
- def setDestroyOnGet( key, turnon=true )
486
- if ( turnon )
487
- @flag_destroyonget["#{key}"] = true
488
- return true
489
- end
490
- @flag_destroyonget.has_key?( key ) \
491
- and @flag_destroyonget.delete( key )
492
- end
493
-
494
- # ==method: destroy!
495
- #
496
- # remove the key from sadie
497
- def destroy! ( key )
498
- unset( key )
499
- primed?( key ) and unprime( key )
500
- end
501
-
502
- # ==method: destroyOnGet?
503
- #
504
- # returns true if the destructOnGet flag is set for the key
505
- def destroyOnGet?( key )
506
- ( @flag_destroyonget.has_key?( key ) && @flag_destroyonget["#{key}"] )
507
- end
508
-
509
- # ==method: set
510
- # alias for setCheap(k,v)
511
- def set( k, v )
512
- setCheap( k, v )
513
- end
514
-
515
- # ==method: setCheap
516
- #
517
- # the cheap setter. key, value pairs stored via this method are kept in memory
518
- def setCheap( k, v )
519
-
520
- # debug! 8, "setting cheap: [#{k},#{v}]"
521
- Sadie::eacherFrame( k, BEFORE ) if ! eacherUnbalanced?( k )
522
- setUnbalancedEacher k
523
-
524
- if getDebugLevel == 10
525
- debug! 10, "dumping value:"
526
- pp v
527
- end
528
-
529
- # set it, mark not expensive and primed
530
- _set( k, v )
531
- _expensive( k, false )
532
- _primed( k, true )
533
-
534
- Sadie::eacherFrame( k, AFTER, v )
535
- clearUnbalancedEacher k
536
-
537
- end
538
-
539
- # ==method: setExpensive
540
- #
541
- # the expensive setter. key, value pairs stored via this method are not kept in memory
542
- # but are stored to file and recalled as needed
543
- def setExpensive(k,v)
544
-
545
- debug! 9, "setting expensive: #{k}"
546
- Sadie::eacherFrame( k, BEFORE ) if ! eacherUnbalanced?( k )
547
- setUnbalancedEacher k
548
-
549
-
550
- expensive_filepath = _computeExpensiveFilepath( k )
551
- serialized_value = Marshal::dump( v )
552
-
553
- File.exist? File.dirname( expensive_filepath ) \
554
- or Dir.mkdir File.dirname( expensive_filepath )
555
-
556
- File.open(expensive_filepath, 'w') { |f|
557
- f.write( serialized_value )
558
- }
559
- _expensive( k, true )
560
- _primed( k, true )
561
-
562
- Sadie::eacherFrame( k, AFTER, v )
563
- clearUnbalancedEacher k
564
- end
565
-
566
-
567
- # ==method: save
568
- #
569
- # serialize to session file
570
- def save
571
- session_id = get("sadie.session_id")
572
- session_filepath = File.expand_path( "session."+session_id, get( "sadie.sessions_dirpath" ) )
573
- serialized_value = Marshal::dump( [ @shortterm, @flag_primed, @flag_expensive ] )
574
- File.open(session_filepath, 'w') { |f|
575
- f.write( serialized_value )
576
- }
577
- return session_id
578
- end
579
-
580
- # ==method: revert!
581
- #
582
- # return to last saved state
583
- #
584
- def revert!
585
-
586
- @shortterm = {
587
- "sadie.session_id" => get( "sadie.session_id" ),
588
- "sadie.sessions_dirpath" => get( "sadie.sessions_dirpath" )
589
- }
590
-
591
- _initializeWithSessionId( get( "sadie.session_id" ) )
592
- end
593
-
594
- # ==method: initializePrimers
595
- #
596
- # call this method only after registering all the plugin directories and setting the
597
- # appropriate session and primer directory paths. after this is called, the key/val
598
- # pairs will be available via get
599
- #
600
- def initializePrimers
601
-
602
- Sadie::setCurrentSadieInstance( self )
603
-
604
- # make sure primer plugins have been initialized
605
- primerPluginsInitialized? \
606
- or initializePrimerPlugins
607
-
608
- eachersInitialized? \
609
- or initializeEachers
610
-
611
- primers_dirpath = get( "sadie.primers_dirpath" ) \
612
- or raise "sadie.primers_dirpath not set"
613
-
614
- return true if primersInitialized? primers_dirpath
615
-
616
- debug! 1, "Initializing primers..."
617
- initializePrimerDirectory( "", primers_dirpath )
618
- debug! 1, "...finished initializing primers."
619
-
620
- @flag_primed[primers_dirpath] = true
621
- end
622
-
623
- def getEacherKey
624
- return nil if ! defined? @eacher_key
625
- @eacher_key.last
626
- end
627
-
628
-
629
-
630
- # ------------------------------------------------------------------------------------------------
631
- # ------------------------------------------------------------------------------------------------
632
-
633
- private
634
-
635
- def setUnbalancedEacher( k )
636
- debug! 10, "setting eacher unbalanced: #{k}"
637
- defined? @eacher_unbalanced or @eacher_unbalanced = Hash.new
638
- @eacher_unbalanced[k] = true
639
- end
640
-
641
- def clearUnbalancedEacher( k )
642
- debug! 10, "clearing eacher unbalanced: #{k}"
643
- @eacher_unbalanced[k] = false if defined? @eacher_unbalanced
644
- end
645
-
646
- def eacherUnbalanced?( k )
647
- return false if ! defined? @eacher_unbalanced
648
- return false if ! @eacher_unbalanced.has_key?( k )
649
- return @eacher_unbalanced[k]
650
- end
651
-
652
- def cheap?( k )
653
- ! expensive? ( k )
654
- end
655
-
656
- # ==method: primed?
657
- #
658
- # INTERNAL: this method should only be called the the class method, Prime
659
- #
660
- def expensive?( k )
661
- @flag_expensive.has_key?( k ) or return false;
662
- @flag_expensive["#{k}"] \
663
- and return true
664
- return false
665
- end
666
-
667
-
668
- # == initialize eachers
669
- #
670
- # register all the eachers
671
- #
672
- # called by initializePrimers so it's not necessary to call this separate from that
673
- def initializeEachers
674
-
675
- primers_dirpath = get( "sadie.primers_dirpath" ) \
676
- or raise "sadie.primers_dirpath not set"
677
-
678
- puts "Initializing eachers..."
679
- setEacherInit
680
- initializeEacherDirectory( "", primers_dirpath )
681
- clearEacherInit
682
- puts "...finished initializing eachers."
683
-
684
-
685
- @eachers_initialized = true
686
- end
687
-
688
- def initializeEacherDirectory( key_prefix, current_dirpath )
689
-
690
- debug! 3, "initializing eacher directory: #{current_dirpath}"
691
- Dir.foreach( current_dirpath ) do |filename|
692
-
693
- # skip the dit dirs
694
- next if filename.eql?(".") || filename.eql?("..") || filename =~ /\~$/
695
-
696
-
697
- filepath = File.expand_path( filename, current_dirpath )
698
-
699
- if File.directory? filepath
700
- new_key_prefix = key_prefix + '.' + filename
701
- new_key_prefix = new_key_prefix.gsub(/^\.+/,"")
702
- initializeEacherDirectory( new_key_prefix, filepath )
703
- else
704
- if filename =~ /\.each(?:\..*)*$/
705
- initializeEacherFile( key_prefix, filepath )
706
- end
707
- end
708
- end
709
- end
710
-
711
- def initializeEacherFile( key_prefix, filepath )
712
- debug! 8, "initializing eacher file (#{key_prefix}): #{filepath}"
713
- setCurrentPrimerFilepath filepath
714
- setCurrentPrimerKeyPrefix key_prefix
715
- load filepath
716
- end
717
-
718
- def eachersInitialized?
719
- defined? @eachers_initialized or return false
720
- @eachers_initialized and return true
721
- return false
722
- end
723
-
724
-
725
-
726
-
727
- def whichEacherFrame
728
- return nil if ! defined? @eacher_frame
729
- @eacher_frame.last
730
- end
731
-
732
- def setEacherFrame( f )
733
- defined? @eacher_frame or @eacher_frame = Array.new
734
- @eacher_frame.push f
735
- end
736
-
737
- def unsetEacherFrame
738
- if defined? @eacher_frame
739
- @eacher_frame.pop
740
- end
741
- end
742
-
743
- def setEacherParam( p )
744
- defined? @eacher_param or @eacher_param = Array.new
745
- @eacher_param.push p
746
- end
747
-
748
- def unsetEacherParam
749
- if defined? @eacher_param
750
- @eacher_param.pop
751
- end
752
- end
753
-
754
- def getEacherParam
755
- return nil if ! defined? @eacher_param
756
- @eacher_param.last
757
- end
758
-
759
- def setEacherKey( k )
760
- defined? @eacher_key or @eacher_key = Array.new
761
- @eacher_key.push k
762
- end
763
-
764
- def unsetEacherKey
765
- if defined? @eacher_key
766
- @eacher_key.pop
767
- end
768
- end
769
-
770
-
771
- def isEacherKey?( key )
772
-
773
- defined? @eacher_frame_redirect or return false
774
- @eacher_frame_redirect.has_key? key or return false
775
- return true
776
- end
777
-
778
- def getEacherDependency( key )
779
- defined? @eacher_frame_redirect or return nil
780
- @eacher_frame_redirect.has_key? key or return nil
781
- @eacher_frame_redirect[key]
782
- end
783
-
784
- def getEachersProvidedByPrimer( sadiekey )
785
- defined? @eachers_provided or return nil
786
- @eachers_provided.has_key? sadiekey or return nil
787
- @eachers_provided[sadiekey]
788
- end
789
-
790
-
791
-
792
- def eacherFilepaths( sadiekey )
793
- defined? @eacher_filepaths or return nil
794
- @eacher_filepaths.has_key? sadiekey or return nil
795
- @eacher_filepaths[sadiekey]
796
- end
797
-
798
- def midEacherInit?
799
- defined? @eacher_init or return false
800
- @eacher_init or return false
801
- true
802
- end
803
-
804
- def setEacherInit
805
- @eacher_init = true
806
- end
807
-
808
- def clearEacherInit
809
- @eacher_init = nil
810
- end
811
-
812
-
813
- def setEachersProvidedByPrimer( sadiekey, providers )
814
-
815
- # record reverse map for use by eacherFrame
816
- defined? @eacher_frame_redirect \
817
- or @eacher_frame_redirect = Hash.new
818
- providers.each do |provider|
819
- debug! 10, "setting provider reverse map for #{provider} to #{sadiekey}"
820
- @eacher_frame_redirect[provider] = sadiekey
821
- end
822
-
823
- defined? @eachers_provided or @eachers_provided = Hash.new
824
- if @eachers_provided.has_key? sadiekey
825
- @eachers_provided[sadiekey] = @eachers_provided[sadiekey].concat( providers )
826
- else
827
- @eachers_provided[sadiekey] = providers
828
- end
829
- end
830
-
831
-
832
-
833
- def memorizeEacherFileLocation( sadiekey, filepath )
834
- debug! 8, "memorizing eacher file location: #{filepath} for #{sadiekey}"
835
- # store the file path
836
- defined? @eacher_filepaths or @eacher_filepaths = Hash.new
837
- if ! @eacher_filepaths.has_key? sadiekey
838
- @eacher_filepaths[sadiekey] = [filepath]
839
- elsif ! @eacher_filepaths[sadiekey].include? filepath
840
- @eacher_filepaths[sadiekey].push filepath
841
- end
842
- end
843
-
844
-
845
-
846
- # ==method: unprime
847
- # unprimes k. Note that this does not unset the value, so
848
- # get(key) will continue to return whatever it otherwise would have.
849
- # run unset as well to have the primer run again.
850
- def unprime( key )
851
- _primed( key, false )
852
- end
853
-
854
- # ==method: primed?
855
- #
856
- # INTERNAL: this method should only be called the the class method, Prime
857
- #
858
- def primed?( k )
859
-
860
- isset?( k ) and return true
861
-
862
- @flag_primed.has_key?( k ) \
863
- or return false
864
- @flag_primed["#{k}"] \
865
- and return true
866
- return false
867
- end
868
-
869
- # direct access getter for shortterm memory
870
- def _get( key )
871
- value = @shortterm["#{key}"]
872
- return value
873
- end
874
-
875
-
876
-
877
- def primerPluginRegistered?( filename )
878
-
879
- @primer_plugin_lookup.each do | plugin_array |
880
- re, path,accepts_block = plugin_array
881
- re.match( filename ) \
882
- and return true
883
- end
884
- return false;
885
- end
886
-
887
- def currentPrimerPluginAcceptsBlock( accepts )
888
- @primer_plugin_accepts_block = accepts
889
- end
890
-
891
- def currentPrimerPluginAcceptsBlock?
892
- @primer_plugin_accepts_block
893
- end
894
-
895
- def currentPrimerPluginPrimeOnInit( prime_on_init )
896
- @primer_plugin_prime_on_init = prime_on_init
897
- end
898
-
899
- def currentPrimerPluginPrimeOnInit?
900
- @primer_plugin_prime_on_init
901
- end
902
-
903
- def setMidPluginInit( filepath )
904
- @mid_plugin_initialization = true
905
- @mid_plugin_filepath = filepath
906
- end
907
-
908
- def unsetMidPluginInit
909
- @mid_plugin_initialization = false
910
- end
911
-
912
- def midPluginInit?
913
- @mid_plugin_initialization
914
- end
915
-
916
- def regPluginMatch ( regexp, filepath, accepts_block, prime_on_init )
917
- @primer_plugin_lookup.push( [ regexp, filepath, accepts_block, prime_on_init ] )
918
- end
919
-
920
- def primerPluginsInitialized?
921
- @primer_plugins_initialized
922
- end
923
-
924
- # == initializePrimerPlugins
925
- #
926
- # register all the primer plugins
927
- #
928
- # called by initializePrimers so it's not necessary to call this separate from that
929
- def initializePrimerPlugins
930
-
931
- defined? @plugins_dir_paths \
932
- or raise 'plugins_dir_paths not set'
933
-
934
- debug! 1, "Initializing primer plugins..."
935
-
936
- # load the plugins
937
- @plugins_dir_paths.each do | dirpath |
938
- Dir.foreach( dirpath ) do |filename|
939
- next if ! filename.match( /\.plugin\.rb$/ )
940
-
941
- filepath = File.expand_path( filename, dirpath )
942
-
943
- debug! 2, "initializing primer plugin with file: #{filename}"
944
-
945
- setMidPluginInit( filepath )
946
- load( filename )
947
- unsetMidPluginInit
948
- end
949
- end
950
- debug! 1, "...finished initializing primer plugins"
951
- @primer_plugins_initialized = true
952
- end
953
-
954
- def setMidPrimerInit ( filepath )
955
- @mid_primer_initialization = true
956
- @mid_primer_filepath = filepath
957
- end
958
-
959
- def unsetMidPrimerInit
960
- @mid_primer_initialization = false
961
- end
962
-
963
- def midPrimerInit?
964
- @mid_primer_initialization \
965
- and return true;
966
- return false;
967
- end
968
-
969
-
970
-
971
- def primersInitialized? ( toplevel_dirpath )
972
- @flag_primed.has_key?( toplevel_dirpath ) \
973
- or return false;
974
- return @flag_primed[toplevel_dirpath]
975
- end
976
-
977
- def initializePrimerDirectory( key_prefix, current_dirpath )
978
- puts "initializing primer directory: #{current_dirpath}"
979
- Dir.foreach( current_dirpath ) do |filename|
980
-
981
- # skip the dit dirs
982
- next if filename.eql?(".") || filename.eql?("..") || filename =~ /\~$/
983
-
984
- filepath = File.expand_path( filename, current_dirpath )
985
-
986
- if File.directory? filepath
987
- new_key_prefix = key_prefix + '.' + filename
988
- new_key_prefix = new_key_prefix.gsub(/^\.+/,"")
989
- initializePrimerDirectory( new_key_prefix, filepath )
990
- else
991
- initializePrimerFile( key_prefix, filepath )
992
- end
993
- end
994
- end
995
-
996
- def initializePrimerFile( key_prefix, filepath )
997
-
998
-
999
- basename = File.basename( filepath )
1000
- if primerPluginRegistered? basename
1001
- setCurrentPrimerFilepath filepath
1002
-
1003
- setCurrentPrimerKeyPrefix key_prefix
1004
-
1005
- basename = File.basename( filepath )
1006
- initializePrimerWithPlugin( key_prefix, filepath )
1007
-
1008
-
1009
- end
1010
- end
1011
-
1012
- def initializePrimerWithPlugin( key_prefix, filepath )
1013
-
1014
- debug! 9, "initializing primer file #{File.basename(filepath)} with plugin"
1015
-
1016
- @primer_plugin_lookup.each do | plugin_array |
1017
-
1018
- # we just need to match the basename
1019
- filename = File.basename( filepath )
1020
-
1021
- regexp, plugin_filepath, accepts_block, prime_on_init = plugin_array
1022
-
1023
- if regexp.match( filename )
1024
-
1025
- setCurrentPrimerPluginFilepath( plugin_filepath )
1026
- prime_on_init \
1027
- or setMidPrimerInit( filepath )
1028
-
1029
- plugin_filename = File.basename( plugin_filepath )
1030
-
1031
- load( plugin_filepath )
1032
-
1033
- prime_on_init \
1034
- or unsetMidPrimerInit
1035
-
1036
-
1037
- return
1038
- end
1039
- end
1040
- end
1041
-
1042
- def setCurrentPrimerPluginFilepath( filepath )
1043
- @current_primer_plugin_filepath = filepath
1044
- end
1045
-
1046
- def getCurrentPrimerPluginFilepath
1047
- @current_primer_plugin_filepath
1048
- end
1049
-
1050
- def setCurrentPrimerKeyPrefix ( prefix )
1051
- @current_primer_keyprefix = prefix
1052
- end
1053
-
1054
- def getCurrentPrimerKeyPrefix
1055
- @current_primer_keyprefix
1056
- end
1057
-
1058
- def setCurrentPrimerFilepath ( filepath )
1059
- @current_primer_filepath = filepath
1060
- end
1061
-
1062
- def getCurrentPrimerFilepath
1063
- @current_primer_filepath
1064
- end
1065
-
1066
- def setCurrentPrimerRequestingKey( key )
1067
- @current_primer_requesting_key = key
1068
- end
1069
-
1070
- def getCurrentPrimerRequestingKey
1071
- @current_primer_requesting_key
1072
- end
1073
-
1074
- # ==memorizePrimerLocation
1075
- #
1076
- # internal, ignore the man behind the curtain
1077
- def memorizePrimerLocation( filepath, plugin_filepath, primer_provides )
1078
-
1079
- # validate primer hash
1080
- #primer_dirpath = @mid_primer_toplevel_primer_dirpath
1081
- primer_dirpath = _get("sadie.primers_dirpath")
1082
- @primer_hash.has_key?( primer_dirpath ) \
1083
- or @primer_hash["#{primer_dirpath}"] = Hash.new
1084
-
1085
- # interate over provides setting primer providers for each
1086
- primer_provides.each do | key |
1087
- setPrimerProvider( key, filepath, plugin_filepath, getCurrentPrimerKeyPrefix )
1088
-
1089
- end
1090
-
1091
- end
1092
-
1093
-
1094
- # ==setPrimerProvider
1095
- #
1096
- # internal, ignore the man behind the curtain
1097
- def setPrimerProvider( primer_name, primer_filepath, primer_plugin_filepath, key_prefix )
1098
-
1099
- primer_dirpath = _get( "sadie.primers_dirpath" )
1100
- @primer_hash.has_key?( primer_dirpath ) \
1101
- or @primer_hash[primer_dirpath] = Hash.new
1102
-
1103
- @primer_hash["#{primer_dirpath}"]["#{primer_name}"] = [ primer_filepath, primer_plugin_filepath, key_prefix ]
1104
-
1105
- end
1106
-
1107
- def primeable?( key )
1108
- p = getPrimerProvider( key )
1109
- return nil if ! defined? (p )
1110
- return nil if p == nil
1111
- return true
1112
- end
1113
-
1114
- def getPrimerProvider( key )
1115
-
1116
- # fetch primers dirpath and validate the primer hash
1117
- primer_dirpath = _get( "sadie.primers_dirpath" )
1118
- @primer_hash.has_key?( primer_dirpath ) \
1119
- or @primer_hash[primer_dirpath] = Hash.new
1120
-
1121
- primers = @primer_hash[primer_dirpath]
1122
- primers.has_key?( key ) \
1123
- or return nil # primer not defined
1124
-
1125
- return primers[key]
1126
- end
1127
-
1128
-
1129
-
1130
- def _primed ( k, is_primed )
1131
- defined? k \
1132
- or raise '_primed> reqd parameter, k, was undefined'
1133
- k.is_a?( String ) \
1134
- or raise '_primed> reqd parameter, k, was non-string'
1135
- if ( is_primed )
1136
- @flag_primed[k] = true
1137
- return true
1138
- end
1139
- @flag_primed.has_key?( k ) \
1140
- or return true
1141
- @flag_primed.delete( k )
1142
- end
1143
-
1144
- def _prime ( k )
1145
-
1146
- debug! 10, "priming: #{k}"
1147
-
1148
- if isEacherKey? k
1149
- get( getEacherDependency( k ) )
1150
- else
1151
-
1152
- #Sadie::eacherFrame( k, BEFORE )
1153
- if provider = getPrimerProvider( k )
1154
- primer_filepath, plugin_filepath, key_prefix = provider
1155
-
1156
- currfilepath = getCurrentPrimerFilepath
1157
-
1158
- setCurrentPrimerFilepath(primer_filepath)
1159
- setCurrentPrimerKeyPrefix( key_prefix )
1160
- Sadie::setCurrentSadieInstance( self )
1161
-
1162
- load plugin_filepath
1163
-
1164
- if defined? currfilepath
1165
- setCurrentPrimerFilepath currfilepath
1166
- end
1167
- end
1168
- #Sadie::eacherFrame( k, AFTER )
1169
- end
1170
- end
1171
-
1172
-
1173
- def _newline( rval=true )
1174
- return rval
1175
- end
1176
-
1177
- # ==method: unset
1178
- # unsets the value of k. Note that this does not unprime, so
1179
- # get(key) will simply return nil. Run with unprime to have the
1180
- # primer run again
1181
- def unset( key )
1182
- _unset( key )
1183
- end
1184
-
1185
- def _recallExpensive( k )
1186
- expensive_filepath = _computeExpensiveFilepath( k )
1187
- File.exists? expensive_filepath \
1188
- or raise "expensive filepath: #{filepath} does not exist"
1189
- f = open( expensive_filepath )
1190
- v = Marshal::load( f.read )
1191
-
1192
- return v
1193
- end
1194
-
1195
- def _computeExpensiveFilepath( k )
1196
- session_id = get( "sadie.session_id" )
1197
- File.expand_path("session."+session_id+".exp."+k, _get( "sadie.sessions_dirpath" ) )
1198
- end
1199
-
1200
- def _expensive( k, isexpensive )
1201
- if isexpensive
1202
- @flag_expensive["#{k}"] = true
1203
- return
1204
- end
1205
- @flag_expensive.delete( k )
1206
- end
1207
-
1208
- # direct access setter for shortterm memory
1209
- def _set( key, value )
1210
- @shortterm["#{key}"] = value
1211
- end
1212
-
1213
- def _unset( key )
1214
- @shortterm.has_key?( key ) \
1215
- and @shortterm.delete( key )
1216
- end
1217
-
1218
-
1219
- # init given path to session file
1220
- def _initializeWithSessionFilePath( session_filepath )
1221
-
1222
- puts "session_filepath: #{session_filepath}"
1223
-
1224
- defined?( session_filepath ) \
1225
- or raise "session_filepath was undefined"
1226
-
1227
- /^\s*$/.match("#{session_filepath}") \
1228
- and raise "session_filepath was empty string"
1229
-
1230
- # bail on non-existant file
1231
- File.exist?( session_filepath ) \
1232
- or raise "session file, " + session_filepath + " does not exist"
1233
-
1234
- # open session file and read internal vars from it
1235
- File.open( session_filepath, "r" ).each do |f|
1236
-
1237
- # make sure no writing happens while we read
1238
- f.flock(File::Lock_SH)
1239
-
1240
- # read vars from file
1241
- mem, primed, expensive = Marshal::load( f.read )
1242
- end
1243
-
1244
- # destructive set on flag vars
1245
- @flag_primed = primed
1246
- @flag_expensive = expensive
1247
-
1248
- # additive set on shortterm mem
1249
- mem.each do |k,v|
1250
- set(k, v)
1251
- end
1252
- end
1253
-
1254
- # init given session id
1255
- def _initializeWithSessionId(session_id)
1256
- session_filepath = File.expand_path( "session."+session_id, _get( "sadie.sessions_dirpath" ) )
1257
- _initializeWithSessionFilePath( session_filepath )
1258
- end
1259
-
1260
- # gen new session id
1261
- def _generateNewSessionId
1262
- begin
1263
- value = ""
1264
- 24.times{value << (65 + rand(25)).chr}
1265
- end while File.exist?(File.expand_path("session."+value, get( "sadie.sessions_dirpath" ) ) )
1266
- return value
1267
- end
1268
-
1269
- # ==method: checkInstanceSanity
1270
- #
1271
- # verifies that needed instance variables are defined
1272
- def _checkInstanceSanity
1273
- defined? @shortterm \
1274
- or @shortterm = Hash.new
1275
- defined? @flag_expensive \
1276
- or @flag_expensive = Hash.new
1277
- defined? @flag_destroyonget \
1278
- or @flag_destroyonget = Hash.new
1279
- defined? @flag_primed \
1280
- or @flag_primed = Hash.new
1281
-
1282
- end
1283
-
1284
- # ==method: checkClassSanity
1285
- #
1286
- # verifies that needed class variables are defined
1287
- def _checkClassSanity
1288
- defined? @flag_primed \
1289
- or @flag_primed = Hash.new
1290
-
1291
- # init primer plugin vars
1292
- if ( ! defined? @primer_plugin_lookup )
1293
- @mid_plugin_initialization = false
1294
- @primer_plugin_lookup = Array.new
1295
- @primer_plugins_initialized = false
1296
- end
1297
-
1298
- # init primer vars
1299
- defined? @primer_hash \
1300
- or @primer_hash = Hash.new
1301
- defined? @flag_primed \
1302
- or @flag_primed = Hash.new
1303
- if ! defined? @mid_primer_initialization
1304
- @mid_primer_initialization = false
1305
- @mid_primer_filepath = nil
1306
- end
1307
-
1308
- end
1309
-
1310
-
1311
- end
1312
-
1313
- require "sadie/version"
1314
- require "sadie/defaults"
1315
-