ajax 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +291 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/app/controllers/ajax_controller.rb +3 -0
- data/app/views/ajax/framework.html.erb +7 -0
- data/config/initializers/ajax.rb +14 -0
- data/lib/ajax.rb +79 -0
- data/lib/ajax/action_controller.rb +154 -0
- data/lib/ajax/action_view.rb +56 -0
- data/lib/ajax/helpers.rb +15 -0
- data/lib/ajax/helpers/request_helper.rb +76 -0
- data/lib/ajax/helpers/robot_helper.rb +31 -0
- data/lib/ajax/helpers/url_helper.rb +47 -0
- data/lib/ajax/railtie.rb +7 -0
- data/lib/ajax/routes.rb +12 -0
- data/lib/ajax/spec/extension.rb +34 -0
- data/lib/ajax/spec/helpers.rb +95 -0
- data/lib/ajax/tasks.rb +1 -0
- data/lib/rack-ajax.rb +60 -0
- data/lib/rack-ajax/decision_tree.rb +60 -0
- data/lib/rack-ajax/parser.rb +115 -0
- data/public/images/loading-icon-large.gif +0 -0
- data/public/images/loading-icon-small.gif +0 -0
- data/public/javascripts/ajax.js +529 -0
- data/public/javascripts/jquery.address-1.1.js +450 -0
- data/public/javascripts/jquery.address-1.1.min.js +11 -0
- data/public/javascripts/jquery.address-1.2.js +528 -0
- data/public/javascripts/jquery.address-1.2.min.js +25 -0
- data/public/javascripts/jquery.address-1.2rc.js +599 -0
- data/public/javascripts/jquery.address-1.2rc.min.js +27 -0
- data/public/javascripts/jquery.json-2.2.js +178 -0
- data/public/javascripts/jquery.json-2.2.min.js +31 -0
- data/rails/init.rb +4 -0
- data/rails/install.rb +23 -0
- data/rails/uninstall.rb +1 -0
- data/spec/ajax/helpers_spec.rb +102 -0
- data/spec/ajax/request_helper_spec.rb +33 -0
- data/spec/integration/ajax_spec.rb +146 -0
- data/spec/rack-ajax/parser_spec.rb +62 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +18 -0
- data/tasks/ajax_tasks.rake +15 -0
- metadata +106 -0
@@ -0,0 +1,154 @@
|
|
1
|
+
module Ajax
|
2
|
+
module ActionController
|
3
|
+
def self.included(klass)
|
4
|
+
klass.class_eval do
|
5
|
+
alias_method_chain :render, :ajax
|
6
|
+
alias_method_chain :redirect_to_full_url, :ajax
|
7
|
+
|
8
|
+
append_after_filter :process_response_headers
|
9
|
+
end
|
10
|
+
klass.extend(ClassMethods)
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
# Set a custom response header if the request is AJAX.
|
16
|
+
#
|
17
|
+
# Call with <tt>key</tt> and optional <tt>value</tt>. Pass a
|
18
|
+
# block to yield a dynamic value.
|
19
|
+
#
|
20
|
+
# Accepts :only and :except conditions because we create
|
21
|
+
# an after_filter.
|
22
|
+
def ajax_header(*args, &block)
|
23
|
+
return unless Ajax.is_enabled?
|
24
|
+
|
25
|
+
options = args.extract_options!
|
26
|
+
key, value = args.shift, args.shift
|
27
|
+
value = block_given? ? Proc.new : value
|
28
|
+
|
29
|
+
prepend_after_filter(options) do |controller|
|
30
|
+
if controller.request.xhr?
|
31
|
+
value = value.is_a?(Proc) ? controller.instance_eval(&value) : value
|
32
|
+
Ajax.set_header(controller.response, key, value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Set the layout to use for AJAX requests.
|
38
|
+
#
|
39
|
+
# By default we look in layouts/ajax/ for this controllers default
|
40
|
+
# layout and render that. If it can't be found, the default layout
|
41
|
+
# is used.
|
42
|
+
def ajax_layout(template_name)
|
43
|
+
write_inheritable_attribute(:ajax_layout, template_name)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
# Redirect to hashed URLs unless the path is excepted.
|
50
|
+
#
|
51
|
+
# Store the URL that we are redirecting to in the session.
|
52
|
+
# If we then have a request for the root URL we know
|
53
|
+
# to render this URL into it.
|
54
|
+
#
|
55
|
+
# If redirecting back to the referer, use the referer
|
56
|
+
# in the Ajax-Info header because it includes the
|
57
|
+
# hashed part of the URL. Otherwise the referer is
|
58
|
+
# always the root url.
|
59
|
+
#
|
60
|
+
# For AJAX requests, respond with an AJAX-suitable
|
61
|
+
# redirect.
|
62
|
+
def redirect_to_full_url_with_ajax(url, status)
|
63
|
+
return redirect_to_full_url_without_ajax(url, status) unless Ajax.is_enabled?
|
64
|
+
raise DoubleRenderError if performed?
|
65
|
+
|
66
|
+
if url == request.headers["Referer"] && !request.headers['Ajax-Info'].blank?
|
67
|
+
url = request.headers['Ajax-Info']['referer']
|
68
|
+
Ajax.logger.debug("[ajax] using referer #{url} from Ajax-Info")
|
69
|
+
end
|
70
|
+
|
71
|
+
if !Ajax.exclude_path?(url) && !Ajax.is_hashed_url?(url)
|
72
|
+
url = Ajax.hashed_url_from_traditional(url)
|
73
|
+
Ajax.logger.info("[ajax] rewrote redirect to #{url}")
|
74
|
+
end
|
75
|
+
|
76
|
+
session[:redirected_to] = url
|
77
|
+
if request.xhr?
|
78
|
+
render(:update) { |page| page.redirect_to(url) }
|
79
|
+
else
|
80
|
+
redirect_to_full_url_without_ajax(url, status)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Convert the Ajax-Info hash to JSON before the request is sent.
|
85
|
+
def process_response_headers
|
86
|
+
case response.headers['Ajax-Info']
|
87
|
+
when Hash
|
88
|
+
response.headers['Ajax-Info'] = response.headers['Ajax-Info'].to_json
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# Intercept rendering to customize the headers and layout handling
|
94
|
+
#
|
95
|
+
def render_with_ajax(options = nil, extra_options = {}, &block)
|
96
|
+
return render_without_ajax(options, extra_options, &block) unless Ajax.is_enabled?
|
97
|
+
|
98
|
+
original_args = [options, extra_options]
|
99
|
+
if request.xhr?
|
100
|
+
|
101
|
+
# Options processing taken from ActionController::Base#render
|
102
|
+
if options.nil?
|
103
|
+
options = { :template => default_template, :layout => true }
|
104
|
+
elsif options == :update
|
105
|
+
options = extra_options.merge({ :update => true })
|
106
|
+
elsif options.is_a?(String) || options.is_a?(Symbol)
|
107
|
+
case options.to_s.index('/')
|
108
|
+
when 0
|
109
|
+
extra_options[:file] = options
|
110
|
+
when nil
|
111
|
+
extra_options[:action] = options
|
112
|
+
else
|
113
|
+
extra_options[:template] = options
|
114
|
+
end
|
115
|
+
options = extra_options
|
116
|
+
elsif !options.is_a?(Hash)
|
117
|
+
extra_options[:partial] = options
|
118
|
+
options = extra_options
|
119
|
+
end
|
120
|
+
|
121
|
+
default = pick_layout(options)
|
122
|
+
default = default.path_without_format_and_extension unless default.nil?
|
123
|
+
ajax_layout = layout_for_ajax(default)
|
124
|
+
ajax_layout = ajax_layout.path_without_format_and_extension unless ajax_layout.nil?
|
125
|
+
options[:layout] = ajax_layout unless ajax_layout.nil?
|
126
|
+
|
127
|
+
# Send the current layout and controller in a custom response header
|
128
|
+
Ajax.set_header(response, :layout, ajax_layout)
|
129
|
+
Ajax.set_header(response, :controller, self.class.controller_name)
|
130
|
+
end
|
131
|
+
render_without_ajax(options, extra_options, &block)
|
132
|
+
end
|
133
|
+
|
134
|
+
# Return the layout to use for an AJAX request, or the default layout if one
|
135
|
+
# cannot be found. If no default is known, <tt>layouts/ajax/application</tt> is used.
|
136
|
+
#
|
137
|
+
# If no ajax_layout is set, look for the default layout in <tt>layouts/ajax</tt>.
|
138
|
+
# If the layout cannot be found, use the default.
|
139
|
+
#
|
140
|
+
# FIXME: Use hard-coded html layout extension because <tt>default_template_format</tt>
|
141
|
+
# is sometimes :js which means the layout isn't found.
|
142
|
+
def layout_for_ajax(default) #:nodoc:
|
143
|
+
ajax_layout = self.class.read_inheritable_attribute(:ajax_layout)
|
144
|
+
if ajax_layout.nil? || !(ajax_layout =~ /^layouts\/ajax/)
|
145
|
+
find_layout("layouts/ajax/#{default.sub(/layouts(\/)?/, '')}", 'html') unless default.nil?
|
146
|
+
else
|
147
|
+
ajax_layout
|
148
|
+
end
|
149
|
+
rescue ::ActionView::MissingTemplate
|
150
|
+
Ajax.logger.info("[ajax] no layout found in layouts/ajax using #{default}")
|
151
|
+
default
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Ajax
|
2
|
+
module ActionView
|
3
|
+
def self.included(klass)
|
4
|
+
klass.class_eval do
|
5
|
+
alias_method_chain :link_to, :ajax if method_defined?(:link_to)
|
6
|
+
end
|
7
|
+
klass.send(:include, Helpers)
|
8
|
+
end
|
9
|
+
|
10
|
+
module Helpers
|
11
|
+
|
12
|
+
# Set a custom response header if the request is AJAX.
|
13
|
+
def ajax_header(key, value)
|
14
|
+
return unless Ajax.is_enabled? && request.xhr?
|
15
|
+
Ajax.set_header(response, key, value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
# Include an attribute on all outgoing links to mark them as Ajax deep links.
|
22
|
+
#
|
23
|
+
# The deep link will be the path and query string from the href.
|
24
|
+
#
|
25
|
+
# To specify a different deep link pass <tt>:data-deep-link => '/deep/link/path'</tt>
|
26
|
+
# in the <tt>link_to</tt> <tt>html_options</tt>.
|
27
|
+
#
|
28
|
+
# To turn off deep linking for a URL, pass <tt>:traditional => true</tt> or
|
29
|
+
# <tt>:data-deep-link => nil</tt>.
|
30
|
+
#
|
31
|
+
# Any paths matching the paths in Ajax.exclude_paths will automatically be
|
32
|
+
# linked to traditionally.
|
33
|
+
def link_to_with_ajax(*args, &block)
|
34
|
+
if Ajax.is_enabled? && !block_given?
|
35
|
+
options = args.second || {}
|
36
|
+
html_options = args.third
|
37
|
+
html_options = (html_options || {}).stringify_keys
|
38
|
+
|
39
|
+
# Insert the deep link unless the URL is traditional
|
40
|
+
if !html_options.has_key?('data-deep-link') && !html_options.delete('traditional')
|
41
|
+
path = url_for(options)
|
42
|
+
|
43
|
+
# Is this path to be excluded?
|
44
|
+
unless Ajax.exclude_path?(path)
|
45
|
+
if path.match(%r[^(http:\/\/[^\/]*)(\/?.*)])
|
46
|
+
path = $2
|
47
|
+
end
|
48
|
+
html_options['data-deep-link'] = path
|
49
|
+
end
|
50
|
+
end
|
51
|
+
args[2] = html_options
|
52
|
+
end
|
53
|
+
link_to_without_ajax(*args, &block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/ajax/helpers.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'ajax/helpers/request_helper'
|
2
|
+
require 'ajax/helpers/robot_helper'
|
3
|
+
require 'ajax/helpers/url_helper'
|
4
|
+
|
5
|
+
module Ajax #:nodoc:
|
6
|
+
module Helpers #:nodoc:
|
7
|
+
def self.included(klass)
|
8
|
+
klass.class_eval do
|
9
|
+
extend RequestHelper
|
10
|
+
extend RobotHelper
|
11
|
+
extend UrlHelper
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Ajax
|
2
|
+
module Helpers
|
3
|
+
module RequestHelper
|
4
|
+
# Recursive merge values
|
5
|
+
DEEP_MERGE = lambda do |key, v1, v2|
|
6
|
+
if v1.is_a?(Hash) && v2.is_a?(Hash)
|
7
|
+
v1.merge(v2, &DEEP_MERGE)
|
8
|
+
elsif v1.is_a?(Array) && v2.is_a?(Array)
|
9
|
+
v1.concat(v2)
|
10
|
+
else
|
11
|
+
[v1, v2].compact.first
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Hash and/or Array values are merged so you can set multiple values
|
16
|
+
def set_header(object, key, value)
|
17
|
+
headers = object.is_a?(::ActionController::Response) ? object.headers : object
|
18
|
+
unless headers["Ajax-Info"].is_a?(Hash)
|
19
|
+
headers["Ajax-Info"] = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Deep merge hashes
|
23
|
+
if headers["Ajax-Info"].has_key?(key.to_s) &&
|
24
|
+
value.is_a?(Hash) &&
|
25
|
+
headers["Ajax-Info"][key.to_s].is_a?(Hash)
|
26
|
+
value = headers["Ajax-Info"][key.to_s].merge(value, &DEEP_MERGE)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Concat arrays
|
30
|
+
if headers["Ajax-Info"].has_key?(key.to_s) &&
|
31
|
+
value.is_a?(Array) &&
|
32
|
+
headers["Ajax-Info"][key.to_s].is_a?(Array)
|
33
|
+
value = headers["Ajax-Info"][key.to_s].concat(value)
|
34
|
+
end
|
35
|
+
|
36
|
+
headers["Ajax-Info"][key.to_s] = value
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_header(object, key)
|
40
|
+
headers = object.is_a?(::ActionController::Request) ? object.headers : object
|
41
|
+
unless headers["Ajax-Info"].is_a?(Hash)
|
42
|
+
headers["Ajax-Info"] = {}
|
43
|
+
end
|
44
|
+
headers['Ajax-Info'][key.to_s]
|
45
|
+
end
|
46
|
+
|
47
|
+
# Set one or more paths that can be accessed directly without the AJAX framework.
|
48
|
+
#
|
49
|
+
# Useful for excluding pages with HTTPS content on them from being loaded
|
50
|
+
# via AJAX.
|
51
|
+
#
|
52
|
+
# <tt>paths</tt> a list of String or Regexp instances that are matched
|
53
|
+
# against each REQUEST_PATH.
|
54
|
+
#
|
55
|
+
# The string and regex paths are modified to match full URLs by prepending
|
56
|
+
# them with the appropriate regular expression.
|
57
|
+
def exclude_paths(paths=nil)
|
58
|
+
if !instance_variable_defined?(:@exclude_paths)
|
59
|
+
@exclude_paths = []
|
60
|
+
end
|
61
|
+
(paths || []).each do |path|
|
62
|
+
@exclude_paths << /^(\w+\:\/\/[^\/]+\/?)?#{path.to_s}$/
|
63
|
+
end
|
64
|
+
@exclude_paths
|
65
|
+
end
|
66
|
+
|
67
|
+
# Return a boolean indicating whether or not to exclude a path from the
|
68
|
+
# AJAX redirect.
|
69
|
+
def exclude_path?(path)
|
70
|
+
!!((@exclude_paths || []).find do |excluded|
|
71
|
+
!!excluded.match(path)
|
72
|
+
end)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Ajax
|
2
|
+
module Helpers
|
3
|
+
module RobotHelper
|
4
|
+
ROBOTS = [
|
5
|
+
{:name => 'Googlebot', :user_agent_regex => /\bGooglebot\b/i, :sample_agent_string => 'Googlebot'},
|
6
|
+
{:name => 'Baidu', :user_agent_regex => /\bBaidu\b/i, :sample_agent_string => 'Baidu'},
|
7
|
+
{:name => 'Gigabot', :user_agent_regex => /\bGigabot\b/i, :sample_agent_string => 'Gigabot'},
|
8
|
+
{:name => 'libwww-perl', :user_agent_regex => /\blibwww-perl\b/i, :sample_agent_string => 'libwww-perl'},
|
9
|
+
{:name => 'lwp-trivial', :user_agent_regex => /\blwp-trivial\b/i, :sample_agent_string => 'lwp-trivial'},
|
10
|
+
{:name => 'MSNBot', :user_agent_regex => /\bmsnbot\b/i, :sample_agent_string => 'msnbot'},
|
11
|
+
{:name => 'SiteUptime', :user_agent_regex => /\bSiteUptime\b/i, :sample_agent_string => 'SiteUptime'},
|
12
|
+
{:name => 'Slurp', :user_agent_regex => /\bSlurp\b/i, :sample_agent_string => 'Slurp'},
|
13
|
+
{:name => 'WordPress', :user_agent_regex => /\bWordPress\b/i, :sample_agent_string => 'WordPress'},
|
14
|
+
{:name => 'ZIBB', :user_agent_regex => /\bZIBB\b/i, :sample_agent_string => 'ZIBB'},
|
15
|
+
{:name => 'ZyBorg', :user_agent_regex => /\bZyBorg\b/i, :sample_agent_string => 'ZyBorg'},
|
16
|
+
]
|
17
|
+
|
18
|
+
def robot_for(user_agent)
|
19
|
+
ROBOTS.each do |r|
|
20
|
+
return r if user_agent =~ r[:user_agent_regex]
|
21
|
+
end
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# Call with a User Agent string
|
26
|
+
def is_robot?(user_agent)
|
27
|
+
!!self.robot_for(user_agent)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Ajax
|
2
|
+
module Helpers
|
3
|
+
module UrlHelper
|
4
|
+
|
5
|
+
# Return a boolean indicating whether the given URL points to the
|
6
|
+
# root path.
|
7
|
+
def url_is_root?(url)
|
8
|
+
!!(URI.parse(url).path =~ %r[^\/?$])
|
9
|
+
end
|
10
|
+
|
11
|
+
# The URL is hashed if the fragment part starts with a /
|
12
|
+
#
|
13
|
+
# For example, http://lol.com#/Rihanna
|
14
|
+
def is_hashed_url?(url)
|
15
|
+
!!(URI.parse(url).fragment =~ %r[^\/])
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return a hashed URL using the fragment of <tt>url</tt>
|
19
|
+
def hashed_url_from_fragment(url)
|
20
|
+
url_host(url) + ('/#/' + (URI.parse(url).fragment || '')).gsub(/\/\//, '/')
|
21
|
+
end
|
22
|
+
|
23
|
+
# Return a traditional URL from the fragment of <tt>url</tt>
|
24
|
+
def traditional_url_from_fragment(url)
|
25
|
+
url_host(url) + ('/' + (URI.parse(url).fragment || '')).gsub(/\/\//, '/')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Return a hashed URL formed from a traditional <tt>url</tt>
|
29
|
+
def hashed_url_from_traditional(url)
|
30
|
+
uri = URI.parse(url)
|
31
|
+
hashed_url = url_host(url) + ('/#/' + (uri.path || '')).gsub(/\/\//, '/')
|
32
|
+
hashed_url += ('?' + uri.query) unless uri.query.nil?
|
33
|
+
hashed_url
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def url_host(url)
|
39
|
+
if url.match(/^(\w+\:\/\/[^\/]+)\/?/)
|
40
|
+
$1
|
41
|
+
else
|
42
|
+
''
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/ajax/railtie.rb
ADDED
data/lib/ajax/routes.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Ajax
|
2
|
+
module Routes
|
3
|
+
# In your <tt>config/routes.rb</tt> file call:
|
4
|
+
# Ajax::Routes.draw(map)
|
5
|
+
# Passing in the routing <tt>map</tt> object.
|
6
|
+
#
|
7
|
+
# Adds an <tt>ajax_framework_path</tt> pointing to <tt>/ajax/framework</tt>
|
8
|
+
def self.draw(map)
|
9
|
+
map.ajax_framework "/ajax/framework", :controller => 'ajax', :action => 'framework'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Ajax
|
2
|
+
module Spec
|
3
|
+
module Extension
|
4
|
+
|
5
|
+
def integrate_ajax
|
6
|
+
Ajax.enabled = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def disable_ajax
|
10
|
+
Ajax.enabled = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def mock_ajax
|
14
|
+
integrate_ajax
|
15
|
+
Ajax.mocked = true
|
16
|
+
end
|
17
|
+
|
18
|
+
def unmock_ajax
|
19
|
+
disable_ajax
|
20
|
+
Ajax.mocked = false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module ActiveSupport
|
27
|
+
class TestCase
|
28
|
+
include Ajax::Spec::Extension
|
29
|
+
|
30
|
+
before(:all) do
|
31
|
+
::Ajax.enabled = false
|
32
|
+
end if method_defined?(:before)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Ajax
|
4
|
+
module Spec
|
5
|
+
module Helpers
|
6
|
+
|
7
|
+
def create_app
|
8
|
+
@app = Class.new { def call(env); true; end }.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def call_rack(url, request_method='GET', env={}, &block)
|
12
|
+
env(url, request_method, env)
|
13
|
+
@rack = Rack::Ajax.new(@app, &block)
|
14
|
+
@response = @rack.call(@env)
|
15
|
+
end
|
16
|
+
|
17
|
+
def should_respond_with(msg)
|
18
|
+
should_be_a_valid_response
|
19
|
+
response_body.should == msg
|
20
|
+
end
|
21
|
+
|
22
|
+
def should_redirect_to(location, code=302)
|
23
|
+
should_be_a_valid_response
|
24
|
+
response_code.should == code
|
25
|
+
response_headers['Location'].should == location
|
26
|
+
end
|
27
|
+
|
28
|
+
def should_set_ajax_response_header(key, value)
|
29
|
+
response_headers['Ajax-Info'][key].should == value
|
30
|
+
end
|
31
|
+
|
32
|
+
def should_set_ajax_request_header(key, value)
|
33
|
+
@env['Ajax-Info'][key].should == value
|
34
|
+
end
|
35
|
+
|
36
|
+
def should_rewrite_to(url)
|
37
|
+
should_be_a_valid_response
|
38
|
+
|
39
|
+
# Check custom headers
|
40
|
+
response_body_as_hash['REQUEST_URI'].should == url
|
41
|
+
end
|
42
|
+
|
43
|
+
def should_not_modify_request
|
44
|
+
should_be_a_valid_response
|
45
|
+
response_code.should == 200
|
46
|
+
|
47
|
+
# If we have the original headers from a call to call_rack()
|
48
|
+
# check that they haven't changed. Otherwise, just make sure
|
49
|
+
# that we don't have the custom rewrite header.
|
50
|
+
if !@env.nil?
|
51
|
+
@env.each { |k,v| response_body_as_hash.should == v }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Response must be [code, {headers}, ['Response']]
|
56
|
+
# Headers must contain the Content-Type header
|
57
|
+
def should_be_a_valid_response
|
58
|
+
return if @response.is_a?(::ActionController::Response)
|
59
|
+
@response.should be_a_kind_of(Array)
|
60
|
+
@response.size.should == 3
|
61
|
+
@response[0].should be_a_kind_of(Integer)
|
62
|
+
@response[1].should be_a_kind_of(Hash)
|
63
|
+
@response[1]['Content-Type'].should =~ %r[^text\/\w+]
|
64
|
+
@response[2].should be_a_kind_of(Array)
|
65
|
+
@response[2][0].should be_a_kind_of(String)
|
66
|
+
end
|
67
|
+
|
68
|
+
def env(uri, request_method, options={})
|
69
|
+
uri = URI.parse(uri)
|
70
|
+
@env = {
|
71
|
+
'REQUEST_URI' => uri.to_s,
|
72
|
+
'PATH_INFO' => uri.path,
|
73
|
+
'QUERY_STRING' => uri.query,
|
74
|
+
'REQUEST_METHOD' => request_method
|
75
|
+
}.merge!(options)
|
76
|
+
end
|
77
|
+
|
78
|
+
def response_body
|
79
|
+
@response.is_a?(::ActionController::Response) ? @response.body : @response[2][0]
|
80
|
+
end
|
81
|
+
|
82
|
+
def response_code
|
83
|
+
@response.is_a?(::ActionController::Response) ? @response.status.to_i : @response[0]
|
84
|
+
end
|
85
|
+
|
86
|
+
def response_headers
|
87
|
+
@response.is_a?(::ActionController::Response) ? @response.headers.to_hash : @response[1]
|
88
|
+
end
|
89
|
+
|
90
|
+
def response_body_as_hash
|
91
|
+
@response_body_as_hash ||= YAML.load(response_body)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|