ruby-web 1.1.1
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/ChangeLog +474 -0
- data/INSTALL.txt +9 -0
- data/InstalledFiles +180 -0
- data/LICENSE.txt +74 -0
- data/Rakefile +529 -0
- data/TODO +65 -0
- data/doc/additional.xml +149 -0
- data/doc/core.xml +652 -0
- data/doc/credits/index.xml +52 -0
- data/doc/credits/php.contributors.xml +118 -0
- data/doc/credits/php.language-snippets.ent +622 -0
- data/doc/install/index.xml +136 -0
- data/doc/install/mac/index.xml +21 -0
- data/doc/install/ruby-web.install.rb.instructions.xml +7 -0
- data/doc/install/unix/index.xml +46 -0
- data/doc/install/win/apache1.xml +166 -0
- data/doc/install/win/apache2.xml +141 -0
- data/doc/install/win/iis.xml +162 -0
- data/doc/install/win/index.xml +24 -0
- data/doc/install/win/installer.xml +31 -0
- data/doc/install/win/manual.xml +43 -0
- data/doc/manual.xml +69 -0
- data/doc/old/apache_cgi.txt +23 -0
- data/doc/old/fastcgi.txt +23 -0
- data/doc/old/mod_ruby.txt +21 -0
- data/doc/old/snippets.rdoc +183 -0
- data/doc/old/webrick.txt +23 -0
- data/doc/old/windows_cgi.txt +9 -0
- data/doc/tutorial.xml +14 -0
- data/doc/xsl/manual-multi.xsl +10 -0
- data/doc/xsl/manual-pdf.xsl +6 -0
- data/doc/xsl/manual-single.xsl +6 -0
- data/doc/xsl/manual.css +22 -0
- data/install.rb +1022 -0
- data/lib/formatter.rb +314 -0
- data/lib/html-parser.rb +429 -0
- data/lib/htmlrepair.rb +113 -0
- data/lib/htmlsplit.rb +842 -0
- data/lib/sgml-parser.rb +332 -0
- data/lib/web.rb +68 -0
- data/lib/web/assertinclude.rb +129 -0
- data/lib/web/config.rb +50 -0
- data/lib/web/connection.rb +1070 -0
- data/lib/web/convenience.rb +154 -0
- data/lib/web/formreader.rb +318 -0
- data/lib/web/htmlparser/html-parser.rb +429 -0
- data/lib/web/htmlparser/sgml-parser.rb +332 -0
- data/lib/web/htmltools/element.rb +296 -0
- data/lib/web/htmltools/stparser.rb +276 -0
- data/lib/web/htmltools/tags.rb +286 -0
- data/lib/web/htmltools/tree.rb +139 -0
- data/lib/web/htmltools/xmltree.rb +160 -0
- data/lib/web/htmltools/xpath.rb +71 -0
- data/lib/web/info.rb +63 -0
- data/lib/web/load.rb +210 -0
- data/lib/web/mime.rb +87 -0
- data/lib/web/phprb.rb +340 -0
- data/lib/web/resources/test/cookie.rb +33 -0
- data/lib/web/resources/test/counter.rb +20 -0
- data/lib/web/resources/test/multipart.rb +14 -0
- data/lib/web/resources/test/redirect.rb +8 -0
- data/lib/web/resources/test/stock.rb +33 -0
- data/lib/web/sapi/apache.rb +129 -0
- data/lib/web/sapi/fastcgi.rb +22 -0
- data/lib/web/sapi/install/apache.rb +180 -0
- data/lib/web/sapi/install/iis.rb +93 -0
- data/lib/web/sapi/install/macosx.rb +90 -0
- data/lib/web/sapi/webrick.rb +86 -0
- data/lib/web/session.rb +83 -0
- data/lib/web/shim/cgi.rb +129 -0
- data/lib/web/shim/rails.rb +175 -0
- data/lib/web/stringio.rb +78 -0
- data/lib/web/strscanparser.rb +24 -0
- data/lib/web/tagparser.rb +96 -0
- data/lib/web/testing.rb +666 -0
- data/lib/web/traceoutput.rb +75 -0
- data/lib/web/unit.rb +56 -0
- data/lib/web/upload.rb +59 -0
- data/lib/web/validate.rb +52 -0
- data/lib/web/wiki.rb +557 -0
- data/lib/web/wiki/linker.rb +72 -0
- data/lib/web/wiki/page.rb +201 -0
- data/lib/webunit.rb +27 -0
- data/lib/webunit/assert.rb +152 -0
- data/lib/webunit/converter.rb +154 -0
- data/lib/webunit/cookie.rb +118 -0
- data/lib/webunit/domwalker.rb +185 -0
- data/lib/webunit/exception.rb +14 -0
- data/lib/webunit/form.rb +116 -0
- data/lib/webunit/frame.rb +37 -0
- data/lib/webunit/htmlelem.rb +122 -0
- data/lib/webunit/image.rb +26 -0
- data/lib/webunit/jscript.rb +31 -0
- data/lib/webunit/link.rb +33 -0
- data/lib/webunit/params.rb +321 -0
- data/lib/webunit/parser.rb +229 -0
- data/lib/webunit/response.rb +464 -0
- data/lib/webunit/runtest.rb +41 -0
- data/lib/webunit/table.rb +148 -0
- data/lib/webunit/testcase.rb +45 -0
- data/lib/webunit/ui/cui/testrunner.rb +50 -0
- data/lib/webunit/utils.rb +68 -0
- data/lib/webunit/webunit.rb +28 -0
- data/test/dev/action.rb +83 -0
- data/test/dev/forms.rb +104 -0
- data/test/dev/forms2.rb +104 -0
- data/test/dev/parser.rb +17 -0
- data/test/dev/scripts/dump.rb +24 -0
- data/test/dev/scripts/makedist.rb +62 -0
- data/test/dev/scripts/uri.rb +41 -0
- data/test/dev/scripts/uri/common.rb +432 -0
- data/test/dev/scripts/uri/ftp.rb +149 -0
- data/test/dev/scripts/uri/generic.rb +1106 -0
- data/test/dev/scripts/uri/http.rb +76 -0
- data/test/dev/scripts/uri/https.rb +26 -0
- data/test/dev/scripts/uri/ldap.rb +238 -0
- data/test/dev/scripts/uri/mailto.rb +260 -0
- data/test/dev/scripts/urireg.rb +174 -0
- data/test/dev/simpledispatcher.rb +156 -0
- data/test/dev/test.action.rb +146 -0
- data/test/dev/test.formreader.rb +463 -0
- data/test/dev/test.simpledispatcher.rb +186 -0
- data/test/dev/webunit/conv/digit-0.rb +21 -0
- data/test/dev/webunit/conv/digit-1.rb +17 -0
- data/test/dev/webunit/conv/digit.rb +23 -0
- data/test/dev/webunit/conv/test_digit-0.rb +16 -0
- data/test/dev/webunit/conv/test_digit-1.rb +19 -0
- data/test/dev/webunit/conv/test_digit.rb +26 -0
- data/test/dev/webunit/conv/test_digit_view-0.rb +76 -0
- data/test/dev/webunit/conv/test_digit_view-1.rb +102 -0
- data/test/dev/webunit/conv/test_digit_view.rb +134 -0
- data/test/installation/htdocs/cgi_test.rb +296 -0
- data/test/installation/htdocs/test_install.rb +4 -0
- data/test/installation/runwebtest.rb +5 -0
- data/test/installation/test_cookie.rb +128 -0
- data/test/installation/test_form.rb +47 -0
- data/test/installation/test_multipart.rb +51 -0
- data/test/installation/test_request.rb +24 -0
- data/test/installation/test_response.rb +35 -0
- data/test/unit/htdocs/cookie.rb +32 -0
- data/test/unit/htdocs/multipart.rb +28 -0
- data/test/unit/htdocs/redirect.rb +12 -0
- data/test/unit/htdocs/simple.rb +13 -0
- data/test/unit/htdocs/stock.rb +33 -0
- data/test/unit/test_assert.rb +162 -0
- data/test/unit/test_cookie.rb +114 -0
- data/test/unit/test_domwalker.rb +77 -0
- data/test/unit/test_form.rb +42 -0
- data/test/unit/test_frame.rb +40 -0
- data/test/unit/test_htmlelem.rb +74 -0
- data/test/unit/test_image.rb +45 -0
- data/test/unit/test_jscript.rb +57 -0
- data/test/unit/test_link.rb +85 -0
- data/test/unit/test_multipart.rb +51 -0
- data/test/unit/test_params.rb +210 -0
- data/test/unit/test_parser.rb +53 -0
- data/test/unit/test_response.rb +150 -0
- data/test/unit/test_table.rb +70 -0
- data/test/unit/test_utils.rb +106 -0
- data/test/unit/test_webunit.rb +28 -0
- data/test/web/mod_ruby_stub.rb +39 -0
- data/test/web/test.assertinclude.rb +109 -0
- data/test/web/test.buffer.rb +182 -0
- data/test/web/test.code.loader.rb +78 -0
- data/test/web/test.config.rb +31 -0
- data/test/web/test.error.handling.rb +91 -0
- data/test/web/test.formreader-2.0.rb +352 -0
- data/test/web/test.load.rb +125 -0
- data/test/web/test.mime-type.rb +23 -0
- data/test/web/test.narf.cgi.rb +106 -0
- data/test/web/test.phprb.rb +239 -0
- data/test/web/test.request.rb +368 -0
- data/test/web/test.response.rb +637 -0
- data/test/web/test.ruby-web.rb +10 -0
- data/test/web/test.session.rb +50 -0
- data/test/web/test.shim.cgi.rb +96 -0
- data/test/web/test.tagparser.rb +65 -0
- data/test/web/test.template2.rb +297 -0
- data/test/web/test.testing2.rb +318 -0
- data/test/web/test.upload.rb +45 -0
- data/test/web/test.validate.rb +46 -0
- data/test/web/test.web.test.rb +495 -0
- data/test/wiki/test.history.rb +297 -0
- data/test/wiki/test.illustration_page.rb +287 -0
- data/test/wiki/test.linker.rb +197 -0
- data/test/wiki/test.tarpit.rb +56 -0
- data/test/wiki/test.wiki.rb +300 -0
- data/test/wikitestroot/admin.rb +7 -0
- data/test/wikitestroot/wiki.rb +6 -0
- metadata +234 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
module Web
|
|
2
|
+
def Web::lib_filename( resource, dirname="missing" )
|
|
3
|
+
if dirname == "missing"
|
|
4
|
+
dirname = File.dirname( Web::parse_trace( caller[1] ).shift )
|
|
5
|
+
end
|
|
6
|
+
File.join( dirname, resource )
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def Web::lib_file_contents( filename, dirname="missing" )
|
|
10
|
+
File.open( lib_filename( filename, dirname ), 'r' ) { |f|
|
|
11
|
+
f.read
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def Web::send_lib_file( filename, dirname = "missing" )
|
|
16
|
+
Web::connection::send_file( Web::lib_filename( filename, dirname ) )
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def Web::escape(string)
|
|
20
|
+
return nil unless string
|
|
21
|
+
string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
|
|
22
|
+
'%' + $1.unpack('H2' * $1.size).join('%').upcase
|
|
23
|
+
end.tr(' ', '+')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def Web::unescape(string)
|
|
28
|
+
return nil unless string
|
|
29
|
+
string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
|
|
30
|
+
[$1.delete('%')].pack('H*')
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def Web::escape_html(string)
|
|
36
|
+
return nil unless string
|
|
37
|
+
string.gsub(/&/n, '&').gsub(/\"/n, '"').gsub(/>/n, '>').gsub(/</n, '<')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# include these methods with Web
|
|
41
|
+
def puts(*args)
|
|
42
|
+
Web::connection.puts(args)
|
|
43
|
+
end
|
|
44
|
+
def print(*args)
|
|
45
|
+
Web::connection.print(*args)
|
|
46
|
+
end
|
|
47
|
+
def write(*args)
|
|
48
|
+
Web::connection.write(*args)
|
|
49
|
+
end
|
|
50
|
+
def escape_html(string)
|
|
51
|
+
Web::escape_html(string)
|
|
52
|
+
end
|
|
53
|
+
def unescape_html(string)
|
|
54
|
+
Web::unescape_html(string)
|
|
55
|
+
end
|
|
56
|
+
def escape_element(string, *elements)
|
|
57
|
+
Web::escape_element(string, *elements)
|
|
58
|
+
end
|
|
59
|
+
def unescape_element(string, *elements)
|
|
60
|
+
Web::unescape_element(string, *elements)
|
|
61
|
+
end
|
|
62
|
+
alias escapeHTML escape_html
|
|
63
|
+
alias html_encode escape_html
|
|
64
|
+
alias unescapeHTML unescape_html
|
|
65
|
+
alias escapeElement escape_element
|
|
66
|
+
alias unescapeElement unescape_element
|
|
67
|
+
def rfc1123_date(time)
|
|
68
|
+
Web::rfc1123_date(time)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def Web::unescape_html(string)
|
|
72
|
+
return nil unless string
|
|
73
|
+
string.gsub(/&(.*?);/n) do
|
|
74
|
+
match = $1.dup
|
|
75
|
+
case match
|
|
76
|
+
when /\Aamp\z/ni then '&'
|
|
77
|
+
when /\Aquot\z/ni then '"'
|
|
78
|
+
when /\Agt\z/ni then '>'
|
|
79
|
+
when /\Alt\z/ni then '<'
|
|
80
|
+
when /\A#0*(\d+)\z/n then
|
|
81
|
+
if Integer($1) < 256
|
|
82
|
+
Integer($1).chr
|
|
83
|
+
else
|
|
84
|
+
if Integer($1) < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U)
|
|
85
|
+
[Integer($1)].pack("U")
|
|
86
|
+
else
|
|
87
|
+
"&##{$1};"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
when /\A#x([0-9a-f]+)\z/ni then
|
|
91
|
+
if $1.hex < 256
|
|
92
|
+
$1.hex.chr
|
|
93
|
+
else
|
|
94
|
+
if $1.hex < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U)
|
|
95
|
+
[$1.hex].pack("U")
|
|
96
|
+
else
|
|
97
|
+
"&#x#{$1};"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
else
|
|
101
|
+
"&#{match};"
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def Web::escape_element(string, *elements)
|
|
108
|
+
return nil unless string
|
|
109
|
+
elements = elements[0] if elements[0].kind_of?(Array)
|
|
110
|
+
unless elements.empty?
|
|
111
|
+
string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do
|
|
112
|
+
Web::escape_html($&)
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
string
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def Web::unescape_element(string, *elements)
|
|
121
|
+
return nil unless string
|
|
122
|
+
elements = elements[0] if elements[0].kind_of?(Array)
|
|
123
|
+
unless elements.empty?
|
|
124
|
+
string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do
|
|
125
|
+
Web::unescape_html($&)
|
|
126
|
+
end
|
|
127
|
+
else
|
|
128
|
+
string
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
class << self
|
|
133
|
+
alias escapeHTML escape_html
|
|
134
|
+
alias html_encode escape_html
|
|
135
|
+
alias unescapeHTML unescape_html
|
|
136
|
+
alias escapeElement escape_element
|
|
137
|
+
alias unescapeElement unescape_element
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
|
|
141
|
+
RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
|
|
142
|
+
def Web::rfc1123_date(time)
|
|
143
|
+
t = time.clone.gmtime
|
|
144
|
+
return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
|
|
145
|
+
RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
|
|
146
|
+
t.hour, t.min, t.sec)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def Web::parse_trace(line)
|
|
150
|
+
line =~ /^((\w:){0,1}.*?):(\d+)(:?(.*))$/
|
|
151
|
+
[ $1, $3, $5 ]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
end
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
class FormReader #:nodoc: all
|
|
2
|
+
attr_accessor :html
|
|
3
|
+
alias :body :html
|
|
4
|
+
attr_reader :url
|
|
5
|
+
def initialize( html )
|
|
6
|
+
@html = html
|
|
7
|
+
@html_tree = nil
|
|
8
|
+
@parsed = nil
|
|
9
|
+
@url = ""
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def get_content
|
|
13
|
+
html
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_writer :forms
|
|
17
|
+
def forms
|
|
18
|
+
@forms ||= { }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def [] (key)
|
|
22
|
+
# ugly ugly ugly
|
|
23
|
+
form_elements( key )
|
|
24
|
+
forms[key]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def form_elements( name )
|
|
28
|
+
unless( forms[name] )
|
|
29
|
+
html_tree.get_elements("form").each{ |form|
|
|
30
|
+
if (name == form.attribute("name"))
|
|
31
|
+
forms[name] ||= FormElements.new
|
|
32
|
+
|
|
33
|
+
forms[name].action = form.attribute("action")
|
|
34
|
+
|
|
35
|
+
form.get_elements("input").each{ |e|
|
|
36
|
+
if ["text","hidden","submit","password","file"].include? e.attribute("type") or e.attribute("type").nil?
|
|
37
|
+
forms[name].push_text( e.attribute("name"),
|
|
38
|
+
Web.unescape(e.attribute("value")) || "" )
|
|
39
|
+
elsif e.attribute("type") == "checkbox"
|
|
40
|
+
# boolean checkboxes
|
|
41
|
+
# - assumed if there is no value
|
|
42
|
+
if (e.attribute("value") == "" || e.attribute("value").nil?)
|
|
43
|
+
forms[name].push( e.attribute("name"),
|
|
44
|
+
if (e.attribute("checked"))
|
|
45
|
+
true
|
|
46
|
+
else
|
|
47
|
+
false
|
|
48
|
+
end )
|
|
49
|
+
else
|
|
50
|
+
# multi select checkboxes
|
|
51
|
+
select = forms[name].find_select( e.attribute("name") )
|
|
52
|
+
select.multiple = true
|
|
53
|
+
select.push_option(e)
|
|
54
|
+
end
|
|
55
|
+
elsif e.attribute("type") == "radio"
|
|
56
|
+
select = forms[name].find_select( e.attribute("name") )
|
|
57
|
+
select.multiple = false
|
|
58
|
+
select.push_option(e)
|
|
59
|
+
elsif e.attribute("type") == "file"
|
|
60
|
+
end
|
|
61
|
+
}
|
|
62
|
+
form.get_elements("textarea").each{ |e|
|
|
63
|
+
forms[name].push_text e.attribute("name"), e.content.to_s.strip
|
|
64
|
+
}
|
|
65
|
+
form.get_elements("select").each { |e|
|
|
66
|
+
select = Select.new
|
|
67
|
+
select.multiple = e.attribute("multiple") != nil
|
|
68
|
+
e.get_elements("option").each{ |option|
|
|
69
|
+
select.shift_option( option )
|
|
70
|
+
}
|
|
71
|
+
forms[name].push_select e.attribute("name"), select
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
forms[name]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def get_fields( name )
|
|
80
|
+
form_elements(name).get_fields
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def get_options( name )
|
|
84
|
+
form_elements(name).get_options
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def html_tree
|
|
88
|
+
unless (@html_tree)
|
|
89
|
+
p = HTMLTree::Parser.new(true, false)
|
|
90
|
+
p.feed get_content
|
|
91
|
+
@html_tree = p.tree
|
|
92
|
+
end
|
|
93
|
+
@html_tree
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def merge_fields( name, edited_fields )
|
|
98
|
+
form_elements(name).merge_fields(edited_fields)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
class Option
|
|
102
|
+
attr_accessor :value, :selected
|
|
103
|
+
def initialize( value, selected )
|
|
104
|
+
@value = value; @selected = selected
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class Select
|
|
109
|
+
attr_accessor :options, :multiple
|
|
110
|
+
def initialize
|
|
111
|
+
@options = Array.new
|
|
112
|
+
@multiple = false
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def shift_option( option )
|
|
116
|
+
options.unshift(make_option_from_element(option))
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def push_option( option )
|
|
120
|
+
options.push(make_option_from_element(option))
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def make_option_from_element( element )
|
|
124
|
+
value = element.attribute("value")
|
|
125
|
+
unless value
|
|
126
|
+
value = element.content.to_s
|
|
127
|
+
value.gsub!( /<[^>]*>/, "" )
|
|
128
|
+
value.strip!
|
|
129
|
+
end
|
|
130
|
+
Option.new( value,
|
|
131
|
+
element.attribute("selected") || \
|
|
132
|
+
element.attribute("checked") )
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def each
|
|
136
|
+
options.each{ |option|
|
|
137
|
+
yield option.value if option.selected
|
|
138
|
+
}
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
include Enumerable
|
|
142
|
+
|
|
143
|
+
def == other
|
|
144
|
+
if other.kind_of?(String) && self.to_a.length == 1
|
|
145
|
+
other == self.to_a[0]
|
|
146
|
+
else
|
|
147
|
+
other == self.to_a
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# these functions are the interface for assert_includes
|
|
152
|
+
# we delegate to the array... but also answer to the options hash
|
|
153
|
+
def has_key?(index)
|
|
154
|
+
self.to_a.has_key?(index)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def __index(key)
|
|
158
|
+
self.to_a.__index(key)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def compare_includes? haystack, prefix=[]
|
|
162
|
+
self.to_a.compare_includes? haystack, prefix
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
class FormElements
|
|
168
|
+
attr_reader :fields
|
|
169
|
+
attr_accessor :action
|
|
170
|
+
|
|
171
|
+
def initialize
|
|
172
|
+
@fields = {}
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def get_fields
|
|
176
|
+
crushedFields = { }
|
|
177
|
+
@fields.each{ |k,v|
|
|
178
|
+
v = v.collect { |v1|
|
|
179
|
+
if v1.kind_of? Select
|
|
180
|
+
v1.to_a.sort
|
|
181
|
+
else
|
|
182
|
+
v1
|
|
183
|
+
end
|
|
184
|
+
}.flatten
|
|
185
|
+
crushedFields[k] = v
|
|
186
|
+
}
|
|
187
|
+
Web::Testing::MultiHashTree.new(crushedFields).fields
|
|
188
|
+
#crushedFields
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def get_options
|
|
192
|
+
all_options = { }
|
|
193
|
+
@fields.each{ |k,v|
|
|
194
|
+
v.each { |field|
|
|
195
|
+
if (field.kind_of? Select)
|
|
196
|
+
all_options[k] = field.options.collect{ |o|
|
|
197
|
+
o.value
|
|
198
|
+
}
|
|
199
|
+
end
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
all_options
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def merge_fields( edited_fields )
|
|
206
|
+
merged = Marshal.load( Marshal.dump( @fields ) )
|
|
207
|
+
|
|
208
|
+
edited_fields.each{ |k,v|
|
|
209
|
+
# normalize inputs
|
|
210
|
+
k = k.to_s
|
|
211
|
+
v = [v] unless v.kind_of? Array
|
|
212
|
+
|
|
213
|
+
# guard against errors
|
|
214
|
+
if merged[k].nil?
|
|
215
|
+
raise Web::Testing::FieldNotFoundException.new( "Element named #{k} not present on form" )
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
if (v.size > merged[k].size)
|
|
219
|
+
raise FormMergeError.new( "Only #{merged[k].size} elements on form; " +
|
|
220
|
+
"Can't merge with #{v.size} new values" )
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
v.each_with_index{ |v, i|
|
|
224
|
+
pristine = @fields[k][i]
|
|
225
|
+
target = merged[k][i]
|
|
226
|
+
|
|
227
|
+
if (pristine.kind_of? Select)
|
|
228
|
+
# guard against improperly submitted values
|
|
229
|
+
unless v.kind_of? Hash
|
|
230
|
+
raise FormMergeError.new( "Values for select elements must be merged in by using merge('#{k}'=>select('#{v}')" )
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# guard against merging multiple
|
|
234
|
+
# values into single select
|
|
235
|
+
if (pristine.multiple == false) & (v.keys.length > 1 )
|
|
236
|
+
raise FormMergeError.new( "Trying to merge multiple [#{ v.inspect }] into single select[#{ k }]" )
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# selects must be merged with a hash
|
|
240
|
+
v.each{ |value, flag|
|
|
241
|
+
# guard against merging nonexistent option
|
|
242
|
+
unless pristine.options.find{ |e|
|
|
243
|
+
e.value == value
|
|
244
|
+
}
|
|
245
|
+
raise FormMergeError. \
|
|
246
|
+
new("Form doesn't have an option for #{value}")
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# turn off everything else for single selects
|
|
251
|
+
|
|
252
|
+
unless target.multiple || flag == false
|
|
253
|
+
target.options.each { |o|
|
|
254
|
+
o.selected = false
|
|
255
|
+
}
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# merge select fields
|
|
259
|
+
target.options.find{ |e|
|
|
260
|
+
e.value == value
|
|
261
|
+
}.selected = flag
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
else
|
|
265
|
+
merged[k][i] = v
|
|
266
|
+
end
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
# delete unchecked checkboxes
|
|
271
|
+
merged.delete_if{ |k,v|
|
|
272
|
+
v.delete_if{ |e|
|
|
273
|
+
e == false
|
|
274
|
+
}
|
|
275
|
+
v.size == 0
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
# flatten out select elements
|
|
281
|
+
merged.each{ |k,v|
|
|
282
|
+
merged[k] = v.collect{ |e|
|
|
283
|
+
if (e.kind_of? Select)
|
|
284
|
+
e.to_a
|
|
285
|
+
else
|
|
286
|
+
e
|
|
287
|
+
end
|
|
288
|
+
}.flatten
|
|
289
|
+
}
|
|
290
|
+
merged
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def push( name, value )
|
|
294
|
+
@fields[name] ||= []
|
|
295
|
+
@fields[name].push value
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def find_select( name )
|
|
299
|
+
select = if (fields[name])
|
|
300
|
+
fields[name].find{ |e|
|
|
301
|
+
e.kind_of? Select
|
|
302
|
+
}
|
|
303
|
+
end
|
|
304
|
+
unless select
|
|
305
|
+
select = Select.new
|
|
306
|
+
push name, select
|
|
307
|
+
end
|
|
308
|
+
select
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
alias :push_text :push
|
|
312
|
+
alias :push_select :push
|
|
313
|
+
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
class FormMergeError < Exception #:nodoc: all
|
|
318
|
+
end
|