EmmanuelOga (owner)

Revisions

gist: 17342 Download_button fork
public
Public Clone URL: git://gist.github.com/17342.git
Embed All Files: show embed
Text #
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
require 'rubygems'
require 'active_support'
 
# generates a normalized URI object, adding the http scheme as default
def NormalizeURI(uri)
  new = uri.to_s
  new_uri = (new =~ /^https?\:\/\/.*/) ? URI(new) : URI("http://#{ new }")
  new_uri.normalize!
  # Google does not like this... strong hint that this is wrong....
  # new_uri.path << "/" unless new_uri.path.last == "/"
  new_uri
end
 
# Merge two uris without loosing query params
# Add more query params if provided.
#
# Options:
#
# uri: A string or URI object
# options: A Hash with query params, or
# another URI or string, or
# another URI or string plus a Hash of query params
#
def JoinURI(source, *options)
  uri = NormalizeURI(source)
 
  return uri if options.empty?
 
  query_params_1 = uri.query
 
  case options.length
  when 1
    first = options.first
 
    if String === first || URI === first
      other_uri = URI(first.to_s)
      query_params_2 = other_uri.query
 
    elsif Hash === first
      query_params_2 = first.to_query
 
    else
     raise ArgumentError, "supply a Hash of query params or another URI or String"
    end
 
  when 2
    other_uri = URI(options.first.to_s)
    query_params_2 = other_uri.query
    query_params_3 = options.last.to_query
 
  else
    raise ArgumentError, "please check the documentation and supply good params"
  end
 
  # Oh my god, ruby URIs suck so badly.... URI#merge does not work very intuitively!
  if other_uri && !other_uri.path.blank?
    uri.path << "/" unless uri.path.last == "/"
    other_path = other_uri.path
    other_path = other_path.slice(1..-1) if other_path.first == "/"
    uri.path << other_path
  end
  
  uri.query = [query_params_1, query_params_2, query_params_3].reject(&:blank?).join("&")
  NormalizeURI(uri)
end
 
if __FILE__ == $0
  require 'spec'
 
  describe "NormalizeURI" do
    it "should add scheme and final / to an uri" do
      NormalizeURI("www.yahoo.com?something=true").to_s.should == "http://www.yahoo.com/?something=true"
    end
  end
 
  describe "JoinedURI" do
    it "should handle google's case" do
      uri = JoinURI(
        "http://www.google.com/m8/feeds",
        '/contacts/default/full',
        "max-results" => 999999, "hd" => "default", "alt" => "json"
      )
      uri.to_s.should =~ /^http\:\/\/www\.google\.com\/m8\/feeds\/contacts\/default\/full\\?.*/
    end
    
    it "should raise ArgumentError when called with something not a Hash, String or URI" do
      lambda do
        JoinURI("http://localhost:3000", Object.new)
      end.should raise_error(ArgumentError)
 
      lambda do
        JoinURI("http://localhost:3000", "/path")
        JoinURI("http://localhost:3000", URI("/path"))
        JoinURI("http://localhost:3000", Hash.new)
      end.should_not raise_error(ArgumentError)
    end
 
    it "should raise ArgumentError when called with more than 3 params" do
      lambda do
        JoinURI("http://localhost:3000", 2, 3, 4)
      end.should raise_error(ArgumentError)
    end
 
    it "should return an new uri equal to the provided if called with a single String" do
      url = "http://test.com/"
      JoinURI(url).to_s.should == url
    end
 
    it "should return an new uri equal to the provided if called with a single URI" do
      uri = URI("http://test.com/")
      JoinURI(uri).should == uri
    end
 
    it "should append params to an uri" do
      JoinURI("http://localhost:3000/a", :x => "y").to_s.should == "http://localhost:3000/a?x=y"
      JoinURI("http://localhost:3000?b=c" , :x => "y").to_s.should == "http://localhost:3000/?b=c&x=y"
      JoinURI("http://localhost:3000/?b=c&j=k", :x => "y").to_s.should == "http://localhost:3000/?b=c&j=k&x=y"
      JoinURI("http://localhost:3000/d?e=f", :x => "y").to_s.should == "http://localhost:3000/d?e=f&x=y"
      JoinURI("http://localhost:3000/g/?h=i", :x => "y").to_s.should == "http://localhost:3000/g/?h=i&x=y"
      JoinURI("yahoo.com", :a => "uno", :b => "dos").to_s.should == "http://yahoo.com/?a=uno&b=dos"
    end
 
    describe "should append two uris preserving the query params of each one" do
      one = URI("www.yahoo.com?uno=dos")
      two = URI("/peteco/carabal?tres=4&cinco=seis")
      result = "http://www.yahoo.com/peteco/carabal?uno=dos&tres=4&cinco=seis"
      
      it "with two uris" do
        JoinURI(one, two).to_s.should == result
      end
      it "with two string" do
        JoinURI(one.to_s, two.to_s).to_s.should == result
      end
      it "with a uri and a string" do
        JoinURI(one, two.to_s).to_s.should == result
      end
      it "with a string and an uri" do
        JoinURI(one.to_s, two).to_s.should == result
      end
 
      it "with two uris and additional query params" do
        JoinURI(one, two, :more => :params).to_s.should == "#{ result }&more=params"
      end
      it "with two string and additional query params" do
        JoinURI(one.to_s, two.to_s, :more => :params).to_s.should == "#{ result }&more=params"
      end
      it "with a uri and a string and additional query params" do
        JoinURI(one, two.to_s, :more => :params).to_s.should == "#{ result }&more=params"
      end
      it "with a string and an uri and additional query params" do
        JoinURI(one.to_s, two, :more => :params).to_s.should == "#{ result }&more=params"
      end
    end
 
    it "should work with https schemes" do
      uri = JoinURI("https://something.com?param=a", "/other/?param=b", :param => "c")
      uri.to_s.should == "https://something.com/other/?param=a&param=b&param=c"
    end
  end
end