simple-client 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (297) hide show
  1. data/.bundle/config +4 -0
  2. data/Gemfile +7 -0
  3. data/Gemfile.lock +23 -0
  4. data/bin/rake +16 -0
  5. data/lib/simple-client/simple-client.rb +229 -0
  6. data/lib/simple-client/version.rb +4 -0
  7. data/lib/simple-client.rb +1 -0
  8. data/test/test_simple-client.rb +236 -0
  9. data/vendor/bundle/ruby/1.8/bin/rake +19 -0
  10. data/vendor/bundle/ruby/1.8/cache/addressable-2.2.8.gem +0 -0
  11. data/vendor/bundle/ruby/1.8/cache/crack-0.3.1.gem +0 -0
  12. data/vendor/bundle/ruby/1.8/cache/rake-0.9.2.2.gem +0 -0
  13. data/vendor/bundle/ruby/1.8/cache/webmock-1.8.8.gem +0 -0
  14. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/CHANGELOG.md +126 -0
  15. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/Gemfile +17 -0
  16. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/Gemfile.lock +35 -0
  17. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/LICENSE.txt +202 -0
  18. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/README.md +83 -0
  19. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/Rakefile +37 -0
  20. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/lib/addressable/idna/native.rb +43 -0
  21. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/lib/addressable/idna/pure.rb +4886 -0
  22. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/lib/addressable/idna.rb +25 -0
  23. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/lib/addressable/template.rb +1047 -0
  24. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/lib/addressable/uri.rb +2288 -0
  25. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/lib/addressable/version.rb +30 -0
  26. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/spec/addressable/idna_spec.rb +216 -0
  27. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/spec/addressable/net_http_compat_spec.rb +26 -0
  28. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/spec/addressable/template_spec.rb +2144 -0
  29. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/spec/addressable/uri_spec.rb +4928 -0
  30. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/tasks/clobber.rake +2 -0
  31. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/tasks/gem.rake +85 -0
  32. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/tasks/git.rake +45 -0
  33. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/tasks/metrics.rake +22 -0
  34. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/tasks/rspec.rake +58 -0
  35. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/tasks/rubyforge.rake +89 -0
  36. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/tasks/yard.rake +27 -0
  37. data/vendor/bundle/ruby/1.8/gems/addressable-2.2.8/website/index.html +110 -0
  38. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/History +25 -0
  39. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/LICENSE +20 -0
  40. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/README.rdoc +42 -0
  41. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/Rakefile +32 -0
  42. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/crack.gemspec +53 -0
  43. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/lib/crack/json.rb +79 -0
  44. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/lib/crack/util.rb +17 -0
  45. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/lib/crack/xml.rb +232 -0
  46. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/lib/crack.rb +8 -0
  47. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/test/crack_test.rb +4 -0
  48. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/test/data/twittersearch-firefox.json +1 -0
  49. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/test/data/twittersearch-ie.json +1 -0
  50. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/test/hash_test.rb +28 -0
  51. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/test/json_test.rb +82 -0
  52. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/test/parser_test.rb +27 -0
  53. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/test/string_test.rb +31 -0
  54. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/test/test_helper.rb +12 -0
  55. data/vendor/bundle/ruby/1.8/gems/crack-0.3.1/test/xml_test.rb +499 -0
  56. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/CHANGES +522 -0
  57. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/MIT-LICENSE +21 -0
  58. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/README.rdoc +197 -0
  59. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/Rakefile +369 -0
  60. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/TODO +20 -0
  61. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/bin/rake +33 -0
  62. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/command_line_usage.rdoc +114 -0
  63. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/example/Rakefile1 +38 -0
  64. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/example/Rakefile2 +35 -0
  65. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/example/a.c +6 -0
  66. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/example/b.c +6 -0
  67. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/example/main.c +11 -0
  68. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/glossary.rdoc +51 -0
  69. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/jamis.rb +591 -0
  70. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/proto_rake.rdoc +127 -0
  71. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/rake.1.gz +0 -0
  72. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/rakefile.rdoc +557 -0
  73. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/rational.rdoc +151 -0
  74. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.4.14.rdoc +23 -0
  75. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.4.15.rdoc +35 -0
  76. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.5.0.rdoc +53 -0
  77. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.5.3.rdoc +78 -0
  78. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.5.4.rdoc +46 -0
  79. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.6.0.rdoc +141 -0
  80. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.7.0.rdoc +119 -0
  81. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.7.1.rdoc +59 -0
  82. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.7.2.rdoc +121 -0
  83. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.7.3.rdoc +47 -0
  84. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.8.0.rdoc +114 -0
  85. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.8.2.rdoc +165 -0
  86. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.8.3.rdoc +112 -0
  87. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.8.4.rdoc +147 -0
  88. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.8.5.rdoc +53 -0
  89. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.8.6.rdoc +55 -0
  90. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.8.7.rdoc +55 -0
  91. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.9.0.rdoc +112 -0
  92. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.9.1.rdoc +52 -0
  93. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/doc/release_notes/rake-0.9.2.rdoc +49 -0
  94. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/install.rb +90 -0
  95. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/alt_system.rb +109 -0
  96. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/application.rb +595 -0
  97. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/classic_namespace.rb +11 -0
  98. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/clean.rb +32 -0
  99. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/cloneable.rb +25 -0
  100. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/contrib/compositepublisher.rb +21 -0
  101. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/contrib/ftptools.rb +150 -0
  102. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/contrib/publisher.rb +73 -0
  103. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/contrib/rubyforgepublisher.rb +16 -0
  104. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/contrib/sshpublisher.rb +50 -0
  105. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/contrib/sys.rb +191 -0
  106. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/default_loader.rb +10 -0
  107. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/dsl_definition.rb +176 -0
  108. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/early_time.rb +18 -0
  109. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/ext/core.rb +27 -0
  110. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/ext/module.rb +39 -0
  111. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/ext/string.rb +167 -0
  112. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/ext/time.rb +14 -0
  113. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/file_creation_task.rb +24 -0
  114. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/file_list.rb +403 -0
  115. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/file_task.rb +47 -0
  116. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/file_utils.rb +114 -0
  117. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/file_utils_ext.rb +145 -0
  118. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/gempackagetask.rb +15 -0
  119. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/invocation_chain.rb +51 -0
  120. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/invocation_exception_mixin.rb +16 -0
  121. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/loaders/makefile.rb +40 -0
  122. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/multi_task.rb +16 -0
  123. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/name_space.rb +25 -0
  124. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/packagetask.rb +185 -0
  125. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/pathmap.rb +1 -0
  126. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/pseudo_status.rb +24 -0
  127. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/rake_module.rb +29 -0
  128. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/rake_test_loader.rb +22 -0
  129. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/rdoctask.rb +234 -0
  130. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/ruby182_test_unit_fix.rb +25 -0
  131. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/rule_recursion_overflow_error.rb +20 -0
  132. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/runtest.rb +21 -0
  133. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/task.rb +327 -0
  134. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/task_argument_error.rb +7 -0
  135. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/task_arguments.rb +78 -0
  136. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/task_manager.rb +307 -0
  137. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/tasklib.rb +22 -0
  138. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/testtask.rb +191 -0
  139. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/version.rb +8 -0
  140. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake/win32.rb +55 -0
  141. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/lib/rake.rb +69 -0
  142. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/file_creation.rb +34 -0
  143. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/helper.rb +492 -0
  144. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake.rb +40 -0
  145. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_application.rb +489 -0
  146. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_application_options.rb +335 -0
  147. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_clean.rb +14 -0
  148. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_definitions.rb +80 -0
  149. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_directory_task.rb +46 -0
  150. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_dsl.rb +77 -0
  151. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_early_time.rb +31 -0
  152. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_extension.rb +59 -0
  153. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_file_creation_task.rb +56 -0
  154. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_file_list.rb +628 -0
  155. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_file_list_path_map.rb +8 -0
  156. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_file_task.rb +102 -0
  157. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_file_utils.rb +305 -0
  158. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_ftp_file.rb +59 -0
  159. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_functional.rb +450 -0
  160. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_invocation_chain.rb +52 -0
  161. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_makefile_loader.rb +44 -0
  162. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_multi_task.rb +51 -0
  163. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_name_space.rb +43 -0
  164. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_package_task.rb +79 -0
  165. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_path_map.rb +157 -0
  166. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_path_map_explode.rb +34 -0
  167. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_path_map_partial.rb +18 -0
  168. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_pseudo_status.rb +21 -0
  169. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_rake_test_loader.rb +21 -0
  170. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_rdoc_task.rb +83 -0
  171. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_require.rb +40 -0
  172. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_rules.rb +327 -0
  173. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_task.rb +267 -0
  174. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_task_argument_parsing.rb +103 -0
  175. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_task_arguments.rb +88 -0
  176. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_task_lib.rb +9 -0
  177. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_task_manager.rb +157 -0
  178. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_task_manager_argument_resolution.rb +36 -0
  179. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_task_with_arguments.rb +173 -0
  180. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_test_task.rb +120 -0
  181. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_top_level_functions.rb +111 -0
  182. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_rake_win32.rb +72 -0
  183. data/vendor/bundle/ruby/1.8/gems/rake-0.9.2.2/test/test_sys.rb +20 -0
  184. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/CHANGELOG.md +749 -0
  185. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/Gemfile +21 -0
  186. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/Guardfile +24 -0
  187. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/LICENSE +20 -0
  188. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/README.md +728 -0
  189. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/Rakefile +65 -0
  190. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/api.rb +63 -0
  191. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/assertion_failure.rb +11 -0
  192. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/callback_registry.rb +35 -0
  193. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/config.rb +10 -0
  194. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/cucumber.rb +8 -0
  195. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/deprecation.rb +9 -0
  196. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/errors.rb +33 -0
  197. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/curb_adapter.rb +287 -0
  198. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/em_http_request/em_http_request_0_x.rb +151 -0
  199. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/em_http_request/em_http_request_1_x.rb +212 -0
  200. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/em_http_request_adapter.rb +11 -0
  201. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/excon_adapter.rb +95 -0
  202. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/http_lib_adapter.rb +7 -0
  203. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/http_lib_adapter_registry.rb +19 -0
  204. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/httpclient_adapter.rb +193 -0
  205. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/net_http.rb +279 -0
  206. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/net_http_response.rb +34 -0
  207. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/patron_adapter.rb +129 -0
  208. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/http_lib_adapters/typhoeus_hydra_adapter.rb +180 -0
  209. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/matchers/hash_including_matcher.rb +25 -0
  210. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/minitest.rb +15 -0
  211. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/rack_response.rb +63 -0
  212. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/request_execution_verifier.rb +56 -0
  213. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/request_pattern.rb +282 -0
  214. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/request_registry.rb +35 -0
  215. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/request_signature.rb +50 -0
  216. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/request_stub.rb +97 -0
  217. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/response.rb +144 -0
  218. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/responses_sequence.rb +40 -0
  219. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/rspec/matchers/request_pattern_matcher.rb +42 -0
  220. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/rspec/matchers/webmock_matcher.rb +46 -0
  221. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/rspec/matchers.rb +28 -0
  222. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/rspec.rb +33 -0
  223. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/stub_registry.rb +61 -0
  224. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/stub_request_snippet.rb +30 -0
  225. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/test_unit.rb +20 -0
  226. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/util/hash_counter.rb +25 -0
  227. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/util/hash_keys_stringifier.rb +23 -0
  228. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/util/headers.rb +43 -0
  229. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/util/json.rb +54 -0
  230. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/util/uri.rb +101 -0
  231. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/util/version_checker.rb +73 -0
  232. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/version.rb +3 -0
  233. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock/webmock.rb +124 -0
  234. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/lib/webmock.rb +49 -0
  235. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/minitest/test_helper.rb +29 -0
  236. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/minitest/test_webmock.rb +6 -0
  237. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/minitest/webmock_spec.rb +50 -0
  238. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/curb/curb_spec.rb +340 -0
  239. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/curb/curb_spec_helper.rb +144 -0
  240. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/em_http_request/em_http_request_spec.rb +183 -0
  241. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/em_http_request/em_http_request_spec_helper.rb +72 -0
  242. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/excon/excon_spec.rb +15 -0
  243. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/excon/excon_spec_helper.rb +38 -0
  244. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/httpclient/httpclient_spec.rb +76 -0
  245. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/httpclient/httpclient_spec_helper.rb +48 -0
  246. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/net_http/net_http_shared.rb +125 -0
  247. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/net_http/net_http_spec.rb +255 -0
  248. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/net_http/net_http_spec_helper.rb +55 -0
  249. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/net_http/real_net_http_spec.rb +20 -0
  250. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/patron/patron_spec.rb +136 -0
  251. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/patron/patron_spec_helper.rb +50 -0
  252. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/shared/allowing_and_disabling_net_connect.rb +142 -0
  253. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/shared/callbacks.rb +146 -0
  254. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/shared/complex_cross_concern_behaviors.rb +36 -0
  255. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/shared/enabling_and_disabling_webmock.rb +95 -0
  256. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/shared/precedence_of_stubs.rb +15 -0
  257. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/shared/request_expectations.rb +666 -0
  258. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/shared/returning_declared_responses.rb +367 -0
  259. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/shared/stubbing_requests.rb +447 -0
  260. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/typhoeus/typhoeus_hydra_spec.rb +74 -0
  261. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/typhoeus/typhoeus_hydra_spec_helper.rb +56 -0
  262. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/acceptance/webmock_shared.rb +41 -0
  263. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/quality_spec.rb +60 -0
  264. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/spec_helper.rb +57 -0
  265. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/support/example_curl_output.txt +22 -0
  266. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/support/my_rack_app.rb +48 -0
  267. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/support/network_connection.rb +25 -0
  268. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/support/webmock_server.rb +65 -0
  269. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/errors_spec.rb +32 -0
  270. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/http_lib_adapters/http_lib_adapter_registry_spec.rb +17 -0
  271. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/http_lib_adapters/http_lib_adapter_spec.rb +12 -0
  272. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/rack_response_spec.rb +74 -0
  273. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/request_execution_verifier_spec.rb +100 -0
  274. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/request_pattern_spec.rb +479 -0
  275. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/request_registry_spec.rb +75 -0
  276. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/request_signature_spec.rb +113 -0
  277. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/request_stub_spec.rb +198 -0
  278. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/response_spec.rb +267 -0
  279. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/stub_registry_spec.rb +86 -0
  280. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/stub_request_snippet_spec.rb +95 -0
  281. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/util/hash_counter_spec.rb +39 -0
  282. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/util/hash_keys_stringifier_spec.rb +27 -0
  283. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/util/headers_spec.rb +28 -0
  284. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/util/json_spec.rb +7 -0
  285. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/util/uri_spec.rb +257 -0
  286. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/util/version_checker_spec.rb +59 -0
  287. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/spec/unit/webmock_spec.rb +7 -0
  288. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/test/http_request.rb +24 -0
  289. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/test/shared_test.rb +76 -0
  290. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/test/test_helper.rb +23 -0
  291. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/test/test_webmock.rb +6 -0
  292. data/vendor/bundle/ruby/1.8/gems/webmock-1.8.8/webmock.gemspec +35 -0
  293. data/vendor/bundle/ruby/1.8/specifications/addressable-2.2.8.gemspec +38 -0
  294. data/vendor/bundle/ruby/1.8/specifications/crack-0.3.1.gemspec +25 -0
  295. data/vendor/bundle/ruby/1.8/specifications/rake-0.9.2.2.gemspec +33 -0
  296. data/vendor/bundle/ruby/1.8/specifications/webmock-1.8.8.gemspec +61 -0
  297. metadata +390 -0
@@ -0,0 +1,2288 @@
1
+ # encoding:utf-8
2
+ #--
3
+ # Copyright (C) 2006-2011 Bob Aman
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #++
17
+
18
+
19
+ require "addressable/version"
20
+ require "addressable/idna"
21
+
22
+ ##
23
+ # Addressable is a library for processing links and URIs.
24
+ module Addressable
25
+ ##
26
+ # This is an implementation of a URI parser based on
27
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>,
28
+ # <a href="http://www.ietf.org/rfc/rfc3987.txt">RFC 3987</a>.
29
+ class URI
30
+ ##
31
+ # Raised if something other than a uri is supplied.
32
+ class InvalidURIError < StandardError
33
+ end
34
+
35
+ ##
36
+ # Container for the character classes specified in
37
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
38
+ module CharacterClasses
39
+ ALPHA = "a-zA-Z"
40
+ DIGIT = "0-9"
41
+ GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@"
42
+ SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\="
43
+ RESERVED = GEN_DELIMS + SUB_DELIMS
44
+ UNRESERVED = ALPHA + DIGIT + "\\-\\.\\_\\~"
45
+ PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
46
+ SCHEME = ALPHA + DIGIT + "\\-\\+\\."
47
+ AUTHORITY = PCHAR
48
+ PATH = PCHAR + "\\/"
49
+ QUERY = PCHAR + "\\/\\?"
50
+ FRAGMENT = PCHAR + "\\/\\?"
51
+ end
52
+
53
+ SLASH = '/'
54
+ EMPTY_STR = ''
55
+
56
+ URIREGEX = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/
57
+
58
+ PORT_MAPPING = {
59
+ "http" => 80,
60
+ "https" => 443,
61
+ "ftp" => 21,
62
+ "tftp" => 69,
63
+ "sftp" => 22,
64
+ "ssh" => 22,
65
+ "svn+ssh" => 22,
66
+ "telnet" => 23,
67
+ "nntp" => 119,
68
+ "gopher" => 70,
69
+ "wais" => 210,
70
+ "ldap" => 389,
71
+ "prospero" => 1525
72
+ }
73
+
74
+ ##
75
+ # Returns a URI object based on the parsed string.
76
+ #
77
+ # @param [String, Addressable::URI, #to_str] uri
78
+ # The URI string to parse.
79
+ # No parsing is performed if the object is already an
80
+ # <code>Addressable::URI</code>.
81
+ #
82
+ # @return [Addressable::URI] The parsed URI.
83
+ def self.parse(uri)
84
+ # If we were given nil, return nil.
85
+ return nil unless uri
86
+ # If a URI object is passed, just return itself.
87
+ return uri.dup if uri.kind_of?(self)
88
+
89
+ # If a URI object of the Ruby standard library variety is passed,
90
+ # convert it to a string, then parse the string.
91
+ # We do the check this way because we don't want to accidentally
92
+ # cause a missing constant exception to be thrown.
93
+ if uri.class.name =~ /^URI\b/
94
+ uri = uri.to_s
95
+ end
96
+
97
+ # Otherwise, convert to a String
98
+ begin
99
+ uri = uri.to_str
100
+ rescue TypeError, NoMethodError
101
+ raise TypeError, "Can't convert #{uri.class} into String."
102
+ end if not uri.is_a? String
103
+
104
+ # This Regexp supplied as an example in RFC 3986, and it works great.
105
+ scan = uri.scan(URIREGEX)
106
+ fragments = scan[0]
107
+ scheme = fragments[1]
108
+ authority = fragments[3]
109
+ path = fragments[4]
110
+ query = fragments[6]
111
+ fragment = fragments[8]
112
+ user = nil
113
+ password = nil
114
+ host = nil
115
+ port = nil
116
+ if authority != nil
117
+ # The Regexp above doesn't split apart the authority.
118
+ userinfo = authority[/^([^\[\]]*)@/, 1]
119
+ if userinfo != nil
120
+ user = userinfo.strip[/^([^:]*):?/, 1]
121
+ password = userinfo.strip[/:(.*)$/, 1]
122
+ end
123
+ host = authority.gsub(/^([^\[\]]*)@/, EMPTY_STR).gsub(/:([^:@\[\]]*?)$/, EMPTY_STR)
124
+ port = authority[/:([^:@\[\]]*?)$/, 1]
125
+ end
126
+ if port == EMPTY_STR
127
+ port = nil
128
+ end
129
+
130
+ return new(
131
+ :scheme => scheme,
132
+ :user => user,
133
+ :password => password,
134
+ :host => host,
135
+ :port => port,
136
+ :path => path,
137
+ :query => query,
138
+ :fragment => fragment
139
+ )
140
+ end
141
+
142
+ ##
143
+ # Converts an input to a URI. The input does not have to be a valid
144
+ # URI — the method will use heuristics to guess what URI was intended.
145
+ # This is not standards-compliant, merely user-friendly.
146
+ #
147
+ # @param [String, Addressable::URI, #to_str] uri
148
+ # The URI string to parse.
149
+ # No parsing is performed if the object is already an
150
+ # <code>Addressable::URI</code>.
151
+ # @param [Hash] hints
152
+ # A <code>Hash</code> of hints to the heuristic parser.
153
+ # Defaults to <code>{:scheme => "http"}</code>.
154
+ #
155
+ # @return [Addressable::URI] The parsed URI.
156
+ def self.heuristic_parse(uri, hints={})
157
+ # If we were given nil, return nil.
158
+ return nil unless uri
159
+ # If a URI object is passed, just return itself.
160
+ return uri.dup if uri.kind_of?(self)
161
+ if !uri.respond_to?(:to_str)
162
+ raise TypeError, "Can't convert #{uri.class} into String."
163
+ end
164
+ # Otherwise, convert to a String
165
+ uri = uri.to_str.dup
166
+ hints = {
167
+ :scheme => "http"
168
+ }.merge(hints)
169
+ case uri
170
+ when /^http:\/+/
171
+ uri.gsub!(/^http:\/+/, "http://")
172
+ when /^https:\/+/
173
+ uri.gsub!(/^https:\/+/, "https://")
174
+ when /^feed:\/+http:\/+/
175
+ uri.gsub!(/^feed:\/+http:\/+/, "feed:http://")
176
+ when /^feed:\/+/
177
+ uri.gsub!(/^feed:\/+/, "feed://")
178
+ when /^file:\/+/
179
+ uri.gsub!(/^file:\/+/, "file:///")
180
+ end
181
+ parsed = self.parse(uri)
182
+ if parsed.scheme =~ /^[^\/?#\.]+\.[^\/?#]+$/
183
+ parsed = self.parse(hints[:scheme] + "://" + uri)
184
+ end
185
+ if parsed.path.include?(".")
186
+ new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1]
187
+ if new_host
188
+ parsed.defer_validation do
189
+ new_path = parsed.path.gsub(
190
+ Regexp.new("^" + Regexp.escape(new_host)), EMPTY_STR)
191
+ parsed.host = new_host
192
+ parsed.path = new_path
193
+ parsed.scheme = hints[:scheme] unless parsed.scheme
194
+ end
195
+ end
196
+ end
197
+ return parsed
198
+ end
199
+
200
+ ##
201
+ # Converts a path to a file scheme URI. If the path supplied is
202
+ # relative, it will be returned as a relative URI. If the path supplied
203
+ # is actually a non-file URI, it will parse the URI as if it had been
204
+ # parsed with <code>Addressable::URI.parse</code>. Handles all of the
205
+ # various Microsoft-specific formats for specifying paths.
206
+ #
207
+ # @param [String, Addressable::URI, #to_str] path
208
+ # Typically a <code>String</code> path to a file or directory, but
209
+ # will return a sensible return value if an absolute URI is supplied
210
+ # instead.
211
+ #
212
+ # @return [Addressable::URI]
213
+ # The parsed file scheme URI or the original URI if some other URI
214
+ # scheme was provided.
215
+ #
216
+ # @example
217
+ # base = Addressable::URI.convert_path("/absolute/path/")
218
+ # uri = Addressable::URI.convert_path("relative/path")
219
+ # (base + uri).to_s
220
+ # #=> "file:///absolute/path/relative/path"
221
+ #
222
+ # Addressable::URI.convert_path(
223
+ # "c:\\windows\\My Documents 100%20\\foo.txt"
224
+ # ).to_s
225
+ # #=> "file:///c:/windows/My%20Documents%20100%20/foo.txt"
226
+ #
227
+ # Addressable::URI.convert_path("http://example.com/").to_s
228
+ # #=> "http://example.com/"
229
+ def self.convert_path(path)
230
+ # If we were given nil, return nil.
231
+ return nil unless path
232
+ # If a URI object is passed, just return itself.
233
+ return path if path.kind_of?(self)
234
+ if !path.respond_to?(:to_str)
235
+ raise TypeError, "Can't convert #{path.class} into String."
236
+ end
237
+ # Otherwise, convert to a String
238
+ path = path.to_str.strip
239
+
240
+ path.gsub!(/^file:\/?\/?/, EMPTY_STR) if path =~ /^file:\/?\/?/
241
+ path = SLASH + path if path =~ /^([a-zA-Z])[\|:]/
242
+ uri = self.parse(path)
243
+
244
+ if uri.scheme == nil
245
+ # Adjust windows-style uris
246
+ uri.path.gsub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do
247
+ "/#{$1.downcase}:/"
248
+ end
249
+ uri.path.gsub!(/\\/, SLASH)
250
+ if File.exists?(uri.path) &&
251
+ File.stat(uri.path).directory?
252
+ uri.path.gsub!(/\/$/, EMPTY_STR)
253
+ uri.path = uri.path + '/'
254
+ end
255
+
256
+ # If the path is absolute, set the scheme and host.
257
+ if uri.path =~ /^\//
258
+ uri.scheme = "file"
259
+ uri.host = EMPTY_STR
260
+ end
261
+ uri.normalize!
262
+ end
263
+
264
+ return uri
265
+ end
266
+
267
+ ##
268
+ # Joins several URIs together.
269
+ #
270
+ # @param [String, Addressable::URI, #to_str] *uris
271
+ # The URIs to join.
272
+ #
273
+ # @return [Addressable::URI] The joined URI.
274
+ #
275
+ # @example
276
+ # base = "http://example.com/"
277
+ # uri = Addressable::URI.parse("relative/path")
278
+ # Addressable::URI.join(base, uri)
279
+ # #=> #<Addressable::URI:0xcab390 URI:http://example.com/relative/path>
280
+ def self.join(*uris)
281
+ uri_objects = uris.collect do |uri|
282
+ if !uri.respond_to?(:to_str)
283
+ raise TypeError, "Can't convert #{uri.class} into String."
284
+ end
285
+ uri.kind_of?(self) ? uri : self.parse(uri.to_str)
286
+ end
287
+ result = uri_objects.shift.dup
288
+ for uri in uri_objects
289
+ result.join!(uri)
290
+ end
291
+ return result
292
+ end
293
+
294
+ ##
295
+ # Percent encodes a URI component.
296
+ #
297
+ # @param [String, #to_str] component The URI component to encode.
298
+ #
299
+ # @param [String, Regexp] character_class
300
+ # The characters which are not percent encoded. If a <code>String</code>
301
+ # is passed, the <code>String</code> must be formatted as a regular
302
+ # expression character class. (Do not include the surrounding square
303
+ # brackets.) For example, <code>"b-zB-Z0-9"</code> would cause
304
+ # everything but the letters 'b' through 'z' and the numbers '0' through
305
+ # '9' to be percent encoded. If a <code>Regexp</code> is passed, the
306
+ # value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A set of
307
+ # useful <code>String</code> values may be found in the
308
+ # <code>Addressable::URI::CharacterClasses</code> module. The default
309
+ # value is the reserved plus unreserved character classes specified in
310
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
311
+ #
312
+ # @return [String] The encoded component.
313
+ #
314
+ # @example
315
+ # Addressable::URI.encode_component("simple/example", "b-zB-Z0-9")
316
+ # => "simple%2Fex%61mple"
317
+ # Addressable::URI.encode_component("simple/example", /[^b-zB-Z0-9]/)
318
+ # => "simple%2Fex%61mple"
319
+ # Addressable::URI.encode_component(
320
+ # "simple/example", Addressable::URI::CharacterClasses::UNRESERVED
321
+ # )
322
+ # => "simple%2Fexample"
323
+ def self.encode_component(component, character_class=
324
+ CharacterClasses::RESERVED + CharacterClasses::UNRESERVED)
325
+ return nil if component.nil?
326
+
327
+ begin
328
+ if component.kind_of?(Symbol) || component.kind_of?(Numeric)
329
+ component = component.to_s
330
+ else
331
+ component = component.to_str
332
+ end
333
+ rescue TypeError, NoMethodError
334
+ raise TypeError, "Can't convert #{component.class} into String."
335
+ end if !component.is_a? String
336
+
337
+ if ![String, Regexp].include?(character_class.class)
338
+ raise TypeError,
339
+ "Expected String or Regexp, got #{character_class.inspect}"
340
+ end
341
+ if character_class.kind_of?(String)
342
+ character_class = /[^#{character_class}]/
343
+ end
344
+ if component.respond_to?(:force_encoding)
345
+ # We can't perform regexps on invalid UTF sequences, but
346
+ # here we need to, so switch to ASCII.
347
+ component = component.dup
348
+ component.force_encoding(Encoding::ASCII_8BIT)
349
+ end
350
+ return component.gsub(character_class) do |sequence|
351
+ (sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join
352
+ end
353
+ end
354
+
355
+ class << self
356
+ alias_method :encode_component, :encode_component
357
+ end
358
+
359
+ ##
360
+ # Unencodes any percent encoded characters within a URI component.
361
+ # This method may be used for unencoding either components or full URIs,
362
+ # however, it is recommended to use the <code>unencode_component</code>
363
+ # alias when unencoding components.
364
+ #
365
+ # @param [String, Addressable::URI, #to_str] uri
366
+ # The URI or component to unencode.
367
+ #
368
+ # @param [Class] returning
369
+ # The type of object to return.
370
+ # This value may only be set to <code>String</code> or
371
+ # <code>Addressable::URI</code>. All other values are invalid. Defaults
372
+ # to <code>String</code>.
373
+ #
374
+ # @return [String, Addressable::URI]
375
+ # The unencoded component or URI.
376
+ # The return type is determined by the <code>returning</code> parameter.
377
+ def self.unencode(uri, returning=String)
378
+ return nil if uri.nil?
379
+
380
+ begin
381
+ uri = uri.to_str
382
+ rescue NoMethodError, TypeError
383
+ raise TypeError, "Can't convert #{uri.class} into String."
384
+ end if !uri.is_a? String
385
+ if ![String, ::Addressable::URI].include?(returning)
386
+ raise TypeError,
387
+ "Expected Class (String or Addressable::URI), " +
388
+ "got #{returning.inspect}"
389
+ end
390
+ result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence|
391
+ sequence[1..3].to_i(16).chr
392
+ end
393
+ result.force_encoding("utf-8") if result.respond_to?(:force_encoding)
394
+ if returning == String
395
+ return result
396
+ elsif returning == ::Addressable::URI
397
+ return ::Addressable::URI.parse(result)
398
+ end
399
+ end
400
+
401
+ class << self
402
+ alias_method :unescape, :unencode
403
+ alias_method :unencode_component, :unencode
404
+ alias_method :unescape_component, :unencode
405
+ end
406
+
407
+
408
+ ##
409
+ # Normalizes the encoding of a URI component.
410
+ #
411
+ # @param [String, #to_str] component The URI component to encode.
412
+ #
413
+ # @param [String, Regexp] character_class
414
+ # The characters which are not percent encoded. If a <code>String</code>
415
+ # is passed, the <code>String</code> must be formatted as a regular
416
+ # expression character class. (Do not include the surrounding square
417
+ # brackets.) For example, <code>"b-zB-Z0-9"</code> would cause
418
+ # everything but the letters 'b' through 'z' and the numbers '0'
419
+ # through '9' to be percent encoded. If a <code>Regexp</code> is passed,
420
+ # the value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A
421
+ # set of useful <code>String</code> values may be found in the
422
+ # <code>Addressable::URI::CharacterClasses</code> module. The default
423
+ # value is the reserved plus unreserved character classes specified in
424
+ # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
425
+ #
426
+ # @return [String] The normalized component.
427
+ #
428
+ # @example
429
+ # Addressable::URI.normalize_component("simpl%65/%65xampl%65", "b-zB-Z")
430
+ # => "simple%2Fex%61mple"
431
+ # Addressable::URI.normalize_component(
432
+ # "simpl%65/%65xampl%65", /[^b-zB-Z]/
433
+ # )
434
+ # => "simple%2Fex%61mple"
435
+ # Addressable::URI.normalize_component(
436
+ # "simpl%65/%65xampl%65",
437
+ # Addressable::URI::CharacterClasses::UNRESERVED
438
+ # )
439
+ # => "simple%2Fexample"
440
+ def self.normalize_component(component, character_class=
441
+ CharacterClasses::RESERVED + CharacterClasses::UNRESERVED)
442
+ return nil if component.nil?
443
+
444
+ begin
445
+ component = component.to_str
446
+ rescue NoMethodError, TypeError
447
+ raise TypeError, "Can't convert #{component.class} into String."
448
+ end if !component.is_a? String
449
+
450
+ if ![String, Regexp].include?(character_class.class)
451
+ raise TypeError,
452
+ "Expected String or Regexp, got #{character_class.inspect}"
453
+ end
454
+ if character_class.kind_of?(String)
455
+ character_class = /[^#{character_class}]/
456
+ end
457
+ if component.respond_to?(:force_encoding)
458
+ # We can't perform regexps on invalid UTF sequences, but
459
+ # here we need to, so switch to ASCII.
460
+ component = component.dup
461
+ component.force_encoding(Encoding::ASCII_8BIT)
462
+ end
463
+ unencoded = self.unencode_component(component)
464
+ begin
465
+ encoded = self.encode_component(
466
+ Addressable::IDNA.unicode_normalize_kc(unencoded),
467
+ character_class
468
+ )
469
+ rescue ArgumentError
470
+ encoded = self.encode_component(unencoded)
471
+ end
472
+ return encoded
473
+ end
474
+
475
+ ##
476
+ # Percent encodes any special characters in the URI.
477
+ #
478
+ # @param [String, Addressable::URI, #to_str] uri
479
+ # The URI to encode.
480
+ #
481
+ # @param [Class] returning
482
+ # The type of object to return.
483
+ # This value may only be set to <code>String</code> or
484
+ # <code>Addressable::URI</code>. All other values are invalid. Defaults
485
+ # to <code>String</code>.
486
+ #
487
+ # @return [String, Addressable::URI]
488
+ # The encoded URI.
489
+ # The return type is determined by the <code>returning</code> parameter.
490
+ def self.encode(uri, returning=String)
491
+ return nil if uri.nil?
492
+
493
+ begin
494
+ uri = uri.to_str
495
+ rescue NoMethodError, TypeError
496
+ raise TypeError, "Can't convert #{uri.class} into String."
497
+ end if !uri.is_a? String
498
+
499
+ if ![String, ::Addressable::URI].include?(returning)
500
+ raise TypeError,
501
+ "Expected Class (String or Addressable::URI), " +
502
+ "got #{returning.inspect}"
503
+ end
504
+ uri_object = uri.kind_of?(self) ? uri : self.parse(uri)
505
+ encoded_uri = Addressable::URI.new(
506
+ :scheme => self.encode_component(uri_object.scheme,
507
+ Addressable::URI::CharacterClasses::SCHEME),
508
+ :authority => self.encode_component(uri_object.authority,
509
+ Addressable::URI::CharacterClasses::AUTHORITY),
510
+ :path => self.encode_component(uri_object.path,
511
+ Addressable::URI::CharacterClasses::PATH),
512
+ :query => self.encode_component(uri_object.query,
513
+ Addressable::URI::CharacterClasses::QUERY),
514
+ :fragment => self.encode_component(uri_object.fragment,
515
+ Addressable::URI::CharacterClasses::FRAGMENT)
516
+ )
517
+ if returning == String
518
+ return encoded_uri.to_s
519
+ elsif returning == ::Addressable::URI
520
+ return encoded_uri
521
+ end
522
+ end
523
+
524
+ class << self
525
+ alias_method :escape, :encode
526
+ end
527
+
528
+ ##
529
+ # Normalizes the encoding of a URI. Characters within a hostname are
530
+ # not percent encoded to allow for internationalized domain names.
531
+ #
532
+ # @param [String, Addressable::URI, #to_str] uri
533
+ # The URI to encode.
534
+ #
535
+ # @param [Class] returning
536
+ # The type of object to return.
537
+ # This value may only be set to <code>String</code> or
538
+ # <code>Addressable::URI</code>. All other values are invalid. Defaults
539
+ # to <code>String</code>.
540
+ #
541
+ # @return [String, Addressable::URI]
542
+ # The encoded URI.
543
+ # The return type is determined by the <code>returning</code> parameter.
544
+ def self.normalized_encode(uri, returning=String)
545
+ begin
546
+ uri = uri.to_str
547
+ rescue NoMethodError, TypeError
548
+ raise TypeError, "Can't convert #{uri.class} into String."
549
+ end if !uri.is_a? String
550
+
551
+ if ![String, ::Addressable::URI].include?(returning)
552
+ raise TypeError,
553
+ "Expected Class (String or Addressable::URI), " +
554
+ "got #{returning.inspect}"
555
+ end
556
+ uri_object = uri.kind_of?(self) ? uri : self.parse(uri)
557
+ components = {
558
+ :scheme => self.unencode_component(uri_object.scheme),
559
+ :user => self.unencode_component(uri_object.user),
560
+ :password => self.unencode_component(uri_object.password),
561
+ :host => self.unencode_component(uri_object.host),
562
+ :port => uri_object.port,
563
+ :path => self.unencode_component(uri_object.path),
564
+ :query => self.unencode_component(uri_object.query),
565
+ :fragment => self.unencode_component(uri_object.fragment)
566
+ }
567
+ components.each do |key, value|
568
+ if value != nil
569
+ begin
570
+ components[key] =
571
+ Addressable::IDNA.unicode_normalize_kc(value.to_str)
572
+ rescue ArgumentError
573
+ # Likely a malformed UTF-8 character, skip unicode normalization
574
+ components[key] = value.to_str
575
+ end
576
+ end
577
+ end
578
+ encoded_uri = Addressable::URI.new(
579
+ :scheme => self.encode_component(components[:scheme],
580
+ Addressable::URI::CharacterClasses::SCHEME),
581
+ :user => self.encode_component(components[:user],
582
+ Addressable::URI::CharacterClasses::UNRESERVED),
583
+ :password => self.encode_component(components[:password],
584
+ Addressable::URI::CharacterClasses::UNRESERVED),
585
+ :host => components[:host],
586
+ :port => components[:port],
587
+ :path => self.encode_component(components[:path],
588
+ Addressable::URI::CharacterClasses::PATH),
589
+ :query => self.encode_component(components[:query],
590
+ Addressable::URI::CharacterClasses::QUERY),
591
+ :fragment => self.encode_component(components[:fragment],
592
+ Addressable::URI::CharacterClasses::FRAGMENT)
593
+ )
594
+ if returning == String
595
+ return encoded_uri.to_s
596
+ elsif returning == ::Addressable::URI
597
+ return encoded_uri
598
+ end
599
+ end
600
+
601
+ ##
602
+ # Encodes a set of key/value pairs according to the rules for the
603
+ # <code>application/x-www-form-urlencoded</code> MIME type.
604
+ #
605
+ # @param [#to_hash, #to_ary] form_values
606
+ # The form values to encode.
607
+ #
608
+ # @param [TrueClass, FalseClass] sort
609
+ # Sort the key/value pairs prior to encoding.
610
+ # Defaults to <code>false</code>.
611
+ #
612
+ # @return [String]
613
+ # The encoded value.
614
+ def self.form_encode(form_values, sort=false)
615
+ if form_values.respond_to?(:to_hash)
616
+ form_values = form_values.to_hash.to_a
617
+ elsif form_values.respond_to?(:to_ary)
618
+ form_values = form_values.to_ary
619
+ else
620
+ raise TypeError, "Can't convert #{form_values.class} into Array."
621
+ end
622
+
623
+ form_values = form_values.inject([]) do |accu, (key, value)|
624
+ if value.kind_of?(Array)
625
+ value.each do |v|
626
+ accu << [key.to_s, v.to_s]
627
+ end
628
+ else
629
+ accu << [key.to_s, value.to_s]
630
+ end
631
+ accu
632
+ end
633
+
634
+ if sort
635
+ # Useful for OAuth and optimizing caching systems
636
+ form_values = form_values.sort
637
+ end
638
+ escaped_form_values = form_values.map do |(key, value)|
639
+ # Line breaks are CRLF pairs
640
+ [
641
+ self.encode_component(
642
+ key.gsub(/(\r\n|\n|\r)/, "\r\n"),
643
+ CharacterClasses::UNRESERVED
644
+ ).gsub("%20", "+"),
645
+ self.encode_component(
646
+ value.gsub(/(\r\n|\n|\r)/, "\r\n"),
647
+ CharacterClasses::UNRESERVED
648
+ ).gsub("%20", "+")
649
+ ]
650
+ end
651
+ return (escaped_form_values.map do |(key, value)|
652
+ "#{key}=#{value}"
653
+ end).join("&")
654
+ end
655
+
656
+ ##
657
+ # Decodes a <code>String</code> according to the rules for the
658
+ # <code>application/x-www-form-urlencoded</code> MIME type.
659
+ #
660
+ # @param [String, #to_str] encoded_value
661
+ # The form values to decode.
662
+ #
663
+ # @return [Array]
664
+ # The decoded values.
665
+ # This is not a <code>Hash</code> because of the possibility for
666
+ # duplicate keys.
667
+ def self.form_unencode(encoded_value)
668
+ if !encoded_value.respond_to?(:to_str)
669
+ raise TypeError, "Can't convert #{encoded_value.class} into String."
670
+ end
671
+ encoded_value = encoded_value.to_str
672
+ split_values = encoded_value.split("&").map do |pair|
673
+ pair.split("=", 2)
674
+ end
675
+ return split_values.map do |(key, value)|
676
+ [
677
+ key ? self.unencode_component(
678
+ key.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n") : nil,
679
+ value ? (self.unencode_component(
680
+ value.gsub("+", "%20")).gsub(/(\r\n|\n|\r)/, "\n")) : nil
681
+ ]
682
+ end
683
+ end
684
+
685
+ ##
686
+ # Creates a new uri object from component parts.
687
+ #
688
+ # @option [String, #to_str] scheme The scheme component.
689
+ # @option [String, #to_str] user The user component.
690
+ # @option [String, #to_str] password The password component.
691
+ # @option [String, #to_str] userinfo
692
+ # The userinfo component. If this is supplied, the user and password
693
+ # components must be omitted.
694
+ # @option [String, #to_str] host The host component.
695
+ # @option [String, #to_str] port The port component.
696
+ # @option [String, #to_str] authority
697
+ # The authority component. If this is supplied, the user, password,
698
+ # userinfo, host, and port components must be omitted.
699
+ # @option [String, #to_str] path The path component.
700
+ # @option [String, #to_str] query The query component.
701
+ # @option [String, #to_str] fragment The fragment component.
702
+ #
703
+ # @return [Addressable::URI] The constructed URI object.
704
+ def initialize(options={})
705
+ if options.has_key?(:authority)
706
+ if (options.keys & [:userinfo, :user, :password, :host, :port]).any?
707
+ raise ArgumentError,
708
+ "Cannot specify both an authority and any of the components " +
709
+ "within the authority."
710
+ end
711
+ end
712
+ if options.has_key?(:userinfo)
713
+ if (options.keys & [:user, :password]).any?
714
+ raise ArgumentError,
715
+ "Cannot specify both a userinfo and either the user or password."
716
+ end
717
+ end
718
+
719
+ self.defer_validation do
720
+ # Bunch of crazy logic required because of the composite components
721
+ # like userinfo and authority.
722
+ self.scheme = options[:scheme] if options[:scheme]
723
+ self.user = options[:user] if options[:user]
724
+ self.password = options[:password] if options[:password]
725
+ self.userinfo = options[:userinfo] if options[:userinfo]
726
+ self.host = options[:host] if options[:host]
727
+ self.port = options[:port] if options[:port]
728
+ self.authority = options[:authority] if options[:authority]
729
+ self.path = options[:path] if options[:path]
730
+ self.query = options[:query] if options[:query]
731
+ self.query_values = options[:query_values] if options[:query_values]
732
+ self.fragment = options[:fragment] if options[:fragment]
733
+ end
734
+ end
735
+
736
+ ##
737
+ # Freeze URI, initializing instance variables.
738
+ #
739
+ # @return [Addressable::URI] The frozen URI object.
740
+ def freeze
741
+ self.normalized_scheme
742
+ self.normalized_user
743
+ self.normalized_password
744
+ self.normalized_userinfo
745
+ self.normalized_host
746
+ self.normalized_port
747
+ self.normalized_authority
748
+ self.normalized_site
749
+ self.normalized_path
750
+ self.normalized_query
751
+ self.normalized_fragment
752
+ self.hash
753
+ super
754
+ end
755
+
756
+ ##
757
+ # The scheme component for this URI.
758
+ #
759
+ # @return [String] The scheme component.
760
+ def scheme
761
+ return instance_variable_defined?(:@scheme) ? @scheme : nil
762
+ end
763
+
764
+ ##
765
+ # The scheme component for this URI, normalized.
766
+ #
767
+ # @return [String] The scheme component, normalized.
768
+ def normalized_scheme
769
+ self.scheme && @normalized_scheme ||= (begin
770
+ if self.scheme =~ /^\s*ssh\+svn\s*$/i
771
+ "svn+ssh"
772
+ else
773
+ Addressable::URI.normalize_component(
774
+ self.scheme.strip.downcase,
775
+ Addressable::URI::CharacterClasses::SCHEME
776
+ )
777
+ end
778
+ end)
779
+ end
780
+
781
+ ##
782
+ # Sets the scheme component for this URI.
783
+ #
784
+ # @param [String, #to_str] new_scheme The new scheme component.
785
+ def scheme=(new_scheme)
786
+ if new_scheme && !new_scheme.respond_to?(:to_str)
787
+ raise TypeError, "Can't convert #{new_scheme.class} into String."
788
+ elsif new_scheme
789
+ new_scheme = new_scheme.to_str
790
+ end
791
+ if new_scheme && new_scheme !~ /[a-z][a-z0-9\.\+\-]*/i
792
+ raise InvalidURIError, "Invalid scheme format."
793
+ end
794
+ @scheme = new_scheme
795
+ @scheme = nil if @scheme.to_s.strip.empty?
796
+
797
+ # Reset dependant values
798
+ @normalized_scheme = nil
799
+ @uri_string = nil
800
+ @hash = nil
801
+
802
+ # Ensure we haven't created an invalid URI
803
+ validate()
804
+ end
805
+
806
+ ##
807
+ # The user component for this URI.
808
+ #
809
+ # @return [String] The user component.
810
+ def user
811
+ return instance_variable_defined?(:@user) ? @user : nil
812
+ end
813
+
814
+ ##
815
+ # The user component for this URI, normalized.
816
+ #
817
+ # @return [String] The user component, normalized.
818
+ def normalized_user
819
+ self.user && @normalized_user ||= (begin
820
+ if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
821
+ (!self.password || self.password.strip.empty?)
822
+ nil
823
+ else
824
+ Addressable::URI.normalize_component(
825
+ self.user.strip,
826
+ Addressable::URI::CharacterClasses::UNRESERVED
827
+ )
828
+ end
829
+ end)
830
+ end
831
+
832
+ ##
833
+ # Sets the user component for this URI.
834
+ #
835
+ # @param [String, #to_str] new_user The new user component.
836
+ def user=(new_user)
837
+ if new_user && !new_user.respond_to?(:to_str)
838
+ raise TypeError, "Can't convert #{new_user.class} into String."
839
+ end
840
+ @user = new_user ? new_user.to_str : nil
841
+
842
+ # You can't have a nil user with a non-nil password
843
+ if password != nil
844
+ @user = EMPTY_STR if @user.nil?
845
+ end
846
+
847
+ # Reset dependant values
848
+ @userinfo = nil
849
+ @normalized_userinfo = nil
850
+ @authority = nil
851
+ @normalized_user = nil
852
+ @uri_string = nil
853
+ @hash = nil
854
+
855
+ # Ensure we haven't created an invalid URI
856
+ validate()
857
+ end
858
+
859
+ ##
860
+ # The password component for this URI.
861
+ #
862
+ # @return [String] The password component.
863
+ def password
864
+ return instance_variable_defined?(:@password) ? @password : nil
865
+ end
866
+
867
+ ##
868
+ # The password component for this URI, normalized.
869
+ #
870
+ # @return [String] The password component, normalized.
871
+ def normalized_password
872
+ self.password && @normalized_password ||= (begin
873
+ if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
874
+ (!self.user || self.user.strip.empty?)
875
+ nil
876
+ else
877
+ Addressable::URI.normalize_component(
878
+ self.password.strip,
879
+ Addressable::URI::CharacterClasses::UNRESERVED
880
+ )
881
+ end
882
+ end)
883
+ end
884
+
885
+ ##
886
+ # Sets the password component for this URI.
887
+ #
888
+ # @param [String, #to_str] new_password The new password component.
889
+ def password=(new_password)
890
+ if new_password && !new_password.respond_to?(:to_str)
891
+ raise TypeError, "Can't convert #{new_password.class} into String."
892
+ end
893
+ @password = new_password ? new_password.to_str : nil
894
+
895
+ # You can't have a nil user with a non-nil password
896
+ @password ||= nil
897
+ @user ||= nil
898
+ if @password != nil
899
+ @user = EMPTY_STR if @user.nil?
900
+ end
901
+
902
+ # Reset dependant values
903
+ @userinfo = nil
904
+ @normalized_userinfo = nil
905
+ @authority = nil
906
+ @normalized_password = nil
907
+ @uri_string = nil
908
+ @hash = nil
909
+
910
+ # Ensure we haven't created an invalid URI
911
+ validate()
912
+ end
913
+
914
+ ##
915
+ # The userinfo component for this URI.
916
+ # Combines the user and password components.
917
+ #
918
+ # @return [String] The userinfo component.
919
+ def userinfo
920
+ current_user = self.user
921
+ current_password = self.password
922
+ (current_user || current_password) && @userinfo ||= (begin
923
+ if current_user && current_password
924
+ "#{current_user}:#{current_password}"
925
+ elsif current_user && !current_password
926
+ "#{current_user}"
927
+ end
928
+ end)
929
+ end
930
+
931
+ ##
932
+ # The userinfo component for this URI, normalized.
933
+ #
934
+ # @return [String] The userinfo component, normalized.
935
+ def normalized_userinfo
936
+ self.userinfo && @normalized_userinfo ||= (begin
937
+ current_user = self.normalized_user
938
+ current_password = self.normalized_password
939
+ if !current_user && !current_password
940
+ nil
941
+ elsif current_user && current_password
942
+ "#{current_user}:#{current_password}"
943
+ elsif current_user && !current_password
944
+ "#{current_user}"
945
+ end
946
+ end)
947
+ end
948
+
949
+ ##
950
+ # Sets the userinfo component for this URI.
951
+ #
952
+ # @param [String, #to_str] new_userinfo The new userinfo component.
953
+ def userinfo=(new_userinfo)
954
+ if new_userinfo && !new_userinfo.respond_to?(:to_str)
955
+ raise TypeError, "Can't convert #{new_userinfo.class} into String."
956
+ end
957
+ new_user, new_password = if new_userinfo
958
+ [
959
+ new_userinfo.to_str.strip[/^(.*):/, 1],
960
+ new_userinfo.to_str.strip[/:(.*)$/, 1]
961
+ ]
962
+ else
963
+ [nil, nil]
964
+ end
965
+
966
+ # Password assigned first to ensure validity in case of nil
967
+ self.password = new_password
968
+ self.user = new_user
969
+
970
+ # Reset dependant values
971
+ @authority = nil
972
+ @uri_string = nil
973
+ @hash = nil
974
+
975
+ # Ensure we haven't created an invalid URI
976
+ validate()
977
+ end
978
+
979
+ ##
980
+ # The host component for this URI.
981
+ #
982
+ # @return [String] The host component.
983
+ def host
984
+ return instance_variable_defined?(:@host) ? @host : nil
985
+ end
986
+
987
+ ##
988
+ # The host component for this URI, normalized.
989
+ #
990
+ # @return [String] The host component, normalized.
991
+ def normalized_host
992
+ self.host && @normalized_host ||= (begin
993
+ if self.host != nil
994
+ if !self.host.strip.empty?
995
+ result = ::Addressable::IDNA.to_ascii(
996
+ URI.unencode_component(self.host.strip.downcase)
997
+ )
998
+ if result[-1..-1] == "."
999
+ # Trailing dots are unnecessary
1000
+ result = result[0...-1]
1001
+ end
1002
+ result
1003
+ else
1004
+ EMPTY_STR
1005
+ end
1006
+ else
1007
+ nil
1008
+ end
1009
+ end)
1010
+ end
1011
+
1012
+ ##
1013
+ # Sets the host component for this URI.
1014
+ #
1015
+ # @param [String, #to_str] new_host The new host component.
1016
+ def host=(new_host)
1017
+ if new_host && !new_host.respond_to?(:to_str)
1018
+ raise TypeError, "Can't convert #{new_host.class} into String."
1019
+ end
1020
+ @host = new_host ? new_host.to_str : nil
1021
+
1022
+ # Reset dependant values
1023
+ @authority = nil
1024
+ @normalized_host = nil
1025
+ @uri_string = nil
1026
+ @hash = nil
1027
+
1028
+ # Ensure we haven't created an invalid URI
1029
+ validate()
1030
+ end
1031
+
1032
+ ##
1033
+ # @see Addressable::URI#host
1034
+ alias_method :hostname, :host
1035
+
1036
+ ##
1037
+ # @see Addressable::URI#host=
1038
+ alias_method :hostname=, :host=
1039
+
1040
+ ##
1041
+ # The authority component for this URI.
1042
+ # Combines the user, password, host, and port components.
1043
+ #
1044
+ # @return [String] The authority component.
1045
+ def authority
1046
+ self.host && @authority ||= (begin
1047
+ authority = ""
1048
+ if self.userinfo != nil
1049
+ authority << "#{self.userinfo}@"
1050
+ end
1051
+ authority << self.host
1052
+ if self.port != nil
1053
+ authority << ":#{self.port}"
1054
+ end
1055
+ authority
1056
+ end)
1057
+ end
1058
+
1059
+ ##
1060
+ # The authority component for this URI, normalized.
1061
+ #
1062
+ # @return [String] The authority component, normalized.
1063
+ def normalized_authority
1064
+ self.authority && @normalized_authority ||= (begin
1065
+ authority = ""
1066
+ if self.normalized_userinfo != nil
1067
+ authority << "#{self.normalized_userinfo}@"
1068
+ end
1069
+ authority << self.normalized_host
1070
+ if self.normalized_port != nil
1071
+ authority << ":#{self.normalized_port}"
1072
+ end
1073
+ authority
1074
+ end)
1075
+ end
1076
+
1077
+ ##
1078
+ # Sets the authority component for this URI.
1079
+ #
1080
+ # @param [String, #to_str] new_authority The new authority component.
1081
+ def authority=(new_authority)
1082
+ if new_authority
1083
+ if !new_authority.respond_to?(:to_str)
1084
+ raise TypeError, "Can't convert #{new_authority.class} into String."
1085
+ end
1086
+ new_authority = new_authority.to_str
1087
+ new_userinfo = new_authority[/^([^\[\]]*)@/, 1]
1088
+ if new_userinfo
1089
+ new_user = new_userinfo.strip[/^([^:]*):?/, 1]
1090
+ new_password = new_userinfo.strip[/:(.*)$/, 1]
1091
+ end
1092
+ new_host =
1093
+ new_authority.gsub(/^([^\[\]]*)@/, EMPTY_STR).gsub(/:([^:@\[\]]*?)$/, EMPTY_STR)
1094
+ new_port =
1095
+ new_authority[/:([^:@\[\]]*?)$/, 1]
1096
+ end
1097
+
1098
+ # Password assigned first to ensure validity in case of nil
1099
+ self.password = defined?(new_password) ? new_password : nil
1100
+ self.user = defined?(new_user) ? new_user : nil
1101
+ self.host = defined?(new_host) ? new_host : nil
1102
+ self.port = defined?(new_port) ? new_port : nil
1103
+
1104
+ # Reset dependant values
1105
+ @userinfo = nil
1106
+ @normalized_userinfo = nil
1107
+ @uri_string = nil
1108
+ @hash = nil
1109
+
1110
+ # Ensure we haven't created an invalid URI
1111
+ validate()
1112
+ end
1113
+
1114
+ ##
1115
+ # The origin for this URI, serialized to ASCII, as per
1116
+ # draft-ietf-websec-origin-00, section 5.2.
1117
+ #
1118
+ # @return [String] The serialized origin.
1119
+ def origin
1120
+ return (if self.scheme && self.authority
1121
+ if self.normalized_port
1122
+ (
1123
+ "#{self.normalized_scheme}://#{self.normalized_host}" +
1124
+ ":#{self.normalized_port}"
1125
+ )
1126
+ else
1127
+ "#{self.normalized_scheme}://#{self.normalized_host}"
1128
+ end
1129
+ else
1130
+ "null"
1131
+ end)
1132
+ end
1133
+
1134
+ # Returns an array of known ip-based schemes. These schemes typically
1135
+ # use a similar URI form:
1136
+ # <code>//<user>:<password>@<host>:<port>/<url-path></code>
1137
+ def self.ip_based_schemes
1138
+ return self.port_mapping.keys
1139
+ end
1140
+
1141
+ # Returns a hash of common IP-based schemes and their default port
1142
+ # numbers. Adding new schemes to this hash, as necessary, will allow
1143
+ # for better URI normalization.
1144
+ def self.port_mapping
1145
+ PORT_MAPPING
1146
+ end
1147
+
1148
+ ##
1149
+ # The port component for this URI.
1150
+ # This is the port number actually given in the URI. This does not
1151
+ # infer port numbers from default values.
1152
+ #
1153
+ # @return [Integer] The port component.
1154
+ def port
1155
+ return instance_variable_defined?(:@port) ? @port : nil
1156
+ end
1157
+
1158
+ ##
1159
+ # The port component for this URI, normalized.
1160
+ #
1161
+ # @return [Integer] The port component, normalized.
1162
+ def normalized_port
1163
+ if URI.port_mapping[self.normalized_scheme] == self.port
1164
+ nil
1165
+ else
1166
+ self.port
1167
+ end
1168
+ end
1169
+
1170
+ ##
1171
+ # Sets the port component for this URI.
1172
+ #
1173
+ # @param [String, Integer, #to_s] new_port The new port component.
1174
+ def port=(new_port)
1175
+ if new_port != nil && new_port.respond_to?(:to_str)
1176
+ new_port = Addressable::URI.unencode_component(new_port.to_str)
1177
+ end
1178
+ if new_port != nil && !(new_port.to_s =~ /^\d+$/)
1179
+ raise InvalidURIError,
1180
+ "Invalid port number: #{new_port.inspect}"
1181
+ end
1182
+
1183
+ @port = new_port.to_s.to_i
1184
+ @port = nil if @port == 0
1185
+
1186
+ # Reset dependant values
1187
+ @authority = nil
1188
+ @normalized_port = nil
1189
+ @uri_string = nil
1190
+ @hash = nil
1191
+
1192
+ # Ensure we haven't created an invalid URI
1193
+ validate()
1194
+ end
1195
+
1196
+ ##
1197
+ # The inferred port component for this URI.
1198
+ # This method will normalize to the default port for the URI's scheme if
1199
+ # the port isn't explicitly specified in the URI.
1200
+ #
1201
+ # @return [Integer] The inferred port component.
1202
+ def inferred_port
1203
+ if self.port.to_i == 0
1204
+ if self.scheme
1205
+ URI.port_mapping[self.scheme.strip.downcase]
1206
+ else
1207
+ nil
1208
+ end
1209
+ else
1210
+ self.port.to_i
1211
+ end
1212
+ end
1213
+
1214
+ ##
1215
+ # The combination of components that represent a site.
1216
+ # Combines the scheme, user, password, host, and port components.
1217
+ # Primarily useful for HTTP and HTTPS.
1218
+ #
1219
+ # For example, <code>"http://example.com/path?query"</code> would have a
1220
+ # <code>site</code> value of <code>"http://example.com"</code>.
1221
+ #
1222
+ # @return [String] The components that identify a site.
1223
+ def site
1224
+ (self.scheme || self.authority) && @site ||= (begin
1225
+ site_string = ""
1226
+ site_string << "#{self.scheme}:" if self.scheme != nil
1227
+ site_string << "//#{self.authority}" if self.authority != nil
1228
+ site_string
1229
+ end)
1230
+ end
1231
+
1232
+ ##
1233
+ # The normalized combination of components that represent a site.
1234
+ # Combines the scheme, user, password, host, and port components.
1235
+ # Primarily useful for HTTP and HTTPS.
1236
+ #
1237
+ # For example, <code>"http://example.com/path?query"</code> would have a
1238
+ # <code>site</code> value of <code>"http://example.com"</code>.
1239
+ #
1240
+ # @return [String] The normalized components that identify a site.
1241
+ def normalized_site
1242
+ self.site && @normalized_site ||= (begin
1243
+ site_string = ""
1244
+ if self.normalized_scheme != nil
1245
+ site_string << "#{self.normalized_scheme}:"
1246
+ end
1247
+ if self.normalized_authority != nil
1248
+ site_string << "//#{self.normalized_authority}"
1249
+ end
1250
+ site_string
1251
+ end)
1252
+ end
1253
+
1254
+ ##
1255
+ # Sets the site value for this URI.
1256
+ #
1257
+ # @param [String, #to_str] new_site The new site value.
1258
+ def site=(new_site)
1259
+ if new_site
1260
+ if !new_site.respond_to?(:to_str)
1261
+ raise TypeError, "Can't convert #{new_site.class} into String."
1262
+ end
1263
+ new_site = new_site.to_str
1264
+ # These two regular expressions derived from the primary parsing
1265
+ # expression
1266
+ self.scheme = new_site[/^(?:([^:\/?#]+):)?(?:\/\/(?:[^\/?#]*))?$/, 1]
1267
+ self.authority = new_site[
1268
+ /^(?:(?:[^:\/?#]+):)?(?:\/\/([^\/?#]*))?$/, 1
1269
+ ]
1270
+ else
1271
+ self.scheme = nil
1272
+ self.authority = nil
1273
+ end
1274
+ end
1275
+
1276
+ ##
1277
+ # The path component for this URI.
1278
+ #
1279
+ # @return [String] The path component.
1280
+ def path
1281
+ return instance_variable_defined?(:@path) ? @path : EMPTY_STR
1282
+ end
1283
+
1284
+ NORMPATH = /^(?!\/)[^\/:]*:.*$/
1285
+ ##
1286
+ # The path component for this URI, normalized.
1287
+ #
1288
+ # @return [String] The path component, normalized.
1289
+ def normalized_path
1290
+ @normalized_path ||= (begin
1291
+ path = self.path.to_s
1292
+ if self.scheme == nil && path =~ NORMPATH
1293
+ # Relative paths with colons in the first segment are ambiguous.
1294
+ path = path.sub(":", "%2F")
1295
+ end
1296
+ # String#split(delimeter, -1) uses the more strict splitting behavior
1297
+ # found by default in Python.
1298
+ result = (path.strip.split(SLASH, -1).map do |segment|
1299
+ Addressable::URI.normalize_component(
1300
+ segment,
1301
+ Addressable::URI::CharacterClasses::PCHAR
1302
+ )
1303
+ end).join(SLASH)
1304
+
1305
+ result = URI.normalize_path(result)
1306
+ if result.empty? &&
1307
+ ["http", "https", "ftp", "tftp"].include?(self.normalized_scheme)
1308
+ result = SLASH
1309
+ end
1310
+ result
1311
+ end)
1312
+ end
1313
+
1314
+ ##
1315
+ # Sets the path component for this URI.
1316
+ #
1317
+ # @param [String, #to_str] new_path The new path component.
1318
+ def path=(new_path)
1319
+ if new_path && !new_path.respond_to?(:to_str)
1320
+ raise TypeError, "Can't convert #{new_path.class} into String."
1321
+ end
1322
+ @path = (new_path || EMPTY_STR).to_str
1323
+ if !@path.empty? && @path[0..0] != SLASH && host != nil
1324
+ @path = "/#{@path}"
1325
+ end
1326
+
1327
+ # Reset dependant values
1328
+ @normalized_path = nil
1329
+ @uri_string = nil
1330
+ @hash = nil
1331
+ end
1332
+
1333
+ ##
1334
+ # The basename, if any, of the file in the path component.
1335
+ #
1336
+ # @return [String] The path's basename.
1337
+ def basename
1338
+ # Path cannot be nil
1339
+ return File.basename(self.path).gsub(/;[^\/]*$/, EMPTY_STR)
1340
+ end
1341
+
1342
+ ##
1343
+ # The extname, if any, of the file in the path component.
1344
+ # Empty string if there is no extension.
1345
+ #
1346
+ # @return [String] The path's extname.
1347
+ def extname
1348
+ return nil unless self.path
1349
+ return File.extname(self.basename)
1350
+ end
1351
+
1352
+ ##
1353
+ # The query component for this URI.
1354
+ #
1355
+ # @return [String] The query component.
1356
+ def query
1357
+ return instance_variable_defined?(:@query) ? @query : nil
1358
+ end
1359
+
1360
+ ##
1361
+ # The query component for this URI, normalized.
1362
+ #
1363
+ # @return [String] The query component, normalized.
1364
+ def normalized_query
1365
+ self.query && @normalized_query ||= (begin
1366
+ (self.query.split("&", -1).map do |pair|
1367
+ Addressable::URI.normalize_component(
1368
+ pair,
1369
+ Addressable::URI::CharacterClasses::QUERY.sub("\\&", "")
1370
+ )
1371
+ end).join("&")
1372
+ end)
1373
+ end
1374
+
1375
+ ##
1376
+ # Sets the query component for this URI.
1377
+ #
1378
+ # @param [String, #to_str] new_query The new query component.
1379
+ def query=(new_query)
1380
+ if new_query && !new_query.respond_to?(:to_str)
1381
+ raise TypeError, "Can't convert #{new_query.class} into String."
1382
+ end
1383
+ @query = new_query ? new_query.to_str : nil
1384
+
1385
+ # Reset dependant values
1386
+ @normalized_query = nil
1387
+ @uri_string = nil
1388
+ @hash = nil
1389
+ end
1390
+
1391
+ ##
1392
+ # Converts the query component to a Hash value.
1393
+ #
1394
+ # @option [Symbol] notation
1395
+ # May be one of <code>:flat</code>, <code>:dot</code>, or
1396
+ # <code>:subscript</code>. The <code>:dot</code> notation is not
1397
+ # supported for assignment. Default value is <code>:subscript</code>.
1398
+ #
1399
+ # @return [Hash, Array] The query string parsed as a Hash or Array object.
1400
+ #
1401
+ # @example
1402
+ # Addressable::URI.parse("?one=1&two=2&three=3").query_values
1403
+ # #=> {"one" => "1", "two" => "2", "three" => "3"}
1404
+ # Addressable::URI.parse("?one[two][three]=four").query_values
1405
+ # #=> {"one" => {"two" => {"three" => "four"}}}
1406
+ # Addressable::URI.parse("?one.two.three=four").query_values(
1407
+ # :notation => :dot
1408
+ # )
1409
+ # #=> {"one" => {"two" => {"three" => "four"}}}
1410
+ # Addressable::URI.parse("?one[two][three]=four").query_values(
1411
+ # :notation => :flat
1412
+ # )
1413
+ # #=> {"one[two][three]" => "four"}
1414
+ # Addressable::URI.parse("?one.two.three=four").query_values(
1415
+ # :notation => :flat
1416
+ # )
1417
+ # #=> {"one.two.three" => "four"}
1418
+ # Addressable::URI.parse(
1419
+ # "?one[two][three][]=four&one[two][three][]=five"
1420
+ # ).query_values
1421
+ # #=> {"one" => {"two" => {"three" => ["four", "five"]}}}
1422
+ # Addressable::URI.parse(
1423
+ # "?one=two&one=three").query_values(:notation => :flat_array)
1424
+ # #=> [['one', 'two'], ['one', 'three']]
1425
+ def query_values(options={})
1426
+ defaults = {:notation => :subscript}
1427
+ options = defaults.merge(options)
1428
+ if ![:flat, :dot, :subscript, :flat_array].include?(options[:notation])
1429
+ raise ArgumentError,
1430
+ "Invalid notation. Must be one of: " +
1431
+ "[:flat, :dot, :subscript, :flat_array]."
1432
+ end
1433
+ dehash = lambda do |hash|
1434
+ hash.each do |(key, value)|
1435
+ if value.kind_of?(Hash)
1436
+ hash[key] = dehash.call(value)
1437
+ end
1438
+ end
1439
+ if hash != {} && hash.keys.all? { |key| key =~ /^\d+$/ }
1440
+ hash.sort.inject([]) do |accu, (_, value)|
1441
+ accu << value; accu
1442
+ end
1443
+ else
1444
+ hash
1445
+ end
1446
+ end
1447
+ return nil if self.query == nil
1448
+ empty_accumulator = :flat_array == options[:notation] ? [] : {}
1449
+ return ((self.query.split("&").map do |pair|
1450
+ pair.split("=", 2) if pair && !pair.empty?
1451
+ end).compact.inject(empty_accumulator.dup) do |accumulator, (key, value)|
1452
+ value = true if value.nil?
1453
+ key = URI.unencode_component(key)
1454
+ if value != true
1455
+ value = URI.unencode_component(value.gsub(/\+/, " "))
1456
+ end
1457
+ if options[:notation] == :flat
1458
+ if accumulator[key]
1459
+ raise ArgumentError, "Key was repeated: #{key.inspect}"
1460
+ end
1461
+ accumulator[key] = value
1462
+ elsif options[:notation] == :flat_array
1463
+ accumulator << [key, value]
1464
+ else
1465
+ if options[:notation] == :dot
1466
+ array_value = false
1467
+ subkeys = key.split(".")
1468
+ elsif options[:notation] == :subscript
1469
+ array_value = !!(key =~ /\[\]$/)
1470
+ subkeys = key.split(/[\[\]]+/)
1471
+ end
1472
+ current_hash = accumulator
1473
+ for i in 0...(subkeys.size - 1)
1474
+ subkey = subkeys[i]
1475
+ current_hash[subkey] = {} unless current_hash[subkey]
1476
+ current_hash = current_hash[subkey]
1477
+ end
1478
+ if array_value
1479
+ current_hash[subkeys.last] = [] unless current_hash[subkeys.last]
1480
+ current_hash[subkeys.last] << value
1481
+ else
1482
+ current_hash[subkeys.last] = value
1483
+ end
1484
+ end
1485
+ accumulator
1486
+ end).inject(empty_accumulator.dup) do |accumulator, (key, value)|
1487
+ if options[:notation] == :flat_array
1488
+ accumulator << [key, value]
1489
+ else
1490
+ accumulator[key] = value.kind_of?(Hash) ? dehash.call(value) : value
1491
+ end
1492
+ accumulator
1493
+ end
1494
+ end
1495
+
1496
+ ##
1497
+ # Sets the query component for this URI from a Hash object.
1498
+ # This method produces a query string using the :subscript notation.
1499
+ # An empty Hash will result in a nil query.
1500
+ #
1501
+ # @param [Hash, #to_hash, Array] new_query_values The new query values.
1502
+ def query_values=(new_query_values)
1503
+ if new_query_values == nil
1504
+ self.query = nil
1505
+ return nil
1506
+ end
1507
+
1508
+ if !new_query_values.is_a?(Array)
1509
+ if !new_query_values.respond_to?(:to_hash)
1510
+ raise TypeError,
1511
+ "Can't convert #{new_query_values.class} into Hash."
1512
+ end
1513
+ new_query_values = new_query_values.to_hash
1514
+ new_query_values = new_query_values.map do |key, value|
1515
+ key = key.to_s if key.kind_of?(Symbol)
1516
+ [key, value]
1517
+ end
1518
+ # Useful default for OAuth and caching.
1519
+ # Only to be used for non-Array inputs. Arrays should preserve order.
1520
+ new_query_values.sort!
1521
+ end
1522
+
1523
+ ##
1524
+ # Joins and converts parent and value into a properly encoded and
1525
+ # ordered URL query.
1526
+ #
1527
+ # @private
1528
+ # @param [String] parent an URI encoded component.
1529
+ # @param [Array, Hash, Symbol, #to_str] value
1530
+ #
1531
+ # @return [String] a properly escaped and ordered URL query.
1532
+ to_query = lambda do |parent, value|
1533
+ if value.is_a?(Hash)
1534
+ value = value.map do |key, val|
1535
+ [
1536
+ URI.encode_component(key, CharacterClasses::UNRESERVED),
1537
+ val
1538
+ ]
1539
+ end
1540
+ value.sort!
1541
+ buffer = ""
1542
+ value.each do |key, val|
1543
+ new_parent = "#{parent}[#{key}]"
1544
+ buffer << "#{to_query.call(new_parent, val)}&"
1545
+ end
1546
+ return buffer.chop
1547
+ elsif value.is_a?(Array)
1548
+ buffer = ""
1549
+ value.each_with_index do |val, i|
1550
+ new_parent = "#{parent}[#{i}]"
1551
+ buffer << "#{to_query.call(new_parent, val)}&"
1552
+ end
1553
+ return buffer.chop
1554
+ elsif value == true
1555
+ return parent
1556
+ else
1557
+ encoded_value = URI.encode_component(
1558
+ value, CharacterClasses::UNRESERVED
1559
+ )
1560
+ return "#{parent}=#{encoded_value}"
1561
+ end
1562
+ end
1563
+
1564
+ # new_query_values have form [['key1', 'value1'], ['key2', 'value2']]
1565
+ buffer = ""
1566
+ new_query_values.each do |parent, value|
1567
+ encoded_parent = URI.encode_component(
1568
+ parent, CharacterClasses::UNRESERVED
1569
+ )
1570
+ buffer << "#{to_query.call(encoded_parent, value)}&"
1571
+ end
1572
+ self.query = buffer.chop
1573
+ end
1574
+
1575
+ ##
1576
+ # The HTTP request URI for this URI. This is the path and the
1577
+ # query string.
1578
+ #
1579
+ # @return [String] The request URI required for an HTTP request.
1580
+ def request_uri
1581
+ return nil if self.absolute? && self.scheme !~ /^https?$/
1582
+ return (
1583
+ (!self.path.empty? ? self.path : SLASH) +
1584
+ (self.query ? "?#{self.query}" : EMPTY_STR)
1585
+ )
1586
+ end
1587
+
1588
+ ##
1589
+ # Sets the HTTP request URI for this URI.
1590
+ #
1591
+ # @param [String, #to_str] new_request_uri The new HTTP request URI.
1592
+ def request_uri=(new_request_uri)
1593
+ if !new_request_uri.respond_to?(:to_str)
1594
+ raise TypeError, "Can't convert #{new_request_uri.class} into String."
1595
+ end
1596
+ if self.absolute? && self.scheme !~ /^https?$/
1597
+ raise InvalidURIError,
1598
+ "Cannot set an HTTP request URI for a non-HTTP URI."
1599
+ end
1600
+ new_request_uri = new_request_uri.to_str
1601
+ path_component = new_request_uri[/^([^\?]*)\?(?:.*)$/, 1]
1602
+ query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1]
1603
+ path_component = path_component.to_s
1604
+ path_component = (!path_component.empty? ? path_component : SLASH)
1605
+ self.path = path_component
1606
+ self.query = query_component
1607
+
1608
+ # Reset dependant values
1609
+ @uri_string = nil
1610
+ @hash = nil
1611
+ end
1612
+
1613
+ ##
1614
+ # The fragment component for this URI.
1615
+ #
1616
+ # @return [String] The fragment component.
1617
+ def fragment
1618
+ return instance_variable_defined?(:@fragment) ? @fragment : nil
1619
+ end
1620
+
1621
+ ##
1622
+ # The fragment component for this URI, normalized.
1623
+ #
1624
+ # @return [String] The fragment component, normalized.
1625
+ def normalized_fragment
1626
+ self.fragment && @normalized_fragment ||= (begin
1627
+ Addressable::URI.normalize_component(
1628
+ self.fragment.strip,
1629
+ Addressable::URI::CharacterClasses::FRAGMENT
1630
+ )
1631
+ end)
1632
+ end
1633
+
1634
+ ##
1635
+ # Sets the fragment component for this URI.
1636
+ #
1637
+ # @param [String, #to_str] new_fragment The new fragment component.
1638
+ def fragment=(new_fragment)
1639
+ if new_fragment && !new_fragment.respond_to?(:to_str)
1640
+ raise TypeError, "Can't convert #{new_fragment.class} into String."
1641
+ end
1642
+ @fragment = new_fragment ? new_fragment.to_str : nil
1643
+
1644
+ # Reset dependant values
1645
+ @normalized_fragment = nil
1646
+ @uri_string = nil
1647
+ @hash = nil
1648
+
1649
+ # Ensure we haven't created an invalid URI
1650
+ validate()
1651
+ end
1652
+
1653
+ ##
1654
+ # Determines if the scheme indicates an IP-based protocol.
1655
+ #
1656
+ # @return [TrueClass, FalseClass]
1657
+ # <code>true</code> if the scheme indicates an IP-based protocol.
1658
+ # <code>false</code> otherwise.
1659
+ def ip_based?
1660
+ if self.scheme
1661
+ return URI.ip_based_schemes.include?(
1662
+ self.scheme.strip.downcase)
1663
+ end
1664
+ return false
1665
+ end
1666
+
1667
+ ##
1668
+ # Determines if the URI is relative.
1669
+ #
1670
+ # @return [TrueClass, FalseClass]
1671
+ # <code>true</code> if the URI is relative. <code>false</code>
1672
+ # otherwise.
1673
+ def relative?
1674
+ return self.scheme.nil?
1675
+ end
1676
+
1677
+ ##
1678
+ # Determines if the URI is absolute.
1679
+ #
1680
+ # @return [TrueClass, FalseClass]
1681
+ # <code>true</code> if the URI is absolute. <code>false</code>
1682
+ # otherwise.
1683
+ def absolute?
1684
+ return !relative?
1685
+ end
1686
+
1687
+ ##
1688
+ # Joins two URIs together.
1689
+ #
1690
+ # @param [String, Addressable::URI, #to_str] The URI to join with.
1691
+ #
1692
+ # @return [Addressable::URI] The joined URI.
1693
+ def join(uri)
1694
+ if !uri.respond_to?(:to_str)
1695
+ raise TypeError, "Can't convert #{uri.class} into String."
1696
+ end
1697
+ if !uri.kind_of?(URI)
1698
+ # Otherwise, convert to a String, then parse.
1699
+ uri = URI.parse(uri.to_str)
1700
+ end
1701
+ if uri.to_s.empty?
1702
+ return self.dup
1703
+ end
1704
+
1705
+ joined_scheme = nil
1706
+ joined_user = nil
1707
+ joined_password = nil
1708
+ joined_host = nil
1709
+ joined_port = nil
1710
+ joined_path = nil
1711
+ joined_query = nil
1712
+ joined_fragment = nil
1713
+
1714
+ # Section 5.2.2 of RFC 3986
1715
+ if uri.scheme != nil
1716
+ joined_scheme = uri.scheme
1717
+ joined_user = uri.user
1718
+ joined_password = uri.password
1719
+ joined_host = uri.host
1720
+ joined_port = uri.port
1721
+ joined_path = URI.normalize_path(uri.path)
1722
+ joined_query = uri.query
1723
+ else
1724
+ if uri.authority != nil
1725
+ joined_user = uri.user
1726
+ joined_password = uri.password
1727
+ joined_host = uri.host
1728
+ joined_port = uri.port
1729
+ joined_path = URI.normalize_path(uri.path)
1730
+ joined_query = uri.query
1731
+ else
1732
+ if uri.path == nil || uri.path.empty?
1733
+ joined_path = self.path
1734
+ if uri.query != nil
1735
+ joined_query = uri.query
1736
+ else
1737
+ joined_query = self.query
1738
+ end
1739
+ else
1740
+ if uri.path[0..0] == SLASH
1741
+ joined_path = URI.normalize_path(uri.path)
1742
+ else
1743
+ base_path = self.path.dup
1744
+ base_path = EMPTY_STR if base_path == nil
1745
+ base_path = URI.normalize_path(base_path)
1746
+
1747
+ # Section 5.2.3 of RFC 3986
1748
+ #
1749
+ # Removes the right-most path segment from the base path.
1750
+ if base_path =~ /\//
1751
+ base_path.gsub!(/\/[^\/]+$/, SLASH)
1752
+ else
1753
+ base_path = EMPTY_STR
1754
+ end
1755
+
1756
+ # If the base path is empty and an authority segment has been
1757
+ # defined, use a base path of SLASH
1758
+ if base_path.empty? && self.authority != nil
1759
+ base_path = SLASH
1760
+ end
1761
+
1762
+ joined_path = URI.normalize_path(base_path + uri.path)
1763
+ end
1764
+ joined_query = uri.query
1765
+ end
1766
+ joined_user = self.user
1767
+ joined_password = self.password
1768
+ joined_host = self.host
1769
+ joined_port = self.port
1770
+ end
1771
+ joined_scheme = self.scheme
1772
+ end
1773
+ joined_fragment = uri.fragment
1774
+
1775
+ return Addressable::URI.new(
1776
+ :scheme => joined_scheme,
1777
+ :user => joined_user,
1778
+ :password => joined_password,
1779
+ :host => joined_host,
1780
+ :port => joined_port,
1781
+ :path => joined_path,
1782
+ :query => joined_query,
1783
+ :fragment => joined_fragment
1784
+ )
1785
+ end
1786
+ alias_method :+, :join
1787
+
1788
+ ##
1789
+ # Destructive form of <code>join</code>.
1790
+ #
1791
+ # @param [String, Addressable::URI, #to_str] The URI to join with.
1792
+ #
1793
+ # @return [Addressable::URI] The joined URI.
1794
+ #
1795
+ # @see Addressable::URI#join
1796
+ def join!(uri)
1797
+ replace_self(self.join(uri))
1798
+ end
1799
+
1800
+ ##
1801
+ # Merges a URI with a <code>Hash</code> of components.
1802
+ # This method has different behavior from <code>join</code>. Any
1803
+ # components present in the <code>hash</code> parameter will override the
1804
+ # original components. The path component is not treated specially.
1805
+ #
1806
+ # @param [Hash, Addressable::URI, #to_hash] The components to merge with.
1807
+ #
1808
+ # @return [Addressable::URI] The merged URI.
1809
+ #
1810
+ # @see Hash#merge
1811
+ def merge(hash)
1812
+ if !hash.respond_to?(:to_hash)
1813
+ raise TypeError, "Can't convert #{hash.class} into Hash."
1814
+ end
1815
+ hash = hash.to_hash
1816
+
1817
+ if hash.has_key?(:authority)
1818
+ if (hash.keys & [:userinfo, :user, :password, :host, :port]).any?
1819
+ raise ArgumentError,
1820
+ "Cannot specify both an authority and any of the components " +
1821
+ "within the authority."
1822
+ end
1823
+ end
1824
+ if hash.has_key?(:userinfo)
1825
+ if (hash.keys & [:user, :password]).any?
1826
+ raise ArgumentError,
1827
+ "Cannot specify both a userinfo and either the user or password."
1828
+ end
1829
+ end
1830
+
1831
+ uri = Addressable::URI.new
1832
+ uri.defer_validation do
1833
+ # Bunch of crazy logic required because of the composite components
1834
+ # like userinfo and authority.
1835
+ uri.scheme =
1836
+ hash.has_key?(:scheme) ? hash[:scheme] : self.scheme
1837
+ if hash.has_key?(:authority)
1838
+ uri.authority =
1839
+ hash.has_key?(:authority) ? hash[:authority] : self.authority
1840
+ end
1841
+ if hash.has_key?(:userinfo)
1842
+ uri.userinfo =
1843
+ hash.has_key?(:userinfo) ? hash[:userinfo] : self.userinfo
1844
+ end
1845
+ if !hash.has_key?(:userinfo) && !hash.has_key?(:authority)
1846
+ uri.user =
1847
+ hash.has_key?(:user) ? hash[:user] : self.user
1848
+ uri.password =
1849
+ hash.has_key?(:password) ? hash[:password] : self.password
1850
+ end
1851
+ if !hash.has_key?(:authority)
1852
+ uri.host =
1853
+ hash.has_key?(:host) ? hash[:host] : self.host
1854
+ uri.port =
1855
+ hash.has_key?(:port) ? hash[:port] : self.port
1856
+ end
1857
+ uri.path =
1858
+ hash.has_key?(:path) ? hash[:path] : self.path
1859
+ uri.query =
1860
+ hash.has_key?(:query) ? hash[:query] : self.query
1861
+ uri.fragment =
1862
+ hash.has_key?(:fragment) ? hash[:fragment] : self.fragment
1863
+ end
1864
+
1865
+ return uri
1866
+ end
1867
+
1868
+ ##
1869
+ # Destructive form of <code>merge</code>.
1870
+ #
1871
+ # @param [Hash, Addressable::URI, #to_hash] The components to merge with.
1872
+ #
1873
+ # @return [Addressable::URI] The merged URI.
1874
+ #
1875
+ # @see Addressable::URI#merge
1876
+ def merge!(uri)
1877
+ replace_self(self.merge(uri))
1878
+ end
1879
+
1880
+ ##
1881
+ # Returns the shortest normalized relative form of this URI that uses the
1882
+ # supplied URI as a base for resolution. Returns an absolute URI if
1883
+ # necessary. This is effectively the opposite of <code>route_to</code>.
1884
+ #
1885
+ # @param [String, Addressable::URI, #to_str] uri The URI to route from.
1886
+ #
1887
+ # @return [Addressable::URI]
1888
+ # The normalized relative URI that is equivalent to the original URI.
1889
+ def route_from(uri)
1890
+ uri = URI.parse(uri).normalize
1891
+ normalized_self = self.normalize
1892
+ if normalized_self.relative?
1893
+ raise ArgumentError, "Expected absolute URI, got: #{self.to_s}"
1894
+ end
1895
+ if uri.relative?
1896
+ raise ArgumentError, "Expected absolute URI, got: #{uri.to_s}"
1897
+ end
1898
+ if normalized_self == uri
1899
+ return Addressable::URI.parse("##{normalized_self.fragment}")
1900
+ end
1901
+ components = normalized_self.to_hash
1902
+ if normalized_self.scheme == uri.scheme
1903
+ components[:scheme] = nil
1904
+ if normalized_self.authority == uri.authority
1905
+ components[:user] = nil
1906
+ components[:password] = nil
1907
+ components[:host] = nil
1908
+ components[:port] = nil
1909
+ if normalized_self.path == uri.path
1910
+ components[:path] = nil
1911
+ if normalized_self.query == uri.query
1912
+ components[:query] = nil
1913
+ end
1914
+ else
1915
+ if uri.path != SLASH
1916
+ components[:path].gsub!(
1917
+ Regexp.new("^" + Regexp.escape(uri.path)), EMPTY_STR)
1918
+ end
1919
+ end
1920
+ end
1921
+ end
1922
+ # Avoid network-path references.
1923
+ if components[:host] != nil
1924
+ components[:scheme] = normalized_self.scheme
1925
+ end
1926
+ return Addressable::URI.new(
1927
+ :scheme => components[:scheme],
1928
+ :user => components[:user],
1929
+ :password => components[:password],
1930
+ :host => components[:host],
1931
+ :port => components[:port],
1932
+ :path => components[:path],
1933
+ :query => components[:query],
1934
+ :fragment => components[:fragment]
1935
+ )
1936
+ end
1937
+
1938
+ ##
1939
+ # Returns the shortest normalized relative form of the supplied URI that
1940
+ # uses this URI as a base for resolution. Returns an absolute URI if
1941
+ # necessary. This is effectively the opposite of <code>route_from</code>.
1942
+ #
1943
+ # @param [String, Addressable::URI, #to_str] uri The URI to route to.
1944
+ #
1945
+ # @return [Addressable::URI]
1946
+ # The normalized relative URI that is equivalent to the supplied URI.
1947
+ def route_to(uri)
1948
+ return URI.parse(uri).route_from(self)
1949
+ end
1950
+
1951
+ ##
1952
+ # Returns a normalized URI object.
1953
+ #
1954
+ # NOTE: This method does not attempt to fully conform to specifications.
1955
+ # It exists largely to correct other people's failures to read the
1956
+ # specifications, and also to deal with caching issues since several
1957
+ # different URIs may represent the same resource and should not be
1958
+ # cached multiple times.
1959
+ #
1960
+ # @return [Addressable::URI] The normalized URI.
1961
+ def normalize
1962
+ # This is a special exception for the frequently misused feed
1963
+ # URI scheme.
1964
+ if normalized_scheme == "feed"
1965
+ if self.to_s =~ /^feed:\/*http:\/*/
1966
+ return URI.parse(
1967
+ self.to_s[/^feed:\/*(http:\/*.*)/, 1]
1968
+ ).normalize
1969
+ end
1970
+ end
1971
+
1972
+ return Addressable::URI.new(
1973
+ :scheme => normalized_scheme,
1974
+ :authority => normalized_authority,
1975
+ :path => normalized_path,
1976
+ :query => normalized_query,
1977
+ :fragment => normalized_fragment
1978
+ )
1979
+ end
1980
+
1981
+ ##
1982
+ # Destructively normalizes this URI object.
1983
+ #
1984
+ # @return [Addressable::URI] The normalized URI.
1985
+ #
1986
+ # @see Addressable::URI#normalize
1987
+ def normalize!
1988
+ replace_self(self.normalize)
1989
+ end
1990
+
1991
+ ##
1992
+ # Creates a URI suitable for display to users. If semantic attacks are
1993
+ # likely, the application should try to detect these and warn the user.
1994
+ # See <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>,
1995
+ # section 7.6 for more information.
1996
+ #
1997
+ # @return [Addressable::URI] A URI suitable for display purposes.
1998
+ def display_uri
1999
+ display_uri = self.normalize
2000
+ display_uri.host = ::Addressable::IDNA.to_unicode(display_uri.host)
2001
+ return display_uri
2002
+ end
2003
+
2004
+ ##
2005
+ # Returns <code>true</code> if the URI objects are equal. This method
2006
+ # normalizes both URIs before doing the comparison, and allows comparison
2007
+ # against <code>Strings</code>.
2008
+ #
2009
+ # @param [Object] uri The URI to compare.
2010
+ #
2011
+ # @return [TrueClass, FalseClass]
2012
+ # <code>true</code> if the URIs are equivalent, <code>false</code>
2013
+ # otherwise.
2014
+ def ===(uri)
2015
+ if uri.respond_to?(:normalize)
2016
+ uri_string = uri.normalize.to_s
2017
+ else
2018
+ begin
2019
+ uri_string = ::Addressable::URI.parse(uri).normalize.to_s
2020
+ rescue InvalidURIError, TypeError
2021
+ return false
2022
+ end
2023
+ end
2024
+ return self.normalize.to_s == uri_string
2025
+ end
2026
+
2027
+ ##
2028
+ # Returns <code>true</code> if the URI objects are equal. This method
2029
+ # normalizes both URIs before doing the comparison.
2030
+ #
2031
+ # @param [Object] uri The URI to compare.
2032
+ #
2033
+ # @return [TrueClass, FalseClass]
2034
+ # <code>true</code> if the URIs are equivalent, <code>false</code>
2035
+ # otherwise.
2036
+ def ==(uri)
2037
+ return false unless uri.kind_of?(URI)
2038
+ return self.normalize.to_s == uri.normalize.to_s
2039
+ end
2040
+
2041
+ ##
2042
+ # Returns <code>true</code> if the URI objects are equal. This method
2043
+ # does NOT normalize either URI before doing the comparison.
2044
+ #
2045
+ # @param [Object] uri The URI to compare.
2046
+ #
2047
+ # @return [TrueClass, FalseClass]
2048
+ # <code>true</code> if the URIs are equivalent, <code>false</code>
2049
+ # otherwise.
2050
+ def eql?(uri)
2051
+ return false unless uri.kind_of?(URI)
2052
+ return self.to_s == uri.to_s
2053
+ end
2054
+
2055
+ ##
2056
+ # A hash value that will make a URI equivalent to its normalized
2057
+ # form.
2058
+ #
2059
+ # @return [Integer] A hash of the URI.
2060
+ def hash
2061
+ return @hash ||= (self.to_s.hash * -1)
2062
+ end
2063
+
2064
+ ##
2065
+ # Clones the URI object.
2066
+ #
2067
+ # @return [Addressable::URI] The cloned URI.
2068
+ def dup
2069
+ duplicated_uri = Addressable::URI.new(
2070
+ :scheme => self.scheme ? self.scheme.dup : nil,
2071
+ :user => self.user ? self.user.dup : nil,
2072
+ :password => self.password ? self.password.dup : nil,
2073
+ :host => self.host ? self.host.dup : nil,
2074
+ :port => self.port,
2075
+ :path => self.path ? self.path.dup : nil,
2076
+ :query => self.query ? self.query.dup : nil,
2077
+ :fragment => self.fragment ? self.fragment.dup : nil
2078
+ )
2079
+ return duplicated_uri
2080
+ end
2081
+
2082
+ ##
2083
+ # Omits components from a URI.
2084
+ #
2085
+ # @param [Symbol] *components The components to be omitted.
2086
+ #
2087
+ # @return [Addressable::URI] The URI with components omitted.
2088
+ #
2089
+ # @example
2090
+ # uri = Addressable::URI.parse("http://example.com/path?query")
2091
+ # #=> #<Addressable::URI:0xcc5e7a URI:http://example.com/path?query>
2092
+ # uri.omit(:scheme, :authority)
2093
+ # #=> #<Addressable::URI:0xcc4d86 URI:/path?query>
2094
+ def omit(*components)
2095
+ invalid_components = components - [
2096
+ :scheme, :user, :password, :userinfo, :host, :port, :authority,
2097
+ :path, :query, :fragment
2098
+ ]
2099
+ unless invalid_components.empty?
2100
+ raise ArgumentError,
2101
+ "Invalid component names: #{invalid_components.inspect}."
2102
+ end
2103
+ duplicated_uri = self.dup
2104
+ duplicated_uri.defer_validation do
2105
+ components.each do |component|
2106
+ duplicated_uri.send((component.to_s + "=").to_sym, nil)
2107
+ end
2108
+ duplicated_uri.user = duplicated_uri.normalized_user
2109
+ end
2110
+ duplicated_uri
2111
+ end
2112
+
2113
+ ##
2114
+ # Destructive form of omit.
2115
+ #
2116
+ # @param [Symbol] *components The components to be omitted.
2117
+ #
2118
+ # @return [Addressable::URI] The URI with components omitted.
2119
+ #
2120
+ # @see Addressable::URI#omit
2121
+ def omit!(*components)
2122
+ replace_self(self.omit(*components))
2123
+ end
2124
+
2125
+ ##
2126
+ # Converts the URI to a <code>String</code>.
2127
+ #
2128
+ # @return [String] The URI's <code>String</code> representation.
2129
+ def to_s
2130
+ if self.scheme == nil && self.path != nil && !self.path.empty? &&
2131
+ self.path =~ NORMPATH
2132
+ raise InvalidURIError,
2133
+ "Cannot assemble URI string with ambiguous path: '#{self.path}'"
2134
+ end
2135
+ @uri_string ||= (begin
2136
+ uri_string = ""
2137
+ uri_string << "#{self.scheme}:" if self.scheme != nil
2138
+ uri_string << "//#{self.authority}" if self.authority != nil
2139
+ uri_string << self.path.to_s
2140
+ uri_string << "?#{self.query}" if self.query != nil
2141
+ uri_string << "##{self.fragment}" if self.fragment != nil
2142
+ if uri_string.respond_to?(:force_encoding)
2143
+ uri_string.force_encoding(Encoding::UTF_8)
2144
+ end
2145
+ uri_string
2146
+ end)
2147
+ end
2148
+
2149
+ ##
2150
+ # URI's are glorified <code>Strings</code>. Allow implicit conversion.
2151
+ alias_method :to_str, :to_s
2152
+
2153
+ ##
2154
+ # Returns a Hash of the URI components.
2155
+ #
2156
+ # @return [Hash] The URI as a <code>Hash</code> of components.
2157
+ def to_hash
2158
+ return {
2159
+ :scheme => self.scheme,
2160
+ :user => self.user,
2161
+ :password => self.password,
2162
+ :host => self.host,
2163
+ :port => self.port,
2164
+ :path => self.path,
2165
+ :query => self.query,
2166
+ :fragment => self.fragment
2167
+ }
2168
+ end
2169
+
2170
+ ##
2171
+ # Returns a <code>String</code> representation of the URI object's state.
2172
+ #
2173
+ # @return [String] The URI object's state, as a <code>String</code>.
2174
+ def inspect
2175
+ sprintf("#<%s:%#0x URI:%s>", URI.to_s, self.object_id, self.to_s)
2176
+ end
2177
+
2178
+ ##
2179
+ # This method allows you to make several changes to a URI simultaneously,
2180
+ # which separately would cause validation errors, but in conjunction,
2181
+ # are valid. The URI will be revalidated as soon as the entire block has
2182
+ # been executed.
2183
+ #
2184
+ # @param [Proc] block
2185
+ # A set of operations to perform on a given URI.
2186
+ def defer_validation(&block)
2187
+ raise LocalJumpError, "No block given." unless block
2188
+ @validation_deferred = true
2189
+ block.call()
2190
+ @validation_deferred = false
2191
+ validate
2192
+ return nil
2193
+ end
2194
+
2195
+ private
2196
+ SELF_REF = '.'
2197
+ PARENT = '..'
2198
+
2199
+ RULE_2A = /\/\.\/|\/\.$/
2200
+ RULE_2B_2C = /\/([^\/]*)\/\.\.\/|\/([^\/]*)\/\.\.$/
2201
+ RULE_2D = /^\.\.?\/?/
2202
+ RULE_PREFIXED_PARENT = /^\/\.\.?\/|^(\/\.\.?)+\/?$/
2203
+
2204
+ ##
2205
+ # Resolves paths to their simplest form.
2206
+ #
2207
+ # @param [String] path The path to normalize.
2208
+ #
2209
+ # @return [String] The normalized path.
2210
+ def self.normalize_path(path)
2211
+ # Section 5.2.4 of RFC 3986
2212
+
2213
+ return nil if path.nil?
2214
+ normalized_path = path.dup
2215
+ begin
2216
+ mod = nil
2217
+ mod ||= normalized_path.gsub!(RULE_2A, SLASH)
2218
+
2219
+ pair = normalized_path.match(RULE_2B_2C)
2220
+ parent, current = pair[1], pair[2] if pair
2221
+ if pair && ((parent != SELF_REF && parent != PARENT) ||
2222
+ (current != SELF_REF && current != PARENT))
2223
+ mod ||= normalized_path.gsub!(
2224
+ Regexp.new(
2225
+ "/#{Regexp.escape(parent.to_s)}/\\.\\./|" +
2226
+ "(/#{Regexp.escape(current.to_s)}/\\.\\.$)"
2227
+ ), SLASH
2228
+ )
2229
+ end
2230
+
2231
+ mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR)
2232
+ # Non-standard, removes prefixed dotted segments from path.
2233
+ mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH)
2234
+ end until mod.nil?
2235
+
2236
+ return normalized_path
2237
+ end
2238
+
2239
+ ##
2240
+ # Ensures that the URI is valid.
2241
+ def validate
2242
+ return if !!@validation_deferred
2243
+ if self.scheme != nil &&
2244
+ (self.host == nil || self.host.empty?) &&
2245
+ (self.path == nil || self.path.empty?)
2246
+ raise InvalidURIError,
2247
+ "Absolute URI missing hierarchical segment: '#{self.to_s}'"
2248
+ end
2249
+ if self.host == nil
2250
+ if self.port != nil ||
2251
+ self.user != nil ||
2252
+ self.password != nil
2253
+ raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'"
2254
+ end
2255
+ end
2256
+ if self.path != nil && !self.path.empty? && self.path[0..0] != SLASH &&
2257
+ self.authority != nil
2258
+ raise InvalidURIError,
2259
+ "Cannot have a relative path with an authority set: '#{self.to_s}'"
2260
+ end
2261
+ return nil
2262
+ end
2263
+
2264
+ ##
2265
+ # Replaces the internal state of self with the specified URI's state.
2266
+ # Used in destructive operations to avoid massive code repetition.
2267
+ #
2268
+ # @param [Addressable::URI] uri The URI to replace <code>self</code> with.
2269
+ #
2270
+ # @return [Addressable::URI] <code>self</code>.
2271
+ def replace_self(uri)
2272
+ # Reset dependant values
2273
+ instance_variables.each do |var|
2274
+ instance_variable_set(var, nil)
2275
+ end
2276
+
2277
+ @scheme = uri.scheme
2278
+ @user = uri.user
2279
+ @password = uri.password
2280
+ @host = uri.host
2281
+ @port = uri.port
2282
+ @path = uri.path
2283
+ @query = uri.query
2284
+ @fragment = uri.fragment
2285
+ return self
2286
+ end
2287
+ end
2288
+ end