mechanize 0.6.11 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of mechanize might be problematic. Click here for more details.
- data/CHANGELOG.txt +8 -0
- data/Manifest.txt +31 -22
- data/lib/mechanize.rb +2 -652
- data/lib/www/mechanize.rb +635 -0
- data/lib/www/mechanize/content_type_error.rb +16 -0
- data/lib/www/mechanize/cookie.rb +64 -0
- data/lib/{mechanize/cookie.rb → www/mechanize/cookie_jar.rb} +0 -60
- data/lib/www/mechanize/file.rb +73 -0
- data/lib/www/mechanize/file_saver.rb +39 -0
- data/lib/{mechanize → www/mechanize}/form.rb +119 -137
- data/lib/www/mechanize/form/button.rb +8 -0
- data/lib/www/mechanize/form/check_box.rb +13 -0
- data/lib/www/mechanize/form/field.rb +28 -0
- data/lib/www/mechanize/form/file_upload.rb +24 -0
- data/lib/www/mechanize/form/image_button.rb +23 -0
- data/lib/www/mechanize/form/multi_select_list.rb +69 -0
- data/lib/www/mechanize/form/option.rb +51 -0
- data/lib/www/mechanize/form/radio_button.rb +38 -0
- data/lib/www/mechanize/form/select_list.rb +41 -0
- data/lib/www/mechanize/headers.rb +12 -0
- data/lib/{mechanize → www/mechanize}/history.rb +0 -0
- data/lib/{mechanize → www/mechanize}/inspect.rb +21 -28
- data/lib/{mechanize → www/mechanize}/list.rb +0 -0
- data/lib/{mechanize → www/mechanize}/monkey_patch.rb +19 -0
- data/lib/www/mechanize/page.rb +121 -0
- data/lib/www/mechanize/page/base.rb +10 -0
- data/lib/www/mechanize/page/frame.rb +22 -0
- data/lib/www/mechanize/page/link.rb +50 -0
- data/lib/www/mechanize/page/meta.rb +10 -0
- data/lib/www/mechanize/pluggable_parsers.rb +93 -0
- data/lib/{mechanize/errors.rb → www/mechanize/response_code_error.rb} +1 -13
- data/test/{test_includes.rb → helper.rb} +4 -18
- data/test/{test_servlets.rb → servlets.rb} +0 -0
- data/test/tc_authenticate.rb +1 -8
- data/test/tc_bad_links.rb +3 -10
- data/test/tc_blank_form.rb +1 -8
- data/test/tc_checkboxes.rb +1 -8
- data/test/tc_cookie_class.rb +1 -6
- data/test/tc_cookie_jar.rb +1 -7
- data/test/tc_cookies.rb +10 -17
- data/test/tc_encoded_links.rb +5 -12
- data/test/tc_errors.rb +4 -11
- data/test/tc_follow_meta.rb +1 -8
- data/test/tc_form_action.rb +6 -14
- data/test/tc_form_as_hash.rb +1 -9
- data/test/tc_form_button.rb +5 -8
- data/test/tc_form_no_inputname.rb +1 -8
- data/test/tc_forms.rb +16 -24
- data/test/tc_frames.rb +3 -10
- data/test/tc_gzipping.rb +2 -9
- data/test/tc_history.rb +5 -12
- data/test/tc_html_unscape_forms.rb +8 -15
- data/test/tc_if_modified_since.rb +1 -6
- data/test/tc_keep_alive.rb +1 -8
- data/test/tc_links.rb +12 -19
- data/test/tc_mech.rb +26 -34
- data/test/{test_mechanize_file.rb → tc_mechanize_file.rb} +1 -6
- data/test/tc_multi_select.rb +10 -17
- data/test/tc_no_attributes.rb +1 -8
- data/test/tc_page.rb +3 -10
- data/test/tc_pluggable_parser.rb +8 -15
- data/test/tc_post_form.rb +3 -10
- data/test/tc_pretty_print.rb +3 -10
- data/test/tc_radiobutton.rb +2 -9
- data/test/tc_referer.rb +13 -20
- data/test/tc_relative_links.rb +1 -8
- data/test/tc_response_code.rb +14 -21
- data/test/tc_save_file.rb +1 -9
- data/test/tc_select.rb +3 -10
- data/test/tc_select_all.rb +2 -10
- data/test/tc_select_none.rb +2 -10
- data/test/tc_select_noopts.rb +2 -9
- data/test/tc_set_fields.rb +2 -9
- data/test/tc_ssl_server.rb +5 -12
- data/test/tc_subclass.rb +2 -9
- data/test/tc_textarea.rb +2 -9
- data/test/tc_upload.rb +2 -9
- data/test/test_all.rb +4 -43
- metadata +96 -80
- data/lib/mechanize/form_elements.rb +0 -254
- data/lib/mechanize/net-overrides/net/http.rb +0 -2107
- data/lib/mechanize/net-overrides/net/https.rb +0 -172
- data/lib/mechanize/net-overrides/net/protocol.rb +0 -380
- data/lib/mechanize/page.rb +0 -138
- data/lib/mechanize/page_elements.rb +0 -77
- data/lib/mechanize/parsers/rexml_page.rb +0 -35
- data/lib/mechanize/pluggable_parsers.rb +0 -204
- data/lib/mechanize/rexml.rb +0 -236
- data/setup.rb +0 -1585
- data/test/tc_proxy.rb +0 -25
- data/test/tc_watches.rb +0 -32
@@ -0,0 +1,16 @@
|
|
1
|
+
module WWW
|
2
|
+
class Mechanize
|
3
|
+
# =Synopsis
|
4
|
+
# This class contains an error for when a pluggable parser tries to
|
5
|
+
# parse a content type that it does not know how to handle. For example
|
6
|
+
# if WWW::Mechanize::Page were to try to parse a PDF, a ContentTypeError
|
7
|
+
# would be thrown.
|
8
|
+
class ContentTypeError < RuntimeError
|
9
|
+
attr_reader :content_type
|
10
|
+
|
11
|
+
def initialize(content_type)
|
12
|
+
@content_type = content_type
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'webrick/cookie'
|
3
|
+
|
4
|
+
module WWW
|
5
|
+
class Mechanize
|
6
|
+
# This class is used to represent an HTTP Cookie.
|
7
|
+
class Cookie < WEBrick::Cookie
|
8
|
+
def self.parse(uri, str, log = nil)
|
9
|
+
return str.split(/,(?=[^;,]*=)|,$/).collect { |c|
|
10
|
+
cookie_elem = c.split(/;/)
|
11
|
+
first_elem = cookie_elem.shift
|
12
|
+
first_elem.strip!
|
13
|
+
key, value = first_elem.split(/=/, 2)
|
14
|
+
cookie = new(key, WEBrick::HTTPUtils.dequote(value))
|
15
|
+
cookie_elem.each{|pair|
|
16
|
+
pair.strip!
|
17
|
+
key, value = pair.split(/=/, 2)
|
18
|
+
if value
|
19
|
+
value = WEBrick::HTTPUtils.dequote(value.strip)
|
20
|
+
end
|
21
|
+
case key.downcase
|
22
|
+
when "domain" then cookie.domain = value.sub(/^\./, '')
|
23
|
+
when "path" then cookie.path = value
|
24
|
+
when 'expires'
|
25
|
+
begin
|
26
|
+
cookie.expires = Time::parse(value)
|
27
|
+
rescue
|
28
|
+
if log
|
29
|
+
log.warn("Couldn't parse expires: #{value}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
when "max-age" then
|
33
|
+
begin
|
34
|
+
cookie.max_age = Integer(value)
|
35
|
+
rescue
|
36
|
+
log.warn("Couldn't parse max age '#{value}'") if log
|
37
|
+
cookie.max_age = nil
|
38
|
+
end
|
39
|
+
when "comment" then cookie.comment = value
|
40
|
+
when "version" then
|
41
|
+
begin
|
42
|
+
cookie.version = Integer(value)
|
43
|
+
rescue
|
44
|
+
log.warn("Couldn't parse version '#{value}'") if log
|
45
|
+
cookie.version = nil
|
46
|
+
end
|
47
|
+
when "secure" then cookie.secure = true
|
48
|
+
end
|
49
|
+
}
|
50
|
+
|
51
|
+
cookie.path ||= uri.path.to_s.sub(/[^\/]*$/, '')
|
52
|
+
cookie.secure ||= false
|
53
|
+
cookie.domain ||= uri.host
|
54
|
+
# Move this in to the cookie jar
|
55
|
+
yield cookie if block_given?
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"#{@name}=#{@value}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,67 +1,7 @@
|
|
1
1
|
require 'yaml'
|
2
|
-
require 'time'
|
3
|
-
require 'webrick/cookie'
|
4
2
|
|
5
3
|
module WWW
|
6
4
|
class Mechanize
|
7
|
-
# This class is used to represent an HTTP Cookie.
|
8
|
-
class Cookie < WEBrick::Cookie
|
9
|
-
def self.parse(uri, str, log = nil)
|
10
|
-
return str.split(/,(?=[^;,]*=)|,$/).collect { |c|
|
11
|
-
cookie_elem = c.split(/;/)
|
12
|
-
first_elem = cookie_elem.shift
|
13
|
-
first_elem.strip!
|
14
|
-
key, value = first_elem.split(/=/, 2)
|
15
|
-
cookie = new(key, WEBrick::HTTPUtils.dequote(value))
|
16
|
-
cookie_elem.each{|pair|
|
17
|
-
pair.strip!
|
18
|
-
key, value = pair.split(/=/, 2)
|
19
|
-
if value
|
20
|
-
value = WEBrick::HTTPUtils.dequote(value.strip)
|
21
|
-
end
|
22
|
-
case key.downcase
|
23
|
-
when "domain" then cookie.domain = value.sub(/^\./, '')
|
24
|
-
when "path" then cookie.path = value
|
25
|
-
when 'expires'
|
26
|
-
begin
|
27
|
-
cookie.expires = Time::parse(value)
|
28
|
-
rescue
|
29
|
-
if log
|
30
|
-
log.warn("Couldn't parse expires: #{value}")
|
31
|
-
end
|
32
|
-
end
|
33
|
-
when "max-age" then
|
34
|
-
begin
|
35
|
-
cookie.max_age = Integer(value)
|
36
|
-
rescue
|
37
|
-
log.warn("Couldn't parse max age '#{value}'") if log
|
38
|
-
cookie.max_age = nil
|
39
|
-
end
|
40
|
-
when "comment" then cookie.comment = value
|
41
|
-
when "version" then
|
42
|
-
begin
|
43
|
-
cookie.version = Integer(value)
|
44
|
-
rescue
|
45
|
-
log.warn("Couldn't parse version '#{value}'") if log
|
46
|
-
cookie.version = nil
|
47
|
-
end
|
48
|
-
when "secure" then cookie.secure = true
|
49
|
-
end
|
50
|
-
}
|
51
|
-
|
52
|
-
cookie.path ||= uri.path.to_s.sub(/[^\/]*$/, '')
|
53
|
-
cookie.secure ||= false
|
54
|
-
cookie.domain ||= uri.host
|
55
|
-
# Move this in to the cookie jar
|
56
|
-
yield cookie if block_given?
|
57
|
-
}
|
58
|
-
end
|
59
|
-
|
60
|
-
def to_s
|
61
|
-
"#{@name}=#{@value}"
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
5
|
# This class is used to manage the Cookies that have been returned from
|
66
6
|
# any particular website.
|
67
7
|
class CookieJar
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module WWW
|
2
|
+
class Mechanize
|
3
|
+
# = Synopsis
|
4
|
+
# This is the default (and base) class for the Pluggable Parsers. If
|
5
|
+
# Mechanize cannot find an appropriate class to use for the content type,
|
6
|
+
# this class will be used. For example, if you download a JPG, Mechanize
|
7
|
+
# will not know how to parse it, so this class will be instantiated.
|
8
|
+
#
|
9
|
+
# This is a good class to use as the base class for building your own
|
10
|
+
# pluggable parsers.
|
11
|
+
#
|
12
|
+
# == Example
|
13
|
+
# require 'rubygems'
|
14
|
+
# require 'mechanize'
|
15
|
+
#
|
16
|
+
# agent = WWW::Mechanize.new
|
17
|
+
# agent.get('http://example.com/foo.jpg').class #=> WWW::Mechanize::File
|
18
|
+
#
|
19
|
+
class File
|
20
|
+
attr_accessor :uri, :response, :body, :code, :filename
|
21
|
+
alias :header :response
|
22
|
+
|
23
|
+
alias :content :body
|
24
|
+
|
25
|
+
def initialize(uri=nil, response=nil, body=nil, code=nil)
|
26
|
+
@uri, @body, @code = uri, body, code
|
27
|
+
@response = Headers.new
|
28
|
+
|
29
|
+
# Copy the headers in to a hash to prevent memory leaks
|
30
|
+
if response
|
31
|
+
response.each { |k,v|
|
32
|
+
@response[k] = v
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
@filename = 'index.html'
|
37
|
+
|
38
|
+
# Set the filename
|
39
|
+
if disposition = @response['content-disposition']
|
40
|
+
disposition.split(/;\s*/).each do |pair|
|
41
|
+
k,v = pair.split(/=/, 2)
|
42
|
+
@filename = v if k.downcase == 'filename'
|
43
|
+
end
|
44
|
+
else
|
45
|
+
if @uri
|
46
|
+
@filename = @uri.path.split(/\//).last || 'index.html'
|
47
|
+
@filename << ".html" unless @filename =~ /\./
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
yield self if block_given?
|
52
|
+
end
|
53
|
+
|
54
|
+
# Use this method to save the content of this object to filename
|
55
|
+
def save_as(filename = nil)
|
56
|
+
if filename.nil?
|
57
|
+
filename = @filename
|
58
|
+
number = 1
|
59
|
+
while(::File.exists?(filename))
|
60
|
+
filename = "#{@filename}.#{number}"
|
61
|
+
number += 1
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
::File::open(filename, "wb") { |f|
|
66
|
+
f.write body
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
alias :save :save_as
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module WWW
|
2
|
+
class Mechanize
|
3
|
+
# = Synopsis
|
4
|
+
# This is a pluggable parser that automatically saves every file
|
5
|
+
# it encounters. It saves the files as a tree, reflecting the
|
6
|
+
# host and file path.
|
7
|
+
#
|
8
|
+
# == Example to save all PDF's
|
9
|
+
# require 'rubygems'
|
10
|
+
# require 'mechanize'
|
11
|
+
#
|
12
|
+
# agent = WWW::Mechanize.new
|
13
|
+
# agent.pluggable_parser.pdf = WWW::Mechanize::FileSaver
|
14
|
+
# agent.get('http://example.com/foo.pdf')
|
15
|
+
#
|
16
|
+
class FileSaver < File
|
17
|
+
attr_reader :filename
|
18
|
+
|
19
|
+
def initialize(uri=nil, response=nil, body=nil, code=nil)
|
20
|
+
super(uri, response, body, code)
|
21
|
+
path = uri.path.empty? ? 'index.html' : uri.path.gsub(/^[\/]*/, '')
|
22
|
+
path += 'index.html' if path =~ /\/$/
|
23
|
+
|
24
|
+
split_path = path.split(/\//)
|
25
|
+
filename = split_path.length > 0 ? split_path.pop : 'index.html'
|
26
|
+
joined_path = split_path.join(::File::SEPARATOR)
|
27
|
+
path = if joined_path.empty?
|
28
|
+
uri.host
|
29
|
+
else
|
30
|
+
"#{uri.host}#{::File::SEPARATOR}#{joined_path}"
|
31
|
+
end
|
32
|
+
|
33
|
+
@filename = "#{path}#{::File::SEPARATOR}#{filename}"
|
34
|
+
FileUtils.mkdir_p(path)
|
35
|
+
save_as(@filename)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,27 +1,28 @@
|
|
1
|
+
require 'www/mechanize/form/field'
|
2
|
+
require 'www/mechanize/form/file_upload'
|
3
|
+
require 'www/mechanize/form/button'
|
4
|
+
require 'www/mechanize/form/image_button'
|
5
|
+
require 'www/mechanize/form/radio_button'
|
6
|
+
require 'www/mechanize/form/check_box'
|
7
|
+
require 'www/mechanize/form/multi_select_list'
|
8
|
+
require 'www/mechanize/form/select_list'
|
9
|
+
require 'www/mechanize/form/option'
|
10
|
+
|
1
11
|
module WWW
|
2
12
|
class Mechanize
|
3
13
|
# =Synopsis
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# GlobalForm takes two nodes, the node where the form tag is located
|
8
|
-
# (form_node), and another node, from which to start looking for form
|
9
|
-
# elements (elements_node) like buttons and the like. For class Form
|
10
|
-
# both fall together into one and the same node.
|
11
|
-
#
|
12
|
-
# Class Form does not work in the case there is some invalid (unbalanced)
|
13
|
-
# html involved, such as:
|
14
|
+
# This class encapsulates a form parsed out of an HTML page. Each type
|
15
|
+
# of input fields available in a form can be accessed through this object.
|
16
|
+
# See GlobalForm for more methods.
|
14
17
|
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
|
23
|
-
class GlobalForm
|
24
|
-
attr_reader :form_node, :elements_node
|
18
|
+
# ==Example
|
19
|
+
# Find a form and print out its fields
|
20
|
+
# form = page.forms.first # => WWW::Mechanize::Form
|
21
|
+
# form.fields.each { |f| puts f.name }
|
22
|
+
# Set the input field 'name' to "Aaron"
|
23
|
+
# form['name'] = 'Aaron'
|
24
|
+
# puts form['name']
|
25
|
+
class Form
|
25
26
|
attr_accessor :method, :action, :name
|
26
27
|
|
27
28
|
attr_reader :fields, :buttons, :file_uploads, :radiobuttons, :checkboxes
|
@@ -29,18 +30,104 @@ module WWW
|
|
29
30
|
|
30
31
|
alias :elements :fields
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
@method = (@form_node['method'] || 'GET').upcase
|
36
|
-
@action = Util::html_unescape(@form_node['action'])
|
37
|
-
@name = @form_node['name']
|
38
|
-
@enctype = @form_node['enctype'] || 'application/x-www-form-urlencoded'
|
39
|
-
@clicked_buttons = []
|
33
|
+
attr_reader :form_node
|
34
|
+
attr_reader :page
|
40
35
|
|
36
|
+
def initialize(node, mech=nil, page=nil)
|
37
|
+
@enctype = node['enctype'] || 'application/x-www-form-urlencoded'
|
38
|
+
@form_node = node
|
39
|
+
@action = Mechanize.html_unescape(node['action'])
|
40
|
+
@method = (node['method'] || 'GET').upcase
|
41
|
+
@name = node['name']
|
42
|
+
@clicked_buttons = []
|
43
|
+
@page = page
|
44
|
+
@mech = mech
|
45
|
+
|
41
46
|
parse
|
42
47
|
end
|
43
|
-
|
48
|
+
|
49
|
+
# Returns whether or not the form contains a field with +field_name+
|
50
|
+
def has_field?(field_name)
|
51
|
+
! fields.find { |f| f.name.eql? field_name }.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
alias :has_key? :has_field?
|
55
|
+
|
56
|
+
def has_value?(value)
|
57
|
+
! fields.find { |f| f.value.eql? value }.nil?
|
58
|
+
end
|
59
|
+
|
60
|
+
def keys; fields.map { |f| f.name }; end
|
61
|
+
|
62
|
+
def values; fields.map { |f| f.value }; end
|
63
|
+
|
64
|
+
# Fetch the first field whose name is equal to +field_name+
|
65
|
+
def field(field_name)
|
66
|
+
fields.find { |f| f.name.eql? field_name }
|
67
|
+
end
|
68
|
+
|
69
|
+
# Add a field with +field_name+ and +value+
|
70
|
+
def add_field!(field_name, value = nil)
|
71
|
+
fields << Field.new(field_name, value)
|
72
|
+
end
|
73
|
+
|
74
|
+
# This method sets multiple fields on the form. It takes a list of field
|
75
|
+
# name, value pairs. If there is more than one field found with the
|
76
|
+
# same name, this method will set the first one found. If you want to
|
77
|
+
# set the value of a duplicate field, use a value which is an Array with
|
78
|
+
# the second value of the array as the index in to the form. The index
|
79
|
+
# is zero based. For example, to set the second field named 'foo', you
|
80
|
+
# could do the following:
|
81
|
+
# form.set_fields( :foo => ['bar', 1] )
|
82
|
+
def set_fields(fields = {})
|
83
|
+
fields.each do |k,v|
|
84
|
+
value = nil
|
85
|
+
index = 0
|
86
|
+
v.each do |val|
|
87
|
+
index = val.to_i unless value.nil?
|
88
|
+
value = val if value.nil?
|
89
|
+
end
|
90
|
+
self.fields.name(k.to_s).[](index).value = value
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Fetch the value of the first input field with the name passed in
|
95
|
+
# ==Example
|
96
|
+
# Fetch the value set in the input field 'name'
|
97
|
+
# puts form['name']
|
98
|
+
def [](field_name)
|
99
|
+
f = field(field_name)
|
100
|
+
f && f.value
|
101
|
+
end
|
102
|
+
|
103
|
+
# Set the value of the first input field with the name passed in
|
104
|
+
# ==Example
|
105
|
+
# Set the value in the input field 'name' to "Aaron"
|
106
|
+
# form['name'] = 'Aaron'
|
107
|
+
def []=(field_name, value)
|
108
|
+
f = field(field_name)
|
109
|
+
if f.nil?
|
110
|
+
add_field!(field_name, value)
|
111
|
+
else
|
112
|
+
f.value = value
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Treat form fields like accessors.
|
117
|
+
def method_missing(id,*args)
|
118
|
+
method = id.to_s.gsub(/=$/, '')
|
119
|
+
if field(method)
|
120
|
+
return field(method).value if args.empty?
|
121
|
+
return field(method).value = args[0]
|
122
|
+
end
|
123
|
+
super
|
124
|
+
end
|
125
|
+
|
126
|
+
# Submit this form with the button passed in
|
127
|
+
def submit(button=nil)
|
128
|
+
@mech.submit(self, button)
|
129
|
+
end
|
130
|
+
|
44
131
|
# This method builds an array of arrays that represent the query
|
45
132
|
# parameters to be used with this form. The return value can then
|
46
133
|
# be used to create a query string for this form.
|
@@ -119,7 +206,7 @@ module WWW
|
|
119
206
|
@checkboxes = WWW::Mechanize::List.new
|
120
207
|
|
121
208
|
# Find all input tags
|
122
|
-
(
|
209
|
+
(form_node/'input').each do |node|
|
123
210
|
type = (node['type'] || 'text').downcase
|
124
211
|
name = node['name']
|
125
212
|
next if name.nil? && !(type == 'submit' || type =='button')
|
@@ -142,13 +229,13 @@ module WWW
|
|
142
229
|
end
|
143
230
|
|
144
231
|
# Find all textarea tags
|
145
|
-
(
|
232
|
+
(form_node/'textarea').each do |node|
|
146
233
|
next if node['name'].nil?
|
147
234
|
@fields << Field.new(node['name'], node.inner_text)
|
148
235
|
end
|
149
236
|
|
150
237
|
# Find all select tags
|
151
|
-
(
|
238
|
+
(form_node/'select').each do |node|
|
152
239
|
next if node['name'].nil?
|
153
240
|
if node.has_attribute? 'multiple'
|
154
241
|
@fields << MultiSelectList.new(node['name'], node)
|
@@ -202,110 +289,5 @@ module WWW
|
|
202
289
|
body
|
203
290
|
end
|
204
291
|
end
|
205
|
-
|
206
|
-
# =Synopsis
|
207
|
-
# This class encapsulates a form parsed out of an HTML page. Each type
|
208
|
-
# of input fields available in a form can be accessed through this object.
|
209
|
-
# See GlobalForm for more methods.
|
210
|
-
#
|
211
|
-
# ==Example
|
212
|
-
# Find a form and print out its fields
|
213
|
-
# form = page.forms.first # => WWW::Mechanize::Form
|
214
|
-
# form.fields.each { |f| puts f.name }
|
215
|
-
# Set the input field 'name' to "Aaron"
|
216
|
-
# form['name'] = 'Aaron'
|
217
|
-
# puts form['name']
|
218
|
-
class Form < GlobalForm
|
219
|
-
attr_reader :node
|
220
|
-
attr_reader :page
|
221
|
-
|
222
|
-
def initialize(node, mech=nil, page=nil)
|
223
|
-
super(node, node)
|
224
|
-
@page = page
|
225
|
-
@mech = mech
|
226
|
-
end
|
227
|
-
|
228
|
-
# Returns whether or not the form contains a field with +field_name+
|
229
|
-
def has_field?(field_name)
|
230
|
-
! fields.find { |f| f.name.eql? field_name }.nil?
|
231
|
-
end
|
232
|
-
|
233
|
-
alias :has_key? :has_field?
|
234
|
-
|
235
|
-
def has_value?(value)
|
236
|
-
! fields.find { |f| f.value.eql? value }.nil?
|
237
|
-
end
|
238
|
-
|
239
|
-
def keys; fields.map { |f| f.name }; end
|
240
|
-
|
241
|
-
def values; fields.map { |f| f.value }; end
|
242
|
-
|
243
|
-
# Fetch the first field whose name is equal to +field_name+
|
244
|
-
def field(field_name)
|
245
|
-
fields.find { |f| f.name.eql? field_name }
|
246
|
-
end
|
247
|
-
|
248
|
-
# Add a field with +field_name+ and +value+
|
249
|
-
def add_field!(field_name, value = nil)
|
250
|
-
fields << WWW::Mechanize::Field.new(field_name, value)
|
251
|
-
end
|
252
|
-
|
253
|
-
# This method sets multiple fields on the form. It takes a list of field
|
254
|
-
# name, value pairs. If there is more than one field found with the
|
255
|
-
# same name, this method will set the first one found. If you want to
|
256
|
-
# set the value of a duplicate field, use a value which is an Array with
|
257
|
-
# the second value of the array as the index in to the form. The index
|
258
|
-
# is zero based. For example, to set the second field named 'foo', you
|
259
|
-
# could do the following:
|
260
|
-
# form.set_fields( :foo => ['bar', 1] )
|
261
|
-
def set_fields(fields = {})
|
262
|
-
fields.each do |k,v|
|
263
|
-
value = nil
|
264
|
-
index = 0
|
265
|
-
v.each do |val|
|
266
|
-
index = val.to_i unless value.nil?
|
267
|
-
value = val if value.nil?
|
268
|
-
end
|
269
|
-
self.fields.name(k.to_s).[](index).value = value
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
# Fetch the value of the first input field with the name passed in
|
274
|
-
# ==Example
|
275
|
-
# Fetch the value set in the input field 'name'
|
276
|
-
# puts form['name']
|
277
|
-
def [](field_name)
|
278
|
-
f = field(field_name)
|
279
|
-
f && f.value
|
280
|
-
end
|
281
|
-
|
282
|
-
# Set the value of the first input field with the name passed in
|
283
|
-
# ==Example
|
284
|
-
# Set the value in the input field 'name' to "Aaron"
|
285
|
-
# form['name'] = 'Aaron'
|
286
|
-
def []=(field_name, value)
|
287
|
-
f = field(field_name)
|
288
|
-
if f.nil?
|
289
|
-
add_field!(field_name, value)
|
290
|
-
else
|
291
|
-
f.value = value
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
# Treat form fields like accessors.
|
296
|
-
def method_missing(id,*args)
|
297
|
-
method = id.to_s.gsub(/=$/, '')
|
298
|
-
if field(method)
|
299
|
-
return field(method).value if args.empty?
|
300
|
-
return field(method).value = args[0]
|
301
|
-
end
|
302
|
-
super
|
303
|
-
end
|
304
|
-
|
305
|
-
# Submit this form with the button passed in
|
306
|
-
def submit(button=nil)
|
307
|
-
@mech.submit(self, button)
|
308
|
-
end
|
309
|
-
end
|
310
292
|
end
|
311
293
|
end
|