mechanize 1.0.1.beta.20110107104205 → 2.0.pre.1

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.

Files changed (89) hide show
  1. data.tar.gz.sig +2 -0
  2. data/{lib/mechanize/chain/post_connect_hook.rb → .gemtest} +0 -0
  3. data/CHANGELOG.rdoc +51 -6
  4. data/EXAMPLES.rdoc +5 -3
  5. data/GUIDE.rdoc +72 -32
  6. data/LICENSE.rdoc +20 -340
  7. data/Manifest.txt +20 -27
  8. data/README.rdoc +12 -9
  9. data/Rakefile +5 -2
  10. data/examples/spider.rb +13 -2
  11. data/lib/mechanize.rb +545 -267
  12. data/lib/mechanize/content_type_error.rb +1 -1
  13. data/lib/mechanize/cookie.rb +72 -65
  14. data/lib/mechanize/cookie_jar.rb +197 -148
  15. data/lib/mechanize/element_matcher.rb +35 -0
  16. data/lib/mechanize/file.rb +3 -1
  17. data/lib/mechanize/file_connection.rb +17 -0
  18. data/lib/mechanize/file_request.rb +26 -0
  19. data/lib/mechanize/file_response.rb +61 -47
  20. data/lib/mechanize/form.rb +57 -58
  21. data/lib/mechanize/form/image_button.rb +2 -3
  22. data/lib/mechanize/form/multi_select_list.rb +71 -55
  23. data/lib/mechanize/form/select_list.rb +34 -62
  24. data/lib/mechanize/monkey_patch.rb +13 -11
  25. data/lib/mechanize/page.rb +277 -270
  26. data/lib/mechanize/page/image.rb +6 -2
  27. data/lib/mechanize/redirect_limit_reached_error.rb +1 -1
  28. data/lib/mechanize/redirect_not_get_or_head_error.rb +1 -1
  29. data/lib/mechanize/response_code_error.rb +3 -3
  30. data/lib/mechanize/unsupported_scheme_error.rb +1 -1
  31. data/lib/mechanize/uri_resolver.rb +82 -0
  32. data/lib/mechanize/util.rb +76 -60
  33. data/test/helper.rb +35 -5
  34. data/test/htdocs/dir with spaces/foo.html +1 -0
  35. data/test/htdocs/rails_3_encoding_hack_form_test.html +27 -0
  36. data/test/htdocs/tc_base_images.html +10 -0
  37. data/test/htdocs/tc_images.html +8 -0
  38. data/test/htdocs/test_click.html +11 -0
  39. data/test/servlets.rb +3 -2
  40. data/test/test_authenticate.rb +5 -5
  41. data/test/test_errors.rb +8 -8
  42. data/test/test_follow_meta.rb +4 -4
  43. data/test/test_form_as_hash.rb +4 -4
  44. data/test/test_forms.rb +3 -7
  45. data/test/test_hash_api.rb +2 -2
  46. data/test/test_headers.rb +1 -1
  47. data/test/test_images.rb +19 -0
  48. data/test/test_mech.rb +6 -6
  49. data/test/test_mechanize.rb +687 -0
  50. data/test/{test_cookie_class.rb → test_mechanize_cookie.rb} +52 -45
  51. data/test/test_mechanize_cookie_jar.rb +400 -0
  52. data/test/test_mechanize_file.rb +7 -1
  53. data/test/test_mechanize_file_request.rb +19 -0
  54. data/test/test_mechanize_file_response.rb +21 -0
  55. data/test/test_mechanize_form_image_button.rb +12 -0
  56. data/test/test_mechanize_page.rb +165 -0
  57. data/test/test_mechanize_uri_resolver.rb +29 -0
  58. data/test/{test_util.rb → test_mechanize_util.rb} +1 -1
  59. data/test/test_multi_select.rb +12 -0
  60. data/test/test_post_form.rb +7 -0
  61. data/test/test_redirect_verb_handling.rb +6 -6
  62. data/test/test_scheme.rb +0 -7
  63. data/test/test_verbs.rb +3 -3
  64. metadata +106 -72
  65. metadata.gz.sig +0 -0
  66. data/lib/mechanize/chain.rb +0 -36
  67. data/lib/mechanize/chain/auth_headers.rb +0 -78
  68. data/lib/mechanize/chain/body_decoding_handler.rb +0 -50
  69. data/lib/mechanize/chain/connection_resolver.rb +0 -28
  70. data/lib/mechanize/chain/custom_headers.rb +0 -21
  71. data/lib/mechanize/chain/handler.rb +0 -9
  72. data/lib/mechanize/chain/header_resolver.rb +0 -48
  73. data/lib/mechanize/chain/parameter_resolver.rb +0 -22
  74. data/lib/mechanize/chain/pre_connect_hook.rb +0 -20
  75. data/lib/mechanize/chain/request_resolver.rb +0 -31
  76. data/lib/mechanize/chain/response_body_parser.rb +0 -36
  77. data/lib/mechanize/chain/response_header_handler.rb +0 -34
  78. data/lib/mechanize/chain/response_reader.rb +0 -39
  79. data/lib/mechanize/chain/ssl_resolver.rb +0 -40
  80. data/lib/mechanize/chain/uri_resolver.rb +0 -75
  81. data/test/chain/test_argument_validator.rb +0 -14
  82. data/test/chain/test_auth_headers.rb +0 -25
  83. data/test/chain/test_custom_headers.rb +0 -18
  84. data/test/chain/test_header_resolver.rb +0 -27
  85. data/test/chain/test_parameter_resolver.rb +0 -35
  86. data/test/chain/test_request_resolver.rb +0 -29
  87. data/test/chain/test_response_reader.rb +0 -24
  88. data/test/test_cookie_jar.rb +0 -324
  89. data/test/test_page.rb +0 -124
@@ -12,9 +12,8 @@ class Mechanize
12
12
  end
13
13
 
14
14
  def query_value
15
- super <<
16
- [@name + ".x", (@x || 0).to_s] <<
17
- [@name + ".y", (@y || 0).to_s]
15
+ [["#{@name}.x", (@x || 0).to_s],
16
+ ["#{@name}.y", (@y || 0).to_s]]
18
17
  end
19
18
  end
20
19
  end
@@ -1,67 +1,83 @@
1
- class Mechanize
2
- class Form
3
- # This class represents a select list where multiple values can be selected.
4
- # MultiSelectList#value= accepts an array, and those values are used as
5
- # values for the select list. For example, to select multiple values,
6
- # simply do this:
7
- # list.value = ['one', 'two']
8
- # Single values are still supported, so these two are the same:
9
- # list.value = ['one']
10
- # list.value = 'one'
11
- class MultiSelectList < Field
12
- attr_accessor :options
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
13
14
 
14
- def initialize node
15
- value = []
16
- @options = []
15
+ attr_accessor :options
17
16
 
18
- # parse
19
- node.search('option').each do |n|
20
- option = Option.new(n, self)
21
- @options << option
22
- end
23
- super(node, value)
24
- end
17
+ def initialize node
18
+ value = []
19
+ @options = []
25
20
 
26
- def query_value
27
- value ? value.collect { |v| [name, v] } : ''
28
- end
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
29
28
 
30
- # Select no options
31
- def select_none
32
- @value = []
33
- options.each { |o| o.untick }
34
- end
29
+ ##
30
+ # Find one option on this select list with +criteria+
31
+ # Example:
32
+ # select_list.option_with(:value => '1').value = 'foo'
35
33
 
36
- # Select all options
37
- def select_all
38
- @value = []
39
- options.each { |o| o.tick }
40
- end
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
41
40
 
42
- # Get a list of all selected options
43
- def selected_options
44
- @options.find_all { |o| o.selected? }
45
- end
41
+ elements_with :option
46
42
 
47
- def value=(values)
48
- select_none
49
- [values].flatten.each do |value|
50
- option = options.find { |o| o.value == value }
51
- if option.nil?
52
- @value.push(value)
53
- else
54
- option.select
55
- end
56
- end
57
- end
43
+ def query_value
44
+ value ? value.collect { |v| [name, v] } : ''
45
+ end
58
46
 
59
- def value
60
- value = []
61
- value.push(*@value)
62
- value.push(*selected_options.collect { |o| o.value })
63
- value
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
64
72
  end
65
73
  end
66
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
+
67
83
  end
@@ -1,68 +1,40 @@
1
- class Mechanize
2
- class Form
3
- # This class represents a select list or drop down box in a Form. Set the
4
- # value for the list by calling SelectList#value=. SelectList contains a
5
- # list of Option that were found. After finding the correct option, set
6
- # the select lists value to the option value:
7
- # selectlist.value = selectlist.options.first.value
8
- # Options can also be selected by "clicking" or selecting them. See Option
9
- class SelectList < MultiSelectList
10
- def initialize node
11
- super
12
- if selected_options.length > 1
13
- selected_options.reverse[1..selected_options.length].each do |o|
14
- o.unselect
15
- end
16
- end
17
- end
18
-
19
- ##
20
- # Find all options on this select list with +criteria+
21
- # Example:
22
- # select_list.options_with(:value => /1|2/).each do |field|
23
- # field.value = '20'
24
- # end
25
- def options_with criteria
26
- criteria = {:name => criteria} if String === criteria
27
- f = @options.find_all do |thing|
28
- criteria.all? { |k,v| v === thing.send(k) }
29
- end
30
- yield f if block_given?
31
- f
32
- end
33
-
34
- ##
35
- # Find one option on this select list with +criteria+
36
- # Example:
37
- # select_list.option_with(:value => '1').value = 'foo'
38
- def option_with criteria
39
- f = options_with(criteria).first
40
- yield f if block_given?
41
- f
42
- end
43
-
44
- def value
45
- value = super
46
- if value.length > 0
47
- value.last
48
- elsif @options.length > 0
49
- @options.first.value
50
- else
51
- nil
52
- end
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
53
13
  end
14
+ end
15
+ end
54
16
 
55
- def value=(new)
56
- if new != new.to_s and new.respond_to? :first
57
- super([new.first])
58
- else
59
- super([new.to_s])
60
- end
61
- end
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
62
27
 
63
- def query_value
64
- value ? [[name, value]] : nil
65
- end
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])
66
33
  end
67
34
  end
35
+
36
+ def query_value
37
+ value ? [[name, value]] : nil
38
+ end
68
39
  end
40
+
@@ -1,14 +1,16 @@
1
- module Net
2
- class HTTP
3
- alias :old_keep_alive? :keep_alive?
4
- def keep_alive?(req, res)
5
- return false if /close/i =~ req['connection'].to_s
6
- return false if @seems_1_0_server
7
- return false if /close/i =~ res['connection'].to_s
8
- return true if /keep-alive/i =~ res['connection'].to_s
9
- return false if /close/i =~ res['proxy-connection'].to_s
10
- return true if /keep-alive/i =~ res['proxy-connection'].to_s
11
- (@curr_http_version == '1.1')
1
+ if RUBY_VERSION < '1.9' then
2
+ module Net
3
+ class HTTP
4
+ alias :old_keep_alive? :keep_alive?
5
+ def keep_alive?(req, res)
6
+ return false if /close/i =~ req['connection'].to_s
7
+ return false if @seems_1_0_server
8
+ return false if /close/i =~ res['connection'].to_s
9
+ return true if /keep-alive/i =~ res['connection'].to_s
10
+ return false if /close/i =~ res['proxy-connection'].to_s
11
+ return true if /keep-alive/i =~ res['proxy-connection'].to_s
12
+ (@curr_http_version == '1.1')
13
+ end
12
14
  end
13
15
  end
14
16
  end
@@ -1,313 +1,320 @@
1
- require 'mechanize/page/link'
2
- require 'mechanize/page/meta'
3
- require 'mechanize/page/base'
4
- require 'mechanize/page/frame'
5
- require 'mechanize/page/image'
6
- require 'mechanize/page/label'
7
- require 'mechanize/headers'
1
+ # = Synopsis
2
+ # This class encapsulates an HTML page. If Mechanize finds a content
3
+ # type of 'text/html', this class will be instantiated and returned.
4
+ #
5
+ # == Example
6
+ # require 'rubygems'
7
+ # require 'mechanize'
8
+ #
9
+ # agent = Mechanize.new
10
+ # agent.get('http://google.com/').class #=> Mechanize::Page
11
+ #
12
+ class Mechanize::Page < Mechanize::File
13
+ extend Forwardable
14
+ extend Mechanize::ElementMatcher
15
+
16
+ attr_accessor :mech
17
+
18
+ def initialize(uri=nil, response=nil, body=nil, code=nil, mech=nil)
19
+ raise Mechanize::ContentTypeError, response['content-type'] unless
20
+ response['content-type'] =~ /^(text\/html)|(application\/xhtml\+xml)/i
21
+
22
+ @bases = nil
23
+ @encoding = nil
24
+ @encodings = [nil]
25
+ @forms = nil
26
+ @frames = nil
27
+ @iframes = nil
28
+ @links = nil
29
+ @mech = mech
30
+ @meta = nil
31
+ @parser = nil
32
+
33
+ @encodings << Mechanize::Util.detect_charset(body) if body
34
+
35
+ response.each do |header, value|
36
+ next unless value =~ /charset/i
37
+ @encodings << charset(value)
38
+ end
8
39
 
9
- class Mechanize
10
- # = Synopsis
11
- # This class encapsulates an HTML page. If Mechanize finds a content
12
- # type of 'text/html', this class will be instantiated and returned.
13
- #
14
- # == Example
15
- # require 'rubygems'
16
- # require 'mechanize'
17
- #
18
- # agent = Mechanize.new
19
- # agent.get('http://google.com/').class #=> Mechanize::Page
20
- #
21
- class Page < Mechanize::File
22
- extend Forwardable
40
+ if body
41
+ # Force the encoding to be 8BIT so we can perform regular expressions.
42
+ # We'll set it to the detected encoding later
43
+ body.force_encoding('ASCII-8BIT') if body.respond_to?(:force_encoding)
44
+
45
+ body.scan(/<meta .*?>/i) do |meta|
46
+ next unless meta =~ /http-equiv\s*=\s*(["'])?content-type\1/i
23
47
 
24
- attr_accessor :mech
48
+ meta =~ /content=(["'])?(.*?)\1/i
25
49
 
26
- def initialize(uri=nil, response=nil, body=nil, code=nil, mech=nil)
27
- @encoding = nil
50
+ encoding = charset $2
28
51
 
29
- method = response.respond_to?(:each_header) ? :each_header : :each
30
- response.send(method) do |header,v|
31
- next unless v =~ /charset/i
32
- encoding = v[/charset=([^; ]+)/, 1]
33
- @encoding = encoding unless encoding == 'none'
52
+ @encodings << encoding if encoding
34
53
  end
54
+ end
35
55
 
36
- # Force the encoding to be 8BIT so we can perform regular expressions.
37
- # We'll set it to the detected encoding later
38
- body.force_encoding('ASCII-8BIT') if body && body.respond_to?(:force_encoding)
56
+ super(uri, response, body, code)
57
+ end
39
58
 
40
- @encoding ||= Util.detect_charset(body)
59
+ def title
60
+ @title ||=
61
+ if doc = parser
62
+ title = doc.search('title').inner_text
63
+ title.empty? ? nil : title
64
+ end
65
+ end
41
66
 
42
- super(uri, response, body, code)
43
- @mech ||= mech
67
+ def charset content_type
68
+ charset = content_type[/charset=([^; ]+)/i, 1]
69
+ return nil if charset == 'none'
70
+ charset
71
+ end
44
72
 
45
- @encoding = nil if html_body =~ /<meta[^>]*charset[^>]*>/i
73
+ def encoding=(encoding)
74
+ @encoding = encoding
46
75
 
47
- raise Mechanize::ContentTypeError.new(response['content-type']) unless
48
- response['content-type'] =~ /^(text\/html)|(application\/xhtml\+xml)/i
49
- @parser = @links = @forms = @meta = @bases = @frames = @iframes = nil
76
+ if @parser
77
+ parser_encoding = @parser.encoding
78
+ if (parser_encoding && parser_encoding.downcase) != (encoding && encoding.downcase)
79
+ # lazy reinitialize the parser with the new encoding
80
+ @parser = nil
81
+ end
50
82
  end
51
83
 
52
- def title
53
- @title ||=
54
- if doc = parser
55
- title = if doc.respond_to?(:title)
56
- doc.title
57
- else
58
- doc.search('title').inner_text
59
- end
60
- if title && !title.empty?
61
- title
62
- else
63
- nil
64
- end
65
- end
66
- end
84
+ encoding
85
+ end
86
+
87
+ def encoding
88
+ parser.respond_to?(:encoding) ? parser.encoding : nil
89
+ end
90
+
91
+ def parser
92
+ return @parser if @parser
93
+ return nil unless @body
94
+
95
+ if @encoding then
96
+ @parser = mech.html_parser.parse(html_body, nil, @encoding)
97
+ else
98
+ @encodings.reverse_each do |encoding|
99
+ @parser = mech.html_parser.parse(html_body, nil, encoding)
67
100
 
68
- def encoding=(encoding)
69
- @encoding = encoding
101
+ break if @parser.errors.empty?
70
102
 
71
- if @parser
72
- parser_encoding = @parser.encoding
73
- if (parser_encoding && parser_encoding.downcase) != (encoding && encoding.downcase)
74
- # lazy reinitialize the parser with the new encoding
75
- @parser = nil
103
+ break unless @parser.errors.any? do |error|
104
+ error.message =~ /(indicate encoding)|(Invalid char)/
76
105
  end
77
106
  end
78
-
79
- encoding
80
107
  end
81
108
 
82
- def encoding
83
- parser.respond_to?(:encoding) ? parser.encoding : nil
84
- end
109
+ @parser
110
+ end
85
111
 
86
- def parser
87
- return @parser if @parser
112
+ alias :root :parser
88
113
 
89
- if body && response
90
- if mech.html_parser == Nokogiri::HTML
91
- @parser = mech.html_parser.parse(html_body, nil, @encoding)
92
- else
93
- @parser = mech.html_parser.parse(html_body)
94
- end
95
- end
114
+ # Get the content type
115
+ def content_type
116
+ response['content-type']
117
+ end
96
118
 
97
- @parser
98
- end
99
- alias :root :parser
119
+ # Search through the page like HPricot
120
+ def_delegator :parser, :search, :search
121
+ def_delegator :parser, :/, :/
122
+ def_delegator :parser, :at, :at
100
123
 
101
- # Get the content type
102
- def content_type
103
- response['content-type']
104
- end
124
+ ##
125
+ # :method: form_with(criteria)
126
+ #
127
+ # Find a single form matching +criteria+.
128
+ # Example:
129
+ # page.form_with(:action => '/post/login.php') do |f|
130
+ # ...
131
+ # end
132
+
133
+ ##
134
+ # :method: forms_with(criteria)
135
+ #
136
+ # Find all forms form matching +criteria+.
137
+ # Example:
138
+ # page.forms_with(:action => '/post/login.php').each do |f|
139
+ # ...
140
+ # end
105
141
 
106
- # Search through the page like HPricot
107
- def_delegator :parser, :search, :search
108
- def_delegator :parser, :/, :/
109
- def_delegator :parser, :at, :at
110
-
111
- ##
112
- # :method: form_with(criteria)
113
- #
114
- # Find a single form matching +criteria+.
115
- # Example:
116
- # page.form_with(:action => '/post/login.php') do |f|
117
- # ...
118
- # end
119
-
120
- ##
121
- # :method: forms_with(criteria)
122
- #
123
- # Find all forms form matching +criteria+.
124
- # Example:
125
- # page.forms_with(:action => '/post/login.php').each do |f|
126
- # ...
127
- # end
128
-
129
- ##
130
- # :method: link_with(criteria)
131
- #
132
- # Find a single link matching +criteria+.
133
- # Example:
134
- # page.link_with(:href => /foo/).click
135
-
136
- ##
137
- # :method: links_with(criteria)
138
- #
139
- # Find all links matching +criteria+.
140
- # Example:
141
- # page.links_with(:href => /foo/).each do |link|
142
- # puts link.href
143
- # end
144
-
145
- ##
146
- # :method: base_with(criteria)
147
- #
148
- # Find a single base tag matching +criteria+.
149
- # Example:
150
- # page.base_with(:href => /foo/).click
151
-
152
- ##
153
- # :method: bases_with(criteria)
154
- #
155
- # Find all base tags matching +criteria+.
156
- # Example:
157
- # page.bases_with(:href => /foo/).each do |base|
158
- # puts base.href
159
- # end
160
-
161
- ##
162
- # :method: frame_with(criteria)
163
- #
164
- # Find a single frame tag matching +criteria+.
165
- # Example:
166
- # page.frame_with(:src => /foo/).click
167
-
168
- ##
169
- # :method: frames_with(criteria)
170
- #
171
- # Find all frame tags matching +criteria+.
172
- # Example:
173
- # page.frames_with(:src => /foo/).each do |frame|
174
- # p frame.src
175
- # end
176
-
177
- ##
178
- # :method: iframe_with(criteria)
179
- #
180
- # Find a single iframe tag matching +criteria+.
181
- # Example:
182
- # page.iframe_with(:src => /foo/).click
183
-
184
- ##
185
- # :method: iframes_with(criteria)
186
- #
187
- # Find all iframe tags matching +criteria+.
188
- # Example:
189
- # page.iframes_with(:src => /foo/).each do |iframe|
190
- # p iframe.src
191
- # end
192
-
193
- # let's meta program!
194
- [:form, :link, :base, :frame, :iframe].each do |type|
195
- eval(<<-eomethod)
196
- def #{type}s_with(criteria)
197
- criteria = {:name => criteria} if String === criteria
198
- f = #{type}s.find_all do |thing|
199
- criteria.all? do |k,v|
200
- k = :dom_id if(k.to_s == "id")
201
- v === thing.send(k)
202
- end
203
- end
204
- yield f if block_given?
205
- f
206
- end
207
-
208
- def #{type}_with(criteria)
209
- f = #{type}s_with(criteria).first
210
- yield f if block_given?
211
- f
212
- end
213
- alias :#{type} :#{type}_with
214
- eomethod
215
- end
142
+ elements_with :form
216
143
 
217
- ##
218
- # Return a list of all link and area tags
219
- def links
220
- @links ||= %w{ a area }.map do |tag|
221
- search(tag).map do |node|
222
- Link.new(node, @mech, self)
223
- end
224
- end.flatten
225
- end
144
+ ##
145
+ # :method: link_with(criteria)
146
+ #
147
+ # Find a single link matching +criteria+.
148
+ # Example:
149
+ # page.link_with(:href => /foo/).click
150
+
151
+ ##
152
+ # :method: links_with(criteria)
153
+ #
154
+ # Find all links matching +criteria+.
155
+ # Example:
156
+ # page.links_with(:href => /foo/).each do |link|
157
+ # puts link.href
158
+ # end
226
159
 
227
- ##
228
- # Return a list of all form tags
229
- def forms
230
- @forms ||= search('form').map do |html_form|
231
- form = Form.new(html_form, @mech, self)
232
- form.action ||= @uri.to_s
233
- form
160
+ elements_with :link
161
+
162
+ ##
163
+ # :method: base_with(criteria)
164
+ #
165
+ # Find a single base tag matching +criteria+.
166
+ # Example:
167
+ # page.base_with(:href => /foo/).click
168
+
169
+ ##
170
+ # :method: bases_with(criteria)
171
+ #
172
+ # Find all base tags matching +criteria+.
173
+ # Example:
174
+ # page.bases_with(:href => /foo/).each do |base|
175
+ # puts base.href
176
+ # end
177
+
178
+ elements_with :base
179
+
180
+ ##
181
+ # :method: frame_with(criteria)
182
+ #
183
+ # Find a single frame tag matching +criteria+.
184
+ # Example:
185
+ # page.frame_with(:src => /foo/).click
186
+
187
+ ##
188
+ # :method: frames_with(criteria)
189
+ #
190
+ # Find all frame tags matching +criteria+.
191
+ # Example:
192
+ # page.frames_with(:src => /foo/).each do |frame|
193
+ # p frame.src
194
+ # end
195
+
196
+ elements_with :frame
197
+
198
+ ##
199
+ # :method: iframe_with(criteria)
200
+ #
201
+ # Find a single iframe tag matching +criteria+.
202
+ # Example:
203
+ # page.iframe_with(:src => /foo/).click
204
+
205
+ ##
206
+ # :method: iframes_with(criteria)
207
+ #
208
+ # Find all iframe tags matching +criteria+.
209
+ # Example:
210
+ # page.iframes_with(:src => /foo/).each do |iframe|
211
+ # p iframe.src
212
+ # end
213
+
214
+ elements_with :iframe
215
+
216
+ ##
217
+ # Return a list of all link and area tags
218
+ def links
219
+ @links ||= %w{ a area }.map do |tag|
220
+ search(tag).map do |node|
221
+ Link.new(node, @mech, self)
234
222
  end
223
+ end.flatten
224
+ end
225
+
226
+ ##
227
+ # Return a list of all form tags
228
+ def forms
229
+ @forms ||= search('form').map do |html_form|
230
+ form = Mechanize::Form.new(html_form, @mech, self)
231
+ form.action ||= @uri.to_s
232
+ form
235
233
  end
234
+ end
236
235
 
237
- ##
238
- # Return a list of all meta tags
239
- def meta
240
- @meta ||= search('head > meta').map do |node|
241
- next unless node['http-equiv'] && node['content']
242
- (equiv, content) = node['http-equiv'], node['content']
243
- if equiv && equiv.downcase == 'refresh'
244
- Meta.parse(content, uri) do |delay, href|
245
- node['delay'] = delay
246
- node['href'] = href
247
- Meta.new(node, @mech, self)
248
- end
236
+ ##
237
+ # Return a list of all meta tags
238
+ def meta
239
+ @meta ||= search('head > meta').map do |node|
240
+ next unless node['http-equiv'] && node['content']
241
+ (equiv, content) = node['http-equiv'], node['content']
242
+ if equiv && equiv.downcase == 'refresh'
243
+ Meta.parse(content, uri) do |delay, href|
244
+ node['delay'] = delay
245
+ node['href'] = href
246
+ Meta.new(node, @mech, self)
249
247
  end
250
- end.compact
251
- end
248
+ end
249
+ end.compact
250
+ end
252
251
 
253
- ##
254
- # Return a list of all base tags
255
- def bases
256
- @bases ||=
257
- search('base').map { |node| Base.new(node, @mech, self) }
258
- end
252
+ ##
253
+ # Return a list of all base tags
254
+ def bases
255
+ @bases ||=
256
+ search('base').map { |node| Base.new(node, @mech, self) }
257
+ end
259
258
 
260
- ##
261
- # Return a list of all frame tags
262
- def frames
263
- @frames ||=
264
- search('frame').map { |node| Frame.new(node, @mech, self) }
265
- end
259
+ ##
260
+ # Return a list of all frame tags
261
+ def frames
262
+ @frames ||=
263
+ search('frame').map { |node| Frame.new(node, @mech, self) }
264
+ end
266
265
 
267
- ##
268
- # Return a list of all iframe tags
269
- def iframes
270
- @iframes ||=
271
- search('iframe').map { |node| Frame.new(node, @mech, self) }
272
- end
266
+ ##
267
+ # Return a list of all iframe tags
268
+ def iframes
269
+ @iframes ||=
270
+ search('iframe').map { |node| Frame.new(node, @mech, self) }
271
+ end
273
272
 
274
- ##
275
- # Return a list of all img tags
276
- def images
277
- @images ||=
278
- search('img').map { |node| Image.new(node, self) }
279
- end
273
+ ##
274
+ # Return a list of all img tags
275
+ def images
276
+ @images ||=
277
+ search('img').map { |node| Image.new(node, self) }
278
+ end
280
279
 
281
- def image_urls
282
- @image_urls ||= images.map(&:url).uniq
283
- end
280
+ def image_urls
281
+ @image_urls ||= images.map(&:url).uniq
282
+ end
284
283
 
285
- ##
286
- # Return a list of all label tags
287
- def labels
288
- @labels ||=
289
- search('label').map { |node| Label.new(node, self) }
290
- end
284
+ ##
285
+ # Return a list of all label tags
286
+ def labels
287
+ @labels ||=
288
+ search('label').map { |node| Label.new(node, self) }
289
+ end
291
290
 
292
- def labels_hash
293
- unless @labels_hash
294
- hash = {}
295
- labels.each do |label|
296
- hash[label.node['for']] = label if label.for
297
- end
298
- @labels_hash = hash
291
+ def labels_hash
292
+ unless @labels_hash
293
+ hash = {}
294
+ labels.each do |label|
295
+ hash[label.node['for']] = label if label.for
299
296
  end
300
- return @labels_hash
297
+ @labels_hash = hash
301
298
  end
299
+ return @labels_hash
300
+ end
302
301
 
303
- private
302
+ private
304
303
 
305
- def html_body
306
- if body
307
- body.length > 0 ? body : '<html></html>'
308
- else
309
- ''
310
- end
304
+ def html_body
305
+ if @body
306
+ @body.empty? ? '<html></html>' : @body
307
+ else
308
+ ''
311
309
  end
312
310
  end
313
311
  end
312
+
313
+ require 'mechanize/headers'
314
+ require 'mechanize/page/image'
315
+ require 'mechanize/page/label'
316
+ require 'mechanize/page/link'
317
+ require 'mechanize/page/base'
318
+ require 'mechanize/page/frame'
319
+ require 'mechanize/page/meta'
320
+