opal 0.3.11 → 0.3.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. data/.gitignore +13 -0
  2. data/Gemfile +10 -0
  3. data/LICENSE +20 -0
  4. data/README.md +11 -116
  5. data/Rakefile +126 -0
  6. data/bin/opal +1 -2
  7. data/docs/spec_runner.html +16 -0
  8. data/index.html +434 -0
  9. data/lib/opal.rb +14 -15
  10. data/lib/opal/builder.rb +46 -148
  11. data/lib/opal/command.rb +45 -115
  12. data/lib/opal/context.rb +139 -78
  13. data/lib/opal/dependency_builder.rb +34 -0
  14. data/lib/opal/environment.rb +92 -0
  15. data/lib/opal/parser/grammar.rb +4915 -0
  16. data/lib/opal/{parser.y → parser/grammar.y} +430 -284
  17. data/lib/opal/parser/lexer.rb +1329 -0
  18. data/lib/opal/parser/parser.rb +1460 -0
  19. data/lib/opal/parser/scope.rb +140 -0
  20. data/lib/opal/parser/sexp.rb +17 -0
  21. data/lib/opal/version.rb +2 -1
  22. data/opal.gemspec +23 -0
  23. data/opal.js +3149 -4162
  24. data/runtime/README.md +25 -0
  25. data/runtime/corelib/alpha.rb +10 -0
  26. data/runtime/corelib/array.rb +962 -0
  27. data/runtime/corelib/basic_object.rb +66 -0
  28. data/runtime/corelib/boolean.rb +44 -0
  29. data/runtime/corelib/class.rb +43 -0
  30. data/runtime/corelib/comparable.rb +25 -0
  31. data/runtime/corelib/complex.rb +2 -0
  32. data/runtime/corelib/dir.rb +29 -0
  33. data/runtime/corelib/enumerable.rb +316 -0
  34. data/runtime/corelib/enumerator.rb +80 -0
  35. data/runtime/corelib/error.rb +25 -0
  36. data/runtime/corelib/file.rb +80 -0
  37. data/runtime/corelib/hash.rb +503 -0
  38. data/runtime/corelib/io.rb +44 -0
  39. data/runtime/corelib/kernel.rb +237 -0
  40. data/runtime/corelib/load_order +29 -0
  41. data/runtime/corelib/match_data.rb +37 -0
  42. data/runtime/corelib/module.rb +171 -0
  43. data/runtime/corelib/native.rb +50 -0
  44. data/runtime/corelib/nil_class.rb +47 -0
  45. data/runtime/corelib/numeric.rb +219 -0
  46. data/runtime/corelib/object.rb +21 -0
  47. data/runtime/corelib/proc.rb +42 -0
  48. data/runtime/corelib/range.rb +38 -0
  49. data/runtime/corelib/rational.rb +16 -0
  50. data/runtime/corelib/regexp.rb +63 -0
  51. data/runtime/corelib/string.rb +185 -0
  52. data/runtime/corelib/struct.rb +97 -0
  53. data/runtime/corelib/time.rb +196 -0
  54. data/runtime/corelib/top_self.rb +7 -0
  55. data/runtime/gemlib/alpha.rb +5 -0
  56. data/runtime/gemlib/kernel.rb +17 -0
  57. data/runtime/gemlib/load_order +2 -0
  58. data/runtime/kernel/class.js +256 -0
  59. data/runtime/kernel/debug.js +42 -0
  60. data/runtime/kernel/init.js +114 -0
  61. data/runtime/kernel/load_order +5 -0
  62. data/runtime/kernel/loader.js +151 -0
  63. data/runtime/kernel/runtime.js +414 -0
  64. data/runtime/spec/README.md +34 -0
  65. data/runtime/spec/core/array/allocate_spec.rb +15 -0
  66. data/runtime/spec/core/array/append_spec.rb +31 -0
  67. data/runtime/spec/core/array/assoc_spec.rb +29 -0
  68. data/runtime/spec/core/array/at_spec.rb +38 -0
  69. data/runtime/spec/core/array/clear_spec.rb +22 -0
  70. data/runtime/spec/core/array/collect_spec.rb +3 -0
  71. data/runtime/spec/core/array/compact_spec.rb +42 -0
  72. data/runtime/spec/core/array/concat_spec.rb +21 -0
  73. data/runtime/spec/core/array/constructor_spec.rb +24 -0
  74. data/runtime/spec/core/array/count_spec.rb +11 -0
  75. data/runtime/spec/core/array/delete_at_spec.rb +31 -0
  76. data/runtime/spec/core/array/delete_if_spec.rb +24 -0
  77. data/runtime/spec/core/array/delete_spec.rb +26 -0
  78. data/runtime/spec/core/array/each_index_spec.rb +33 -0
  79. data/runtime/spec/core/array/each_spec.rb +11 -0
  80. data/runtime/spec/core/array/element_reference_spec.rb +136 -0
  81. data/runtime/spec/core/array/element_set_spec.rb +7 -0
  82. data/runtime/spec/core/array/empty_spec.rb +10 -0
  83. data/runtime/spec/core/array/eql_spec.rb +3 -0
  84. data/runtime/spec/core/array/equal_value_spec.rb +3 -0
  85. data/runtime/spec/core/array/fetch_spec.rb +26 -0
  86. data/runtime/spec/core/array/first_spec.rb +54 -0
  87. data/runtime/spec/core/array/fixtures/classes.rb +8 -0
  88. data/runtime/spec/core/array/flatten_spec.rb +41 -0
  89. data/runtime/spec/core/array/include_spec.rb +20 -0
  90. data/runtime/spec/core/array/insert_spec.rb +59 -0
  91. data/runtime/spec/core/array/last_spec.rb +57 -0
  92. data/runtime/spec/core/array/length_spec.rb +3 -0
  93. data/runtime/spec/core/array/map_spec.rb +3 -0
  94. data/runtime/spec/core/array/plus_spec.rb +16 -0
  95. data/runtime/spec/core/array/pop_spec.rb +79 -0
  96. data/runtime/spec/core/array/push_spec.rb +19 -0
  97. data/runtime/spec/core/array/rassoc_spec.rb +12 -0
  98. data/runtime/spec/core/array/reject_spec.rb +54 -0
  99. data/runtime/spec/core/array/replace_spec.rb +3 -0
  100. data/runtime/spec/core/array/reverse_each_spec.rb +18 -0
  101. data/runtime/spec/core/array/reverse_spec.rb +9 -0
  102. data/runtime/spec/core/array/shared/collect.rb +53 -0
  103. data/runtime/spec/core/array/shared/eql.rb +19 -0
  104. data/runtime/spec/core/array/shared/length.rb +6 -0
  105. data/runtime/spec/core/array/shared/replace.rb +31 -0
  106. data/runtime/spec/core/class/new_spec.rb +19 -0
  107. data/runtime/spec/core/enumerable/all_spec.rb +102 -0
  108. data/runtime/spec/core/enumerable/any_spec.rb +115 -0
  109. data/runtime/spec/core/enumerable/collect_spec.rb +3 -0
  110. data/runtime/spec/core/enumerable/count_spec.rb +29 -0
  111. data/runtime/spec/core/enumerable/detect_spec.rb +3 -0
  112. data/runtime/spec/core/enumerable/find_spec.rb +3 -0
  113. data/runtime/spec/core/enumerable/fixtures/classes.rb +26 -0
  114. data/runtime/spec/core/enumerable/shared/collect.rb +12 -0
  115. data/runtime/spec/core/enumerable/shared/entries.rb +7 -0
  116. data/runtime/spec/core/enumerable/shared/find.rb +49 -0
  117. data/runtime/spec/core/enumerable/to_a_spec.rb +7 -0
  118. data/runtime/spec/core/false/and_spec.rb +11 -0
  119. data/runtime/spec/core/false/inspect_spec.rb +7 -0
  120. data/runtime/spec/core/false/or_spec.rb +11 -0
  121. data/runtime/spec/core/false/to_s_spec.rb +7 -0
  122. data/runtime/spec/core/false/xor_spec.rb +11 -0
  123. data/runtime/spec/core/hash/allocate_spec.rb +15 -0
  124. data/runtime/spec/core/hash/assoc_spec.rb +29 -0
  125. data/runtime/spec/core/hash/clear_spec.rb +21 -0
  126. data/runtime/spec/core/hash/clone_spec.rb +12 -0
  127. data/runtime/spec/core/hash/default_spec.rb +6 -0
  128. data/runtime/spec/core/hash/delete_if_spec.rb +15 -0
  129. data/runtime/spec/core/hash/element_reference_spec.rb +16 -0
  130. data/runtime/spec/core/hash/element_set_spec.rb +8 -0
  131. data/runtime/spec/core/hash/new_spec.rb +13 -0
  132. data/runtime/spec/core/matchdata/to_a_spec.rb +7 -0
  133. data/runtime/spec/core/nil/and_spec.rb +12 -0
  134. data/runtime/spec/core/nil/inspect_spec.rb +8 -0
  135. data/runtime/spec/core/nil/nil_spec.rb +8 -0
  136. data/runtime/spec/core/nil/or_spec.rb +12 -0
  137. data/runtime/spec/core/nil/to_a_spec.rb +8 -0
  138. data/runtime/spec/core/nil/to_f_spec.rb +12 -0
  139. data/runtime/spec/core/nil/to_i_spec.rb +12 -0
  140. data/runtime/spec/core/nil/to_s_spec.rb +8 -0
  141. data/runtime/spec/core/nil/xor_spec.rb +12 -0
  142. data/runtime/spec/core/numeric/equal_value_spec.rb +11 -0
  143. data/runtime/spec/core/object/is_a_spec.rb +2 -0
  144. data/runtime/spec/core/object/shared/kind_of.rb +0 -0
  145. data/runtime/spec/core/regexp/match_spec.rb +23 -0
  146. data/runtime/spec/core/regexp/shared/match.rb +11 -0
  147. data/runtime/spec/core/symbol/to_proc_spec.rb +8 -0
  148. data/runtime/spec/core/true/and_spec.rb +11 -0
  149. data/runtime/spec/core/true/inspect_spec.rb +7 -0
  150. data/runtime/spec/core/true/or_spec.rb +11 -0
  151. data/runtime/spec/core/true/to_s_spec.rb +7 -0
  152. data/runtime/spec/core/true/xor_spec.rb +11 -0
  153. data/runtime/spec/language/alias_spec.rb +25 -0
  154. data/runtime/spec/language/and_spec.rb +62 -0
  155. data/runtime/spec/language/array_spec.rb +68 -0
  156. data/runtime/spec/language/block_spec.rb +105 -0
  157. data/runtime/spec/language/break_spec.rb +49 -0
  158. data/runtime/spec/language/case_spec.rb +165 -0
  159. data/runtime/spec/language/defined_spec.rb +80 -0
  160. data/runtime/spec/language/ensure_spec.rb +82 -0
  161. data/runtime/spec/language/fixtures/block.rb +19 -0
  162. data/runtime/spec/language/fixtures/break.rb +39 -0
  163. data/runtime/spec/language/fixtures/defined.rb +9 -0
  164. data/runtime/spec/language/fixtures/ensure.rb +37 -0
  165. data/runtime/spec/language/fixtures/next.rb +46 -0
  166. data/runtime/spec/language/fixtures/send.rb +36 -0
  167. data/runtime/spec/language/fixtures/super.rb +43 -0
  168. data/runtime/spec/language/hash_spec.rb +43 -0
  169. data/runtime/spec/language/if_spec.rb +278 -0
  170. data/runtime/spec/language/loop_spec.rb +32 -0
  171. data/runtime/spec/language/next_spec.rb +128 -0
  172. data/runtime/spec/language/or_spec.rb +65 -0
  173. data/runtime/spec/language/predefined_spec.rb +21 -0
  174. data/runtime/spec/language/regexp/interpolation_spec.rb +9 -0
  175. data/runtime/spec/language/regexp_spec.rb +7 -0
  176. data/runtime/spec/language/send_spec.rb +105 -0
  177. data/runtime/spec/language/string_spec.rb +4 -0
  178. data/runtime/spec/language/super_spec.rb +18 -0
  179. data/runtime/spec/language/symbol_spec.rb +41 -0
  180. data/runtime/spec/language/undef_spec.rb +16 -0
  181. data/runtime/spec/language/unless_spec.rb +44 -0
  182. data/runtime/spec/language/until_spec.rb +137 -0
  183. data/runtime/spec/language/variables_spec.rb +28 -0
  184. data/runtime/spec/language/versions/hash_1.9.rb +20 -0
  185. data/runtime/spec/language/while_spec.rb +175 -0
  186. data/runtime/spec/library/stringscanner/scan_spec.rb +36 -0
  187. data/runtime/spec/opal/forwardable/def_instance_delegator_spec.rb +49 -0
  188. data/runtime/spec/opal/opal/defined_spec.rb +15 -0
  189. data/runtime/spec/opal/opal/function_spec.rb +11 -0
  190. data/runtime/spec/opal/opal/native_spec.rb +16 -0
  191. data/runtime/spec/opal/opal/null_spec.rb +10 -0
  192. data/runtime/spec/opal/opal/number_spec.rb +11 -0
  193. data/runtime/spec/opal/opal/object_spec.rb +16 -0
  194. data/runtime/spec/opal/opal/string_spec.rb +11 -0
  195. data/runtime/spec/opal/opal/typeof_spec.rb +9 -0
  196. data/runtime/spec/opal/opal/undefined_spec.rb +10 -0
  197. data/runtime/spec/opal/true/case_compare_spec.rb +12 -0
  198. data/runtime/spec/opal/true/class_spec.rb +10 -0
  199. data/runtime/spec/spec_helper.rb +25 -0
  200. data/runtime/stdlib/base64.rb +91 -0
  201. data/runtime/stdlib/date.rb +4 -0
  202. data/{stdlib → runtime/stdlib}/dev.rb +0 -0
  203. data/runtime/stdlib/forwardable.rb +33 -0
  204. data/runtime/stdlib/optparse.rb +0 -0
  205. data/runtime/stdlib/pp.rb +6 -0
  206. data/{stdlib → runtime/stdlib}/racc/parser.rb +0 -0
  207. data/runtime/stdlib/rbconfig.rb +0 -0
  208. data/runtime/stdlib/si.rb +17 -0
  209. data/runtime/stdlib/strscan.rb +53 -0
  210. data/runtime/stdlib/uri.rb +111 -0
  211. data/runtime/stdlib/uri/common.rb +1014 -0
  212. data/runtime/stdlib/uri/ftp.rb +261 -0
  213. data/runtime/stdlib/uri/generic.rb +1599 -0
  214. data/runtime/stdlib/uri/http.rb +106 -0
  215. data/runtime/stdlib/uri/https.rb +22 -0
  216. data/runtime/stdlib/uri/ldap.rb +260 -0
  217. data/runtime/stdlib/uri/ldaps.rb +20 -0
  218. data/runtime/stdlib/uri/mailto.rb +280 -0
  219. data/spec/builder/build_source_spec.rb +52 -0
  220. data/spec/builder/fixtures/build_source/adam.rb +0 -0
  221. data/spec/builder/fixtures/build_source/bar/a.rb +0 -0
  222. data/spec/builder/fixtures/build_source/bar/wow/b.rb +0 -0
  223. data/spec/builder/fixtures/build_source/bar/wow/cow/c.rb +0 -0
  224. data/spec/builder/fixtures/build_source/beynon.rb +0 -0
  225. data/spec/builder/fixtures/build_source/charles.js +0 -0
  226. data/spec/builder/fixtures/build_source/foo/a.rb +0 -0
  227. data/spec/builder/fixtures/build_source/foo/b.rb +0 -0
  228. data/spec/builder/fixtures/build_source/foo/x.js +0 -0
  229. data/spec/builder/fixtures/build_source/foo/y.js +0 -0
  230. data/spec/builder/output_path_spec.rb +50 -0
  231. data/spec/grammar/alias_spec.rb +26 -0
  232. data/spec/grammar/and_spec.rb +13 -0
  233. data/spec/grammar/array_spec.rb +22 -0
  234. data/spec/grammar/attrasgn_spec.rb +28 -0
  235. data/spec/grammar/begin_spec.rb +38 -0
  236. data/spec/grammar/block_spec.rb +12 -0
  237. data/spec/grammar/break_spec.rb +17 -0
  238. data/spec/grammar/call_spec.rb +58 -0
  239. data/spec/grammar/class_spec.rb +35 -0
  240. data/spec/grammar/const_spec.rb +13 -0
  241. data/spec/grammar/cvar_spec.rb +11 -0
  242. data/spec/grammar/def_spec.rb +60 -0
  243. data/spec/grammar/false_spec.rb +17 -0
  244. data/spec/grammar/file_spec.rb +7 -0
  245. data/spec/grammar/gvar_spec.rb +13 -0
  246. data/spec/grammar/hash_spec.rb +17 -0
  247. data/spec/grammar/iasgn_spec.rb +9 -0
  248. data/spec/grammar/if_spec.rb +26 -0
  249. data/spec/grammar/iter_spec.rb +59 -0
  250. data/spec/grammar/ivar_spec.rb +9 -0
  251. data/spec/grammar/lasgn_spec.rb +8 -0
  252. data/spec/grammar/line_spec.rb +8 -0
  253. data/spec/grammar/lvar_spec.rb +38 -0
  254. data/spec/grammar/module_spec.rb +27 -0
  255. data/spec/grammar/nil_spec.rb +17 -0
  256. data/spec/grammar/not_spec.rb +27 -0
  257. data/spec/grammar/op_asgn1_spec.rb +23 -0
  258. data/spec/grammar/op_asgn2_spec.rb +23 -0
  259. data/spec/grammar/or_spec.rb +13 -0
  260. data/spec/grammar/return_spec.rb +17 -0
  261. data/spec/grammar/sclass_spec.rb +20 -0
  262. data/spec/grammar/self_spec.rb +17 -0
  263. data/spec/grammar/str_spec.rb +96 -0
  264. data/spec/grammar/super_spec.rb +20 -0
  265. data/spec/grammar/true_spec.rb +17 -0
  266. data/spec/grammar/undef_spec.rb +15 -0
  267. data/spec/grammar/unless_spec.rb +13 -0
  268. data/spec/grammar/while_spec.rb +15 -0
  269. data/spec/grammar/xstr_spec.rb +116 -0
  270. data/spec/grammar/yield_spec.rb +20 -0
  271. data/spec/spec_helper.rb +9 -0
  272. metadata +346 -21
  273. data/lib/opal/bundle.rb +0 -34
  274. data/lib/opal/lexer.rb +0 -902
  275. data/lib/opal/nodes.rb +0 -2150
  276. data/lib/opal/parser.rb +0 -4894
  277. data/lib/opal/rake/bundle_task.rb +0 -63
  278. data/opal-parser.js +0 -8343
  279. data/stdlib/strscan.rb +0 -52
  280. data/templates/init/Rakefile +0 -7
  281. data/templates/init/index.html +0 -17
  282. data/templates/init/lib/__NAME__.rb +0 -2
@@ -0,0 +1,10 @@
1
+ require File.expand_path('../../../spec_helper', __FILE__)
2
+
3
+ describe "TrueClass#class" do
4
+ it "should return true for the 'true' literal, otherwise false" do
5
+ true.class.should == TrueClass
6
+ (false.class == TrueClass).should == false
7
+ (nil.class == TrueClass).should == false
8
+ end
9
+ end
10
+
@@ -0,0 +1,25 @@
1
+ # make sure these tests are indeed running inside opal, not any other
2
+ # ruby engine.
3
+ #unless RUBY_ENGINE =~ /opal/
4
+ # abort <<-EOS
5
+ #Opal Tests
6
+ #==========
7
+ #
8
+ #These tests MUST be run inside opal, not `#{RUBY_ENGINE}' engine
9
+ #
10
+ #To run Array#first tests, for example:
11
+ #
12
+ # opal spec/core/array/first_spec.rb
13
+ #
14
+ #EOS
15
+ #end
16
+
17
+ require 'opal/spec/autorun'
18
+
19
+ ##
20
+ # Spec runner - if in browser, and spec_helper.rb is the main file then
21
+ # just run the spec files immediately.
22
+ if $0 == __FILE__
23
+ Dir['runtime/spec/**/*.rb'].each { |spec| require spec }
24
+ end
25
+
@@ -0,0 +1,91 @@
1
+ #
2
+ # = base64.rb: methods for base64-encoding and -decoding strings
3
+ #
4
+
5
+ # The Base64 module provides for the encoding (#encode64, #strict_encode64,
6
+ # #urlsafe_encode64) and decoding (#decode64, #strict_decode64,
7
+ # #urlsafe_decode64) of binary data using a Base64 representation.
8
+ #
9
+ # == Example
10
+ #
11
+ # A simple encoding and decoding.
12
+ #
13
+ # require "base64"
14
+ #
15
+ # enc = Base64.encode64('Send reinforcements')
16
+ # # -> "U2VuZCByZWluZm9yY2VtZW50cw==\n"
17
+ # plain = Base64.decode64(enc)
18
+ # # -> "Send reinforcements"
19
+ #
20
+ # The purpose of using base64 to encode data is that it translates any
21
+ # binary data into purely printable characters.
22
+
23
+ module Base64
24
+ module_function
25
+
26
+ # Returns the Base64-encoded version of +bin+.
27
+ # This method complies with RFC 2045.
28
+ # Line feeds are added to every 60 encoded charactors.
29
+ #
30
+ # require 'base64'
31
+ # Base64.encode64("Now is the time for all good coders\nto learn Ruby")
32
+ #
33
+ # <i>Generates:</i>
34
+ #
35
+ # Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKdG8gbGVhcm4g
36
+ # UnVieQ==
37
+ def encode64(bin)
38
+ [bin].pack("m")
39
+ end
40
+
41
+ # Returns the Base64-decoded version of +str+.
42
+ # This method complies with RFC 2045.
43
+ # Characters outside the base alphabet are ignored.
44
+ #
45
+ # require 'base64'
46
+ # str = 'VGhpcyBpcyBsaW5lIG9uZQpUaGlzIG' +
47
+ # 'lzIGxpbmUgdHdvClRoaXMgaXMgbGlu' +
48
+ # 'ZSB0aHJlZQpBbmQgc28gb24uLi4K'
49
+ # puts Base64.decode64(str)
50
+ #
51
+ # <i>Generates:</i>
52
+ #
53
+ # This is line one
54
+ # This is line two
55
+ # This is line three
56
+ # And so on...
57
+ def decode64(str)
58
+ str.unpack("m").first
59
+ end
60
+
61
+ # Returns the Base64-encoded version of +bin+.
62
+ # This method complies with RFC 4648.
63
+ # No line feeds are added.
64
+ def strict_encode64(bin)
65
+ [bin].pack("m0")
66
+ end
67
+
68
+ # Returns the Base64-decoded version of +str+.
69
+ # This method complies with RFC 4648.
70
+ # ArgumentError is raised if +str+ is incorrectly padded or contains
71
+ # non-alphabet characters. Note that CR or LF are also rejected.
72
+ def strict_decode64(str)
73
+ str.unpack("m0").first
74
+ end
75
+
76
+ # Returns the Base64-encoded version of +bin+.
77
+ # This method complies with ``Base 64 Encoding with URL and Filename Safe
78
+ # Alphabet'' in RFC 4648.
79
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
80
+ def urlsafe_encode64(bin)
81
+ strict_encode64(bin).tr("+/", "-_")
82
+ end
83
+
84
+ # Returns the Base64-decoded version of +str+.
85
+ # This method complies with ``Base 64 Encoding with URL and Filename Safe
86
+ # Alphabet'' in RFC 4648.
87
+ # The alphabet uses '-' instead of '+' and '_' instead of '/'.
88
+ def urlsafe_decode64(str)
89
+ strict_decode64(str.tr("-_", "+/"))
90
+ end
91
+ end
@@ -0,0 +1,4 @@
1
+ class Date
2
+ ITALY = :italy
3
+ end
4
+
File without changes
@@ -0,0 +1,33 @@
1
+ module Forwardable
2
+ def instance_delegate(hash)
3
+ hash.each do |methods, accessor|
4
+ methods = [methods] unless methods.respond_to?(:each)
5
+ methods.each do |method|
6
+ def_instance_delegator(accessor, method)
7
+ end
8
+ end
9
+ end
10
+
11
+ def def_instance_delegators(accessor, *methods)
12
+ methods.each { |m| def_instance_delegator accessor, m }
13
+ end
14
+
15
+ def def_instance_delegator(accessor, method, ali = method)
16
+ accessor = accessor.to_s
17
+ if accessor.start_with? '@'
18
+ define_method ali do |args|
19
+ `args = $slice.call(arguments, 1);`
20
+ instance_variable_get(accessor).__send__(method, *args)
21
+ end
22
+ else
23
+ define_method ali do |args|
24
+ `args = $slice.call(arguments, 1);`
25
+ __send__(accessor).__send__(method, *args)
26
+ end
27
+ end
28
+ end
29
+
30
+ alias delegate instance_delegate
31
+ alias def_delegators def_instance_delegators
32
+ alias def_delegator def_instance_delegator
33
+ end
File without changes
@@ -0,0 +1,6 @@
1
+ module Kernel
2
+ def pretty_inspect
3
+ inspect
4
+ end
5
+ end
6
+
File without changes
File without changes
@@ -0,0 +1,17 @@
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
@@ -0,0 +1,53 @@
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
@@ -0,0 +1,111 @@
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'
@@ -0,0 +1,1014 @@
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