zuk-picnic 0.7.999.20090212

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/CHANGELOG.txt +1 -0
  2. data/History.txt +68 -0
  3. data/LICENSE.txt +165 -0
  4. data/Manifest.txt +29 -0
  5. data/README.txt +31 -0
  6. data/Rakefile +62 -0
  7. data/lib/picnic/authentication.rb +218 -0
  8. data/lib/picnic/cli.rb +165 -0
  9. data/lib/picnic/conf.rb +135 -0
  10. data/lib/picnic/controllers.rb +4 -0
  11. data/lib/picnic/logger.rb +41 -0
  12. data/lib/picnic/server.rb +98 -0
  13. data/lib/picnic/service_control.rb +274 -0
  14. data/lib/picnic/version.rb +9 -0
  15. data/lib/picnic.rb +48 -0
  16. data/setup.rb +1585 -0
  17. data/test/picnic_test.rb +11 -0
  18. data/test/test_helper.rb +2 -0
  19. data/vendor/camping-2.0.20090212/CHANGELOG +118 -0
  20. data/vendor/camping-2.0.20090212/COPYING +18 -0
  21. data/vendor/camping-2.0.20090212/README +119 -0
  22. data/vendor/camping-2.0.20090212/Rakefile +174 -0
  23. data/vendor/camping-2.0.20090212/bin/camping +99 -0
  24. data/vendor/camping-2.0.20090212/doc/camping.1.gz +0 -0
  25. data/vendor/camping-2.0.20090212/examples/README +5 -0
  26. data/vendor/camping-2.0.20090212/examples/blog.rb +375 -0
  27. data/vendor/camping-2.0.20090212/examples/campsh.rb +629 -0
  28. data/vendor/camping-2.0.20090212/examples/tepee.rb +242 -0
  29. data/vendor/camping-2.0.20090212/extras/Camping.gif +0 -0
  30. data/vendor/camping-2.0.20090212/extras/flipbook_rdoc.rb +491 -0
  31. data/vendor/camping-2.0.20090212/extras/permalink.gif +0 -0
  32. data/vendor/camping-2.0.20090212/lib/camping/ar/session.rb +132 -0
  33. data/vendor/camping-2.0.20090212/lib/camping/ar.rb +78 -0
  34. data/vendor/camping-2.0.20090212/lib/camping/mab.rb +26 -0
  35. data/vendor/camping-2.0.20090212/lib/camping/reloader.rb +163 -0
  36. data/vendor/camping-2.0.20090212/lib/camping/server.rb +158 -0
  37. data/vendor/camping-2.0.20090212/lib/camping/session.rb +74 -0
  38. data/vendor/camping-2.0.20090212/lib/camping-unabridged.rb +638 -0
  39. data/vendor/camping-2.0.20090212/lib/camping.rb +54 -0
  40. data/vendor/camping-2.0.20090212/setup.rb +1551 -0
  41. data/vendor/camping-2.0.20090212/test/apps/env_debug.rb +65 -0
  42. data/vendor/camping-2.0.20090212/test/apps/forms.rb +95 -0
  43. data/vendor/camping-2.0.20090212/test/apps/misc.rb +86 -0
  44. data/vendor/camping-2.0.20090212/test/apps/sessions.rb +38 -0
  45. data/vendor/camping-2.0.20090212/test/test_camping.rb +54 -0
  46. metadata +128 -0
@@ -0,0 +1,491 @@
1
+ CAMPING_EXTRAS_DIR = File.expand_path(File.dirname(__FILE__))
2
+
3
+ module Generators
4
+ class HTMLGenerator
5
+ def generate_html
6
+ @files_and_classes = {
7
+ 'allfiles' => gen_into_index(@files),
8
+ 'allclasses' => gen_into_index(@classes),
9
+ "initial_page" => main_url,
10
+ 'realtitle' => CGI.escapeHTML(@options.title),
11
+ 'charset' => @options.charset
12
+ }
13
+
14
+ # the individual descriptions for files and classes
15
+ gen_into(@files)
16
+ gen_into(@classes)
17
+ gen_main_index
18
+
19
+ # this method is defined in the template file
20
+ write_extra_pages if defined? write_extra_pages
21
+ end
22
+
23
+ def gen_into(list)
24
+ hsh = @files_and_classes.dup
25
+ list.each do |item|
26
+ if item.document_self
27
+ op_file = item.path
28
+ hsh['root'] = item.path.split("/").map { ".." }[1..-1].join("/")
29
+ item.instance_variable_set("@values", hsh)
30
+ File.makedirs(File.dirname(op_file))
31
+ File.open(op_file, "w") { |file| item.write_on(file) }
32
+ end
33
+ end
34
+ end
35
+
36
+ def gen_into_index(list)
37
+ res = []
38
+ list.each do |item|
39
+ hsh = item.value_hash
40
+ hsh['href'] = item.path
41
+ hsh['name'] = item.index_name
42
+ res << hsh
43
+ end
44
+ res
45
+ end
46
+
47
+ def gen_main_index
48
+ template = TemplatePage.new(RDoc::Page::INDEX)
49
+ File.open("index.html", "w") do |f|
50
+ values = @files_and_classes.dup
51
+ if @options.inline_source
52
+ values['inline_source'] = true
53
+ end
54
+ template.write_html_on(f, values)
55
+ end
56
+ ['Camping.gif', 'permalink.gif'].each do |img|
57
+ ipath = File.join(CAMPING_EXTRAS_DIR, img)
58
+ File.copy(ipath, img)
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+
65
+ module RDoc
66
+ module Page
67
+ ######################################################################
68
+ #
69
+ # The following is used for the -1 option
70
+ #
71
+
72
+ FONTS = "verdana,arial,'Bitstream Vera Sans',helvetica,sans-serif"
73
+
74
+ STYLE = %{
75
+ body, th, td {
76
+ font: normal 14px verdana,arial,'Bitstream Vera Sans',helvetica,sans-serif;
77
+ line-height: 160%;
78
+ padding: 0; margin: 0;
79
+ margin-bottom: 30px;
80
+ /* background-color: #402; */
81
+ background-color: #694;
82
+ }
83
+ h1, h2, h3, h4 {
84
+ font-family: Utopia, Georgia, serif;
85
+ font-weight: bold;
86
+ letter-spacing: -0.018em;
87
+ }
88
+ h1 { font-size: 24px; margin: .15em 1em 0 0 }
89
+ h2 { font-size: 24px }
90
+ h3 { font-size: 19px }
91
+ h4 { font-size: 17px; font-weight: normal; }
92
+ h4.ruled { border-bottom: solid 1px #CC9; }
93
+ h2.ruled { padding-top: 35px; border-top: solid 1px #AA5; }
94
+
95
+ /* Link styles */
96
+ :link, :visited {
97
+ color: #00b;
98
+ }
99
+ :link:hover, :visited:hover {
100
+ background-color: #eee;
101
+ color: #B22;
102
+ }
103
+ #fullpage {
104
+ width: 720px;
105
+ margin: 0 auto;
106
+ }
107
+ .page_shade, .page {
108
+ padding: 0px 5px 5px 0px;
109
+ background-color: #fcfcf9;
110
+ border: solid 1px #983;
111
+ }
112
+ .page {
113
+ margin-left: -5px;
114
+ margin-top: -5px;
115
+ padding: 20px 35px;
116
+ }
117
+ .page .header {
118
+ float: right;
119
+ color: #777;
120
+ font-size: 10px;
121
+ }
122
+ .page h1, .page h2, .page h3 {
123
+ clear: both;
124
+ text-align: center;
125
+ }
126
+ #pager {
127
+ padding: 10px 4px;
128
+ color: white;
129
+ font-size: 11px;
130
+ }
131
+ #pager :link, #pager :visited {
132
+ color: #bfb;
133
+ padding: 0px 5px;
134
+ }
135
+ #pager :link:hover, #pager :visited:hover {
136
+ background-color: #262;
137
+ color: white;
138
+ }
139
+ #logo { float: left; }
140
+ #menu { background-color: #dfa; padding: 4px 12px; margin: 0; }
141
+ #menu h3 { padding: 0; margin: 0; }
142
+ #menu #links { float: right; }
143
+ pre { font-weight: bold; color: #730; }
144
+ tt { color: #703; font-size: 12pt; }
145
+ .dyn-source { background-color: #775915; padding: 4px 8px; margin: 0; display: none; }
146
+ .dyn-source pre { color: #DDDDDD; font-size: 8pt; }
147
+ .source-link { text-align: right; font-size: 8pt; }
148
+ .ruby-comment { color: green; font-style: italic }
149
+ .ruby-constant { color: #CCDDFF; font-weight: bold; }
150
+ .ruby-identifier { color: #CCCCCC; }
151
+ .ruby-ivar { color: #BBCCFF; }
152
+ .ruby-keyword { color: #EEEEFF; font-weight: bold }
153
+ .ruby-node { color: #FFFFFF; }
154
+ .ruby-operator { color: #CCCCCC; }
155
+ .ruby-regexp { color: #DDFFDD; }
156
+ .ruby-value { color: #FFAAAA; font-style: italic }
157
+ .kw { color: #DDDDFF; font-weight: bold }
158
+ .cmt { color: #CCFFCC; font-style: italic }
159
+ .str { color: #EECCCC; font-style: italic }
160
+ .re { color: #EECCCC; }
161
+ }
162
+
163
+ CONTENTS_XML = %{
164
+ IF:description
165
+ %description%
166
+ ENDIF:description
167
+
168
+ IF:requires
169
+ <h4>Requires:</h4>
170
+ <ul>
171
+ START:requires
172
+ IF:aref
173
+ <li><a href="%aref%">%name%</a></li>
174
+ ENDIF:aref
175
+ IFNOT:aref
176
+ <li>%name%</li>
177
+ ENDIF:aref
178
+ END:requires
179
+ </ul>
180
+ ENDIF:requires
181
+
182
+ IF:attributes
183
+ <h4>Attributes</h4>
184
+ <table>
185
+ START:attributes
186
+ <tr><td>%name%</td><td>%rw%</td><td>%a_desc%</td></tr>
187
+ END:attributes
188
+ </table>
189
+ ENDIF:attributes
190
+
191
+ IF:includes
192
+ <h4>Includes</h4>
193
+ <ul>
194
+ START:includes
195
+ IF:aref
196
+ <li><a href="%aref%">%name%</a></li>
197
+ ENDIF:aref
198
+ IFNOT:aref
199
+ <li>%name%</li>
200
+ ENDIF:aref
201
+ END:includes
202
+ </ul>
203
+ ENDIF:includes
204
+
205
+ START:sections
206
+ IF:method_list
207
+ <h2 class="ruled">Methods</h2>
208
+ START:method_list
209
+ IF:methods
210
+ START:methods
211
+ <h4 class="ruled">%type% %category% method:
212
+ IF:callseq
213
+ <strong><a name="%aref%">%callseq%</a></strong> <a href="#%aref%"><img src="%root%/permalink.gif" border="0" title="Permalink to %callseq%" /></a>
214
+ ENDIF:callseq
215
+ IFNOT:callseq
216
+ <strong><a name="%aref%">%name%%params%</a></strong> <a href="#%aref%"><img src="%root%/permalink.gif" border="0" title="Permalink to %type% %category% method: %name%" /></a></h4>
217
+ ENDIF:callseq
218
+
219
+ IF:m_desc
220
+ %m_desc%
221
+ ENDIF:m_desc
222
+
223
+ IF:sourcecode
224
+ <div class="sourcecode">
225
+ <p class="source-link">[ <a href="javascript:toggleSource('%aref%_source')" id="l_%aref%_source">show source</a> ]</p>
226
+ <div id="%aref%_source" class="dyn-source">
227
+ <pre>
228
+ %sourcecode%
229
+ </pre>
230
+ </div>
231
+ </div>
232
+ ENDIF:sourcecode
233
+ END:methods
234
+ ENDIF:methods
235
+ END:method_list
236
+ ENDIF:method_list
237
+ END:sections
238
+ }
239
+
240
+ ############################################################################
241
+
242
+
243
+ BODY = %{
244
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
245
+ <html>
246
+ <head>
247
+ <title>
248
+ IF:title
249
+ %realtitle% &raquo; %title%
250
+ ENDIF:title
251
+ IFNOT:title
252
+ %realtitle%
253
+ ENDIF:title
254
+ </title>
255
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%" />
256
+ <link rel="stylesheet" href="%style_url%" type="text/css" media="screen" />
257
+ <script language="JavaScript" type="text/javascript">
258
+ // <![CDATA[
259
+
260
+ function toggleSource( id )
261
+ {
262
+ var elem
263
+ var link
264
+
265
+ if( document.getElementById )
266
+ {
267
+ elem = document.getElementById( id )
268
+ link = document.getElementById( "l_" + id )
269
+ }
270
+ else if ( document.all )
271
+ {
272
+ elem = eval( "document.all." + id )
273
+ link = eval( "document.all.l_" + id )
274
+ }
275
+ else
276
+ return false;
277
+
278
+ if( elem.style.display == "block" )
279
+ {
280
+ elem.style.display = "none"
281
+ link.innerHTML = "show source"
282
+ }
283
+ else
284
+ {
285
+ elem.style.display = "block"
286
+ link.innerHTML = "hide source"
287
+ }
288
+ }
289
+
290
+ function openCode( url )
291
+ {
292
+ window.open( url, "SOURCE_CODE", "width=400,height=400,scrollbars=yes" )
293
+ }
294
+ // ]]>
295
+ </script>
296
+ </head>
297
+ <body>
298
+ <div id="menu">
299
+ <div id="links">
300
+ <a href="http://redhanded.hobix.com/bits/campingAMicroframework.html">backstory</a> |
301
+ <a href="http://code.whytheluckystiff.net/camping/">wiki</a> |
302
+ <a href="http://code.whytheluckystiff.net/camping/newticket">bugs</a> |
303
+ <a href="http://code.whytheluckystiff.net/svn/camping/">svn</a>
304
+ </div>
305
+ <h3 class="title">%title%</h3>
306
+ </div>
307
+ <div id="fullpage">
308
+ <div id="logo"><img src="%root%/Camping.gif" /></div>
309
+ <div id="pager">
310
+ <strong>Files:</strong>
311
+ START:allfiles
312
+ <a href="%root%/%href%" value="%title%">%name%</a>
313
+ END:allfiles
314
+ IF:allclasses
315
+ |
316
+ <strong>classes:</strong>
317
+ START:allclasses
318
+ <a href="%root%/%href%" title="%title%">%name%</a>
319
+ END:allclasses
320
+ ENDIF:allclasses
321
+ </ul>
322
+ </div>
323
+
324
+ !INCLUDE!
325
+
326
+ </div>
327
+ </body>
328
+ </html>
329
+ }
330
+
331
+ ###############################################################################
332
+
333
+ FILE_PAGE = <<_FILE_PAGE_
334
+ <div id="%full_path%" class="page_shade">
335
+ <div class="page">
336
+ <div class="header">
337
+ <div class="path">%full_path% / %dtm_modified%</div>
338
+ </div>
339
+ #{CONTENTS_XML}
340
+ </div>
341
+ </div>
342
+ _FILE_PAGE_
343
+
344
+ ###################################################################
345
+
346
+ CLASS_PAGE = %{
347
+ <div id="%full_name%" class="page_shade">
348
+ <div class="page">
349
+ IF:parent
350
+ <h3>%classmod% %full_name% &lt; HREF:par_url:parent:</h3>
351
+ ENDIF:parent
352
+ IFNOT:parent
353
+ <h3>%classmod% %full_name%</h3>
354
+ ENDIF:parent
355
+
356
+ IF:infiles
357
+ (in files
358
+ START:infiles
359
+ HREF:full_path_url:full_path:
360
+ END:infiles
361
+ )
362
+ ENDIF:infiles
363
+ } + CONTENTS_XML + %{
364
+ </div>
365
+ </div>
366
+ }
367
+
368
+ ###################################################################
369
+
370
+ METHOD_LIST = %{
371
+ IF:includes
372
+ <div class="tablesubsubtitle">Included modules</div><br>
373
+ <div class="name-list">
374
+ START:includes
375
+ <span class="method-name">HREF:aref:name:</span>
376
+ END:includes
377
+ </div>
378
+ ENDIF:includes
379
+
380
+ IF:method_list
381
+ START:method_list
382
+ IF:methods
383
+ <table cellpadding=5 width="100%">
384
+ <tr><td class="tablesubtitle">%type% %category% methods</td></tr>
385
+ </table>
386
+ START:methods
387
+ <table width="100%" cellspacing = 0 cellpadding=5 border=0>
388
+ <tr><td class="methodtitle">
389
+ <a name="%aref%">
390
+ IF:callseq
391
+ <b>%callseq%</b>
392
+ ENDIF:callseq
393
+ IFNOT:callseq
394
+ <b>%name%</b>%params%
395
+ ENDIF:callseq
396
+ IF:codeurl
397
+ <a href="%codeurl%" target="source" class="srclink">src</a>
398
+ ENDIF:codeurl
399
+ </a></td></tr>
400
+ </table>
401
+ IF:m_desc
402
+ <div class="description">
403
+ %m_desc%
404
+ </div>
405
+ ENDIF:m_desc
406
+ IF:aka
407
+ <div class="aka">
408
+ This method is also aliased as
409
+ START:aka
410
+ <a href="%aref%">%name%</a>
411
+ END:aka
412
+ </div>
413
+ ENDIF:aka
414
+ IF:sourcecode
415
+ <div class="sourcecode">
416
+ <p class="source-link">[ <a href="javascript:toggleSource('%aref%_source')" id="l_%aref%_source">show source</a> ]</p>
417
+ <div id="%aref%_source" class="dyn-source">
418
+ <pre>
419
+ %sourcecode%
420
+ </pre>
421
+ </div>
422
+ </div>
423
+ ENDIF:sourcecode
424
+ END:methods
425
+ ENDIF:methods
426
+ END:method_list
427
+ ENDIF:method_list
428
+ }
429
+
430
+
431
+ ########################## Index ################################
432
+
433
+ FR_INDEX_BODY = %{
434
+ !INCLUDE!
435
+ }
436
+
437
+ FILE_INDEX = %{
438
+ <html>
439
+ <head>
440
+ <meta http-equiv="Content-Type" content="text/html; charset=%charset%">
441
+ <style>
442
+ <!--
443
+ body {
444
+ background-color: #ddddff;
445
+ font-family: #{FONTS};
446
+ font-size: 11px;
447
+ font-style: normal;
448
+ line-height: 14px;
449
+ color: #000040;
450
+ }
451
+ div.banner {
452
+ background: #0000aa;
453
+ color: white;
454
+ padding: 1;
455
+ margin: 0;
456
+ font-size: 90%;
457
+ font-weight: bold;
458
+ line-height: 1.1;
459
+ text-align: center;
460
+ width: 100%;
461
+ }
462
+
463
+ -->
464
+ </style>
465
+ <base target="docwin">
466
+ </head>
467
+ <body>
468
+ <div class="banner">%list_title%</div>
469
+ START:entries
470
+ <a href="%href%">%name%</a><br>
471
+ END:entries
472
+ </body></html>
473
+ }
474
+
475
+ CLASS_INDEX = FILE_INDEX
476
+ METHOD_INDEX = FILE_INDEX
477
+
478
+ INDEX = %{
479
+ <HTML>
480
+ <HEAD>
481
+ <META HTTP-EQUIV="refresh" content="0;URL=%initial_page%">
482
+ <TITLE>%realtitle%</TITLE>
483
+ </HEAD>
484
+ <BODY>
485
+ Click <a href="%initial_page%">here</a> to open the Camping docs.
486
+ </BODY>
487
+ </HTML>
488
+ }
489
+
490
+ end
491
+ end
@@ -0,0 +1,132 @@
1
+ # == About camping/ar/session.rb
2
+ #
3
+ # This file contains two modules which supply basic sessioning to your Camping app.
4
+ # Again, we're dealing with a pretty little bit of code: approx. 60 lines.
5
+ #
6
+ # * Camping::Models::Session is a module which adds a single <tt>sessions</tt> table
7
+ # to your database.
8
+ # * Camping::ARSession is a module which you will mix into your application (or into
9
+ # specific controllers which require sessions) to supply a <tt>@state</tt> variable
10
+ # you can use in controllers and views.
11
+ #
12
+ # For a basic tutorial, see the *Getting Started* section of the Camping::ARSession module.
13
+ require 'camping'
14
+ require 'camping/ar'
15
+
16
+ module Camping::Models
17
+ # A database table for storing Camping sessions. Contains a unique 32-character hashid, a
18
+ # creation timestamp, and a column of serialized data called <tt>ivars</tt>.
19
+ class Session < Base
20
+ serialize :ivars
21
+ set_primary_key :hashid
22
+
23
+ def []=(k, v) # :nodoc:
24
+ self.ivars[k] = v
25
+ end
26
+ def [](k) # :nodoc:
27
+ self.ivars[k] rescue nil
28
+ end
29
+
30
+ protected
31
+ RAND_CHARS = [*'A'..'Z'] + [*'0'..'9'] + [*'a'..'z']
32
+ def before_create
33
+ rand_max = RAND_CHARS.size
34
+ sid = (0...32).inject("") { |ret,_| ret << RAND_CHARS[rand(rand_max)] }
35
+ write_attribute('hashid', sid)
36
+ end
37
+
38
+ # Generates a new session ID and creates a row for the new session in the database.
39
+ def self.generate cookies
40
+ sess = Session.create :ivars => Camping::H[]
41
+ cookies.camping_sid = sess.hashid
42
+ sess
43
+ end
44
+
45
+ # Gets the existing session based on the <tt>camping_sid</tt> available in cookies.
46
+ # If none is found, generates a new session.
47
+ def self.persist cookies
48
+ session = nil
49
+ if cookies.camping_sid
50
+ session = Camping::Models::Session.find_by_hashid cookies.camping_sid
51
+ end
52
+ unless session
53
+ session = Camping::Models::Session.generate cookies
54
+ end
55
+ session
56
+ end
57
+
58
+ # Builds the session table in the database. To be used in your application's
59
+ # <tt>create</tt> method.
60
+ #
61
+ # Like so:
62
+ #
63
+ # def Blog.create
64
+ # Camping::Models::Session.create_schema
65
+ # unless Blog::Models::Post.table_exists?
66
+ # ActiveRecord::Schema.define(&Blog::Models.schema)
67
+ # end
68
+ # end
69
+ #
70
+ def self.create_schema
71
+ unless table_exists?
72
+ ActiveRecord::Schema.define do
73
+ create_table :sessions, :force => true, :id => false do |t|
74
+ t.column :hashid, :string, :limit => 32, :null => false
75
+ t.column :created_at, :datetime
76
+ t.column :ivars, :text
77
+ end
78
+ add_index :sessions, [:hashid], :unique => true
79
+ end
80
+ reset_column_information
81
+ end
82
+ end
83
+ end
84
+ Session.partial_updates = false if Session.respond_to?(:partial_updates=)
85
+ end
86
+
87
+ module Camping
88
+ # The Camping::ARSession module is designed to be mixed into your application or into specific
89
+ # controllers which require sessions. This module defines a <tt>service</tt> method which
90
+ # intercepts all requests handed to those controllers.
91
+ #
92
+ # == Getting Started
93
+ #
94
+ # To get sessions working for your application:
95
+ #
96
+ # 1. <tt>require 'camping/session'</tt>
97
+ # 2. Mixin the module: <tt>module YourApp; include Camping::ARSession end</tt>
98
+ # 3. In your application's <tt>create</tt> method, add a call to <tt>Camping::Models::Session.create_schema</tt>
99
+ # 4. Throughout your application, use the <tt>@state</tt> var like a hash to store your application's data.
100
+ #
101
+ # If you are unfamiliar with the <tt>create</tt> method, see
102
+ # http://code.whytheluckystiff.net/camping/wiki/GiveUsTheCreateMethod.
103
+ #
104
+ # == A Few Notes
105
+ #
106
+ # * The session ID is stored in a cookie. Look in <tt>@cookies.camping_sid</tt>.
107
+ # * The session data is stored in the <tt>sessions</tt> table in your database.
108
+ # * All mounted Camping apps using this class will use the same database table.
109
+ # * However, your application's data is stored in its own hash.
110
+ # * Session data is only saved if it has changed.
111
+ module ARSession
112
+ # This <tt>service</tt> method, when mixed into controllers, intercepts requests
113
+ # and wraps them with code to start and close the session. If a session isn't found
114
+ # in the database it is created. The <tt>@state</tt> variable is set and if it changes,
115
+ # it is saved back into the database.
116
+ def service(*a)
117
+ session = Camping::Models::Session.persist @cookies
118
+ app = self.class.name.gsub(/^(\w+)::.+$/, '\1')
119
+ @state = (session[app] ||= Camping::H[])
120
+ hash_before = Marshal.dump(@state).hash
121
+ return super(*a)
122
+ ensure
123
+ if session
124
+ hash_after = Marshal.dump(@state).hash
125
+ unless hash_before == hash_after
126
+ session[app] = @state
127
+ session.save
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,78 @@
1
+ class MissingLibrary < Exception #:nodoc: all
2
+ end
3
+ begin
4
+ require 'active_record'
5
+ rescue LoadError => e
6
+ raise MissingLibrary, "ActiveRecord could not be loaded (is it installed?): #{e.message}"
7
+ end
8
+
9
+ $AR_EXTRAS = %{
10
+ Base = ActiveRecord::Base unless const_defined? :Base
11
+
12
+ def Y; ActiveRecord::Base.verify_active_connections!; self; end
13
+
14
+ class SchemaInfo < Base
15
+ end
16
+
17
+ def self.V(n)
18
+ @final = [n, @final.to_i].max
19
+ m = (@migrations ||= [])
20
+ Class.new(ActiveRecord::Migration) do
21
+ meta_def(:version) { n }
22
+ meta_def(:inherited) { |k| m << k }
23
+ end
24
+ end
25
+
26
+ def self.create_schema(opts = {})
27
+ opts[:assume] ||= 0
28
+ opts[:version] ||= @final
29
+ if @migrations
30
+ unless SchemaInfo.table_exists?
31
+ ActiveRecord::Schema.define do
32
+ create_table SchemaInfo.table_name do |t|
33
+ t.column :version, :float
34
+ end
35
+ end
36
+ end
37
+
38
+ si = SchemaInfo.find(:first) || SchemaInfo.new(:version => opts[:assume])
39
+ if si.version < opts[:version]
40
+ @migrations.each do |k|
41
+ k.migrate(:up) if si.version < k.version and k.version <= opts[:version]
42
+ k.migrate(:down) if si.version > k.version and k.version > opts[:version]
43
+ end
44
+ si.update_attributes(:version => opts[:version])
45
+ end
46
+ end
47
+ end
48
+ }
49
+
50
+ module Camping
51
+ module Models
52
+ A = ActiveRecord
53
+ # Base is an alias for ActiveRecord::Base. The big warning I'm going to give you
54
+ # about this: *Base overloads table_name_prefix.* This means that if you have a
55
+ # model class Blog::Models::Post, it's table name will be <tt>blog_posts</tt>.
56
+ #
57
+ # ActiveRecord is not loaded if you never reference this class. The minute you
58
+ # use the ActiveRecord or Camping::Models::Base class, then the ActiveRecord library
59
+ # is loaded.
60
+ Base = A::Base
61
+
62
+ # The default prefix for Camping model classes is the topmost module name lowercase
63
+ # and followed with an underscore.
64
+ #
65
+ # Tepee::Models::Page.table_name_prefix
66
+ # #=> "tepee_pages"
67
+ #
68
+ def Base.table_name_prefix
69
+ "#{name[/\w+/]}_".downcase.sub(/^(#{A}|camping)_/i,'')
70
+ end
71
+ module_eval $AR_EXTRAS
72
+ end
73
+ end
74
+ Camping::S.sub! /autoload\s*:Base\s*,\s*['"]camping\/ar['"]/, ""
75
+ Camping::S.sub! /def\s*Y[;\s]*self[;\s]*end/, $AR_EXTRAS
76
+ Camping::Apps.each do |c|
77
+ c::Models.module_eval $AR_EXTRAS
78
+ end