Class: Mechanize::Form

Inherits:
Object
  • Object
show all
Extended by:
ElementMatcher
Defined in:
lib/mechanize/form.rb

Overview

This class encapsulates a form parsed out of an HTML page. Each type of input fields available in a form can be accessed through this object.

Examples

Find a form and print out its fields

form = page.forms.first # => Mechanize::Form
form.fields.each { |f| puts f.name }

Set the input field ‘name’ to “Aaron”

form['name'] = 'Aaron'
puts form['name']

Defined Under Namespace

Classes: Button, CheckBox, Field, FileUpload, Hidden, ImageButton, Keygen, MultiSelectList, Option, RadioButton, Reset, SelectList, Submit, Text, Textarea

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from ElementMatcher

elements_with

Constructor Details

#initialize(node, mech = nil, page = nil) ⇒ Form

Returns a new instance of Form.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/mechanize/form.rb', line 41

def initialize(node, mech=nil, page=nil)
  @enctype = node['enctype'] || 'application/x-www-form-urlencoded'
  @form_node        = node
  @action           = Mechanize::Util.html_unescape(node['action'])
  @method           = (node['method'] || 'GET').upcase
  @name             = node['name']
  @clicked_buttons  = []
  @page             = page
  @mech             = mech

  @encoding = node['accept-charset'] || (page && page.encoding) || nil
  @ignore_encoding_error = false
  parse
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args) ⇒ Object

Treat form fields like accessors.



165
166
167
168
169
170
171
172
173
174
# File 'lib/mechanize/form.rb', line 165

def method_missing(meth, *args)
  method = meth.to_s.gsub(/=$/, '')

  if field(method)
    return field(method).value if args.empty?
    return field(method).value = args[0]
  end

  super
end

Instance Attribute Details

#actionObject

Returns the value of attribute action.



22
23
24
# File 'lib/mechanize/form.rb', line 22

def action
  @action
end

#buttonsObject (readonly)

Returns the value of attribute buttons.



24
25
26
# File 'lib/mechanize/form.rb', line 24

def buttons
  @buttons
end

#checkboxesObject (readonly)

Returns the value of attribute checkboxes.



24
25
26
# File 'lib/mechanize/form.rb', line 24

def checkboxes
  @checkboxes
end

#encodingObject

Character encoding of form data (i.e. UTF-8)



30
31
32
# File 'lib/mechanize/form.rb', line 30

def encoding
  @encoding
end

#enctypeObject

Content-Type for form data (i.e. application/x-www-form-urlencoded)



27
28
29
# File 'lib/mechanize/form.rb', line 27

def enctype
  @enctype
end

#fieldsObject (readonly) Also known as: elements

Returns the value of attribute fields.



24
25
26
# File 'lib/mechanize/form.rb', line 24

def fields
  @fields
end

#file_uploadsObject (readonly)

Returns the value of attribute file_uploads.



24
25
26
# File 'lib/mechanize/form.rb', line 24

def file_uploads
  @file_uploads
end

#form_nodeObject (readonly)

Returns the value of attribute form_node.



38
39
40
# File 'lib/mechanize/form.rb', line 38

def form_node
  @form_node
end

#ignore_encoding_errorObject

When true, character encoding errors will never be never raised on form submission. Default is false



34
35
36
# File 'lib/mechanize/form.rb', line 34

def ignore_encoding_error
  @ignore_encoding_error
end

#methodObject

Returns the value of attribute method.



22
23
24
# File 'lib/mechanize/form.rb', line 22

def method
  @method
end

#nameObject

Returns the value of attribute name.



22
23
24
# File 'lib/mechanize/form.rb', line 22

def name
  @name
end

#pageObject (readonly)

Returns the value of attribute page.



39
40
41
# File 'lib/mechanize/form.rb', line 39

def page
  @page
end

#radiobuttonsObject (readonly)

Returns the value of attribute radiobuttons.



24
25
26
# File 'lib/mechanize/form.rb', line 24

def radiobuttons
  @radiobuttons
end

Instance Method Details

#[](field_name) ⇒ Object

Fetch the value of the first input field with the name passed in

Example

Fetch the value set in the input field ‘name’

puts form['name']


146
147
148
149
# File 'lib/mechanize/form.rb', line 146

def [](field_name)
  f = field(field_name)
  f && f.value
end

#[]=(field_name, value) ⇒ Object

Set the value of the first input field with the name passed in

Example

Set the value in the input field ‘name’ to “Aaron”

form['name'] = 'Aaron'


155
156
157
158
159
160
161
162
# File 'lib/mechanize/form.rb', line 155

def []=(field_name, value)
  f = field(field_name)
  if f
    f.value = value
  else
    add_field!(field_name, value)
  end
end

#add_button_to_query(button) ⇒ Object

This method adds a button to the query. If the form needs to be submitted with multiple buttons, pass each button to this method.



257
258
259
# File 'lib/mechanize/form.rb', line 257

def add_button_to_query(button)
  @clicked_buttons << button
end

#add_field!(field_name, value = nil) ⇒ Object

Add a field with field_name and value



103
104
105
# File 'lib/mechanize/form.rb', line 103

def add_field!(field_name, value = nil)
  fields << Field.new({'name' => field_name}, value)
end

#build_query(buttons = []) ⇒ Object

This method builds an array of arrays that represent the query parameters to be used with this form. The return value can then be used to create a query string for this form.



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# File 'lib/mechanize/form.rb', line 206

def build_query(buttons = [])
  query = []
  @mech.log.info("form encoding: #{encoding}") if @mech && @mech.log

  successful_controls = []

  (fields + checkboxes).sort.each do |f|
    case f
    when Mechanize::Form::CheckBox
      if f.checked
        successful_controls << f
      end
    when Mechanize::Form::Field
      successful_controls << f
    end
  end

  radio_groups = {}
  radiobuttons.each do |f|
    fname = from_native_charset(f.name)
    radio_groups[fname] ||= []
    radio_groups[fname] << 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
      successful_controls << f
    elsif checked.size > 1
      raise Mechanize::Error,
            "multiple radiobuttons are checked in the same group!"
    end
  end

  @clicked_buttons.each { |b|
    successful_controls << b
  }

  successful_controls.sort.each do |ctrl| # DOM order
    qval = proc_query(ctrl)
    query.push(*qval)
  end

  query
end

#buttonObject

:method: buttons_with(criteria)

Find all buttons that match criteria Example:

form.buttons_with(:value => /submit/).each do |button|
  button.value = 'hello!'
end


327
# File 'lib/mechanize/form.rb', line 327

elements_with :button

#checkboxObject

:method: checkboxes_with(criteria)

Find all checkboxes that match criteria Example:

form.checkboxes_with(:name => /woo/).each do |field|
  field.check
end


381
# File 'lib/mechanize/form.rb', line 381

elements_with :checkbox,   :checkboxes

#click_button(button = buttons.first) ⇒ Object

Submit form using button. Defaults to the first button.



183
184
185
# File 'lib/mechanize/form.rb', line 183

def click_button(button = buttons.first)
  submit(button)
end

#delete_field!(field_name) ⇒ Object

Removes all fields with name field_name.



289
290
291
# File 'lib/mechanize/form.rb', line 289

def delete_field!(field_name)
  @fields.delete_if{ |f| f.name == field_name}
end

#dom_classObject

This method is a shortcut to get form’s DOM class. Common usage:

page.form_with(:dom_class => "foorm")

Note that you can also use :class to get to this method:

page.form_with(:class => "foorm")


98
99
100
# File 'lib/mechanize/form.rb', line 98

def dom_class
  form_node['class']
end

#dom_idObject

This method is a shortcut to get form’s DOM id. Common usage:

page.form_with(:dom_id => "foorm")

Note that you can also use :id to get to this method:

page.form_with(:id => "foorm")


89
90
91
# File 'lib/mechanize/form.rb', line 89

def dom_id
  form_node['id']
end

#fieldObject

:method: fields_with(criteria)

Find all fields that match criteria Example:

form.fields_with(:value => /foo/).each do |field|
  field.value = 'hello!'
end


309
# File 'lib/mechanize/form.rb', line 309

elements_with :field

#file_uploadObject

:method: file_uploads_with(criteria)

Find all file upload fields that match criteria Example:

form.file_uploads_with(:file_name => /picutre/).each do |field|
  field.value = 'foo!'
end


345
# File 'lib/mechanize/form.rb', line 345

elements_with :file_upload

#has_field?(field_name) ⇒ Boolean Also known as: has_key?

Returns whether or not the form contains a field with field_name

Returns:

  • (Boolean)


57
58
59
# File 'lib/mechanize/form.rb', line 57

def has_field?(field_name)
  fields.find { |f| f.name == field_name }
end

#has_value?(value) ⇒ Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/mechanize/form.rb', line 63

def has_value?(value)
  fields.find { |f| f.value == value }
end

#hidden_field?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


81
# File 'lib/mechanize/form.rb', line 81

def hidden_field?(field_name)     hiddens.find{|f| f.name == field_name}; end

#hiddensObject



74
# File 'lib/mechanize/form.rb', line 74

def hiddens  ; @hiddens   ||=  fields.select { |f| f.class == Hidden   }; end

#keygensObject



76
# File 'lib/mechanize/form.rb', line 76

def keygens  ; @keygens   ||=  fields.select { |f| f.class == Keygen   }; end

#keysObject



67
# File 'lib/mechanize/form.rb', line 67

def keys; fields.map { |f| f.name }; end

#pretty_print(q) ⇒ Object

:nodoc:



383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/mechanize/form.rb', line 383

def pretty_print(q) # :nodoc:
  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

#radiobuttonObject

:method: radiobuttons_with(criteria)

Find all radio buttons that match criteria Example:

form.radiobuttons_with(:name => /woo/).each do |field|
  field.check
end


363
# File 'lib/mechanize/form.rb', line 363

elements_with :radiobutton

#request_dataObject

This method calculates the request data to be sent back to the server for this form, depending on if this is a regular post, get, or a multi-part post,



264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/mechanize/form.rb', line 264

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.map do |k,v|
      param_to_multipart(k, v) if k
    end.compact

    params.concat @file_uploads.map { |f| file_to_multipart(f) }

    params.map do |part|
      part.force_encoding('ASCII-8BIT') if part.respond_to? :force_encoding
      "--#{boundary}\r\n#{part}"
    end.join('') +
      "--#{boundary}--\r\n"
  else
    Mechanize::Util.build_query_string(query_params)
  end
end

#reset_button?(button_name) ⇒ Boolean

Returns:

  • (Boolean)


79
# File 'lib/mechanize/form.rb', line 79

def reset_button?(button_name)     resets.find{|f| f.name == button_name}; end

#resetsObject



72
# File 'lib/mechanize/form.rb', line 72

def resets   ; @resets    ||= buttons.select { |f| f.class == Reset    }; end

#set_fields(fields = {}) ⇒ Object

This method sets multiple fields on the form. It takes a list of fields which are name, value pairs.

If there is more than one field found with the same name, this method will set the first one found. If you want to set the value of a duplicate field, use a value which is a Hash with the key as the index in to the form. The index is zero based.

For example, to set the second field named ‘foo’, you could do the following:

form.set_fields :foo => { 1 => 'bar' }


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/mechanize/form.rb', line 121

def set_fields fields = {}
  fields.each do |name, v|
    case v
    when Hash
      v.each do |index, value|
        self.fields_with(:name => name.to_s)[index].value = value
      end
    else
      value = nil
      index = 0

      [v].flatten.each do |val|
        index = val.to_i if value
        value = val unless value
      end

      self.fields_with(:name => name.to_s)[index].value = value
    end
  end
end

#submit(button = nil, headers = {}) ⇒ Object

Submit this form with the button passed in



177
178
179
# File 'lib/mechanize/form.rb', line 177

def submit button=nil, headers = {}
  @mech.submit(self, button, headers)
end

#submit_button?(button_name) ⇒ Boolean

Returns:

  • (Boolean)


78
# File 'lib/mechanize/form.rb', line 78

def submit_button?(button_name)   submits.find{|f| f.name == button_name}; end

#submitsObject



71
# File 'lib/mechanize/form.rb', line 71

def submits  ; @submits   ||= buttons.select { |f| f.class == Submit   }; end

#text_field?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


80
# File 'lib/mechanize/form.rb', line 80

def text_field?(field_name)         texts.find{|f| f.name == field_name}; end

#textarea_field?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


82
# File 'lib/mechanize/form.rb', line 82

def textarea_field?(field_name) textareas.find{|f| f.name == field_name}; end

#textareasObject



75
# File 'lib/mechanize/form.rb', line 75

def textareas; @textareas ||=  fields.select { |f| f.class == Textarea }; end

#textsObject



73
# File 'lib/mechanize/form.rb', line 73

def texts    ; @texts     ||=  fields.select { |f| f.class == Text     }; end

#valuesObject



69
# File 'lib/mechanize/form.rb', line 69

def values; fields.map { |f| f.value }; end