webrat 0.4.1 → 0.4.2
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.
- data/History.txt +25 -0
- data/Rakefile +1 -1
- data/lib/webrat/core/configuration.rb +5 -0
- data/lib/webrat/core/matchers/have_content.rb +7 -3
- data/lib/webrat/core/matchers/have_selector.rb +37 -15
- data/lib/webrat/core/matchers/have_tag.rb +8 -58
- data/lib/webrat/core/matchers/have_xpath.rb +74 -20
- data/lib/webrat/core/session.rb +23 -1
- data/lib/webrat/merb_session.rb +1 -1
- data/lib/webrat/selenium/matchers/have_tag.rb +1 -1
- data/lib/webrat/selenium.rb +1 -1
- data/lib/webrat.rb +1 -1
- metadata +3 -4
- data/lib/webrat/core_extensions/hash_with_indifferent_access.rb +0 -131
data/History.txt
CHANGED
@@ -1,3 +1,28 @@
|
|
1
|
+
== 0.4.2 / 2009-02-24
|
2
|
+
|
3
|
+
* Major enhancements
|
4
|
+
|
5
|
+
* Significant improvements to have_selector. It now supports specifying
|
6
|
+
attributes in a hash and :count and :content options. See
|
7
|
+
have_selector_spec.rb for more.
|
8
|
+
* Add the same functionality mentioned above to have_xpath
|
9
|
+
|
10
|
+
* Minor enhancements
|
11
|
+
|
12
|
+
* Squeeze extra whitespace out of failures messages from contain
|
13
|
+
matcher
|
14
|
+
* Detect infinite redirects and raise a Webrat::InfiniteRedirectError
|
15
|
+
(Daniel Lucraft)
|
16
|
+
|
17
|
+
* Bug fixes
|
18
|
+
|
19
|
+
* Properly quote single and double quotes strings in XPath
|
20
|
+
* Fix warning caused by Nokogiri deprecating CSS::Parser.parse
|
21
|
+
(Aaron Patterson)
|
22
|
+
* Accept do/end blocks in matchers. [#157] (Peter Jaros)
|
23
|
+
* Quote --chdir option to mongrel_rails to support RAILS_ROOTs with spaces
|
24
|
+
(T.J. VanSlyke)
|
25
|
+
|
1
26
|
== 0.4.1 / 2009-01-31
|
2
27
|
|
3
28
|
* Minor enhancements
|
data/Rakefile
CHANGED
@@ -51,6 +51,10 @@ module Webrat
|
|
51
51
|
# Set the key that Selenium uses to determine the browser running. Default *firefox
|
52
52
|
attr_accessor :selenium_browser_key
|
53
53
|
|
54
|
+
# How many redirects to the same URL should be halted as an infinite redirect
|
55
|
+
# loop? Defaults to 10
|
56
|
+
attr_accessor :infinite_redirect_limit
|
57
|
+
|
54
58
|
def initialize # :nodoc:
|
55
59
|
self.open_error_files = true
|
56
60
|
self.parse_with_nokogiri = !Webrat.on_java?
|
@@ -58,6 +62,7 @@ module Webrat
|
|
58
62
|
self.application_port = 3001
|
59
63
|
self.application_address = 'localhost'
|
60
64
|
self.selenium_server_port = 4444
|
65
|
+
self.infinite_redirect_limit = 10
|
61
66
|
self.selenium_browser_key = '*firefox'
|
62
67
|
end
|
63
68
|
|
@@ -26,15 +26,19 @@ module Webrat
|
|
26
26
|
# ==== Returns
|
27
27
|
# String:: The failure message.
|
28
28
|
def failure_message
|
29
|
-
"expected the following element's content to #{content_message}:\n#{@element}"
|
29
|
+
"expected the following element's content to #{content_message}:\n#{squeeze_space(@element)}"
|
30
30
|
end
|
31
31
|
|
32
32
|
# ==== Returns
|
33
33
|
# String:: The failure message to be displayed in negative matches.
|
34
34
|
def negative_failure_message
|
35
|
-
"expected the following element's content to not #{content_message}:\n#{@element}"
|
35
|
+
"expected the following element's content to not #{content_message}:\n#{squeeze_space(@element)}"
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
|
+
def squeeze_space(inner_text)
|
39
|
+
inner_text.gsub(/^\s*$/, "").squeeze("\n")
|
40
|
+
end
|
41
|
+
|
38
42
|
def content_message
|
39
43
|
case @content
|
40
44
|
when String
|
@@ -1,24 +1,46 @@
|
|
1
|
+
require "webrat/core/matchers/have_xpath"
|
2
|
+
|
1
3
|
module Webrat
|
2
4
|
module Matchers
|
3
5
|
|
4
6
|
class HaveSelector < HaveXpath #:nodoc:
|
5
|
-
|
6
7
|
# ==== Returns
|
7
8
|
# String:: The failure message.
|
8
9
|
def failure_message
|
9
|
-
"expected following
|
10
|
+
"expected following output to contain a #{tag_inspect} tag:\n#{@document}"
|
10
11
|
end
|
11
|
-
|
12
|
+
|
12
13
|
# ==== Returns
|
13
14
|
# String:: The failure message to be displayed in negative matches.
|
14
15
|
def negative_failure_message
|
15
|
-
"expected following
|
16
|
+
"expected following output to omit a #{tag_inspect}:\n#{@document}"
|
16
17
|
end
|
17
|
-
|
18
|
+
|
19
|
+
def tag_inspect
|
20
|
+
options = @options.dup
|
21
|
+
count = options.delete(:count)
|
22
|
+
content = options.delete(:content)
|
23
|
+
|
24
|
+
html = "<#{@expected}"
|
25
|
+
options.each do |k,v|
|
26
|
+
html << " #{k}='#{v}'"
|
27
|
+
end
|
28
|
+
|
29
|
+
if content
|
30
|
+
html << ">#{content}</#{@expected}>"
|
31
|
+
else
|
32
|
+
html << "/>"
|
33
|
+
end
|
34
|
+
|
35
|
+
html
|
36
|
+
end
|
37
|
+
|
18
38
|
def query
|
19
|
-
Nokogiri::CSS
|
39
|
+
Nokogiri::CSS.parse(@expected.to_s).map do |ast|
|
40
|
+
ast.to_xpath
|
41
|
+
end.first
|
20
42
|
end
|
21
|
-
|
43
|
+
|
22
44
|
end
|
23
45
|
|
24
46
|
# Matches HTML content against a CSS 3 selector.
|
@@ -28,24 +50,24 @@ module Webrat
|
|
28
50
|
#
|
29
51
|
# ==== Returns
|
30
52
|
# HaveSelector:: A new have selector matcher.
|
31
|
-
def have_selector(
|
32
|
-
HaveSelector.new(
|
53
|
+
def have_selector(name, attributes = {}, &block)
|
54
|
+
HaveSelector.new(name, attributes, &block)
|
33
55
|
end
|
34
56
|
alias_method :match_selector, :have_selector
|
35
57
|
|
36
58
|
|
37
59
|
# Asserts that the body of the response contains
|
38
60
|
# the supplied selector
|
39
|
-
def assert_have_selector(
|
40
|
-
|
41
|
-
assert
|
61
|
+
def assert_have_selector(name, attributes = {}, &block)
|
62
|
+
matcher = HaveSelector.new(name, attributes, &block)
|
63
|
+
assert matcher.matches?(response_body), matcher.failure_message
|
42
64
|
end
|
43
65
|
|
44
66
|
# Asserts that the body of the response
|
45
67
|
# does not contain the supplied string or regepx
|
46
|
-
def assert_have_no_selector(
|
47
|
-
|
48
|
-
assert !
|
68
|
+
def assert_have_no_selector(name, attributes = {}, &block)
|
69
|
+
matcher = HaveSelector.new(name, attributes, &block)
|
70
|
+
assert !matcher.matches?(response_body), matcher.negative_failure_message
|
49
71
|
end
|
50
72
|
|
51
73
|
end
|
@@ -1,70 +1,20 @@
|
|
1
|
+
require "webrat/core/matchers/have_selector"
|
2
|
+
|
1
3
|
module Webrat
|
2
|
-
|
3
4
|
module HaveTagMatcher
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
# String:: The failure message.
|
8
|
-
def failure_message
|
9
|
-
"expected following output to contain a #{tag_inspect} tag:\n#{@document}"
|
10
|
-
end
|
11
|
-
|
12
|
-
# ==== Returns
|
13
|
-
# String:: The failure message to be displayed in negative matches.
|
14
|
-
def negative_failure_message
|
15
|
-
"expected following output to omit a #{tag_inspect}:\n#{@document}"
|
16
|
-
end
|
17
|
-
|
18
|
-
def tag_inspect
|
19
|
-
options = @expected.last.dup
|
20
|
-
content = options.delete(:content)
|
21
|
-
|
22
|
-
html = "<#{@expected.first}"
|
23
|
-
options.each do |k,v|
|
24
|
-
html << " #{k}='#{v}'"
|
25
|
-
end
|
26
|
-
|
27
|
-
if content
|
28
|
-
html << ">#{content}</#{@expected.first}>"
|
29
|
-
else
|
30
|
-
html << "/>"
|
31
|
-
end
|
32
|
-
|
33
|
-
html
|
34
|
-
end
|
35
|
-
|
36
|
-
def query
|
37
|
-
options = @expected.last.dup
|
38
|
-
selector = @expected.first.to_s
|
39
|
-
|
40
|
-
selector << ":contains('#{options.delete(:content)}')" if options[:content]
|
41
|
-
|
42
|
-
options.each do |key, value|
|
43
|
-
selector << "[#{key}='#{value}']"
|
44
|
-
end
|
45
|
-
|
46
|
-
Nokogiri::CSS::Parser.parse(selector).map { |ast| ast.to_xpath }
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
def have_tag(name, attributes = {}, &block)
|
51
|
-
HaveTag.new([name, attributes], &block)
|
6
|
+
def have_tag(*args, &block)
|
7
|
+
have_selector(*args, &block)
|
52
8
|
end
|
53
9
|
|
54
10
|
alias_method :match_tag, :have_tag
|
55
11
|
|
56
|
-
|
57
|
-
|
58
|
-
def assert_have_tag(name, attributes = {})
|
59
|
-
ht = HaveTag.new([name, attributes])
|
60
|
-
assert ht.matches?(response_body), ht.failure_message
|
12
|
+
def assert_have_tag(*args, &block)
|
13
|
+
assert_have_selector(*args, &block)
|
61
14
|
end
|
62
15
|
|
63
|
-
|
64
|
-
|
65
|
-
def assert_have_no_tag(name, attributes = {})
|
66
|
-
ht = HaveTag.new([name, attributes])
|
67
|
-
assert !ht.matches?(response_body), ht.negative_failure_message
|
16
|
+
def assert_have_no_tag(*args, &block)
|
17
|
+
assert_have_no_selector(*args, &block)
|
68
18
|
end
|
69
19
|
|
70
20
|
end
|
@@ -5,53 +5,90 @@ module Webrat
|
|
5
5
|
module Matchers
|
6
6
|
|
7
7
|
class HaveXpath #:nodoc:
|
8
|
-
def initialize(expected, &block)
|
8
|
+
def initialize(expected, options = {}, &block)
|
9
9
|
@expected = expected
|
10
|
+
@options = options
|
10
11
|
@block = block
|
11
12
|
end
|
12
13
|
|
13
|
-
def matches?(stringlike)
|
14
|
+
def matches?(stringlike, &block)
|
15
|
+
@block ||= block
|
16
|
+
matched = matches(stringlike)
|
17
|
+
|
18
|
+
if @options[:count]
|
19
|
+
matched.size == @options[:count] && (!@block || @block.call(matched))
|
20
|
+
else
|
21
|
+
matched.any? && (!@block || @block.call(matched))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def matches(stringlike)
|
14
26
|
if Webrat.configuration.parse_with_nokogiri?
|
15
|
-
|
27
|
+
nokogiri_matches(stringlike)
|
16
28
|
else
|
17
|
-
|
29
|
+
rexml_matches(stringlike)
|
18
30
|
end
|
19
31
|
end
|
20
32
|
|
21
|
-
def
|
33
|
+
def rexml_matches(stringlike)
|
22
34
|
if REXML::Node === stringlike || Array === stringlike
|
23
35
|
@query = query.map { |q| q.gsub(%r'//', './') }
|
24
36
|
else
|
25
37
|
@query = query
|
26
38
|
end
|
27
39
|
|
40
|
+
add_options_conditions_to(@query)
|
41
|
+
|
28
42
|
@document = Webrat.rexml_document(stringlike)
|
29
43
|
|
30
|
-
|
44
|
+
@query.map do |q|
|
31
45
|
if @document.is_a?(Array)
|
32
46
|
@document.map { |d| REXML::XPath.match(d, q) }
|
33
47
|
else
|
34
48
|
REXML::XPath.match(@document, q)
|
35
49
|
end
|
36
50
|
end.flatten.compact
|
37
|
-
|
38
|
-
matched.any? && (!@block || @block.call(matched))
|
39
51
|
end
|
40
52
|
|
41
|
-
def
|
53
|
+
def nokogiri_matches(stringlike)
|
42
54
|
if Nokogiri::XML::NodeSet === stringlike
|
43
|
-
@query = query.
|
55
|
+
@query = query.gsub(%r'//', './')
|
44
56
|
else
|
45
57
|
@query = query
|
46
58
|
end
|
47
59
|
|
60
|
+
add_options_conditions_to(@query)
|
61
|
+
|
48
62
|
@document = Webrat::XML.document(stringlike)
|
49
|
-
|
50
|
-
|
63
|
+
@document.xpath(*@query)
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_options_conditions_to(query)
|
67
|
+
add_attributes_conditions_to(query)
|
68
|
+
add_content_condition_to(query)
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_attributes_conditions_to(query)
|
72
|
+
attribute_conditions = []
|
73
|
+
|
74
|
+
@options.each do |key, value|
|
75
|
+
next if [:content, :count].include?(key)
|
76
|
+
attribute_conditions << "@#{key} = #{xpath_escape(value)}"
|
77
|
+
end
|
78
|
+
|
79
|
+
if attribute_conditions.any?
|
80
|
+
query << "[#{attribute_conditions.join(' and ')}]"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_content_condition_to(query)
|
85
|
+
if @options[:content]
|
86
|
+
query << "[contains(., #{xpath_escape(@options[:content])})]"
|
87
|
+
end
|
51
88
|
end
|
52
89
|
|
53
90
|
def query
|
54
|
-
|
91
|
+
@expected
|
55
92
|
end
|
56
93
|
|
57
94
|
# ==== Returns
|
@@ -64,7 +101,24 @@ module Webrat
|
|
64
101
|
# String:: The failure message to be displayed in negative matches.
|
65
102
|
def negative_failure_message
|
66
103
|
"expected following text to not match xpath #{@expected}:\n#{@document}"
|
67
|
-
end
|
104
|
+
end
|
105
|
+
|
106
|
+
protected
|
107
|
+
|
108
|
+
def xpath_escape(string)
|
109
|
+
if string.include?("'") && string.include?('"')
|
110
|
+
parts = string.split("'").map do |part|
|
111
|
+
"'#{part}'"
|
112
|
+
end
|
113
|
+
|
114
|
+
"concat(" + parts.join(", \"'\", ") + ")"
|
115
|
+
elsif string.include?("'")
|
116
|
+
"\"#{string}\""
|
117
|
+
else
|
118
|
+
"'#{string}'"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
68
122
|
end
|
69
123
|
|
70
124
|
# Matches HTML content against an XPath query
|
@@ -74,18 +128,18 @@ module Webrat
|
|
74
128
|
#
|
75
129
|
# ==== Returns
|
76
130
|
# HaveXpath:: A new have xpath matcher.
|
77
|
-
def have_xpath(expected, &block)
|
78
|
-
HaveXpath.new(expected, &block)
|
131
|
+
def have_xpath(expected, options = {}, &block)
|
132
|
+
HaveXpath.new(expected, options, &block)
|
79
133
|
end
|
80
134
|
alias_method :match_xpath, :have_xpath
|
81
135
|
|
82
|
-
def assert_have_xpath(expected, &block)
|
83
|
-
hs = HaveXpath.new(expected, &block)
|
136
|
+
def assert_have_xpath(expected, options = {}, &block)
|
137
|
+
hs = HaveXpath.new(expected, options, &block)
|
84
138
|
assert hs.matches?(response_body), hs.failure_message
|
85
139
|
end
|
86
140
|
|
87
|
-
def assert_have_no_xpath(expected, &block)
|
88
|
-
hs = HaveXpath.new(expected, &block)
|
141
|
+
def assert_have_no_xpath(expected, options = {}, &block)
|
142
|
+
hs = HaveXpath.new(expected, options, &block)
|
89
143
|
assert !hs.matches?(response_body), hs.negative_failure_message
|
90
144
|
end
|
91
145
|
|
data/lib/webrat/core/session.rb
CHANGED
@@ -9,6 +9,9 @@ module Webrat
|
|
9
9
|
class PageLoadError < WebratError
|
10
10
|
end
|
11
11
|
|
12
|
+
class InfiniteRedirectError < WebratError
|
13
|
+
end
|
14
|
+
|
12
15
|
def self.session_class
|
13
16
|
case Webrat.configuration.mode
|
14
17
|
when :rails
|
@@ -112,11 +115,30 @@ For example:
|
|
112
115
|
@http_method = http_method
|
113
116
|
@data = data
|
114
117
|
|
115
|
-
|
118
|
+
if internal_redirect?
|
119
|
+
check_for_infinite_redirects
|
120
|
+
request_page(response_location, :get, {})
|
121
|
+
end
|
116
122
|
|
117
123
|
return response
|
118
124
|
end
|
125
|
+
|
126
|
+
def check_for_infinite_redirects
|
127
|
+
if current_url == response_location
|
128
|
+
@_identical_redirect_count ||= 0
|
129
|
+
@_identical_redirect_count += 1
|
130
|
+
end
|
131
|
+
|
132
|
+
if infinite_redirect_limit_exceeded?
|
133
|
+
raise InfiniteRedirectError.new("#{Webrat.configuration.infinite_redirect_limit} redirects to the same URL (#{current_url.inspect})")
|
134
|
+
end
|
135
|
+
end
|
119
136
|
|
137
|
+
def infinite_redirect_limit_exceeded?
|
138
|
+
Webrat.configuration.infinite_redirect_limit &&
|
139
|
+
(@_identical_redirect_count || 0) > Webrat.configuration.infinite_redirect_limit
|
140
|
+
end
|
141
|
+
|
120
142
|
def success_code? #:nodoc:
|
121
143
|
(200..499).include?(response_code)
|
122
144
|
end
|
data/lib/webrat/merb_session.rb
CHANGED
data/lib/webrat/selenium.rb
CHANGED
@@ -27,7 +27,7 @@ module Webrat
|
|
27
27
|
|
28
28
|
def self.start_app_server #:nodoc:
|
29
29
|
pid_file = prepare_pid_file("#{RAILS_ROOT}/tmp/pids", "mongrel_selenium.pid")
|
30
|
-
system("mongrel_rails start -d --chdir
|
30
|
+
system("mongrel_rails start -d --chdir='#{RAILS_ROOT}' --port=#{Webrat.configuration.application_port} --environment=#{Webrat.configuration.application_environment} --pid #{pid_file} &")
|
31
31
|
TCPSocket.wait_for_service :host => Webrat.configuration.application_address, :port => Webrat.configuration.application_port.to_i
|
32
32
|
end
|
33
33
|
|
data/lib/webrat.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webrat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryan Helmkamp
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-02-24 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 1.
|
23
|
+
version: 1.2.0
|
24
24
|
version:
|
25
25
|
description: Webrat. Ruby Acceptance Testing for Web applications
|
26
26
|
email: bryan@brynary.com
|
@@ -83,7 +83,6 @@ files:
|
|
83
83
|
- lib/webrat/core_extensions/blank.rb
|
84
84
|
- lib/webrat/core_extensions/deprecate.rb
|
85
85
|
- lib/webrat/core_extensions/detect_mapped.rb
|
86
|
-
- lib/webrat/core_extensions/hash_with_indifferent_access.rb
|
87
86
|
- lib/webrat/core_extensions/meta_class.rb
|
88
87
|
- lib/webrat/core_extensions/nil_to_param.rb
|
89
88
|
- lib/webrat/mechanize.rb
|
@@ -1,131 +0,0 @@
|
|
1
|
-
# This class has dubious semantics and we only have it so that
|
2
|
-
# people can write params[:key] instead of params['key']
|
3
|
-
# and they get the same value for both keys.
|
4
|
-
class HashWithIndifferentAccess < Hash #:nodoc:
|
5
|
-
def initialize(constructor = {})
|
6
|
-
if constructor.is_a?(Hash)
|
7
|
-
super()
|
8
|
-
update(constructor)
|
9
|
-
else
|
10
|
-
super(constructor)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def default(key = nil)
|
15
|
-
if key.is_a?(Symbol) && include?(key = key.to_s)
|
16
|
-
self[key]
|
17
|
-
else
|
18
|
-
super
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
23
|
-
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
24
|
-
|
25
|
-
#
|
26
|
-
# Assigns a new value to the hash.
|
27
|
-
#
|
28
|
-
# Example:
|
29
|
-
#
|
30
|
-
# hash = HashWithIndifferentAccess.new
|
31
|
-
# hash[:key] = "value"
|
32
|
-
#
|
33
|
-
def []=(key, value)
|
34
|
-
regular_writer(convert_key(key), convert_value(value))
|
35
|
-
end
|
36
|
-
|
37
|
-
#
|
38
|
-
# Updates the instantized hash with values from the second.
|
39
|
-
#
|
40
|
-
# Example:
|
41
|
-
#
|
42
|
-
# >> hash_1 = HashWithIndifferentAccess.new
|
43
|
-
# => {}
|
44
|
-
#
|
45
|
-
# >> hash_1[:key] = "value"
|
46
|
-
# => "value"
|
47
|
-
#
|
48
|
-
# >> hash_2 = HashWithIndifferentAccess.new
|
49
|
-
# => {}
|
50
|
-
#
|
51
|
-
# >> hash_2[:key] = "New Value!"
|
52
|
-
# => "New Value!"
|
53
|
-
#
|
54
|
-
# >> hash_1.update(hash_2)
|
55
|
-
# => {"key"=>"New Value!"}
|
56
|
-
#
|
57
|
-
def update(other_hash)
|
58
|
-
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
|
59
|
-
self
|
60
|
-
end
|
61
|
-
|
62
|
-
alias_method :merge!, :update
|
63
|
-
|
64
|
-
# Checks the hash for a key matching the argument passed in
|
65
|
-
def key?(key)
|
66
|
-
super(convert_key(key))
|
67
|
-
end
|
68
|
-
|
69
|
-
alias_method :include?, :key?
|
70
|
-
alias_method :has_key?, :key?
|
71
|
-
alias_method :member?, :key?
|
72
|
-
|
73
|
-
# Fetches the value for the specified key, same as doing hash[key]
|
74
|
-
def fetch(key, *extras)
|
75
|
-
super(convert_key(key), *extras)
|
76
|
-
end
|
77
|
-
|
78
|
-
# Returns an array of the values at the specified indicies.
|
79
|
-
def values_at(*indices)
|
80
|
-
indices.collect {|key| self[convert_key(key)]}
|
81
|
-
end
|
82
|
-
|
83
|
-
# Returns an exact copy of the hash.
|
84
|
-
def dup
|
85
|
-
HashWithIndifferentAccess.new(self)
|
86
|
-
end
|
87
|
-
|
88
|
-
# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
|
89
|
-
# Does not overwrite the existing hash.
|
90
|
-
def merge(hash)
|
91
|
-
self.dup.update(hash)
|
92
|
-
end
|
93
|
-
|
94
|
-
# Removes a specified key from the hash.
|
95
|
-
def delete(key)
|
96
|
-
super(convert_key(key))
|
97
|
-
end
|
98
|
-
|
99
|
-
def stringify_keys!; self end
|
100
|
-
def symbolize_keys!; self end
|
101
|
-
def to_options!; self end
|
102
|
-
|
103
|
-
# Convert to a Hash with String keys.
|
104
|
-
def to_hash
|
105
|
-
Hash.new(default).merge(self)
|
106
|
-
end
|
107
|
-
|
108
|
-
protected
|
109
|
-
def convert_key(key)
|
110
|
-
key.kind_of?(Symbol) ? key.to_s : key
|
111
|
-
end
|
112
|
-
|
113
|
-
def convert_value(value)
|
114
|
-
case value
|
115
|
-
when Hash
|
116
|
-
value.with_indifferent_access
|
117
|
-
when Array
|
118
|
-
value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
|
119
|
-
else
|
120
|
-
value
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
class Hash #:nodoc:
|
126
|
-
def with_indifferent_access
|
127
|
-
hash = HashWithIndifferentAccess.new(self)
|
128
|
-
hash.default = self.default
|
129
|
-
hash
|
130
|
-
end
|
131
|
-
end
|