tap-mechanize 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|