activesupport 5.0.7.1

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 (236) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1013 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +39 -0
  5. data/lib/active_support.rb +99 -0
  6. data/lib/active_support/all.rb +3 -0
  7. data/lib/active_support/array_inquirer.rb +44 -0
  8. data/lib/active_support/backtrace_cleaner.rb +103 -0
  9. data/lib/active_support/benchmarkable.rb +49 -0
  10. data/lib/active_support/builder.rb +6 -0
  11. data/lib/active_support/cache.rb +701 -0
  12. data/lib/active_support/cache/file_store.rb +204 -0
  13. data/lib/active_support/cache/mem_cache_store.rb +207 -0
  14. data/lib/active_support/cache/memory_store.rb +167 -0
  15. data/lib/active_support/cache/null_store.rb +41 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +172 -0
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
  18. data/lib/active_support/callbacks.rb +791 -0
  19. data/lib/active_support/concern.rb +142 -0
  20. data/lib/active_support/concurrency/latch.rb +26 -0
  21. data/lib/active_support/concurrency/share_lock.rb +226 -0
  22. data/lib/active_support/configurable.rb +148 -0
  23. data/lib/active_support/core_ext.rb +4 -0
  24. data/lib/active_support/core_ext/array.rb +7 -0
  25. data/lib/active_support/core_ext/array/access.rb +90 -0
  26. data/lib/active_support/core_ext/array/conversions.rb +211 -0
  27. data/lib/active_support/core_ext/array/extract_options.rb +29 -0
  28. data/lib/active_support/core_ext/array/grouping.rb +107 -0
  29. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  30. data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -0
  31. data/lib/active_support/core_ext/array/wrap.rb +46 -0
  32. data/lib/active_support/core_ext/benchmark.rb +14 -0
  33. data/lib/active_support/core_ext/big_decimal.rb +1 -0
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  35. data/lib/active_support/core_ext/class.rb +2 -0
  36. data/lib/active_support/core_ext/class/attribute.rb +128 -0
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -0
  38. data/lib/active_support/core_ext/class/subclasses.rb +41 -0
  39. data/lib/active_support/core_ext/date.rb +5 -0
  40. data/lib/active_support/core_ext/date/acts_like.rb +8 -0
  41. data/lib/active_support/core_ext/date/blank.rb +12 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +143 -0
  43. data/lib/active_support/core_ext/date/conversions.rb +95 -0
  44. data/lib/active_support/core_ext/date/zones.rb +6 -0
  45. data/lib/active_support/core_ext/date_and_time/calculations.rb +335 -0
  46. data/lib/active_support/core_ext/date_and_time/compatibility.rb +14 -0
  47. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  48. data/lib/active_support/core_ext/date_time.rb +5 -0
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +14 -0
  50. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +199 -0
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/conversions.rb +105 -0
  54. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  55. data/lib/active_support/core_ext/enumerable.rb +146 -0
  56. data/lib/active_support/core_ext/file.rb +1 -0
  57. data/lib/active_support/core_ext/file/atomic.rb +68 -0
  58. data/lib/active_support/core_ext/hash.rb +9 -0
  59. data/lib/active_support/core_ext/hash/compact.rb +24 -0
  60. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +38 -0
  62. data/lib/active_support/core_ext/hash/except.rb +22 -0
  63. data/lib/active_support/core_ext/hash/indifferent_access.rb +23 -0
  64. data/lib/active_support/core_ext/hash/keys.rb +170 -0
  65. data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -0
  66. data/lib/active_support/core_ext/hash/slice.rb +48 -0
  67. data/lib/active_support/core_ext/hash/transform_values.rb +29 -0
  68. data/lib/active_support/core_ext/integer.rb +3 -0
  69. data/lib/active_support/core_ext/integer/inflections.rb +29 -0
  70. data/lib/active_support/core_ext/integer/multiple.rb +10 -0
  71. data/lib/active_support/core_ext/integer/time.rb +29 -0
  72. data/lib/active_support/core_ext/kernel.rb +4 -0
  73. data/lib/active_support/core_ext/kernel/agnostics.rb +11 -0
  74. data/lib/active_support/core_ext/kernel/concern.rb +12 -0
  75. data/lib/active_support/core_ext/kernel/debugger.rb +3 -0
  76. data/lib/active_support/core_ext/kernel/reporting.rb +43 -0
  77. data/lib/active_support/core_ext/kernel/singleton_class.rb +6 -0
  78. data/lib/active_support/core_ext/load_error.rb +31 -0
  79. data/lib/active_support/core_ext/marshal.rb +22 -0
  80. data/lib/active_support/core_ext/module.rb +12 -0
  81. data/lib/active_support/core_ext/module/aliasing.rb +74 -0
  82. data/lib/active_support/core_ext/module/anonymous.rb +28 -0
  83. data/lib/active_support/core_ext/module/attr_internal.rb +36 -0
  84. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  85. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  86. data/lib/active_support/core_ext/module/concerning.rb +135 -0
  87. data/lib/active_support/core_ext/module/delegation.rb +216 -0
  88. data/lib/active_support/core_ext/module/deprecation.rb +23 -0
  89. data/lib/active_support/core_ext/module/introspection.rb +68 -0
  90. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -0
  91. data/lib/active_support/core_ext/module/qualified_const.rb +70 -0
  92. data/lib/active_support/core_ext/module/reachable.rb +8 -0
  93. data/lib/active_support/core_ext/module/remove_method.rb +35 -0
  94. data/lib/active_support/core_ext/name_error.rb +31 -0
  95. data/lib/active_support/core_ext/numeric.rb +4 -0
  96. data/lib/active_support/core_ext/numeric/bytes.rb +64 -0
  97. data/lib/active_support/core_ext/numeric/conversions.rb +144 -0
  98. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  99. data/lib/active_support/core_ext/numeric/time.rb +74 -0
  100. data/lib/active_support/core_ext/object.rb +14 -0
  101. data/lib/active_support/core_ext/object/acts_like.rb +10 -0
  102. data/lib/active_support/core_ext/object/blank.rb +143 -0
  103. data/lib/active_support/core_ext/object/conversions.rb +4 -0
  104. data/lib/active_support/core_ext/object/deep_dup.rb +53 -0
  105. data/lib/active_support/core_ext/object/duplicable.rb +124 -0
  106. data/lib/active_support/core_ext/object/inclusion.rb +27 -0
  107. data/lib/active_support/core_ext/object/instance_variables.rb +28 -0
  108. data/lib/active_support/core_ext/object/json.rb +205 -0
  109. data/lib/active_support/core_ext/object/to_param.rb +1 -0
  110. data/lib/active_support/core_ext/object/to_query.rb +84 -0
  111. data/lib/active_support/core_ext/object/try.rb +146 -0
  112. data/lib/active_support/core_ext/object/with_options.rb +69 -0
  113. data/lib/active_support/core_ext/range.rb +4 -0
  114. data/lib/active_support/core_ext/range/conversions.rb +31 -0
  115. data/lib/active_support/core_ext/range/each.rb +21 -0
  116. data/lib/active_support/core_ext/range/include_range.rb +23 -0
  117. data/lib/active_support/core_ext/range/overlaps.rb +8 -0
  118. data/lib/active_support/core_ext/regexp.rb +5 -0
  119. data/lib/active_support/core_ext/securerandom.rb +23 -0
  120. data/lib/active_support/core_ext/string.rb +13 -0
  121. data/lib/active_support/core_ext/string/access.rb +104 -0
  122. data/lib/active_support/core_ext/string/behavior.rb +6 -0
  123. data/lib/active_support/core_ext/string/conversions.rb +57 -0
  124. data/lib/active_support/core_ext/string/exclude.rb +11 -0
  125. data/lib/active_support/core_ext/string/filters.rb +102 -0
  126. data/lib/active_support/core_ext/string/indent.rb +43 -0
  127. data/lib/active_support/core_ext/string/inflections.rb +244 -0
  128. data/lib/active_support/core_ext/string/inquiry.rb +13 -0
  129. data/lib/active_support/core_ext/string/multibyte.rb +53 -0
  130. data/lib/active_support/core_ext/string/output_safety.rb +260 -0
  131. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -0
  132. data/lib/active_support/core_ext/string/strip.rb +23 -0
  133. data/lib/active_support/core_ext/string/zones.rb +14 -0
  134. data/lib/active_support/core_ext/struct.rb +3 -0
  135. data/lib/active_support/core_ext/time.rb +5 -0
  136. data/lib/active_support/core_ext/time/acts_like.rb +8 -0
  137. data/lib/active_support/core_ext/time/calculations.rb +290 -0
  138. data/lib/active_support/core_ext/time/compatibility.rb +14 -0
  139. data/lib/active_support/core_ext/time/conversions.rb +67 -0
  140. data/lib/active_support/core_ext/time/marshal.rb +3 -0
  141. data/lib/active_support/core_ext/time/zones.rb +111 -0
  142. data/lib/active_support/core_ext/uri.rb +24 -0
  143. data/lib/active_support/dependencies.rb +755 -0
  144. data/lib/active_support/dependencies/autoload.rb +77 -0
  145. data/lib/active_support/dependencies/interlock.rb +55 -0
  146. data/lib/active_support/deprecation.rb +43 -0
  147. data/lib/active_support/deprecation/behaviors.rb +90 -0
  148. data/lib/active_support/deprecation/instance_delegator.rb +37 -0
  149. data/lib/active_support/deprecation/method_wrappers.rb +70 -0
  150. data/lib/active_support/deprecation/proxy_wrappers.rb +149 -0
  151. data/lib/active_support/deprecation/reporting.rb +112 -0
  152. data/lib/active_support/descendants_tracker.rb +60 -0
  153. data/lib/active_support/duration.rb +235 -0
  154. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  155. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  156. data/lib/active_support/evented_file_update_checker.rb +199 -0
  157. data/lib/active_support/execution_wrapper.rb +126 -0
  158. data/lib/active_support/executor.rb +6 -0
  159. data/lib/active_support/file_update_checker.rb +157 -0
  160. data/lib/active_support/gem_version.rb +15 -0
  161. data/lib/active_support/gzip.rb +36 -0
  162. data/lib/active_support/hash_with_indifferent_access.rb +329 -0
  163. data/lib/active_support/i18n.rb +13 -0
  164. data/lib/active_support/i18n_railtie.rb +115 -0
  165. data/lib/active_support/inflections.rb +70 -0
  166. data/lib/active_support/inflector.rb +7 -0
  167. data/lib/active_support/inflector/inflections.rb +242 -0
  168. data/lib/active_support/inflector/methods.rb +390 -0
  169. data/lib/active_support/inflector/transliterate.rb +112 -0
  170. data/lib/active_support/json.rb +2 -0
  171. data/lib/active_support/json/decoding.rb +74 -0
  172. data/lib/active_support/json/encoding.rb +127 -0
  173. data/lib/active_support/key_generator.rb +71 -0
  174. data/lib/active_support/lazy_load_hooks.rb +76 -0
  175. data/lib/active_support/locale/en.yml +135 -0
  176. data/lib/active_support/log_subscriber.rb +109 -0
  177. data/lib/active_support/log_subscriber/test_helper.rb +104 -0
  178. data/lib/active_support/logger.rb +106 -0
  179. data/lib/active_support/logger_silence.rb +28 -0
  180. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  181. data/lib/active_support/message_encryptor.rb +114 -0
  182. data/lib/active_support/message_verifier.rb +134 -0
  183. data/lib/active_support/multibyte.rb +21 -0
  184. data/lib/active_support/multibyte/chars.rb +231 -0
  185. data/lib/active_support/multibyte/unicode.rb +413 -0
  186. data/lib/active_support/notifications.rb +212 -0
  187. data/lib/active_support/notifications/fanout.rb +157 -0
  188. data/lib/active_support/notifications/instrumenter.rb +91 -0
  189. data/lib/active_support/number_helper.rb +368 -0
  190. data/lib/active_support/number_helper/number_converter.rb +182 -0
  191. data/lib/active_support/number_helper/number_to_currency_converter.rb +44 -0
  192. data/lib/active_support/number_helper/number_to_delimited_converter.rb +28 -0
  193. data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
  194. data/lib/active_support/number_helper/number_to_human_size_converter.rb +62 -0
  195. data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
  196. data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
  197. data/lib/active_support/number_helper/number_to_rounded_converter.rb +92 -0
  198. data/lib/active_support/option_merger.rb +25 -0
  199. data/lib/active_support/ordered_hash.rb +48 -0
  200. data/lib/active_support/ordered_options.rb +81 -0
  201. data/lib/active_support/per_thread_registry.rb +58 -0
  202. data/lib/active_support/proxy_object.rb +13 -0
  203. data/lib/active_support/rails.rb +27 -0
  204. data/lib/active_support/railtie.rb +51 -0
  205. data/lib/active_support/reloader.rb +129 -0
  206. data/lib/active_support/rescuable.rb +173 -0
  207. data/lib/active_support/security_utils.rb +27 -0
  208. data/lib/active_support/string_inquirer.rb +26 -0
  209. data/lib/active_support/subscriber.rb +120 -0
  210. data/lib/active_support/tagged_logging.rb +77 -0
  211. data/lib/active_support/test_case.rb +88 -0
  212. data/lib/active_support/testing/assertions.rb +99 -0
  213. data/lib/active_support/testing/autorun.rb +5 -0
  214. data/lib/active_support/testing/constant_lookup.rb +50 -0
  215. data/lib/active_support/testing/declarative.rb +26 -0
  216. data/lib/active_support/testing/deprecation.rb +36 -0
  217. data/lib/active_support/testing/file_fixtures.rb +34 -0
  218. data/lib/active_support/testing/isolation.rb +115 -0
  219. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  220. data/lib/active_support/testing/setup_and_teardown.rb +50 -0
  221. data/lib/active_support/testing/stream.rb +42 -0
  222. data/lib/active_support/testing/tagged_logging.rb +25 -0
  223. data/lib/active_support/testing/time_helpers.rb +136 -0
  224. data/lib/active_support/time.rb +18 -0
  225. data/lib/active_support/time_with_zone.rb +511 -0
  226. data/lib/active_support/values/time_zone.rb +484 -0
  227. data/lib/active_support/values/unicode_tables.dat +0 -0
  228. data/lib/active_support/version.rb +8 -0
  229. data/lib/active_support/xml_mini.rb +209 -0
  230. data/lib/active_support/xml_mini/jdom.rb +181 -0
  231. data/lib/active_support/xml_mini/libxml.rb +77 -0
  232. data/lib/active_support/xml_mini/libxmlsax.rb +82 -0
  233. data/lib/active_support/xml_mini/nokogiri.rb +81 -0
  234. data/lib/active_support/xml_mini/nokogirisax.rb +85 -0
  235. data/lib/active_support/xml_mini/rexml.rb +128 -0
  236. metadata +350 -0
@@ -0,0 +1,146 @@
1
+ module Enumerable
2
+ # Enumerable#sum was added in Ruby 2.4 but it only works with Numeric elements
3
+ # when we omit an identity.
4
+ #
5
+ # We tried shimming it to attempt the fast native method, rescue TypeError,
6
+ # and fall back to the compatible implementation, but that's much slower than
7
+ # just calling the compat method in the first place.
8
+ if Enumerable.instance_methods(false).include?(:sum) && !((?a..?b).sum rescue false)
9
+ # We can't use Refinements here because Refinements with Module which will be prepended
10
+ # doesn't work well https://bugs.ruby-lang.org/issues/13446
11
+ alias :_original_sum_with_required_identity :sum
12
+ private :_original_sum_with_required_identity
13
+ # Calculates a sum from the elements.
14
+ #
15
+ # payments.sum { |p| p.price * p.tax_rate }
16
+ # payments.sum(&:price)
17
+ #
18
+ # The latter is a shortcut for:
19
+ #
20
+ # payments.inject(0) { |sum, p| sum + p.price }
21
+ #
22
+ # It can also calculate the sum without the use of a block.
23
+ #
24
+ # [5, 15, 10].sum # => 30
25
+ # ['foo', 'bar'].sum # => "foobar"
26
+ # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
27
+ #
28
+ # The default sum of an empty list is zero. You can override this default:
29
+ #
30
+ # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
31
+ def sum(identity = nil, &block)
32
+ if identity
33
+ _original_sum_with_required_identity(identity, &block)
34
+ elsif block_given?
35
+ map(&block).sum(identity)
36
+ else
37
+ inject(:+) || 0
38
+ end
39
+ end
40
+ else
41
+ def sum(identity = nil, &block)
42
+ if block_given?
43
+ map(&block).sum(identity)
44
+ else
45
+ sum = identity ? inject(identity, :+) : inject(:+)
46
+ sum || identity || 0
47
+ end
48
+ end
49
+ end
50
+
51
+ # Convert an enumerable to a hash.
52
+ #
53
+ # people.index_by(&:login)
54
+ # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
55
+ # people.index_by { |person| "#{person.first_name} #{person.last_name}" }
56
+ # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
57
+ def index_by
58
+ if block_given?
59
+ Hash[map { |elem| [yield(elem), elem] }]
60
+ else
61
+ to_enum(:index_by) { size if respond_to?(:size) }
62
+ end
63
+ end
64
+
65
+ # Returns +true+ if the enumerable has more than 1 element. Functionally
66
+ # equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
67
+ # much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
68
+ # if more than one person is over 26.
69
+ def many?
70
+ cnt = 0
71
+ if block_given?
72
+ any? do |element|
73
+ cnt += 1 if yield element
74
+ cnt > 1
75
+ end
76
+ else
77
+ any? { (cnt += 1) > 1 }
78
+ end
79
+ end
80
+
81
+ # The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
82
+ # collection does not include the object.
83
+ def exclude?(object)
84
+ !include?(object)
85
+ end
86
+
87
+ # Returns a copy of the enumerable without the specified elements.
88
+ #
89
+ # ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd"
90
+ # => ["David", "Rafael"]
91
+ #
92
+ # {foo: 1, bar: 2, baz: 3}.without :bar
93
+ # => {foo: 1, baz: 3}
94
+ def without(*elements)
95
+ reject { |element| elements.include?(element) }
96
+ end
97
+
98
+ # Convert an enumerable to an array based on the given key.
99
+ #
100
+ # [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
101
+ # => ["David", "Rafael", "Aaron"]
102
+ #
103
+ # [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
104
+ # => [[1, "David"], [2, "Rafael"]]
105
+ def pluck(*keys)
106
+ if keys.many?
107
+ map { |element| keys.map { |key| element[key] } }
108
+ else
109
+ map { |element| element[keys.first] }
110
+ end
111
+ end
112
+ end
113
+
114
+ class Range #:nodoc:
115
+ # Optimize range sum to use arithmetic progression if a block is not given and
116
+ # we have a range of numeric values.
117
+ def sum(identity = nil)
118
+ if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
119
+ super
120
+ else
121
+ actual_last = exclude_end? ? (last - 1) : last
122
+ if actual_last >= first
123
+ sum = identity || 0
124
+ sum + (actual_last - first + 1) * (actual_last + first) / 2
125
+ else
126
+ identity || 0
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
133
+ #
134
+ # We tried shimming it to attempt the fast native method, rescue TypeError,
135
+ # and fall back to the compatible implementation, but that's much slower than
136
+ # just calling the compat method in the first place.
137
+ if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
138
+ class Array
139
+ remove_method :sum
140
+
141
+ def sum(*args) #:nodoc:
142
+ # Use Enumerable#sum instead.
143
+ super
144
+ end
145
+ end
146
+ end
@@ -0,0 +1 @@
1
+ require 'active_support/core_ext/file/atomic'
@@ -0,0 +1,68 @@
1
+ require 'fileutils'
2
+
3
+ class File
4
+ # Write to a file atomically. Useful for situations where you don't
5
+ # want other processes or threads to see half-written files.
6
+ #
7
+ # File.atomic_write('important.file') do |file|
8
+ # file.write('hello')
9
+ # end
10
+ #
11
+ # This method needs to create a temporary file. By default it will create it
12
+ # in the same directory as the destination file. If you don't like this
13
+ # behavior you can provide a different directory but it must be on the
14
+ # same physical filesystem as the file you're trying to write.
15
+ #
16
+ # File.atomic_write('/data/something.important', '/data/tmp') do |file|
17
+ # file.write('hello')
18
+ # end
19
+ def self.atomic_write(file_name, temp_dir = dirname(file_name))
20
+ require 'tempfile' unless defined?(Tempfile)
21
+
22
+ Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
23
+ temp_file.binmode
24
+ return_val = yield temp_file
25
+ temp_file.close
26
+
27
+ old_stat = if exist?(file_name)
28
+ # Get original file permissions
29
+ stat(file_name)
30
+ elsif temp_dir != dirname(file_name)
31
+ # If not possible, probe which are the default permissions in the
32
+ # destination directory.
33
+ probe_stat_in(dirname(file_name))
34
+ end
35
+
36
+ if old_stat
37
+ # Set correct permissions on new file
38
+ begin
39
+ chown(old_stat.uid, old_stat.gid, temp_file.path)
40
+ # This operation will affect filesystem ACL's
41
+ chmod(old_stat.mode, temp_file.path)
42
+ rescue Errno::EPERM, Errno::EACCES
43
+ # Changing file ownership failed, moving on.
44
+ end
45
+ end
46
+
47
+ # Overwrite original file with temp file
48
+ rename(temp_file.path, file_name)
49
+ return_val
50
+ end
51
+ end
52
+
53
+ # Private utility method.
54
+ def self.probe_stat_in(dir) #:nodoc:
55
+ basename = [
56
+ '.permissions_check',
57
+ Thread.current.object_id,
58
+ Process.pid,
59
+ rand(1000000)
60
+ ].join('.')
61
+
62
+ file_name = join(dir, basename)
63
+ FileUtils.touch(file_name)
64
+ stat(file_name)
65
+ ensure
66
+ FileUtils.rm_f(file_name) if file_name
67
+ end
68
+ end
@@ -0,0 +1,9 @@
1
+ require 'active_support/core_ext/hash/compact'
2
+ require 'active_support/core_ext/hash/conversions'
3
+ require 'active_support/core_ext/hash/deep_merge'
4
+ require 'active_support/core_ext/hash/except'
5
+ require 'active_support/core_ext/hash/indifferent_access'
6
+ require 'active_support/core_ext/hash/keys'
7
+ require 'active_support/core_ext/hash/reverse_merge'
8
+ require 'active_support/core_ext/hash/slice'
9
+ require 'active_support/core_ext/hash/transform_values'
@@ -0,0 +1,24 @@
1
+ class Hash
2
+ unless Hash.instance_methods(false).include?(:compact)
3
+ # Returns a hash with non +nil+ values.
4
+ #
5
+ # hash = { a: true, b: false, c: nil}
6
+ # hash.compact # => { a: true, b: false}
7
+ # hash # => { a: true, b: false, c: nil}
8
+ # { c: nil }.compact # => {}
9
+ def compact
10
+ self.select { |_, value| !value.nil? }
11
+ end
12
+ end
13
+
14
+ unless Hash.instance_methods(false).include?(:compact!)
15
+ # Replaces current hash with non +nil+ values.
16
+ #
17
+ # hash = { a: true, b: false, c: nil}
18
+ # hash.compact! # => { a: true, b: false}
19
+ # hash # => { a: true, b: false}
20
+ def compact!
21
+ self.reject! { |_, value| value.nil? }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,262 @@
1
+ require 'active_support/xml_mini'
2
+ require 'active_support/time'
3
+ require 'active_support/core_ext/object/blank'
4
+ require 'active_support/core_ext/object/to_param'
5
+ require 'active_support/core_ext/object/to_query'
6
+ require 'active_support/core_ext/array/wrap'
7
+ require 'active_support/core_ext/hash/reverse_merge'
8
+ require 'active_support/core_ext/string/inflections'
9
+
10
+ class Hash
11
+ # Returns a string containing an XML representation of its receiver:
12
+ #
13
+ # { foo: 1, bar: 2 }.to_xml
14
+ # # =>
15
+ # # <?xml version="1.0" encoding="UTF-8"?>
16
+ # # <hash>
17
+ # # <foo type="integer">1</foo>
18
+ # # <bar type="integer">2</bar>
19
+ # # </hash>
20
+ #
21
+ # To do so, the method loops over the pairs and builds nodes that depend on
22
+ # the _values_. Given a pair +key+, +value+:
23
+ #
24
+ # * If +value+ is a hash there's a recursive call with +key+ as <tt>:root</tt>.
25
+ #
26
+ # * If +value+ is an array there's a recursive call with +key+ as <tt>:root</tt>,
27
+ # and +key+ singularized as <tt>:children</tt>.
28
+ #
29
+ # * If +value+ is a callable object it must expect one or two arguments. Depending
30
+ # on the arity, the callable is invoked with the +options+ hash as first argument
31
+ # with +key+ as <tt>:root</tt>, and +key+ singularized as second argument. The
32
+ # callable can add nodes by using <tt>options[:builder]</tt>.
33
+ #
34
+ # {foo: lambda { |options, key| options[:builder].b(key) }}.to_xml
35
+ # # => "<b>foo</b>"
36
+ #
37
+ # * If +value+ responds to +to_xml+ the method is invoked with +key+ as <tt>:root</tt>.
38
+ #
39
+ # class Foo
40
+ # def to_xml(options)
41
+ # options[:builder].bar 'fooing!'
42
+ # end
43
+ # end
44
+ #
45
+ # { foo: Foo.new }.to_xml(skip_instruct: true)
46
+ # # =>
47
+ # # <hash>
48
+ # # <bar>fooing!</bar>
49
+ # # </hash>
50
+ #
51
+ # * Otherwise, a node with +key+ as tag is created with a string representation of
52
+ # +value+ as text node. If +value+ is +nil+ an attribute "nil" set to "true" is added.
53
+ # Unless the option <tt>:skip_types</tt> exists and is true, an attribute "type" is
54
+ # added as well according to the following mapping:
55
+ #
56
+ # XML_TYPE_NAMES = {
57
+ # "Symbol" => "symbol",
58
+ # "Integer" => "integer",
59
+ # "BigDecimal" => "decimal",
60
+ # "Float" => "float",
61
+ # "TrueClass" => "boolean",
62
+ # "FalseClass" => "boolean",
63
+ # "Date" => "date",
64
+ # "DateTime" => "dateTime",
65
+ # "Time" => "dateTime"
66
+ # }
67
+ #
68
+ # By default the root node is "hash", but that's configurable via the <tt>:root</tt> option.
69
+ #
70
+ # The default XML builder is a fresh instance of <tt>Builder::XmlMarkup</tt>. You can
71
+ # configure your own builder with the <tt>:builder</tt> option. The method also accepts
72
+ # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
73
+ def to_xml(options = {})
74
+ require 'active_support/builder' unless defined?(Builder)
75
+
76
+ options = options.dup
77
+ options[:indent] ||= 2
78
+ options[:root] ||= 'hash'
79
+ options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
80
+
81
+ builder = options[:builder]
82
+ builder.instruct! unless options.delete(:skip_instruct)
83
+
84
+ root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options)
85
+
86
+ builder.tag!(root) do
87
+ each { |key, value| ActiveSupport::XmlMini.to_tag(key, value, options) }
88
+ yield builder if block_given?
89
+ end
90
+ end
91
+
92
+ class << self
93
+ # Returns a Hash containing a collection of pairs when the key is the node name and the value is
94
+ # its content
95
+ #
96
+ # xml = <<-XML
97
+ # <?xml version="1.0" encoding="UTF-8"?>
98
+ # <hash>
99
+ # <foo type="integer">1</foo>
100
+ # <bar type="integer">2</bar>
101
+ # </hash>
102
+ # XML
103
+ #
104
+ # hash = Hash.from_xml(xml)
105
+ # # => {"hash"=>{"foo"=>1, "bar"=>2}}
106
+ #
107
+ # +DisallowedType+ is raised if the XML contains attributes with <tt>type="yaml"</tt> or
108
+ # <tt>type="symbol"</tt>. Use <tt>Hash.from_trusted_xml</tt> to
109
+ # parse this XML.
110
+ #
111
+ # Custom +disallowed_types+ can also be passed in the form of an
112
+ # array.
113
+ #
114
+ # xml = <<-XML
115
+ # <?xml version="1.0" encoding="UTF-8"?>
116
+ # <hash>
117
+ # <foo type="integer">1</foo>
118
+ # <bar type="string">"David"</bar>
119
+ # </hash>
120
+ # XML
121
+ #
122
+ # hash = Hash.from_xml(xml, ['integer'])
123
+ # # => ActiveSupport::XMLConverter::DisallowedType: Disallowed type attribute: "integer"
124
+ #
125
+ # Note that passing custom disallowed types will override the default types,
126
+ # which are Symbol and YAML.
127
+ def from_xml(xml, disallowed_types = nil)
128
+ ActiveSupport::XMLConverter.new(xml, disallowed_types).to_h
129
+ end
130
+
131
+ # Builds a Hash from XML just like <tt>Hash.from_xml</tt>, but also allows Symbol and YAML.
132
+ def from_trusted_xml(xml)
133
+ from_xml xml, []
134
+ end
135
+ end
136
+ end
137
+
138
+ module ActiveSupport
139
+ class XMLConverter # :nodoc:
140
+ # Raised if the XML contains attributes with type="yaml" or
141
+ # type="symbol". Read Hash#from_xml for more details.
142
+ class DisallowedType < StandardError
143
+ def initialize(type)
144
+ super "Disallowed type attribute: #{type.inspect}"
145
+ end
146
+ end
147
+
148
+ DISALLOWED_TYPES = %w(symbol yaml)
149
+
150
+ def initialize(xml, disallowed_types = nil)
151
+ @xml = normalize_keys(XmlMini.parse(xml))
152
+ @disallowed_types = disallowed_types || DISALLOWED_TYPES
153
+ end
154
+
155
+ def to_h
156
+ deep_to_h(@xml)
157
+ end
158
+
159
+ private
160
+ def normalize_keys(params)
161
+ case params
162
+ when Hash
163
+ Hash[params.map { |k,v| [k.to_s.tr('-', '_'), normalize_keys(v)] } ]
164
+ when Array
165
+ params.map { |v| normalize_keys(v) }
166
+ else
167
+ params
168
+ end
169
+ end
170
+
171
+ def deep_to_h(value)
172
+ case value
173
+ when Hash
174
+ process_hash(value)
175
+ when Array
176
+ process_array(value)
177
+ when String
178
+ value
179
+ else
180
+ raise "can't typecast #{value.class.name} - #{value.inspect}"
181
+ end
182
+ end
183
+
184
+ def process_hash(value)
185
+ if value.include?('type') && !value['type'].is_a?(Hash) && @disallowed_types.include?(value['type'])
186
+ raise DisallowedType, value['type']
187
+ end
188
+
189
+ if become_array?(value)
190
+ _, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
191
+ if entries.nil? || value['__content__'].try(:empty?)
192
+ []
193
+ else
194
+ case entries
195
+ when Array
196
+ entries.collect { |v| deep_to_h(v) }
197
+ when Hash
198
+ [deep_to_h(entries)]
199
+ else
200
+ raise "can't typecast #{entries.inspect}"
201
+ end
202
+ end
203
+ elsif become_content?(value)
204
+ process_content(value)
205
+
206
+ elsif become_empty_string?(value)
207
+ ''
208
+ elsif become_hash?(value)
209
+ xml_value = Hash[value.map { |k,v| [k, deep_to_h(v)] }]
210
+
211
+ # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
212
+ # how multipart uploaded files from HTML appear
213
+ xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
214
+ end
215
+ end
216
+
217
+ def become_content?(value)
218
+ value['type'] == 'file' || (value['__content__'] && (value.keys.size == 1 || value['__content__'].present?))
219
+ end
220
+
221
+ def become_array?(value)
222
+ value['type'] == 'array'
223
+ end
224
+
225
+ def become_empty_string?(value)
226
+ # { "string" => true }
227
+ # No tests fail when the second term is removed.
228
+ value['type'] == 'string' && value['nil'] != 'true'
229
+ end
230
+
231
+ def become_hash?(value)
232
+ !nothing?(value) && !garbage?(value)
233
+ end
234
+
235
+ def nothing?(value)
236
+ # blank or nil parsed values are represented by nil
237
+ value.blank? || value['nil'] == 'true'
238
+ end
239
+
240
+ def garbage?(value)
241
+ # If the type is the only element which makes it then
242
+ # this still makes the value nil, except if type is
243
+ # an XML node(where type['value'] is a Hash)
244
+ value['type'] && !value['type'].is_a?(::Hash) && value.size == 1
245
+ end
246
+
247
+ def process_content(value)
248
+ content = value['__content__']
249
+ if parser = ActiveSupport::XmlMini::PARSING[value['type']]
250
+ parser.arity == 1 ? parser.call(content) : parser.call(content, value)
251
+ else
252
+ content
253
+ end
254
+ end
255
+
256
+ def process_array(value)
257
+ value.map! { |i| deep_to_h(i) }
258
+ value.length > 1 ? value : value.first
259
+ end
260
+
261
+ end
262
+ end