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,26 @@
1
+ class MissingLibrary < Exception #:nodoc: all
2
+ end
3
+ begin
4
+ require 'markaby'
5
+ rescue LoadError => e
6
+ raise MissingLibrary, "Markaby could not be loaded (is it installed?): #{e.message}"
7
+ end
8
+
9
+ $MAB_CODE = %{
10
+ # The Mab class wraps Markaby, allowing it to run methods from Camping::Views
11
+ # and also to replace :href, :action and :src attributes in tags by prefixing the root
12
+ # path.
13
+ class Mab < Markaby::Builder
14
+ include Views
15
+ def tag!(*g,&b)
16
+ h=g[-1]
17
+ [:href,:action,:src].map{|a|(h[a]&&=self/h[a])rescue 0}
18
+ super
19
+ end
20
+ end
21
+ }
22
+
23
+ Camping::S.sub! /autoload\s*:Mab\s*,\s*['"]camping\/mab['"]/, $MAB_CODE
24
+ Camping::Apps.each do |c|
25
+ c.module_eval $MAB_CODE
26
+ end
@@ -0,0 +1,163 @@
1
+ module Camping
2
+ # == The Camping Reloader
3
+ #
4
+ # Camping apps are generally small and predictable. Many Camping apps are
5
+ # contained within a single file. Larger apps are split into a handful of
6
+ # other Ruby libraries within the same directory.
7
+ #
8
+ # Since Camping apps (and their dependencies) are loaded with Ruby's require
9
+ # method, there is a record of them in $LOADED_FEATURES. Which leaves a
10
+ # perfect space for this class to manage auto-reloading an app if any of its
11
+ # immediate dependencies changes.
12
+ #
13
+ # == Wrapping Your Apps
14
+ #
15
+ # Since bin/camping and the Camping::FastCGI class already use the Reloader,
16
+ # you probably don't need to hack it on your own. But, if you're rolling your
17
+ # own situation, here's how.
18
+ #
19
+ # Rather than this:
20
+ #
21
+ # require 'yourapp'
22
+ #
23
+ # Use this:
24
+ #
25
+ # require 'camping/reloader'
26
+ # Camping::Reloader.new('/path/to/yourapp.rb')
27
+ #
28
+ # The reloader will take care of requiring the app and monitoring all files
29
+ # for alterations.
30
+ class Reloader
31
+ attr_accessor :klass, :mtime, :mount, :requires
32
+
33
+ # Creates the reloader, assigns a +script+ to it and initially loads the
34
+ # application. Pass in the full path to the script, otherwise the script
35
+ # will be loaded relative to the current working directory.
36
+ def initialize(script)
37
+ @script = File.expand_path(script)
38
+ @mount = File.basename(script, '.rb')
39
+ @requires = nil
40
+ load_app
41
+ end
42
+
43
+ # Find the application, based on the script name.
44
+ def find_app(title)
45
+ @klass = Object.const_get(Object.constants.grep(/^#{title}$/i)[0]) rescue nil
46
+ end
47
+
48
+ # If the file isn't found, if we need to remove the app from the global
49
+ # namespace, this will be sure to do so and set @klass to nil.
50
+ def remove_app
51
+ if @klass
52
+ Camping::Apps.delete(@klass)
53
+ Object.send :remove_const, @klass.name
54
+ @klass = nil
55
+ end
56
+ end
57
+
58
+ # Loads (or reloads) the application. The reloader will take care of calling
59
+ # this for you. You can certainly call it yourself if you feel it's warranted.
60
+ def load_app
61
+ title = File.basename(@script)[/^([\w_]+)/,1].gsub /_/,''
62
+ begin
63
+ all_requires = $LOADED_FEATURES.dup
64
+ load @script
65
+ @requires = ($LOADED_FEATURES - all_requires).select do |req|
66
+ req.index(File.basename(@script) + "/") == 0 || req.index(title + "/") == 0
67
+ end
68
+ rescue Exception => e
69
+ puts "!! trouble loading #{title.inspect}: [#{e.class}] #{e.message}"
70
+ puts e.backtrace.join("\n")
71
+ find_app title
72
+ remove_app
73
+ return
74
+ end
75
+
76
+ @mtime = mtime
77
+ find_app title
78
+ unless @klass and @klass.const_defined? :C
79
+ puts "!! trouble loading #{title.inspect}: not a Camping app, no #{title.capitalize} module found"
80
+ remove_app
81
+ return
82
+ end
83
+
84
+ Reloader.conditional_connect
85
+ @klass.create if @klass.respond_to? :create
86
+ puts "** #{title.inspect} app loaded"
87
+ @klass
88
+ end
89
+
90
+ # The timestamp of the most recently modified app dependency.
91
+ def mtime
92
+ ((@requires || []) + [@script]).map do |fname|
93
+ fname = fname.gsub(/^#{Regexp::quote File.dirname(@script)}\//, '')
94
+ begin
95
+ File.mtime(File.join(File.dirname(@script), fname))
96
+ rescue Errno::ENOENT
97
+ remove_app
98
+ @mtime
99
+ end
100
+ end.reject{|t| t > Time.now }.max
101
+ end
102
+
103
+ # Conditional reloading of the app. This gets called on each request and
104
+ # only reloads if the modification times on any of the files is updated.
105
+ def reload_app
106
+ return if @klass and @mtime and mtime <= @mtime
107
+
108
+ if @requires
109
+ @requires.each { |req| $LOADED_FEATURES.delete(req) }
110
+ end
111
+ remove_app
112
+ load_app
113
+ end
114
+
115
+ # Conditionally reloads (using reload_app.) Then passes the request through
116
+ # to the wrapped Camping app.
117
+ def call(*a)
118
+ reload_app
119
+ if @klass
120
+ @klass.call(*a)
121
+ else
122
+ Camping.call(*a)
123
+ end
124
+ end
125
+
126
+ # Returns source code for the main script in the application.
127
+ def view_source
128
+ File.read(@script)
129
+ end
130
+
131
+ class << self
132
+ attr_writer :database, :log
133
+
134
+ def conditional_connect
135
+ # If database models are present, `autoload?` will return nil.
136
+ unless Camping::Models.autoload? :Base
137
+ if @database and @database[:adapter] == 'sqlite3'
138
+ begin
139
+ require 'sqlite3_api'
140
+ rescue LoadError
141
+ puts "!! Your SQLite3 adapter isn't a compiled extension."
142
+ abort "!! Please check out http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for tips."
143
+ end
144
+ end
145
+
146
+ case @log
147
+ when Logger
148
+ Camping::Models::Base.logger = @log
149
+ when String
150
+ require 'logger'
151
+ Camping::Models::Base.logger = Logger.new(@log == "-" ? STDOUT : @log)
152
+ end
153
+
154
+ Camping::Models::Base.establish_connection @database if @database
155
+
156
+ if Camping::Models.const_defined?(:Session)
157
+ Camping::Models::Session.create_schema
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,158 @@
1
+ require 'irb'
2
+ require 'rack'
3
+ require 'camping/reloader'
4
+
5
+ module Camping::Server
6
+ class Base < Hash
7
+ include Enumerable
8
+
9
+ attr_reader :paths
10
+ attr_accessor :conf
11
+
12
+ def initialize(conf, paths = [])
13
+ unless conf.database
14
+ raise "!! No home directory found. Please specify a database file, see --help."
15
+ end
16
+
17
+ @conf = conf
18
+ Camping::Reloader.database = conf.database
19
+ Camping::Reloader.log = conf.log
20
+
21
+ @paths = []
22
+ paths.each { |script| add_app script }
23
+ # TODO exception instead of abort()
24
+ # abort("** No apps successfully loaded") unless self.detect { |app| app.klass }
25
+
26
+ end
27
+
28
+ def add_app(path)
29
+ @paths << path
30
+ if File.directory? path
31
+ Dir[File.join(path, '*.rb')].each { |s| insert_app(s)}
32
+ else
33
+ insert_app(path)
34
+ end
35
+ # TODO check to see if the application is created or not... exception perhaps?
36
+ end
37
+
38
+ def find_new_scripts
39
+ self.values.each { |app| app.reload_app }
40
+ @paths.each do |path|
41
+ Dir[File.join(path, '*.rb')].each do |script|
42
+ smount = File.basename(script, '.rb')
43
+ next if detect { |x| x.mount == smount }
44
+
45
+ puts "** Discovered new #{script}"
46
+ # TODO hmm. the next should be handled by the add_app thingy
47
+ app = insert_app(script)
48
+ next unless app
49
+
50
+ yield app
51
+
52
+ end
53
+ end
54
+ self.values.sort! { |x, y| x.mount <=> y.mount }
55
+ end
56
+ def index_page
57
+ welcome = "You are Camping"
58
+ apps = self
59
+ <<-HTML
60
+ <html>
61
+ <head>
62
+ <title>#{welcome}</title>
63
+ <style type="text/css">
64
+ body {
65
+ font-family: verdana, arial, sans-serif;
66
+ padding: 10px 40px;
67
+ margin: 0;
68
+ }
69
+ h1, h2, h3, h4, h5, h6 {
70
+ font-family: utopia, georgia, serif;
71
+ }
72
+ </style>
73
+ </head>
74
+ <body>
75
+ <h1>#{welcome}</h1>
76
+ <p>Good day. These are the Camping apps you've mounted.</p>
77
+ <ul>
78
+ #{apps.values.select{|app|app.klass}.map do |app|
79
+ "<li><h3 style=\"display: inline\"><a href=\"/#{app.mount}\">#{app.klass.name}</a></h3><small> / <a href=\"/code/#{app.mount}\">View source</a></small></li>"
80
+ end.join("\n")}
81
+ </ul>
82
+ </body>
83
+ </html>
84
+ HTML
85
+ end
86
+
87
+ def each(&b)
88
+ self.values.each(&b)
89
+ end
90
+
91
+ # for RSpec tests
92
+ def apps
93
+ self.values
94
+ end
95
+
96
+ def start
97
+ handler, conf = case @conf.server
98
+ when "console"
99
+ ARGV.clear
100
+ IRB.start
101
+ exit
102
+ when "mongrel"
103
+ puts "** Starting Mongrel on #{@conf.host}:#{@conf.port}"
104
+ [Rack::Handler::Mongrel, {:Port => @conf.port, :Host => @conf.host}]
105
+ when "webrick"
106
+ [Rack::Handler::WEBrick, {:Port => @conf.port, :BindAddress => @conf.host}]
107
+ end
108
+
109
+ rapp = if apps.length > 1
110
+ hash = {
111
+ "/" => proc {|env|[200,{'Content-Type'=>'text/html'},index_page]}
112
+ }
113
+ apps.each do |app|
114
+ hash["/#{app.mount}"] = app
115
+ hash["/code/#{app.mount}"] = proc do |env|
116
+ [200,{'Content-Type'=>'text/plain'},app.view_source]
117
+ end
118
+ end
119
+ Rack::URLMap.new(hash)
120
+ else
121
+ apps.first
122
+ end
123
+ rapp = Rack::Lint.new(rapp)
124
+ rapp = XSendfile.new(rapp)
125
+ rapp = Rack::ShowExceptions.new(rapp)
126
+ handler.run(rapp, conf)
127
+ end
128
+
129
+ private
130
+
131
+ def insert_app(script)
132
+ self[script] = Camping::Reloader.new(script)
133
+ end
134
+ end
135
+
136
+ # A Rack middleware for reading X-Sendfile. Should only be used in
137
+ # development.
138
+ class XSendfile
139
+
140
+ HEADERS = [
141
+ "X-Sendfile",
142
+ "X-Accel-Redirect",
143
+ "X-LIGHTTPD-send-file"
144
+ ]
145
+
146
+ def initialize(app)
147
+ @app = app
148
+ end
149
+
150
+ def call(env)
151
+ status, headers, body = @app.call(env)
152
+ if path = headers.values_at(*HEADERS).compact.first
153
+ body = File.read(path)
154
+ end
155
+ [status, headers, body]
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,74 @@
1
+ # == About camping/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::Session 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::Session module.
13
+ #require 'camping'
14
+ require 'base64'
15
+ require 'openssl'
16
+
17
+ module Camping
18
+ # The Camping::Session module is designed to be mixed into your application or into specific
19
+ # controllers which require sessions. This module defines a <tt>service</tt> method which
20
+ # intercepts all requests handed to those controllers.
21
+ #
22
+ # == Getting Started
23
+ #
24
+ # To get sessions working for your application:
25
+ #
26
+ # 1. <tt>require 'camping/session'</tt>
27
+ # 2. Mixin the module: <tt>module YourApp; include Camping::Session end</tt>
28
+ # 3. Define a secret (and keep it secret): <tt>module YourApp; @@state_secret = "SECRET!"; end</tt>
29
+ # 4. Throughout your application, use the <tt>@state</tt> var like a hash to store your application's data.
30
+ #
31
+ # == A Few Notes
32
+ #
33
+ # * The session is stored in a cookie. Look in <tt>@cookies.identity</tt>.
34
+ # * Session data is only saved if it has changed.
35
+ module Session
36
+ DIGEST = OpenSSL::Digest::SHA1.new
37
+ # This <tt>service</tt> method, when mixed into controllers, intercepts requests
38
+ # and wraps them with code to start and close the session. If a session isn't found
39
+ # in the cookie it is created. The <tt>@state</tt> variable is set and if it changes,
40
+ # it is saved back into the cookie.
41
+ def service(*a)
42
+ @session_blob = @input.camping_blob || @cookies.camping_blob
43
+ @session_hash = @input.camping_hash || @cookies.camping_hash
44
+ decoded_blob, data = '', {}
45
+ begin
46
+ if @session_blob && @session_hash && secure_blob_hasher(@session_blob) == @session_hash
47
+ decoded_blob = Base64.decode64(@session_blob)
48
+ data = Marshal.restore(decoded_blob)
49
+ end
50
+
51
+ app = C.name
52
+ @state = (data[app] ||= Camping::H[])
53
+ hash_before = decoded_blob.hash
54
+ return super(*a)
55
+ ensure
56
+ data[app] = @state
57
+ decoded_blob = Marshal.dump(data)
58
+ unless hash_before == decoded_blob.hash
59
+ @session_blob = Base64.encode64(decoded_blob).gsub("\n", '').strip
60
+ @session_hash = secure_blob_hasher(@session_blob)
61
+ raise "The session contains to much data" if @session_blob.length > 4096
62
+ @cookies.camping_blob = @session_blob
63
+ @cookies.camping_hash = @session_hash
64
+ end
65
+ end
66
+ end
67
+
68
+ def secure_blob_hasher(data)
69
+ OpenSSL::HMAC.hexdigest(DIGEST, state_secret, "#{@env.REMOTE_ADDR}#{data}")
70
+ end
71
+
72
+ def state_secret; [__FILE__, File.mtime(__FILE__)].join(":") end
73
+ end
74
+ end