ruby-web 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (190) hide show
  1. data/ChangeLog +474 -0
  2. data/INSTALL.txt +9 -0
  3. data/InstalledFiles +180 -0
  4. data/LICENSE.txt +74 -0
  5. data/Rakefile +529 -0
  6. data/TODO +65 -0
  7. data/doc/additional.xml +149 -0
  8. data/doc/core.xml +652 -0
  9. data/doc/credits/index.xml +52 -0
  10. data/doc/credits/php.contributors.xml +118 -0
  11. data/doc/credits/php.language-snippets.ent +622 -0
  12. data/doc/install/index.xml +136 -0
  13. data/doc/install/mac/index.xml +21 -0
  14. data/doc/install/ruby-web.install.rb.instructions.xml +7 -0
  15. data/doc/install/unix/index.xml +46 -0
  16. data/doc/install/win/apache1.xml +166 -0
  17. data/doc/install/win/apache2.xml +141 -0
  18. data/doc/install/win/iis.xml +162 -0
  19. data/doc/install/win/index.xml +24 -0
  20. data/doc/install/win/installer.xml +31 -0
  21. data/doc/install/win/manual.xml +43 -0
  22. data/doc/manual.xml +69 -0
  23. data/doc/old/apache_cgi.txt +23 -0
  24. data/doc/old/fastcgi.txt +23 -0
  25. data/doc/old/mod_ruby.txt +21 -0
  26. data/doc/old/snippets.rdoc +183 -0
  27. data/doc/old/webrick.txt +23 -0
  28. data/doc/old/windows_cgi.txt +9 -0
  29. data/doc/tutorial.xml +14 -0
  30. data/doc/xsl/manual-multi.xsl +10 -0
  31. data/doc/xsl/manual-pdf.xsl +6 -0
  32. data/doc/xsl/manual-single.xsl +6 -0
  33. data/doc/xsl/manual.css +22 -0
  34. data/install.rb +1022 -0
  35. data/lib/formatter.rb +314 -0
  36. data/lib/html-parser.rb +429 -0
  37. data/lib/htmlrepair.rb +113 -0
  38. data/lib/htmlsplit.rb +842 -0
  39. data/lib/sgml-parser.rb +332 -0
  40. data/lib/web.rb +68 -0
  41. data/lib/web/assertinclude.rb +129 -0
  42. data/lib/web/config.rb +50 -0
  43. data/lib/web/connection.rb +1070 -0
  44. data/lib/web/convenience.rb +154 -0
  45. data/lib/web/formreader.rb +318 -0
  46. data/lib/web/htmlparser/html-parser.rb +429 -0
  47. data/lib/web/htmlparser/sgml-parser.rb +332 -0
  48. data/lib/web/htmltools/element.rb +296 -0
  49. data/lib/web/htmltools/stparser.rb +276 -0
  50. data/lib/web/htmltools/tags.rb +286 -0
  51. data/lib/web/htmltools/tree.rb +139 -0
  52. data/lib/web/htmltools/xmltree.rb +160 -0
  53. data/lib/web/htmltools/xpath.rb +71 -0
  54. data/lib/web/info.rb +63 -0
  55. data/lib/web/load.rb +210 -0
  56. data/lib/web/mime.rb +87 -0
  57. data/lib/web/phprb.rb +340 -0
  58. data/lib/web/resources/test/cookie.rb +33 -0
  59. data/lib/web/resources/test/counter.rb +20 -0
  60. data/lib/web/resources/test/multipart.rb +14 -0
  61. data/lib/web/resources/test/redirect.rb +8 -0
  62. data/lib/web/resources/test/stock.rb +33 -0
  63. data/lib/web/sapi/apache.rb +129 -0
  64. data/lib/web/sapi/fastcgi.rb +22 -0
  65. data/lib/web/sapi/install/apache.rb +180 -0
  66. data/lib/web/sapi/install/iis.rb +93 -0
  67. data/lib/web/sapi/install/macosx.rb +90 -0
  68. data/lib/web/sapi/webrick.rb +86 -0
  69. data/lib/web/session.rb +83 -0
  70. data/lib/web/shim/cgi.rb +129 -0
  71. data/lib/web/shim/rails.rb +175 -0
  72. data/lib/web/stringio.rb +78 -0
  73. data/lib/web/strscanparser.rb +24 -0
  74. data/lib/web/tagparser.rb +96 -0
  75. data/lib/web/testing.rb +666 -0
  76. data/lib/web/traceoutput.rb +75 -0
  77. data/lib/web/unit.rb +56 -0
  78. data/lib/web/upload.rb +59 -0
  79. data/lib/web/validate.rb +52 -0
  80. data/lib/web/wiki.rb +557 -0
  81. data/lib/web/wiki/linker.rb +72 -0
  82. data/lib/web/wiki/page.rb +201 -0
  83. data/lib/webunit.rb +27 -0
  84. data/lib/webunit/assert.rb +152 -0
  85. data/lib/webunit/converter.rb +154 -0
  86. data/lib/webunit/cookie.rb +118 -0
  87. data/lib/webunit/domwalker.rb +185 -0
  88. data/lib/webunit/exception.rb +14 -0
  89. data/lib/webunit/form.rb +116 -0
  90. data/lib/webunit/frame.rb +37 -0
  91. data/lib/webunit/htmlelem.rb +122 -0
  92. data/lib/webunit/image.rb +26 -0
  93. data/lib/webunit/jscript.rb +31 -0
  94. data/lib/webunit/link.rb +33 -0
  95. data/lib/webunit/params.rb +321 -0
  96. data/lib/webunit/parser.rb +229 -0
  97. data/lib/webunit/response.rb +464 -0
  98. data/lib/webunit/runtest.rb +41 -0
  99. data/lib/webunit/table.rb +148 -0
  100. data/lib/webunit/testcase.rb +45 -0
  101. data/lib/webunit/ui/cui/testrunner.rb +50 -0
  102. data/lib/webunit/utils.rb +68 -0
  103. data/lib/webunit/webunit.rb +28 -0
  104. data/test/dev/action.rb +83 -0
  105. data/test/dev/forms.rb +104 -0
  106. data/test/dev/forms2.rb +104 -0
  107. data/test/dev/parser.rb +17 -0
  108. data/test/dev/scripts/dump.rb +24 -0
  109. data/test/dev/scripts/makedist.rb +62 -0
  110. data/test/dev/scripts/uri.rb +41 -0
  111. data/test/dev/scripts/uri/common.rb +432 -0
  112. data/test/dev/scripts/uri/ftp.rb +149 -0
  113. data/test/dev/scripts/uri/generic.rb +1106 -0
  114. data/test/dev/scripts/uri/http.rb +76 -0
  115. data/test/dev/scripts/uri/https.rb +26 -0
  116. data/test/dev/scripts/uri/ldap.rb +238 -0
  117. data/test/dev/scripts/uri/mailto.rb +260 -0
  118. data/test/dev/scripts/urireg.rb +174 -0
  119. data/test/dev/simpledispatcher.rb +156 -0
  120. data/test/dev/test.action.rb +146 -0
  121. data/test/dev/test.formreader.rb +463 -0
  122. data/test/dev/test.simpledispatcher.rb +186 -0
  123. data/test/dev/webunit/conv/digit-0.rb +21 -0
  124. data/test/dev/webunit/conv/digit-1.rb +17 -0
  125. data/test/dev/webunit/conv/digit.rb +23 -0
  126. data/test/dev/webunit/conv/test_digit-0.rb +16 -0
  127. data/test/dev/webunit/conv/test_digit-1.rb +19 -0
  128. data/test/dev/webunit/conv/test_digit.rb +26 -0
  129. data/test/dev/webunit/conv/test_digit_view-0.rb +76 -0
  130. data/test/dev/webunit/conv/test_digit_view-1.rb +102 -0
  131. data/test/dev/webunit/conv/test_digit_view.rb +134 -0
  132. data/test/installation/htdocs/cgi_test.rb +296 -0
  133. data/test/installation/htdocs/test_install.rb +4 -0
  134. data/test/installation/runwebtest.rb +5 -0
  135. data/test/installation/test_cookie.rb +128 -0
  136. data/test/installation/test_form.rb +47 -0
  137. data/test/installation/test_multipart.rb +51 -0
  138. data/test/installation/test_request.rb +24 -0
  139. data/test/installation/test_response.rb +35 -0
  140. data/test/unit/htdocs/cookie.rb +32 -0
  141. data/test/unit/htdocs/multipart.rb +28 -0
  142. data/test/unit/htdocs/redirect.rb +12 -0
  143. data/test/unit/htdocs/simple.rb +13 -0
  144. data/test/unit/htdocs/stock.rb +33 -0
  145. data/test/unit/test_assert.rb +162 -0
  146. data/test/unit/test_cookie.rb +114 -0
  147. data/test/unit/test_domwalker.rb +77 -0
  148. data/test/unit/test_form.rb +42 -0
  149. data/test/unit/test_frame.rb +40 -0
  150. data/test/unit/test_htmlelem.rb +74 -0
  151. data/test/unit/test_image.rb +45 -0
  152. data/test/unit/test_jscript.rb +57 -0
  153. data/test/unit/test_link.rb +85 -0
  154. data/test/unit/test_multipart.rb +51 -0
  155. data/test/unit/test_params.rb +210 -0
  156. data/test/unit/test_parser.rb +53 -0
  157. data/test/unit/test_response.rb +150 -0
  158. data/test/unit/test_table.rb +70 -0
  159. data/test/unit/test_utils.rb +106 -0
  160. data/test/unit/test_webunit.rb +28 -0
  161. data/test/web/mod_ruby_stub.rb +39 -0
  162. data/test/web/test.assertinclude.rb +109 -0
  163. data/test/web/test.buffer.rb +182 -0
  164. data/test/web/test.code.loader.rb +78 -0
  165. data/test/web/test.config.rb +31 -0
  166. data/test/web/test.error.handling.rb +91 -0
  167. data/test/web/test.formreader-2.0.rb +352 -0
  168. data/test/web/test.load.rb +125 -0
  169. data/test/web/test.mime-type.rb +23 -0
  170. data/test/web/test.narf.cgi.rb +106 -0
  171. data/test/web/test.phprb.rb +239 -0
  172. data/test/web/test.request.rb +368 -0
  173. data/test/web/test.response.rb +637 -0
  174. data/test/web/test.ruby-web.rb +10 -0
  175. data/test/web/test.session.rb +50 -0
  176. data/test/web/test.shim.cgi.rb +96 -0
  177. data/test/web/test.tagparser.rb +65 -0
  178. data/test/web/test.template2.rb +297 -0
  179. data/test/web/test.testing2.rb +318 -0
  180. data/test/web/test.upload.rb +45 -0
  181. data/test/web/test.validate.rb +46 -0
  182. data/test/web/test.web.test.rb +495 -0
  183. data/test/wiki/test.history.rb +297 -0
  184. data/test/wiki/test.illustration_page.rb +287 -0
  185. data/test/wiki/test.linker.rb +197 -0
  186. data/test/wiki/test.tarpit.rb +56 -0
  187. data/test/wiki/test.wiki.rb +300 -0
  188. data/test/wikitestroot/admin.rb +7 -0
  189. data/test/wikitestroot/wiki.rb +6 -0
  190. metadata +234 -0
@@ -0,0 +1,104 @@
1
+
2
+ class Date # :nodoc:
3
+ def _dump(limit) Marshal.dump([@rjd, @sg], -1) end
4
+ def self._load(str) new0(*Marshal.load(str)) end
5
+ end
6
+
7
+ def encode64(bin) # :nodoc:
8
+ [bin].pack("m").gsub(/\n/,'').gsub(/=/,'.')
9
+ end
10
+
11
+ def decode64(str) # :nodoc:
12
+ str.gsub(/\./,'=').unpack("m")[0]
13
+ end
14
+
15
+
16
+ module Web
17
+ module Request # :nodoc
18
+ def Request.typed_params params
19
+ params2 = {}
20
+ params.collect do |k,v|
21
+ if ! (k =~ /type/)
22
+ if (atype = params["#{k}-type"][0])
23
+ begin
24
+ params2[k] = eval(Web.unescape(atype)).unencode(v[0])
25
+ rescue
26
+ params2[k] = eval(Web.unescape(atype)).unencode(Web.unescape(v[0]))
27
+ end
28
+ else
29
+ if v[0].kind_of? String
30
+ params2[k] = v[0]
31
+ else
32
+ params2[k] = v[0]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ params2
38
+ end
39
+
40
+ def Request.parse_typed_params query_string
41
+ Request.typed_params(Web::Request.parse_query_string(query_string))
42
+ end
43
+ end
44
+
45
+ class << self
46
+ def encode_objects hash
47
+ newhash = {}
48
+ hash.each do |k,v|
49
+ v = ([] << v).flatten
50
+ v.each { |v|
51
+ if v.kind_of?(String)
52
+ newhash[k] = v
53
+ elsif
54
+ newhash[k] = Web.escape(v.encode)
55
+ newhash["#{k}-type"] = v.class.name
56
+ end
57
+ }
58
+ end
59
+ newhash
60
+ end
61
+
62
+ def typed_params
63
+ $__web__cgi.typed_params
64
+ end
65
+ end
66
+
67
+ class CGI
68
+ def typed_params
69
+ Request.typed_params multiple_params
70
+ end
71
+
72
+ def make_query_string params
73
+ params.collect do |a,b|
74
+ "#{a}=#{Web.escape(b)}"
75
+ end.join("&")
76
+ end
77
+
78
+ def query
79
+ if Web["__submitted"] != ""
80
+ aquery = {}
81
+ typed_params.each do |k,v|
82
+ if k =~ /^__q\.(.+)/
83
+ aquery[$1] = v
84
+ end
85
+ end
86
+ aquery
87
+ else
88
+ typed_params
89
+ end
90
+ end
91
+
92
+ def reset_headers
93
+ @headers_sent = false
94
+ end
95
+
96
+ def script_path
97
+ if m = /(.*)\//.match(Web.get_cgi.script_name)
98
+ $1
99
+ else
100
+ ""
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,104 @@
1
+
2
+ class Date # :nodoc:
3
+ def _dump(limit) Marshal.dump([@rjd, @sg], -1) end
4
+ def self._load(str) new0(*Marshal.load(str)) end
5
+ end
6
+
7
+ def encode64(bin) # :nodoc:
8
+ [bin].pack("m").gsub(/\n/,'').gsub(/=/,'.')
9
+ end
10
+
11
+ def decode64(str) # :nodoc:
12
+ str.gsub(/\./,'=').unpack("m")[0]
13
+ end
14
+
15
+
16
+ module Web
17
+ module Request # :nodoc
18
+ def Request.typed_params params
19
+ params2 = {}
20
+ params.collect do |k,v|
21
+ if ! (k =~ /type/)
22
+ if (atype = params["#{k}-type"][0])
23
+ begin
24
+ params2[k] = eval(Web.unescape(atype)).unencode(v[0])
25
+ rescue
26
+ params2[k] = eval(Web.unescape(atype)).unencode(Web.unescape(v[0]))
27
+ end
28
+ else
29
+ if v[0].kind_of? String
30
+ params2[k] = v[0]
31
+ else
32
+ params2[k] = v[0]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ params2
38
+ end
39
+
40
+ def Request.parse_typed_params query_string
41
+ Request.typed_params(Web::Request.parse_query_string(query_string))
42
+ end
43
+ end
44
+
45
+ class << self
46
+ def encode_objects hash
47
+ newhash = {}
48
+ hash.each do |k,v|
49
+ v = ([] << v).flatten
50
+ v.each { |v|
51
+ if v.kind_of?(String)
52
+ newhash[k] = v
53
+ elsif
54
+ newhash[k] = Web.escape(v.encode)
55
+ newhash["#{k}-type"] = v.class.name
56
+ end
57
+ }
58
+ end
59
+ newhash
60
+ end
61
+
62
+ def typed_params
63
+ $__web__cgi.typed_params
64
+ end
65
+ end
66
+
67
+ class CGI
68
+ def typed_params
69
+ Request.typed_params multiple_params
70
+ end
71
+
72
+ def make_query_string params
73
+ params.collect do |a,b|
74
+ "#{a}=#{Web.escape(b)}"
75
+ end.join("&")
76
+ end
77
+
78
+ def query
79
+ if Web["__submitted"] != ""
80
+ aquery = {}
81
+ typed_params.each do |k,v|
82
+ if k =~ /^__q\.(.+)/
83
+ aquery[$1] = v
84
+ end
85
+ end
86
+ aquery
87
+ else
88
+ typed_params
89
+ end
90
+ end
91
+
92
+ def reset_headers
93
+ @headers_sent = false
94
+ end
95
+
96
+ def script_path
97
+ if m = /(.*)\//.match(Web.get_cgi.script_name)
98
+ $1
99
+ else
100
+ ""
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,17 @@
1
+ # note this returns the un-arrayified version of the array
2
+ def parse_query_string_typed(query) #:nodoc: :notest:
3
+ params = parse_query_string query
4
+ params2 = {}
5
+ params.collect do |k,v|
6
+ if ! (k =~ /type/)
7
+ if (atype = params["#{k}#type"][0])
8
+ params2[k] = Module.const_get(atype.intern).unencode(v[0])
9
+ else
10
+ params2[k] = v[0]
11
+ end
12
+ end
13
+ end
14
+ params2
15
+ end
16
+
17
+
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/ruby
2
+
3
+ filename="/Users/patsplat/Desktop/temp.bin"
4
+
5
+ if (ENV['REQUEST_METHOD'] == "POST")
6
+ length = Integer(ENV['CONTENT_LENGTH'])
7
+ $stdin.binmode
8
+ contents = $stdin.read(length) or ''
9
+ File.open( filename, "w" ) { |file|
10
+ file.binmode
11
+ file.write( contents )
12
+ }
13
+ end
14
+
15
+ #Web['file'].save( '/Users/patsplat/Desktop/test.png' )
16
+
17
+ #Web::puts contents
18
+
19
+ #Web::send_file( '/Users/patsplat/Desktop/test.png' )
20
+
21
+ print "Content-type: text/html\r\n\r\n"
22
+ print "hello!<br>content-length: #{ length }<br>"
23
+ print "boundary: #{ ENV['CONTENT_TYPE'] }<br>"
24
+ print ENV.inspect
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/ruby
2
+
3
+ NARF_SVN_SERVER = "http://svn.narf-lib.org/svn/narf"
4
+
5
+ cwd = Dir.pwd
6
+
7
+ require 'ftools'
8
+
9
+ if ARGV.size != 3
10
+ puts "Usage: ruby scripts/makedist.rb username password 1.2.3"
11
+ puts ""
12
+ puts " * username and password are your narf svn credentials"
13
+ puts " * 1.2.3 is the narf release number"
14
+ exit
15
+ end
16
+
17
+ username = ARGV[0]
18
+ password = ARGV[1]
19
+ version = ARGV[2]
20
+
21
+ versiontag = "VERSION_#{version.gsub(/\./,'_')}"
22
+
23
+ system( "rm narf*.gem" )
24
+ gemspec = File.open( "narf.gemspec", "r" ) { |f|
25
+ f.read
26
+ }
27
+ gemspec.sub(/s.version = "\d.\d.\d"/,
28
+ "s.version = \"#{version}\"" )
29
+ File.open("narf.gemspec", "w" ) { |f|
30
+ f.write gemspec
31
+ }
32
+
33
+ svn = "svn --username #{username} --password #{ password }"
34
+ system( "#{svn} log > ChangeLog")
35
+ system( "#{svn} commit -m \"Preparing for #{version} release\"" )
36
+ system( "#{svn} delete #{NARF_SVN_SERVER}/releases/#{versiontag} -m \"Deleted any existing release branch for #{version}\"" )
37
+ system( "#{svn} copy #{NARF_SVN_SERVER}/trunk/ #{NARF_SVN_SERVER}/releases/#{versiontag} -m \"Created release branch for #{version}\"" )
38
+
39
+ Dir.mkdir( "../dist" ) unless( File.exists? "../dist" )
40
+ system("rm -Rf ../dist/narf-#{version}")
41
+ Dir.chdir("../dist")
42
+
43
+ system("#{svn} export #{NARF_SVN_SERVER}/releases/#{versiontag} narf-#{version}" )
44
+
45
+ system("cd narf-#{version}; ruby build.rb rdoc");
46
+ system("tar cvzf narf-#{version}.tgz narf-#{version}")
47
+
48
+ # update sourcefoge
49
+ system("ncftpput upload.sourceforge.net incoming narf-#{version}.tgz")
50
+
51
+ # build gems
52
+ Dir.chdir(cwd)
53
+ system("gem build narf.gemspec")
54
+ system("ncftpput upload.sourceforge.net incoming narf-#{version}.gem")
55
+
56
+ # update raa
57
+
58
+ # update ruby-forge
59
+
60
+
61
+
62
+
@@ -0,0 +1,41 @@
1
+ #
2
+ # $Id: uri.rb,v 1.1.1.1 2002/11/29 04:34:24 patsplat Exp $
3
+ #
4
+ # Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
5
+ # You can redistribute it and/or modify it under the same term as Ruby.
6
+ #
7
+
8
+ =begin
9
+
10
+ Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
11
+ You can redistribute it and/or modify it under the same term as Ruby.
12
+
13
+ = URI - URI support for Ruby
14
+
15
+ =end
16
+
17
+ module URI
18
+ VERSION_CODE = '000907'.freeze
19
+ VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
20
+ end
21
+
22
+ =begin
23
+
24
+ == Components
25
+
26
+ * ((<URI>)) Module
27
+ * ((<URI::Generic>)) Class
28
+ * ((<URI::FTP>)) Class
29
+ * ((<URI::HTTP>)) Class
30
+ * ((<URI::HTTPS>)) Class
31
+ * ((<URI::LDAP>)) Class
32
+ * ((<URI::MailTo>)) Class
33
+
34
+ =end
35
+ require 'uri/common'
36
+ require 'uri/generic'
37
+ require 'uri/ftp'
38
+ require 'uri/http'
39
+ require 'uri/https'
40
+ require 'uri/ldap'
41
+ require 'uri/mailto'
@@ -0,0 +1,432 @@
1
+ #
2
+ # $Id: common.rb,v 1.1.1.1 2002/11/29 04:34:25 patsplat Exp $
3
+ #
4
+ # Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
5
+ # You can redistribute it and/or modify it under the same term as Ruby.
6
+ #
7
+
8
+ =begin
9
+
10
+ == URI
11
+
12
+ =end
13
+
14
+ module URI
15
+ module REGEXP
16
+ module PATTERN
17
+ # RFC 2396 (URI Generic Syntax)
18
+ # RFC 2732 (IPv6 Literal Addresses in URL's)
19
+ # RFC 2373 (IPv6 Addressing Architecture)
20
+
21
+ # alpha = lowalpha | upalpha
22
+ ALPHA = "a-zA-Z"
23
+ # alphanum = alpha | digit
24
+ ALNUM = "#{ALPHA}\\d"
25
+
26
+ # hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
27
+ # "a" | "b" | "c" | "d" | "e" | "f"
28
+ HEX = "a-fA-F\\d"
29
+ # escaped = "%" hex hex
30
+ ESCAPED = "%[#{HEX}]{2}"
31
+ # mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
32
+ # "(" | ")"
33
+ # unreserved = alphanum | mark
34
+ UNRESERVED = "-_.!~*'()#{ALNUM}"
35
+ # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
36
+ # "$" | ","
37
+ # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
38
+ # "$" | "," | "[" | "]" (RFC 2732)
39
+ RESERVED = ";/?:@&=+$,\\[\\]"
40
+
41
+ # uric = reserved | unreserved | escaped
42
+ URIC = "(?:[#{UNRESERVED}#{RESERVED}]|#{ESCAPED})"
43
+ # uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
44
+ # "&" | "=" | "+" | "$" | ","
45
+ URIC_NO_SLASH = "(?:[#{UNRESERVED};?:@&=+$,]|#{ESCAPED})"
46
+ # query = *uric
47
+ QUERY = "#{URIC}*"
48
+ # fragment = *uric
49
+ FRAGMENT = "#{URIC}*"
50
+
51
+ # domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
52
+ DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
53
+ # toplabel = alpha | alpha *( alphanum | "-" ) alphanum
54
+ TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
55
+ # hostname = *( domainlabel "." ) toplabel [ "." ]
56
+ HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
57
+
58
+ # RFC 2373, APPENDIX B:
59
+ # IPv6address = hexpart [ ":" IPv4address ]
60
+ # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
61
+ # hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
62
+ # hexseq = hex4 *( ":" hex4)
63
+ # hex4 = 1*4HEXDIG
64
+ #
65
+ # XXX: This definition has a flaw. "::" + IPv4address must be
66
+ # allowed too. Here is a replacement.
67
+ #
68
+ # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
69
+ IPV4ADDR = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"
70
+ # hex4 = 1*4HEXDIG
71
+ HEX4 = "[#{HEX}]{1,4}"
72
+ # lastpart = hex4 | IPv4address
73
+ LASTPART = "(?:#{HEX4}|#{IPV4ADDR})"
74
+ # hexseq1 = *( hex4 ":" ) hex4
75
+ HEXSEQ1 = "(?:#{HEX4}:)*#{HEX4}"
76
+ # hexseq2 = *( hex4 ":" ) lastpart
77
+ HEXSEQ2 = "(?:#{HEX4}:)*#{LASTPART}"
78
+ # IPv6address = hexseq2 | [ hexseq1 ] "::" [ hexseq2 ]
79
+ IPV6ADDR = "(?:#{HEXSEQ2}|(?:#{HEXSEQ1})?::(?:#{HEXSEQ2})?)"
80
+
81
+ # IPv6prefix = ( hexseq1 | [ hexseq1 ] "::" [ hexseq1 ] ) "/" 1*2DIGIT
82
+ # unused
83
+
84
+ # ipv6reference = "[" IPv6address "]" (RFC 2732)
85
+ IPV6REF = "\\[#{IPV6ADDR}\\]"
86
+
87
+ # host = hostname | IPv4address
88
+ # host = hostname | IPv4address | IPv6reference (RFC 2732)
89
+ HOST = "(?:#{HOSTNAME}|#{IPV4ADDR}|#{IPV6REF})"
90
+ # port = *digit
91
+ PORT = "\d*"
92
+ # hostport = host [ ":" port ]
93
+ HOSTPORT = "#{HOST}(?:#{PORT})?"
94
+
95
+ # userinfo = *( unreserved | escaped |
96
+ # ";" | ":" | "&" | "=" | "+" | "$" | "," )
97
+ USERINFO = "(?:[#{UNRESERVED};:&=+$,]|#{ESCAPED})*"
98
+
99
+ # pchar = unreserved | escaped |
100
+ # ":" | "@" | "&" | "=" | "+" | "$" | ","
101
+ PCHAR = "(?:[#{UNRESERVED}:@&=+$,]|#{ESCAPED})"
102
+ # param = *pchar
103
+ PARAM = "#{PCHAR}*"
104
+ # segment = *pchar *( ";" param )
105
+ SEGMENT = "#{PCHAR}*(?:;#{PARAM})*"
106
+ # path_segments = segment *( "/" segment )
107
+ PATH_SEGMENTS = "#{SEGMENT}(?:/#{SEGMENT})*"
108
+
109
+ # server = [ [ userinfo "@" ] hostport ]
110
+ SERVER = "(?:#{USERINFO}@)?#{HOSTPORT}"
111
+ # reg_name = 1*( unreserved | escaped | "$" | "," |
112
+ # ";" | ":" | "@" | "&" | "=" | "+" )
113
+ REG_NAME = "(?:[#{UNRESERVED}$,;+@&=+]|#{ESCAPED})+"
114
+ # authority = server | reg_name
115
+ AUTHORITY = "(?:#{SERVER}|#{REG_NAME})"
116
+
117
+ # rel_segment = 1*( unreserved | escaped |
118
+ # ";" | "@" | "&" | "=" | "+" | "$" | "," )
119
+ REL_SEGMENT = "(?:[#{UNRESERVED};@&=+$,]|#{ESCAPED})+"
120
+
121
+ # scheme = alpha *( alpha | digit | "+" | "-" | "." )
122
+ SCHEME = "[#{ALPHA}][-+.#{ALPHA}\\d]*"
123
+
124
+ # abs_path = "/" path_segments
125
+ ABS_PATH = "/#{PATH_SEGMENTS}"
126
+ # rel_path = rel_segment [ abs_path ]
127
+ REL_PATH = "#{REL_SEGMENT}(?:#{ABS_PATH})?"
128
+ # net_path = "//" authority [ abs_path ]
129
+ NET_PATH = "//#{AUTHORITY}(?:#{ABS_PATH})?"
130
+
131
+ # hier_part = ( net_path | abs_path ) [ "?" query ]
132
+ HIER_PART = "(?:#{NET_PATH}|#{ABS_PATH})(?:\\?(?:#{QUERY}))?"
133
+ # opaque_part = uric_no_slash *uric
134
+ OPAQUE_PART = "#{URIC_NO_SLASH}#{URIC}*"
135
+
136
+ # absoluteURI = scheme ":" ( hier_part | opaque_part )
137
+ ABS_URI = "#{SCHEME}:(?:#{HIER_PART}|#{OPAQUE_PART})"
138
+ # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
139
+ REL_URI = "(?:#{NET_PATH}|#{ABS_PATH}|#{REL_PATH})(?:\\?#{QUERY})?"
140
+
141
+ # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
142
+ URI_REF = "(?:#{ABS_URI}|#{REL_URI})?(?:##{FRAGMENT})?"
143
+
144
+ # XXX:
145
+ X_ABS_URI = "
146
+ (#{PATTERN::SCHEME}): (?# 1: scheme)
147
+ (?:
148
+ (?:(?:
149
+ //(?:
150
+ (?:(?:(#{PATTERN::USERINFO})@)? (?# 2: userinfo)
151
+ (?:(#{PATTERN::HOST})(?::(\\d*))?))?(?# 3: host, 4: port)
152
+ |
153
+ (#{PATTERN::REG_NAME}) (?# 5: registry)
154
+ ))?
155
+ ((?!//)#{PATTERN::ABS_PATH})? (?# 6: path)
156
+ )(?:\\?(#{PATTERN::QUERY}))? (?# 7: query)
157
+ |
158
+ (#{PATTERN::OPAQUE_PART}) (?# 8: opaque)
159
+ )
160
+ (?:\\#(#{PATTERN::FRAGMENT}))? (?# 9: fragment)
161
+ "
162
+ X_REL_URI = "
163
+ (?:
164
+ (?:
165
+ //
166
+ (?:
167
+ (?:(#{PATTERN::USERINFO})@)? (?# 1: userinfo)
168
+ (#{PATTERN::HOST})?(?::(\\d*))? (?# 2: host, 3: port)
169
+ |
170
+ (#{PATTERN::REG_NAME}) (?# 4: registry)
171
+ )
172
+ )
173
+ |
174
+ (#{PATTERN::REL_SEGMENT}) (?# 5: rel_segment)
175
+ )?
176
+ (#{PATTERN::ABS_PATH})? (?# 6: abs_path)
177
+ (?:\\?(#{PATTERN::QUERY}))? (?# 7: query)
178
+ (?:\\#(#{PATTERN::FRAGMENT}))? (?# 8: fragment)
179
+ "
180
+ end # PATTERN
181
+
182
+ # for URI::split
183
+ ABS_URI = Regexp.new('^' + PATTERN::X_ABS_URI + '$', #'
184
+ Regexp::EXTENDED, 'N').freeze
185
+ REL_URI = Regexp.new('^' + PATTERN::X_REL_URI + '$', #'
186
+ Regexp::EXTENDED, 'N').freeze
187
+
188
+ # for URI::extract
189
+ URI_REF = Regexp.new(PATTERN::URI_REF, false, 'N').freeze
190
+ ABS_URI_REF = Regexp.new(PATTERN::X_ABS_URI, Regexp::EXTENDED, 'N').freeze
191
+ REL_URI_REF = Regexp.new(PATTERN::X_REL_URI, Regexp::EXTENDED, 'N').freeze
192
+
193
+ # for URI::escape/unescape
194
+ ESCAPED = Regexp.new(PATTERN::ESCAPED, false, 'N').freeze
195
+ UNSAFE = Regexp.new("[^#{PATTERN::UNRESERVED}#{PATTERN::RESERVED}]",
196
+ false, 'N').freeze
197
+
198
+ # for Generic#initialize
199
+ SCHEME = Regexp.new("^#{PATTERN::SCHEME}$", false, 'N').freeze #"
200
+ USERINFO = Regexp.new("^#{PATTERN::USERINFO}$", false, 'N').freeze #"
201
+ HOST = Regexp.new("^#{PATTERN::HOST}$", false, 'N').freeze #"
202
+ PORT = Regexp.new("^#{PATTERN::PORT}$", false, 'N').freeze #"
203
+ OPAQUE = Regexp.new("^#{PATTERN::OPAQUE_PART}$", false, 'N').freeze #"
204
+ REGISTRY = Regexp.new("^#{PATTERN::REG_NAME}$", false, 'N').freeze #"
205
+ ABS_PATH = Regexp.new("^#{PATTERN::ABS_PATH}$", false, 'N').freeze #"
206
+ REL_PATH = Regexp.new("^#{PATTERN::REL_PATH}$", false, 'N').freeze #"
207
+ QUERY = Regexp.new("^#{PATTERN::QUERY}$", false, 'N').freeze #"
208
+ FRAGMENT = Regexp.new("^#{PATTERN::FRAGMENT}$", false, 'N').freeze #"
209
+ end # REGEXP
210
+
211
+ module Util
212
+ def make_components_hash(klass, array_hash)
213
+ tmp = {}
214
+ if array_hash.kind_of?(Array) &&
215
+ array_hash.size == klass.component.size - 1
216
+ klass.component[1..-1].each_index do |i|
217
+ begin
218
+ tmp[klass.component[i + 1]] = array_hash[i].clone
219
+ rescue TypeError
220
+ tmp[klass.component[i + 1]] = array_hash[i]
221
+ end
222
+ end
223
+
224
+ elsif array_hash.kind_of?(Hash)
225
+ array_hash.each do |key, value|
226
+ begin
227
+ tmp[key] = value.clone
228
+ rescue TypeError
229
+ tmp[key] = value
230
+ end
231
+ end
232
+ else
233
+ raise ArgumentError,
234
+ "expected Array of or Hash of components of #{klass.to_s} (#{klass.component[1..-1].join(', ')})"
235
+ end
236
+ tmp[:scheme] = klass.to_s.sub(/\A.*::/, '').downcase
237
+
238
+ return tmp
239
+ end
240
+ module_function :make_components_hash
241
+ end
242
+
243
+ module Escape
244
+ include REGEXP
245
+
246
+ def escape(str, unsafe = UNSAFE)
247
+ unless unsafe.kind_of?(Regexp)
248
+ # perhaps unsafe is String object
249
+ unsafe = Regexp.new(Regexp.quote(unsafe), false, 'N')
250
+ end
251
+ str.gsub(unsafe) do |us|
252
+ tmp = ''
253
+ us.each_byte do |uc|
254
+ tmp << sprintf('%%%02X', uc)
255
+ end
256
+ tmp
257
+ end
258
+ end
259
+ alias encode escape
260
+
261
+ def unescape(str)
262
+ str.gsub(ESCAPED) do
263
+ $&[1,2].hex.chr
264
+ end
265
+ end
266
+ alias decode unescape
267
+ end
268
+
269
+ include REGEXP
270
+ extend Escape
271
+
272
+ @@schemes = {}
273
+
274
+ class Error < StandardError; end
275
+ class InvalidURIError < Error; end # it is not URI.
276
+ class InvalidComponentError < Error; end # it is not component of URI.
277
+ class BadURIError < Error; end # the URI is valid but it is bad for the position.
278
+
279
+ =begin
280
+
281
+ === Methods
282
+
283
+ --- URI::split(uri)
284
+
285
+ =end
286
+
287
+ def self.split(uri)
288
+ case uri
289
+ when ''
290
+ # null uri
291
+
292
+ when ABS_URI
293
+ scheme, userinfo, host, port,
294
+ registry, path, query, opaque, fragment = $~[1..-1]
295
+
296
+ # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
297
+
298
+ # absoluteURI = scheme ":" ( hier_part | opaque_part )
299
+ # hier_part = ( net_path | abs_path ) [ "?" query ]
300
+ # opaque_part = uric_no_slash *uric
301
+
302
+ # abs_path = "/" path_segments
303
+ # net_path = "//" authority [ abs_path ]
304
+
305
+ # authority = server | reg_name
306
+ # server = [ [ userinfo "@" ] hostport ]
307
+
308
+ if !scheme
309
+ raise InvalidURIError,
310
+ "bad URI(absolute but no scheme): #{uri}"
311
+ end
312
+ if !opaque && (!path && (!host && !registry))
313
+ raise InvalidURIError,
314
+ "bad URI(absolute but no path): #{uri}"
315
+ end
316
+
317
+ when REL_URI
318
+ scheme = nil
319
+ opaque = nil
320
+
321
+ userinfo, host, port, registry,
322
+ rel_segment, abs_path, query, fragment = $~[1..-1]
323
+ if rel_segment && abs_path
324
+ path = rel_segment + abs_path
325
+ elsif rel_segment
326
+ path = rel_segment
327
+ elsif abs_path
328
+ path = abs_path
329
+ end
330
+
331
+ # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
332
+
333
+ # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
334
+
335
+ # net_path = "//" authority [ abs_path ]
336
+ # abs_path = "/" path_segments
337
+ # rel_path = rel_segment [ abs_path ]
338
+
339
+ # authority = server | reg_name
340
+ # server = [ [ userinfo "@" ] hostport ]
341
+
342
+ else
343
+ raise InvalidURIError, "bad URI(is not URI?): #{uri}"
344
+ end
345
+
346
+ path = '' if !path && !opaque # (see RFC2396 Section 5.2)
347
+ ret = [
348
+ scheme,
349
+ userinfo, host, port, # X
350
+ registry, # X
351
+ path, # Y
352
+ opaque, # Y
353
+ query,
354
+ fragment
355
+ ]
356
+ return ret
357
+ end
358
+
359
+ =begin
360
+
361
+ --- URI::parse(uri_str)
362
+
363
+ =end
364
+ def self.parse(uri)
365
+ scheme, userinfo, host, port,
366
+ registry, path, opaque, query, fragment = self.split(uri)
367
+
368
+ if scheme && @@schemes.include?(scheme.upcase)
369
+ @@schemes[scheme.upcase].new(scheme, userinfo, host, port,
370
+ registry, path, opaque, query,
371
+ fragment)
372
+ else
373
+ Generic.new(scheme, userinfo, host, port,
374
+ registry, path, opaque, query,
375
+ fragment)
376
+ end
377
+ end
378
+
379
+ =begin
380
+
381
+ --- URI::join(str[, str, ...])
382
+
383
+ =end
384
+ def self.join(*str)
385
+ u = self.parse(str[0])
386
+ str[1 .. -1].each do |x|
387
+ u = u.merge(x)
388
+ end
389
+ u
390
+ end
391
+
392
+ =begin
393
+
394
+ --- URI::extract(str[, schemes])
395
+
396
+ =end
397
+ def self.extract(str, schemes = [])
398
+ urls = []
399
+ if schemes.size > 0
400
+ tmp = Regexp.new('(?:' + schemes.collect{|s|
401
+ Regexp.quote(s + ':')
402
+ }.join('|') + ')',
403
+ Regexp::IGNORECASE, 'N')
404
+ str.scan(tmp) {
405
+ tmp_str = $& + $'
406
+ if ABS_URI_REF =~ tmp_str
407
+ if block_given?
408
+ yield($&)
409
+ else
410
+ urls << $&
411
+ end
412
+ end
413
+ }
414
+
415
+ else
416
+ str.scan(ABS_URI_REF) {
417
+ if block_given?
418
+ yield($&)
419
+ else
420
+ urls << $&
421
+ end
422
+ }
423
+ end
424
+
425
+ if block_given?
426
+ return nil
427
+ else
428
+ return urls
429
+ end
430
+ end
431
+
432
+ end # URI