opal 0.3.15 → 0.3.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (236) hide show
  1. data/.gitignore +1 -1
  2. data/Gemfile +8 -2
  3. data/README.md +1 -1
  4. data/Rakefile +51 -57
  5. data/bin/opal +50 -2
  6. data/{runtime/corelib → core}/alpha.rb +6 -1
  7. data/{runtime/corelib → core}/array.rb +38 -42
  8. data/{runtime/corelib → core}/basic_object.rb +6 -17
  9. data/core/boolean.rb +40 -0
  10. data/core/class.rb +69 -0
  11. data/{runtime/corelib → core}/comparable.rb +0 -0
  12. data/core/debug.js +59 -0
  13. data/core/debug.rb +35 -0
  14. data/core/dir.rb +90 -0
  15. data/core/enumerable.rb +331 -0
  16. data/core/enumerator.rb +126 -0
  17. data/core/error.rb +40 -0
  18. data/{runtime/corelib → core}/file.rb +6 -3
  19. data/core/gemlib.rb +30 -0
  20. data/{runtime/corelib → core}/hash.rb +37 -35
  21. data/{runtime/corelib → core}/io.rb +0 -0
  22. data/{runtime/corelib → core}/kernel.rb +26 -21
  23. data/{runtime/corelib → core}/load_order +2 -5
  24. data/{runtime/corelib → core}/match_data.rb +2 -4
  25. data/core/module.rb +204 -0
  26. data/{runtime/corelib → core}/nil_class.rb +1 -7
  27. data/{runtime/corelib → core}/numeric.rb +9 -13
  28. data/core/object.rb +17 -0
  29. data/{runtime/corelib → core}/proc.rb +2 -13
  30. data/{runtime/corelib → core}/range.rb +19 -7
  31. data/{runtime/corelib → core}/rational.rb +0 -0
  32. data/{runtime/corelib → core}/regexp.rb +2 -6
  33. data/core/runtime.js +672 -0
  34. data/{runtime/corelib → core}/string.rb +25 -9
  35. data/{runtime/corelib → core}/struct.rb +0 -0
  36. data/core/time.rb +111 -0
  37. data/{runtime/corelib → core}/top_self.rb +0 -0
  38. data/{runtime/spec → core_spec}/README.md +0 -0
  39. data/{runtime/spec → core_spec}/core/array/allocate_spec.rb +0 -0
  40. data/{runtime/spec → core_spec}/core/array/append_spec.rb +0 -0
  41. data/{runtime/spec → core_spec}/core/array/assoc_spec.rb +0 -0
  42. data/{runtime/spec → core_spec}/core/array/at_spec.rb +0 -0
  43. data/{runtime/spec → core_spec}/core/array/clear_spec.rb +0 -0
  44. data/{runtime/spec → core_spec}/core/array/collect_spec.rb +0 -0
  45. data/{runtime/spec → core_spec}/core/array/compact_spec.rb +0 -0
  46. data/{runtime/spec → core_spec}/core/array/concat_spec.rb +0 -0
  47. data/{runtime/spec → core_spec}/core/array/constructor_spec.rb +0 -0
  48. data/{runtime/spec → core_spec}/core/array/count_spec.rb +0 -0
  49. data/{runtime/spec → core_spec}/core/array/delete_at_spec.rb +0 -0
  50. data/{runtime/spec → core_spec}/core/array/delete_if_spec.rb +0 -0
  51. data/{runtime/spec → core_spec}/core/array/delete_spec.rb +0 -0
  52. data/{runtime/spec → core_spec}/core/array/each_index_spec.rb +0 -0
  53. data/{runtime/spec → core_spec}/core/array/each_spec.rb +0 -0
  54. data/{runtime/spec → core_spec}/core/array/element_reference_spec.rb +0 -0
  55. data/{runtime/spec → core_spec}/core/array/element_set_spec.rb +0 -0
  56. data/{runtime/spec → core_spec}/core/array/empty_spec.rb +0 -0
  57. data/{runtime/spec → core_spec}/core/array/eql_spec.rb +0 -0
  58. data/{runtime/spec → core_spec}/core/array/equal_value_spec.rb +0 -0
  59. data/{runtime/spec → core_spec}/core/array/fetch_spec.rb +0 -0
  60. data/{runtime/spec → core_spec}/core/array/first_spec.rb +0 -0
  61. data/{runtime/spec → core_spec}/core/array/fixtures/classes.rb +0 -0
  62. data/{runtime/spec → core_spec}/core/array/flatten_spec.rb +0 -0
  63. data/{runtime/spec → core_spec}/core/array/include_spec.rb +0 -0
  64. data/{runtime/spec → core_spec}/core/array/insert_spec.rb +0 -0
  65. data/{runtime/spec → core_spec}/core/array/last_spec.rb +0 -0
  66. data/{runtime/spec → core_spec}/core/array/length_spec.rb +0 -0
  67. data/{runtime/spec → core_spec}/core/array/map_spec.rb +0 -0
  68. data/{runtime/spec → core_spec}/core/array/plus_spec.rb +0 -0
  69. data/{runtime/spec → core_spec}/core/array/pop_spec.rb +0 -0
  70. data/{runtime/spec → core_spec}/core/array/push_spec.rb +0 -0
  71. data/{runtime/spec → core_spec}/core/array/rassoc_spec.rb +0 -0
  72. data/{runtime/spec → core_spec}/core/array/reject_spec.rb +0 -0
  73. data/{runtime/spec → core_spec}/core/array/replace_spec.rb +0 -0
  74. data/{runtime/spec → core_spec}/core/array/reverse_each_spec.rb +0 -0
  75. data/{runtime/spec → core_spec}/core/array/reverse_spec.rb +0 -0
  76. data/{runtime/spec → core_spec}/core/array/shared/collect.rb +0 -0
  77. data/{runtime/spec → core_spec}/core/array/shared/eql.rb +0 -0
  78. data/{runtime/spec → core_spec}/core/array/shared/length.rb +0 -0
  79. data/{runtime/spec → core_spec}/core/array/shared/replace.rb +0 -0
  80. data/{runtime/spec → core_spec}/core/class/new_spec.rb +0 -0
  81. data/{runtime/spec → core_spec}/core/enumerable/all_spec.rb +0 -0
  82. data/{runtime/spec → core_spec}/core/enumerable/any_spec.rb +0 -0
  83. data/{runtime/spec → core_spec}/core/enumerable/collect_spec.rb +0 -0
  84. data/{runtime/spec → core_spec}/core/enumerable/count_spec.rb +0 -0
  85. data/{runtime/spec → core_spec}/core/enumerable/detect_spec.rb +0 -0
  86. data/{runtime/spec → core_spec}/core/enumerable/find_spec.rb +0 -0
  87. data/core_spec/core/enumerable/first_spec.rb +3 -0
  88. data/{runtime/spec → core_spec}/core/enumerable/fixtures/classes.rb +0 -0
  89. data/{runtime/spec → core_spec}/core/enumerable/shared/collect.rb +0 -0
  90. data/{runtime/spec → core_spec}/core/enumerable/shared/entries.rb +0 -0
  91. data/{runtime/spec → core_spec}/core/enumerable/shared/find.rb +0 -0
  92. data/core_spec/core/enumerable/shared/take.rb +31 -0
  93. data/{runtime/spec → core_spec}/core/enumerable/to_a_spec.rb +0 -0
  94. data/{runtime/spec → core_spec}/core/false/and_spec.rb +0 -0
  95. data/{runtime/spec → core_spec}/core/false/inspect_spec.rb +0 -0
  96. data/{runtime/spec → core_spec}/core/false/or_spec.rb +0 -0
  97. data/{runtime/spec → core_spec}/core/false/to_s_spec.rb +0 -0
  98. data/{runtime/spec → core_spec}/core/false/xor_spec.rb +0 -0
  99. data/{runtime/spec → core_spec}/core/hash/allocate_spec.rb +0 -0
  100. data/{runtime/spec → core_spec}/core/hash/assoc_spec.rb +0 -0
  101. data/{runtime/spec → core_spec}/core/hash/clear_spec.rb +0 -0
  102. data/{runtime/spec → core_spec}/core/hash/clone_spec.rb +0 -0
  103. data/{runtime/spec → core_spec}/core/hash/default_spec.rb +0 -0
  104. data/{runtime/spec → core_spec}/core/hash/delete_if_spec.rb +0 -0
  105. data/{runtime/spec → core_spec}/core/hash/element_reference_spec.rb +0 -0
  106. data/{runtime/spec → core_spec}/core/hash/element_set_spec.rb +0 -0
  107. data/{runtime/spec → core_spec}/core/hash/new_spec.rb +0 -0
  108. data/{runtime/spec → core_spec}/core/matchdata/to_a_spec.rb +0 -0
  109. data/{runtime/spec → core_spec}/core/nil/and_spec.rb +0 -0
  110. data/{runtime/spec → core_spec}/core/nil/inspect_spec.rb +0 -0
  111. data/{runtime/spec → core_spec}/core/nil/nil_spec.rb +0 -0
  112. data/{runtime/spec → core_spec}/core/nil/or_spec.rb +0 -0
  113. data/{runtime/spec → core_spec}/core/nil/to_a_spec.rb +0 -0
  114. data/{runtime/spec → core_spec}/core/nil/to_f_spec.rb +0 -0
  115. data/{runtime/spec → core_spec}/core/nil/to_i_spec.rb +0 -0
  116. data/{runtime/spec → core_spec}/core/nil/to_s_spec.rb +0 -0
  117. data/{runtime/spec → core_spec}/core/nil/xor_spec.rb +0 -0
  118. data/{runtime/spec → core_spec}/core/numeric/equal_value_spec.rb +0 -0
  119. data/{runtime/spec → core_spec}/core/object/is_a_spec.rb +0 -0
  120. data/{runtime/spec → core_spec}/core/object/shared/kind_of.rb +0 -0
  121. data/{runtime/spec → core_spec}/core/regexp/match_spec.rb +0 -0
  122. data/{runtime/spec → core_spec}/core/regexp/shared/match.rb +0 -0
  123. data/{runtime/spec → core_spec}/core/symbol/to_proc_spec.rb +0 -0
  124. data/{runtime/spec → core_spec}/core/true/and_spec.rb +0 -0
  125. data/{runtime/spec → core_spec}/core/true/inspect_spec.rb +0 -0
  126. data/{runtime/spec → core_spec}/core/true/or_spec.rb +0 -0
  127. data/{runtime/spec → core_spec}/core/true/to_s_spec.rb +0 -0
  128. data/{runtime/spec → core_spec}/core/true/xor_spec.rb +0 -0
  129. data/{runtime/spec → core_spec}/language/alias_spec.rb +0 -0
  130. data/{runtime/spec → core_spec}/language/and_spec.rb +0 -0
  131. data/{runtime/spec → core_spec}/language/array_spec.rb +0 -0
  132. data/{runtime/spec → core_spec}/language/block_spec.rb +0 -0
  133. data/{runtime/spec → core_spec}/language/break_spec.rb +0 -0
  134. data/{runtime/spec → core_spec}/language/case_spec.rb +0 -0
  135. data/{runtime/spec → core_spec}/language/defined_spec.rb +0 -0
  136. data/{runtime/spec → core_spec}/language/ensure_spec.rb +0 -0
  137. data/{runtime/spec → core_spec}/language/fixtures/block.rb +0 -0
  138. data/{runtime/spec → core_spec}/language/fixtures/break.rb +0 -0
  139. data/{runtime/spec → core_spec}/language/fixtures/defined.rb +0 -0
  140. data/{runtime/spec → core_spec}/language/fixtures/ensure.rb +0 -0
  141. data/{runtime/spec → core_spec}/language/fixtures/next.rb +0 -0
  142. data/{runtime/spec → core_spec}/language/fixtures/send.rb +0 -0
  143. data/{runtime/spec → core_spec}/language/fixtures/super.rb +0 -0
  144. data/{runtime/spec → core_spec}/language/hash_spec.rb +0 -0
  145. data/{runtime/spec → core_spec}/language/if_spec.rb +0 -0
  146. data/{runtime/spec → core_spec}/language/loop_spec.rb +0 -0
  147. data/{runtime/spec → core_spec}/language/next_spec.rb +0 -0
  148. data/{runtime/spec → core_spec}/language/or_spec.rb +0 -0
  149. data/{runtime/spec → core_spec}/language/predefined_spec.rb +0 -0
  150. data/{runtime/spec → core_spec}/language/regexp/interpolation_spec.rb +8 -0
  151. data/{runtime/spec → core_spec}/language/regexp_spec.rb +0 -0
  152. data/{runtime/spec → core_spec}/language/send_spec.rb +0 -0
  153. data/{runtime/spec → core_spec}/language/string_spec.rb +0 -0
  154. data/{runtime/spec → core_spec}/language/super_spec.rb +0 -0
  155. data/{runtime/spec → core_spec}/language/symbol_spec.rb +0 -0
  156. data/{runtime/spec → core_spec}/language/undef_spec.rb +0 -0
  157. data/{runtime/spec → core_spec}/language/unless_spec.rb +0 -0
  158. data/{runtime/spec → core_spec}/language/until_spec.rb +0 -0
  159. data/core_spec/language/variables_spec.rb +112 -0
  160. data/{runtime/spec → core_spec}/language/versions/hash_1.9.rb +0 -0
  161. data/{runtime/spec → core_spec}/language/while_spec.rb +0 -0
  162. data/{runtime/spec → core_spec}/opal/opal/defined_spec.rb +0 -0
  163. data/{runtime/spec → core_spec}/opal/opal/function_spec.rb +0 -0
  164. data/{runtime/spec → core_spec}/opal/opal/native_spec.rb +0 -0
  165. data/{runtime/spec → core_spec}/opal/opal/null_spec.rb +0 -0
  166. data/{runtime/spec → core_spec}/opal/opal/number_spec.rb +0 -0
  167. data/{runtime/spec → core_spec}/opal/opal/object_spec.rb +0 -0
  168. data/{runtime/spec → core_spec}/opal/opal/string_spec.rb +0 -0
  169. data/{runtime/spec → core_spec}/opal/opal/typeof_spec.rb +0 -0
  170. data/{runtime/spec → core_spec}/opal/opal/undefined_spec.rb +0 -0
  171. data/{runtime/spec → core_spec}/opal/true/case_compare_spec.rb +0 -0
  172. data/{runtime/spec → core_spec}/opal/true/class_spec.rb +0 -0
  173. data/{docs/spec_runner.html → core_spec/release_runner.html} +4 -3
  174. data/core_spec/runner.html +16 -0
  175. data/core_spec/spec_helper.rb +23 -0
  176. data/lib/opal.rb +85 -2
  177. data/lib/opal/builder.rb +129 -46
  178. data/lib/opal/context.rb +47 -26
  179. data/lib/opal/dependency_builder.rb +113 -14
  180. data/lib/opal/environment.rb +40 -45
  181. data/lib/opal/parser/grammar.rb +2296 -2254
  182. data/lib/opal/parser/grammar.y +27 -8
  183. data/lib/opal/parser/lexer.rb +12 -3
  184. data/lib/opal/parser/parser.rb +117 -30
  185. data/lib/opal/parser/scope.rb +2 -2
  186. data/lib/opal/version.rb +1 -1
  187. data/opal.gemspec +3 -8
  188. data/spec/grammar/masgn_spec.rb +37 -0
  189. metadata +177 -227
  190. data/index.html +0 -434
  191. data/lib/opal/command.rb +0 -73
  192. data/runtime/README.md +0 -25
  193. data/runtime/corelib/boolean.rb +0 -44
  194. data/runtime/corelib/class.rb +0 -43
  195. data/runtime/corelib/complex.rb +0 -2
  196. data/runtime/corelib/dir.rb +0 -29
  197. data/runtime/corelib/enumerable.rb +0 -316
  198. data/runtime/corelib/enumerator.rb +0 -80
  199. data/runtime/corelib/error.rb +0 -25
  200. data/runtime/corelib/module.rb +0 -171
  201. data/runtime/corelib/native.rb +0 -50
  202. data/runtime/corelib/object.rb +0 -21
  203. data/runtime/corelib/time.rb +0 -196
  204. data/runtime/gemlib/alpha.rb +0 -5
  205. data/runtime/gemlib/kernel.rb +0 -17
  206. data/runtime/gemlib/load_order +0 -2
  207. data/runtime/kernel/class.js +0 -256
  208. data/runtime/kernel/debug.js +0 -42
  209. data/runtime/kernel/init.js +0 -114
  210. data/runtime/kernel/load_order +0 -5
  211. data/runtime/kernel/loader.js +0 -151
  212. data/runtime/kernel/runtime.js +0 -414
  213. data/runtime/spec/language/variables_spec.rb +0 -28
  214. data/runtime/spec/library/stringscanner/scan_spec.rb +0 -36
  215. data/runtime/spec/opal/forwardable/def_instance_delegator_spec.rb +0 -49
  216. data/runtime/spec/spec_helper.rb +0 -25
  217. data/runtime/stdlib/base64.rb +0 -91
  218. data/runtime/stdlib/date.rb +0 -4
  219. data/runtime/stdlib/dev.rb +0 -171
  220. data/runtime/stdlib/forwardable.rb +0 -33
  221. data/runtime/stdlib/optparse.rb +0 -0
  222. data/runtime/stdlib/pp.rb +0 -6
  223. data/runtime/stdlib/racc/parser.rb +0 -159
  224. data/runtime/stdlib/rbconfig.rb +0 -0
  225. data/runtime/stdlib/si.rb +0 -17
  226. data/runtime/stdlib/strscan.rb +0 -53
  227. data/runtime/stdlib/uri.rb +0 -111
  228. data/runtime/stdlib/uri/common.rb +0 -1014
  229. data/runtime/stdlib/uri/ftp.rb +0 -261
  230. data/runtime/stdlib/uri/generic.rb +0 -1599
  231. data/runtime/stdlib/uri/http.rb +0 -106
  232. data/runtime/stdlib/uri/https.rb +0 -22
  233. data/runtime/stdlib/uri/ldap.rb +0 -260
  234. data/runtime/stdlib/uri/ldaps.rb +0 -20
  235. data/runtime/stdlib/uri/mailto.rb +0 -280
  236. data/spec/builder/output_path_spec.rb +0 -50
File without changes
data/runtime/stdlib/pp.rb DELETED
@@ -1,6 +0,0 @@
1
- module Kernel
2
- def pretty_inspect
3
- inspect
4
- end
5
- end
6
-
@@ -1,159 +0,0 @@
1
- # Opal port of racc/parser.rb.
2
- #
3
- # Original license:
4
- #
5
- # $originalId: parser.rb,v 1.8 2006/07/06 11:42:07 aamine Exp $
6
- #
7
- # Copyright (c) 1999-2006 Minero Aoki
8
- #
9
- # This program is free software.
10
- # You can distribute/modify this program under the same terms of ruby.
11
- #
12
- # As a special exception, when this code is copied by Racc
13
- # into a Racc output file, you may use that output file
14
- # without restriction.
15
- module Racc
16
-
17
- class Parser
18
-
19
- def _racc_setup
20
- Racc_arg
21
- end
22
-
23
- def do_parse
24
- _racc_do_parse_rb _racc_setup, false
25
- end
26
-
27
- def _racc_do_parse_rb(arg, in_debug)
28
- action_table = arg[0]
29
- action_check = arg[1]
30
- action_default = arg[2]
31
- action_pointer = arg[3]
32
-
33
- goto_table = arg[4]
34
- goto_check = arg[5]
35
- goto_default = arg[6]
36
- goto_pointer = arg[7]
37
-
38
- nt_base = arg[8]
39
- reduce_table = arg[9]
40
- token_table = arg[10]
41
- shift_n = arg[11]
42
- reduce_n = arg[12]
43
-
44
- use_result = arg[13]
45
-
46
- # racc sys vars
47
- racc_state = [0]
48
- racc_tstack = []
49
- racc_vstack = []
50
-
51
- racc_t = nil
52
- racc_tok = nil
53
- racc_val = nil
54
- racc_read_next = true
55
-
56
- racc_user_yyerror = false
57
- racc_error_status = 0
58
-
59
- token = nil; act = nil; i = nil; nerr = nil; custate = nil
60
-
61
- while true
62
- i = action_pointer[racc_state[-1]]
63
-
64
- if i
65
- if racc_read_next
66
- if racc_t != 0 # not EOF
67
- token = next_token
68
-
69
- racc_tok = token[0]
70
- racc_val = token[1]
71
-
72
- if racc_tok == false # EOF
73
- racc_t = 0
74
- else
75
- racc_t = token_table[racc_tok]
76
- racc_t = 1 unless racc_t
77
- # racc_t ||= 1
78
- end
79
-
80
- racc_read_next = false
81
- end
82
- end
83
-
84
- i += racc_t
85
-
86
- if (i < 0) || (act = action_table[i]).nil? || (action_check[i] != racc_state[-1])
87
- act = action_default[racc_state[-1]]
88
- end
89
-
90
- else
91
- act = action_default[racc_state[-1]]
92
- end
93
-
94
- if act > 0 && act < shift_n
95
- if racc_error_status > 0
96
- if racc_t != 1
97
- racc_error_status -= 1
98
- end
99
- end
100
-
101
- racc_vstack.push racc_val
102
- curstate = act
103
- racc_state << act
104
- racc_read_next = true
105
-
106
- elsif act < 0 && act > -reduce_n
107
- reduce_i = act * -3
108
- reduce_len = reduce_table[reduce_i]
109
- reduce_to = reduce_table[reduce_i + 1]
110
- method_id = reduce_table[reduce_i + 2]
111
-
112
- tmp_v = racc_vstack.last reduce_len
113
-
114
- racc_state.pop reduce_len
115
- racc_vstack.pop reduce_len
116
- racc_tstack.pop reduce_len
117
-
118
- if use_result
119
- reduce_call_result = self.__send__ method_id, tmp_v, nil, tmp_v[0]
120
- racc_vstack.push reduce_call_result
121
- else
122
- raise "not using result??"
123
- end
124
-
125
- racc_tstack.push reduce_to
126
-
127
- k1 = reduce_to - nt_base
128
-
129
- if (reduce_i = goto_pointer[k1]) != nil
130
- reduce_i += racc_state[-1]
131
-
132
- if (reduce_i >= 0) && ((curstate = goto_table[reduce_i]) != nil) && (goto_check[reduce_i] == k1)
133
- racc_state.push curstate
134
- else
135
- racc_state.push goto_default[k1]
136
- end
137
-
138
- else
139
- racc_state.push goto_default[k1]
140
- end
141
-
142
- elsif act == shift_n
143
- # action
144
- return racc_vstack[0]
145
-
146
- elsif act == -reduce_n
147
- # reduce
148
- raise "Opal Syntax Error: unexpected '#{racc_tok.inspect}'"
149
-
150
- else
151
- raise "Rac: unknown action: #{act}"
152
- end
153
-
154
- # raise "and finished loop"
155
- end
156
- end # _racc_do_parse_rb
157
- end
158
- end
159
-
File without changes
data/runtime/stdlib/si.rb DELETED
@@ -1,17 +0,0 @@
1
- class Numeric
2
- def seconds
3
- self
4
- end; alias second seconds
5
-
6
- def minutes
7
- self * 60
8
- end; alias minute minutes
9
-
10
- def hours
11
- self * 60.minutes
12
- end; alias hour hours
13
-
14
- def days
15
- self * 24.hours
16
- end; alias day days
17
- end
@@ -1,53 +0,0 @@
1
- class StringScanner
2
- def initialize(string)
3
- @string = string
4
- @at = 0
5
- @matched = ''
6
- @working = string
7
- end
8
-
9
- def scan(regex)
10
- %x{
11
- var regex = new RegExp('^' + regex.toString().substring(1, regex.toString().length - 1)),
12
- result = regex.exec(#@working);
13
-
14
- if (result == null) {
15
- #@matched = '';
16
-
17
- return nil;
18
- }
19
- else if (typeof(result) === 'object') {
20
- #@at += result[0].length;
21
- #@working = #@working.substring(result[0].length);
22
- #@matched = result[0];
23
-
24
- return result[0];
25
- }
26
- else if (typeof(result) === 'string') {
27
- #@at += result.length;
28
- #@working = #@working.substring(result.length);
29
-
30
- return result;
31
- }
32
- else {
33
- return nil;
34
- }
35
- }
36
- end
37
-
38
- def check(regex)
39
- `!!new RegExp('^' + regex.toString().substring(1, regex.toString().length - 1)).exec(#@working)`
40
- end
41
-
42
- def peek(length)
43
- `#@working.substring(0, length)`
44
- end
45
-
46
- def eos?
47
- `#@working.length === 0`
48
- end
49
-
50
- def matched
51
- @matched
52
- end
53
- end
@@ -1,111 +0,0 @@
1
- # URI is a module providing classes to handle Uniform Resource Identifiers
2
- # (RFC2396[http://tools.ietf.org/html/rfc2396])
3
- #
4
- # == Features
5
- #
6
- # * Uniform handling of handling URIs
7
- # * Flexibility to introduce custom URI schemes
8
- # * Flexibility to have an alternate URI::Parser (or just different patterns
9
- # and regexp's)
10
- #
11
- # == Basic example
12
- #
13
- # require 'uri'
14
- #
15
- # uri = URI("http://foo.com/posts?id=30&limit=5#time=1305298413")
16
- # #=> #<URI::HTTP:0x00000000b14880
17
- # URL:http://foo.com/posts?id=30&limit=5#time=1305298413>
18
- # uri.scheme
19
- # #=> "http"
20
- # uri.host
21
- # #=> "foo.com"
22
- # uri.path
23
- # #=> "/posts"
24
- # uri.query
25
- # #=> "id=30&limit=5"
26
- # uri.fragment
27
- # #=> "time=1305298413"
28
- #
29
- # uri.to_s
30
- # #=> "http://foo.com/posts?id=30&limit=5#time=1305298413"
31
- #
32
- # == Adding custom URIs
33
- #
34
- # module URI
35
- # class RSYNC < Generic
36
- # DEFAULT_PORT = 873
37
- # end
38
- # @@schemes['RSYNC'] = RSYNC
39
- # end
40
- # #=> URI::RSYNC
41
- #
42
- # URI.scheme_list
43
- # #=> {"FTP"=>URI::FTP, "HTTP"=>URI::HTTP, "HTTPS"=>URI::HTTPS,
44
- # "LDAP"=>URI::LDAP, "LDAPS"=>URI::LDAPS, "MAILTO"=>URI::MailTo,
45
- # "RSYNC"=>URI::RSYNC}
46
- #
47
- # uri = URI("rsync://rsync.foo.com")
48
- # #=> #<URI::RSYNC:0x00000000f648c8 URL:rsync://rsync.foo.com>
49
- #
50
- # == RFC References
51
- #
52
- # A good place to view an RFC spec is http://www.ietf.org/rfc.html
53
- #
54
- # Here is a list of all related RFC's.
55
- # - RFC822[http://tools.ietf.org/html/rfc822]
56
- # - RFC1738[http://tools.ietf.org/html/rfc1738]
57
- # - RFC2255[http://tools.ietf.org/html/rfc2255]
58
- # - RFC2368[http://tools.ietf.org/html/rfc2368]
59
- # - RFC2373[http://tools.ietf.org/html/rfc2373]
60
- # - RFC2396[http://tools.ietf.org/html/rfc2396]
61
- # - RFC2732[http://tools.ietf.org/html/rfc2732]
62
- # - RFC3986[http://tools.ietf.org/html/rfc3986]
63
- #
64
- # == Class tree
65
- #
66
- # - URI::Generic (in uri/generic.rb)
67
- # - URI::FTP - (in uri/ftp.rb)
68
- # - URI::HTTP - (in uri/http.rb)
69
- # - URI::HTTPS - (in uri/https.rb)
70
- # - URI::LDAP - (in uri/ldap.rb)
71
- # - URI::LDAPS - (in uri/ldaps.rb)
72
- # - URI::MailTo - (in uri/mailto.rb)
73
- # - URI::Parser - (in uri/common.rb)
74
- # - URI::REGEXP - (in uri/common.rb)
75
- # - URI::REGEXP::PATTERN - (in uri/common.rb)
76
- # - URI::Util - (in uri/common.rb)
77
- # - URI::Escape - (in uri/common.rb)
78
- # - URI::Error - (in uri/common.rb)
79
- # - URI::InvalidURIError - (in uri/common.rb)
80
- # - URI::InvalidComponentError - (in uri/common.rb)
81
- # - URI::BadURIError - (in uri/common.rb)
82
- #
83
- # == Copyright Info
84
- #
85
- # Author:: Akira Yamada <akira@ruby-lang.org>
86
- # Documentation::
87
- # Akira Yamada <akira@ruby-lang.org>
88
- # Dmitry V. Sabanin <sdmitry@lrn.ru>
89
- # Vincent Batts <vbatts@hashbangbash.com>
90
- # License::
91
- # Copyright (c) 2001 akira yamada <akira@ruby-lang.org>
92
- # You can redistribute it and/or modify it under the same term as Ruby.
93
- # Revision:: $Id$
94
- #
95
-
96
- module URI
97
- # :stopdoc:
98
- VERSION_CODE = '000911'.freeze
99
- VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
100
- # :startdoc:
101
-
102
- end
103
-
104
- require 'uri/common'
105
- require 'uri/generic'
106
- require 'uri/ftp'
107
- require 'uri/http'
108
- require 'uri/https'
109
- require 'uri/ldap'
110
- require 'uri/ldaps'
111
- require 'uri/mailto'
@@ -1,1014 +0,0 @@
1
- #--
2
- # = uri/common.rb
3
- #
4
- # Author:: Akira Yamada <akira@ruby-lang.org>
5
- # Revision:: $Id$
6
- # License::
7
- # You can redistribute it and/or modify it under the same term as Ruby.
8
- #
9
- # See URI for general documentation
10
- #
11
-
12
- module URI
13
- #
14
- # Includes URI::REGEXP::PATTERN
15
- #
16
- module REGEXP
17
- #
18
- # Patterns used to parse URI's
19
- #
20
- module PATTERN
21
- # :stopdoc:
22
-
23
- # RFC 2396 (URI Generic Syntax)
24
- # RFC 2732 (IPv6 Literal Addresses in URL's)
25
- # RFC 2373 (IPv6 Addressing Architecture)
26
-
27
- # alpha = lowalpha | upalpha
28
- ALPHA = "a-zA-Z"
29
- # alphanum = alpha | digit
30
- ALNUM = "#{ALPHA}\\d"
31
-
32
- # hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
33
- # "a" | "b" | "c" | "d" | "e" | "f"
34
- HEX = "a-fA-F\\d"
35
- # escaped = "%" hex hex
36
- ESCAPED = "%[#{HEX}]{2}"
37
- # mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
38
- # "(" | ")"
39
- # unreserved = alphanum | mark
40
- UNRESERVED = "\\-_.!~*'()#{ALNUM}"
41
- # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
42
- # "$" | ","
43
- # reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
44
- # "$" | "," | "[" | "]" (RFC 2732)
45
- RESERVED = ";/?:@&=+$,\\[\\]"
46
-
47
- # domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
48
- DOMLABEL = "(?:[#{ALNUM}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
49
- # toplabel = alpha | alpha *( alphanum | "-" ) alphanum
50
- TOPLABEL = "(?:[#{ALPHA}](?:[-#{ALNUM}]*[#{ALNUM}])?)"
51
- # hostname = *( domainlabel "." ) toplabel [ "." ]
52
- HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
53
-
54
- # :startdoc:
55
- end # PATTERN
56
-
57
- # :startdoc:
58
- end # REGEXP
59
-
60
- # class that Parses String's into URI's
61
- #
62
- # It contains a Hash set of patterns and Regexp's that match and validate.
63
- #
64
- class Parser
65
- include REGEXP
66
-
67
- #
68
- # == Synopsis
69
- #
70
- # URI::Parser.new([opts])
71
- #
72
- # == Args
73
- #
74
- # The constructor accepts a hash as options for parser.
75
- # Keys of options are pattern names of URI components
76
- # and values of options are pattern strings.
77
- # The constructor generetes set of regexps for parsing URIs.
78
- #
79
- # You can use the following keys:
80
- #
81
- # * :ESCAPED (URI::PATTERN::ESCAPED in default)
82
- # * :UNRESERVED (URI::PATTERN::UNRESERVED in default)
83
- # * :DOMLABEL (URI::PATTERN::DOMLABEL in default)
84
- # * :TOPLABEL (URI::PATTERN::TOPLABEL in default)
85
- # * :HOSTNAME (URI::PATTERN::HOSTNAME in default)
86
- #
87
- # == Examples
88
- #
89
- # p = URI::Parser.new(:ESCAPED => "(?:%[a-fA-F0-9]{2}|%u[a-fA-F0-9]{4})")
90
- # u = p.parse("http://example.jp/%uABCD") #=> #<URI::HTTP:0xb78cf4f8 URL:http://example.jp/%uABCD>
91
- # URI.parse(u.to_s) #=> raises URI::InvalidURIError
92
- #
93
- # s = "http://examle.com/ABCD"
94
- # u1 = p.parse(s) #=> #<URI::HTTP:0xb78c3220 URL:http://example.com/ABCD>
95
- # u2 = URI.parse(s) #=> #<URI::HTTP:0xb78b6d54 URL:http://example.com/ABCD>
96
- # u1 == u2 #=> true
97
- # u1.eql?(u2) #=> false
98
- #
99
- def initialize(opts = {})
100
- @pattern = initialize_pattern(opts)
101
- @pattern.each_value {|v| v.freeze}
102
- @pattern.freeze
103
-
104
- @regexp = initialize_regexp(@pattern)
105
- @regexp.each_value {|v| v.freeze}
106
- @regexp.freeze
107
- end
108
-
109
- # The Hash of patterns.
110
- #
111
- # see also URI::Parser.initialize_pattern
112
- attr_reader :pattern
113
-
114
- # The Hash of Regexp
115
- #
116
- # see also URI::Parser.initialize_regexp
117
- attr_reader :regexp
118
-
119
- # Returns a split URI against regexp[:ABS_URI]
120
- def split(uri)
121
- case uri
122
- when ''
123
- # null uri
124
-
125
- when @regexp[:ABS_URI]
126
- scheme, opaque, userinfo, host, port,
127
- registry, path, query, fragment = $~[1..-1]
128
-
129
- # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
130
-
131
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
132
- # hier_part = ( net_path | abs_path ) [ "?" query ]
133
- # opaque_part = uric_no_slash *uric
134
-
135
- # abs_path = "/" path_segments
136
- # net_path = "//" authority [ abs_path ]
137
-
138
- # authority = server | reg_name
139
- # server = [ [ userinfo "@" ] hostport ]
140
-
141
- if !scheme
142
- raise InvalidURIError,
143
- "bad URI(absolute but no scheme): #{uri}"
144
- end
145
- if !opaque && (!path && (!host && !registry))
146
- raise InvalidURIError,
147
- "bad URI(absolute but no path): #{uri}"
148
- end
149
-
150
- when @regexp[:REL_URI]
151
- scheme = nil
152
- opaque = nil
153
-
154
- userinfo, host, port, registry,
155
- rel_segment, abs_path, query, fragment = $~[1..-1]
156
- if rel_segment && abs_path
157
- path = rel_segment + abs_path
158
- elsif rel_segment
159
- path = rel_segment
160
- elsif abs_path
161
- path = abs_path
162
- end
163
-
164
- # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
165
-
166
- # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
167
-
168
- # net_path = "//" authority [ abs_path ]
169
- # abs_path = "/" path_segments
170
- # rel_path = rel_segment [ abs_path ]
171
-
172
- # authority = server | reg_name
173
- # server = [ [ userinfo "@" ] hostport ]
174
-
175
- else
176
- raise InvalidURIError, "bad URI(is not URI?): #{uri}"
177
- end
178
-
179
- path = '' if !path && !opaque # (see RFC2396 Section 5.2)
180
- ret = [
181
- scheme,
182
- userinfo, host, port, # X
183
- registry, # X
184
- path, # Y
185
- opaque, # Y
186
- query,
187
- fragment
188
- ]
189
- return ret
190
- end
191
-
192
- #
193
- # == Args
194
- #
195
- # +uri+::
196
- # String
197
- #
198
- # == Description
199
- #
200
- # parses +uri+ and constructs either matching URI scheme object
201
- # (FTP, HTTP, HTTPS, LDAP, LDAPS, or MailTo) or URI::Generic
202
- #
203
- # == Usage
204
- #
205
- # p = URI::Parser.new
206
- # p.parse("ldap://ldap.example.com/dc=example?user=john")
207
- # #=> #<URI::LDAP:0x00000000b9e7e8 URL:ldap://ldap.example.com/dc=example?user=john>
208
- #
209
- def parse(uri)
210
- scheme, userinfo, host, port,
211
- registry, path, opaque, query, fragment = self.split(uri)
212
-
213
- if scheme && URI.scheme_list.include?(scheme.upcase)
214
- URI.scheme_list[scheme.upcase].new(scheme, userinfo, host, port,
215
- registry, path, opaque, query,
216
- fragment, self)
217
- else
218
- Generic.new(scheme, userinfo, host, port,
219
- registry, path, opaque, query,
220
- fragment, self)
221
- end
222
- end
223
-
224
-
225
- #
226
- # == Args
227
- #
228
- # +uris+::
229
- # an Array of Strings
230
- #
231
- # == Description
232
- #
233
- # Attempts to parse and merge a set of URIs
234
- #
235
- def join(*uris)
236
- uris[0] = convert_to_uri(uris[0])
237
- uris.inject :merge
238
- end
239
-
240
- #
241
- # :call-seq:
242
- # extract( str )
243
- # extract( str, schemes )
244
- # extract( str, schemes ) {|item| block }
245
- #
246
- # == Args
247
- #
248
- # +str+::
249
- # String to search
250
- # +schemes+::
251
- # Patterns to apply to +str+
252
- #
253
- # == Description
254
- #
255
- # Attempts to parse and merge a set of URIs
256
- # If no +block+ given , then returns the result,
257
- # else it calls +block+ for each element in result.
258
- #
259
- # see also URI::Parser.make_regexp
260
- #
261
- def extract(str, schemes = nil, &block)
262
- if block_given?
263
- str.scan(make_regexp(schemes)) { yield $& }
264
- nil
265
- else
266
- result = []
267
- str.scan(make_regexp(schemes)) { result.push $& }
268
- result
269
- end
270
- end
271
-
272
- # returns Regexp that is default self.regexp[:ABS_URI_REF],
273
- # unless +schemes+ is provided. Then it is a Regexp.union with self.pattern[:X_ABS_URI]
274
- def make_regexp(schemes = nil)
275
- unless schemes
276
- @regexp[:ABS_URI_REF]
277
- else
278
- /(?=#{Regexp.union(*schemes)}:)#{@pattern[:X_ABS_URI]}/x
279
- end
280
- end
281
-
282
- #
283
- # :call-seq:
284
- # escape( str )
285
- # escape( str, unsafe )
286
- #
287
- # == Args
288
- #
289
- # +str+::
290
- # String to make safe
291
- # +unsafe+::
292
- # Regexp to apply. Defaults to self.regexp[:UNSAFE]
293
- #
294
- # == Description
295
- #
296
- # constructs a safe String from +str+, removing unsafe characters,
297
- # replacing them with codes.
298
- #
299
- def escape(str, unsafe = @regexp[:UNSAFE])
300
- unless unsafe.kind_of?(Regexp)
301
- # perhaps unsafe is String object
302
- unsafe = Regexp.new("[#{Regexp.quote(unsafe)}]", false)
303
- end
304
- str.gsub(unsafe) do
305
- us = $&
306
- tmp = ''
307
- us.each_byte do |uc|
308
- tmp << sprintf('%%%02X', uc)
309
- end
310
- tmp
311
- end.force_encoding(Encoding::US_ASCII)
312
- end
313
-
314
- #
315
- # :call-seq:
316
- # unescape( str )
317
- # unescape( str, unsafe )
318
- #
319
- # == Args
320
- #
321
- # +str+::
322
- # String to remove escapes from
323
- # +unsafe+::
324
- # Regexp to apply. Defaults to self.regexp[:ESCAPED]
325
- #
326
- # == Description
327
- #
328
- # Removes escapes from +str+
329
- #
330
- def unescape(str, escaped = @regexp[:ESCAPED])
331
- str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(str.encoding)
332
- end
333
-
334
- @@to_s = Kernel.instance_method(:to_s)
335
- def inspect
336
- @@to_s.bind(self).call
337
- end
338
-
339
- private
340
-
341
- # Constructs the default Hash of patterns
342
- def initialize_pattern(opts = {})
343
- ret = {}
344
- ret[:ESCAPED] = escaped = (opts.delete(:ESCAPED) || PATTERN::ESCAPED)
345
- ret[:UNRESERVED] = unreserved = opts.delete(:UNRESERVED) || PATTERN::UNRESERVED
346
- ret[:RESERVED] = reserved = opts.delete(:RESERVED) || PATTERN::RESERVED
347
- ret[:DOMLABEL] = opts.delete(:DOMLABEL) || PATTERN::DOMLABEL
348
- ret[:TOPLABEL] = opts.delete(:TOPLABEL) || PATTERN::TOPLABEL
349
- ret[:HOSTNAME] = hostname = opts.delete(:HOSTNAME)
350
-
351
- # RFC 2396 (URI Generic Syntax)
352
- # RFC 2732 (IPv6 Literal Addresses in URL's)
353
- # RFC 2373 (IPv6 Addressing Architecture)
354
-
355
- # uric = reserved | unreserved | escaped
356
- ret[:URIC] = uric = "(?:[#{unreserved}#{reserved}]|#{escaped})"
357
- # uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
358
- # "&" | "=" | "+" | "$" | ","
359
- ret[:URIC_NO_SLASH] = uric_no_slash = "(?:[#{unreserved};?:@&=+$,]|#{escaped})"
360
- # query = *uric
361
- ret[:QUERY] = query = "#{uric}*"
362
- # fragment = *uric
363
- ret[:FRAGMENT] = fragment = "#{uric}*"
364
-
365
- # hostname = *( domainlabel "." ) toplabel [ "." ]
366
- # reg-name = *( unreserved / pct-encoded / sub-delims ) # RFC3986
367
- unless hostname
368
- ret[:HOSTNAME] = hostname = "(?:[a-zA-Z0-9\\-.]|%\\h\\h)+"
369
- end
370
-
371
- # RFC 2373, APPENDIX B:
372
- # IPv6address = hexpart [ ":" IPv4address ]
373
- # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
374
- # hexpart = hexseq | hexseq "::" [ hexseq ] | "::" [ hexseq ]
375
- # hexseq = hex4 *( ":" hex4)
376
- # hex4 = 1*4HEXDIG
377
- #
378
- # XXX: This definition has a flaw. "::" + IPv4address must be
379
- # allowed too. Here is a replacement.
380
- #
381
- # IPv4address = 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT "." 1*3DIGIT
382
- ret[:IPV4ADDR] = ipv4addr = "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}"
383
- # hex4 = 1*4HEXDIG
384
- hex4 = "[#{PATTERN::HEX}]{1,4}"
385
- # lastpart = hex4 | IPv4address
386
- lastpart = "(?:#{hex4}|#{ipv4addr})"
387
- # hexseq1 = *( hex4 ":" ) hex4
388
- hexseq1 = "(?:#{hex4}:)*#{hex4}"
389
- # hexseq2 = *( hex4 ":" ) lastpart
390
- hexseq2 = "(?:#{hex4}:)*#{lastpart}"
391
- # IPv6address = hexseq2 | [ hexseq1 ] "::" [ hexseq2 ]
392
- ret[:IPV6ADDR] = ipv6addr = "(?:#{hexseq2}|(?:#{hexseq1})?::(?:#{hexseq2})?)"
393
-
394
- # IPv6prefix = ( hexseq1 | [ hexseq1 ] "::" [ hexseq1 ] ) "/" 1*2DIGIT
395
- # unused
396
-
397
- # ipv6reference = "[" IPv6address "]" (RFC 2732)
398
- ret[:IPV6REF] = ipv6ref = "\\[#{ipv6addr}\\]"
399
-
400
- # host = hostname | IPv4address
401
- # host = hostname | IPv4address | IPv6reference (RFC 2732)
402
- ret[:HOST] = host = "(?:#{hostname}|#{ipv4addr}|#{ipv6ref})"
403
- # port = *digit
404
- port = '\d*'
405
- # hostport = host [ ":" port ]
406
- ret[:HOSTPORT] = hostport = "#{host}(?::#{port})?"
407
-
408
- # userinfo = *( unreserved | escaped |
409
- # ";" | ":" | "&" | "=" | "+" | "$" | "," )
410
- ret[:USERINFO] = userinfo = "(?:[#{unreserved};:&=+$,]|#{escaped})*"
411
-
412
- # pchar = unreserved | escaped |
413
- # ":" | "@" | "&" | "=" | "+" | "$" | ","
414
- pchar = "(?:[#{unreserved}:@&=+$,]|#{escaped})"
415
- # param = *pchar
416
- param = "#{pchar}*"
417
- # segment = *pchar *( ";" param )
418
- segment = "#{pchar}*(?:;#{param})*"
419
- # path_segments = segment *( "/" segment )
420
- ret[:PATH_SEGMENTS] = path_segments = "#{segment}(?:/#{segment})*"
421
-
422
- # server = [ [ userinfo "@" ] hostport ]
423
- server = "(?:#{userinfo}@)?#{hostport}"
424
- # reg_name = 1*( unreserved | escaped | "$" | "," |
425
- # ";" | ":" | "@" | "&" | "=" | "+" )
426
- ret[:REG_NAME] = reg_name = "(?:[#{unreserved}$,;:@&=+]|#{escaped})+"
427
- # authority = server | reg_name
428
- authority = "(?:#{server}|#{reg_name})"
429
-
430
- # rel_segment = 1*( unreserved | escaped |
431
- # ";" | "@" | "&" | "=" | "+" | "$" | "," )
432
- ret[:REL_SEGMENT] = rel_segment = "(?:[#{unreserved};@&=+$,]|#{escaped})+"
433
-
434
- # scheme = alpha *( alpha | digit | "+" | "-" | "." )
435
- ret[:SCHEME] = scheme = "[#{PATTERN::ALPHA}][\\-+.#{PATTERN::ALPHA}\\d]*"
436
-
437
- # abs_path = "/" path_segments
438
- ret[:ABS_PATH] = abs_path = "/#{path_segments}"
439
- # rel_path = rel_segment [ abs_path ]
440
- ret[:REL_PATH] = rel_path = "#{rel_segment}(?:#{abs_path})?"
441
- # net_path = "//" authority [ abs_path ]
442
- ret[:NET_PATH] = net_path = "//#{authority}(?:#{abs_path})?"
443
-
444
- # hier_part = ( net_path | abs_path ) [ "?" query ]
445
- ret[:HIER_PART] = hier_part = "(?:#{net_path}|#{abs_path})(?:\\?(?:#{query}))?"
446
- # opaque_part = uric_no_slash *uric
447
- ret[:OPAQUE_PART] = opaque_part = "#{uric_no_slash}#{uric}*"
448
-
449
- # absoluteURI = scheme ":" ( hier_part | opaque_part )
450
- ret[:ABS_URI] = abs_uri = "#{scheme}:(?:#{hier_part}|#{opaque_part})"
451
- # relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
452
- ret[:REL_URI] = rel_uri = "(?:#{net_path}|#{abs_path}|#{rel_path})(?:\\?#{query})?"
453
-
454
- # URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
455
- ret[:URI_REF] = "(?:#{abs_uri}|#{rel_uri})?(?:##{fragment})?"
456
-
457
- ret[:X_ABS_URI] = "
458
- (#{scheme}): (?# 1: scheme)
459
- (?:
460
- (#{opaque_part}) (?# 2: opaque)
461
- |
462
- (?:(?:
463
- //(?:
464
- (?:(?:(#{userinfo})@)? (?# 3: userinfo)
465
- (?:(#{host})(?::(\\d*))?))? (?# 4: host, 5: port)
466
- |
467
- (#{reg_name}) (?# 6: registry)
468
- )
469
- |
470
- (?!//)) (?# XXX: '//' is the mark for hostport)
471
- (#{abs_path})? (?# 7: path)
472
- )(?:\\?(#{query}))? (?# 8: query)
473
- )
474
- (?:\\#(#{fragment}))? (?# 9: fragment)
475
- "
476
-
477
- ret[:X_REL_URI] = "
478
- (?:
479
- (?:
480
- //
481
- (?:
482
- (?:(#{userinfo})@)? (?# 1: userinfo)
483
- (#{host})?(?::(\\d*))? (?# 2: host, 3: port)
484
- |
485
- (#{reg_name}) (?# 4: registry)
486
- )
487
- )
488
- |
489
- (#{rel_segment}) (?# 5: rel_segment)
490
- )?
491
- (#{abs_path})? (?# 6: abs_path)
492
- (?:\\?(#{query}))? (?# 7: query)
493
- (?:\\#(#{fragment}))? (?# 8: fragment)
494
- "
495
-
496
- ret
497
- end
498
-
499
- # Constructs the default Hash of Regexp's
500
- def initialize_regexp(pattern)
501
- ret = {}
502
-
503
- # for URI::split
504
- ret[:ABS_URI] = Regexp.new('\A\s*' + pattern[:X_ABS_URI] + '\s*\z', Regexp::EXTENDED)
505
- ret[:REL_URI] = Regexp.new('\A\s*' + pattern[:X_REL_URI] + '\s*\z', Regexp::EXTENDED)
506
-
507
- # for URI::extract
508
- ret[:URI_REF] = Regexp.new(pattern[:URI_REF])
509
- ret[:ABS_URI_REF] = Regexp.new(pattern[:X_ABS_URI], Regexp::EXTENDED)
510
- ret[:REL_URI_REF] = Regexp.new(pattern[:X_REL_URI], Regexp::EXTENDED)
511
-
512
- # for URI::escape/unescape
513
- ret[:ESCAPED] = Regexp.new(pattern[:ESCAPED])
514
- ret[:UNSAFE] = Regexp.new("[^#{pattern[:UNRESERVED]}#{pattern[:RESERVED]}]")
515
-
516
- # for Generic#initialize
517
- ret[:SCHEME] = Regexp.new("^#{pattern[:SCHEME]}$")
518
- ret[:USERINFO] = Regexp.new("^#{pattern[:USERINFO]}$")
519
- ret[:HOST] = Regexp.new("^#{pattern[:HOST]}$")
520
- ret[:PORT] = Regexp.new("^#{pattern[:PORT]}$")
521
- ret[:OPAQUE] = Regexp.new("^#{pattern[:OPAQUE_PART]}$")
522
- ret[:REGISTRY] = Regexp.new("^#{pattern[:REG_NAME]}$")
523
- ret[:ABS_PATH] = Regexp.new("^#{pattern[:ABS_PATH]}$")
524
- ret[:REL_PATH] = Regexp.new("^#{pattern[:REL_PATH]}$")
525
- ret[:QUERY] = Regexp.new("^#{pattern[:QUERY]}$")
526
- ret[:FRAGMENT] = Regexp.new("^#{pattern[:FRAGMENT]}$")
527
-
528
- ret
529
- end
530
-
531
- def convert_to_uri(uri)
532
- if uri.is_a?(URI::Generic)
533
- uri
534
- elsif uri = String.try_convert(uri)
535
- parse(uri)
536
- else
537
- raise ArgumentError,
538
- "bad argument (expected URI object or URI string)"
539
- end
540
- end
541
-
542
- end # class Parser
543
-
544
- # URI::Parser.new
545
- DEFAULT_PARSER = Parser.new
546
- DEFAULT_PARSER.pattern.each_pair do |sym, str|
547
- unless REGEXP::PATTERN.const_defined?(sym)
548
- REGEXP::PATTERN.const_set(sym, str)
549
- end
550
- end
551
- DEFAULT_PARSER.regexp.each_pair do |sym, str|
552
- const_set(sym, str)
553
- end
554
-
555
- module Util # :nodoc:
556
- def make_components_hash(klass, array_hash)
557
- tmp = {}
558
- if array_hash.kind_of?(Array) &&
559
- array_hash.size == klass.component.size - 1
560
- klass.component[1..-1].each_index do |i|
561
- begin
562
- tmp[klass.component[i + 1]] = array_hash[i].clone
563
- rescue TypeError
564
- tmp[klass.component[i + 1]] = array_hash[i]
565
- end
566
- end
567
-
568
- elsif array_hash.kind_of?(Hash)
569
- array_hash.each do |key, value|
570
- begin
571
- tmp[key] = value.clone
572
- rescue TypeError
573
- tmp[key] = value
574
- end
575
- end
576
- else
577
- raise ArgumentError,
578
- "expected Array of or Hash of components of #{klass.to_s} (#{klass.component[1..-1].join(', ')})"
579
- end
580
- tmp[:scheme] = klass.to_s.sub(/\A.*::/, '').downcase
581
-
582
- return tmp
583
- end
584
- module_function :make_components_hash
585
- end
586
-
587
- # module for escaping unsafe characters with codes.
588
- module Escape
589
- #
590
- # == Synopsis
591
- #
592
- # URI.escape(str [, unsafe])
593
- #
594
- # == Args
595
- #
596
- # +str+::
597
- # String to replaces in.
598
- # +unsafe+::
599
- # Regexp that matches all symbols that must be replaced with codes.
600
- # By default uses <tt>REGEXP::UNSAFE</tt>.
601
- # When this argument is a String, it represents a character set.
602
- #
603
- # == Description
604
- #
605
- # Escapes the string, replacing all unsafe characters with codes.
606
- #
607
- # == Usage
608
- #
609
- # require 'uri'
610
- #
611
- # enc_uri = URI.escape("http://example.com/?a=\11\15")
612
- # p enc_uri
613
- # # => "http://example.com/?a=%09%0D"
614
- #
615
- # p URI.unescape(enc_uri)
616
- # # => "http://example.com/?a=\t\r"
617
- #
618
- # p URI.escape("@?@!", "!?")
619
- # # => "@%3F@%21"
620
- #
621
- def escape(*arg)
622
- warn "#{caller(1)[0]}: warning: URI.escape is obsolete" if $VERBOSE
623
- DEFAULT_PARSER.escape(*arg)
624
- end
625
- alias encode escape
626
- #
627
- # == Synopsis
628
- #
629
- # URI.unescape(str)
630
- #
631
- # == Args
632
- #
633
- # +str+::
634
- # Unescapes the string.
635
- #
636
- # == Usage
637
- #
638
- # require 'uri'
639
- #
640
- # enc_uri = URI.escape("http://example.com/?a=\11\15")
641
- # p enc_uri
642
- # # => "http://example.com/?a=%09%0D"
643
- #
644
- # p URI.unescape(enc_uri)
645
- # # => "http://example.com/?a=\t\r"
646
- #
647
- def unescape(*arg)
648
- warn "#{caller(1)[0]}: warning: URI.unescape is obsolete" if $VERBOSE
649
- DEFAULT_PARSER.unescape(*arg)
650
- end
651
- alias decode unescape
652
- end # module Escape
653
-
654
- extend Escape
655
- include REGEXP
656
-
657
- @@schemes = {}
658
- # Returns a Hash of the defined schemes
659
- def self.scheme_list
660
- @@schemes
661
- end
662
-
663
- #
664
- # Base class for all URI exceptions.
665
- #
666
- class Error < StandardError; end
667
- #
668
- # Not a URI.
669
- #
670
- class InvalidURIError < Error; end
671
- #
672
- # Not a URI component.
673
- #
674
- class InvalidComponentError < Error; end
675
- #
676
- # URI is valid, bad usage is not.
677
- #
678
- class BadURIError < Error; end
679
-
680
- #
681
- # == Synopsis
682
- #
683
- # URI::split(uri)
684
- #
685
- # == Args
686
- #
687
- # +uri+::
688
- # String with URI.
689
- #
690
- # == Description
691
- #
692
- # Splits the string on following parts and returns array with result:
693
- #
694
- # * Scheme
695
- # * Userinfo
696
- # * Host
697
- # * Port
698
- # * Registry
699
- # * Path
700
- # * Opaque
701
- # * Query
702
- # * Fragment
703
- #
704
- # == Usage
705
- #
706
- # require 'uri'
707
- #
708
- # p URI.split("http://www.ruby-lang.org/")
709
- # # => ["http", nil, "www.ruby-lang.org", nil, nil, "/", nil, nil, nil]
710
- #
711
- def self.split(uri)
712
- DEFAULT_PARSER.split(uri)
713
- end
714
-
715
- #
716
- # == Synopsis
717
- #
718
- # URI::parse(uri_str)
719
- #
720
- # == Args
721
- #
722
- # +uri_str+::
723
- # String with URI.
724
- #
725
- # == Description
726
- #
727
- # Creates one of the URI's subclasses instance from the string.
728
- #
729
- # == Raises
730
- #
731
- # URI::InvalidURIError
732
- # Raised if URI given is not a correct one.
733
- #
734
- # == Usage
735
- #
736
- # require 'uri'
737
- #
738
- # uri = URI.parse("http://www.ruby-lang.org/")
739
- # p uri
740
- # # => #<URI::HTTP:0x202281be URL:http://www.ruby-lang.org/>
741
- # p uri.scheme
742
- # # => "http"
743
- # p uri.host
744
- # # => "www.ruby-lang.org"
745
- #
746
- def self.parse(uri)
747
- DEFAULT_PARSER.parse(uri)
748
- end
749
-
750
- #
751
- # == Synopsis
752
- #
753
- # URI::join(str[, str, ...])
754
- #
755
- # == Args
756
- #
757
- # +str+::
758
- # String(s) to work with
759
- #
760
- # == Description
761
- #
762
- # Joins URIs.
763
- #
764
- # == Usage
765
- #
766
- # require 'uri'
767
- #
768
- # p URI.join("http://example.com/","main.rbx")
769
- # # => #<URI::HTTP:0x2022ac02 URL:http://localhost/main.rbx>
770
- #
771
- # p URI.join('http://example.com', 'foo')
772
- # # => #<URI::HTTP:0x01ab80a0 URL:http://example.com/foo>
773
- #
774
- # p URI.join('http://example.com', '/foo', '/bar')
775
- # # => #<URI::HTTP:0x01aaf0b0 URL:http://example.com/bar>
776
- #
777
- # p URI.join('http://example.com', '/foo', 'bar')
778
- # # => #<URI::HTTP:0x801a92af0 URL:http://example.com/bar>
779
- #
780
- # p URI.join('http://example.com', '/foo/', 'bar')
781
- # # => #<URI::HTTP:0x80135a3a0 URL:http://example.com/foo/bar>
782
- #
783
- #
784
- def self.join(*str)
785
- DEFAULT_PARSER.join(*str)
786
- end
787
-
788
- #
789
- # == Synopsis
790
- #
791
- # URI::extract(str[, schemes][,&blk])
792
- #
793
- # == Args
794
- #
795
- # +str+::
796
- # String to extract URIs from.
797
- # +schemes+::
798
- # Limit URI matching to a specific schemes.
799
- #
800
- # == Description
801
- #
802
- # Extracts URIs from a string. If block given, iterates through all matched URIs.
803
- # Returns nil if block given or array with matches.
804
- #
805
- # == Usage
806
- #
807
- # require "uri"
808
- #
809
- # URI.extract("text here http://foo.example.org/bla and here mailto:test@example.com and here also.")
810
- # # => ["http://foo.example.com/bla", "mailto:test@example.com"]
811
- #
812
- def self.extract(str, schemes = nil, &block)
813
- DEFAULT_PARSER.extract(str, schemes, &block)
814
- end
815
-
816
- #
817
- # == Synopsis
818
- #
819
- # URI::regexp([match_schemes])
820
- #
821
- # == Args
822
- #
823
- # +match_schemes+::
824
- # Array of schemes. If given, resulting regexp matches to URIs
825
- # whose scheme is one of the match_schemes.
826
- #
827
- # == Description
828
- # Returns a Regexp object which matches to URI-like strings.
829
- # The Regexp object returned by this method includes arbitrary
830
- # number of capture group (parentheses). Never rely on it's number.
831
- #
832
- # == Usage
833
- #
834
- # require 'uri'
835
- #
836
- # # extract first URI from html_string
837
- # html_string.slice(URI.regexp)
838
- #
839
- # # remove ftp URIs
840
- # html_string.sub(URI.regexp(['ftp'])
841
- #
842
- # # You should not rely on the number of parentheses
843
- # html_string.scan(URI.regexp) do |*matches|
844
- # p $&
845
- # end
846
- #
847
- def self.regexp(schemes = nil)
848
- DEFAULT_PARSER.make_regexp(schemes)
849
- end
850
-
851
- TBLENCWWWCOMP_ = {} # :nodoc:
852
- TBLDECWWWCOMP_ = {} # :nodoc:
853
- HTML5ASCIIINCOMPAT = [Encoding::UTF_7, Encoding::UTF_16BE, Encoding::UTF_16LE,
854
- Encoding::UTF_32BE, Encoding::UTF_32LE] # :nodoc:
855
-
856
- # Encode given +str+ to URL-encoded form data.
857
- #
858
- # This method doesn't convert *, -, ., 0-9, A-Z, _, a-z, but does convert SP
859
- # (ASCII space) to + and converts others to %XX.
860
- #
861
- # This is an implementation of
862
- # http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
863
- #
864
- # See URI.decode_www_form_component, URI.encode_www_form
865
- def self.encode_www_form_component(str)
866
- if TBLENCWWWCOMP_.empty?
867
- tbl = {}
868
- 256.times do |i|
869
- tbl[i.chr] = '%%%02X' % i
870
- end
871
- tbl[' '] = '+'
872
- begin
873
- TBLENCWWWCOMP_.replace(tbl)
874
- TBLENCWWWCOMP_.freeze
875
- rescue
876
- end
877
- end
878
- str = str.to_s
879
- if HTML5ASCIIINCOMPAT.include?(str.encoding)
880
- str = str.encode(Encoding::UTF_8)
881
- else
882
- str = str.dup
883
- end
884
- str.force_encoding(Encoding::ASCII_8BIT)
885
- str.gsub!(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_)
886
- str.force_encoding(Encoding::US_ASCII)
887
- end
888
-
889
- # Decode given +str+ of URL-encoded form data.
890
- #
891
- # This decods + to SP.
892
- #
893
- # See URI.encode_www_form_component, URI.decode_www_form
894
- def self.decode_www_form_component(str, enc=Encoding::UTF_8)
895
- if TBLDECWWWCOMP_.empty?
896
- tbl = {}
897
- 256.times do |i|
898
- h, l = i>>4, i&15
899
- tbl['%%%X%X' % [h, l]] = i.chr
900
- tbl['%%%x%X' % [h, l]] = i.chr
901
- tbl['%%%X%x' % [h, l]] = i.chr
902
- tbl['%%%x%x' % [h, l]] = i.chr
903
- end
904
- tbl['+'] = ' '
905
- begin
906
- TBLDECWWWCOMP_.replace(tbl)
907
- TBLDECWWWCOMP_.freeze
908
- rescue
909
- end
910
- end
911
- raise ArgumentError, "invalid %-encoding (#{str})" unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
912
- str.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
913
- end
914
-
915
- # Generate URL-encoded form data from given +enum+.
916
- #
917
- # This generates application/x-www-form-urlencoded data defined in HTML5
918
- # from given an Enumerable object.
919
- #
920
- # This internally uses URI.encode_www_form_component(str).
921
- #
922
- # This method doesn't convert the encoding of given items, so convert them
923
- # before call this method if you want to send data as other than original
924
- # encoding or mixed encoding data. (Strings which are encoded in an HTML5
925
- # ASCII incompatible encoding are converted to UTF-8.)
926
- #
927
- # This method doesn't handle files. When you send a file, use
928
- # multipart/form-data.
929
- #
930
- # This is an implementation of
931
- # http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
932
- #
933
- # URI.encode_www_form([["q", "ruby"], ["lang", "en"]])
934
- # #=> "q=ruby&lang=en"
935
- # URI.encode_www_form("q" => "ruby", "lang" => "en")
936
- # #=> "q=ruby&lang=en"
937
- # URI.encode_www_form("q" => ["ruby", "perl"], "lang" => "en")
938
- # #=> "q=ruby&q=perl&lang=en"
939
- # URI.encode_www_form([["q", "ruby"], ["q", "perl"], ["lang", "en"]])
940
- # #=> "q=ruby&q=perl&lang=en"
941
- #
942
- # See URI.encode_www_form_component, URI.decode_www_form
943
- def self.encode_www_form(enum)
944
- enum.map do |k,v|
945
- if v.nil?
946
- encode_www_form_component(k)
947
- elsif v.respond_to?(:to_ary)
948
- v.to_ary.map do |w|
949
- str = encode_www_form_component(k)
950
- unless w.nil?
951
- str << '='
952
- str << encode_www_form_component(w)
953
- end
954
- end.join('&')
955
- else
956
- str = encode_www_form_component(k)
957
- str << '='
958
- str << encode_www_form_component(v)
959
- end
960
- end.join('&')
961
- end
962
-
963
- WFKV_ = '(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)' # :nodoc:
964
-
965
- # Decode URL-encoded form data from given +str+.
966
- #
967
- # This decodes application/x-www-form-urlencoded data
968
- # and returns array of key-value array.
969
- # This internally uses URI.decode_www_form_component.
970
- #
971
- # _charset_ hack is not supported now because the mapping from given charset
972
- # to Ruby's encoding is not clear yet.
973
- # see also http://www.w3.org/TR/html5/syntax.html#character-encodings-0
974
- #
975
- # This refers http://www.w3.org/TR/html5/forms.html#url-encoded-form-data
976
- #
977
- # ary = URI.decode_www_form("a=1&a=2&b=3")
978
- # p ary #=> [['a', '1'], ['a', '2'], ['b', '3']]
979
- # p ary.assoc('a').last #=> '1'
980
- # p ary.assoc('b').last #=> '3'
981
- # p ary.rassoc('a').last #=> '2'
982
- # p Hash[ary] # => {"a"=>"2", "b"=>"3"}
983
- #
984
- # See URI.decode_www_form_component, URI.encode_www_form
985
- def self.decode_www_form(str, enc=Encoding::UTF_8)
986
- return [] if str.empty?
987
- unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/o =~ str
988
- raise ArgumentError, "invalid data of application/x-www-form-urlencoded (#{str})"
989
- end
990
- ary = []
991
- $&.scan(/([^=;&]+)=([^;&]*)/) do
992
- ary << [decode_www_form_component($1, enc), decode_www_form_component($2, enc)]
993
- end
994
- ary
995
- end
996
- end # module URI
997
-
998
- module Kernel
999
-
1000
- #
1001
- # Returns +uri+ converted to a URI object.
1002
- #
1003
- def URI(uri)
1004
- if uri.is_a?(URI::Generic)
1005
- uri
1006
- elsif uri = String.try_convert(uri)
1007
- URI.parse(uri)
1008
- else
1009
- raise ArgumentError,
1010
- "bad argument (expected URI object or URI string)"
1011
- end
1012
- end
1013
- module_function :URI
1014
- end