tap-mechanize 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History +4 -0
- data/README +1 -1
- data/lib/tap/mechanize/capture.rb +98 -37
- data/lib/tap/mechanize/get.rb +1 -1
- data/lib/tap/mechanize/request.rb +2 -1
- data/lib/tap/mechanize/submit.rb +1 -1
- data/lib/tap/mechanize/test/echo_server.rb +1 -1
- data/lib/tap/mechanize/utils.rb +2 -2
- data/tap.yml +0 -1
- data/views/tap/mechanize/capture/redirect.js +51 -33
- data/views/tap/mechanize/capture/redirect_http.erb +8 -3
- data/views/tap/mechanize/capture/tutorial.erb +2 -0
- metadata +4 -4
data/History
CHANGED
data/README
CHANGED
@@ -12,7 +12,7 @@ configuration files can be edited and resubmitted using a Request task.
|
|
12
12
|
Multi-step actions, file uploads, and actions that require the use of HTTPS
|
13
13
|
may all be automated in this way.
|
14
14
|
|
15
|
-
* Lighthouse[http://bahuvrihi.lighthouseapp.com/projects/
|
15
|
+
* Lighthouse[http://bahuvrihi.lighthouseapp.com/projects/20532-tap-mechanize/overview]
|
16
16
|
* Github[http://github.com/bahuvrihi/tap-mechanize/tree/master]
|
17
17
|
* {Google Group}[http://groups.google.com/group/ruby-on-tap]
|
18
18
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'tap/controller'
|
2
2
|
require 'tap/mechanize/utils'
|
3
3
|
require 'tap/ubiquity/utils'
|
4
|
+
require 'uri'
|
4
5
|
|
5
6
|
module Tap
|
6
7
|
module Mechanize
|
@@ -11,57 +12,57 @@ module Tap
|
|
11
12
|
include Tap::Ubiquity::Utils
|
12
13
|
|
13
14
|
PREFIX = '__redirect_http_'
|
14
|
-
REDIRECT_PARAMETER = '__redirect_http_original_action'
|
15
15
|
|
16
16
|
# Brings up the tutorial.
|
17
17
|
def index
|
18
|
-
render 'index.erb', :locals => {:captures =>
|
18
|
+
render 'index.erb', :locals => {:captures => data.index(:data) }
|
19
19
|
end
|
20
20
|
|
21
|
-
def create(id
|
22
|
-
|
23
|
-
io << YAML.dump([parse_request
|
21
|
+
def create(id)
|
22
|
+
data.create(:data, id) do |io|
|
23
|
+
io << YAML.dump([parse_request])
|
24
24
|
end
|
25
25
|
download(id)
|
26
26
|
end
|
27
27
|
|
28
28
|
def show(id)
|
29
29
|
response['Content-Type'] = "text/plain"
|
30
|
-
|
30
|
+
data.read(:data, id)
|
31
31
|
end
|
32
32
|
|
33
33
|
def download(id)
|
34
|
-
path =
|
34
|
+
path = data.path(:data, id)
|
35
35
|
filename = id
|
36
36
|
filename += ".yml" if File.extname(id) == ""
|
37
37
|
|
38
38
|
response['Content-Type'] = "text/plain"
|
39
39
|
response['Content-Disposition'] = "attachment; filename=#{filename};"
|
40
|
-
|
40
|
+
data.read(:data, id)
|
41
41
|
end
|
42
42
|
|
43
|
-
def update(id="request"
|
44
|
-
path =
|
43
|
+
def update(id="request")
|
44
|
+
path = data.path(:data, id)
|
45
45
|
requests = File.exists?(path) ? YAML.load_file(path) : []
|
46
|
-
requests << parse_request
|
46
|
+
requests << parse_request
|
47
47
|
|
48
|
-
|
48
|
+
data.create_or_update(:data, id) do |io|
|
49
49
|
io << YAML.dump(requests)
|
50
50
|
end
|
51
51
|
download(id)
|
52
52
|
end
|
53
53
|
|
54
54
|
def destroy(id)
|
55
|
-
|
55
|
+
data.destroy(:data, id)
|
56
56
|
redirect uri(:index)
|
57
57
|
end
|
58
58
|
|
59
59
|
# Brings up a tutorial teaching how to capture and resubmit forms.
|
60
60
|
def tutorial
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
render 'tutorial.erb'
|
62
|
+
end
|
63
|
+
|
64
|
+
def command
|
65
|
+
serve js_injection(:redirect_http)
|
65
66
|
end
|
66
67
|
|
67
68
|
def test
|
@@ -75,15 +76,26 @@ module Tap
|
|
75
76
|
|
76
77
|
# Returns the redirection script.
|
77
78
|
def redirect_http
|
79
|
+
|
80
|
+
# note configs are formatted into the javascript; keys MUST be valid
|
81
|
+
# names, but values can be anything that converts to json
|
82
|
+
configs = [
|
83
|
+
[:submit_request, false],
|
84
|
+
[:keep_content, false],
|
85
|
+
[:keep_headers, false],
|
86
|
+
[:name, 'request']
|
87
|
+
]
|
88
|
+
|
78
89
|
css = render 'redirect.css'
|
79
90
|
script = render 'redirect.js', :locals => {
|
80
|
-
:redirect_parameter => REDIRECT_PARAMETER,
|
81
91
|
:redirect_action => uri(:update),
|
92
|
+
:configs => configs
|
82
93
|
}
|
83
94
|
|
84
95
|
content = render 'redirect_http.erb', :locals => {
|
85
96
|
:css => css,
|
86
|
-
:script => script
|
97
|
+
:script => script,
|
98
|
+
:configs => configs
|
87
99
|
}
|
88
100
|
|
89
101
|
if request.get?
|
@@ -137,34 +149,81 @@ if(current = document.getElementById("#{prefix}")) {
|
|
137
149
|
PREFIX
|
138
150
|
end
|
139
151
|
|
140
|
-
def
|
141
|
-
|
142
|
-
|
152
|
+
def data
|
153
|
+
server.data
|
154
|
+
end
|
155
|
+
|
156
|
+
def uri(*args)
|
157
|
+
"http://#{server.host}:#{server.port}#{super}"
|
158
|
+
end
|
159
|
+
|
160
|
+
# Returns the data recieved in the query string.
|
161
|
+
def get_params
|
162
|
+
env = request.env
|
163
|
+
if env["rack.request.query_string"] == request.query_string
|
164
|
+
env["rack.request.query_hash"]
|
165
|
+
else
|
166
|
+
env["rack.request.query_string"] = request.query_string
|
167
|
+
env["rack.request.query_hash"] =
|
168
|
+
parse_query(request.query_string)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns the data recieved in the request body.
|
173
|
+
#
|
174
|
+
# This method support both application/x-www-form-urlencoded and
|
175
|
+
# multipart/form-data.
|
176
|
+
def post_params
|
143
177
|
env = request.env
|
144
|
-
env["rack.request.form_input"]
|
145
|
-
|
146
|
-
|
147
|
-
env["rack.request.
|
148
|
-
env["rack.
|
178
|
+
if env["rack.request.form_input"].eql? env["rack.input"]
|
179
|
+
env["rack.request.form_hash"]
|
180
|
+
elsif request.form_data?
|
181
|
+
env["rack.request.form_input"] = env["rack.input"]
|
182
|
+
unless env["rack.request.form_hash"] =
|
183
|
+
Rack::Utils::Multipart.parse_multipart(env)
|
184
|
+
form_vars = env["rack.input"].read
|
185
|
+
|
186
|
+
# Fix for Safari Ajax postings that always append \0
|
187
|
+
form_vars.sub!(/\0\z/, '')
|
188
|
+
|
189
|
+
env["rack.request.form_vars"] = form_vars
|
190
|
+
env["rack.request.form_hash"] = parse_query(form_vars)
|
191
|
+
|
192
|
+
begin
|
193
|
+
env["rack.input"].rewind if env["rack.input"].respond_to?(:rewind)
|
194
|
+
rescue Errno::ESPIPE
|
195
|
+
# Handles exceptions raised by input streams that cannot be rewound
|
196
|
+
# such as when using plain CGI under Apache
|
197
|
+
end
|
198
|
+
end
|
199
|
+
env["rack.request.form_hash"]
|
200
|
+
else
|
201
|
+
{}
|
149
202
|
end
|
150
203
|
end
|
151
204
|
|
205
|
+
def capture_parameters # :nodoc:
|
206
|
+
get_params.update(post_params)
|
207
|
+
end
|
208
|
+
|
152
209
|
# helper to parse the request into a request hash for
|
153
210
|
# use by a Tap::Mechanize::Submit task
|
154
|
-
def parse_request
|
155
|
-
|
156
|
-
|
211
|
+
def parse_request
|
212
|
+
params = capture_parameters
|
213
|
+
capture_params = {}
|
214
|
+
params.each_key do |key|
|
215
|
+
if key =~ /#{prefix}/
|
216
|
+
normalize_params(capture_params, key, params.delete(key))
|
217
|
+
end
|
157
218
|
end
|
158
|
-
|
159
|
-
capture_overloaded_parameters
|
219
|
+
capture_params = capture_params[prefix]
|
160
220
|
|
161
221
|
hash = {}
|
162
|
-
parse_rack_request(request, keep_content).each_pair do |key, value|
|
222
|
+
parse_rack_request(request, params, capture_params['keep_content'] == "true").each_pair do |key, value|
|
163
223
|
hash[key.to_s] = value
|
164
224
|
end
|
165
225
|
|
166
|
-
action =
|
167
|
-
|
226
|
+
action = capture_params['original_action']
|
168
227
|
hash['uri'] = case action
|
169
228
|
when /^http/
|
170
229
|
# action is an href already
|
@@ -182,8 +241,10 @@ if(current = document.getElementById("#{prefix}")) {
|
|
182
241
|
File.join(base, action)
|
183
242
|
end
|
184
243
|
|
185
|
-
# remove
|
186
|
-
|
244
|
+
# remove extra data
|
245
|
+
unless capture_params['keep_headers'] == 'true'
|
246
|
+
hash.delete('headers')
|
247
|
+
end
|
187
248
|
hash.delete('version')
|
188
249
|
|
189
250
|
hash
|
data/lib/tap/mechanize/get.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
require 'tap/task'
|
1
2
|
require 'tap/mechanize/agent'
|
2
3
|
|
3
4
|
module Tap
|
4
5
|
module Mechanize
|
5
6
|
class Request < Tap::Task
|
6
|
-
nest :mechanize, Agent
|
7
|
+
nest :mechanize, Agent, :instance_reader => :mechanize # the mechanize agent
|
7
8
|
|
8
9
|
# Returns the mechanize agent.
|
9
10
|
#--
|
data/lib/tap/mechanize/submit.rb
CHANGED
@@ -2,7 +2,7 @@ require 'tap/mechanize/request'
|
|
2
2
|
|
3
3
|
module Tap
|
4
4
|
module Mechanize
|
5
|
-
# :startdoc::
|
5
|
+
# :startdoc::task submits a captured http request
|
6
6
|
#
|
7
7
|
# Performs a series of HTTP requests and returns the content of the final
|
8
8
|
# page. Requests must be hashes that at least specify the uri of the next
|
@@ -10,7 +10,7 @@ module Tap
|
|
10
10
|
def self.call(env)
|
11
11
|
body = env['rack.input'].read
|
12
12
|
headers = {}
|
13
|
-
env.each_pair {|key, value| headers[key] =
|
13
|
+
env.each_pair {|key, value| headers[key] = value unless key =~ /^rack/ }
|
14
14
|
|
15
15
|
[200, headers, [body]]
|
16
16
|
end
|
data/lib/tap/mechanize/utils.rb
CHANGED
@@ -120,7 +120,7 @@ module Tap
|
|
120
120
|
end
|
121
121
|
|
122
122
|
# Parses a Rack::Request, with the same activity as parse_http_request.
|
123
|
-
def parse_rack_request(request, keep_content=true)
|
123
|
+
def parse_rack_request(request, request_params, keep_content=true)
|
124
124
|
headers = {}
|
125
125
|
request.env.each_pair do |key, value|
|
126
126
|
key = case key
|
@@ -134,7 +134,7 @@ module Tap
|
|
134
134
|
end
|
135
135
|
|
136
136
|
params = {}
|
137
|
-
|
137
|
+
request_params.each_pair do |key, value|
|
138
138
|
params[key] = each_member(value) do |obj|
|
139
139
|
if obj.kind_of?(Hash)
|
140
140
|
file = {'Content-Type' => obj[:type], 'Filename' => obj[:filename]}
|
data/tap.yml
CHANGED
@@ -1 +0,0 @@
|
|
1
|
-
gems: tap-tasks
|
@@ -1,14 +1,23 @@
|
|
1
1
|
var RedirectHttp = {
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
<% configs.each do |(key, value)| %>
|
3
|
+
<%= key %>: <%= value.to_json %>,
|
4
|
+
<% end %>
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
// Generates a redirection input with the specified value. Inputs
|
7
|
+
// have names like '<%= prefix %>[key]' to prevent collisions and
|
8
|
+
// facilitate parsing server-side.
|
9
|
+
redirect_input: function(key, value) {
|
10
|
+
var input = document.createElement("input");
|
11
|
+
input.setAttribute("id", '<%= prefix %>[' + key + ']');
|
12
|
+
input.setAttribute("name", '<%= prefix %>[' + key + ']');
|
13
|
+
input.setAttribute("type", 'hidden');
|
14
|
+
input.setAttribute("value", value);
|
15
|
+
return input;
|
9
16
|
},
|
10
17
|
|
11
|
-
|
18
|
+
// Redirect the form, adds the redirection inputs, and then submits the
|
19
|
+
// form, if submit is true or undefined. After submit, the redirection
|
20
|
+
// inputs are removed from the form.
|
12
21
|
redirect_form: function(form, submit) {
|
13
22
|
if(typeof submit == 'undefined') { submit = true };
|
14
23
|
|
@@ -26,11 +35,23 @@ var RedirectHttp = {
|
|
26
35
|
}
|
27
36
|
}
|
28
37
|
|
29
|
-
//
|
30
|
-
|
31
|
-
|
38
|
+
// set redirection inputs
|
39
|
+
var original_action = form.getAttribute('<%= prefix %>original_action');
|
40
|
+
var redirect_inputs = [
|
41
|
+
<% configs.each do |(key, value)| %>
|
42
|
+
RedirectHttp.redirect_input('<%= key %>', RedirectHttp.<%= key %>),
|
43
|
+
<% end %>
|
44
|
+
RedirectHttp.redirect_input('original_action', original_action)
|
45
|
+
];
|
46
|
+
form.setAttribute('action', '<%= redirect_action %>');
|
47
|
+
for(i=0; i<redirect_inputs.length; i++) { form.appendChild(redirect_inputs[i]); }
|
48
|
+
|
32
49
|
form.submit();
|
33
50
|
|
51
|
+
// reset redirection inputs
|
52
|
+
form.setAttribute('action', original_action);
|
53
|
+
for(i=0; i<redirect_inputs.length; i++) { form.removeChild(redirect_inputs[i]); }
|
54
|
+
|
34
55
|
if(RedirectHttp.submit_request) {
|
35
56
|
this.revert();
|
36
57
|
form.submit();
|
@@ -44,13 +65,20 @@ var RedirectHttp = {
|
|
44
65
|
};
|
45
66
|
},
|
46
67
|
|
47
|
-
|
68
|
+
// Sumbits the redirected link with redirection parameters in the query
|
69
|
+
// string, if submit is true or undefined.
|
48
70
|
redirect_link: function(link, submit) {
|
49
71
|
if(typeof submit == 'undefined') { submit = true };
|
50
72
|
|
51
73
|
if(submit) {
|
52
74
|
var original_href = link.getAttribute('<%= prefix %>original_href');
|
53
|
-
|
75
|
+
redirect_params = [
|
76
|
+
<% configs.each do |(key, value)| %>
|
77
|
+
escape('<%= prefix %>[<%= key %>]') + "=" + escape(RedirectHttp.<%= key %>),
|
78
|
+
<% end %>
|
79
|
+
'<%= prefix %>[original_action]=' + escape(original_href)
|
80
|
+
];
|
81
|
+
location.href = '<%= redirect_action %>?' + redirect_params.join("&").replace(/%20/g, "+");
|
54
82
|
|
55
83
|
if(RedirectHttp.submit_request) {
|
56
84
|
this.revert();
|
@@ -59,8 +87,9 @@ var RedirectHttp = {
|
|
59
87
|
};
|
60
88
|
},
|
61
89
|
|
62
|
-
|
63
|
-
|
90
|
+
// Wraps the current onX event so that it may be called without interfering
|
91
|
+
// with the redirection (ie wrapper). Note events are not called again
|
92
|
+
// when a form is submitted or a redirection is performed by the wrapper.
|
64
93
|
wrap: function(current, wrapper) {
|
65
94
|
return "try {" +
|
66
95
|
" var <%= prefix %>result = function(<%= prefix %>this) { " +
|
@@ -72,7 +101,7 @@ var RedirectHttp = {
|
|
72
101
|
"}; return false;"
|
73
102
|
},
|
74
103
|
|
75
|
-
|
104
|
+
// Redirects forms and links to '<%= redirect_action %>'
|
76
105
|
redirect: function() {
|
77
106
|
try {
|
78
107
|
|
@@ -85,15 +114,8 @@ var RedirectHttp = {
|
|
85
114
|
if(form.getAttribute("class") != "<%= prefix %>form") {
|
86
115
|
|
87
116
|
// store the original action
|
88
|
-
|
89
|
-
|
90
|
-
input.setAttribute("name", '<%= redirect_parameter %>');
|
91
|
-
input.setAttribute("type", 'hidden');
|
92
|
-
input.setAttribute("value", form.getAttribute('action'));
|
93
|
-
|
94
|
-
form.setAttribute('<%= prefix %>index', i);
|
95
|
-
form.appendChild(input);
|
96
|
-
|
117
|
+
form.setAttribute("<%= prefix %>original_action", form.getAttribute('action'));
|
118
|
+
|
97
119
|
// redirect onSubmit
|
98
120
|
var current_on_submit = '';
|
99
121
|
if(form.hasAttribute("onSubmit")) current_on_submit = form.getAttribute("onSubmit");
|
@@ -130,7 +152,7 @@ var RedirectHttp = {
|
|
130
152
|
}
|
131
153
|
},
|
132
154
|
|
133
|
-
|
155
|
+
// Reverts redirection and removes the redirection div
|
134
156
|
revert: function() {
|
135
157
|
try {
|
136
158
|
|
@@ -140,13 +162,9 @@ var RedirectHttp = {
|
|
140
162
|
var form = forms[i];
|
141
163
|
|
142
164
|
// check in case the form was not redirected
|
143
|
-
if(form.hasAttribute('<%= prefix %>
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
form.setAttribute('action', input.value);
|
148
|
-
form.removeAttribute('<%= prefix %>index');
|
149
|
-
form.removeChild(input);
|
165
|
+
if(form.hasAttribute('<%= prefix %>original_action')) {
|
166
|
+
form.setAttribute('action', form.getAttribute('<%= prefix %>original_action'));
|
167
|
+
form.removeAttribute('<%= prefix %>original_action');
|
150
168
|
|
151
169
|
form.setAttribute('onSubmit', form.getAttribute('<%= prefix %>original_callback'));
|
152
170
|
form.removeAttribute('<%= prefix %>original_callback');
|
@@ -177,7 +195,7 @@ var RedirectHttp = {
|
|
177
195
|
if(redirect_http) document.body.removeChild(redirect_http);
|
178
196
|
},
|
179
197
|
|
180
|
-
// Alerts
|
198
|
+
// Alerts errors due to RedirectHttp
|
181
199
|
alert_error: function(ex) {
|
182
200
|
alert("Redirect HTTP Error: " + ex.message + "\n\n The webpage may have been corrupted; be sure to refresh.");
|
183
201
|
}
|
@@ -1,8 +1,13 @@
|
|
1
1
|
<span id='<%= prefix %>message'>Redirecting HTTP Requests</span>
|
2
2
|
<ul id='<%= prefix %>controls' >
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
<% configs.each do |(key, value)| %>
|
4
|
+
<% case value %>
|
5
|
+
<% when true, false %>
|
6
|
+
<li><input id='<%= prefix %><%= key %>' type='checkbox' <%= value ? "checked='true' " : '' %>onchange='javascript:RedirectHttp.<%= key %>=this.checked;'><%= key %></input></li>
|
7
|
+
<% else %>
|
8
|
+
<li><input id='<%= prefix %><%= key %>' type='text' value='<%= value %>' onchange='javascript:RedirectHttp.<%= key %>=this.value;'><%= key %></input></li>
|
9
|
+
<% end %>
|
10
|
+
<% end %>
|
6
11
|
</ul>
|
7
12
|
<a id='<%= prefix %>revert' href='javascript:RedirectHttp.revert();' class="<%= prefix %>link">close</a>
|
8
13
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tap-mechanize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon Chiang
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-05-25 00:00:00 -06:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.
|
23
|
+
version: 0.3.0
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: tap-tasks
|
@@ -30,7 +30,7 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.2.0
|
34
34
|
version:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: mechanize
|