opal 0.3.15 → 0.3.16

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.
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