core_ext 0.0.1
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.
- checksums.yaml +7 -0
- data/README.md +3 -0
- data/lib/core_ext/array/access.rb +76 -0
- data/lib/core_ext/array/conversions.rb +211 -0
- data/lib/core_ext/array/extract_options.rb +29 -0
- data/lib/core_ext/array/grouping.rb +116 -0
- data/lib/core_ext/array/inquiry.rb +17 -0
- data/lib/core_ext/array/prepend_and_append.rb +7 -0
- data/lib/core_ext/array/wrap.rb +46 -0
- data/lib/core_ext/array.rb +7 -0
- data/lib/core_ext/array_inquirer.rb +44 -0
- data/lib/core_ext/benchmark.rb +14 -0
- data/lib/core_ext/benchmarkable.rb +49 -0
- data/lib/core_ext/big_decimal/conversions.rb +14 -0
- data/lib/core_ext/big_decimal.rb +1 -0
- data/lib/core_ext/builder.rb +6 -0
- data/lib/core_ext/callbacks.rb +770 -0
- data/lib/core_ext/class/attribute.rb +128 -0
- data/lib/core_ext/class/attribute_accessors.rb +4 -0
- data/lib/core_ext/class/subclasses.rb +42 -0
- data/lib/core_ext/class.rb +2 -0
- data/lib/core_ext/concern.rb +142 -0
- data/lib/core_ext/configurable.rb +148 -0
- data/lib/core_ext/date/acts_like.rb +8 -0
- data/lib/core_ext/date/blank.rb +12 -0
- data/lib/core_ext/date/calculations.rb +143 -0
- data/lib/core_ext/date/conversions.rb +93 -0
- data/lib/core_ext/date/zones.rb +6 -0
- data/lib/core_ext/date.rb +5 -0
- data/lib/core_ext/date_and_time/calculations.rb +328 -0
- data/lib/core_ext/date_and_time/zones.rb +40 -0
- data/lib/core_ext/date_time/acts_like.rb +14 -0
- data/lib/core_ext/date_time/blank.rb +12 -0
- data/lib/core_ext/date_time/calculations.rb +177 -0
- data/lib/core_ext/date_time/conversions.rb +104 -0
- data/lib/core_ext/date_time/zones.rb +6 -0
- data/lib/core_ext/date_time.rb +5 -0
- data/lib/core_ext/deprecation/behaviors.rb +86 -0
- data/lib/core_ext/deprecation/instance_delegator.rb +24 -0
- data/lib/core_ext/deprecation/method_wrappers.rb +70 -0
- data/lib/core_ext/deprecation/proxy_wrappers.rb +149 -0
- data/lib/core_ext/deprecation/reporting.rb +105 -0
- data/lib/core_ext/deprecation.rb +43 -0
- data/lib/core_ext/digest/uuid.rb +51 -0
- data/lib/core_ext/duration.rb +157 -0
- data/lib/core_ext/enumerable.rb +106 -0
- data/lib/core_ext/file/atomic.rb +68 -0
- data/lib/core_ext/file.rb +1 -0
- data/lib/core_ext/hash/compact.rb +20 -0
- data/lib/core_ext/hash/conversions.rb +261 -0
- data/lib/core_ext/hash/deep_merge.rb +38 -0
- data/lib/core_ext/hash/except.rb +22 -0
- data/lib/core_ext/hash/indifferent_access.rb +23 -0
- data/lib/core_ext/hash/keys.rb +170 -0
- data/lib/core_ext/hash/reverse_merge.rb +22 -0
- data/lib/core_ext/hash/slice.rb +48 -0
- data/lib/core_ext/hash/transform_values.rb +29 -0
- data/lib/core_ext/hash.rb +9 -0
- data/lib/core_ext/hash_with_indifferent_access.rb +298 -0
- data/lib/core_ext/inflections.rb +70 -0
- data/lib/core_ext/inflector/inflections.rb +244 -0
- data/lib/core_ext/inflector/methods.rb +381 -0
- data/lib/core_ext/inflector/transliterate.rb +112 -0
- data/lib/core_ext/inflector.rb +7 -0
- data/lib/core_ext/integer/inflections.rb +29 -0
- data/lib/core_ext/integer/multiple.rb +10 -0
- data/lib/core_ext/integer/time.rb +29 -0
- data/lib/core_ext/integer.rb +3 -0
- data/lib/core_ext/json/decoding.rb +67 -0
- data/lib/core_ext/json/encoding.rb +127 -0
- data/lib/core_ext/json.rb +2 -0
- data/lib/core_ext/kernel/agnostics.rb +11 -0
- data/lib/core_ext/kernel/concern.rb +10 -0
- data/lib/core_ext/kernel/reporting.rb +41 -0
- data/lib/core_ext/kernel/singleton_class.rb +6 -0
- data/lib/core_ext/kernel.rb +4 -0
- data/lib/core_ext/load_error.rb +30 -0
- data/lib/core_ext/logger.rb +57 -0
- data/lib/core_ext/logger_silence.rb +24 -0
- data/lib/core_ext/marshal.rb +19 -0
- data/lib/core_ext/module/aliasing.rb +74 -0
- data/lib/core_ext/module/anonymous.rb +28 -0
- data/lib/core_ext/module/attr_internal.rb +36 -0
- data/lib/core_ext/module/attribute_accessors.rb +212 -0
- data/lib/core_ext/module/concerning.rb +135 -0
- data/lib/core_ext/module/delegation.rb +218 -0
- data/lib/core_ext/module/deprecation.rb +23 -0
- data/lib/core_ext/module/introspection.rb +62 -0
- data/lib/core_ext/module/method_transplanting.rb +3 -0
- data/lib/core_ext/module/qualified_const.rb +52 -0
- data/lib/core_ext/module/reachable.rb +8 -0
- data/lib/core_ext/module/remove_method.rb +35 -0
- data/lib/core_ext/module.rb +11 -0
- data/lib/core_ext/multibyte/chars.rb +231 -0
- data/lib/core_ext/multibyte/unicode.rb +388 -0
- data/lib/core_ext/multibyte.rb +21 -0
- data/lib/core_ext/name_error.rb +31 -0
- data/lib/core_ext/numeric/bytes.rb +64 -0
- data/lib/core_ext/numeric/conversions.rb +132 -0
- data/lib/core_ext/numeric/inquiry.rb +26 -0
- data/lib/core_ext/numeric/time.rb +74 -0
- data/lib/core_ext/numeric.rb +4 -0
- data/lib/core_ext/object/acts_like.rb +10 -0
- data/lib/core_ext/object/blank.rb +140 -0
- data/lib/core_ext/object/conversions.rb +4 -0
- data/lib/core_ext/object/deep_dup.rb +53 -0
- data/lib/core_ext/object/duplicable.rb +98 -0
- data/lib/core_ext/object/inclusion.rb +27 -0
- data/lib/core_ext/object/instance_variables.rb +28 -0
- data/lib/core_ext/object/json.rb +199 -0
- data/lib/core_ext/object/to_param.rb +1 -0
- data/lib/core_ext/object/to_query.rb +84 -0
- data/lib/core_ext/object/try.rb +146 -0
- data/lib/core_ext/object/with_options.rb +69 -0
- data/lib/core_ext/object.rb +14 -0
- data/lib/core_ext/option_merger.rb +25 -0
- data/lib/core_ext/ordered_hash.rb +48 -0
- data/lib/core_ext/ordered_options.rb +81 -0
- data/lib/core_ext/range/conversions.rb +34 -0
- data/lib/core_ext/range/each.rb +21 -0
- data/lib/core_ext/range/include_range.rb +23 -0
- data/lib/core_ext/range/overlaps.rb +8 -0
- data/lib/core_ext/range.rb +4 -0
- data/lib/core_ext/regexp.rb +5 -0
- data/lib/core_ext/rescuable.rb +119 -0
- data/lib/core_ext/securerandom.rb +23 -0
- data/lib/core_ext/security_utils.rb +20 -0
- data/lib/core_ext/string/access.rb +104 -0
- data/lib/core_ext/string/behavior.rb +6 -0
- data/lib/core_ext/string/conversions.rb +56 -0
- data/lib/core_ext/string/exclude.rb +11 -0
- data/lib/core_ext/string/filters.rb +102 -0
- data/lib/core_ext/string/indent.rb +43 -0
- data/lib/core_ext/string/inflections.rb +235 -0
- data/lib/core_ext/string/inquiry.rb +13 -0
- data/lib/core_ext/string/multibyte.rb +53 -0
- data/lib/core_ext/string/output_safety.rb +261 -0
- data/lib/core_ext/string/starts_ends_with.rb +4 -0
- data/lib/core_ext/string/strip.rb +23 -0
- data/lib/core_ext/string/zones.rb +14 -0
- data/lib/core_ext/string.rb +13 -0
- data/lib/core_ext/string_inquirer.rb +26 -0
- data/lib/core_ext/tagged_logging.rb +78 -0
- data/lib/core_ext/test_case.rb +88 -0
- data/lib/core_ext/testing/assertions.rb +99 -0
- data/lib/core_ext/testing/autorun.rb +12 -0
- data/lib/core_ext/testing/composite_filter.rb +54 -0
- data/lib/core_ext/testing/constant_lookup.rb +50 -0
- data/lib/core_ext/testing/declarative.rb +26 -0
- data/lib/core_ext/testing/deprecation.rb +36 -0
- data/lib/core_ext/testing/file_fixtures.rb +34 -0
- data/lib/core_ext/testing/isolation.rb +115 -0
- data/lib/core_ext/testing/method_call_assertions.rb +41 -0
- data/lib/core_ext/testing/setup_and_teardown.rb +50 -0
- data/lib/core_ext/testing/stream.rb +42 -0
- data/lib/core_ext/testing/tagged_logging.rb +25 -0
- data/lib/core_ext/testing/time_helpers.rb +134 -0
- data/lib/core_ext/time/acts_like.rb +8 -0
- data/lib/core_ext/time/calculations.rb +284 -0
- data/lib/core_ext/time/conversions.rb +66 -0
- data/lib/core_ext/time/zones.rb +95 -0
- data/lib/core_ext/time.rb +20 -0
- data/lib/core_ext/time_with_zone.rb +503 -0
- data/lib/core_ext/time_zone.rb +464 -0
- data/lib/core_ext/uri.rb +25 -0
- data/lib/core_ext/version.rb +3 -0
- data/lib/core_ext/xml_mini/jdom.rb +181 -0
- data/lib/core_ext/xml_mini/libxml.rb +79 -0
- data/lib/core_ext/xml_mini/libxmlsax.rb +85 -0
- data/lib/core_ext/xml_mini/nokogiri.rb +83 -0
- data/lib/core_ext/xml_mini/nokogirisax.rb +87 -0
- data/lib/core_ext/xml_mini/rexml.rb +130 -0
- data/lib/core_ext/xml_mini.rb +194 -0
- data/lib/core_ext.rb +3 -0
- metadata +310 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 87d93ff39aee4506fbf6be9ce91a4c8e607e49aa
|
|
4
|
+
data.tar.gz: f8be51872fac5c526fca972e2e022ee0c31a2cb6
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 5ec18c6158abd27e745625af270dadf2e0ba817255dab84ea2a799ddb6b52241061e43d89c083b4398e8c4dfe11a71152c1f3b32b8a78b4e3986769e270959a1
|
|
7
|
+
data.tar.gz: 5091f649d5f221d95b2ce6256fe0e808fbda8c109d0eae0d8c6eab196904d146047683219796a8f795a08a3c29a5c8ccd465794ad4acd50bb464b384d85966ab
|
data/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
class Array
|
|
2
|
+
# Returns the tail of the array from +position+.
|
|
3
|
+
#
|
|
4
|
+
# %w( a b c d ).from(0) # => ["a", "b", "c", "d"]
|
|
5
|
+
# %w( a b c d ).from(2) # => ["c", "d"]
|
|
6
|
+
# %w( a b c d ).from(10) # => []
|
|
7
|
+
# %w().from(0) # => []
|
|
8
|
+
# %w( a b c d ).from(-2) # => ["c", "d"]
|
|
9
|
+
# %w( a b c ).from(-10) # => []
|
|
10
|
+
def from(position)
|
|
11
|
+
self[position, length] || []
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Returns the beginning of the array up to +position+.
|
|
15
|
+
#
|
|
16
|
+
# %w( a b c d ).to(0) # => ["a"]
|
|
17
|
+
# %w( a b c d ).to(2) # => ["a", "b", "c"]
|
|
18
|
+
# %w( a b c d ).to(10) # => ["a", "b", "c", "d"]
|
|
19
|
+
# %w().to(0) # => []
|
|
20
|
+
# %w( a b c d ).to(-2) # => ["a", "b", "c"]
|
|
21
|
+
# %w( a b c ).to(-10) # => []
|
|
22
|
+
def to(position)
|
|
23
|
+
if position >= 0
|
|
24
|
+
take position + 1
|
|
25
|
+
else
|
|
26
|
+
self[0..position]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Returns a copy of the Array without the specified elements.
|
|
31
|
+
#
|
|
32
|
+
# people = ["David", "Rafael", "Aaron", "Todd"]
|
|
33
|
+
# people.without "Aaron", "Todd"
|
|
34
|
+
# => ["David", "Rafael"]
|
|
35
|
+
#
|
|
36
|
+
# Note: This is an optimization of `Enumerable#without` that uses `Array#-`
|
|
37
|
+
# instead of `Array#reject` for performance reasons.
|
|
38
|
+
def without(*elements)
|
|
39
|
+
self - elements
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Equal to <tt>self[1]</tt>.
|
|
43
|
+
#
|
|
44
|
+
# %w( a b c d e ).second # => "b"
|
|
45
|
+
def second
|
|
46
|
+
self[1]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Equal to <tt>self[2]</tt>.
|
|
50
|
+
#
|
|
51
|
+
# %w( a b c d e ).third # => "c"
|
|
52
|
+
def third
|
|
53
|
+
self[2]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Equal to <tt>self[3]</tt>.
|
|
57
|
+
#
|
|
58
|
+
# %w( a b c d e ).fourth # => "d"
|
|
59
|
+
def fourth
|
|
60
|
+
self[3]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Equal to <tt>self[4]</tt>.
|
|
64
|
+
#
|
|
65
|
+
# %w( a b c d e ).fifth # => "e"
|
|
66
|
+
def fifth
|
|
67
|
+
self[4]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Equal to <tt>self[41]</tt>. Also known as accessing "the reddit".
|
|
71
|
+
#
|
|
72
|
+
# (1..42).to_a.forty_two # => 42
|
|
73
|
+
def forty_two
|
|
74
|
+
self[41]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
require 'core_ext/xml_mini'
|
|
2
|
+
require 'core_ext/hash/keys'
|
|
3
|
+
require 'core_ext/string/inflections'
|
|
4
|
+
require 'core_ext/object/to_param'
|
|
5
|
+
require 'core_ext/object/to_query'
|
|
6
|
+
|
|
7
|
+
class Array
|
|
8
|
+
# Converts the array to a comma-separated sentence where the last element is
|
|
9
|
+
# joined by the connector word.
|
|
10
|
+
#
|
|
11
|
+
# You can pass the following options to change the default behavior. If you
|
|
12
|
+
# pass an option key that doesn't exist in the list below, it will raise an
|
|
13
|
+
# <tt>ArgumentError</tt>.
|
|
14
|
+
#
|
|
15
|
+
# ==== Options
|
|
16
|
+
#
|
|
17
|
+
# * <tt>:words_connector</tt> - The sign or word used to join the elements
|
|
18
|
+
# in arrays with two or more elements (default: ", ").
|
|
19
|
+
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements
|
|
20
|
+
# in arrays with two elements (default: " and ").
|
|
21
|
+
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element
|
|
22
|
+
# in arrays with three or more elements (default: ", and ").
|
|
23
|
+
# * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
|
|
24
|
+
# the connector options defined on the 'support.array' namespace in the
|
|
25
|
+
# corresponding dictionary file.
|
|
26
|
+
#
|
|
27
|
+
# ==== Examples
|
|
28
|
+
#
|
|
29
|
+
# [].to_sentence # => ""
|
|
30
|
+
# ['one'].to_sentence # => "one"
|
|
31
|
+
# ['one', 'two'].to_sentence # => "one and two"
|
|
32
|
+
# ['one', 'two', 'three'].to_sentence # => "one, two, and three"
|
|
33
|
+
#
|
|
34
|
+
# ['one', 'two'].to_sentence(passing: 'invalid option')
|
|
35
|
+
# # => ArgumentError: Unknown key: :passing. Valid keys are: :words_connector, :two_words_connector, :last_word_connector, :locale
|
|
36
|
+
#
|
|
37
|
+
# ['one', 'two'].to_sentence(two_words_connector: '-')
|
|
38
|
+
# # => "one-two"
|
|
39
|
+
#
|
|
40
|
+
# ['one', 'two', 'three'].to_sentence(words_connector: ' or ', last_word_connector: ' or at least ')
|
|
41
|
+
# # => "one or two or at least three"
|
|
42
|
+
#
|
|
43
|
+
# Using <tt>:locale</tt> option:
|
|
44
|
+
#
|
|
45
|
+
# # Given this locale dictionary:
|
|
46
|
+
# #
|
|
47
|
+
# # es:
|
|
48
|
+
# # support:
|
|
49
|
+
# # array:
|
|
50
|
+
# # words_connector: " o "
|
|
51
|
+
# # two_words_connector: " y "
|
|
52
|
+
# # last_word_connector: " o al menos "
|
|
53
|
+
#
|
|
54
|
+
# ['uno', 'dos'].to_sentence(locale: :es)
|
|
55
|
+
# # => "uno y dos"
|
|
56
|
+
#
|
|
57
|
+
# ['uno', 'dos', 'tres'].to_sentence(locale: :es)
|
|
58
|
+
# # => "uno o dos o al menos tres"
|
|
59
|
+
def to_sentence(options = {})
|
|
60
|
+
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector, :locale)
|
|
61
|
+
|
|
62
|
+
default_connectors = {
|
|
63
|
+
:words_connector => ', ',
|
|
64
|
+
:two_words_connector => ' and ',
|
|
65
|
+
:last_word_connector => ', and '
|
|
66
|
+
}
|
|
67
|
+
if defined?(I18n)
|
|
68
|
+
i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {})
|
|
69
|
+
default_connectors.merge!(i18n_connectors)
|
|
70
|
+
end
|
|
71
|
+
options = default_connectors.merge!(options)
|
|
72
|
+
|
|
73
|
+
case length
|
|
74
|
+
when 0
|
|
75
|
+
''
|
|
76
|
+
when 1
|
|
77
|
+
"#{self[0]}"
|
|
78
|
+
when 2
|
|
79
|
+
"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
|
|
80
|
+
else
|
|
81
|
+
"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Extends <tt>Array#to_s</tt> to convert a collection of elements into a
|
|
86
|
+
# comma separated id list if <tt>:db</tt> argument is given as the format.
|
|
87
|
+
#
|
|
88
|
+
# Blog.all.to_formatted_s(:db) # => "1,2,3"
|
|
89
|
+
# Blog.none.to_formatted_s(:db) # => "null"
|
|
90
|
+
# [1,2].to_formatted_s # => "[1, 2]"
|
|
91
|
+
def to_formatted_s(format = :default)
|
|
92
|
+
case format
|
|
93
|
+
when :db
|
|
94
|
+
if empty?
|
|
95
|
+
'null'
|
|
96
|
+
else
|
|
97
|
+
collect(&:id).join(',')
|
|
98
|
+
end
|
|
99
|
+
else
|
|
100
|
+
to_default_s
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
alias_method :to_default_s, :to_s
|
|
104
|
+
alias_method :to_s, :to_formatted_s
|
|
105
|
+
|
|
106
|
+
# Returns a string that represents the array in XML by invoking +to_xml+
|
|
107
|
+
# on each element. Active Record collections delegate their representation
|
|
108
|
+
# in XML to this method.
|
|
109
|
+
#
|
|
110
|
+
# All elements are expected to respond to +to_xml+, if any of them does
|
|
111
|
+
# not then an exception is raised.
|
|
112
|
+
#
|
|
113
|
+
# The root node reflects the class name of the first element in plural
|
|
114
|
+
# if all elements belong to the same type and that's not Hash:
|
|
115
|
+
#
|
|
116
|
+
# customer.projects.to_xml
|
|
117
|
+
#
|
|
118
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
119
|
+
# <projects type="array">
|
|
120
|
+
# <project>
|
|
121
|
+
# <amount type="decimal">20000.0</amount>
|
|
122
|
+
# <customer-id type="integer">1567</customer-id>
|
|
123
|
+
# <deal-date type="date">2008-04-09</deal-date>
|
|
124
|
+
# ...
|
|
125
|
+
# </project>
|
|
126
|
+
# <project>
|
|
127
|
+
# <amount type="decimal">57230.0</amount>
|
|
128
|
+
# <customer-id type="integer">1567</customer-id>
|
|
129
|
+
# <deal-date type="date">2008-04-15</deal-date>
|
|
130
|
+
# ...
|
|
131
|
+
# </project>
|
|
132
|
+
# </projects>
|
|
133
|
+
#
|
|
134
|
+
# Otherwise the root element is "objects":
|
|
135
|
+
#
|
|
136
|
+
# [{ foo: 1, bar: 2}, { baz: 3}].to_xml
|
|
137
|
+
#
|
|
138
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
139
|
+
# <objects type="array">
|
|
140
|
+
# <object>
|
|
141
|
+
# <bar type="integer">2</bar>
|
|
142
|
+
# <foo type="integer">1</foo>
|
|
143
|
+
# </object>
|
|
144
|
+
# <object>
|
|
145
|
+
# <baz type="integer">3</baz>
|
|
146
|
+
# </object>
|
|
147
|
+
# </objects>
|
|
148
|
+
#
|
|
149
|
+
# If the collection is empty the root element is "nil-classes" by default:
|
|
150
|
+
#
|
|
151
|
+
# [].to_xml
|
|
152
|
+
#
|
|
153
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
154
|
+
# <nil-classes type="array"/>
|
|
155
|
+
#
|
|
156
|
+
# To ensure a meaningful root element use the <tt>:root</tt> option:
|
|
157
|
+
#
|
|
158
|
+
# customer_with_no_projects.projects.to_xml(root: 'projects')
|
|
159
|
+
#
|
|
160
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
161
|
+
# <projects type="array"/>
|
|
162
|
+
#
|
|
163
|
+
# By default name of the node for the children of root is <tt>root.singularize</tt>.
|
|
164
|
+
# You can change it with the <tt>:children</tt> option.
|
|
165
|
+
#
|
|
166
|
+
# The +options+ hash is passed downwards:
|
|
167
|
+
#
|
|
168
|
+
# Message.all.to_xml(skip_types: true)
|
|
169
|
+
#
|
|
170
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
|
171
|
+
# <messages>
|
|
172
|
+
# <message>
|
|
173
|
+
# <created-at>2008-03-07T09:58:18+01:00</created-at>
|
|
174
|
+
# <id>1</id>
|
|
175
|
+
# <name>1</name>
|
|
176
|
+
# <updated-at>2008-03-07T09:58:18+01:00</updated-at>
|
|
177
|
+
# <user-id>1</user-id>
|
|
178
|
+
# </message>
|
|
179
|
+
# </messages>
|
|
180
|
+
#
|
|
181
|
+
def to_xml(options = {})
|
|
182
|
+
require 'core_ext/builder' unless defined?(Builder)
|
|
183
|
+
|
|
184
|
+
options = options.dup
|
|
185
|
+
options[:indent] ||= 2
|
|
186
|
+
options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
|
|
187
|
+
options[:root] ||= \
|
|
188
|
+
if first.class != Hash && all? { |e| e.is_a?(first.class) }
|
|
189
|
+
underscored = CoreExt::Inflector.underscore(first.class.name)
|
|
190
|
+
CoreExt::Inflector.pluralize(underscored).tr('/', '_')
|
|
191
|
+
else
|
|
192
|
+
'objects'
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
builder = options[:builder]
|
|
196
|
+
builder.instruct! unless options.delete(:skip_instruct)
|
|
197
|
+
|
|
198
|
+
root = CoreExt::XmlMini.rename_key(options[:root].to_s, options)
|
|
199
|
+
children = options.delete(:children) || root.singularize
|
|
200
|
+
attributes = options[:skip_types] ? {} : { type: 'array' }
|
|
201
|
+
|
|
202
|
+
if empty?
|
|
203
|
+
builder.tag!(root, attributes)
|
|
204
|
+
else
|
|
205
|
+
builder.tag!(root, attributes) do
|
|
206
|
+
each { |value| CoreExt::XmlMini.to_tag(children, value, options) }
|
|
207
|
+
yield builder if block_given?
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
class Hash
|
|
2
|
+
# By default, only instances of Hash itself are extractable.
|
|
3
|
+
# Subclasses of Hash may implement this method and return
|
|
4
|
+
# true to declare themselves as extractable. If a Hash
|
|
5
|
+
# is extractable, Array#extract_options! pops it from
|
|
6
|
+
# the Array when it is the last element of the Array.
|
|
7
|
+
def extractable_options?
|
|
8
|
+
instance_of?(Hash)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Array
|
|
13
|
+
# Extracts options from a set of arguments. Removes and returns the last
|
|
14
|
+
# element in the array if it's a hash, otherwise returns a blank hash.
|
|
15
|
+
#
|
|
16
|
+
# def options(*args)
|
|
17
|
+
# args.extract_options!
|
|
18
|
+
# end
|
|
19
|
+
#
|
|
20
|
+
# options(1, 2) # => {}
|
|
21
|
+
# options(1, 2, a: :b) # => {:a=>:b}
|
|
22
|
+
def extract_options!
|
|
23
|
+
if last.is_a?(Hash) && last.extractable_options?
|
|
24
|
+
pop
|
|
25
|
+
else
|
|
26
|
+
{}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
class Array
|
|
2
|
+
# Splits or iterates over the array in groups of size +number+,
|
|
3
|
+
# padding any remaining slots with +fill_with+ unless it is +false+.
|
|
4
|
+
#
|
|
5
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups_of(3) {|group| p group}
|
|
6
|
+
# ["1", "2", "3"]
|
|
7
|
+
# ["4", "5", "6"]
|
|
8
|
+
# ["7", "8", "9"]
|
|
9
|
+
# ["10", nil, nil]
|
|
10
|
+
#
|
|
11
|
+
# %w(1 2 3 4 5).in_groups_of(2, ' ') {|group| p group}
|
|
12
|
+
# ["1", "2"]
|
|
13
|
+
# ["3", "4"]
|
|
14
|
+
# ["5", " "]
|
|
15
|
+
#
|
|
16
|
+
# %w(1 2 3 4 5).in_groups_of(2, false) {|group| p group}
|
|
17
|
+
# ["1", "2"]
|
|
18
|
+
# ["3", "4"]
|
|
19
|
+
# ["5"]
|
|
20
|
+
def in_groups_of(number, fill_with = nil)
|
|
21
|
+
if number.to_i <= 0
|
|
22
|
+
raise ArgumentError,
|
|
23
|
+
"Group size must be a positive integer, was #{number.inspect}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if fill_with == false
|
|
27
|
+
collection = self
|
|
28
|
+
else
|
|
29
|
+
# size % number gives how many extra we have;
|
|
30
|
+
# subtracting from number gives how many to add;
|
|
31
|
+
# modulo number ensures we don't add group of just fill.
|
|
32
|
+
padding = (number - size % number) % number
|
|
33
|
+
collection = dup.concat(Array.new(padding, fill_with))
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
if block_given?
|
|
37
|
+
collection.each_slice(number) { |slice| yield(slice) }
|
|
38
|
+
else
|
|
39
|
+
collection.each_slice(number).to_a
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Splits or iterates over the array in +number+ of groups, padding any
|
|
44
|
+
# remaining slots with +fill_with+ unless it is +false+.
|
|
45
|
+
#
|
|
46
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3) {|group| p group}
|
|
47
|
+
# ["1", "2", "3", "4"]
|
|
48
|
+
# ["5", "6", "7", nil]
|
|
49
|
+
# ["8", "9", "10", nil]
|
|
50
|
+
#
|
|
51
|
+
# %w(1 2 3 4 5 6 7 8 9 10).in_groups(3, ' ') {|group| p group}
|
|
52
|
+
# ["1", "2", "3", "4"]
|
|
53
|
+
# ["5", "6", "7", " "]
|
|
54
|
+
# ["8", "9", "10", " "]
|
|
55
|
+
#
|
|
56
|
+
# %w(1 2 3 4 5 6 7).in_groups(3, false) {|group| p group}
|
|
57
|
+
# ["1", "2", "3"]
|
|
58
|
+
# ["4", "5"]
|
|
59
|
+
# ["6", "7"]
|
|
60
|
+
def in_groups(number, fill_with = nil)
|
|
61
|
+
# size.div number gives minor group size;
|
|
62
|
+
# size % number gives how many objects need extra accommodation;
|
|
63
|
+
# each group hold either division or division + 1 items.
|
|
64
|
+
division = size.div number
|
|
65
|
+
modulo = size % number
|
|
66
|
+
|
|
67
|
+
# create a new array avoiding dup
|
|
68
|
+
groups = []
|
|
69
|
+
start = 0
|
|
70
|
+
|
|
71
|
+
number.times do |index|
|
|
72
|
+
length = division + (modulo > 0 && modulo > index ? 1 : 0)
|
|
73
|
+
groups << last_group = slice(start, length)
|
|
74
|
+
last_group << fill_with if fill_with != false &&
|
|
75
|
+
modulo > 0 && length == division
|
|
76
|
+
start += length
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
if block_given?
|
|
80
|
+
groups.each { |g| yield(g) }
|
|
81
|
+
else
|
|
82
|
+
groups
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Divides the array into one or more subarrays based on a delimiting +value+
|
|
87
|
+
# or the result of an optional block.
|
|
88
|
+
#
|
|
89
|
+
# [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
|
|
90
|
+
# (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
|
|
91
|
+
def split(value = nil)
|
|
92
|
+
if block_given?
|
|
93
|
+
inject([[]]) do |results, element|
|
|
94
|
+
if yield(element)
|
|
95
|
+
results << []
|
|
96
|
+
else
|
|
97
|
+
results.last << element
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
results
|
|
101
|
+
end
|
|
102
|
+
else
|
|
103
|
+
results, arr = [[]], self.dup
|
|
104
|
+
until arr.empty?
|
|
105
|
+
if (idx = arr.index(value))
|
|
106
|
+
results.last.concat(arr.shift(idx))
|
|
107
|
+
arr.shift
|
|
108
|
+
results << []
|
|
109
|
+
else
|
|
110
|
+
results.last.concat(arr.shift(arr.size))
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
results
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'core_ext/array_inquirer'
|
|
2
|
+
|
|
3
|
+
class Array
|
|
4
|
+
# Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way
|
|
5
|
+
# to check its string-like contents.
|
|
6
|
+
#
|
|
7
|
+
# pets = [:cat, :dog].inquiry
|
|
8
|
+
#
|
|
9
|
+
# pets.cat? # => true
|
|
10
|
+
# pets.ferret? # => false
|
|
11
|
+
#
|
|
12
|
+
# pets.any?(:cat, :ferret) # => true
|
|
13
|
+
# pets.any?(:ferret, :alligator) # => false
|
|
14
|
+
def inquiry
|
|
15
|
+
CoreExt::ArrayInquirer.new(self)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
class Array
|
|
2
|
+
# Wraps its argument in an array unless it is already an array (or array-like).
|
|
3
|
+
#
|
|
4
|
+
# Specifically:
|
|
5
|
+
#
|
|
6
|
+
# * If the argument is +nil+ an empty array is returned.
|
|
7
|
+
# * Otherwise, if the argument responds to +to_ary+ it is invoked, and its result returned.
|
|
8
|
+
# * Otherwise, returns an array with the argument as its single element.
|
|
9
|
+
#
|
|
10
|
+
# Array.wrap(nil) # => []
|
|
11
|
+
# Array.wrap([1, 2, 3]) # => [1, 2, 3]
|
|
12
|
+
# Array.wrap(0) # => [0]
|
|
13
|
+
#
|
|
14
|
+
# This method is similar in purpose to <tt>Kernel#Array</tt>, but there are some differences:
|
|
15
|
+
#
|
|
16
|
+
# * If the argument responds to +to_ary+ the method is invoked. <tt>Kernel#Array</tt>
|
|
17
|
+
# moves on to try +to_a+ if the returned value is +nil+, but <tt>Array.wrap</tt> returns
|
|
18
|
+
# an array with the argument as its single element right away.
|
|
19
|
+
# * If the returned value from +to_ary+ is neither +nil+ nor an +Array+ object, <tt>Kernel#Array</tt>
|
|
20
|
+
# raises an exception, while <tt>Array.wrap</tt> does not, it just returns the value.
|
|
21
|
+
# * It does not call +to_a+ on the argument, if the argument does not respond to +to_ary+
|
|
22
|
+
# it returns an array with the argument as its single element.
|
|
23
|
+
#
|
|
24
|
+
# The last point is easily explained with some enumerables:
|
|
25
|
+
#
|
|
26
|
+
# Array(foo: :bar) # => [[:foo, :bar]]
|
|
27
|
+
# Array.wrap(foo: :bar) # => [{:foo=>:bar}]
|
|
28
|
+
#
|
|
29
|
+
# There's also a related idiom that uses the splat operator:
|
|
30
|
+
#
|
|
31
|
+
# [*object]
|
|
32
|
+
#
|
|
33
|
+
# which returns <tt>[]</tt> for +nil+, but calls to <tt>Array(object)</tt> otherwise.
|
|
34
|
+
#
|
|
35
|
+
# The differences with <tt>Kernel#Array</tt> explained above
|
|
36
|
+
# apply to the rest of <tt>object</tt>s.
|
|
37
|
+
def self.wrap(object)
|
|
38
|
+
if object.nil?
|
|
39
|
+
[]
|
|
40
|
+
elsif object.respond_to?(:to_ary)
|
|
41
|
+
object.to_ary || [object]
|
|
42
|
+
else
|
|
43
|
+
[object]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module CoreExt
|
|
2
|
+
# Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check
|
|
3
|
+
# its string-like contents:
|
|
4
|
+
#
|
|
5
|
+
# variants = CoreExt::ArrayInquirer.new([:phone, :tablet])
|
|
6
|
+
#
|
|
7
|
+
# variants.phone? # => true
|
|
8
|
+
# variants.tablet? # => true
|
|
9
|
+
# variants.desktop? # => false
|
|
10
|
+
class ArrayInquirer < Array
|
|
11
|
+
# Passes each element of +candidates+ collection to ArrayInquirer collection.
|
|
12
|
+
# The method returns true if at least one element is the same. If +candidates+
|
|
13
|
+
# collection is not given, method returns true.
|
|
14
|
+
#
|
|
15
|
+
# variants = CoreExt::ArrayInquirer.new([:phone, :tablet])
|
|
16
|
+
#
|
|
17
|
+
# variants.any? # => true
|
|
18
|
+
# variants.any?(:phone, :tablet) # => true
|
|
19
|
+
# variants.any?('phone', 'desktop') # => true
|
|
20
|
+
# variants.any?(:desktop, :watch) # => false
|
|
21
|
+
def any?(*candidates, &block)
|
|
22
|
+
if candidates.none?
|
|
23
|
+
super
|
|
24
|
+
else
|
|
25
|
+
candidates.any? do |candidate|
|
|
26
|
+
include?(candidate.to_sym) || include?(candidate.to_s)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
def respond_to_missing?(name, include_private = false)
|
|
33
|
+
name[-1] == '?'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def method_missing(name, *args)
|
|
37
|
+
if name[-1] == '?'
|
|
38
|
+
any?(name[0..-2])
|
|
39
|
+
else
|
|
40
|
+
super
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'core_ext/benchmark'
|
|
2
|
+
require 'core_ext/hash/keys'
|
|
3
|
+
|
|
4
|
+
module CoreExt
|
|
5
|
+
module Benchmarkable
|
|
6
|
+
# Allows you to measure the execution time of a block in a template and
|
|
7
|
+
# records the result to the log. Wrap this block around expensive operations
|
|
8
|
+
# or possible bottlenecks to get a time reading for the operation. For
|
|
9
|
+
# example, let's say you thought your file processing method was taking too
|
|
10
|
+
# 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 (<tt>:debug</tt>, <tt>:info</tt>,
|
|
20
|
+
# <tt>:warn</tt>, <tt>:error</tt>) as the <tt>:level</tt> option. The
|
|
21
|
+
# default logger level value is <tt>:info</tt>.
|
|
22
|
+
#
|
|
23
|
+
# <% benchmark 'Low-level files', level: :debug do %>
|
|
24
|
+
# <%= lowlevel_files_operation %>
|
|
25
|
+
# <% end %>
|
|
26
|
+
#
|
|
27
|
+
# Finally, you can pass true as the third argument to silence all log
|
|
28
|
+
# activity (other than the timing information) from inside the block. This
|
|
29
|
+
# is great for boiling down a noisy block to just a single statement that
|
|
30
|
+
# produces one log line:
|
|
31
|
+
#
|
|
32
|
+
# <% benchmark 'Process data files', level: :info, silence: true do %>
|
|
33
|
+
# <%= expensive_and_chatty_files_operation %>
|
|
34
|
+
# <% end %>
|
|
35
|
+
def benchmark(message = "Benchmarking", options = {})
|
|
36
|
+
if logger
|
|
37
|
+
options.assert_valid_keys(:level, :silence)
|
|
38
|
+
options[:level] ||= :info
|
|
39
|
+
|
|
40
|
+
result = nil
|
|
41
|
+
ms = Benchmark.ms { result = options[:silence] ? silence { yield } : yield }
|
|
42
|
+
logger.send(options[:level], '%s (%.1fms)' % [ message, ms ])
|
|
43
|
+
result
|
|
44
|
+
else
|
|
45
|
+
yield
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'bigdecimal'
|
|
2
|
+
require 'bigdecimal/util'
|
|
3
|
+
|
|
4
|
+
module CoreExt
|
|
5
|
+
module BigDecimalWithDefaultFormat #:nodoc:
|
|
6
|
+
DEFAULT_STRING_FORMAT = 'F'
|
|
7
|
+
|
|
8
|
+
def to_s(format = nil)
|
|
9
|
+
super(format || DEFAULT_STRING_FORMAT)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
BigDecimal.prepend(CoreExt::BigDecimalWithDefaultFormat)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'core_ext/big_decimal/conversions'
|