csd 0.0.15 → 0.0.16

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 (256) hide show
  1. data/.gitignore +1 -0
  2. data/COPYING +367 -0
  3. data/Rakefile +10 -10
  4. data/VERSION +1 -1
  5. data/bin/ai +19 -0
  6. data/csd.gemspec +257 -35
  7. data/lib/active_support.rb +75 -0
  8. data/lib/active_support/all.rb +3 -0
  9. data/lib/active_support/backtrace_cleaner.rb +94 -0
  10. data/lib/active_support/base64.rb +42 -0
  11. data/lib/active_support/basic_object.rb +21 -0
  12. data/lib/active_support/benchmarkable.rb +60 -0
  13. data/lib/active_support/buffered_logger.rb +132 -0
  14. data/lib/active_support/builder.rb +6 -0
  15. data/lib/active_support/cache.rb +626 -0
  16. data/lib/active_support/cache/compressed_mem_cache_store.rb +13 -0
  17. data/lib/active_support/cache/file_store.rb +188 -0
  18. data/lib/active_support/cache/mem_cache_store.rb +191 -0
  19. data/lib/active_support/cache/memory_store.rb +159 -0
  20. data/lib/active_support/cache/strategy/local_cache.rb +164 -0
  21. data/lib/active_support/cache/synchronized_memory_store.rb +11 -0
  22. data/lib/active_support/callbacks.rb +600 -0
  23. data/lib/active_support/concern.rb +29 -0
  24. data/lib/active_support/configurable.rb +36 -0
  25. data/lib/active_support/core_ext.rb +3 -0
  26. data/lib/active_support/core_ext/array.rb +7 -0
  27. data/lib/active_support/core_ext/array/access.rb +46 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +164 -0
  29. data/lib/active_support/core_ext/array/extract_options.rb +29 -0
  30. data/lib/active_support/core_ext/array/grouping.rb +100 -0
  31. data/lib/active_support/core_ext/array/random_access.rb +20 -0
  32. data/lib/active_support/core_ext/array/uniq_by.rb +17 -0
  33. data/lib/active_support/core_ext/array/wrap.rb +22 -0
  34. data/lib/active_support/core_ext/benchmark.rb +7 -0
  35. data/lib/active_support/core_ext/big_decimal.rb +1 -0
  36. data/lib/active_support/core_ext/big_decimal/conversions.rb +27 -0
  37. data/lib/active_support/core_ext/cgi.rb +1 -0
  38. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +19 -0
  39. data/lib/active_support/core_ext/class.rb +4 -0
  40. data/lib/active_support/core_ext/class/attribute.rb +67 -0
  41. data/lib/active_support/core_ext/class/attribute_accessors.rb +63 -0
  42. data/lib/active_support/core_ext/class/delegating_attributes.rb +44 -0
  43. data/lib/active_support/core_ext/class/inheritable_attributes.rb +232 -0
  44. data/lib/active_support/core_ext/class/subclasses.rb +55 -0
  45. data/lib/active_support/core_ext/date/acts_like.rb +8 -0
  46. data/lib/active_support/core_ext/date/calculations.rb +240 -0
  47. data/lib/active_support/core_ext/date/conversions.rb +99 -0
  48. data/lib/active_support/core_ext/date/freeze.rb +31 -0
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +13 -0
  50. data/lib/active_support/core_ext/date_time/calculations.rb +113 -0
  51. data/lib/active_support/core_ext/date_time/conversions.rb +102 -0
  52. data/lib/active_support/core_ext/date_time/zones.rb +17 -0
  53. data/lib/active_support/core_ext/enumerable.rb +119 -0
  54. data/lib/active_support/core_ext/exception.rb +3 -0
  55. data/lib/active_support/core_ext/file.rb +2 -0
  56. data/lib/active_support/core_ext/file/atomic.rb +41 -0
  57. data/lib/active_support/core_ext/file/path.rb +5 -0
  58. data/lib/active_support/core_ext/float.rb +1 -0
  59. data/lib/active_support/core_ext/float/rounding.rb +19 -0
  60. data/lib/active_support/core_ext/hash.rb +8 -0
  61. data/lib/active_support/core_ext/hash/conversions.rb +150 -0
  62. data/lib/active_support/core_ext/hash/deep_merge.rb +16 -0
  63. data/lib/active_support/core_ext/hash/diff.rb +13 -0
  64. data/lib/active_support/core_ext/hash/except.rb +24 -0
  65. data/lib/active_support/core_ext/hash/indifferent_access.rb +14 -0
  66. data/lib/active_support/core_ext/hash/keys.rb +45 -0
  67. data/lib/active_support/core_ext/hash/reverse_merge.rb +28 -0
  68. data/lib/active_support/core_ext/hash/slice.rb +38 -0
  69. data/lib/active_support/core_ext/integer.rb +3 -0
  70. data/lib/active_support/core_ext/integer/inflections.rb +14 -0
  71. data/lib/active_support/core_ext/integer/multiple.rb +6 -0
  72. data/lib/active_support/core_ext/integer/time.rb +39 -0
  73. data/lib/active_support/core_ext/kernel.rb +5 -0
  74. data/lib/active_support/core_ext/kernel/agnostics.rb +11 -0
  75. data/lib/active_support/core_ext/kernel/debugger.rb +16 -0
  76. data/lib/active_support/core_ext/kernel/reporting.rb +62 -0
  77. data/lib/active_support/core_ext/kernel/requires.rb +26 -0
  78. data/lib/active_support/core_ext/kernel/singleton_class.rb +13 -0
  79. data/lib/active_support/core_ext/load_error.rb +23 -0
  80. data/lib/active_support/core_ext/logger.rb +146 -0
  81. data/lib/active_support/core_ext/module.rb +12 -0
  82. data/lib/active_support/core_ext/module/aliasing.rb +70 -0
  83. data/lib/active_support/core_ext/module/anonymous.rb +24 -0
  84. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +31 -0
  85. data/lib/active_support/core_ext/module/attr_internal.rb +32 -0
  86. data/lib/active_support/core_ext/module/attribute_accessors.rb +66 -0
  87. data/lib/active_support/core_ext/module/delegation.rb +146 -0
  88. data/lib/active_support/core_ext/module/deprecation.rb +9 -0
  89. data/lib/active_support/core_ext/module/introspection.rb +88 -0
  90. data/lib/active_support/core_ext/module/method_names.rb +14 -0
  91. data/lib/active_support/core_ext/module/reachable.rb +10 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +6 -0
  93. data/lib/active_support/core_ext/module/synchronization.rb +42 -0
  94. data/lib/active_support/core_ext/name_error.rb +18 -0
  95. data/lib/active_support/core_ext/numeric.rb +2 -0
  96. data/lib/active_support/core_ext/numeric/bytes.rb +44 -0
  97. data/lib/active_support/core_ext/numeric/time.rb +77 -0
  98. data/lib/active_support/core_ext/object.rb +14 -0
  99. data/lib/active_support/core_ext/object/acts_like.rb +10 -0
  100. data/lib/active_support/core_ext/object/blank.rb +76 -0
  101. data/lib/active_support/core_ext/object/conversions.rb +4 -0
  102. data/lib/active_support/core_ext/object/duplicable.rb +65 -0
  103. data/lib/active_support/core_ext/object/extending.rb +11 -0
  104. data/lib/active_support/core_ext/object/instance_variables.rb +67 -0
  105. data/lib/active_support/core_ext/object/misc.rb +2 -0
  106. data/lib/active_support/core_ext/object/returning.rb +42 -0
  107. data/lib/active_support/core_ext/object/to_param.rb +49 -0
  108. data/lib/active_support/core_ext/object/to_query.rb +27 -0
  109. data/lib/active_support/core_ext/object/try.rb +36 -0
  110. data/lib/active_support/core_ext/object/with_options.rb +26 -0
  111. data/lib/active_support/core_ext/proc.rb +14 -0
  112. data/lib/active_support/core_ext/process.rb +1 -0
  113. data/lib/active_support/core_ext/process/daemon.rb +23 -0
  114. data/lib/active_support/core_ext/range.rb +4 -0
  115. data/lib/active_support/core_ext/range/blockless_step.rb +29 -0
  116. data/lib/active_support/core_ext/range/conversions.rb +21 -0
  117. data/lib/active_support/core_ext/range/include_range.rb +21 -0
  118. data/lib/active_support/core_ext/range/overlaps.rb +8 -0
  119. data/lib/active_support/core_ext/regexp.rb +5 -0
  120. data/lib/active_support/core_ext/rexml.rb +46 -0
  121. data/lib/active_support/core_ext/string.rb +12 -0
  122. data/lib/active_support/core_ext/string/access.rb +99 -0
  123. data/lib/active_support/core_ext/string/behavior.rb +7 -0
  124. data/lib/active_support/core_ext/string/conversions.rb +61 -0
  125. data/lib/active_support/core_ext/string/encoding.rb +11 -0
  126. data/lib/active_support/core_ext/string/exclude.rb +6 -0
  127. data/lib/active_support/core_ext/string/filters.rb +49 -0
  128. data/lib/active_support/core_ext/string/inflections.rb +149 -0
  129. data/lib/active_support/core_ext/string/interpolation.rb +2 -0
  130. data/lib/active_support/core_ext/string/multibyte.rb +72 -0
  131. data/lib/active_support/core_ext/string/output_safety.rb +109 -0
  132. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -0
  133. data/lib/active_support/core_ext/string/xchar.rb +18 -0
  134. data/lib/active_support/core_ext/time/acts_like.rb +8 -0
  135. data/lib/active_support/core_ext/time/calculations.rb +282 -0
  136. data/lib/active_support/core_ext/time/conversions.rb +85 -0
  137. data/lib/active_support/core_ext/time/marshal.rb +56 -0
  138. data/lib/active_support/core_ext/time/publicize_conversion_methods.rb +10 -0
  139. data/lib/active_support/core_ext/time/zones.rb +78 -0
  140. data/lib/active_support/core_ext/uri.rb +22 -0
  141. data/lib/active_support/dependencies.rb +628 -0
  142. data/lib/active_support/dependencies/autoload.rb +50 -0
  143. data/lib/active_support/deprecation.rb +18 -0
  144. data/lib/active_support/deprecation/behaviors.rb +38 -0
  145. data/lib/active_support/deprecation/method_wrappers.rb +29 -0
  146. data/lib/active_support/deprecation/proxy_wrappers.rb +74 -0
  147. data/lib/active_support/deprecation/reporting.rb +56 -0
  148. data/lib/active_support/duration.rb +105 -0
  149. data/lib/active_support/gzip.rb +25 -0
  150. data/lib/active_support/hash_with_indifferent_access.rb +145 -0
  151. data/lib/active_support/i18n.rb +8 -0
  152. data/lib/active_support/inflections.rb +56 -0
  153. data/lib/active_support/inflector.rb +7 -0
  154. data/lib/active_support/inflector/inflections.rb +211 -0
  155. data/lib/active_support/inflector/methods.rb +141 -0
  156. data/lib/active_support/inflector/transliterate.rb +97 -0
  157. data/lib/active_support/json.rb +2 -0
  158. data/lib/active_support/json/backends/jsongem.rb +43 -0
  159. data/lib/active_support/json/backends/yajl.rb +40 -0
  160. data/lib/active_support/json/backends/yaml.rb +90 -0
  161. data/lib/active_support/json/decoding.rb +51 -0
  162. data/lib/active_support/json/encoding.rb +254 -0
  163. data/lib/active_support/json/variable.rb +11 -0
  164. data/lib/active_support/lazy_load_hooks.rb +27 -0
  165. data/lib/active_support/locale/en.yml +36 -0
  166. data/lib/active_support/memoizable.rb +103 -0
  167. data/lib/active_support/message_encryptor.rb +71 -0
  168. data/lib/active_support/message_verifier.rb +62 -0
  169. data/lib/active_support/multibyte.rb +44 -0
  170. data/lib/active_support/multibyte/chars.rb +480 -0
  171. data/lib/active_support/multibyte/exceptions.rb +8 -0
  172. data/lib/active_support/multibyte/unicode.rb +393 -0
  173. data/lib/active_support/multibyte/utils.rb +60 -0
  174. data/lib/active_support/notifications.rb +81 -0
  175. data/lib/active_support/notifications/fanout.rb +93 -0
  176. data/lib/active_support/notifications/instrumenter.rb +56 -0
  177. data/lib/active_support/option_merger.rb +25 -0
  178. data/lib/active_support/ordered_hash.rb +158 -0
  179. data/lib/active_support/ordered_options.rb +27 -0
  180. data/lib/active_support/railtie.rb +100 -0
  181. data/lib/active_support/rescuable.rb +114 -0
  182. data/lib/active_support/ruby/shim.rb +22 -0
  183. data/lib/active_support/secure_random.rb +199 -0
  184. data/lib/active_support/string_inquirer.rb +21 -0
  185. data/lib/active_support/test_case.rb +42 -0
  186. data/lib/active_support/testing/assertions.rb +82 -0
  187. data/lib/active_support/testing/declarative.rb +40 -0
  188. data/lib/active_support/testing/default.rb +9 -0
  189. data/lib/active_support/testing/deprecation.rb +55 -0
  190. data/lib/active_support/testing/isolation.rb +154 -0
  191. data/lib/active_support/testing/pending.rb +48 -0
  192. data/lib/active_support/testing/performance.rb +455 -0
  193. data/lib/active_support/testing/setup_and_teardown.rb +111 -0
  194. data/lib/active_support/time.rb +34 -0
  195. data/lib/active_support/time/autoload.rb +5 -0
  196. data/lib/active_support/time_with_zone.rb +341 -0
  197. data/lib/active_support/values/time_zone.rb +377 -0
  198. data/lib/active_support/values/unicode_tables.dat +0 -0
  199. data/lib/active_support/version.rb +10 -0
  200. data/lib/active_support/whiny_nil.rb +60 -0
  201. data/lib/active_support/xml_mini.rb +158 -0
  202. data/lib/active_support/xml_mini/jdom.rb +168 -0
  203. data/lib/active_support/xml_mini/libxml.rb +80 -0
  204. data/lib/active_support/xml_mini/libxmlsax.rb +85 -0
  205. data/lib/active_support/xml_mini/nokogiri.rb +78 -0
  206. data/lib/active_support/xml_mini/nokogirisax.rb +83 -0
  207. data/lib/active_support/xml_mini/rexml.rb +129 -0
  208. data/lib/csd.rb +82 -2
  209. data/lib/csd/application.rb +2 -0
  210. data/lib/csd/application/default.rb +51 -0
  211. data/lib/csd/application/default/base.rb +15 -0
  212. data/lib/csd/application/minisip.rb +25 -0
  213. data/lib/csd/application/minisip/about.yml +14 -0
  214. data/lib/csd/application/minisip/base.rb +161 -0
  215. data/lib/csd/application/minisip/error.rb +11 -0
  216. data/lib/csd/application/minisip/options/common.rb +0 -0
  217. data/lib/csd/application/minisip/options/compile.rb +59 -0
  218. data/lib/csd/{applications → application}/minisip/unix/base.rb +10 -11
  219. data/lib/csd/application/opensips/about.yml +2 -0
  220. data/lib/csd/applications.rb +55 -0
  221. data/lib/csd/commands.rb +88 -65
  222. data/lib/csd/error.rb +31 -0
  223. data/lib/csd/extensions.rb +1 -0
  224. data/lib/{extensions → csd/extensions}/core/array.rb +2 -2
  225. data/lib/csd/extensions/core/dir.rb +46 -0
  226. data/lib/{extensions → csd/extensions}/core/file.rb +2 -2
  227. data/lib/{extensions → csd/extensions}/core/object.rb +2 -2
  228. data/lib/csd/extensions/core/option_parser.rb +33 -0
  229. data/lib/{extensions → csd/extensions}/core/pathname.rb +12 -3
  230. data/lib/{extensions → csd/extensions}/core/string.rb +2 -2
  231. data/lib/{extensions → csd/extensions}/gem/platform.rb +6 -2
  232. data/lib/csd/global_open_struct.rb +18 -0
  233. data/lib/csd/options.rb +124 -95
  234. data/lib/csd/path.rb +31 -0
  235. data/lib/csd/ui.rb +1 -0
  236. data/lib/csd/ui/cli.rb +7 -0
  237. data/lib/csd/ui/ui.rb +46 -0
  238. data/lib/csd/version.rb +9 -0
  239. data/lib/term/ansicolor.rb +102 -0
  240. data/lib/term/ansicolor/.keep +0 -0
  241. data/lib/term/ansicolor/version.rb +10 -0
  242. data/test/functional/test_applications.rb +86 -0
  243. data/test/functional/test_commands.rb +42 -29
  244. data/test/functional/test_options.rb +98 -0
  245. data/test/helper.rb +14 -0
  246. data/test/unit/test_dir.rb +38 -0
  247. data/test/unit/test_pathname.rb +32 -0
  248. metadata +253 -40
  249. data/LICENSE +0 -20
  250. data/bin/csd +0 -8
  251. data/lib/csd/applications/base.rb +0 -33
  252. data/lib/csd/applications/minisip/base.rb +0 -125
  253. data/lib/csd/applications/minisip/init.rb +0 -20
  254. data/lib/csd/init.rb +0 -69
  255. data/lib/csd/path_container.rb +0 -15
  256. data/publish +0 -29
@@ -0,0 +1,75 @@
1
+ #--
2
+ # Copyright (c) 2005 David Heinemeier Hansson
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ module ActiveSupport
25
+ class << self
26
+ attr_accessor :load_all_hooks
27
+ def on_load_all(&hook) load_all_hooks << hook end
28
+ def load_all!; load_all_hooks.each { |hook| hook.call } end
29
+ end
30
+ self.load_all_hooks = []
31
+
32
+ on_load_all do
33
+ [Dependencies, Deprecation, Gzip, MessageVerifier, Multibyte, SecureRandom]
34
+ end
35
+ end
36
+
37
+ require "active_support/dependencies/autoload"
38
+
39
+ module ActiveSupport
40
+ extend ActiveSupport::Autoload
41
+
42
+ # TODO: Narrow this list down
43
+ eager_autoload do
44
+ autoload :BacktraceCleaner
45
+ autoload :Base64
46
+ autoload :BasicObject
47
+ autoload :Benchmarkable
48
+ autoload :BufferedLogger
49
+ autoload :Cache
50
+ autoload :Callbacks
51
+ autoload :Concern
52
+ autoload :Configurable
53
+ autoload :Deprecation
54
+ autoload :Gzip
55
+ autoload :Inflector
56
+ autoload :JSON
57
+ autoload :Memoizable
58
+ autoload :MessageEncryptor
59
+ autoload :MessageVerifier
60
+ autoload :Multibyte
61
+ autoload :OptionMerger
62
+ autoload :OrderedHash
63
+ autoload :OrderedOptions
64
+ autoload :Notifications
65
+ autoload :Rescuable
66
+ autoload :SecureRandom
67
+ autoload :StringInquirer
68
+ autoload :XmlMini
69
+ end
70
+
71
+ autoload :SafeBuffer, "active_support/core_ext/string/output_safety"
72
+ autoload :TestCase
73
+ end
74
+
75
+ autoload :I18n, "active_support/i18n"
@@ -0,0 +1,3 @@
1
+ require 'active_support'
2
+ require 'active_support/time'
3
+ require 'active_support/core_ext'
@@ -0,0 +1,94 @@
1
+ module ActiveSupport
2
+ # Many backtraces include too much information that's not relevant for the context. This makes it hard to find the signal
3
+ # in the backtrace and adds debugging time. With a BacktraceCleaner, you can setup filters and silencers for your particular
4
+ # context, so only the relevant lines are included.
5
+ #
6
+ # If you need to reconfigure an existing BacktraceCleaner, like the one in Rails, to show as much as possible, you can always
7
+ # call BacktraceCleaner#remove_silencers! Also, if you need to reconfigure an existing BacktraceCleaner so that it does not
8
+ # filter or modify the paths of any lines of the backtrace, you can call BacktraceCleaner#remove_filters! These two methods
9
+ # will give you a completely untouched backtrace.
10
+ #
11
+ # Example:
12
+ #
13
+ # bc = BacktraceCleaner.new
14
+ # bc.add_filter { |line| line.gsub(Rails.root, '') }
15
+ # bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
16
+ # bc.clean(exception.backtrace) # will strip the Rails.root prefix and skip any lines from mongrel or rubygems
17
+ #
18
+ # Inspired by the Quiet Backtrace gem by Thoughtbot.
19
+ class BacktraceCleaner
20
+ def initialize
21
+ @filters, @silencers = [], []
22
+ end
23
+
24
+ # Returns the backtrace after all filters and silencers has been run against it. Filters run first, then silencers.
25
+ def clean(backtrace, kind = :silent)
26
+ filtered = filter(backtrace)
27
+
28
+ case kind
29
+ when :silent
30
+ silence(filtered)
31
+ when :noise
32
+ noise(filtered)
33
+ else
34
+ filtered
35
+ end
36
+ end
37
+
38
+ # Adds a filter from the block provided. Each line in the backtrace will be mapped against this filter.
39
+ #
40
+ # Example:
41
+ #
42
+ # # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
43
+ # backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
44
+ def add_filter(&block)
45
+ @filters << block
46
+ end
47
+
48
+ # Adds a silencer from the block provided. If the silencer returns true for a given line, it'll be excluded from the
49
+ # clean backtrace.
50
+ #
51
+ # Example:
52
+ #
53
+ # # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
54
+ # backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
55
+ def add_silencer(&block)
56
+ @silencers << block
57
+ end
58
+
59
+ # Will remove all silencers, but leave in the filters. This is useful if your context of debugging suddenly expands as
60
+ # you suspect a bug in the libraries you use.
61
+ def remove_silencers!
62
+ @silencers = []
63
+ end
64
+
65
+ def remove_filters!
66
+ @filters = []
67
+ end
68
+
69
+ private
70
+ def filter(backtrace)
71
+ @filters.each do |f|
72
+ backtrace = backtrace.map { |line| f.call(line) }
73
+ end
74
+
75
+ backtrace
76
+ end
77
+
78
+ def silence(backtrace)
79
+ @silencers.each do |s|
80
+ backtrace = backtrace.reject { |line| s.call(line) }
81
+ end
82
+
83
+ backtrace
84
+ end
85
+
86
+ def noise(backtrace)
87
+ @silencers.each do |s|
88
+ backtrace = backtrace.select { |line| s.call(line) }
89
+ end
90
+
91
+ backtrace
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,42 @@
1
+ begin
2
+ require 'base64'
3
+ rescue LoadError
4
+ end
5
+
6
+ module ActiveSupport
7
+ if defined? ::Base64
8
+ Base64 = ::Base64
9
+ else
10
+ # Base64 provides utility methods for encoding and de-coding binary data
11
+ # using a base 64 representation. A base 64 representation of binary data
12
+ # consists entirely of printable US-ASCII characters. The Base64 module
13
+ # is included in Ruby 1.8, but has been removed in Ruby 1.9.
14
+ module Base64
15
+ # Encodes a string to its base 64 representation. Each 60 characters of
16
+ # output is separated by a newline character.
17
+ #
18
+ # ActiveSupport::Base64.encode64("Original unencoded string")
19
+ # # => "T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw==\n"
20
+ def self.encode64(data)
21
+ [data].pack("m")
22
+ end
23
+
24
+ # Decodes a base 64 encoded string to its original representation.
25
+ #
26
+ # ActiveSupport::Base64.decode64("T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw==")
27
+ # # => "Original unencoded string"
28
+ def self.decode64(data)
29
+ data.unpack("m").first
30
+ end
31
+ end
32
+ end
33
+
34
+ # Encodes the value as base64 without the newline breaks. This makes the base64 encoding readily usable as URL parameters
35
+ # or memcache keys without further processing.
36
+ #
37
+ # ActiveSupport::Base64.encode64s("Original unencoded string")
38
+ # # => "T3JpZ2luYWwgdW5lbmNvZGVkIHN0cmluZw=="
39
+ def Base64.encode64s(value)
40
+ encode64(value).gsub(/\n/, '')
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveSupport
2
+ if defined? ::BasicObject
3
+ # A class with no predefined methods that behaves similarly to Builder's
4
+ # BlankSlate. Used for proxy classes.
5
+ class BasicObject < ::BasicObject
6
+ undef_method :==
7
+ undef_method :equal?
8
+
9
+ # Let ActiveSupport::BasicObject at least raise exceptions.
10
+ def raise(*args)
11
+ ::Object.send(:raise, *args)
12
+ end
13
+ end
14
+ else
15
+ class BasicObject #:nodoc:
16
+ instance_methods.each do |m|
17
+ undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,60 @@
1
+ require 'active_support/core_ext/benchmark'
2
+ require 'active_support/core_ext/hash/keys'
3
+
4
+ module ActiveSupport
5
+ module Benchmarkable
6
+ # Allows you to measure the execution time of a block
7
+ # in a template and records the result to the log. Wrap this block around
8
+ # expensive operations or possible bottlenecks to get a time reading
9
+ # for the operation. For example, let's say you thought your file
10
+ # processing method was taking too long; you could wrap it in a benchmark block.
11
+ #
12
+ # <% benchmark "Process data files" do %>
13
+ # <%= expensive_files_operation %>
14
+ # <% end %>
15
+ #
16
+ # That would add something like "Process data files (345.2ms)" to the log,
17
+ # which you can then use to compare timings when optimizing your code.
18
+ #
19
+ # You may give an optional logger level as the :level option.
20
+ # (:debug, :info, :warn, :error); the default value is :info.
21
+ #
22
+ # <% benchmark "Low-level files", :level => :debug do %>
23
+ # <%= lowlevel_files_operation %>
24
+ # <% end %>
25
+ #
26
+ # Finally, you can pass true as the third argument to silence all log activity
27
+ # inside the block. This is great for boiling down a noisy block to just a single statement:
28
+ #
29
+ # <% benchmark "Process data files", :level => :info, :silence => true do %>
30
+ # <%= expensive_and_chatty_files_operation %>
31
+ # <% end %>
32
+ def benchmark(message = "Benchmarking", options = {})
33
+ if logger
34
+ if options.is_a?(Symbol)
35
+ ActiveSupport::Deprecation.warn("use benchmark('#{message}', :level => :#{options}) instead", caller)
36
+ options = { :level => options, :silence => false }
37
+ else
38
+ options.assert_valid_keys(:level, :silence)
39
+ options[:level] ||= :info
40
+ end
41
+
42
+ result = nil
43
+ ms = Benchmark.ms { result = options[:silence] ? logger.silence { yield } : yield }
44
+ logger.send(options[:level], '%s (%.1fms)' % [ message, ms ])
45
+ result
46
+ else
47
+ yield
48
+ end
49
+ end
50
+
51
+ # Silence the logger during the execution of the block.
52
+ #
53
+ def silence
54
+ old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger
55
+ yield
56
+ ensure
57
+ logger.level = old_logger_level if logger
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,132 @@
1
+ require 'active_support/core_ext/class/attribute_accessors'
2
+
3
+ module ActiveSupport
4
+ # Inspired by the buffered logger idea by Ezra
5
+ class BufferedLogger
6
+ module Severity
7
+ DEBUG = 0
8
+ INFO = 1
9
+ WARN = 2
10
+ ERROR = 3
11
+ FATAL = 4
12
+ UNKNOWN = 5
13
+ end
14
+ include Severity
15
+
16
+ MAX_BUFFER_SIZE = 1000
17
+
18
+ ##
19
+ # :singleton-method:
20
+ # Set to false to disable the silencer
21
+ cattr_accessor :silencer
22
+ self.silencer = true
23
+
24
+ # Silences the logger for the duration of the block.
25
+ def silence(temporary_level = ERROR)
26
+ if silencer
27
+ begin
28
+ old_logger_level, self.level = level, temporary_level
29
+ yield self
30
+ ensure
31
+ self.level = old_logger_level
32
+ end
33
+ else
34
+ yield self
35
+ end
36
+ end
37
+
38
+ attr_accessor :level
39
+ attr_reader :auto_flushing
40
+
41
+ def initialize(log, level = DEBUG)
42
+ @level = level
43
+ @buffer = {}
44
+ @auto_flushing = 1
45
+ @guard = Mutex.new
46
+
47
+ if log.respond_to?(:write)
48
+ @log = log
49
+ elsif File.exist?(log)
50
+ @log = open(log, (File::WRONLY | File::APPEND))
51
+ @log.sync = true
52
+ else
53
+ FileUtils.mkdir_p(File.dirname(log))
54
+ @log = open(log, (File::WRONLY | File::APPEND | File::CREAT))
55
+ @log.sync = true
56
+ end
57
+ end
58
+
59
+ def add(severity, message = nil, progname = nil, &block)
60
+ return if @level > severity
61
+ message = (message || (block && block.call) || progname).to_s
62
+ # If a newline is necessary then create a new message ending with a newline.
63
+ # Ensures that the original message is not mutated.
64
+ message = "#{message}\n" unless message[-1] == ?\n
65
+ buffer << message
66
+ auto_flush
67
+ message
68
+ end
69
+
70
+ # Dynamically add methods such as:
71
+ # def info
72
+ # def warn
73
+ # def debug
74
+ for severity in Severity.constants
75
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
76
+ def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
77
+ add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
78
+ end # end
79
+
80
+ def #{severity.downcase}? # def debug?
81
+ #{severity} >= @level # DEBUG >= @level
82
+ end # end
83
+ EOT
84
+ end
85
+
86
+ # Set the auto-flush period. Set to true to flush after every log message,
87
+ # to an integer to flush every N messages, or to false, nil, or zero to
88
+ # never auto-flush. If you turn auto-flushing off, be sure to regularly
89
+ # flush the log yourself -- it will eat up memory until you do.
90
+ def auto_flushing=(period)
91
+ @auto_flushing =
92
+ case period
93
+ when true; 1
94
+ when false, nil, 0; MAX_BUFFER_SIZE
95
+ when Integer; period
96
+ else raise ArgumentError, "Unrecognized auto_flushing period: #{period.inspect}"
97
+ end
98
+ end
99
+
100
+ def flush
101
+ @guard.synchronize do
102
+ unless buffer.empty?
103
+ old_buffer = buffer
104
+ @log.write(old_buffer.join)
105
+ end
106
+
107
+ # Important to do this even if buffer was empty or else @buffer will
108
+ # accumulate empty arrays for each request where nothing was logged.
109
+ clear_buffer
110
+ end
111
+ end
112
+
113
+ def close
114
+ flush
115
+ @log.close if @log.respond_to?(:close)
116
+ @log = nil
117
+ end
118
+
119
+ protected
120
+ def auto_flush
121
+ flush if buffer.size >= @auto_flushing
122
+ end
123
+
124
+ def buffer
125
+ @buffer[Thread.current] ||= []
126
+ end
127
+
128
+ def clear_buffer
129
+ @buffer.delete(Thread.current)
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,6 @@
1
+ begin
2
+ require 'builder'
3
+ rescue LoadError => e
4
+ $stderr.puts "You don't have builder installed in your application. Please add it to your Gemfile and run bundle install"
5
+ raise e
6
+ end
@@ -0,0 +1,626 @@
1
+ require 'benchmark'
2
+ require 'zlib'
3
+ require 'active_support/core_ext/array/extract_options'
4
+ require 'active_support/core_ext/array/wrap'
5
+ require 'active_support/core_ext/benchmark'
6
+ require 'active_support/core_ext/exception'
7
+ require 'active_support/core_ext/class/attribute_accessors'
8
+ require 'active_support/core_ext/numeric/bytes'
9
+ require 'active_support/core_ext/numeric/time'
10
+ require 'active_support/core_ext/object/to_param'
11
+ require 'active_support/core_ext/string/inflections'
12
+
13
+ module ActiveSupport
14
+ # See ActiveSupport::Cache::Store for documentation.
15
+ module Cache
16
+ autoload :FileStore, 'active_support/cache/file_store'
17
+ autoload :MemoryStore, 'active_support/cache/memory_store'
18
+ autoload :MemCacheStore, 'active_support/cache/mem_cache_store'
19
+ autoload :SynchronizedMemoryStore, 'active_support/cache/synchronized_memory_store'
20
+ autoload :CompressedMemCacheStore, 'active_support/cache/compressed_mem_cache_store'
21
+
22
+ EMPTY_OPTIONS = {}.freeze
23
+
24
+ # These options mean something to all cache implementations. Individual cache
25
+ # implementations may support additional optons.
26
+ UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl]
27
+
28
+ module Strategy
29
+ autoload :LocalCache, 'active_support/cache/strategy/local_cache'
30
+ end
31
+
32
+ # Creates a new CacheStore object according to the given options.
33
+ #
34
+ # If no arguments are passed to this method, then a new
35
+ # ActiveSupport::Cache::MemoryStore object will be returned.
36
+ #
37
+ # If you pass a Symbol as the first argument, then a corresponding cache
38
+ # store class under the ActiveSupport::Cache namespace will be created.
39
+ # For example:
40
+ #
41
+ # ActiveSupport::Cache.lookup_store(:memory_store)
42
+ # # => returns a new ActiveSupport::Cache::MemoryStore object
43
+ #
44
+ # ActiveSupport::Cache.lookup_store(:mem_cache_store)
45
+ # # => returns a new ActiveSupport::Cache::MemCacheStore object
46
+ #
47
+ # Any additional arguments will be passed to the corresponding cache store
48
+ # class's constructor:
49
+ #
50
+ # ActiveSupport::Cache.lookup_store(:file_store, "/tmp/cache")
51
+ # # => same as: ActiveSupport::Cache::FileStore.new("/tmp/cache")
52
+ #
53
+ # If the first argument is not a Symbol, then it will simply be returned:
54
+ #
55
+ # ActiveSupport::Cache.lookup_store(MyOwnCacheStore.new)
56
+ # # => returns MyOwnCacheStore.new
57
+ def self.lookup_store(*store_option)
58
+ store, *parameters = *Array.wrap(store_option).flatten
59
+
60
+ case store
61
+ when Symbol
62
+ store_class_name = store.to_s.camelize
63
+ store_class = ActiveSupport::Cache.const_get(store_class_name)
64
+ store_class.new(*parameters)
65
+ when nil
66
+ ActiveSupport::Cache::MemoryStore.new
67
+ else
68
+ store
69
+ end
70
+ end
71
+
72
+ def self.expand_cache_key(key, namespace = nil)
73
+ expanded_cache_key = namespace ? "#{namespace}/" : ""
74
+
75
+ prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
76
+ if prefix
77
+ expanded_cache_key << "#{prefix}/"
78
+ end
79
+
80
+ expanded_cache_key <<
81
+ if key.respond_to?(:cache_key)
82
+ key.cache_key
83
+ elsif key.is_a?(Array)
84
+ if key.size > 1
85
+ key.collect { |element| expand_cache_key(element) }.to_param
86
+ else
87
+ key.first.to_param
88
+ end
89
+ elsif key
90
+ key.to_param
91
+ end.to_s
92
+
93
+ expanded_cache_key
94
+ end
95
+
96
+ # An abstract cache store class. There are multiple cache store
97
+ # implementations, each having its own additional features. See the classes
98
+ # under the ActiveSupport::Cache module, e.g.
99
+ # ActiveSupport::Cache::MemCacheStore. MemCacheStore is currently the most
100
+ # popular cache store for large production websites.
101
+ #
102
+ # Some implementations may not support all methods beyond the basic cache
103
+ # methods of +fetch+, +write+, +read+, +exist?+, and +delete+.
104
+ #
105
+ # ActiveSupport::Cache::Store can store any serializable Ruby object.
106
+ #
107
+ # cache = ActiveSupport::Cache::MemoryStore.new
108
+ #
109
+ # cache.read("city") # => nil
110
+ # cache.write("city", "Duckburgh")
111
+ # cache.read("city") # => "Duckburgh"
112
+ #
113
+ # Keys are always translated into Strings and are case sensitive. When an
114
+ # object is specified as a key, its +cache_key+ method will be called if it
115
+ # is defined. Otherwise, the +to_param+ method will be called. Hashes and
116
+ # Arrays can be used as keys. The elements will be delimited by slashes
117
+ # and Hashes elements will be sorted by key so they are consistent.
118
+ #
119
+ # cache.read("city") == cache.read(:city) # => true
120
+ #
121
+ # Nil values can be cached.
122
+ #
123
+ # If your cache is on a shared infrastructure, you can define a namespace for
124
+ # your cache entries. If a namespace is defined, it will be prefixed on to every
125
+ # key. The namespace can be either a static value or a Proc. If it is a Proc, it
126
+ # will be invoked when each key is evaluated so that you can use application logic
127
+ # to invalidate keys.
128
+ #
129
+ # cache.namespace = lambda { @last_mod_time } # Set the namespace to a variable
130
+ # @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
131
+ #
132
+ # All caches support auto expiring content after a specified number of seconds.
133
+ # To set the cache entry time to live, you can either specify +:expires_in+ as
134
+ # an option to the constructor to have it affect all entries or to the +fetch+
135
+ # or +write+ methods for just one entry.
136
+ #
137
+ # cache = ActiveSupport::Cache::MemoryStore.new(:expire_in => 5.minutes)
138
+ # cache.write(key, value, :expire_in => 1.minute) # Set a lower value for one entry
139
+ #
140
+ # Caches can also store values in a compressed format to save space and reduce
141
+ # time spent sending data. Since there is some overhead, values must be large
142
+ # enough to warrant compression. To turn on compression either pass
143
+ # <tt>:compress => true</tt> in the initializer or to +fetch+ or +write+.
144
+ # To specify the threshold at which to compress values, set
145
+ # <tt>:compress_threshold</tt>. The default threshold is 32K.
146
+ class Store
147
+
148
+ cattr_accessor :logger, :instance_writer => true
149
+
150
+ attr_reader :silence
151
+ alias :silence? :silence
152
+
153
+ # Create a new cache. The options will be passed to any write method calls except
154
+ # for :namespace which can be used to set the global namespace for the cache.
155
+ def initialize (options = nil)
156
+ @options = options ? options.dup : {}
157
+ end
158
+
159
+ # Get the default options set when the cache was created.
160
+ def options
161
+ @options ||= {}
162
+ end
163
+
164
+ # Silence the logger.
165
+ def silence!
166
+ @silence = true
167
+ self
168
+ end
169
+
170
+ # Silence the logger within a block.
171
+ def mute
172
+ previous_silence, @silence = defined?(@silence) && @silence, true
173
+ yield
174
+ ensure
175
+ @silence = previous_silence
176
+ end
177
+
178
+ # Set to true if cache stores should be instrumented. By default is false.
179
+ def self.instrument=(boolean)
180
+ Thread.current[:instrument_cache_store] = boolean
181
+ end
182
+
183
+ def self.instrument
184
+ Thread.current[:instrument_cache_store] || false
185
+ end
186
+
187
+ # Fetches data from the cache, using the given key. If there is data in
188
+ # the cache with the given key, then that data is returned.
189
+ #
190
+ # If there is no such data in the cache (a cache miss occurred), then
191
+ # then nil will be returned. However, if a block has been passed, then
192
+ # that block will be run in the event of a cache miss. The return value
193
+ # of the block will be written to the cache under the given cache key,
194
+ # and that return value will be returned.
195
+ #
196
+ # cache.write("today", "Monday")
197
+ # cache.fetch("today") # => "Monday"
198
+ #
199
+ # cache.fetch("city") # => nil
200
+ # cache.fetch("city") do
201
+ # "Duckburgh"
202
+ # end
203
+ # cache.fetch("city") # => "Duckburgh"
204
+ #
205
+ # You may also specify additional options via the +options+ argument.
206
+ # Setting <tt>:force => true</tt> will force a cache miss:
207
+ #
208
+ # cache.write("today", "Monday")
209
+ # cache.fetch("today", :force => true) # => nil
210
+ #
211
+ # Setting <tt>:compress</tt> will store a large cache entry set by the call
212
+ # in a compressed format.
213
+ #
214
+ # Setting <tt>:expires_in</tt> will set an expiration time on the cache
215
+ # entry if it is set by call.
216
+ #
217
+ # Setting <tt>:race_condition_ttl</tt> will invoke logic on entries set with
218
+ # an <tt>:expires_in</tt> option. If an entry is found in the cache that is
219
+ # expired and it has been expired for less than the number of seconds specified
220
+ # by this option and a block was passed to the method call, then the expiration
221
+ # future time of the entry in the cache will be updated to that many seconds
222
+ # in the and the block will be evaluated and written to the cache.
223
+ #
224
+ # This is very useful in situations where a cache entry is used very frequently
225
+ # under heavy load. The first process to find an expired cache entry will then
226
+ # become responsible for regenerating that entry while other processes continue
227
+ # to use the slightly out of date entry. This can prevent race conditions where
228
+ # too many processes are trying to regenerate the entry all at once. If the
229
+ # process regenerating the entry errors out, the entry will be regenerated
230
+ # after the specified number of seconds.
231
+ #
232
+ # # Set all values to expire after one minute.
233
+ # cache = ActiveSupport::Cache::MemoryCache.new(:expires_in => 1.minute)
234
+ #
235
+ # cache.write("foo", "original value")
236
+ # val_1 = nil
237
+ # val_2 = nil
238
+ # sleep 60
239
+ #
240
+ # Thread.new do
241
+ # val_1 = cache.fetch("foo", :race_condition_ttl => 10) do
242
+ # sleep 1
243
+ # "new value 1"
244
+ # end
245
+ # end
246
+ #
247
+ # Thread.new do
248
+ # val_2 = cache.fetch("foo", :race_condition_ttl => 10) do
249
+ # "new value 2"
250
+ # end
251
+ # end
252
+ #
253
+ # # val_1 => "new value 1"
254
+ # # val_2 => "original value"
255
+ # # cache.fetch("foo") => "new value 1"
256
+ #
257
+ # Other options will be handled by the specific cache store implementation.
258
+ # Internally, #fetch calls #read_entry, and calls #write_entry on a cache miss.
259
+ # +options+ will be passed to the #read and #write calls.
260
+ #
261
+ # For example, MemCacheStore's #write method supports the +:raw+
262
+ # option, which tells the memcached server to store all values as strings.
263
+ # We can use this option with #fetch too:
264
+ #
265
+ # cache = ActiveSupport::Cache::MemCacheStore.new
266
+ # cache.fetch("foo", :force => true, :raw => true) do
267
+ # :bar
268
+ # end
269
+ # cache.fetch("foo") # => "bar"
270
+ def fetch(name, options = nil, &block)
271
+ options = merged_options(options)
272
+ key = namespaced_key(name, options)
273
+ entry = instrument(:read, name, options) { read_entry(key, options) } unless options[:force]
274
+ if entry && entry.expired?
275
+ race_ttl = options[:race_condition_ttl].to_f
276
+ if race_ttl and Time.now.to_f - entry.expires_at <= race_ttl
277
+ entry.expires_at = Time.now + race_ttl
278
+ write_entry(key, entry, :expires_in => race_ttl * 2)
279
+ else
280
+ delete_entry(key, options)
281
+ end
282
+ entry = nil
283
+ end
284
+
285
+ if entry
286
+ entry.value
287
+ elsif block_given?
288
+ result = instrument(:generate, name, options, &block)
289
+ write(name, result, options)
290
+ result
291
+ end
292
+ end
293
+
294
+ # Fetches data from the cache, using the given key. If there is data in
295
+ # the cache with the given key, then that data is returned. Otherwise,
296
+ # nil is returned.
297
+ #
298
+ # Options are passed to the underlying cache implementation.
299
+ def read(name, options = nil)
300
+ options = merged_options(options)
301
+ key = namespaced_key(name, options)
302
+ instrument(:read, name, options) do
303
+ entry = read_entry(key, options)
304
+ if entry
305
+ if entry.expired?
306
+ delete_entry(key, options)
307
+ nil
308
+ else
309
+ entry.value
310
+ end
311
+ else
312
+ nil
313
+ end
314
+ end
315
+ end
316
+
317
+ # Read multiple values at once from the cache. Options can be passed
318
+ # in the last argument.
319
+ #
320
+ # Some cache implementation may optimize this method.
321
+ #
322
+ # Returns a hash mapping the names provided to the values found.
323
+ def read_multi(*names)
324
+ options = names.extract_options!
325
+ options = merged_options(options)
326
+ results = {}
327
+ names.each do |name|
328
+ key = namespaced_key(name, options)
329
+ entry = read_entry(key, options)
330
+ if entry
331
+ if entry.expired?
332
+ delete_entry(key)
333
+ else
334
+ results[name] = entry.value
335
+ end
336
+ end
337
+ end
338
+ results
339
+ end
340
+
341
+ # Writes the given value to the cache, with the given key.
342
+ #
343
+ # You may also specify additional options via the +options+ argument.
344
+ # The specific cache store implementation will decide what to do with
345
+ # +options+.
346
+ def write(name, value, options = nil)
347
+ options = merged_options(options)
348
+ instrument(:write, name, options) do
349
+ entry = Entry.new(value, options)
350
+ write_entry(namespaced_key(name, options), entry, options)
351
+ end
352
+ end
353
+
354
+ # Delete an entry in the cache. Returns +true+ if there was an entry to delete.
355
+ #
356
+ # Options are passed to the underlying cache implementation.
357
+ def delete(name, options = nil)
358
+ options = merged_options(options)
359
+ instrument(:delete, name) do
360
+ delete_entry(namespaced_key(name, options), options)
361
+ end
362
+ end
363
+
364
+ # Return true if the cache contains an entry with this name.
365
+ #
366
+ # Options are passed to the underlying cache implementation.
367
+ def exist?(name, options = nil)
368
+ options = merged_options(options)
369
+ instrument(:exist?, name) do
370
+ entry = read_entry(namespaced_key(name, options), options)
371
+ if entry && !entry.expired?
372
+ true
373
+ else
374
+ false
375
+ end
376
+ end
377
+ end
378
+
379
+ # Delete all entries whose keys match a pattern.
380
+ #
381
+ # Options are passed to the underlying cache implementation.
382
+ #
383
+ # Not all implementations may support +delete_matched+.
384
+ def delete_matched(matcher, options = nil)
385
+ raise NotImplementedError.new("#{self.class.name} does not support delete_matched")
386
+ end
387
+
388
+ # Increment an integer value in the cache.
389
+ #
390
+ # Options are passed to the underlying cache implementation.
391
+ #
392
+ # Not all implementations may support +delete_matched+.
393
+ def increment(name, amount = 1, options = nil)
394
+ raise NotImplementedError.new("#{self.class.name} does not support increment")
395
+ end
396
+
397
+ # Increment an integer value in the cache.
398
+ #
399
+ # Options are passed to the underlying cache implementation.
400
+ #
401
+ # Not all implementations may support +delete_matched+.
402
+ def decrement(name, amount = 1, options = nil)
403
+ raise NotImplementedError.new("#{self.class.name} does not support decrement")
404
+ end
405
+
406
+ # Cleanup the cache by removing expired entries. Not all cache implementations may
407
+ # support this method.
408
+ #
409
+ # Options are passed to the underlying cache implementation.
410
+ #
411
+ # Not all implementations may support +delete_matched+.
412
+ def cleanup(options = nil)
413
+ raise NotImplementedError.new("#{self.class.name} does not support cleanup")
414
+ end
415
+
416
+ # Clear the entire cache. Not all cache implementations may support this method.
417
+ # You should be careful with this method since it could affect other processes
418
+ # if you are using a shared cache.
419
+ #
420
+ # Options are passed to the underlying cache implementation.
421
+ #
422
+ # Not all implementations may support +delete_matched+.
423
+ def clear(options = nil)
424
+ raise NotImplementedError.new("#{self.class.name} does not support clear")
425
+ end
426
+
427
+ protected
428
+ # Add the namespace defined in the options to a pattern designed to match keys.
429
+ # Implementations that support delete_matched should call this method to translate
430
+ # a pattern that matches names into one that matches namespaced keys.
431
+ def key_matcher(pattern, options)
432
+ prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace]
433
+ if prefix
434
+ source = pattern.source
435
+ if source.start_with?('^')
436
+ source = source[1, source.length]
437
+ else
438
+ source = ".*#{source[0, source.length]}"
439
+ end
440
+ Regexp.new("^#{Regexp.escape(prefix)}:#{source}", pattern.options)
441
+ else
442
+ pattern
443
+ end
444
+ end
445
+
446
+ # Read an entry from the cache implementation. Subclasses must implement this method.
447
+ def read_entry(key, options) # :nodoc:
448
+ raise NotImplementedError.new
449
+ end
450
+
451
+ # Write an entry to the cache implementation. Subclasses must implement this method.
452
+ def write_entry(key, entry, options) # :nodoc:
453
+ raise NotImplementedError.new
454
+ end
455
+
456
+ # Delete an entry from the cache implementation. Subclasses must implement this method.
457
+ def delete_entry(key, options) # :nodoc:
458
+ raise NotImplementedError.new
459
+ end
460
+
461
+ private
462
+ # Merge the default options with ones specific to a method call.
463
+ def merged_options(call_options) # :nodoc:
464
+ if call_options
465
+ options.merge(call_options)
466
+ else
467
+ options.dup
468
+ end
469
+ end
470
+
471
+ # Expand a key to be a consistent string value. If the object responds to +cache_key+,
472
+ # it will be called. Otherwise, the to_param method will be called. If the key is a
473
+ # Hash, the keys will be sorted alphabetically.
474
+ def expanded_key(key) # :nodoc:
475
+ if key.respond_to?(:cache_key)
476
+ key = key.cache_key.to_s
477
+ elsif key.is_a?(Array)
478
+ if key.size > 1
479
+ key.collect{|element| expanded_key(element)}.to_param
480
+ else
481
+ key.first.to_param
482
+ end
483
+ elsif key.is_a?(Hash)
484
+ key = key.to_a.sort{|a,b| a.first.to_s <=> b.first.to_s}.collect{|k,v| "#{k}=#{v}"}.to_param
485
+ else
486
+ key = key.to_param
487
+ end
488
+ end
489
+
490
+ # Prefix a key with the namespace. The two values will be delimited with a colon.
491
+ def namespaced_key(key, options)
492
+ key = expanded_key(key)
493
+ namespace = options[:namespace] if options
494
+ prefix = namespace.is_a?(Proc) ? namespace.call : namespace
495
+ key = "#{prefix}:#{key}" if prefix
496
+ key
497
+ end
498
+
499
+ def instrument(operation, key, options = nil)
500
+ log(operation, key, options)
501
+
502
+ if self.class.instrument
503
+ payload = { :key => key }
504
+ payload.merge!(options) if options.is_a?(Hash)
505
+ ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload){ yield }
506
+ else
507
+ yield
508
+ end
509
+ end
510
+
511
+ def log(operation, key, options = nil)
512
+ return unless logger && logger.debug? && !silence?
513
+ logger.debug("Cache #{operation}: #{key}#{options.blank? ? "" : " (#{options.inspect})"}")
514
+ end
515
+ end
516
+
517
+ # Entry that is put into caches. It supports expiration time on entries and can compress values
518
+ # to save space in the cache.
519
+ class Entry
520
+ attr_reader :created_at, :expires_in
521
+
522
+ DEFAULT_COMPRESS_LIMIT = 16.kilobytes
523
+
524
+ class << self
525
+ # Create an entry with internal attributes set. This method is intended to be
526
+ # used by implementations that store cache entries in a native format instead
527
+ # of as serialized Ruby objects.
528
+ def create (raw_value, created_at, options = {})
529
+ entry = new(nil)
530
+ entry.instance_variable_set(:@value, raw_value)
531
+ entry.instance_variable_set(:@created_at, created_at.to_f)
532
+ entry.instance_variable_set(:@compressed, !!options[:compressed])
533
+ entry.instance_variable_set(:@expires_in, options[:expires_in])
534
+ entry
535
+ end
536
+ end
537
+
538
+ # Create a new cache entry for the specified value. Options supported are
539
+ # +:compress+, +:compress_threshold+, and +:expires_in+.
540
+ def initialize(value, options = {})
541
+ @compressed = false
542
+ @expires_in = options[:expires_in]
543
+ @expires_in = @expires_in.to_f if @expires_in
544
+ @created_at = Time.now.to_f
545
+ if value
546
+ if should_compress?(value, options)
547
+ @value = Zlib::Deflate.deflate(Marshal.dump(value))
548
+ @compressed = true
549
+ else
550
+ @value = value
551
+ end
552
+ else
553
+ @value = nil
554
+ end
555
+ end
556
+
557
+ # Get the raw value. This value may be serialized and compressed.
558
+ def raw_value
559
+ @value
560
+ end
561
+
562
+ # Get the value stored in the cache.
563
+ def value
564
+ if @value
565
+ val = compressed? ? Marshal.load(Zlib::Inflate.inflate(@value)) : @value
566
+ unless val.frozen?
567
+ val.freeze rescue nil
568
+ end
569
+ val
570
+ end
571
+ end
572
+
573
+ def compressed?
574
+ @compressed
575
+ end
576
+
577
+ # Check if the entry is expired. The +expires_in+ parameter can override the
578
+ # value set when the entry was created.
579
+ def expired?
580
+ if @expires_in && @created_at + @expires_in <= Time.now.to_f
581
+ true
582
+ else
583
+ false
584
+ end
585
+ end
586
+
587
+ # Set a new time to live on the entry so it expires at the given time.
588
+ def expires_at=(time)
589
+ if time
590
+ @expires_in = time.to_f - @created_at
591
+ else
592
+ @expires_in = nil
593
+ end
594
+ end
595
+
596
+ # Seconds since the epoch when the cache entry will expire.
597
+ def expires_at
598
+ @expires_in ? @created_at + @expires_in : nil
599
+ end
600
+
601
+ # Get the size of the cached value. This could be less than value.size
602
+ # if the data is compressed.
603
+ def size
604
+ if @value.nil?
605
+ 0
606
+ elsif @value.respond_to?(:bytesize)
607
+ @value.bytesize
608
+ else
609
+ Marshal.dump(@value).bytesize
610
+ end
611
+ end
612
+
613
+ private
614
+ def should_compress?(value, options)
615
+ if options[:compress] && value
616
+ unless value.is_a?(Numeric)
617
+ compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT
618
+ serialized_value = value.is_a?(String) ? value : Marshal.dump(value)
619
+ return true if serialized_value.size >= compress_threshold
620
+ end
621
+ end
622
+ false
623
+ end
624
+ end
625
+ end
626
+ end