opal 0.3.11 → 0.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +13 -0
- data/Gemfile +10 -0
- data/LICENSE +20 -0
- data/README.md +11 -116
- data/Rakefile +126 -0
- data/bin/opal +1 -2
- data/docs/spec_runner.html +16 -0
- data/index.html +434 -0
- data/lib/opal.rb +14 -15
- data/lib/opal/builder.rb +46 -148
- data/lib/opal/command.rb +45 -115
- data/lib/opal/context.rb +139 -78
- data/lib/opal/dependency_builder.rb +34 -0
- data/lib/opal/environment.rb +92 -0
- data/lib/opal/parser/grammar.rb +4915 -0
- data/lib/opal/{parser.y → parser/grammar.y} +430 -284
- data/lib/opal/parser/lexer.rb +1329 -0
- data/lib/opal/parser/parser.rb +1460 -0
- data/lib/opal/parser/scope.rb +140 -0
- data/lib/opal/parser/sexp.rb +17 -0
- data/lib/opal/version.rb +2 -1
- data/opal.gemspec +23 -0
- data/opal.js +3149 -4162
- data/runtime/README.md +25 -0
- data/runtime/corelib/alpha.rb +10 -0
- data/runtime/corelib/array.rb +962 -0
- data/runtime/corelib/basic_object.rb +66 -0
- data/runtime/corelib/boolean.rb +44 -0
- data/runtime/corelib/class.rb +43 -0
- data/runtime/corelib/comparable.rb +25 -0
- data/runtime/corelib/complex.rb +2 -0
- data/runtime/corelib/dir.rb +29 -0
- data/runtime/corelib/enumerable.rb +316 -0
- data/runtime/corelib/enumerator.rb +80 -0
- data/runtime/corelib/error.rb +25 -0
- data/runtime/corelib/file.rb +80 -0
- data/runtime/corelib/hash.rb +503 -0
- data/runtime/corelib/io.rb +44 -0
- data/runtime/corelib/kernel.rb +237 -0
- data/runtime/corelib/load_order +29 -0
- data/runtime/corelib/match_data.rb +37 -0
- data/runtime/corelib/module.rb +171 -0
- data/runtime/corelib/native.rb +50 -0
- data/runtime/corelib/nil_class.rb +47 -0
- data/runtime/corelib/numeric.rb +219 -0
- data/runtime/corelib/object.rb +21 -0
- data/runtime/corelib/proc.rb +42 -0
- data/runtime/corelib/range.rb +38 -0
- data/runtime/corelib/rational.rb +16 -0
- data/runtime/corelib/regexp.rb +63 -0
- data/runtime/corelib/string.rb +185 -0
- data/runtime/corelib/struct.rb +97 -0
- data/runtime/corelib/time.rb +196 -0
- data/runtime/corelib/top_self.rb +7 -0
- data/runtime/gemlib/alpha.rb +5 -0
- data/runtime/gemlib/kernel.rb +17 -0
- data/runtime/gemlib/load_order +2 -0
- data/runtime/kernel/class.js +256 -0
- data/runtime/kernel/debug.js +42 -0
- data/runtime/kernel/init.js +114 -0
- data/runtime/kernel/load_order +5 -0
- data/runtime/kernel/loader.js +151 -0
- data/runtime/kernel/runtime.js +414 -0
- data/runtime/spec/README.md +34 -0
- data/runtime/spec/core/array/allocate_spec.rb +15 -0
- data/runtime/spec/core/array/append_spec.rb +31 -0
- data/runtime/spec/core/array/assoc_spec.rb +29 -0
- data/runtime/spec/core/array/at_spec.rb +38 -0
- data/runtime/spec/core/array/clear_spec.rb +22 -0
- data/runtime/spec/core/array/collect_spec.rb +3 -0
- data/runtime/spec/core/array/compact_spec.rb +42 -0
- data/runtime/spec/core/array/concat_spec.rb +21 -0
- data/runtime/spec/core/array/constructor_spec.rb +24 -0
- data/runtime/spec/core/array/count_spec.rb +11 -0
- data/runtime/spec/core/array/delete_at_spec.rb +31 -0
- data/runtime/spec/core/array/delete_if_spec.rb +24 -0
- data/runtime/spec/core/array/delete_spec.rb +26 -0
- data/runtime/spec/core/array/each_index_spec.rb +33 -0
- data/runtime/spec/core/array/each_spec.rb +11 -0
- data/runtime/spec/core/array/element_reference_spec.rb +136 -0
- data/runtime/spec/core/array/element_set_spec.rb +7 -0
- data/runtime/spec/core/array/empty_spec.rb +10 -0
- data/runtime/spec/core/array/eql_spec.rb +3 -0
- data/runtime/spec/core/array/equal_value_spec.rb +3 -0
- data/runtime/spec/core/array/fetch_spec.rb +26 -0
- data/runtime/spec/core/array/first_spec.rb +54 -0
- data/runtime/spec/core/array/fixtures/classes.rb +8 -0
- data/runtime/spec/core/array/flatten_spec.rb +41 -0
- data/runtime/spec/core/array/include_spec.rb +20 -0
- data/runtime/spec/core/array/insert_spec.rb +59 -0
- data/runtime/spec/core/array/last_spec.rb +57 -0
- data/runtime/spec/core/array/length_spec.rb +3 -0
- data/runtime/spec/core/array/map_spec.rb +3 -0
- data/runtime/spec/core/array/plus_spec.rb +16 -0
- data/runtime/spec/core/array/pop_spec.rb +79 -0
- data/runtime/spec/core/array/push_spec.rb +19 -0
- data/runtime/spec/core/array/rassoc_spec.rb +12 -0
- data/runtime/spec/core/array/reject_spec.rb +54 -0
- data/runtime/spec/core/array/replace_spec.rb +3 -0
- data/runtime/spec/core/array/reverse_each_spec.rb +18 -0
- data/runtime/spec/core/array/reverse_spec.rb +9 -0
- data/runtime/spec/core/array/shared/collect.rb +53 -0
- data/runtime/spec/core/array/shared/eql.rb +19 -0
- data/runtime/spec/core/array/shared/length.rb +6 -0
- data/runtime/spec/core/array/shared/replace.rb +31 -0
- data/runtime/spec/core/class/new_spec.rb +19 -0
- data/runtime/spec/core/enumerable/all_spec.rb +102 -0
- data/runtime/spec/core/enumerable/any_spec.rb +115 -0
- data/runtime/spec/core/enumerable/collect_spec.rb +3 -0
- data/runtime/spec/core/enumerable/count_spec.rb +29 -0
- data/runtime/spec/core/enumerable/detect_spec.rb +3 -0
- data/runtime/spec/core/enumerable/find_spec.rb +3 -0
- data/runtime/spec/core/enumerable/fixtures/classes.rb +26 -0
- data/runtime/spec/core/enumerable/shared/collect.rb +12 -0
- data/runtime/spec/core/enumerable/shared/entries.rb +7 -0
- data/runtime/spec/core/enumerable/shared/find.rb +49 -0
- data/runtime/spec/core/enumerable/to_a_spec.rb +7 -0
- data/runtime/spec/core/false/and_spec.rb +11 -0
- data/runtime/spec/core/false/inspect_spec.rb +7 -0
- data/runtime/spec/core/false/or_spec.rb +11 -0
- data/runtime/spec/core/false/to_s_spec.rb +7 -0
- data/runtime/spec/core/false/xor_spec.rb +11 -0
- data/runtime/spec/core/hash/allocate_spec.rb +15 -0
- data/runtime/spec/core/hash/assoc_spec.rb +29 -0
- data/runtime/spec/core/hash/clear_spec.rb +21 -0
- data/runtime/spec/core/hash/clone_spec.rb +12 -0
- data/runtime/spec/core/hash/default_spec.rb +6 -0
- data/runtime/spec/core/hash/delete_if_spec.rb +15 -0
- data/runtime/spec/core/hash/element_reference_spec.rb +16 -0
- data/runtime/spec/core/hash/element_set_spec.rb +8 -0
- data/runtime/spec/core/hash/new_spec.rb +13 -0
- data/runtime/spec/core/matchdata/to_a_spec.rb +7 -0
- data/runtime/spec/core/nil/and_spec.rb +12 -0
- data/runtime/spec/core/nil/inspect_spec.rb +8 -0
- data/runtime/spec/core/nil/nil_spec.rb +8 -0
- data/runtime/spec/core/nil/or_spec.rb +12 -0
- data/runtime/spec/core/nil/to_a_spec.rb +8 -0
- data/runtime/spec/core/nil/to_f_spec.rb +12 -0
- data/runtime/spec/core/nil/to_i_spec.rb +12 -0
- data/runtime/spec/core/nil/to_s_spec.rb +8 -0
- data/runtime/spec/core/nil/xor_spec.rb +12 -0
- data/runtime/spec/core/numeric/equal_value_spec.rb +11 -0
- data/runtime/spec/core/object/is_a_spec.rb +2 -0
- data/runtime/spec/core/object/shared/kind_of.rb +0 -0
- data/runtime/spec/core/regexp/match_spec.rb +23 -0
- data/runtime/spec/core/regexp/shared/match.rb +11 -0
- data/runtime/spec/core/symbol/to_proc_spec.rb +8 -0
- data/runtime/spec/core/true/and_spec.rb +11 -0
- data/runtime/spec/core/true/inspect_spec.rb +7 -0
- data/runtime/spec/core/true/or_spec.rb +11 -0
- data/runtime/spec/core/true/to_s_spec.rb +7 -0
- data/runtime/spec/core/true/xor_spec.rb +11 -0
- data/runtime/spec/language/alias_spec.rb +25 -0
- data/runtime/spec/language/and_spec.rb +62 -0
- data/runtime/spec/language/array_spec.rb +68 -0
- data/runtime/spec/language/block_spec.rb +105 -0
- data/runtime/spec/language/break_spec.rb +49 -0
- data/runtime/spec/language/case_spec.rb +165 -0
- data/runtime/spec/language/defined_spec.rb +80 -0
- data/runtime/spec/language/ensure_spec.rb +82 -0
- data/runtime/spec/language/fixtures/block.rb +19 -0
- data/runtime/spec/language/fixtures/break.rb +39 -0
- data/runtime/spec/language/fixtures/defined.rb +9 -0
- data/runtime/spec/language/fixtures/ensure.rb +37 -0
- data/runtime/spec/language/fixtures/next.rb +46 -0
- data/runtime/spec/language/fixtures/send.rb +36 -0
- data/runtime/spec/language/fixtures/super.rb +43 -0
- data/runtime/spec/language/hash_spec.rb +43 -0
- data/runtime/spec/language/if_spec.rb +278 -0
- data/runtime/spec/language/loop_spec.rb +32 -0
- data/runtime/spec/language/next_spec.rb +128 -0
- data/runtime/spec/language/or_spec.rb +65 -0
- data/runtime/spec/language/predefined_spec.rb +21 -0
- data/runtime/spec/language/regexp/interpolation_spec.rb +9 -0
- data/runtime/spec/language/regexp_spec.rb +7 -0
- data/runtime/spec/language/send_spec.rb +105 -0
- data/runtime/spec/language/string_spec.rb +4 -0
- data/runtime/spec/language/super_spec.rb +18 -0
- data/runtime/spec/language/symbol_spec.rb +41 -0
- data/runtime/spec/language/undef_spec.rb +16 -0
- data/runtime/spec/language/unless_spec.rb +44 -0
- data/runtime/spec/language/until_spec.rb +137 -0
- data/runtime/spec/language/variables_spec.rb +28 -0
- data/runtime/spec/language/versions/hash_1.9.rb +20 -0
- data/runtime/spec/language/while_spec.rb +175 -0
- data/runtime/spec/library/stringscanner/scan_spec.rb +36 -0
- data/runtime/spec/opal/forwardable/def_instance_delegator_spec.rb +49 -0
- data/runtime/spec/opal/opal/defined_spec.rb +15 -0
- data/runtime/spec/opal/opal/function_spec.rb +11 -0
- data/runtime/spec/opal/opal/native_spec.rb +16 -0
- data/runtime/spec/opal/opal/null_spec.rb +10 -0
- data/runtime/spec/opal/opal/number_spec.rb +11 -0
- data/runtime/spec/opal/opal/object_spec.rb +16 -0
- data/runtime/spec/opal/opal/string_spec.rb +11 -0
- data/runtime/spec/opal/opal/typeof_spec.rb +9 -0
- data/runtime/spec/opal/opal/undefined_spec.rb +10 -0
- data/runtime/spec/opal/true/case_compare_spec.rb +12 -0
- data/runtime/spec/opal/true/class_spec.rb +10 -0
- data/runtime/spec/spec_helper.rb +25 -0
- data/runtime/stdlib/base64.rb +91 -0
- data/runtime/stdlib/date.rb +4 -0
- data/{stdlib → runtime/stdlib}/dev.rb +0 -0
- data/runtime/stdlib/forwardable.rb +33 -0
- data/runtime/stdlib/optparse.rb +0 -0
- data/runtime/stdlib/pp.rb +6 -0
- data/{stdlib → runtime/stdlib}/racc/parser.rb +0 -0
- data/runtime/stdlib/rbconfig.rb +0 -0
- data/runtime/stdlib/si.rb +17 -0
- data/runtime/stdlib/strscan.rb +53 -0
- data/runtime/stdlib/uri.rb +111 -0
- data/runtime/stdlib/uri/common.rb +1014 -0
- data/runtime/stdlib/uri/ftp.rb +261 -0
- data/runtime/stdlib/uri/generic.rb +1599 -0
- data/runtime/stdlib/uri/http.rb +106 -0
- data/runtime/stdlib/uri/https.rb +22 -0
- data/runtime/stdlib/uri/ldap.rb +260 -0
- data/runtime/stdlib/uri/ldaps.rb +20 -0
- data/runtime/stdlib/uri/mailto.rb +280 -0
- data/spec/builder/build_source_spec.rb +52 -0
- data/spec/builder/fixtures/build_source/adam.rb +0 -0
- data/spec/builder/fixtures/build_source/bar/a.rb +0 -0
- data/spec/builder/fixtures/build_source/bar/wow/b.rb +0 -0
- data/spec/builder/fixtures/build_source/bar/wow/cow/c.rb +0 -0
- data/spec/builder/fixtures/build_source/beynon.rb +0 -0
- data/spec/builder/fixtures/build_source/charles.js +0 -0
- data/spec/builder/fixtures/build_source/foo/a.rb +0 -0
- data/spec/builder/fixtures/build_source/foo/b.rb +0 -0
- data/spec/builder/fixtures/build_source/foo/x.js +0 -0
- data/spec/builder/fixtures/build_source/foo/y.js +0 -0
- data/spec/builder/output_path_spec.rb +50 -0
- data/spec/grammar/alias_spec.rb +26 -0
- data/spec/grammar/and_spec.rb +13 -0
- data/spec/grammar/array_spec.rb +22 -0
- data/spec/grammar/attrasgn_spec.rb +28 -0
- data/spec/grammar/begin_spec.rb +38 -0
- data/spec/grammar/block_spec.rb +12 -0
- data/spec/grammar/break_spec.rb +17 -0
- data/spec/grammar/call_spec.rb +58 -0
- data/spec/grammar/class_spec.rb +35 -0
- data/spec/grammar/const_spec.rb +13 -0
- data/spec/grammar/cvar_spec.rb +11 -0
- data/spec/grammar/def_spec.rb +60 -0
- data/spec/grammar/false_spec.rb +17 -0
- data/spec/grammar/file_spec.rb +7 -0
- data/spec/grammar/gvar_spec.rb +13 -0
- data/spec/grammar/hash_spec.rb +17 -0
- data/spec/grammar/iasgn_spec.rb +9 -0
- data/spec/grammar/if_spec.rb +26 -0
- data/spec/grammar/iter_spec.rb +59 -0
- data/spec/grammar/ivar_spec.rb +9 -0
- data/spec/grammar/lasgn_spec.rb +8 -0
- data/spec/grammar/line_spec.rb +8 -0
- data/spec/grammar/lvar_spec.rb +38 -0
- data/spec/grammar/module_spec.rb +27 -0
- data/spec/grammar/nil_spec.rb +17 -0
- data/spec/grammar/not_spec.rb +27 -0
- data/spec/grammar/op_asgn1_spec.rb +23 -0
- data/spec/grammar/op_asgn2_spec.rb +23 -0
- data/spec/grammar/or_spec.rb +13 -0
- data/spec/grammar/return_spec.rb +17 -0
- data/spec/grammar/sclass_spec.rb +20 -0
- data/spec/grammar/self_spec.rb +17 -0
- data/spec/grammar/str_spec.rb +96 -0
- data/spec/grammar/super_spec.rb +20 -0
- data/spec/grammar/true_spec.rb +17 -0
- data/spec/grammar/undef_spec.rb +15 -0
- data/spec/grammar/unless_spec.rb +13 -0
- data/spec/grammar/while_spec.rb +15 -0
- data/spec/grammar/xstr_spec.rb +116 -0
- data/spec/grammar/yield_spec.rb +20 -0
- data/spec/spec_helper.rb +9 -0
- metadata +346 -21
- data/lib/opal/bundle.rb +0 -34
- data/lib/opal/lexer.rb +0 -902
- data/lib/opal/nodes.rb +0 -2150
- data/lib/opal/parser.rb +0 -4894
- data/lib/opal/rake/bundle_task.rb +0 -63
- data/opal-parser.js +0 -8343
- data/stdlib/strscan.rb +0 -52
- data/templates/init/Rakefile +0 -7
- data/templates/init/index.html +0 -17
- 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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
@@ -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
|