activesupport 3.0.0.beta4 → 3.0.pre

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (333) hide show
  1. data/CHANGELOG +1 -100
  2. data/lib/active_support.rb +4 -38
  3. data/lib/active_support/autoload.rb +28 -0
  4. data/lib/active_support/backtrace_cleaner.rb +9 -31
  5. data/lib/active_support/benchmarkable.rb +0 -1
  6. data/lib/active_support/buffered_logger.rb +1 -0
  7. data/lib/active_support/cache.rb +81 -436
  8. data/lib/active_support/cache/compressed_mem_cache_store.rb +13 -6
  9. data/lib/active_support/cache/file_store.rb +41 -139
  10. data/lib/active_support/cache/mem_cache_store.rb +75 -120
  11. data/lib/active_support/cache/memory_store.rb +27 -127
  12. data/lib/active_support/cache/strategy/local_cache.rb +58 -111
  13. data/lib/active_support/cache/synchronized_memory_store.rb +38 -2
  14. data/lib/active_support/callbacks.rb +48 -87
  15. data/lib/active_support/configurable.rb +18 -19
  16. data/lib/active_support/core_ext/array.rb +0 -1
  17. data/lib/active_support/core_ext/array/access.rb +1 -1
  18. data/lib/active_support/core_ext/array/conversions.rb +54 -29
  19. data/lib/active_support/core_ext/array/extract_options.rb +1 -16
  20. data/lib/active_support/core_ext/array/random_access.rb +5 -19
  21. data/lib/active_support/core_ext/array/wrap.rb +9 -13
  22. data/lib/active_support/core_ext/benchmark.rb +12 -0
  23. data/lib/active_support/core_ext/boolean.rb +1 -0
  24. data/lib/active_support/core_ext/boolean/conversions.rb +11 -0
  25. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -2
  26. data/lib/active_support/core_ext/class.rb +1 -1
  27. data/lib/active_support/core_ext/class/attribute_accessors.rb +27 -33
  28. data/lib/active_support/core_ext/class/delegating_attributes.rb +41 -35
  29. data/lib/active_support/core_ext/class/inheritable_attributes.rb +13 -22
  30. data/lib/active_support/core_ext/class/removal.rb +53 -0
  31. data/lib/active_support/core_ext/date.rb +7 -0
  32. data/lib/active_support/core_ext/date/calculations.rb +8 -30
  33. data/lib/active_support/core_ext/date/conversions.rb +2 -2
  34. data/lib/active_support/core_ext/date_time.rb +5 -0
  35. data/lib/active_support/core_ext/date_time/calculations.rb +1 -2
  36. data/lib/active_support/core_ext/date_time/conversions.rb +5 -23
  37. data/lib/active_support/core_ext/enumerable.rb +9 -5
  38. data/lib/active_support/core_ext/exception.rb +47 -0
  39. data/lib/active_support/core_ext/file.rb +0 -1
  40. data/lib/active_support/core_ext/file/atomic.rb +2 -3
  41. data/lib/active_support/core_ext/float/rounding.rb +2 -3
  42. data/lib/active_support/core_ext/hash/conversions.rb +145 -65
  43. data/lib/active_support/core_ext/hash/deep_merge.rb +7 -6
  44. data/lib/active_support/core_ext/hash/except.rb +0 -8
  45. data/lib/active_support/core_ext/hash/indifferent_access.rb +0 -5
  46. data/lib/active_support/core_ext/hash/keys.rb +11 -10
  47. data/lib/active_support/core_ext/hash/slice.rb +0 -6
  48. data/lib/active_support/core_ext/integer.rb +1 -1
  49. data/lib/active_support/core_ext/integer/even_odd.rb +16 -0
  50. data/lib/active_support/core_ext/kernel.rb +1 -1
  51. data/lib/active_support/core_ext/kernel/daemonizing.rb +7 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +2 -3
  53. data/lib/active_support/core_ext/kernel/reporting.rb +1 -2
  54. data/lib/active_support/core_ext/load_error.rb +30 -17
  55. data/lib/active_support/core_ext/logger.rb +1 -1
  56. data/lib/active_support/core_ext/module.rb +3 -5
  57. data/lib/active_support/core_ext/module/aliasing.rb +1 -1
  58. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +1 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +21 -25
  61. data/lib/active_support/core_ext/module/delegation.rb +10 -21
  62. data/lib/active_support/core_ext/module/inclusion.rb +30 -0
  63. data/lib/active_support/core_ext/module/introspection.rb +8 -8
  64. data/lib/active_support/core_ext/module/loading.rb +23 -0
  65. data/lib/active_support/core_ext/module/synchronization.rb +1 -2
  66. data/lib/active_support/core_ext/name_error.rb +1 -3
  67. data/lib/active_support/core_ext/nil.rb +1 -0
  68. data/lib/active_support/core_ext/nil/conversions.rb +5 -0
  69. data/lib/active_support/core_ext/object.rb +2 -6
  70. data/lib/active_support/core_ext/object/blank.rb +2 -20
  71. data/lib/active_support/core_ext/object/conversions.rb +16 -2
  72. data/lib/active_support/core_ext/object/duplicable.rb +1 -23
  73. data/lib/active_support/core_ext/object/extending.rb +77 -8
  74. data/lib/active_support/core_ext/object/instance_variables.rb +7 -0
  75. data/lib/active_support/core_ext/object/metaclass.rb +13 -0
  76. data/lib/active_support/core_ext/object/misc.rb +1 -0
  77. data/lib/active_support/core_ext/object/tap.rb +16 -0
  78. data/lib/active_support/core_ext/object/with_options.rb +0 -2
  79. data/lib/active_support/core_ext/proc.rb +4 -4
  80. data/lib/active_support/core_ext/regexp.rb +22 -0
  81. data/lib/active_support/core_ext/rexml.rb +1 -4
  82. data/lib/active_support/core_ext/string.rb +2 -3
  83. data/lib/active_support/core_ext/string/access.rb +2 -4
  84. data/lib/active_support/core_ext/string/bytesize.rb +5 -0
  85. data/lib/active_support/core_ext/string/conversions.rb +1 -36
  86. data/lib/active_support/core_ext/string/filters.rb +0 -29
  87. data/lib/active_support/core_ext/string/inflections.rb +12 -1
  88. data/lib/active_support/core_ext/string/interpolation.rb +92 -2
  89. data/lib/active_support/core_ext/string/iterators.rb +13 -0
  90. data/lib/active_support/core_ext/string/multibyte.rb +19 -16
  91. data/lib/active_support/core_ext/string/output_safety.rb +35 -101
  92. data/lib/active_support/core_ext/string/starts_ends_with.rb +14 -0
  93. data/lib/active_support/core_ext/string/xchar.rb +1 -1
  94. data/lib/active_support/core_ext/symbol.rb +1 -0
  95. data/lib/active_support/core_ext/symbol/to_proc.rb +14 -0
  96. data/lib/active_support/core_ext/time.rb +10 -0
  97. data/lib/active_support/core_ext/time/calculations.rb +7 -9
  98. data/lib/active_support/core_ext/time/conversions.rb +0 -1
  99. data/lib/active_support/core_ext/time/marshal_with_utc_flag.rb +22 -0
  100. data/lib/active_support/core_ext/uri.rb +4 -10
  101. data/lib/active_support/dependencies.rb +192 -179
  102. data/lib/active_support/deprecated_callbacks.rb +283 -0
  103. data/lib/active_support/deprecation/behaviors.rb +1 -1
  104. data/lib/active_support/deprecation/method_wrappers.rb +9 -10
  105. data/lib/active_support/deprecation/reporting.rb +1 -2
  106. data/lib/active_support/duration.rb +2 -6
  107. data/lib/active_support/hash_with_indifferent_access.rb +1 -9
  108. data/lib/active_support/inflections.rb +1 -1
  109. data/lib/active_support/inflector.rb +407 -4
  110. data/lib/active_support/json/backends/jsongem.rb +9 -12
  111. data/lib/active_support/json/decoding.rb +1 -16
  112. data/lib/active_support/json/encoding.rb +12 -42
  113. data/lib/active_support/locale/en.yml +1 -4
  114. data/lib/active_support/memoizable.rb +1 -1
  115. data/lib/active_support/message_encryptor.rb +0 -1
  116. data/lib/active_support/message_verifier.rb +5 -6
  117. data/lib/active_support/multibyte.rb +22 -7
  118. data/lib/active_support/multibyte/chars.rb +392 -164
  119. data/lib/active_support/multibyte/unicode_database.rb +71 -0
  120. data/lib/active_support/multibyte/utils.rb +7 -6
  121. data/lib/active_support/notifications.rb +113 -23
  122. data/lib/active_support/ordered_hash.rb +11 -35
  123. data/lib/active_support/ordered_options.rb +0 -6
  124. data/lib/active_support/rescuable.rb +4 -7
  125. data/lib/active_support/ruby/shim.rb +6 -4
  126. data/lib/active_support/test_case.rb +7 -2
  127. data/lib/active_support/testing/assertions.rb +0 -15
  128. data/lib/active_support/testing/declarative.rb +1 -1
  129. data/lib/active_support/testing/isolation.rb +19 -63
  130. data/lib/active_support/testing/performance.rb +337 -342
  131. data/lib/active_support/testing/setup_and_teardown.rb +29 -51
  132. data/lib/active_support/time.rb +3 -23
  133. data/lib/active_support/time_with_zone.rb +10 -5
  134. data/lib/active_support/values/time_zone.rb +84 -40
  135. data/lib/active_support/values/unicode_tables.dat +0 -0
  136. data/lib/active_support/vendor.rb +16 -0
  137. data/lib/active_support/vendor/builder-2.1.2/lib/blankslate.rb +113 -0
  138. data/lib/active_support/vendor/builder-2.1.2/lib/builder.rb +13 -0
  139. data/lib/active_support/vendor/builder-2.1.2/lib/builder/blankslate.rb +20 -0
  140. data/lib/active_support/vendor/builder-2.1.2/lib/builder/css.rb +250 -0
  141. data/lib/active_support/vendor/builder-2.1.2/lib/builder/xchar.rb +115 -0
  142. data/lib/active_support/vendor/builder-2.1.2/lib/builder/xmlbase.rb +139 -0
  143. data/lib/active_support/vendor/builder-2.1.2/lib/builder/xmlevents.rb +63 -0
  144. data/lib/active_support/vendor/builder-2.1.2/lib/builder/xmlmarkup.rb +328 -0
  145. data/lib/active_support/vendor/i18n-0.1.3/MIT-LICENSE +20 -0
  146. data/lib/active_support/vendor/i18n-0.1.3/README.textile +20 -0
  147. data/lib/active_support/vendor/i18n-0.1.3/Rakefile +5 -0
  148. data/lib/active_support/vendor/i18n-0.1.3/i18n.gemspec +27 -0
  149. data/lib/active_support/vendor/i18n-0.1.3/lib/i18n.rb +204 -0
  150. data/lib/active_support/vendor/i18n-0.1.3/lib/i18n/backend/simple.rb +215 -0
  151. data/lib/active_support/vendor/i18n-0.1.3/lib/i18n/exceptions.rb +53 -0
  152. data/lib/active_support/vendor/i18n-0.1.3/test/all.rb +5 -0
  153. data/lib/active_support/vendor/i18n-0.1.3/test/i18n_exceptions_test.rb +99 -0
  154. data/lib/active_support/vendor/i18n-0.1.3/test/i18n_test.rb +124 -0
  155. data/lib/active_support/vendor/i18n-0.1.3/test/locale/en.rb +1 -0
  156. data/lib/active_support/vendor/i18n-0.1.3/test/locale/en.yml +3 -0
  157. data/lib/active_support/vendor/i18n-0.1.3/test/simple_backend_test.rb +567 -0
  158. data/lib/active_support/vendor/memcache-client-1.7.5/lib/memcache.rb +1133 -0
  159. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo.rb +33 -0
  160. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/data_timezone.rb +47 -0
  161. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/data_timezone_info.rb +228 -0
  162. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Africa/Algiers.rb +55 -0
  163. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Africa/Cairo.rb +219 -0
  164. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Africa/Casablanca.rb +42 -0
  165. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Africa/Harare.rb +18 -0
  166. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Africa/Johannesburg.rb +25 -0
  167. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Africa/Monrovia.rb +22 -0
  168. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Africa/Nairobi.rb +23 -0
  169. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Argentina/Buenos_Aires.rb +166 -0
  170. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Argentina/San_Juan.rb +86 -0
  171. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Bogota.rb +23 -0
  172. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Caracas.rb +23 -0
  173. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Chicago.rb +283 -0
  174. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Chihuahua.rb +136 -0
  175. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Denver.rb +204 -0
  176. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Godthab.rb +161 -0
  177. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Guatemala.rb +27 -0
  178. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Halifax.rb +274 -0
  179. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Indiana/Indianapolis.rb +149 -0
  180. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Juneau.rb +194 -0
  181. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/La_Paz.rb +22 -0
  182. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Lima.rb +35 -0
  183. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Los_Angeles.rb +232 -0
  184. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Mazatlan.rb +139 -0
  185. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Mexico_City.rb +144 -0
  186. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Monterrey.rb +131 -0
  187. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/New_York.rb +282 -0
  188. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Phoenix.rb +30 -0
  189. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Regina.rb +74 -0
  190. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Santiago.rb +205 -0
  191. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Sao_Paulo.rb +171 -0
  192. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/St_Johns.rb +288 -0
  193. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/America/Tijuana.rb +196 -0
  194. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Almaty.rb +67 -0
  195. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Baghdad.rb +73 -0
  196. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Baku.rb +161 -0
  197. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Bangkok.rb +20 -0
  198. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Chongqing.rb +33 -0
  199. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Colombo.rb +30 -0
  200. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Dhaka.rb +27 -0
  201. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Hong_Kong.rb +87 -0
  202. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Irkutsk.rb +165 -0
  203. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Jakarta.rb +30 -0
  204. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Jerusalem.rb +163 -0
  205. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Kabul.rb +20 -0
  206. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Kamchatka.rb +163 -0
  207. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Karachi.rb +32 -0
  208. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Kathmandu.rb +20 -0
  209. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Kolkata.rb +25 -0
  210. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Krasnoyarsk.rb +163 -0
  211. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Kuala_Lumpur.rb +31 -0
  212. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Kuwait.rb +18 -0
  213. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Magadan.rb +163 -0
  214. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Muscat.rb +18 -0
  215. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Novosibirsk.rb +164 -0
  216. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Rangoon.rb +24 -0
  217. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Riyadh.rb +18 -0
  218. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Seoul.rb +34 -0
  219. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Shanghai.rb +35 -0
  220. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Singapore.rb +33 -0
  221. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Taipei.rb +59 -0
  222. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Tashkent.rb +47 -0
  223. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Tbilisi.rb +78 -0
  224. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Tehran.rb +121 -0
  225. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Tokyo.rb +30 -0
  226. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Ulaanbaatar.rb +65 -0
  227. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Urumqi.rb +33 -0
  228. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Vladivostok.rb +164 -0
  229. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Yakutsk.rb +163 -0
  230. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Yekaterinburg.rb +165 -0
  231. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Asia/Yerevan.rb +165 -0
  232. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Atlantic/Azores.rb +270 -0
  233. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Atlantic/Cape_Verde.rb +23 -0
  234. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Atlantic/South_Georgia.rb +18 -0
  235. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Australia/Adelaide.rb +187 -0
  236. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Australia/Brisbane.rb +35 -0
  237. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Australia/Darwin.rb +29 -0
  238. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Australia/Hobart.rb +193 -0
  239. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Australia/Melbourne.rb +185 -0
  240. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Australia/Perth.rb +37 -0
  241. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Australia/Sydney.rb +185 -0
  242. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Etc/UTC.rb +16 -0
  243. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Amsterdam.rb +228 -0
  244. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Athens.rb +185 -0
  245. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Belgrade.rb +163 -0
  246. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Berlin.rb +188 -0
  247. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Bratislava.rb +13 -0
  248. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Brussels.rb +232 -0
  249. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Bucharest.rb +181 -0
  250. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Budapest.rb +197 -0
  251. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Copenhagen.rb +179 -0
  252. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Dublin.rb +276 -0
  253. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Helsinki.rb +163 -0
  254. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Istanbul.rb +218 -0
  255. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Kiev.rb +168 -0
  256. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Lisbon.rb +268 -0
  257. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Ljubljana.rb +13 -0
  258. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/London.rb +288 -0
  259. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Madrid.rb +211 -0
  260. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Minsk.rb +170 -0
  261. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Moscow.rb +181 -0
  262. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Paris.rb +232 -0
  263. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Prague.rb +187 -0
  264. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Riga.rb +176 -0
  265. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Rome.rb +215 -0
  266. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Sarajevo.rb +13 -0
  267. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Skopje.rb +13 -0
  268. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Sofia.rb +173 -0
  269. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Stockholm.rb +165 -0
  270. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Tallinn.rb +172 -0
  271. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Vienna.rb +183 -0
  272. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Vilnius.rb +170 -0
  273. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Warsaw.rb +212 -0
  274. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Europe/Zagreb.rb +13 -0
  275. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Auckland.rb +202 -0
  276. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Fiji.rb +23 -0
  277. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Guam.rb +22 -0
  278. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Honolulu.rb +28 -0
  279. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Majuro.rb +20 -0
  280. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Midway.rb +25 -0
  281. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Noumea.rb +25 -0
  282. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Pago_Pago.rb +26 -0
  283. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Port_Moresby.rb +20 -0
  284. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/definitions/Pacific/Tongatapu.rb +27 -0
  285. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/info_timezone.rb +52 -0
  286. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/linked_timezone.rb +51 -0
  287. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/linked_timezone_info.rb +44 -0
  288. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/offset_rationals.rb +98 -0
  289. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/ruby_core_support.rb +56 -0
  290. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/time_or_datetime.rb +292 -0
  291. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/timezone.rb +508 -0
  292. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/timezone_definition.rb +56 -0
  293. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/timezone_info.rb +40 -0
  294. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/timezone_offset_info.rb +94 -0
  295. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/timezone_period.rb +198 -0
  296. data/lib/active_support/vendor/tzinfo-0.3.13/lib/tzinfo/timezone_transition_info.rb +129 -0
  297. data/lib/active_support/version.rb +2 -3
  298. data/lib/active_support/whiny_nil.rb +7 -9
  299. data/lib/active_support/xml_mini.rb +1 -126
  300. data/lib/active_support/xml_mini/jdom.rb +0 -2
  301. data/lib/active_support/xml_mini/libxml.rb +86 -24
  302. data/lib/active_support/xml_mini/nokogiri.rb +24 -27
  303. data/lib/active_support/xml_mini/rexml.rb +1 -7
  304. metadata +191 -49
  305. data/lib/active_support/builder.rb +0 -6
  306. data/lib/active_support/core_ext/array/uniq_by.rb +0 -17
  307. data/lib/active_support/core_ext/class/attribute.rb +0 -67
  308. data/lib/active_support/core_ext/class/subclasses.rb +0 -55
  309. data/lib/active_support/core_ext/file/path.rb +0 -5
  310. data/lib/active_support/core_ext/integer/multiple.rb +0 -6
  311. data/lib/active_support/core_ext/kernel/singleton_class.rb +0 -13
  312. data/lib/active_support/core_ext/module/anonymous.rb +0 -24
  313. data/lib/active_support/core_ext/module/method_names.rb +0 -14
  314. data/lib/active_support/core_ext/module/reachable.rb +0 -10
  315. data/lib/active_support/core_ext/module/remove_method.rb +0 -6
  316. data/lib/active_support/core_ext/object/to_param.rb +0 -49
  317. data/lib/active_support/core_ext/object/to_query.rb +0 -27
  318. data/lib/active_support/core_ext/string/encoding.rb +0 -11
  319. data/lib/active_support/core_ext/string/exclude.rb +0 -6
  320. data/lib/active_support/core_ext/time/marshal.rb +0 -56
  321. data/lib/active_support/dependencies/autoload.rb +0 -50
  322. data/lib/active_support/i18n.rb +0 -8
  323. data/lib/active_support/inflector/inflections.rb +0 -211
  324. data/lib/active_support/inflector/methods.rb +0 -141
  325. data/lib/active_support/inflector/transliterate.rb +0 -97
  326. data/lib/active_support/json/backends/yajl.rb +0 -40
  327. data/lib/active_support/lazy_load_hooks.rb +0 -27
  328. data/lib/active_support/multibyte/unicode.rb +0 -393
  329. data/lib/active_support/notifications/fanout.rb +0 -93
  330. data/lib/active_support/notifications/instrumenter.rb +0 -56
  331. data/lib/active_support/railtie.rb +0 -100
  332. data/lib/active_support/xml_mini/libxmlsax.rb +0 -85
  333. data/lib/active_support/xml_mini/nokogirisax.rb +0 -83
@@ -0,0 +1,1133 @@
1
+ $TESTING = defined?($TESTING) && $TESTING
2
+
3
+ require 'socket'
4
+ require 'thread'
5
+ require 'zlib'
6
+ require 'digest/sha1'
7
+ require 'net/protocol'
8
+
9
+ ##
10
+ # A Ruby client library for memcached.
11
+ #
12
+
13
+ class MemCache
14
+
15
+ ##
16
+ # The version of MemCache you are using.
17
+
18
+ VERSION = '1.7.5'
19
+
20
+ ##
21
+ # Default options for the cache object.
22
+
23
+ DEFAULT_OPTIONS = {
24
+ :namespace => nil,
25
+ :readonly => false,
26
+ :multithread => true,
27
+ :failover => true,
28
+ :timeout => 0.5,
29
+ :logger => nil,
30
+ :no_reply => false,
31
+ :check_size => true,
32
+ :autofix_keys => false,
33
+ :namespace_separator => ':',
34
+ }
35
+
36
+ ##
37
+ # Default memcached port.
38
+
39
+ DEFAULT_PORT = 11211
40
+
41
+ ##
42
+ # Default memcached server weight.
43
+
44
+ DEFAULT_WEIGHT = 1
45
+
46
+ ##
47
+ # The namespace for this instance
48
+
49
+ attr_reader :namespace
50
+
51
+ ##
52
+ # The multithread setting for this instance
53
+
54
+ attr_reader :multithread
55
+
56
+ ##
57
+ # Whether to try to fix keys that are too long and will be truncated by
58
+ # using their SHA1 hash instead.
59
+ # The hash is only used on keys longer than 250 characters, or containing spaces,
60
+ # to avoid impacting performance unnecesarily.
61
+ #
62
+ # In theory, your code should generate correct keys when calling memcache,
63
+ # so it's your responsibility and you should try to fix this problem at its source.
64
+ #
65
+ # But if that's not possible, enable this option and memcache-client will give you a hand.
66
+
67
+ attr_reader :autofix_keys
68
+
69
+ ##
70
+ # The servers this client talks to. Play at your own peril.
71
+
72
+ attr_reader :servers
73
+
74
+ ##
75
+ # Socket timeout limit with this client, defaults to 0.5 sec.
76
+ # Set to nil to disable timeouts.
77
+
78
+ attr_reader :timeout
79
+
80
+ ##
81
+ # Should the client try to failover to another server if the
82
+ # first server is down? Defaults to true.
83
+
84
+ attr_reader :failover
85
+
86
+ ##
87
+ # Log debug/info/warn/error to the given Logger, defaults to nil.
88
+
89
+ attr_reader :logger
90
+
91
+ ##
92
+ # Don't send or look for a reply from the memcached server for write operations.
93
+ # Please note this feature only works in memcached 1.2.5 and later. Earlier
94
+ # versions will reply with "ERROR".
95
+ attr_reader :no_reply
96
+
97
+ ##
98
+ # Accepts a list of +servers+ and a list of +opts+. +servers+ may be
99
+ # omitted. See +servers=+ for acceptable server list arguments.
100
+ #
101
+ # Valid options for +opts+ are:
102
+ #
103
+ # [:namespace] Prepends this value to all keys added or retrieved.
104
+ # [:readonly] Raises an exception on cache writes when true.
105
+ # [:multithread] Wraps cache access in a Mutex for thread safety. Defaults to true.
106
+ # [:failover] Should the client try to failover to another server if the
107
+ # first server is down? Defaults to true.
108
+ # [:timeout] Time to use as the socket read timeout. Defaults to 0.5 sec,
109
+ # set to nil to disable timeouts.
110
+ # [:logger] Logger to use for info/debug output, defaults to nil
111
+ # [:no_reply] Don't bother looking for a reply for write operations (i.e. they
112
+ # become 'fire and forget'), memcached 1.2.5 and later only, speeds up
113
+ # set/add/delete/incr/decr significantly.
114
+ # [:check_size] Raises a MemCacheError if the value to be set is greater than 1 MB, which
115
+ # is the maximum key size for the standard memcached server. Defaults to true.
116
+ # [:autofix_keys] If a key is longer than 250 characters or contains spaces,
117
+ # use an SHA1 hash instead, to prevent collisions on truncated keys.
118
+ # Other options are ignored.
119
+
120
+ def initialize(*args)
121
+ servers = []
122
+ opts = {}
123
+
124
+ case args.length
125
+ when 0 then # NOP
126
+ when 1 then
127
+ arg = args.shift
128
+ case arg
129
+ when Hash then opts = arg
130
+ when Array then servers = arg
131
+ when String then servers = [arg]
132
+ else raise ArgumentError, 'first argument must be Array, Hash or String'
133
+ end
134
+ when 2 then
135
+ servers, opts = args
136
+ else
137
+ raise ArgumentError, "wrong number of arguments (#{args.length} for 2)"
138
+ end
139
+
140
+ opts = DEFAULT_OPTIONS.merge opts
141
+ @namespace = opts[:namespace]
142
+ @readonly = opts[:readonly]
143
+ @multithread = opts[:multithread]
144
+ @autofix_keys = opts[:autofix_keys]
145
+ @timeout = opts[:timeout]
146
+ @failover = opts[:failover]
147
+ @logger = opts[:logger]
148
+ @no_reply = opts[:no_reply]
149
+ @check_size = opts[:check_size]
150
+ @namespace_separator = opts[:namespace_separator]
151
+ @mutex = Mutex.new if @multithread
152
+
153
+ logger.info { "memcache-client #{VERSION} #{Array(servers).inspect}" } if logger
154
+
155
+ Thread.current[:memcache_client] = self.object_id if !@multithread
156
+
157
+ self.servers = servers
158
+ end
159
+
160
+ ##
161
+ # Returns a string representation of the cache object.
162
+
163
+ def inspect
164
+ "<MemCache: %d servers, ns: %p, ro: %p>" %
165
+ [@servers.length, @namespace, @readonly]
166
+ end
167
+
168
+ ##
169
+ # Returns whether there is at least one active server for the object.
170
+
171
+ def active?
172
+ not @servers.empty?
173
+ end
174
+
175
+ ##
176
+ # Returns whether or not the cache object was created read only.
177
+
178
+ def readonly?
179
+ @readonly
180
+ end
181
+
182
+ ##
183
+ # Set the servers that the requests will be distributed between. Entries
184
+ # can be either strings of the form "hostname:port" or
185
+ # "hostname:port:weight" or MemCache::Server objects.
186
+ #
187
+ def servers=(servers)
188
+ # Create the server objects.
189
+ @servers = Array(servers).collect do |server|
190
+ case server
191
+ when String
192
+ host, port, weight = server.split ':', 3
193
+ port ||= DEFAULT_PORT
194
+ weight ||= DEFAULT_WEIGHT
195
+ Server.new self, host, port, weight
196
+ else
197
+ server
198
+ end
199
+ end
200
+
201
+ logger.debug { "Servers now: #{@servers.inspect}" } if logger
202
+
203
+ # There's no point in doing this if there's only one server
204
+ @continuum = create_continuum_for(@servers) if @servers.size > 1
205
+
206
+ @servers
207
+ end
208
+
209
+ ##
210
+ # Decrements the value for +key+ by +amount+ and returns the new value.
211
+ # +key+ must already exist. If +key+ is not an integer, it is assumed to be
212
+ # 0. +key+ can not be decremented below 0.
213
+
214
+ def decr(key, amount = 1)
215
+ raise MemCacheError, "Update of readonly cache" if @readonly
216
+ with_server(key) do |server, cache_key|
217
+ cache_decr server, cache_key, amount
218
+ end
219
+ rescue TypeError => err
220
+ handle_error nil, err
221
+ end
222
+
223
+ ##
224
+ # Retrieves +key+ from memcache. If +raw+ is false, the value will be
225
+ # unmarshalled.
226
+
227
+ def get(key, raw = false)
228
+ with_server(key) do |server, cache_key|
229
+ logger.debug { "get #{key} from #{server.inspect}" } if logger
230
+ value = cache_get server, cache_key
231
+ return nil if value.nil?
232
+ value = Marshal.load value unless raw
233
+ return value
234
+ end
235
+ rescue TypeError => err
236
+ handle_error nil, err
237
+ end
238
+
239
+ ##
240
+ # Performs a +get+ with the given +key+. If
241
+ # the value does not exist and a block was given,
242
+ # the block will be called and the result saved via +add+.
243
+ #
244
+ # If you do not provide a block, using this
245
+ # method is the same as using +get+.
246
+ #
247
+ def fetch(key, expiry = 0, raw = false)
248
+ value = get(key, raw)
249
+
250
+ if value.nil? && block_given?
251
+ value = yield
252
+ add(key, value, expiry, raw)
253
+ end
254
+
255
+ value
256
+ end
257
+
258
+ ##
259
+ # Retrieves multiple values from memcached in parallel, if possible.
260
+ #
261
+ # The memcached protocol supports the ability to retrieve multiple
262
+ # keys in a single request. Pass in an array of keys to this method
263
+ # and it will:
264
+ #
265
+ # 1. map the key to the appropriate memcached server
266
+ # 2. send a single request to each server that has one or more key values
267
+ #
268
+ # Returns a hash of values.
269
+ #
270
+ # cache["a"] = 1
271
+ # cache["b"] = 2
272
+ # cache.get_multi "a", "b" # => { "a" => 1, "b" => 2 }
273
+ #
274
+ # Note that get_multi assumes the values are marshalled.
275
+
276
+ def get_multi(*keys)
277
+ raise MemCacheError, 'No active servers' unless active?
278
+
279
+ keys.flatten!
280
+ key_count = keys.length
281
+ cache_keys = {}
282
+ server_keys = Hash.new { |h,k| h[k] = [] }
283
+
284
+ # map keys to servers
285
+ keys.each do |key|
286
+ server, cache_key = request_setup key
287
+ cache_keys[cache_key] = key
288
+ server_keys[server] << cache_key
289
+ end
290
+
291
+ results = {}
292
+
293
+ server_keys.each do |server, keys_for_server|
294
+ keys_for_server_str = keys_for_server.join ' '
295
+ begin
296
+ values = cache_get_multi server, keys_for_server_str
297
+ values.each do |key, value|
298
+ results[cache_keys[key]] = Marshal.load value
299
+ end
300
+ rescue IndexError => e
301
+ # Ignore this server and try the others
302
+ logger.warn { "Unable to retrieve #{keys_for_server.size} elements from #{server.inspect}: #{e.message}"} if logger
303
+ end
304
+ end
305
+
306
+ return results
307
+ rescue TypeError => err
308
+ handle_error nil, err
309
+ end
310
+
311
+ ##
312
+ # Increments the value for +key+ by +amount+ and returns the new value.
313
+ # +key+ must already exist. If +key+ is not an integer, it is assumed to be
314
+ # 0.
315
+
316
+ def incr(key, amount = 1)
317
+ raise MemCacheError, "Update of readonly cache" if @readonly
318
+ with_server(key) do |server, cache_key|
319
+ cache_incr server, cache_key, amount
320
+ end
321
+ rescue TypeError => err
322
+ handle_error nil, err
323
+ end
324
+
325
+ ##
326
+ # Add +key+ to the cache with value +value+ that expires in +expiry+
327
+ # seconds. If +raw+ is true, +value+ will not be Marshalled.
328
+ #
329
+ # Warning: Readers should not call this method in the event of a cache miss;
330
+ # see MemCache#add.
331
+
332
+ ONE_MB = 1024 * 1024
333
+
334
+ def set(key, value, expiry = 0, raw = false)
335
+ raise MemCacheError, "Update of readonly cache" if @readonly
336
+
337
+ value = Marshal.dump value unless raw
338
+ with_server(key) do |server, cache_key|
339
+ logger.debug { "set #{key} to #{server.inspect}: #{value.to_s.size}" } if logger
340
+
341
+ if @check_size && value.to_s.size > ONE_MB
342
+ raise MemCacheError, "Value too large, memcached can only store 1MB of data per key"
343
+ end
344
+
345
+ command = "set #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n"
346
+
347
+ with_socket_management(server) do |socket|
348
+ socket.write command
349
+ break nil if @no_reply
350
+ result = socket.gets
351
+ raise_on_error_response! result
352
+
353
+ if result.nil?
354
+ server.close
355
+ raise MemCacheError, "lost connection to #{server.host}:#{server.port}"
356
+ end
357
+
358
+ result
359
+ end
360
+ end
361
+ end
362
+
363
+ ##
364
+ # "cas" is a check and set operation which means "store this data but
365
+ # only if no one else has updated since I last fetched it." This can
366
+ # be used as a form of optimistic locking.
367
+ #
368
+ # Works in block form like so:
369
+ # cache.cas('some-key') do |value|
370
+ # value + 1
371
+ # end
372
+ #
373
+ # Returns:
374
+ # +nil+ if the value was not found on the memcached server.
375
+ # +STORED+ if the value was updated successfully
376
+ # +EXISTS+ if the value was updated by someone else since last fetch
377
+
378
+ def cas(key, expiry=0, raw=false)
379
+ raise MemCacheError, "Update of readonly cache" if @readonly
380
+ raise MemCacheError, "A block is required" unless block_given?
381
+
382
+ (value, token) = gets(key, raw)
383
+ return nil unless value
384
+ updated = yield value
385
+ value = Marshal.dump updated unless raw
386
+
387
+ with_server(key) do |server, cache_key|
388
+ logger.debug { "cas #{key} to #{server.inspect}: #{value.to_s.size}" } if logger
389
+ command = "cas #{cache_key} 0 #{expiry} #{value.to_s.size} #{token}#{noreply}\r\n#{value}\r\n"
390
+
391
+ with_socket_management(server) do |socket|
392
+ socket.write command
393
+ break nil if @no_reply
394
+ result = socket.gets
395
+ raise_on_error_response! result
396
+
397
+ if result.nil?
398
+ server.close
399
+ raise MemCacheError, "lost connection to #{server.host}:#{server.port}"
400
+ end
401
+
402
+ result
403
+ end
404
+ end
405
+ end
406
+
407
+ ##
408
+ # Add +key+ to the cache with value +value+ that expires in +expiry+
409
+ # seconds, but only if +key+ does not already exist in the cache.
410
+ # If +raw+ is true, +value+ will not be Marshalled.
411
+ #
412
+ # Readers should call this method in the event of a cache miss, not
413
+ # MemCache#set.
414
+
415
+ def add(key, value, expiry = 0, raw = false)
416
+ raise MemCacheError, "Update of readonly cache" if @readonly
417
+ value = Marshal.dump value unless raw
418
+ with_server(key) do |server, cache_key|
419
+ logger.debug { "add #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger
420
+ command = "add #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n"
421
+
422
+ with_socket_management(server) do |socket|
423
+ socket.write command
424
+ break nil if @no_reply
425
+ result = socket.gets
426
+ raise_on_error_response! result
427
+ result
428
+ end
429
+ end
430
+ end
431
+
432
+ ##
433
+ # Add +key+ to the cache with value +value+ that expires in +expiry+
434
+ # seconds, but only if +key+ already exists in the cache.
435
+ # If +raw+ is true, +value+ will not be Marshalled.
436
+ def replace(key, value, expiry = 0, raw = false)
437
+ raise MemCacheError, "Update of readonly cache" if @readonly
438
+ value = Marshal.dump value unless raw
439
+ with_server(key) do |server, cache_key|
440
+ logger.debug { "replace #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger
441
+ command = "replace #{cache_key} 0 #{expiry} #{value.to_s.size}#{noreply}\r\n#{value}\r\n"
442
+
443
+ with_socket_management(server) do |socket|
444
+ socket.write command
445
+ break nil if @no_reply
446
+ result = socket.gets
447
+ raise_on_error_response! result
448
+ result
449
+ end
450
+ end
451
+ end
452
+
453
+ ##
454
+ # Append - 'add this data to an existing key after existing data'
455
+ # Please note the value is always passed to memcached as raw since it
456
+ # doesn't make a lot of sense to concatenate marshalled data together.
457
+ def append(key, value)
458
+ raise MemCacheError, "Update of readonly cache" if @readonly
459
+ with_server(key) do |server, cache_key|
460
+ logger.debug { "append #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger
461
+ command = "append #{cache_key} 0 0 #{value.to_s.size}#{noreply}\r\n#{value}\r\n"
462
+
463
+ with_socket_management(server) do |socket|
464
+ socket.write command
465
+ break nil if @no_reply
466
+ result = socket.gets
467
+ raise_on_error_response! result
468
+ result
469
+ end
470
+ end
471
+ end
472
+
473
+ ##
474
+ # Prepend - 'add this data to an existing key before existing data'
475
+ # Please note the value is always passed to memcached as raw since it
476
+ # doesn't make a lot of sense to concatenate marshalled data together.
477
+ def prepend(key, value)
478
+ raise MemCacheError, "Update of readonly cache" if @readonly
479
+ with_server(key) do |server, cache_key|
480
+ logger.debug { "prepend #{key} to #{server}: #{value ? value.to_s.size : 'nil'}" } if logger
481
+ command = "prepend #{cache_key} 0 0 #{value.to_s.size}#{noreply}\r\n#{value}\r\n"
482
+
483
+ with_socket_management(server) do |socket|
484
+ socket.write command
485
+ break nil if @no_reply
486
+ result = socket.gets
487
+ raise_on_error_response! result
488
+ result
489
+ end
490
+ end
491
+ end
492
+
493
+ ##
494
+ # Removes +key+ from the cache in +expiry+ seconds.
495
+
496
+ def delete(key, expiry = 0)
497
+ raise MemCacheError, "Update of readonly cache" if @readonly
498
+ with_server(key) do |server, cache_key|
499
+ with_socket_management(server) do |socket|
500
+ logger.debug { "delete #{cache_key} on #{server}" } if logger
501
+ socket.write "delete #{cache_key} #{expiry}#{noreply}\r\n"
502
+ break nil if @no_reply
503
+ result = socket.gets
504
+ raise_on_error_response! result
505
+ result
506
+ end
507
+ end
508
+ end
509
+
510
+ ##
511
+ # Flush the cache from all memcache servers.
512
+ # A non-zero value for +delay+ will ensure that the flush
513
+ # is propogated slowly through your memcached server farm.
514
+ # The Nth server will be flushed N*delay seconds from now,
515
+ # asynchronously so this method returns quickly.
516
+ # This prevents a huge database spike due to a total
517
+ # flush all at once.
518
+
519
+ def flush_all(delay=0)
520
+ raise MemCacheError, 'No active servers' unless active?
521
+ raise MemCacheError, "Update of readonly cache" if @readonly
522
+
523
+ begin
524
+ delay_time = 0
525
+ @servers.each do |server|
526
+ with_socket_management(server) do |socket|
527
+ logger.debug { "flush_all #{delay_time} on #{server}" } if logger
528
+ if delay == 0 # older versions of memcached will fail silently otherwise
529
+ socket.write "flush_all#{noreply}\r\n"
530
+ else
531
+ socket.write "flush_all #{delay_time}#{noreply}\r\n"
532
+ end
533
+ break nil if @no_reply
534
+ result = socket.gets
535
+ raise_on_error_response! result
536
+ result
537
+ end
538
+ delay_time += delay
539
+ end
540
+ rescue IndexError => err
541
+ handle_error nil, err
542
+ end
543
+ end
544
+
545
+ ##
546
+ # Reset the connection to all memcache servers. This should be called if
547
+ # there is a problem with a cache lookup that might have left the connection
548
+ # in a corrupted state.
549
+
550
+ def reset
551
+ @servers.each { |server| server.close }
552
+ end
553
+
554
+ ##
555
+ # Returns statistics for each memcached server. An explanation of the
556
+ # statistics can be found in the memcached docs:
557
+ #
558
+ # http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt
559
+ #
560
+ # Example:
561
+ #
562
+ # >> pp CACHE.stats
563
+ # {"localhost:11211"=>
564
+ # {"bytes"=>4718,
565
+ # "pid"=>20188,
566
+ # "connection_structures"=>4,
567
+ # "time"=>1162278121,
568
+ # "pointer_size"=>32,
569
+ # "limit_maxbytes"=>67108864,
570
+ # "cmd_get"=>14532,
571
+ # "version"=>"1.2.0",
572
+ # "bytes_written"=>432583,
573
+ # "cmd_set"=>32,
574
+ # "get_misses"=>0,
575
+ # "total_connections"=>19,
576
+ # "curr_connections"=>3,
577
+ # "curr_items"=>4,
578
+ # "uptime"=>1557,
579
+ # "get_hits"=>14532,
580
+ # "total_items"=>32,
581
+ # "rusage_system"=>0.313952,
582
+ # "rusage_user"=>0.119981,
583
+ # "bytes_read"=>190619}}
584
+ # => nil
585
+
586
+ def stats
587
+ raise MemCacheError, "No active servers" unless active?
588
+ server_stats = {}
589
+
590
+ @servers.each do |server|
591
+ next unless server.alive?
592
+
593
+ with_socket_management(server) do |socket|
594
+ value = nil
595
+ socket.write "stats\r\n"
596
+ stats = {}
597
+ while line = socket.gets do
598
+ raise_on_error_response! line
599
+ break if line == "END\r\n"
600
+ if line =~ /\ASTAT ([\S]+) ([\w\.\:]+)/ then
601
+ name, value = $1, $2
602
+ stats[name] = case name
603
+ when 'version'
604
+ value
605
+ when 'rusage_user', 'rusage_system' then
606
+ seconds, microseconds = value.split(/:/, 2)
607
+ microseconds ||= 0
608
+ Float(seconds) + (Float(microseconds) / 1_000_000)
609
+ else
610
+ if value =~ /\A\d+\Z/ then
611
+ value.to_i
612
+ else
613
+ value
614
+ end
615
+ end
616
+ end
617
+ end
618
+ server_stats["#{server.host}:#{server.port}"] = stats
619
+ end
620
+ end
621
+
622
+ raise MemCacheError, "No active servers" if server_stats.empty?
623
+ server_stats
624
+ end
625
+
626
+ ##
627
+ # Shortcut to get a value from the cache.
628
+
629
+ alias [] get
630
+
631
+ ##
632
+ # Shortcut to save a value in the cache. This method does not set an
633
+ # expiration on the entry. Use set to specify an explicit expiry.
634
+
635
+ def []=(key, value)
636
+ set key, value
637
+ end
638
+
639
+ protected unless $TESTING
640
+
641
+ ##
642
+ # Create a key for the cache, incorporating the namespace qualifier if
643
+ # requested.
644
+
645
+ def make_cache_key(key)
646
+ if @autofix_keys and (key =~ /\s/ or (key.length + (namespace.nil? ? 0 : namespace.length)) > 250)
647
+ key = "#{Digest::SHA1.hexdigest(key)}-autofixed"
648
+ end
649
+
650
+ if namespace.nil? then
651
+ key
652
+ else
653
+ "#{@namespace}#{@namespace_separator}#{key}"
654
+ end
655
+ end
656
+
657
+ ##
658
+ # Returns an interoperable hash value for +key+. (I think, docs are
659
+ # sketchy for down servers).
660
+
661
+ def hash_for(key)
662
+ Zlib.crc32(key)
663
+ end
664
+
665
+ ##
666
+ # Pick a server to handle the request based on a hash of the key.
667
+
668
+ def get_server_for_key(key, options = {})
669
+ raise ArgumentError, "illegal character in key #{key.inspect}" if
670
+ key =~ /\s/
671
+ raise ArgumentError, "key too long #{key.inspect}" if key.length > 250
672
+ raise MemCacheError, "No servers available" if @servers.empty?
673
+ return @servers.first if @servers.length == 1
674
+
675
+ hkey = hash_for(key)
676
+
677
+ 20.times do |try|
678
+ entryidx = Continuum.binary_search(@continuum, hkey)
679
+ server = @continuum[entryidx].server
680
+ return server if server.alive?
681
+ break unless failover
682
+ hkey = hash_for "#{try}#{key}"
683
+ end
684
+
685
+ raise MemCacheError, "No servers available"
686
+ end
687
+
688
+ ##
689
+ # Performs a raw decr for +cache_key+ from +server+. Returns nil if not
690
+ # found.
691
+
692
+ def cache_decr(server, cache_key, amount)
693
+ with_socket_management(server) do |socket|
694
+ socket.write "decr #{cache_key} #{amount}#{noreply}\r\n"
695
+ break nil if @no_reply
696
+ text = socket.gets
697
+ raise_on_error_response! text
698
+ return nil if text == "NOT_FOUND\r\n"
699
+ return text.to_i
700
+ end
701
+ end
702
+
703
+ ##
704
+ # Fetches the raw data for +cache_key+ from +server+. Returns nil on cache
705
+ # miss.
706
+
707
+ def cache_get(server, cache_key)
708
+ with_socket_management(server) do |socket|
709
+ socket.write "get #{cache_key}\r\n"
710
+ keyline = socket.gets # "VALUE <key> <flags> <bytes>\r\n"
711
+
712
+ if keyline.nil? then
713
+ server.close
714
+ raise MemCacheError, "lost connection to #{server.host}:#{server.port}"
715
+ end
716
+
717
+ raise_on_error_response! keyline
718
+ return nil if keyline == "END\r\n"
719
+
720
+ unless keyline =~ /(\d+)\r/ then
721
+ server.close
722
+ raise MemCacheError, "unexpected response #{keyline.inspect}"
723
+ end
724
+ value = socket.read $1.to_i
725
+ socket.read 2 # "\r\n"
726
+ socket.gets # "END\r\n"
727
+ return value
728
+ end
729
+ end
730
+
731
+ def gets(key, raw = false)
732
+ with_server(key) do |server, cache_key|
733
+ logger.debug { "gets #{key} from #{server.inspect}" } if logger
734
+ result = with_socket_management(server) do |socket|
735
+ socket.write "gets #{cache_key}\r\n"
736
+ keyline = socket.gets # "VALUE <key> <flags> <bytes> <cas token>\r\n"
737
+
738
+ if keyline.nil? then
739
+ server.close
740
+ raise MemCacheError, "lost connection to #{server.host}:#{server.port}"
741
+ end
742
+
743
+ raise_on_error_response! keyline
744
+ return nil if keyline == "END\r\n"
745
+
746
+ unless keyline =~ /(\d+) (\w+)\r/ then
747
+ server.close
748
+ raise MemCacheError, "unexpected response #{keyline.inspect}"
749
+ end
750
+ value = socket.read $1.to_i
751
+ socket.read 2 # "\r\n"
752
+ socket.gets # "END\r\n"
753
+ [value, $2]
754
+ end
755
+ result[0] = Marshal.load result[0] unless raw
756
+ result
757
+ end
758
+ rescue TypeError => err
759
+ handle_error nil, err
760
+ end
761
+
762
+
763
+ ##
764
+ # Fetches +cache_keys+ from +server+ using a multi-get.
765
+
766
+ def cache_get_multi(server, cache_keys)
767
+ with_socket_management(server) do |socket|
768
+ values = {}
769
+ socket.write "get #{cache_keys}\r\n"
770
+
771
+ while keyline = socket.gets do
772
+ return values if keyline == "END\r\n"
773
+ raise_on_error_response! keyline
774
+
775
+ unless keyline =~ /\AVALUE (.+) (.+) (.+)/ then
776
+ server.close
777
+ raise MemCacheError, "unexpected response #{keyline.inspect}"
778
+ end
779
+
780
+ key, data_length = $1, $3
781
+ values[$1] = socket.read data_length.to_i
782
+ socket.read(2) # "\r\n"
783
+ end
784
+
785
+ server.close
786
+ raise MemCacheError, "lost connection to #{server.host}:#{server.port}" # TODO: retry here too
787
+ end
788
+ end
789
+
790
+ ##
791
+ # Performs a raw incr for +cache_key+ from +server+. Returns nil if not
792
+ # found.
793
+
794
+ def cache_incr(server, cache_key, amount)
795
+ with_socket_management(server) do |socket|
796
+ socket.write "incr #{cache_key} #{amount}#{noreply}\r\n"
797
+ break nil if @no_reply
798
+ text = socket.gets
799
+ raise_on_error_response! text
800
+ return nil if text == "NOT_FOUND\r\n"
801
+ return text.to_i
802
+ end
803
+ end
804
+
805
+ ##
806
+ # Gets or creates a socket connected to the given server, and yields it
807
+ # to the block, wrapped in a mutex synchronization if @multithread is true.
808
+ #
809
+ # If a socket error (SocketError, SystemCallError, IOError) or protocol error
810
+ # (MemCacheError) is raised by the block, closes the socket, attempts to
811
+ # connect again, and retries the block (once). If an error is again raised,
812
+ # reraises it as MemCacheError.
813
+ #
814
+ # If unable to connect to the server (or if in the reconnect wait period),
815
+ # raises MemCacheError. Note that the socket connect code marks a server
816
+ # dead for a timeout period, so retrying does not apply to connection attempt
817
+ # failures (but does still apply to unexpectedly lost connections etc.).
818
+
819
+ def with_socket_management(server, &block)
820
+ check_multithread_status!
821
+
822
+ @mutex.lock if @multithread
823
+ retried = false
824
+
825
+ begin
826
+ socket = server.socket
827
+
828
+ # Raise an IndexError to show this server is out of whack. If were inside
829
+ # a with_server block, we'll catch it and attempt to restart the operation.
830
+
831
+ raise IndexError, "No connection to server (#{server.status})" if socket.nil?
832
+
833
+ block.call(socket)
834
+
835
+ rescue SocketError, Errno::EAGAIN, Timeout::Error => err
836
+ logger.warn { "Socket failure: #{err.message}" } if logger
837
+ server.mark_dead(err)
838
+ handle_error(server, err)
839
+
840
+ rescue MemCacheError, SystemCallError, IOError => err
841
+ logger.warn { "Generic failure: #{err.class.name}: #{err.message}" } if logger
842
+ handle_error(server, err) if retried || socket.nil?
843
+ retried = true
844
+ retry
845
+ end
846
+ ensure
847
+ @mutex.unlock if @multithread
848
+ end
849
+
850
+ def with_server(key)
851
+ retried = false
852
+ begin
853
+ server, cache_key = request_setup(key)
854
+ yield server, cache_key
855
+ rescue IndexError => e
856
+ logger.warn { "Server failed: #{e.class.name}: #{e.message}" } if logger
857
+ if !retried && @servers.size > 1
858
+ logger.info { "Connection to server #{server.inspect} DIED! Retrying operation..." } if logger
859
+ retried = true
860
+ retry
861
+ end
862
+ handle_error(nil, e)
863
+ end
864
+ end
865
+
866
+ ##
867
+ # Handles +error+ from +server+.
868
+
869
+ def handle_error(server, error)
870
+ raise error if error.is_a?(MemCacheError)
871
+ server.close if server
872
+ new_error = MemCacheError.new error.message
873
+ new_error.set_backtrace error.backtrace
874
+ raise new_error
875
+ end
876
+
877
+ def noreply
878
+ @no_reply ? ' noreply' : ''
879
+ end
880
+
881
+ ##
882
+ # Performs setup for making a request with +key+ from memcached. Returns
883
+ # the server to fetch the key from and the complete key to use.
884
+
885
+ def request_setup(key)
886
+ raise MemCacheError, 'No active servers' unless active?
887
+ cache_key = make_cache_key key
888
+ server = get_server_for_key cache_key
889
+ return server, cache_key
890
+ end
891
+
892
+ def raise_on_error_response!(response)
893
+ if response =~ /\A(?:CLIENT_|SERVER_)?ERROR(.*)/
894
+ raise MemCacheError, $1.strip
895
+ end
896
+ end
897
+
898
+ def create_continuum_for(servers)
899
+ total_weight = servers.inject(0) { |memo, srv| memo + srv.weight }
900
+ continuum = []
901
+
902
+ servers.each do |server|
903
+ entry_count_for(server, servers.size, total_weight).times do |idx|
904
+ hash = Digest::SHA1.hexdigest("#{server.host}:#{server.port}:#{idx}")
905
+ value = Integer("0x#{hash[0..7]}")
906
+ continuum << Continuum::Entry.new(value, server)
907
+ end
908
+ end
909
+
910
+ continuum.sort { |a, b| a.value <=> b.value }
911
+ end
912
+
913
+ def entry_count_for(server, total_servers, total_weight)
914
+ ((total_servers * Continuum::POINTS_PER_SERVER * server.weight) / Float(total_weight)).floor
915
+ end
916
+
917
+ def check_multithread_status!
918
+ return if @multithread
919
+
920
+ if Thread.current[:memcache_client] != self.object_id
921
+ raise MemCacheError, <<-EOM
922
+ You are accessing this memcache-client instance from multiple threads but have not enabled multithread support.
923
+ Normally: MemCache.new(['localhost:11211'], :multithread => true)
924
+ In Rails: config.cache_store = [:mem_cache_store, 'localhost:11211', { :multithread => true }]
925
+ EOM
926
+ end
927
+ end
928
+
929
+ ##
930
+ # This class represents a memcached server instance.
931
+
932
+ class Server
933
+
934
+ ##
935
+ # The amount of time to wait before attempting to re-establish a
936
+ # connection with a server that is marked dead.
937
+
938
+ RETRY_DELAY = 30.0
939
+
940
+ ##
941
+ # The host the memcached server is running on.
942
+
943
+ attr_reader :host
944
+
945
+ ##
946
+ # The port the memcached server is listening on.
947
+
948
+ attr_reader :port
949
+
950
+ ##
951
+ # The weight given to the server.
952
+
953
+ attr_reader :weight
954
+
955
+ ##
956
+ # The time of next retry if the connection is dead.
957
+
958
+ attr_reader :retry
959
+
960
+ ##
961
+ # A text status string describing the state of the server.
962
+
963
+ attr_reader :status
964
+
965
+ attr_reader :logger
966
+
967
+ ##
968
+ # Create a new MemCache::Server object for the memcached instance
969
+ # listening on the given host and port, weighted by the given weight.
970
+
971
+ def initialize(memcache, host, port = DEFAULT_PORT, weight = DEFAULT_WEIGHT)
972
+ raise ArgumentError, "No host specified" if host.nil? or host.empty?
973
+ raise ArgumentError, "No port specified" if port.nil? or port.to_i.zero?
974
+
975
+ @host = host
976
+ @port = port.to_i
977
+ @weight = weight.to_i
978
+
979
+ @sock = nil
980
+ @retry = nil
981
+ @status = 'NOT CONNECTED'
982
+ @timeout = memcache.timeout
983
+ @logger = memcache.logger
984
+ end
985
+
986
+ ##
987
+ # Return a string representation of the server object.
988
+
989
+ def inspect
990
+ "<MemCache::Server: %s:%d [%d] (%s)>" % [@host, @port, @weight, @status]
991
+ end
992
+
993
+ ##
994
+ # Check whether the server connection is alive. This will cause the
995
+ # socket to attempt to connect if it isn't already connected and or if
996
+ # the server was previously marked as down and the retry time has
997
+ # been exceeded.
998
+
999
+ def alive?
1000
+ !!socket
1001
+ end
1002
+
1003
+ ##
1004
+ # Try to connect to the memcached server targeted by this object.
1005
+ # Returns the connected socket object on success or nil on failure.
1006
+
1007
+ def socket
1008
+ return @sock if @sock and not @sock.closed?
1009
+
1010
+ @sock = nil
1011
+
1012
+ # If the host was dead, don't retry for a while.
1013
+ return if @retry and @retry > Time.now
1014
+
1015
+ # Attempt to connect if not already connected.
1016
+ begin
1017
+ @sock = connect_to(@host, @port, @timeout)
1018
+ @sock.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1
1019
+ @retry = nil
1020
+ @status = 'CONNECTED'
1021
+ rescue SocketError, SystemCallError, IOError => err
1022
+ logger.warn { "Unable to open socket: #{err.class.name}, #{err.message}" } if logger
1023
+ mark_dead err
1024
+ end
1025
+
1026
+ return @sock
1027
+ end
1028
+
1029
+ def connect_to(host, port, timeout=nil)
1030
+ io = MemCache::BufferedIO.new(TCPSocket.new(host, port))
1031
+ io.read_timeout = timeout
1032
+ io
1033
+ end
1034
+
1035
+ ##
1036
+ # Close the connection to the memcached server targeted by this
1037
+ # object. The server is not considered dead.
1038
+
1039
+ def close
1040
+ @sock.close if @sock && !@sock.closed?
1041
+ @sock = nil
1042
+ @retry = nil
1043
+ @status = "NOT CONNECTED"
1044
+ end
1045
+
1046
+ ##
1047
+ # Mark the server as dead and close its socket.
1048
+
1049
+ def mark_dead(error)
1050
+ @sock.close if @sock && !@sock.closed?
1051
+ @sock = nil
1052
+ @retry = Time.now + RETRY_DELAY
1053
+
1054
+ reason = "#{error.class.name}: #{error.message}"
1055
+ @status = sprintf "%s:%s DEAD (%s), will retry at %s", @host, @port, reason, @retry
1056
+ @logger.info { @status } if @logger
1057
+ end
1058
+
1059
+ end
1060
+
1061
+ ##
1062
+ # Base MemCache exception class.
1063
+
1064
+ class MemCacheError < RuntimeError; end
1065
+
1066
+ class BufferedIO < Net::BufferedIO # :nodoc:
1067
+ BUFSIZE = 1024 * 16
1068
+
1069
+ if RUBY_VERSION < '1.9.1'
1070
+ def rbuf_fill
1071
+ begin
1072
+ @rbuf << @io.read_nonblock(BUFSIZE)
1073
+ rescue Errno::EWOULDBLOCK
1074
+ retry unless @read_timeout
1075
+ if IO.select([@io], nil, nil, @read_timeout)
1076
+ retry
1077
+ else
1078
+ raise Timeout::Error, 'IO timeout'
1079
+ end
1080
+ end
1081
+ end
1082
+ end
1083
+
1084
+ def setsockopt(*args)
1085
+ @io.setsockopt(*args)
1086
+ end
1087
+
1088
+ def gets
1089
+ readuntil("\n")
1090
+ end
1091
+ end
1092
+
1093
+ end
1094
+
1095
+ module Continuum
1096
+ POINTS_PER_SERVER = 160 # this is the default in libmemcached
1097
+
1098
+ # Find the closest index in Continuum with value <= the given value
1099
+ def self.binary_search(ary, value, &block)
1100
+ upper = ary.size - 1
1101
+ lower = 0
1102
+ idx = 0
1103
+
1104
+ while(lower <= upper) do
1105
+ idx = (lower + upper) / 2
1106
+ comp = ary[idx].value <=> value
1107
+
1108
+ if comp == 0
1109
+ return idx
1110
+ elsif comp > 0
1111
+ upper = idx - 1
1112
+ else
1113
+ lower = idx + 1
1114
+ end
1115
+ end
1116
+ return upper
1117
+ end
1118
+
1119
+ class Entry
1120
+ attr_reader :value
1121
+ attr_reader :server
1122
+
1123
+ def initialize(val, srv)
1124
+ @value = val
1125
+ @server = srv
1126
+ end
1127
+
1128
+ def inspect
1129
+ "<#{value}, #{server.host}:#{server.port}>"
1130
+ end
1131
+ end
1132
+
1133
+ end