aai10-mechanize 2.0.1.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.
Files changed (176) hide show
  1. data/.autotest +6 -0
  2. data/.gitignore +9 -0
  3. data/CHANGELOG.rdoc +652 -0
  4. data/EXAMPLES.rdoc +187 -0
  5. data/FAQ.rdoc +11 -0
  6. data/GUIDE.rdoc +163 -0
  7. data/LICENSE.rdoc +20 -0
  8. data/Manifest.txt +172 -0
  9. data/README.rdoc +63 -0
  10. data/Rakefile +36 -0
  11. data/aai10-mechanize.gemspec +20 -0
  12. data/examples/flickr_upload.rb +22 -0
  13. data/examples/mech-dump.rb +5 -0
  14. data/examples/proxy_req.rb +7 -0
  15. data/examples/rubyforge.rb +20 -0
  16. data/examples/spider.rb +21 -0
  17. data/lib/mechanize.rb +664 -0
  18. data/lib/mechanize/content_type_error.rb +14 -0
  19. data/lib/mechanize/cookie.rb +116 -0
  20. data/lib/mechanize/cookie_jar.rb +202 -0
  21. data/lib/mechanize/element_matcher.rb +35 -0
  22. data/lib/mechanize/file.rb +80 -0
  23. data/lib/mechanize/file_connection.rb +17 -0
  24. data/lib/mechanize/file_request.rb +26 -0
  25. data/lib/mechanize/file_response.rb +74 -0
  26. data/lib/mechanize/file_saver.rb +37 -0
  27. data/lib/mechanize/form.rb +478 -0
  28. data/lib/mechanize/form/button.rb +9 -0
  29. data/lib/mechanize/form/check_box.rb +11 -0
  30. data/lib/mechanize/form/field.rb +44 -0
  31. data/lib/mechanize/form/file_upload.rb +23 -0
  32. data/lib/mechanize/form/image_button.rb +20 -0
  33. data/lib/mechanize/form/multi_select_list.rb +83 -0
  34. data/lib/mechanize/form/option.rb +49 -0
  35. data/lib/mechanize/form/radio_button.rb +48 -0
  36. data/lib/mechanize/form/select_list.rb +40 -0
  37. data/lib/mechanize/headers.rb +25 -0
  38. data/lib/mechanize/history.rb +83 -0
  39. data/lib/mechanize/http.rb +3 -0
  40. data/lib/mechanize/http/agent.rb +738 -0
  41. data/lib/mechanize/inspect.rb +88 -0
  42. data/lib/mechanize/monkey_patch.rb +37 -0
  43. data/lib/mechanize/page.rb +408 -0
  44. data/lib/mechanize/page/base.rb +8 -0
  45. data/lib/mechanize/page/frame.rb +27 -0
  46. data/lib/mechanize/page/image.rb +30 -0
  47. data/lib/mechanize/page/label.rb +20 -0
  48. data/lib/mechanize/page/link.rb +82 -0
  49. data/lib/mechanize/page/meta_refresh.rb +56 -0
  50. data/lib/mechanize/pluggable_parsers.rb +101 -0
  51. data/lib/mechanize/redirect_limit_reached_error.rb +16 -0
  52. data/lib/mechanize/redirect_not_get_or_head_error.rb +19 -0
  53. data/lib/mechanize/response_code_error.rb +22 -0
  54. data/lib/mechanize/response_read_error.rb +27 -0
  55. data/lib/mechanize/robots_disallowed_error.rb +29 -0
  56. data/lib/mechanize/unsupported_scheme_error.rb +8 -0
  57. data/lib/mechanize/util.rb +113 -0
  58. data/test/data/htpasswd +1 -0
  59. data/test/data/server.crt +16 -0
  60. data/test/data/server.csr +12 -0
  61. data/test/data/server.key +15 -0
  62. data/test/data/server.pem +15 -0
  63. data/test/helper.rb +175 -0
  64. data/test/htdocs/alt_text.html +10 -0
  65. data/test/htdocs/bad_form_test.html +9 -0
  66. data/test/htdocs/button.jpg +0 -0
  67. data/test/htdocs/canonical_uri.html +9 -0
  68. data/test/htdocs/dir with spaces/foo.html +1 -0
  69. data/test/htdocs/empty_form.html +6 -0
  70. data/test/htdocs/file_upload.html +26 -0
  71. data/test/htdocs/find_link.html +41 -0
  72. data/test/htdocs/form_multi_select.html +16 -0
  73. data/test/htdocs/form_multival.html +37 -0
  74. data/test/htdocs/form_no_action.html +18 -0
  75. data/test/htdocs/form_no_input_name.html +16 -0
  76. data/test/htdocs/form_select.html +16 -0
  77. data/test/htdocs/form_select_all.html +16 -0
  78. data/test/htdocs/form_select_none.html +17 -0
  79. data/test/htdocs/form_select_noopts.html +10 -0
  80. data/test/htdocs/form_set_fields.html +14 -0
  81. data/test/htdocs/form_test.html +188 -0
  82. data/test/htdocs/frame_referer_test.html +10 -0
  83. data/test/htdocs/frame_test.html +30 -0
  84. data/test/htdocs/google.html +13 -0
  85. data/test/htdocs/iframe_test.html +16 -0
  86. data/test/htdocs/index.html +6 -0
  87. data/test/htdocs/link with space.html +5 -0
  88. data/test/htdocs/meta_cookie.html +11 -0
  89. data/test/htdocs/no_title_test.html +6 -0
  90. data/test/htdocs/nofollow.html +9 -0
  91. data/test/htdocs/noindex.html +9 -0
  92. data/test/htdocs/norobots.html +8 -0
  93. data/test/htdocs/rails_3_encoding_hack_form_test.html +27 -0
  94. data/test/htdocs/rel_nofollow.html +8 -0
  95. data/test/htdocs/relative/tc_relative_links.html +21 -0
  96. data/test/htdocs/robots.html +8 -0
  97. data/test/htdocs/robots.txt +2 -0
  98. data/test/htdocs/tc_bad_charset.html +9 -0
  99. data/test/htdocs/tc_bad_links.html +5 -0
  100. data/test/htdocs/tc_base_images.html +10 -0
  101. data/test/htdocs/tc_base_link.html +8 -0
  102. data/test/htdocs/tc_blank_form.html +11 -0
  103. data/test/htdocs/tc_charset.html +6 -0
  104. data/test/htdocs/tc_checkboxes.html +19 -0
  105. data/test/htdocs/tc_encoded_links.html +5 -0
  106. data/test/htdocs/tc_field_precedence.html +11 -0
  107. data/test/htdocs/tc_follow_meta.html +8 -0
  108. data/test/htdocs/tc_form_action.html +48 -0
  109. data/test/htdocs/tc_images.html +8 -0
  110. data/test/htdocs/tc_links.html +18 -0
  111. data/test/htdocs/tc_meta_in_body.html +9 -0
  112. data/test/htdocs/tc_no_attributes.html +16 -0
  113. data/test/htdocs/tc_pretty_print.html +17 -0
  114. data/test/htdocs/tc_radiobuttons.html +17 -0
  115. data/test/htdocs/tc_referer.html +16 -0
  116. data/test/htdocs/tc_relative_links.html +19 -0
  117. data/test/htdocs/tc_textarea.html +23 -0
  118. data/test/htdocs/test_bad_encoding.html +52 -0
  119. data/test/htdocs/test_click.html +11 -0
  120. data/test/htdocs/unusual______.html +5 -0
  121. data/test/servlets.rb +402 -0
  122. data/test/ssl_server.rb +48 -0
  123. data/test/test_cookies.rb +129 -0
  124. data/test/test_form_action.rb +52 -0
  125. data/test/test_form_as_hash.rb +59 -0
  126. data/test/test_form_button.rb +46 -0
  127. data/test/test_frames.rb +34 -0
  128. data/test/test_headers.rb +33 -0
  129. data/test/test_history.rb +118 -0
  130. data/test/test_history_added.rb +16 -0
  131. data/test/test_html_unscape_forms.rb +46 -0
  132. data/test/test_if_modified_since.rb +20 -0
  133. data/test/test_images.rb +19 -0
  134. data/test/test_mechanize.rb +852 -0
  135. data/test/test_mechanize_cookie.rb +345 -0
  136. data/test/test_mechanize_cookie_jar.rb +433 -0
  137. data/test/test_mechanize_file.rb +53 -0
  138. data/test/test_mechanize_file_request.rb +19 -0
  139. data/test/test_mechanize_file_response.rb +21 -0
  140. data/test/test_mechanize_form.rb +576 -0
  141. data/test/test_mechanize_form_check_box.rb +37 -0
  142. data/test/test_mechanize_form_encoding.rb +120 -0
  143. data/test/test_mechanize_form_field.rb +21 -0
  144. data/test/test_mechanize_form_image_button.rb +12 -0
  145. data/test/test_mechanize_form_textarea.rb +51 -0
  146. data/test/test_mechanize_http_agent.rb +697 -0
  147. data/test/test_mechanize_link.rb +84 -0
  148. data/test/test_mechanize_page_encoding.rb +147 -0
  149. data/test/test_mechanize_page_link.rb +382 -0
  150. data/test/test_mechanize_page_meta_refresh.rb +115 -0
  151. data/test/test_mechanize_redirect_not_get_or_head_error.rb +18 -0
  152. data/test/test_mechanize_subclass.rb +22 -0
  153. data/test/test_mechanize_util.rb +92 -0
  154. data/test/test_multi_select.rb +118 -0
  155. data/test/test_no_attributes.rb +13 -0
  156. data/test/test_option.rb +18 -0
  157. data/test/test_pluggable_parser.rb +136 -0
  158. data/test/test_post_form.rb +37 -0
  159. data/test/test_pretty_print.rb +22 -0
  160. data/test/test_radiobutton.rb +75 -0
  161. data/test/test_redirect_limit_reached.rb +39 -0
  162. data/test/test_redirect_ok.rb +25 -0
  163. data/test/test_referer.rb +81 -0
  164. data/test/test_relative_links.rb +40 -0
  165. data/test/test_request.rb +13 -0
  166. data/test/test_response_code.rb +53 -0
  167. data/test/test_robots.rb +72 -0
  168. data/test/test_save_file.rb +48 -0
  169. data/test/test_scheme.rb +48 -0
  170. data/test/test_select.rb +119 -0
  171. data/test/test_select_all.rb +15 -0
  172. data/test/test_select_none.rb +15 -0
  173. data/test/test_select_noopts.rb +18 -0
  174. data/test/test_set_fields.rb +44 -0
  175. data/test/test_ssl_server.rb +20 -0
  176. metadata +360 -0
@@ -0,0 +1,9 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class represents a Submit button in a form.
4
+ class Button < Field ; end
5
+ class Submit < Button; end
6
+ class Reset < Button; end
7
+ end
8
+ end
9
+
@@ -0,0 +1,11 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class represents a check box found in a Form. To activate the
4
+ # CheckBox in the Form, set the checked method to true.
5
+ class CheckBox < RadioButton
6
+ def query_value
7
+ [[@name, @value || "on"]]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class represents a field in a form. It handles the following input
4
+ # tags found in a form:
5
+ # text, password, hidden, int, textarea
6
+ #
7
+ # To set the value of a field, just use the value method:
8
+ # field.value = "foo"
9
+ class Field
10
+ attr_accessor :name, :value, :node
11
+
12
+ def initialize node, value = node['value']
13
+ @node = node
14
+ @name = Util.html_unescape(node['name'])
15
+ @value = if value.is_a? String
16
+ Util.html_unescape(value)
17
+ else
18
+ value
19
+ end
20
+ end
21
+
22
+ def query_value
23
+ [[@name, @value || '']]
24
+ end
25
+
26
+ def <=> other
27
+ return 0 if self == other
28
+ return 1 if Hash === node
29
+ return -1 if Hash === other.node
30
+ node <=> other.node
31
+ end
32
+
33
+ # This method is a shortcut to get field's DOM id.
34
+ # Common usage: form.field_with(:dom_id => "foo")
35
+ def dom_id
36
+ node['id']
37
+ end
38
+ end
39
+
40
+ class Text < Field; end
41
+ class Textarea < Field; end
42
+ class Hidden < Field; end
43
+ end
44
+ end
@@ -0,0 +1,23 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class represents a file upload field found in a form. To use this
4
+ # class, set FileUpload#file_data= to the data of the file you want
5
+ # to upload and FileUpload#mime_type= to the appropriate mime type
6
+ # of the file.
7
+ # See the example in EXAMPLES[link://files/EXAMPLES_txt.html]
8
+ class FileUpload < Field
9
+ attr_accessor :file_name # File name
10
+ attr_accessor :mime_type # Mime Type (Optional)
11
+
12
+ alias :file_data :value
13
+ alias :file_data= :value=
14
+
15
+ def initialize node, file_name
16
+ @file_name = Util.html_unescape(file_name)
17
+ @file_data = nil
18
+ @node = node
19
+ super(node, @file_data)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,20 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class represents an image button in a form. Use the x and y methods
4
+ # to set the x and y positions for where the mouse "clicked".
5
+ class ImageButton < Button
6
+ attr_accessor :x, :y
7
+
8
+ def initialize *args
9
+ @x = nil
10
+ @y = nil
11
+ super
12
+ end
13
+
14
+ def query_value
15
+ [["#{@name}.x", (@x || 0).to_s],
16
+ ["#{@name}.y", (@y || 0).to_s]]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,83 @@
1
+ # This class represents a select list where multiple values can be selected.
2
+ # MultiSelectList#value= accepts an array, and those values are used as
3
+ # values for the select list. For example, to select multiple values,
4
+ # simply do this:
5
+ #
6
+ # list.value = ['one', 'two']
7
+ #
8
+ # Single values are still supported, so these two are the same:
9
+ #
10
+ # list.value = ['one']
11
+ # list.value = 'one'
12
+ class Mechanize::Form::MultiSelectList < Mechanize::Form::Field
13
+ extend Mechanize::ElementMatcher
14
+
15
+ attr_accessor :options
16
+
17
+ def initialize node
18
+ value = []
19
+ @options = []
20
+
21
+ # parse
22
+ node.search('option').each do |n|
23
+ option = Mechanize::Form::Option.new(n, self)
24
+ @options << option
25
+ end
26
+ super(node, value)
27
+ end
28
+
29
+ ##
30
+ # Find one option on this select list with +criteria+
31
+ # Example:
32
+ # select_list.option_with(:value => '1').value = 'foo'
33
+
34
+ ##
35
+ # Find all options on this select list with +criteria+
36
+ # Example:
37
+ # select_list.options_with(:value => /1|2/).each do |field|
38
+ # field.value = '20'
39
+ # end
40
+
41
+ elements_with :option
42
+
43
+ def query_value
44
+ value ? value.collect { |v| [name, v] } : ''
45
+ end
46
+
47
+ # Select no options
48
+ def select_none
49
+ @value = []
50
+ options.each { |o| o.untick }
51
+ end
52
+
53
+ # Select all options
54
+ def select_all
55
+ @value = []
56
+ options.each { |o| o.tick }
57
+ end
58
+
59
+ # Get a list of all selected options
60
+ def selected_options
61
+ @options.find_all { |o| o.selected? }
62
+ end
63
+
64
+ def value=(values)
65
+ select_none
66
+ [values].flatten.each do |value|
67
+ option = options.find { |o| o.value == value }
68
+ if option.nil?
69
+ @value.push(value)
70
+ else
71
+ option.select
72
+ end
73
+ end
74
+ end
75
+
76
+ def value
77
+ value = []
78
+ value.push(*@value)
79
+ value.push(*selected_options.collect { |o| o.value })
80
+ value
81
+ end
82
+
83
+ end
@@ -0,0 +1,49 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class contains option an option found within SelectList. A
4
+ # SelectList can have many Option classes associated with it. An option
5
+ # can be selected by calling Option#tick, or Option#click. For example,
6
+ # select the first option in a list:
7
+ # select_list.first.tick
8
+ class Option
9
+ attr_reader :value, :selected, :text, :select_list
10
+
11
+ alias :to_s :value
12
+ alias :selected? :selected
13
+
14
+ def initialize(node, select_list)
15
+ @text = node.inner_text
16
+ @value = Util.html_unescape(node['value'] || node.inner_text)
17
+ @selected = node.has_attribute? 'selected'
18
+ @select_list = select_list # The select list this option belongs to
19
+ end
20
+
21
+ # Select this option
22
+ def select
23
+ unselect_peers
24
+ @selected = true
25
+ end
26
+
27
+ # Unselect this option
28
+ def unselect
29
+ @selected = false
30
+ end
31
+
32
+ alias :tick :select
33
+ alias :untick :unselect
34
+
35
+ # Toggle the selection value of this option
36
+ def click
37
+ unselect_peers
38
+ @selected = !@selected
39
+ end
40
+
41
+ private
42
+ def unselect_peers
43
+ if @select_list.instance_of? SelectList
44
+ @select_list.select_none
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,48 @@
1
+ class Mechanize
2
+ class Form
3
+ # This class represents a radio button found in a Form. To activate the
4
+ # RadioButton in the Form, set the checked method to true.
5
+ class RadioButton < Field
6
+ attr_accessor :checked
7
+
8
+ def initialize node, form
9
+ @checked = !!node['checked']
10
+ @form = form
11
+ super(node)
12
+ end
13
+
14
+ def check
15
+ uncheck_peers
16
+ @checked = true
17
+ end
18
+
19
+ def uncheck
20
+ @checked = false
21
+ end
22
+
23
+ def click
24
+ checked ? uncheck : check
25
+ end
26
+
27
+ def label
28
+ (id = self['id']) && @form.page.labels_hash[id] || nil
29
+ end
30
+
31
+ def text
32
+ label.text rescue nil
33
+ end
34
+
35
+ def [](key)
36
+ @node[key]
37
+ end
38
+
39
+ private
40
+ def uncheck_peers
41
+ @form.radiobuttons_with(:name => name).each do |b|
42
+ next if b.value == value
43
+ b.uncheck
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,40 @@
1
+ # This class represents a select list or drop down box in a Form. Set the
2
+ # value for the list by calling SelectList#value=. SelectList contains a
3
+ # list of Option that were found. After finding the correct option, set
4
+ # the select lists value to the option value:
5
+ # selectlist.value = selectlist.options.first.value
6
+ # Options can also be selected by "clicking" or selecting them. See Option
7
+ class Mechanize::Form::SelectList < Mechanize::Form::MultiSelectList
8
+ def initialize node
9
+ super
10
+ if selected_options.length > 1
11
+ selected_options.reverse[1..selected_options.length].each do |o|
12
+ o.unselect
13
+ end
14
+ end
15
+ end
16
+
17
+ def value
18
+ value = super
19
+ if value.length > 0
20
+ value.last
21
+ elsif @options.length > 0
22
+ @options.first.value
23
+ else
24
+ nil
25
+ end
26
+ end
27
+
28
+ def value=(new)
29
+ if new != new.to_s and new.respond_to? :first
30
+ super([new.first])
31
+ else
32
+ super([new.to_s])
33
+ end
34
+ end
35
+
36
+ def query_value
37
+ value ? [[name, value]] : nil
38
+ end
39
+ end
40
+
@@ -0,0 +1,25 @@
1
+ class Mechanize
2
+ class Headers < Hash
3
+ def [](key)
4
+ super(key.downcase)
5
+ end
6
+
7
+ def []=(key, value)
8
+ super(key.downcase, value)
9
+ end
10
+
11
+ def key?(key)
12
+ super(key.downcase)
13
+ end
14
+
15
+ def canonical_each
16
+ block_given? or return enum_for(__method__)
17
+ each { |key, value|
18
+ key = key.capitalize
19
+ key.gsub!(/-([a-z])/) { "-#{$1.upcase}" }
20
+ yield [key, value]
21
+ }
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,83 @@
1
+ class Mechanize
2
+ ##
3
+ # This class manages history for your mechanize object.
4
+ class History < Array
5
+ attr_accessor :max_size
6
+
7
+ def initialize(max_size = nil)
8
+ @max_size = max_size
9
+ @history_index = {}
10
+ end
11
+
12
+ def initialize_copy(orig)
13
+ super
14
+ @history_index = orig.instance_variable_get(:@history_index).dup
15
+ end
16
+
17
+ def inspect # :nodoc:
18
+ uris = map { |page| page.uri }.join ', '
19
+
20
+ "[#{uris}]"
21
+ end
22
+
23
+ def push(page, uri = nil)
24
+ super(page)
25
+
26
+ @history_index[(uri ? uri : page.uri).to_s] = page
27
+
28
+ if @max_size && self.length > @max_size
29
+ while self.length > @max_size
30
+ self.shift
31
+ end
32
+ end
33
+
34
+ self
35
+ end
36
+ alias :<< :push
37
+
38
+ def visited_page(uri)
39
+ page = @history_index[uri.to_s]
40
+
41
+ return page if page # HACK
42
+
43
+ uri = uri.dup
44
+ uri.path = '/' if uri.path.empty?
45
+
46
+ @history_index[uri.to_s]
47
+ end
48
+
49
+ alias visited? visited_page
50
+
51
+ def clear
52
+ @history_index.clear
53
+ super
54
+ end
55
+
56
+ def shift
57
+ return nil if length == 0
58
+ page = self[0]
59
+ self[0] = nil
60
+
61
+ super
62
+
63
+ remove_from_index(page)
64
+ page
65
+ end
66
+
67
+ def pop
68
+ return nil if length == 0
69
+ page = super
70
+ remove_from_index(page)
71
+ page
72
+ end
73
+
74
+ private
75
+
76
+ def remove_from_index(page)
77
+ @history_index.each do |k,v|
78
+ @history_index.delete(k) if v == page
79
+ end
80
+ end
81
+
82
+ end
83
+ end