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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1013 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +39 -0
- data/lib/active_support.rb +99 -0
- data/lib/active_support/all.rb +3 -0
- data/lib/active_support/array_inquirer.rb +44 -0
- data/lib/active_support/backtrace_cleaner.rb +103 -0
- data/lib/active_support/benchmarkable.rb +49 -0
- data/lib/active_support/builder.rb +6 -0
- data/lib/active_support/cache.rb +701 -0
- data/lib/active_support/cache/file_store.rb +204 -0
- data/lib/active_support/cache/mem_cache_store.rb +207 -0
- data/lib/active_support/cache/memory_store.rb +167 -0
- data/lib/active_support/cache/null_store.rb +41 -0
- data/lib/active_support/cache/strategy/local_cache.rb +172 -0
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
- data/lib/active_support/callbacks.rb +791 -0
- data/lib/active_support/concern.rb +142 -0
- data/lib/active_support/concurrency/latch.rb +26 -0
- data/lib/active_support/concurrency/share_lock.rb +226 -0
- data/lib/active_support/configurable.rb +148 -0
- data/lib/active_support/core_ext.rb +4 -0
- data/lib/active_support/core_ext/array.rb +7 -0
- data/lib/active_support/core_ext/array/access.rb +90 -0
- data/lib/active_support/core_ext/array/conversions.rb +211 -0
- data/lib/active_support/core_ext/array/extract_options.rb +29 -0
- data/lib/active_support/core_ext/array/grouping.rb +107 -0
- data/lib/active_support/core_ext/array/inquiry.rb +17 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -0
- data/lib/active_support/core_ext/array/wrap.rb +46 -0
- data/lib/active_support/core_ext/benchmark.rb +14 -0
- data/lib/active_support/core_ext/big_decimal.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
- data/lib/active_support/core_ext/class.rb +2 -0
- data/lib/active_support/core_ext/class/attribute.rb +128 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -0
- data/lib/active_support/core_ext/class/subclasses.rb +41 -0
- data/lib/active_support/core_ext/date.rb +5 -0
- data/lib/active_support/core_ext/date/acts_like.rb +8 -0
- data/lib/active_support/core_ext/date/blank.rb +12 -0
- data/lib/active_support/core_ext/date/calculations.rb +143 -0
- data/lib/active_support/core_ext/date/conversions.rb +95 -0
- data/lib/active_support/core_ext/date/zones.rb +6 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +335 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +14 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
- data/lib/active_support/core_ext/date_time.rb +5 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +14 -0
- data/lib/active_support/core_ext/date_time/blank.rb +12 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +199 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +105 -0
- data/lib/active_support/core_ext/digest/uuid.rb +51 -0
- data/lib/active_support/core_ext/enumerable.rb +146 -0
- data/lib/active_support/core_ext/file.rb +1 -0
- data/lib/active_support/core_ext/file/atomic.rb +68 -0
- data/lib/active_support/core_ext/hash.rb +9 -0
- data/lib/active_support/core_ext/hash/compact.rb +24 -0
- data/lib/active_support/core_ext/hash/conversions.rb +262 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +38 -0
- data/lib/active_support/core_ext/hash/except.rb +22 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +23 -0
- data/lib/active_support/core_ext/hash/keys.rb +170 -0
- data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -0
- data/lib/active_support/core_ext/hash/slice.rb +48 -0
- data/lib/active_support/core_ext/hash/transform_values.rb +29 -0
- data/lib/active_support/core_ext/integer.rb +3 -0
- data/lib/active_support/core_ext/integer/inflections.rb +29 -0
- data/lib/active_support/core_ext/integer/multiple.rb +10 -0
- data/lib/active_support/core_ext/integer/time.rb +29 -0
- data/lib/active_support/core_ext/kernel.rb +4 -0
- data/lib/active_support/core_ext/kernel/agnostics.rb +11 -0
- data/lib/active_support/core_ext/kernel/concern.rb +12 -0
- data/lib/active_support/core_ext/kernel/debugger.rb +3 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +43 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +6 -0
- data/lib/active_support/core_ext/load_error.rb +31 -0
- data/lib/active_support/core_ext/marshal.rb +22 -0
- data/lib/active_support/core_ext/module.rb +12 -0
- data/lib/active_support/core_ext/module/aliasing.rb +74 -0
- data/lib/active_support/core_ext/module/anonymous.rb +28 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +36 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
- data/lib/active_support/core_ext/module/concerning.rb +135 -0
- data/lib/active_support/core_ext/module/delegation.rb +216 -0
- data/lib/active_support/core_ext/module/deprecation.rb +23 -0
- data/lib/active_support/core_ext/module/introspection.rb +68 -0
- data/lib/active_support/core_ext/module/method_transplanting.rb +3 -0
- data/lib/active_support/core_ext/module/qualified_const.rb +70 -0
- data/lib/active_support/core_ext/module/reachable.rb +8 -0
- data/lib/active_support/core_ext/module/remove_method.rb +35 -0
- data/lib/active_support/core_ext/name_error.rb +31 -0
- data/lib/active_support/core_ext/numeric.rb +4 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +64 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +144 -0
- data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
- data/lib/active_support/core_ext/numeric/time.rb +74 -0
- data/lib/active_support/core_ext/object.rb +14 -0
- data/lib/active_support/core_ext/object/acts_like.rb +10 -0
- data/lib/active_support/core_ext/object/blank.rb +143 -0
- data/lib/active_support/core_ext/object/conversions.rb +4 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +53 -0
- data/lib/active_support/core_ext/object/duplicable.rb +124 -0
- data/lib/active_support/core_ext/object/inclusion.rb +27 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +28 -0
- data/lib/active_support/core_ext/object/json.rb +205 -0
- data/lib/active_support/core_ext/object/to_param.rb +1 -0
- data/lib/active_support/core_ext/object/to_query.rb +84 -0
- data/lib/active_support/core_ext/object/try.rb +146 -0
- data/lib/active_support/core_ext/object/with_options.rb +69 -0
- data/lib/active_support/core_ext/range.rb +4 -0
- data/lib/active_support/core_ext/range/conversions.rb +31 -0
- data/lib/active_support/core_ext/range/each.rb +21 -0
- data/lib/active_support/core_ext/range/include_range.rb +23 -0
- data/lib/active_support/core_ext/range/overlaps.rb +8 -0
- data/lib/active_support/core_ext/regexp.rb +5 -0
- data/lib/active_support/core_ext/securerandom.rb +23 -0
- data/lib/active_support/core_ext/string.rb +13 -0
- data/lib/active_support/core_ext/string/access.rb +104 -0
- data/lib/active_support/core_ext/string/behavior.rb +6 -0
- data/lib/active_support/core_ext/string/conversions.rb +57 -0
- data/lib/active_support/core_ext/string/exclude.rb +11 -0
- data/lib/active_support/core_ext/string/filters.rb +102 -0
- data/lib/active_support/core_ext/string/indent.rb +43 -0
- data/lib/active_support/core_ext/string/inflections.rb +244 -0
- data/lib/active_support/core_ext/string/inquiry.rb +13 -0
- data/lib/active_support/core_ext/string/multibyte.rb +53 -0
- data/lib/active_support/core_ext/string/output_safety.rb +260 -0
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -0
- data/lib/active_support/core_ext/string/strip.rb +23 -0
- data/lib/active_support/core_ext/string/zones.rb +14 -0
- data/lib/active_support/core_ext/struct.rb +3 -0
- data/lib/active_support/core_ext/time.rb +5 -0
- data/lib/active_support/core_ext/time/acts_like.rb +8 -0
- data/lib/active_support/core_ext/time/calculations.rb +290 -0
- data/lib/active_support/core_ext/time/compatibility.rb +14 -0
- data/lib/active_support/core_ext/time/conversions.rb +67 -0
- data/lib/active_support/core_ext/time/marshal.rb +3 -0
- data/lib/active_support/core_ext/time/zones.rb +111 -0
- data/lib/active_support/core_ext/uri.rb +24 -0
- data/lib/active_support/dependencies.rb +755 -0
- data/lib/active_support/dependencies/autoload.rb +77 -0
- data/lib/active_support/dependencies/interlock.rb +55 -0
- data/lib/active_support/deprecation.rb +43 -0
- data/lib/active_support/deprecation/behaviors.rb +90 -0
- data/lib/active_support/deprecation/instance_delegator.rb +37 -0
- data/lib/active_support/deprecation/method_wrappers.rb +70 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +149 -0
- data/lib/active_support/deprecation/reporting.rb +112 -0
- data/lib/active_support/descendants_tracker.rb +60 -0
- data/lib/active_support/duration.rb +235 -0
- data/lib/active_support/duration/iso8601_parser.rb +122 -0
- data/lib/active_support/duration/iso8601_serializer.rb +51 -0
- data/lib/active_support/evented_file_update_checker.rb +199 -0
- data/lib/active_support/execution_wrapper.rb +126 -0
- data/lib/active_support/executor.rb +6 -0
- data/lib/active_support/file_update_checker.rb +157 -0
- data/lib/active_support/gem_version.rb +15 -0
- data/lib/active_support/gzip.rb +36 -0
- data/lib/active_support/hash_with_indifferent_access.rb +329 -0
- data/lib/active_support/i18n.rb +13 -0
- data/lib/active_support/i18n_railtie.rb +115 -0
- data/lib/active_support/inflections.rb +70 -0
- data/lib/active_support/inflector.rb +7 -0
- data/lib/active_support/inflector/inflections.rb +242 -0
- data/lib/active_support/inflector/methods.rb +390 -0
- data/lib/active_support/inflector/transliterate.rb +112 -0
- data/lib/active_support/json.rb +2 -0
- data/lib/active_support/json/decoding.rb +74 -0
- data/lib/active_support/json/encoding.rb +127 -0
- data/lib/active_support/key_generator.rb +71 -0
- data/lib/active_support/lazy_load_hooks.rb +76 -0
- data/lib/active_support/locale/en.yml +135 -0
- data/lib/active_support/log_subscriber.rb +109 -0
- data/lib/active_support/log_subscriber/test_helper.rb +104 -0
- data/lib/active_support/logger.rb +106 -0
- data/lib/active_support/logger_silence.rb +28 -0
- data/lib/active_support/logger_thread_safe_level.rb +31 -0
- data/lib/active_support/message_encryptor.rb +114 -0
- data/lib/active_support/message_verifier.rb +134 -0
- data/lib/active_support/multibyte.rb +21 -0
- data/lib/active_support/multibyte/chars.rb +231 -0
- data/lib/active_support/multibyte/unicode.rb +413 -0
- data/lib/active_support/notifications.rb +212 -0
- data/lib/active_support/notifications/fanout.rb +157 -0
- data/lib/active_support/notifications/instrumenter.rb +91 -0
- data/lib/active_support/number_helper.rb +368 -0
- data/lib/active_support/number_helper/number_converter.rb +182 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +44 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +28 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +62 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +92 -0
- data/lib/active_support/option_merger.rb +25 -0
- data/lib/active_support/ordered_hash.rb +48 -0
- data/lib/active_support/ordered_options.rb +81 -0
- data/lib/active_support/per_thread_registry.rb +58 -0
- data/lib/active_support/proxy_object.rb +13 -0
- data/lib/active_support/rails.rb +27 -0
- data/lib/active_support/railtie.rb +51 -0
- data/lib/active_support/reloader.rb +129 -0
- data/lib/active_support/rescuable.rb +173 -0
- data/lib/active_support/security_utils.rb +27 -0
- data/lib/active_support/string_inquirer.rb +26 -0
- data/lib/active_support/subscriber.rb +120 -0
- data/lib/active_support/tagged_logging.rb +77 -0
- data/lib/active_support/test_case.rb +88 -0
- data/lib/active_support/testing/assertions.rb +99 -0
- data/lib/active_support/testing/autorun.rb +5 -0
- data/lib/active_support/testing/constant_lookup.rb +50 -0
- data/lib/active_support/testing/declarative.rb +26 -0
- data/lib/active_support/testing/deprecation.rb +36 -0
- data/lib/active_support/testing/file_fixtures.rb +34 -0
- data/lib/active_support/testing/isolation.rb +115 -0
- data/lib/active_support/testing/method_call_assertions.rb +41 -0
- data/lib/active_support/testing/setup_and_teardown.rb +50 -0
- data/lib/active_support/testing/stream.rb +42 -0
- data/lib/active_support/testing/tagged_logging.rb +25 -0
- data/lib/active_support/testing/time_helpers.rb +136 -0
- data/lib/active_support/time.rb +18 -0
- data/lib/active_support/time_with_zone.rb +511 -0
- data/lib/active_support/values/time_zone.rb +484 -0
- data/lib/active_support/values/unicode_tables.dat +0 -0
- data/lib/active_support/version.rb +8 -0
- data/lib/active_support/xml_mini.rb +209 -0
- data/lib/active_support/xml_mini/jdom.rb +181 -0
- data/lib/active_support/xml_mini/libxml.rb +77 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +82 -0
- data/lib/active_support/xml_mini/nokogiri.rb +81 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +85 -0
- data/lib/active_support/xml_mini/rexml.rb +128 -0
- 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
|