class WWW::Mechanize::Form
puts form[‘name’]<br>form = ‘Aaron’
Set the input field ‘name’ to “Aaron”
form.fields.each { |f| puts f.name }
form = page.forms.first # => WWW::Mechanize::Form
Find a form and print out its fields
==Example
See GlobalForm for more methods.
of input fields available in a form can be accessed through this object.
This class encapsulates a form parsed out of an HTML page. Each type
=Synopsis
def [](field_name)
Fetch the value set in the input field 'name'
==Example
Fetch the value of the first input field with the name passed in
def [](field_name) f = field(field_name) f && f.value end
def []=(field_name, value)
Set the value in the input field 'name' to "Aaron"
==Example
Set the value of the first input field with the name passed in
def []=(field_name, value) f = field(field_name) if f.nil? add_field!(field_name, value) else f.value = value end end
def add_button_to_query(button)
This method adds a button to the query. If the form needs to be
def add_button_to_query(button) @clicked_buttons << button end
def add_field!(field_name, value = nil)
def add_field!(field_name, value = nil) fields << Field.new(field_name, value) end
def build_query(buttons = [])
parameters to be used with this form. The return value can then
This method builds an array of arrays that represent the query
def build_query(buttons = []) query = [] fields().each do |f| query.push(*f.query_value) end checkboxes().each do |f| query.push(*f.query_value) if f.checked end radio_groups = {} radiobuttons().each do |f| radio_groups[f.name] ||= [] radio_groups[f.name] << f end # take one radio button from each group radio_groups.each_value do |g| checked = g.select {|f| f.checked} if checked.size == 1 f = checked.first query.push(*f.query_value) elsif checked.size > 1 raise "multiple radiobuttons are checked in the same group!" end end @clicked_buttons.each { |b| query.push(*b.query_value) } query end
def click_button(button = buttons.first)
Submit form using +button+. Defaults
def click_button(button = buttons.first) submit(button) end
def delete_field!(field_name)
def delete_field!(field_name) @fields.delete_if{ |f| f.name == field_name} end
def file_to_multipart(file)
def file_to_multipart(file) file_name = file.file_name ? ::File.basename(file.file_name) : '' body = "Content-Disposition: form-data; name=\"" + "#{mime_value_quote(file.name)}\"; " + "filename=\"#{mime_value_quote(file_name)}\"\r\n" + "Content-Transfer-Encoding: binary\r\n" if file.file_data.nil? and ! file.file_name.nil? file.file_data = ::File.open(file.file_name, "rb") { |f| f.read } file.mime_type = WEBrick::HTTPUtils.mime_type(file.file_name, WEBrick::HTTPUtils::DefaultMimeTypes) end if file.mime_type != nil body << "Content-Type: #{file.mime_type}\r\n" end body << if file.file_data.respond_to? :read "\r\n#{file.file_data.read}\r\n" else "\r\n#{file.file_data}\r\n" end body end
def has_field?(field_name)
def has_field?(field_name) ! fields.find { |f| f.name.eql? field_name }.nil? end
def has_value?(value)
def has_value?(value) ! fields.find { |f| f.value.eql? value }.nil? end
def initialize(node, mech=nil, page=nil)
def initialize(node, mech=nil, page=nil) @enctype = node['enctype'] || 'application/x-www-form-urlencoded' @form_node = node @action = Util.html_unescape(node['action']) @method = (node['method'] || 'GET').upcase @name = node['name'] @clicked_buttons = [] @page = page @mech = mech parse end
def keys; fields.map { |f| f.name }; end
def keys; fields.map { |f| f.name }; end
def method_missing(id,*args)
def method_missing(id,*args) method = id.to_s.gsub(/=$/, '') if field(method) return field(method).value if args.empty? return field(method).value = args[0] end super end
def mime_value_quote(str)
def mime_value_quote(str) str.gsub(/(["\r\\])/){|s| '\\' + s} end
def param_to_multipart(name, value)
def param_to_multipart(name, value) return "Content-Disposition: form-data; name=\"" + "#{mime_value_quote(name)}\"\r\n" + "\r\n#{value}\r\n" end
def parse
def parse @fields = WWW::Mechanize::List.new @buttons = WWW::Mechanize::List.new @file_uploads = WWW::Mechanize::List.new @radiobuttons = WWW::Mechanize::List.new @checkboxes = WWW::Mechanize::List.new # Find all input tags form_node.search('input').each do |node| type = (node['type'] || 'text').downcase name = node['name'] next if name.nil? && !(type == 'submit' || type =='button') case type when 'radio' @radiobuttons << RadioButton.new(node['name'], node['value'], !!node['checked'], self) when 'checkbox' @checkboxes << CheckBox.new(node['name'], node['value'], !!node['checked'], self) when 'file' @file_uploads << FileUpload.new(node['name'], nil) when 'submit' @buttons << Button.new(node['name'], node['value']) when 'button' @buttons << Button.new(node['name'], node['value']) when 'image' @buttons << ImageButton.new(node['name'], node['value']) else @fields << Field.new(node['name'], node['value'] || '') end end # Find all textarea tags form_node.search('textarea').each do |node| next if node['name'].nil? @fields << Field.new(node['name'], node.inner_text) end # Find all select tags form_node.search('select').each do |node| next if node['name'].nil? if node.has_attribute? 'multiple' @fields << MultiSelectList.new(node['name'], node) else @fields << SelectList.new(node['name'], node) end end # Find all submit button tags # FIXME: what can I do with the reset buttons? form_node.search('button').each do |node| type = (node['type'] || 'submit').downcase next if type == 'reset' @buttons << Button.new(node['name'], node['value']) end end
def pretty_print(q)
def pretty_print(q) q.object_group(self) { q.breakable; q.group(1, '{name', '}') { q.breakable; q.pp name } q.breakable; q.group(1, '{method', '}') { q.breakable; q.pp method } q.breakable; q.group(1, '{action', '}') { q.breakable; q.pp action } q.breakable; q.group(1, '{fields', '}') { fields.each do |field| q.breakable q.pp field end } q.breakable; q.group(1, '{radiobuttons', '}') { radiobuttons.each { |b| q.breakable; q.pp b } } q.breakable; q.group(1, '{checkboxes', '}') { checkboxes.each { |b| q.breakable; q.pp b } } q.breakable; q.group(1, '{file_uploads', '}') { file_uploads.each { |b| q.breakable; q.pp b } } q.breakable; q.group(1, '{buttons', '}') { buttons.each { |b| q.breakable; q.pp b } } } end
def rand_string(len = 10)
def rand_string(len = 10) chars = ("a".."z").to_a + ("A".."Z").to_a string = "" 1.upto(len) { |i| string << chars[rand(chars.size-1)] } string end
def request_data
for this form, depending on if this is a regular post, get, or a
This method calculates the request data to be sent back to the server
def request_data query_params = build_query() case @enctype.downcase when /^multipart\/form-data/ boundary = rand_string(20) @enctype = "multipart/form-data; boundary=#{boundary}" params = [] query_params.each { |k,v| params << param_to_multipart(k, v) } @file_uploads.each { |f| params << file_to_multipart(f) } params.collect { |p| "--#{boundary}\r\n#{p}" }.join('') + "--#{boundary}--\r\n" else WWW::Mechanize::Util.build_query_string(query_params) end end
def set_fields(fields = {})
could do the following:
is zero based. For example, to set the second field named 'foo', you
the key as the index in to the form. The index
set the value of a duplicate field, use a value which is a Hash with
same name, this method will set the first one found. If you want to
name, value pairs. If there is more than one field found with the
This method sets multiple fields on the form. It takes a list of field
def set_fields(fields = {}) fields.each do |k,v| case v when Hash v.each do |index, value| self.fields_with(:name => k.to_s).[](index).value = value end else value = nil index = 0 [v].flatten.each do |val| index = val.to_i unless value.nil? value = val if value.nil? end self.fields_with(:name => k.to_s).[](index).value = value end end end
def submit(button=nil)
def submit(button=nil) @mech.submit(self, button) end
def values; fields.map { |f| f.value }; end
def values; fields.map { |f| f.value }; end