raw 0.49.0
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/CONTRIBUTORS +106 -0
- data/doc/LICENSE +32 -0
- data/doc/coding_conventions.txt +11 -0
- data/lib/raw.rb +42 -0
- data/lib/raw/adapter.rb +113 -0
- data/lib/raw/adapter/cgi.rb +41 -0
- data/lib/raw/adapter/fastcgi.rb +48 -0
- data/lib/raw/adapter/mongrel.rb +146 -0
- data/lib/raw/adapter/script.rb +94 -0
- data/lib/raw/adapter/webrick.rb +144 -0
- data/lib/raw/adapter/webrick/vcr.rb +91 -0
- data/lib/raw/cgi.rb +323 -0
- data/lib/raw/cgi/cookie.rb +47 -0
- data/lib/raw/cgi/http.rb +62 -0
- data/lib/raw/compiler.rb +138 -0
- data/lib/raw/compiler/filter/cleanup.rb +21 -0
- data/lib/raw/compiler/filter/elements.rb +166 -0
- data/lib/raw/compiler/filter/elements/element.rb +210 -0
- data/lib/raw/compiler/filter/localization.rb +23 -0
- data/lib/raw/compiler/filter/markup.rb +32 -0
- data/lib/raw/compiler/filter/morph.rb +123 -0
- data/lib/raw/compiler/filter/morph/each.rb +34 -0
- data/lib/raw/compiler/filter/morph/for.rb +11 -0
- data/lib/raw/compiler/filter/morph/if.rb +26 -0
- data/lib/raw/compiler/filter/morph/selected_if.rb +43 -0
- data/lib/raw/compiler/filter/morph/standard.rb +55 -0
- data/lib/raw/compiler/filter/morph/times.rb +27 -0
- data/lib/raw/compiler/filter/script.rb +116 -0
- data/lib/raw/compiler/filter/squeeze.rb +16 -0
- data/lib/raw/compiler/filter/static_include.rb +74 -0
- data/lib/raw/compiler/filter/template.rb +121 -0
- data/lib/raw/compiler/reloader.rb +96 -0
- data/lib/raw/context.rb +154 -0
- data/lib/raw/context/flash.rb +157 -0
- data/lib/raw/context/global.rb +88 -0
- data/lib/raw/context/request.rb +338 -0
- data/lib/raw/context/response.rb +57 -0
- data/lib/raw/context/session.rb +198 -0
- data/lib/raw/context/session/drb.rb +11 -0
- data/lib/raw/context/session/file.rb +15 -0
- data/lib/raw/context/session/memcached.rb +13 -0
- data/lib/raw/context/session/memory.rb +12 -0
- data/lib/raw/context/session/og.rb +15 -0
- data/lib/raw/context/session/pstore.rb +13 -0
- data/lib/raw/control.rb +18 -0
- data/lib/raw/control/attribute.rb +91 -0
- data/lib/raw/control/attribute/checkbox.rb +25 -0
- data/lib/raw/control/attribute/datetime.rb +21 -0
- data/lib/raw/control/attribute/file.rb +20 -0
- data/lib/raw/control/attribute/fixnum.rb +26 -0
- data/lib/raw/control/attribute/float.rb +26 -0
- data/lib/raw/control/attribute/options.rb +38 -0
- data/lib/raw/control/attribute/password.rb +16 -0
- data/lib/raw/control/attribute/text.rb +16 -0
- data/lib/raw/control/attribute/textarea.rb +16 -0
- data/lib/raw/control/none.rb +16 -0
- data/lib/raw/control/relation.rb +59 -0
- data/lib/raw/control/relation/belongs_to.rb +0 -0
- data/lib/raw/control/relation/has_many.rb +97 -0
- data/lib/raw/control/relation/joins_many.rb +0 -0
- data/lib/raw/control/relation/many_to_many.rb +0 -0
- data/lib/raw/control/relation/refers_to.rb +29 -0
- data/lib/raw/controller.rb +37 -0
- data/lib/raw/controller/publishable.rb +160 -0
- data/lib/raw/dispatcher.rb +209 -0
- data/lib/raw/dispatcher/format.rb +108 -0
- data/lib/raw/dispatcher/format/atom.rb +31 -0
- data/lib/raw/dispatcher/format/css.rb +0 -0
- data/lib/raw/dispatcher/format/html.rb +42 -0
- data/lib/raw/dispatcher/format/json.rb +31 -0
- data/lib/raw/dispatcher/format/rss.rb +33 -0
- data/lib/raw/dispatcher/format/xoxo.rb +31 -0
- data/lib/raw/dispatcher/mounter.rb +60 -0
- data/lib/raw/dispatcher/router.rb +111 -0
- data/lib/raw/errors.rb +19 -0
- data/lib/raw/helper.rb +86 -0
- data/lib/raw/helper/benchmark.rb +23 -0
- data/lib/raw/helper/buffer.rb +60 -0
- data/lib/raw/helper/cookie.rb +32 -0
- data/lib/raw/helper/debug.rb +28 -0
- data/lib/raw/helper/default.rb +16 -0
- data/lib/raw/helper/feed.rb +451 -0
- data/lib/raw/helper/form.rb +284 -0
- data/lib/raw/helper/javascript.rb +59 -0
- data/lib/raw/helper/layout.rb +40 -0
- data/lib/raw/helper/navigation.rb +87 -0
- data/lib/raw/helper/pager.rb +305 -0
- data/lib/raw/helper/table.rb +247 -0
- data/lib/raw/helper/xhtml.rb +218 -0
- data/lib/raw/helper/xml.rb +125 -0
- data/lib/raw/mixin/magick.rb +35 -0
- data/lib/raw/mixin/sweeper.rb +71 -0
- data/lib/raw/mixin/thumbnails.rb +1 -0
- data/lib/raw/mixin/webfile.rb +165 -0
- data/lib/raw/render.rb +271 -0
- data/lib/raw/render/builder.rb +26 -0
- data/lib/raw/render/caching.rb +81 -0
- data/lib/raw/render/call.rb +43 -0
- data/lib/raw/render/send_file.rb +46 -0
- data/lib/raw/render/stream.rb +39 -0
- data/lib/raw/scaffold.rb +13 -0
- data/lib/raw/scaffold/controller.rb +25 -0
- data/lib/raw/scaffold/model.rb +157 -0
- data/lib/raw/test.rb +5 -0
- data/lib/raw/test/assertions.rb +169 -0
- data/lib/raw/test/context.rb +55 -0
- data/lib/raw/test/testcase.rb +79 -0
- data/lib/raw/util/attr.rb +128 -0
- data/lib/raw/util/encode_uri.rb +149 -0
- data/lib/raw/util/html_filter.rb +538 -0
- data/lib/raw/util/markup.rb +130 -0
- data/test/glue/tc_webfile.rb +1 -0
- data/test/nitro/CONFIG.rb +3 -0
- data/test/nitro/adapter/raw_post1.bin +9 -0
- data/test/nitro/adapter/tc_webrick.rb +16 -0
- data/test/nitro/cgi/tc_cookie.rb +14 -0
- data/test/nitro/cgi/tc_request.rb +61 -0
- data/test/nitro/compiler/tc_client_morpher.rb +47 -0
- data/test/nitro/compiler/tc_compiler.rb +25 -0
- data/test/nitro/dispatcher/tc_mounter.rb +47 -0
- data/test/nitro/helper/tc_feed.rb +135 -0
- data/test/nitro/helper/tc_navbar.rb +74 -0
- data/test/nitro/helper/tc_pager.rb +35 -0
- data/test/nitro/helper/tc_table.rb +68 -0
- data/test/nitro/helper/tc_xhtml.rb +19 -0
- data/test/nitro/tc_caching.rb +19 -0
- data/test/nitro/tc_cgi.rb +222 -0
- data/test/nitro/tc_context.rb +17 -0
- data/test/nitro/tc_controller.rb +103 -0
- data/test/nitro/tc_controller_aspect.rb +32 -0
- data/test/nitro/tc_controller_params.rb +885 -0
- data/test/nitro/tc_dispatcher.rb +109 -0
- data/test/nitro/tc_element.rb +85 -0
- data/test/nitro/tc_flash.rb +59 -0
- data/test/nitro/tc_helper.rb +47 -0
- data/test/nitro/tc_render.rb +119 -0
- data/test/nitro/tc_router.rb +61 -0
- data/test/nitro/tc_server.rb +35 -0
- data/test/nitro/tc_session.rb +66 -0
- data/test/nitro/tc_template.rb +71 -0
- data/test/nitro/util/tc_encode_url.rb +87 -0
- data/test/nitro/util/tc_markup.rb +31 -0
- data/test/public/blog/another/very_litle/index.xhtml +1 -0
- data/test/public/blog/inc1.xhtml +2 -0
- data/test/public/blog/inc2.xhtml +1 -0
- data/test/public/blog/list.xhtml +9 -0
- data/test/public/dummy_mailer/registration.xhtml +5 -0
- metadata +244 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
require "facets/more/settings"
|
4
|
+
require "facets/core/file/self/write"
|
5
|
+
require "facets/core/kernel/eigenclass"
|
6
|
+
|
7
|
+
module Raw
|
8
|
+
|
9
|
+
# Add output caching to the Render.
|
10
|
+
|
11
|
+
module Caching
|
12
|
+
|
13
|
+
# Enable or disable view caching.
|
14
|
+
|
15
|
+
setting :enabled, :default => true, :doc => "Enable view caching"
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Cache the output (view) of the current action.
|
20
|
+
|
21
|
+
def cache_output
|
22
|
+
return unless (caching_enabled? and caching_allowed?)
|
23
|
+
|
24
|
+
if self.class.ann(@action, :cache) # or self.class.ann(:self, :cache)
|
25
|
+
path = File.join(@context.application.public_dir, @context.path)
|
26
|
+
FileUtils.makedirs(File.dirname(path))
|
27
|
+
Logger.debug "Caching '#{path}'" if $DBG
|
28
|
+
File.write(path, @out)
|
29
|
+
end
|
30
|
+
rescue => ex
|
31
|
+
Logger.error ex.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
# Explicitly expire the given cached file. If the filename has
|
35
|
+
# no extension attach .* to expire the cached files for
|
36
|
+
# all format representations.
|
37
|
+
#--
|
38
|
+
# TODO: use encode_uri
|
39
|
+
#++
|
40
|
+
|
41
|
+
def expire_output(*args)
|
42
|
+
path = encode_uri(*args)
|
43
|
+
|
44
|
+
if File.extname(path).blank?
|
45
|
+
# Clear all cached representations.
|
46
|
+
if path =~ %r{/$}
|
47
|
+
path << "index.*"
|
48
|
+
else
|
49
|
+
path << ".*"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
path = File.join(Context.current.application.public_dir, path)
|
54
|
+
|
55
|
+
Logger.debug "Expiring cache files '#{path}'" if $DBG
|
56
|
+
FileUtils.rm_rf(path)
|
57
|
+
rescue => ex
|
58
|
+
# drink it!
|
59
|
+
end
|
60
|
+
alias_method :delete_output, :expire_output
|
61
|
+
|
62
|
+
# Enable or disable caching. Can be overriden per controller
|
63
|
+
# for extra fine grained caching control.
|
64
|
+
|
65
|
+
def caching_enabled?
|
66
|
+
Caching.enabled
|
67
|
+
end
|
68
|
+
|
69
|
+
# Is caching allowed for this action (page)? The default
|
70
|
+
# implementation does not cache post request or request
|
71
|
+
# with query parameters. You can work arround the second
|
72
|
+
# 'limitation' by cleverly using Nitro's implicit support
|
73
|
+
# for 'nice' URIs.
|
74
|
+
|
75
|
+
def caching_allowed?
|
76
|
+
not (@context.post? or @context.uri =~ /\?/)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Raw
|
2
|
+
|
3
|
+
#--
|
4
|
+
# Seaside style call/answer methods.
|
5
|
+
#++
|
6
|
+
|
7
|
+
module Render
|
8
|
+
|
9
|
+
# Call redirects to the given URI but push the original
|
10
|
+
# URI in a callstack, so that the target can return by
|
11
|
+
# executing answer.
|
12
|
+
#
|
13
|
+
#--
|
14
|
+
# FIXME: dont use yet, you have to encode the branch to
|
15
|
+
# make this safe for use.
|
16
|
+
#++
|
17
|
+
|
18
|
+
def call(*args)
|
19
|
+
(session[:CALL_STACK] ||= []).push(request.uri)
|
20
|
+
redirect(*args)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns from a call by poping the callstack.
|
24
|
+
# Use force = false to make this mechanism more flexible.
|
25
|
+
#--
|
26
|
+
# FIXME: don't use yet.
|
27
|
+
#++
|
28
|
+
|
29
|
+
def answer(force = false, status = 303)
|
30
|
+
if stack = session[:CALL_STACK] and not stack.empty?
|
31
|
+
redirect(stack.pop, :status => status)
|
32
|
+
else
|
33
|
+
if force
|
34
|
+
raise 'Cannot answer, call stack is empty'
|
35
|
+
else
|
36
|
+
redirect_to_home
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "raw/render"
|
2
|
+
|
3
|
+
module Raw
|
4
|
+
|
5
|
+
module Render
|
6
|
+
|
7
|
+
# Send a file download to the client.
|
8
|
+
#
|
9
|
+
# Like render and redirect, the action is exited upon calling
|
10
|
+
#
|
11
|
+
# [+fname+] That name of the file
|
12
|
+
# [+path+] Specifying true mean fname contains the full path.
|
13
|
+
# The default, false, uses Server.public_root as the path.
|
14
|
+
#
|
15
|
+
# [+return+] true on success, false on failure
|
16
|
+
#
|
17
|
+
# === Examples
|
18
|
+
#
|
19
|
+
# require "raw/render/send_file"
|
20
|
+
#
|
21
|
+
# class MyController < Nitro:Controller
|
22
|
+
# def download(fname)
|
23
|
+
# send_file(fname)
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# class MyController < Nitro:Controller
|
28
|
+
# def download
|
29
|
+
# send_file("/etc/password", true)
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
|
33
|
+
def send_file(fname = nil, fullpath = false)
|
34
|
+
fname = fullpath ? fname : "#{@context.application.public_dir}/#{fname}"
|
35
|
+
f = File.open(fname, "rb")
|
36
|
+
@context.response_headers["Cache-control"] = "private"
|
37
|
+
@context.response_headers["Content-Length"] = "#{File.size?(f) || 0}"
|
38
|
+
@context.response_headers["Content-Type"] = "application/force-download"
|
39
|
+
@context.output_buffer = f
|
40
|
+
raise RenderExit
|
41
|
+
end
|
42
|
+
alias_method :sendfile, :send_file
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require "raw/render"
|
2
|
+
|
3
|
+
module Raw
|
4
|
+
|
5
|
+
module Render
|
6
|
+
|
7
|
+
# Enable streaming mode for the current HTTP Response.
|
8
|
+
# You can optionally provide an existing IO object for
|
9
|
+
# streaming.
|
10
|
+
#--
|
11
|
+
# This code is considered a hack fix. But it still is useful
|
12
|
+
# so for the moment it stays in the distribution.
|
13
|
+
#++
|
14
|
+
|
15
|
+
def stream(io = nil)
|
16
|
+
if io
|
17
|
+
# Reuse an existing IO if it exists.
|
18
|
+
@context.output_buffer = io
|
19
|
+
else
|
20
|
+
r, w = IO.pipe
|
21
|
+
|
22
|
+
@context.output_buffer = r
|
23
|
+
@out = w
|
24
|
+
r.sync = true
|
25
|
+
w.class.send(:define_method, :empty?) { false }
|
26
|
+
|
27
|
+
Thread.new do
|
28
|
+
begin
|
29
|
+
yield
|
30
|
+
ensure
|
31
|
+
w.close
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/lib/raw/scaffold.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Raw
|
2
|
+
|
3
|
+
# Scaffolding is one facet of Nitro's Rapid Application
|
4
|
+
# Develpoment (RAD) features. The scaffolder automatically
|
5
|
+
# generates common code for managed object and their
|
6
|
+
# controllers.
|
7
|
+
|
8
|
+
module Scaffold
|
9
|
+
end
|
10
|
+
|
11
|
+
require "raw/scaffold/model"
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Raw
|
2
|
+
|
3
|
+
module Scaffold
|
4
|
+
|
5
|
+
# Automatically creates a scaffold controller to handle the
|
6
|
+
# given models.
|
7
|
+
|
8
|
+
def self.controller(*models)
|
9
|
+
for m in models
|
10
|
+
scaffold_controller(m)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.enchant_controller(model)
|
15
|
+
eval %{
|
16
|
+
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class Controller
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
module Raw
|
2
|
+
|
3
|
+
# Scaffolding is one facet of Nitro's Rapid Application
|
4
|
+
# Develpoment (RAD) features. The scaffolder automatically
|
5
|
+
# generates common code for managed object and their
|
6
|
+
# controllers.
|
7
|
+
|
8
|
+
module Scaffold
|
9
|
+
|
10
|
+
# Automatically enchant all models ?
|
11
|
+
|
12
|
+
setting :enchant_all_models, :default => false, :doc => 'Automatically enchant all models?'
|
13
|
+
|
14
|
+
# Enchant all models.
|
15
|
+
|
16
|
+
def self.all_models
|
17
|
+
if Scaffold.enchant_all_models
|
18
|
+
self.model(*Og.manager.managed_classes)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# 'Enchant' a model class (typically a managed class,
|
23
|
+
# entity). A collection of useful methods are magically
|
24
|
+
# added to the class and/or the class instances.
|
25
|
+
#
|
26
|
+
# * to_s
|
27
|
+
# * to_href
|
28
|
+
# * to_link
|
29
|
+
# * to_edit_href
|
30
|
+
# * to_admin_href
|
31
|
+
#--
|
32
|
+
# to_xxx is used instead of xxx in an attempt to avoid
|
33
|
+
# colisions with user defined methods.
|
34
|
+
#++
|
35
|
+
|
36
|
+
def self.model(*classes)
|
37
|
+
for c in classes
|
38
|
+
enchant_model c
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#--
|
43
|
+
# Actually enchant the given class. Override this method
|
44
|
+
# to customize for your application. The string calculation
|
45
|
+
# code is deliberatly dynamic to work with Ruby's OO
|
46
|
+
# features.
|
47
|
+
#++
|
48
|
+
|
49
|
+
def self.enchant_model(klass)
|
50
|
+
# Find the controller that handles this model. Unless no
|
51
|
+
# controller annotation is defined, try to find a controller
|
52
|
+
# of the form: Model::Controller. Some examples:
|
53
|
+
#
|
54
|
+
# class Ticket
|
55
|
+
# ann :self, :controller => SpecialTicketController
|
56
|
+
# ..
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# or try to find a Ticket::Controller class.
|
60
|
+
|
61
|
+
controller = klass.ann(:self, :controller) || klass.constant('Controller')
|
62
|
+
|
63
|
+
# If the class defines a text_key use it to create more
|
64
|
+
# readable (and SEO friendly) URIs.
|
65
|
+
|
66
|
+
key = klass.ann(:self, :text_key) || 'oid'
|
67
|
+
|
68
|
+
# to_s
|
69
|
+
|
70
|
+
if klass.instance_methods.include? 'title'
|
71
|
+
define_instance_method klass, :to_s, %{ title }, force = true
|
72
|
+
elsif klass.instance_methods.include? 'name'
|
73
|
+
define_instance_method klass, :to_s, %{ name }, force = true
|
74
|
+
end
|
75
|
+
|
76
|
+
# to_href
|
77
|
+
# ex: /articles/23
|
78
|
+
|
79
|
+
define_instance_method klass, :to_href, %{
|
80
|
+
"\#{#{controller}.mount_path}/read/\#{#{key}}".squeeze('/')
|
81
|
+
}
|
82
|
+
|
83
|
+
# to_link
|
84
|
+
# ex: <a href="/articles/23">The article's title</a>
|
85
|
+
|
86
|
+
define_instance_method klass, :to_link, %{
|
87
|
+
%|<a href="\#{to_href}">\#{to_s}</a>|
|
88
|
+
}
|
89
|
+
|
90
|
+
# to_link
|
91
|
+
# ex: <a href="/articles/23">The article's title</a>
|
92
|
+
|
93
|
+
define_class_method klass, :controller, %{
|
94
|
+
#{controller}
|
95
|
+
}
|
96
|
+
|
97
|
+
if defined? OgAdminController
|
98
|
+
self.extend(OgAdminHelper)
|
99
|
+
|
100
|
+
# to_edit_href
|
101
|
+
# ex: admin/update/Article/23
|
102
|
+
|
103
|
+
define_instance_method klass, :to_edit_href, %{
|
104
|
+
"\#{OgAdminController.mount_path}/update/#{class_to_name(klass)}/\#{oid}"
|
105
|
+
}
|
106
|
+
|
107
|
+
# to_admin_href
|
108
|
+
# ex: admin/list/Article
|
109
|
+
|
110
|
+
define_instance_method klass, :to_admin_href, %{
|
111
|
+
"\#{AdminController.mount_path}/list/#{class_to_name(klass)}"
|
112
|
+
}
|
113
|
+
|
114
|
+
# to_admin_href
|
115
|
+
# ex: admin/list/Article
|
116
|
+
|
117
|
+
define_class_method klass, :to_admin_href, %{
|
118
|
+
"\#{AdminController.mount_path}/list/#{class_to_name(klass)}"
|
119
|
+
}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
#--
|
124
|
+
# This helper defines an instance method for the
|
125
|
+
# scaffolded class. The method is only defined if the klass
|
126
|
+
# does not already respond to it.
|
127
|
+
#++
|
128
|
+
|
129
|
+
def self.define_instance_method(klass, meth, body, force = false)
|
130
|
+
if force or (!klass.instance_methods.include? meth.to_s)
|
131
|
+
klass.module_eval %{
|
132
|
+
def #{meth}
|
133
|
+
#{body}
|
134
|
+
end
|
135
|
+
}
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
#--
|
140
|
+
# This helper defines an class method for the
|
141
|
+
# scaffolded class. The method is only defined if the klass
|
142
|
+
# does not already respond to it.
|
143
|
+
#++
|
144
|
+
|
145
|
+
def self.define_class_method(klass, meth, body, force = false)
|
146
|
+
if force or (!klass.respond_to? meth.to_s)
|
147
|
+
klass.module_eval %{
|
148
|
+
def self.#{meth}
|
149
|
+
#{body}
|
150
|
+
end
|
151
|
+
}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
data/lib/raw/test.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/assertions'
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
module Test::Unit::Assertions
|
6
|
+
|
7
|
+
STATUS_MAP = {
|
8
|
+
:success => 200,
|
9
|
+
:ok => 200,
|
10
|
+
:redirect => 307
|
11
|
+
}
|
12
|
+
|
13
|
+
# :section: General assertions.
|
14
|
+
|
15
|
+
# Check the status of the response.
|
16
|
+
|
17
|
+
def assert_response(options = {})
|
18
|
+
unless options.is_a? Hash
|
19
|
+
options = { :status => options }
|
20
|
+
end
|
21
|
+
msg = options[:msg]
|
22
|
+
if status = options.fetch(:status, :success)
|
23
|
+
status = STATUS_MAP[status] if STATUS_MAP.has_key?(status)
|
24
|
+
assert_status(status, msg)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert_status(status, msg)
|
29
|
+
msg = format_msg("Status not '#{status}'", msg)
|
30
|
+
assert_block(msg) { @context.status == status }
|
31
|
+
end
|
32
|
+
|
33
|
+
#--
|
34
|
+
# Compile some helpers.
|
35
|
+
#++
|
36
|
+
|
37
|
+
for m in [:get, :post, :put, :delete, :head]
|
38
|
+
eval %{
|
39
|
+
def assert_#{m}(uri, headers = {}, params = {}, session = nil)
|
40
|
+
#{m}(uri, headers, params, session)
|
41
|
+
assert_response :success
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def assert_output(options = {})
|
47
|
+
msg = options[:msg]
|
48
|
+
if re = options[:match] || options[:contains]
|
49
|
+
assert_output_match(re, msg)
|
50
|
+
end
|
51
|
+
if re = options[:no_match] || options[:contains_no]
|
52
|
+
assert_output_not_match(re, msg)
|
53
|
+
end
|
54
|
+
if content_type = options[:content_type]
|
55
|
+
assert_content_type(content_type, msg)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def assert_output_match(re, msg)
|
60
|
+
msg = format_msg("Rendered output does not match '#{re.source}'", msg)
|
61
|
+
assert_block(msg) { @context.body =~ Regexp.new(re) }
|
62
|
+
end
|
63
|
+
alias_method :assert_output_contains, :assert_output_match
|
64
|
+
|
65
|
+
def assert_output_not_match(re, msg)
|
66
|
+
msg = format_msg("Rendered output matches '#{re.source}'", msg)
|
67
|
+
assert_block(msg) { @context.out =~ Regexp.new(re) }
|
68
|
+
end
|
69
|
+
alias_method :assert_output_contains_not, :assert_output_match
|
70
|
+
|
71
|
+
def assert_content_type(ctype, msg)
|
72
|
+
msg = format_msg("Content type is not '#{ctype}' as expected", msg)
|
73
|
+
assert_block(msg) { @context.content_type == ctype }
|
74
|
+
end
|
75
|
+
|
76
|
+
# :section: Session related assertions.
|
77
|
+
|
78
|
+
def assert_session(options = {})
|
79
|
+
msg = options[:msg]
|
80
|
+
if key = options[:has]
|
81
|
+
assert_session_has(key, msg)
|
82
|
+
end
|
83
|
+
if key = options[:has_no] || options[:no]
|
84
|
+
assert_session_has_no(key, msg)
|
85
|
+
end
|
86
|
+
if key = options[:key] and value = options[:value]
|
87
|
+
assert_session_equal(key, value, msg)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def assert_session_has(key, msg = nil)
|
92
|
+
msg = format_msg("Object '#{key}' not found in session", msg)
|
93
|
+
assert_block(msg) { @context.session[key] }
|
94
|
+
end
|
95
|
+
|
96
|
+
def assert_session_has_no(key, msg = nil)
|
97
|
+
msg = format_msg("Unexpected object '#{key}' found in session", msg)
|
98
|
+
assert_block(msg) { !@context.session[key] }
|
99
|
+
end
|
100
|
+
|
101
|
+
def assert_session_equal(key, value, msg = nil)
|
102
|
+
msg = format_msg("The value of session object '#{key}' is '#{@context.session[key]}' but was expected '#{value}'", msg)
|
103
|
+
assert_block(msg) { @context.session[key] == value }
|
104
|
+
end
|
105
|
+
|
106
|
+
# :section: Cookies related assertions.
|
107
|
+
|
108
|
+
def assert_cookie(options = {})
|
109
|
+
msg = options[:msg]
|
110
|
+
if key = options[:has]
|
111
|
+
assert_cookie_has(key, msg)
|
112
|
+
end
|
113
|
+
if key = options[:has_no] || options[:no]
|
114
|
+
assert_cookie_has_no(key, msg)
|
115
|
+
end
|
116
|
+
if key = options[:key] and value = options[:value]
|
117
|
+
assert_cookie_equal(key, value, msg)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def assert_cookie_has(name, msg = nil)
|
122
|
+
msg = format_msg("Cookie '#{name}' not found", msg)
|
123
|
+
assert_block(msg) { @context.response_cookie(name) }
|
124
|
+
end
|
125
|
+
|
126
|
+
def assert_cookie_has_no(name, msg = nil)
|
127
|
+
msg = format_msg("Unexpected cookie '#{name}' found", msg)
|
128
|
+
assert_block(msg) { !@context.response_cookie(name) }
|
129
|
+
end
|
130
|
+
|
131
|
+
def assert_cookie_equal(name, value, msg = nil)
|
132
|
+
unless cookie = @context.response_cookie(name)
|
133
|
+
msg = format_msg("Cookie '#{name}' not found", msg)
|
134
|
+
assert_block(msg) { false }
|
135
|
+
end
|
136
|
+
msg = format_msg("The value of cookie '#{name}' is '#{cookie.value}' but was expected '#{value}'", msg)
|
137
|
+
assert_block(msg) { cookie.value == value }
|
138
|
+
end
|
139
|
+
|
140
|
+
# :section: Nitro::Template related assertions.
|
141
|
+
|
142
|
+
# :section: Redirection assertions.
|
143
|
+
|
144
|
+
def assert_redirected(options = {})
|
145
|
+
msg = options[:msg]
|
146
|
+
|
147
|
+
msg = format_msg("No redirection (status = #{@context.status})", msg)
|
148
|
+
assert_block(msg) { @context.redirect? }
|
149
|
+
|
150
|
+
if to = options[:to]
|
151
|
+
msg = format_msg("Not redirected to '#{to}'", msg)
|
152
|
+
assert_block(msg) { @context.response_headers['location'] == "http://#{to}" }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def assert_not_redirected(options = {})
|
157
|
+
msg = options[:msg]
|
158
|
+
msg = format_msg("Unexpected redirection (location = '#{@context.response_headers['location']}')", msg)
|
159
|
+
assert_block(msg) { !@context.redirect? }
|
160
|
+
end
|
161
|
+
|
162
|
+
# :section: Utility methods
|
163
|
+
|
164
|
+
def format_msg(message, extra) # :nodoc:
|
165
|
+
extra += ', ' if extra
|
166
|
+
return "#{extra}#{message}"
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|