rubycas-server 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.txt +38 -0
- data/Manifest.txt +4 -11
- data/README.txt +1 -1
- data/Rakefile +2 -2
- data/bin/rubycas-server +16 -47
- data/bin/rubycas-server-ctl +13 -154
- data/config.example.yml +113 -64
- data/lib/casserver.rb +78 -80
- data/lib/casserver/authenticators/active_directory_ldap.rb +3 -0
- data/lib/casserver/authenticators/ldap.rb +14 -1
- data/lib/casserver/authenticators/sql_encrypted.rb +75 -0
- data/lib/casserver/controllers.rb +19 -8
- data/lib/casserver/environment.rb +23 -0
- data/lib/casserver/models.rb +104 -53
- data/lib/casserver/utils.rb +0 -24
- data/lib/casserver/version.rb +2 -2
- data/lib/casserver/views.rb +28 -0
- data/lib/rubycas-server.rb +1 -0
- metadata +77 -68
- data/vendor/camping-1.5.180/CHANGELOG +0 -99
- data/vendor/camping-1.5.180/COPYING +0 -18
- data/vendor/camping-1.5.180/README +0 -119
- data/vendor/camping-1.5.180/Rakefile +0 -117
- data/vendor/camping-1.5.180/lib/camping-unabridged.rb +0 -762
- data/vendor/camping-1.5.180/lib/camping.rb +0 -55
- data/vendor/camping-1.5.180/lib/camping/db.rb +0 -78
- data/vendor/camping-1.5.180/lib/camping/fastcgi.rb +0 -244
- data/vendor/camping-1.5.180/lib/camping/reloader.rb +0 -163
- data/vendor/camping-1.5.180/lib/camping/session.rb +0 -123
- data/vendor/camping-1.5.180/lib/camping/webrick.rb +0 -68
@@ -1,117 +0,0 @@
|
|
1
|
-
require 'rake'
|
2
|
-
require 'rake/clean'
|
3
|
-
require 'rake/gempackagetask'
|
4
|
-
require 'rake/rdoctask'
|
5
|
-
require 'rake/testtask'
|
6
|
-
require 'fileutils'
|
7
|
-
include FileUtils
|
8
|
-
|
9
|
-
NAME = "camping"
|
10
|
-
REV = File.read(".svn/entries")[/committed-rev="(\d+)"/, 1] rescue nil
|
11
|
-
VERS = ENV['VERSION'] || ("1.5" + (REV ? ".#{REV}" : ""))
|
12
|
-
CLEAN.include ['**/.*.sw?', '*.gem', '.config', 'test/test.log']
|
13
|
-
RDOC_OPTS = ['--quiet', '--title', "Camping, the Documentation",
|
14
|
-
"--opname", "index.html",
|
15
|
-
"--line-numbers",
|
16
|
-
"--main", "README",
|
17
|
-
"--inline-source"]
|
18
|
-
|
19
|
-
desc "Packages up Camping."
|
20
|
-
task :default => [:package]
|
21
|
-
task :package => [:clean]
|
22
|
-
|
23
|
-
task :doc => [:before_doc, :rdoc, :after_doc]
|
24
|
-
|
25
|
-
task :before_doc do
|
26
|
-
mv "lib/camping.rb", "lib/camping-mural.rb"
|
27
|
-
mv "lib/camping-unabridged.rb", "lib/camping.rb"
|
28
|
-
end
|
29
|
-
|
30
|
-
Rake::RDocTask.new do |rdoc|
|
31
|
-
rdoc.rdoc_dir = 'doc/rdoc'
|
32
|
-
rdoc.options += RDOC_OPTS
|
33
|
-
rdoc.template = "extras/flipbook_rdoc.rb"
|
34
|
-
rdoc.main = "README"
|
35
|
-
rdoc.title = "Camping, the Documentation"
|
36
|
-
rdoc.rdoc_files.add ['README', 'CHANGELOG', 'COPYING', 'lib/camping.rb', 'lib/camping/*.rb']
|
37
|
-
end
|
38
|
-
|
39
|
-
task :after_doc do
|
40
|
-
mv "lib/camping.rb", "lib/camping-unabridged.rb"
|
41
|
-
mv "lib/camping-mural.rb", "lib/camping.rb"
|
42
|
-
cp "extras/Camping.gif", "doc/rdoc/"
|
43
|
-
cp "extras/permalink.gif", "doc/rdoc/"
|
44
|
-
sh %{scp -r doc/rdoc/* #{ENV['USER']}@rubyforge.org:/var/www/gforge-projects/camping/}
|
45
|
-
end
|
46
|
-
|
47
|
-
spec =
|
48
|
-
Gem::Specification.new do |s|
|
49
|
-
s.name = NAME
|
50
|
-
s.version = VERS
|
51
|
-
s.platform = Gem::Platform::RUBY
|
52
|
-
s.has_rdoc = true
|
53
|
-
s.extra_rdoc_files = ["README", "CHANGELOG", "COPYING"]
|
54
|
-
s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)\/', '--exclude', 'lib/camping.rb']
|
55
|
-
s.summary = "minature rails for stay-at-home moms"
|
56
|
-
s.description = s.summary
|
57
|
-
s.author = "why the lucky stiff"
|
58
|
-
s.email = 'why@ruby-lang.org'
|
59
|
-
s.homepage = 'http://code.whytheluckystiff.net/camping/'
|
60
|
-
s.executables = ['camping']
|
61
|
-
|
62
|
-
s.add_dependency('activesupport', '>=1.3.1')
|
63
|
-
s.add_dependency('markaby', '>=0.5')
|
64
|
-
s.add_dependency('metaid')
|
65
|
-
s.required_ruby_version = '>= 1.8.2'
|
66
|
-
|
67
|
-
s.files = %w(COPYING README Rakefile) +
|
68
|
-
Dir.glob("{bin,doc,test,lib,extras}/**/*") +
|
69
|
-
Dir.glob("ext/**/*.{h,c,rb}") +
|
70
|
-
Dir.glob("examples/**/*.rb") +
|
71
|
-
Dir.glob("tools/*.rb")
|
72
|
-
|
73
|
-
s.require_path = "lib"
|
74
|
-
# s.extensions = FileList["ext/**/extconf.rb"].to_a
|
75
|
-
s.bindir = "bin"
|
76
|
-
end
|
77
|
-
|
78
|
-
omni =
|
79
|
-
Gem::Specification.new do |s|
|
80
|
-
s.name = "camping-omnibus"
|
81
|
-
s.version = VERS
|
82
|
-
s.platform = Gem::Platform::RUBY
|
83
|
-
s.summary = "the camping meta-package for updating ActiveRecord, Mongrel and SQLite3 bindings"
|
84
|
-
s.description = s.summary
|
85
|
-
%w[author email homepage].each { |x| s.__send__("#{x}=", spec.__send__(x)) }
|
86
|
-
|
87
|
-
s.add_dependency('camping', "=#{VERS}")
|
88
|
-
s.add_dependency('activerecord')
|
89
|
-
s.add_dependency('sqlite3-ruby', '>=1.1.0.1')
|
90
|
-
s.add_dependency('mongrel')
|
91
|
-
s.add_dependency('acts_as_versioned')
|
92
|
-
s.add_dependency('RedCloth')
|
93
|
-
end
|
94
|
-
|
95
|
-
Rake::GemPackageTask.new(spec) do |p|
|
96
|
-
p.need_tar = true
|
97
|
-
p.gem_spec = spec
|
98
|
-
end
|
99
|
-
|
100
|
-
Rake::GemPackageTask.new(omni) do |p|
|
101
|
-
p.gem_spec = omni
|
102
|
-
end
|
103
|
-
|
104
|
-
task :install do
|
105
|
-
sh %{rake package}
|
106
|
-
sh %{sudo gem install pkg/#{NAME}-#{VERS}}
|
107
|
-
end
|
108
|
-
|
109
|
-
task :uninstall => [:clean] do
|
110
|
-
sh %{sudo gem uninstall #{NAME}}
|
111
|
-
end
|
112
|
-
|
113
|
-
Rake::TestTask.new(:test) do |t|
|
114
|
-
t.test_files = FileList['test/test_*.rb']
|
115
|
-
# t.warning = true
|
116
|
-
# t.verbose = true
|
117
|
-
end
|
@@ -1,762 +0,0 @@
|
|
1
|
-
# == About camping.rb
|
2
|
-
#
|
3
|
-
# Camping comes with two versions of its source code. The code contained in
|
4
|
-
# lib/camping.rb is compressed, stripped of whitespace, using compact algorithms
|
5
|
-
# to keep it tight. The unspoken rule is that camping.rb should be flowed with
|
6
|
-
# no more than 80 characters per line and must not exceed four kilobytes.
|
7
|
-
#
|
8
|
-
# On the other hand, lib/camping-unabridged.rb contains the same code, laid out
|
9
|
-
# nicely with piles of documentation everywhere. This documentation is entirely
|
10
|
-
# generated from lib/camping-unabridged.rb using RDoc and our "flipbook" template
|
11
|
-
# found in the extras directory of any camping distribution.
|
12
|
-
#
|
13
|
-
# == Requirements
|
14
|
-
#
|
15
|
-
# Camping requires at least Ruby 1.8.2.
|
16
|
-
#
|
17
|
-
# Camping depends on the following libraries. If you install through RubyGems,
|
18
|
-
# these will be automatically installed for you.
|
19
|
-
#
|
20
|
-
# * ActiveRecord, used in your models.
|
21
|
-
# ActiveRecord is an object-to-relational database mapper with adapters
|
22
|
-
# for SQLite3, MySQL, PostgreSQL, SQL Server and more.
|
23
|
-
# * Markaby, used in your views to describe HTML in plain Ruby.
|
24
|
-
# * MetAid, a few metaprogramming methods which Camping uses.
|
25
|
-
# * Tempfile, for storing file uploads.
|
26
|
-
#
|
27
|
-
# Camping also works well with Mongrel, the swift Ruby web server.
|
28
|
-
# http://rubyforge.org/projects/mongrel Mongrel comes with examples
|
29
|
-
# in its <tt>examples/camping</tt> directory.
|
30
|
-
#
|
31
|
-
%w[active_support markaby tempfile uri].each { |lib| require lib }
|
32
|
-
|
33
|
-
# == Camping
|
34
|
-
#
|
35
|
-
# The camping module contains three modules for separating your application:
|
36
|
-
#
|
37
|
-
# * Camping::Models for your database interaction classes, all derived from ActiveRecord::Base.
|
38
|
-
# * Camping::Controllers for storing controller classes, which map URLs to code.
|
39
|
-
# * Camping::Views for storing methods which generate HTML.
|
40
|
-
#
|
41
|
-
# Of use to you is also one module for storing helpful additional methods:
|
42
|
-
#
|
43
|
-
# * Camping::Helpers which can be used in controllers and views.
|
44
|
-
#
|
45
|
-
# == The Camping Server
|
46
|
-
#
|
47
|
-
# How do you run Camping apps? Oh, uh... The Camping Server!
|
48
|
-
#
|
49
|
-
# The Camping Server is, firstly and thusly, a set of rules. At the very least, The Camping Server must:
|
50
|
-
#
|
51
|
-
# * Load all Camping apps in a directory.
|
52
|
-
# * Load new apps that appear in that directory.
|
53
|
-
# * Mount those apps according to their filename. (e.g. blog.rb is mounted at /blog.)
|
54
|
-
# * Run each app's <tt>create</tt> method upon startup.
|
55
|
-
# * Reload the app if its modification time changes.
|
56
|
-
# * Reload the app if it requires any files under the same directory and one of their modification times changes.
|
57
|
-
# * Support the X-Sendfile header.
|
58
|
-
#
|
59
|
-
# In fact, Camping comes with its own little The Camping Server.
|
60
|
-
#
|
61
|
-
# At a command prompt, run: <tt>camping examples/</tt> and the entire <tt>examples/</tt> directory will be served.
|
62
|
-
#
|
63
|
-
# Configurations also exist for Apache and Lighttpd. See http://code.whytheluckystiff.net/camping/wiki/TheCampingServer.
|
64
|
-
#
|
65
|
-
# == The <tt>create</tt> method
|
66
|
-
#
|
67
|
-
# Many postambles will check for your application's <tt>create</tt> method and will run it
|
68
|
-
# when the web server starts up. This is a good place to check for database tables and create
|
69
|
-
# those tables to save users of your application from needing to manually set them up.
|
70
|
-
#
|
71
|
-
# def Blog.create
|
72
|
-
# unless Blog::Models::Post.table_exists?
|
73
|
-
# ActiveRecord::Schema.define do
|
74
|
-
# create_table :blog_posts, :force => true do |t|
|
75
|
-
# t.column :id, :integer, :null => false
|
76
|
-
# t.column :user_id, :integer, :null => false
|
77
|
-
# t.column :title, :string, :limit => 255
|
78
|
-
# t.column :body, :text
|
79
|
-
# end
|
80
|
-
# end
|
81
|
-
# end
|
82
|
-
# end
|
83
|
-
#
|
84
|
-
# For more tips, see http://code.whytheluckystiff.net/camping/wiki/GiveUsTheCreateMethod.
|
85
|
-
module Camping
|
86
|
-
# Stores an +Array+ of all Camping applications modules. Modules are added
|
87
|
-
# automatically by +Camping.goes+.
|
88
|
-
#
|
89
|
-
# Camping.goes :Blog
|
90
|
-
# Camping.goes :Tepee
|
91
|
-
# Camping::Apps # => [Blog, Tepee]
|
92
|
-
#
|
93
|
-
Apps = []
|
94
|
-
C = self
|
95
|
-
S = IO.read(__FILE__).sub(/^ S = I.+$/,'')
|
96
|
-
P="Cam\ping Problem!"
|
97
|
-
|
98
|
-
H = HashWithIndifferentAccess
|
99
|
-
# An object-like Hash, based on ActiveSupport's HashWithIndifferentAccess.
|
100
|
-
# All Camping query string and cookie variables are loaded as this.
|
101
|
-
#
|
102
|
-
# To access the query string, for instance, use the <tt>@input</tt> variable.
|
103
|
-
#
|
104
|
-
# module Blog::Models
|
105
|
-
# class Index < R '/'
|
106
|
-
# def get
|
107
|
-
# if page = @input.page.to_i > 0
|
108
|
-
# page -= 1
|
109
|
-
# end
|
110
|
-
# @posts = Post.find :all, :offset => page * 20, :limit => 20
|
111
|
-
# render :index
|
112
|
-
# end
|
113
|
-
# end
|
114
|
-
# end
|
115
|
-
#
|
116
|
-
# In the above example if you visit <tt>/?page=2</tt>, you'll get the second
|
117
|
-
# page of twenty posts. You can also use <tt>@input[:page]</tt> or <tt>@input['page']</tt>
|
118
|
-
# to get the value for the <tt>page</tt> query variable.
|
119
|
-
#
|
120
|
-
# Use the <tt>@cookies</tt> variable in the same fashion to access cookie variables.
|
121
|
-
# Also, the <tt>@env</tt> variable is an H containing the HTTP headers and server info.
|
122
|
-
class H
|
123
|
-
# Gets or sets keys in the hash.
|
124
|
-
#
|
125
|
-
# @cookies.my_favorite = :macadamian
|
126
|
-
# @cookies.my_favorite
|
127
|
-
# => :macadamian
|
128
|
-
#
|
129
|
-
def method_missing(m,*a)
|
130
|
-
m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m]:raise(NoMethodError,"#{m}")
|
131
|
-
end
|
132
|
-
alias_method :u, :regular_update
|
133
|
-
end
|
134
|
-
|
135
|
-
# Helpers contains methods available in your controllers and views. You may add
|
136
|
-
# methods of your own to this module, including many helper methods from Rails.
|
137
|
-
# This is analogous to Rails' <tt>ApplicationHelper</tt> module.
|
138
|
-
#
|
139
|
-
# == Using ActionPack Helpers
|
140
|
-
#
|
141
|
-
# If you'd like to include helpers from Rails' modules, you'll need to look up the
|
142
|
-
# helper module in the Rails documentation at http://api.rubyonrails.org/.
|
143
|
-
#
|
144
|
-
# For example, if you look up the <tt>ActionView::Helpers::FormHelper</tt> class,
|
145
|
-
# you'll find that it's loaded from the <tt>action_view/helpers/form_helper.rb</tt>
|
146
|
-
# file. You'll need to have the ActionPack gem installed for this to work.
|
147
|
-
#
|
148
|
-
# require 'action_view/helpers/form_helper.rb'
|
149
|
-
#
|
150
|
-
# # This example is unfinished.. soon..
|
151
|
-
#
|
152
|
-
module Helpers
|
153
|
-
# From inside your controllers and views, you will often need to figure out
|
154
|
-
# the route used to get to a certain controller +c+. Pass the controller class
|
155
|
-
# and any arguments into the R method, a string containing the route will be
|
156
|
-
# returned to you.
|
157
|
-
#
|
158
|
-
# Assuming you have a specific route in an edit controller:
|
159
|
-
#
|
160
|
-
# class Edit < R '/edit/(\d+)'
|
161
|
-
#
|
162
|
-
# A specific route to the Edit controller can be built with:
|
163
|
-
#
|
164
|
-
# R(Edit, 1)
|
165
|
-
#
|
166
|
-
# Which outputs: <tt>/edit/1</tt>.
|
167
|
-
#
|
168
|
-
# You may also pass in a model object and the ID of the object will be used.
|
169
|
-
#
|
170
|
-
# If a controller has many routes, the route will be selected if it is the
|
171
|
-
# first in the routing list to have the right number of arguments.
|
172
|
-
#
|
173
|
-
# == Using R in the View
|
174
|
-
#
|
175
|
-
# Keep in mind that this route doesn't include the root path.
|
176
|
-
# You will need to use <tt>/</tt> (the slash method above) in your controllers.
|
177
|
-
# Or, go ahead and use the Helpers#URL method to build a complete URL for a route.
|
178
|
-
#
|
179
|
-
# However, in your views, the :href, :src and :action attributes automatically
|
180
|
-
# pass through the slash method, so you are encouraged to use <tt>R</tt> or
|
181
|
-
# <tt>URL</tt> in your views.
|
182
|
-
#
|
183
|
-
# module Blog::Views
|
184
|
-
# def menu
|
185
|
-
# div.menu! do
|
186
|
-
# a 'Home', :href => URL()
|
187
|
-
# a 'Profile', :href => "/profile"
|
188
|
-
# a 'Logout', :href => R(Logout)
|
189
|
-
# a 'Google', :href => 'http://google.com'
|
190
|
-
# end
|
191
|
-
# end
|
192
|
-
# end
|
193
|
-
#
|
194
|
-
# Let's say the above example takes place inside an application mounted at
|
195
|
-
# <tt>http://localhost:3301/frodo</tt> and that a controller named <tt>Logout</tt>
|
196
|
-
# is assigned to route <tt>/logout</tt>. The HTML will come out as:
|
197
|
-
#
|
198
|
-
# <div id="menu">
|
199
|
-
# <a href="//localhost:3301/frodo/">Home</a>
|
200
|
-
# <a href="/frodo/profile">Profile</a>
|
201
|
-
# <a href="/frodo/logout">Logout</a>
|
202
|
-
# <a href="http://google.com">Google</a>
|
203
|
-
# </div>
|
204
|
-
#
|
205
|
-
def R(c,*g)
|
206
|
-
p,h=/\(.+?\)/,g.grep(Hash)
|
207
|
-
(g-=h).inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|
|
208
|
-
s.sub p,C.escape((a[a.class.primary_key]rescue a))
|
209
|
-
}+(h.any?? "?"+h[0].map{|x|x.map{|z|C.escape z}*"="}*"&": "")
|
210
|
-
end
|
211
|
-
|
212
|
-
# Shows AR validation errors for the object passed.
|
213
|
-
# There is no output if there are no errors.
|
214
|
-
#
|
215
|
-
# An example might look like:
|
216
|
-
#
|
217
|
-
# errors_for @post
|
218
|
-
#
|
219
|
-
# Might (depending on actual data) render something like this in Markaby:
|
220
|
-
#
|
221
|
-
# ul.errors do
|
222
|
-
# li "Body can't be empty"
|
223
|
-
# li "Title must be unique"
|
224
|
-
# end
|
225
|
-
#
|
226
|
-
# Add a simple ul.errors {color:red; font-weight:bold;} CSS rule and you
|
227
|
-
# have built-in, usable error checking in only one line of code. :-)
|
228
|
-
#
|
229
|
-
# See AR validation documentation for details on validations.
|
230
|
-
def errors_for(o); ul.errors { o.errors.each_full { |er| li er } } if o.errors.any?; end
|
231
|
-
# Simply builds a complete path from a path +p+ within the app. If your application is
|
232
|
-
# mounted at <tt>/blog</tt>:
|
233
|
-
#
|
234
|
-
# self / "/view/1" #=> "/blog/view/1"
|
235
|
-
# self / "styles.css" #=> "styles.css"
|
236
|
-
# self / R(Edit, 1) #=> "/blog/edit/1"
|
237
|
-
#
|
238
|
-
def /(p); p[/^\//]?@root+p:p end
|
239
|
-
# Builds a URL route to a controller or a path, returning a URI object.
|
240
|
-
# This way you'll get the hostname and the port number, a complete URL.
|
241
|
-
# No scheme is given (http or https).
|
242
|
-
#
|
243
|
-
# You can use this to grab URLs for controllers using the R-style syntax.
|
244
|
-
# So, if your application is mounted at <tt>http://test.ing/blog/</tt>
|
245
|
-
# and you have a View controller which routes as <tt>R '/view/(\d+)'</tt>:
|
246
|
-
#
|
247
|
-
# URL(View, @post.id) #=> #<URL://test.ing/blog/view/12>
|
248
|
-
#
|
249
|
-
# Or you can use the direct path:
|
250
|
-
#
|
251
|
-
# self.URL #=> #<URL://test.ing/blog/>
|
252
|
-
# self.URL + "view/12" #=> #<URL://test.ing/blog/view/12>
|
253
|
-
# URL("/view/12") #=> #<URL://test.ing/blog/view/12>
|
254
|
-
#
|
255
|
-
# Since no scheme is given, you will need to add the scheme yourself:
|
256
|
-
#
|
257
|
-
# "http" + URL("/view/12") #=> "http://test.ing/blog/view/12"
|
258
|
-
#
|
259
|
-
# It's okay to pass URL strings through this method as well:
|
260
|
-
#
|
261
|
-
# URL("http://google.com") #=> #<URI:http://google.com>
|
262
|
-
#
|
263
|
-
# Any string which doesn't begin with a slash will pass through
|
264
|
-
# unscathed.
|
265
|
-
def URL c='/',*a
|
266
|
-
c = R(c, *a) if c.respond_to? :urls
|
267
|
-
c = self/c
|
268
|
-
c = "//"+@env.HTTP_HOST+c if c[/^\//]
|
269
|
-
URI(c)
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
# Camping::Base is built into each controller by way of the generic routing
|
274
|
-
# class Camping::R. In some ways, this class is trying to do too much, but
|
275
|
-
# it saves code for all the glue to stay in one place.
|
276
|
-
#
|
277
|
-
# Forgivable, considering that it's only really a handful of methods and accessors.
|
278
|
-
#
|
279
|
-
# == Treating controller methods like Response objects
|
280
|
-
#
|
281
|
-
# Camping originally came with a barebones Response object, but it's often much more readable
|
282
|
-
# to just use your controller as the response.
|
283
|
-
#
|
284
|
-
# Go ahead and alter the status, cookies, headers and body instance variables as you
|
285
|
-
# see fit in order to customize the response.
|
286
|
-
#
|
287
|
-
# module Camping::Controllers
|
288
|
-
# class SoftLink
|
289
|
-
# def get
|
290
|
-
# redirect "/"
|
291
|
-
# end
|
292
|
-
# end
|
293
|
-
# end
|
294
|
-
#
|
295
|
-
# Is equivalent to:
|
296
|
-
#
|
297
|
-
# module Camping::Controllers
|
298
|
-
# class SoftLink
|
299
|
-
# def get
|
300
|
-
# @status = 302
|
301
|
-
# @headers['Location'] = "/"
|
302
|
-
# end
|
303
|
-
# end
|
304
|
-
# end
|
305
|
-
#
|
306
|
-
module Base
|
307
|
-
include Helpers
|
308
|
-
attr_accessor :input, :cookies, :env, :headers, :body, :status, :root
|
309
|
-
Z = "\r\n"
|
310
|
-
|
311
|
-
# Display a view, calling it by its method name +m+. If a <tt>layout</tt>
|
312
|
-
# method is found in Camping::Views, it will be used to wrap the HTML.
|
313
|
-
#
|
314
|
-
# module Camping::Controllers
|
315
|
-
# class Show
|
316
|
-
# def get
|
317
|
-
# @posts = Post.find :all
|
318
|
-
# render :index
|
319
|
-
# end
|
320
|
-
# end
|
321
|
-
# end
|
322
|
-
#
|
323
|
-
def render(m); end; undef_method :render
|
324
|
-
|
325
|
-
# Any stray method calls will be passed to Markaby. This means you can reply
|
326
|
-
# with HTML directly from your controller for quick debugging.
|
327
|
-
#
|
328
|
-
# module Camping::Controllers
|
329
|
-
# class Info
|
330
|
-
# def get; code @env.inspect end
|
331
|
-
# end
|
332
|
-
# end
|
333
|
-
#
|
334
|
-
# If you have a <tt>layout</tt> method in Camping::Views, it will be used to
|
335
|
-
# wrap the HTML.
|
336
|
-
def method_missing(*a,&b)
|
337
|
-
a.shift if a[0]==:render
|
338
|
-
m=Mab.new({},self)
|
339
|
-
s=m.capture{send(*a,&b)}
|
340
|
-
s=m.capture{send(:layout){s}} if /^_/!~a[0].to_s and m.respond_to?:layout
|
341
|
-
s
|
342
|
-
end
|
343
|
-
|
344
|
-
# Formulate a redirect response: a 302 status with <tt>Location</tt> header
|
345
|
-
# and a blank body. Uses Helpers#URL to build the location from a controller
|
346
|
-
# route or path.
|
347
|
-
#
|
348
|
-
# So, given a root of <tt>http://localhost:3301/articles</tt>:
|
349
|
-
#
|
350
|
-
# redirect "view/12" # redirects to "//localhost:3301/articles/view/12"
|
351
|
-
# redirect View, 12 # redirects to "//localhost:3301/articles/view/12"
|
352
|
-
#
|
353
|
-
# <b>NOTE:</b> This method doesn't magically exit your methods and redirect.
|
354
|
-
# You'll need to <tt>return redirect(...)</tt> if this isn't the last statement
|
355
|
-
# in your code.
|
356
|
-
def redirect(*a)
|
357
|
-
r(302,'','Location'=>URL(*a))
|
358
|
-
end
|
359
|
-
|
360
|
-
# A quick means of setting this controller's status, body and headers.
|
361
|
-
# Used internally by Camping, but... by all means...
|
362
|
-
#
|
363
|
-
# r(302, '', 'Location' => self / "/view/12")
|
364
|
-
#
|
365
|
-
# Is equivalent to:
|
366
|
-
#
|
367
|
-
# redirect "/view/12"
|
368
|
-
#
|
369
|
-
def r(s, b, h = {}); @status = s; @headers.merge!(h); @body = b; end
|
370
|
-
|
371
|
-
# Turn a controller into an array. This is designed to be used to pipe
|
372
|
-
# controllers into the <tt>r</tt> method. A great way to forward your
|
373
|
-
# requests!
|
374
|
-
#
|
375
|
-
# class Read < '/(\d+)'
|
376
|
-
# def get(id)
|
377
|
-
# Post.find(id)
|
378
|
-
# rescue
|
379
|
-
# r *Blog.get(:NotFound, @env.REQUEST_URI)
|
380
|
-
# end
|
381
|
-
# end
|
382
|
-
#
|
383
|
-
def to_a;[@status, @body, @headers] end
|
384
|
-
|
385
|
-
def initialize(r, e, m) #:nodoc:
|
386
|
-
e = H[e.to_hash]
|
387
|
-
@status, @method, @env, @headers, @root = 200, m.downcase, e,
|
388
|
-
{'Content-Type'=>'text/html'}, e.SCRIPT_NAME.sub(/\/$/,'')
|
389
|
-
@k = C.kp(e.HTTP_COOKIE)
|
390
|
-
qs = C.qsp(e.QUERY_STRING)
|
391
|
-
@in = r
|
392
|
-
if %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)|n.match(e.CONTENT_TYPE)
|
393
|
-
b = /(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/
|
394
|
-
until @in.eof?
|
395
|
-
fh=H[]
|
396
|
-
for l in @in
|
397
|
-
case l
|
398
|
-
when Z: break
|
399
|
-
when /^Content-Disposition: form-data;/
|
400
|
-
fh.u H[*$'.scan(/(?:\s(\w+)="([^"]+)")/).flatten]
|
401
|
-
when /^Content-Type: (.+?)(\r$|\Z)/m
|
402
|
-
puts "=> fh[type] = #$1"
|
403
|
-
fh[:type] = $1
|
404
|
-
end
|
405
|
-
end
|
406
|
-
fn=fh[:name]
|
407
|
-
o=if fh[:filename]
|
408
|
-
o=fh[:tempfile]=Tempfile.new(:C)
|
409
|
-
o.binmode
|
410
|
-
else
|
411
|
-
fh=""
|
412
|
-
end
|
413
|
-
while l=@in.read(16384)
|
414
|
-
if l=~b
|
415
|
-
o<<$`.chomp
|
416
|
-
@in.seek(-$'.size,IO::SEEK_CUR)
|
417
|
-
break
|
418
|
-
end
|
419
|
-
o<<l
|
420
|
-
end
|
421
|
-
C.qsp(fn,'&;',fh,qs) if fn
|
422
|
-
fh[:tempfile].rewind if fh.is_a?H
|
423
|
-
end
|
424
|
-
elsif @method == "post"
|
425
|
-
qs.merge!(C.qsp(@in.read))
|
426
|
-
end
|
427
|
-
@cookies, @input = @k.dup, qs.dup
|
428
|
-
end
|
429
|
-
|
430
|
-
# All requests pass through this method before going to the controller. Some magic
|
431
|
-
# in Camping can be performed by overriding this method.
|
432
|
-
#
|
433
|
-
# See http://code.whytheluckystiff.net/camping/wiki/BeforeAndAfterOverrides for more
|
434
|
-
# on before and after overrides with Camping.
|
435
|
-
def service(*a)
|
436
|
-
@body = send(@method, *a) if respond_to? @method
|
437
|
-
@headers['Set-Cookie'] = @cookies.map { |k,v| "#{k}=#{C.escape(v)}; path=#{self/"/"}" if v != @k[k] } - [nil]
|
438
|
-
self
|
439
|
-
end
|
440
|
-
|
441
|
-
# Used by the web server to convert the current request to a string. If you need to
|
442
|
-
# alter the way Camping builds HTTP headers, consider overriding this method.
|
443
|
-
def to_s
|
444
|
-
a=[]
|
445
|
-
@headers.map{|k,v|[*v].map{|x|a<<"#{k}: #{x}"}}
|
446
|
-
"Status: #{@status}#{Z+a*Z+Z*2+@body}"
|
447
|
-
end
|
448
|
-
|
449
|
-
end
|
450
|
-
|
451
|
-
# Controllers is a module for placing classes which handle URLs. This is done
|
452
|
-
# by defining a route to each class using the Controllers::R method.
|
453
|
-
#
|
454
|
-
# module Camping::Controllers
|
455
|
-
# class Edit < R '/edit/(\d+)'
|
456
|
-
# def get; end
|
457
|
-
# def post; end
|
458
|
-
# end
|
459
|
-
# end
|
460
|
-
#
|
461
|
-
# If no route is set, Camping will guess the route from the class name.
|
462
|
-
# The rule is very simple: the route becomes a slash followed by the lowercased
|
463
|
-
# class name. See Controllers::D for the complete rules of dispatch.
|
464
|
-
#
|
465
|
-
# == Special classes
|
466
|
-
#
|
467
|
-
# There are two special classes used for handling 404 and 500 errors. The
|
468
|
-
# NotFound class handles URLs not found. The ServerError class handles exceptions
|
469
|
-
# uncaught by your application.
|
470
|
-
module Controllers
|
471
|
-
@r = []
|
472
|
-
class << self
|
473
|
-
def r #:nodoc:
|
474
|
-
@r
|
475
|
-
end
|
476
|
-
# Add routes to a controller class by piling them into the R method.
|
477
|
-
#
|
478
|
-
# module Camping::Controllers
|
479
|
-
# class Edit < R '/edit/(\d+)', '/new'
|
480
|
-
# def get(id)
|
481
|
-
# if id # edit
|
482
|
-
# else # new
|
483
|
-
# end
|
484
|
-
# end
|
485
|
-
# end
|
486
|
-
# end
|
487
|
-
#
|
488
|
-
# You will need to use routes in either of these cases:
|
489
|
-
#
|
490
|
-
# * You want to assign multiple routes to a controller.
|
491
|
-
# * You want your controller to receive arguments.
|
492
|
-
#
|
493
|
-
# Most of the time the rules inferred by dispatch method Controllers::D will get you
|
494
|
-
# by just fine.
|
495
|
-
def R *u
|
496
|
-
r=@r
|
497
|
-
Class.new {
|
498
|
-
meta_def(:urls){u}
|
499
|
-
meta_def(:inherited){|x|r<<x}
|
500
|
-
}
|
501
|
-
end
|
502
|
-
|
503
|
-
# Dispatch routes to controller classes.
|
504
|
-
# For each class, routes are checked for a match based on their order in the routing list
|
505
|
-
# given to Controllers::R. If no routes were given, the dispatcher uses a slash followed
|
506
|
-
# by the name of the controller lowercased.
|
507
|
-
#
|
508
|
-
# Controllers are searched in this order:
|
509
|
-
#
|
510
|
-
# # Classes without routes, since they refer to a very specific URL.
|
511
|
-
# # Classes with routes are searched in order of their creation.
|
512
|
-
#
|
513
|
-
# So, define your catch-all controllers last.
|
514
|
-
def D(path)
|
515
|
-
r.map { |k|
|
516
|
-
k.urls.map { |x|
|
517
|
-
return k, $~[1..-1] if path =~ /^#{x}\/?$/
|
518
|
-
}
|
519
|
-
}
|
520
|
-
[NotFound, [path]]
|
521
|
-
end
|
522
|
-
|
523
|
-
# The route maker, this is called by Camping internally, you shouldn't need to call it.
|
524
|
-
#
|
525
|
-
# Still, it's worth know what this method does. Since Ruby doesn't keep track of class
|
526
|
-
# creation order, we're keeping an internal list of the controllers which inherit from R().
|
527
|
-
# This method goes through and adds all the remaining routes to the beginning of the list
|
528
|
-
# and ensures all the controllers have the right mixins.
|
529
|
-
#
|
530
|
-
# Anyway, if you are calling the URI dispatcher from outside of a Camping server, you'll
|
531
|
-
# definitely need to call this at least once to set things up.
|
532
|
-
def M
|
533
|
-
def M #:nodoc:
|
534
|
-
end
|
535
|
-
constants.map { |c|
|
536
|
-
k=const_get(c)
|
537
|
-
k.send :include,C,Base,Models
|
538
|
-
r[0,0]=k if !r.include?k
|
539
|
-
k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls
|
540
|
-
}
|
541
|
-
end
|
542
|
-
end
|
543
|
-
|
544
|
-
# The NotFound class is a special controller class for handling 404 errors, in case you'd
|
545
|
-
# like to alter the appearance of the 404. The path is passed in as +p+.
|
546
|
-
#
|
547
|
-
# module Camping::Controllers
|
548
|
-
# class NotFound
|
549
|
-
# def get(p)
|
550
|
-
# @status = 404
|
551
|
-
# div do
|
552
|
-
# h1 'Camping Problem!'
|
553
|
-
# h2 "#{p} not found"
|
554
|
-
# end
|
555
|
-
# end
|
556
|
-
# end
|
557
|
-
# end
|
558
|
-
#
|
559
|
-
class NotFound < R()
|
560
|
-
def get(p)
|
561
|
-
r(404, Mab.new{h1(P);h2("#{p} not found")})
|
562
|
-
end
|
563
|
-
end
|
564
|
-
|
565
|
-
# The ServerError class is a special controller class for handling many (but not all) 500 errors.
|
566
|
-
# If there is a parse error in Camping or in your application's source code, it will not be caught
|
567
|
-
# by Camping. The controller class +k+ and request method +m+ (GET, POST, etc.) where the error
|
568
|
-
# took place are passed in, along with the Exception +e+ which can be mined for useful info.
|
569
|
-
#
|
570
|
-
# module Camping::Controllers
|
571
|
-
# class ServerError
|
572
|
-
# def get(k,m,e)
|
573
|
-
# @status = 500
|
574
|
-
# div do
|
575
|
-
# h1 'Camping Problem!'
|
576
|
-
# h2 "in #{k}.#{m}"
|
577
|
-
# h3 "#{e.class} #{e.message}:"
|
578
|
-
# ul do
|
579
|
-
# e.backtrace.each do |bt|
|
580
|
-
# li bt
|
581
|
-
# end
|
582
|
-
# end
|
583
|
-
# end
|
584
|
-
# end
|
585
|
-
# end
|
586
|
-
# end
|
587
|
-
#
|
588
|
-
class ServerError < R()
|
589
|
-
def get(k,m,e)
|
590
|
-
r(500, Mab.new {
|
591
|
-
h1(P)
|
592
|
-
h2 "#{k}.#{m}"
|
593
|
-
h3 "#{e.class} #{e.message}:"
|
594
|
-
ul { e.backtrace.each { |bt| li bt } }
|
595
|
-
}.to_s)
|
596
|
-
end
|
597
|
-
end
|
598
|
-
end
|
599
|
-
X = Controllers
|
600
|
-
|
601
|
-
class << self
|
602
|
-
# When you are running many applications, you may want to create independent
|
603
|
-
# modules for each Camping application. Namespaces for each. Camping::goes
|
604
|
-
# defines a toplevel constant with the whole MVC rack inside.
|
605
|
-
#
|
606
|
-
# require 'camping'
|
607
|
-
# Camping.goes :Blog
|
608
|
-
#
|
609
|
-
# module Blog::Controllers; ... end
|
610
|
-
# module Blog::Models; ... end
|
611
|
-
# module Blog::Views; ... end
|
612
|
-
#
|
613
|
-
def goes(m)
|
614
|
-
eval S.gsub(/Camping/,m.to_s).gsub("A\pps = []","Cam\ping::Apps<<self"), TOPLEVEL_BINDING
|
615
|
-
end
|
616
|
-
|
617
|
-
# URL escapes a string.
|
618
|
-
#
|
619
|
-
# Camping.escape("I'd go to the museum straightway!")
|
620
|
-
# #=> "I%27d+go+to+the+museum+straightway%21"
|
621
|
-
#
|
622
|
-
def escape(s); s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.unpack('H2'*$&.size)*'%').upcase}.tr(' ', '+') end
|
623
|
-
|
624
|
-
# Unescapes a URL-encoded string.
|
625
|
-
#
|
626
|
-
# Camping.un("I%27d+go+to+the+museum+straightway%21")
|
627
|
-
# #=> "I'd go to the museum straightway!"
|
628
|
-
#
|
629
|
-
def un(s); s.tr('+', ' ').gsub(/%([\da-f]{2})/in){[$1].pack('H*')} end
|
630
|
-
|
631
|
-
# Parses a query string into an Camping::H object.
|
632
|
-
#
|
633
|
-
# input = Camping.qsp("name=Philarp+Tremain&hair=sandy+blonde")
|
634
|
-
# input.name
|
635
|
-
# #=> "Philarp Tremaine"
|
636
|
-
#
|
637
|
-
# Also parses out the Hash-like syntax used in PHP and Rails and builds
|
638
|
-
# nested hashes from it.
|
639
|
-
#
|
640
|
-
# input = Camping.qsp("post[id]=1&post[user]=_why")
|
641
|
-
# #=> {'post' => {'id' => '1', 'user' => '_why'}}
|
642
|
-
#
|
643
|
-
def qsp(qs, d='&;', y=nil, z=H[])
|
644
|
-
m = proc {|_,o,n|o.u(n,&m)rescue([*o]<<n)}
|
645
|
-
(qs||'').
|
646
|
-
split(/[#{d}] */n).
|
647
|
-
inject((b,z=z,H[])[0]) { |h,p| k, v=un(p).split('=',2)
|
648
|
-
h.u(k.split(/[\]\[]+/).reverse.
|
649
|
-
inject(y||v) { |x,i| H[i,x] },&m)
|
650
|
-
}
|
651
|
-
end
|
652
|
-
|
653
|
-
# Parses a string of cookies from the <tt>Cookie</tt> header.
|
654
|
-
def kp(s); c = qsp(s, ';,'); end
|
655
|
-
|
656
|
-
# Fields a request through Camping. For traditional CGI applications, the method can be
|
657
|
-
# executed without arguments.
|
658
|
-
#
|
659
|
-
# if __FILE__ == $0
|
660
|
-
# Camping::Models::Base.establish_connection :adapter => 'sqlite3',
|
661
|
-
# :database => 'blog3.db'
|
662
|
-
# Camping::Models::Base.logger = Logger.new('camping.log')
|
663
|
-
# puts Camping.run
|
664
|
-
# end
|
665
|
-
#
|
666
|
-
# The Camping controller returned from <tt>run</tt> has a <tt>to_s</tt> method in case you
|
667
|
-
# are running from CGI or want to output the full HTTP output. In the above example, <tt>puts</tt>
|
668
|
-
# will call <tt>to_s</tt> for you.
|
669
|
-
#
|
670
|
-
# For FastCGI and Webrick-loaded applications, you will need to use a request loop, with <tt>run</tt>
|
671
|
-
# at the center, passing in the read +r+ and write +w+ streams. You will also need to mimick or
|
672
|
-
# pass in the <tt>ENV</tt> replacement as part of your wrapper.
|
673
|
-
#
|
674
|
-
# See Camping::FastCGI and Camping::WEBrick for examples.
|
675
|
-
#
|
676
|
-
def run(r=$stdin,e=ENV)
|
677
|
-
X.M
|
678
|
-
k,a=X.D un("/#{e['PATH_INFO']}".gsub(/\/+/,'/'))
|
679
|
-
k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.service *a
|
680
|
-
rescue Object=>x
|
681
|
-
X::ServerError.new(r,e,'get').service(k,m,x)
|
682
|
-
end
|
683
|
-
|
684
|
-
# The Camping scriptable dispatcher. Any unhandled method call to the app module will
|
685
|
-
# be sent to a controller class, specified as an argument.
|
686
|
-
#
|
687
|
-
# Blog.get(:Index)
|
688
|
-
# #=> #<Blog::Controllers::Index ... >
|
689
|
-
#
|
690
|
-
# The controller object contains all the @cookies, @body, @headers, etc. formulated by
|
691
|
-
# the response.
|
692
|
-
#
|
693
|
-
# You can also feed environment variables and query variables as a hash, the final
|
694
|
-
# argument.
|
695
|
-
#
|
696
|
-
# Blog.post(:Login, :input => {'username' => 'admin', 'password' => 'camping'})
|
697
|
-
# #=> #<Blog::Controllers::Login @user=... >
|
698
|
-
#
|
699
|
-
# Blog.get(:Info, :env => {:HTTP_HOST => 'wagon'})
|
700
|
-
# #=> #<Blog::Controllers::Info @env={'HTTP_HOST'=>'wagon'} ...>
|
701
|
-
#
|
702
|
-
def method_missing(m, c, *a)
|
703
|
-
X.M
|
704
|
-
k = X.const_get(c).new(StringIO.new,
|
705
|
-
H['HTTP_HOST','','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s)
|
706
|
-
H.new(a.pop).each { |e,f| k.send("#{e}=",f) } if Hash === a[-1]
|
707
|
-
k.service *a
|
708
|
-
end
|
709
|
-
end
|
710
|
-
|
711
|
-
# Models is an empty Ruby module for housing model classes derived
|
712
|
-
# from ActiveRecord::Base. As a shortcut, you may derive from Base
|
713
|
-
# which is an alias for ActiveRecord::Base.
|
714
|
-
#
|
715
|
-
# module Camping::Models
|
716
|
-
# class Post < Base; belongs_to :user end
|
717
|
-
# class User < Base; has_many :posts end
|
718
|
-
# end
|
719
|
-
#
|
720
|
-
# == Where Models are Used
|
721
|
-
#
|
722
|
-
# Models are used in your controller classes. However, if your model class
|
723
|
-
# name conflicts with a controller class name, you will need to refer to it
|
724
|
-
# using the Models module.
|
725
|
-
#
|
726
|
-
# module Camping::Controllers
|
727
|
-
# class Post < R '/post/(\d+)'
|
728
|
-
# def get(post_id)
|
729
|
-
# @post = Models::Post.find post_id
|
730
|
-
# render :index
|
731
|
-
# end
|
732
|
-
# end
|
733
|
-
# end
|
734
|
-
#
|
735
|
-
# Models cannot be referred to in Views at this time.
|
736
|
-
module Models
|
737
|
-
autoload :Base,'camping/db'
|
738
|
-
def Y;self;end
|
739
|
-
end
|
740
|
-
|
741
|
-
# Views is an empty module for storing methods which create HTML. The HTML is described
|
742
|
-
# using the Markaby language.
|
743
|
-
#
|
744
|
-
# == Using the layout method
|
745
|
-
#
|
746
|
-
# If your Views module has a <tt>layout</tt> method defined, it will be called with a block
|
747
|
-
# which will insert content from your view.
|
748
|
-
module Views; include Controllers, Helpers end
|
749
|
-
|
750
|
-
# The Mab class wraps Markaby, allowing it to run methods from Camping::Views
|
751
|
-
# and also to replace :href, :action and :src attributes in tags by prefixing the root
|
752
|
-
# path.
|
753
|
-
class Mab < Markaby::Builder
|
754
|
-
include Views
|
755
|
-
def tag!(*g,&b)
|
756
|
-
h=g[-1]
|
757
|
-
[:href,:action,:src].each{|a|(h[a]=self/h[a])rescue 0}
|
758
|
-
super
|
759
|
-
end
|
760
|
-
end
|
761
|
-
end
|
762
|
-
|