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.
Files changed (175) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +3 -0
  3. data/lib/core_ext/array/access.rb +76 -0
  4. data/lib/core_ext/array/conversions.rb +211 -0
  5. data/lib/core_ext/array/extract_options.rb +29 -0
  6. data/lib/core_ext/array/grouping.rb +116 -0
  7. data/lib/core_ext/array/inquiry.rb +17 -0
  8. data/lib/core_ext/array/prepend_and_append.rb +7 -0
  9. data/lib/core_ext/array/wrap.rb +46 -0
  10. data/lib/core_ext/array.rb +7 -0
  11. data/lib/core_ext/array_inquirer.rb +44 -0
  12. data/lib/core_ext/benchmark.rb +14 -0
  13. data/lib/core_ext/benchmarkable.rb +49 -0
  14. data/lib/core_ext/big_decimal/conversions.rb +14 -0
  15. data/lib/core_ext/big_decimal.rb +1 -0
  16. data/lib/core_ext/builder.rb +6 -0
  17. data/lib/core_ext/callbacks.rb +770 -0
  18. data/lib/core_ext/class/attribute.rb +128 -0
  19. data/lib/core_ext/class/attribute_accessors.rb +4 -0
  20. data/lib/core_ext/class/subclasses.rb +42 -0
  21. data/lib/core_ext/class.rb +2 -0
  22. data/lib/core_ext/concern.rb +142 -0
  23. data/lib/core_ext/configurable.rb +148 -0
  24. data/lib/core_ext/date/acts_like.rb +8 -0
  25. data/lib/core_ext/date/blank.rb +12 -0
  26. data/lib/core_ext/date/calculations.rb +143 -0
  27. data/lib/core_ext/date/conversions.rb +93 -0
  28. data/lib/core_ext/date/zones.rb +6 -0
  29. data/lib/core_ext/date.rb +5 -0
  30. data/lib/core_ext/date_and_time/calculations.rb +328 -0
  31. data/lib/core_ext/date_and_time/zones.rb +40 -0
  32. data/lib/core_ext/date_time/acts_like.rb +14 -0
  33. data/lib/core_ext/date_time/blank.rb +12 -0
  34. data/lib/core_ext/date_time/calculations.rb +177 -0
  35. data/lib/core_ext/date_time/conversions.rb +104 -0
  36. data/lib/core_ext/date_time/zones.rb +6 -0
  37. data/lib/core_ext/date_time.rb +5 -0
  38. data/lib/core_ext/deprecation/behaviors.rb +86 -0
  39. data/lib/core_ext/deprecation/instance_delegator.rb +24 -0
  40. data/lib/core_ext/deprecation/method_wrappers.rb +70 -0
  41. data/lib/core_ext/deprecation/proxy_wrappers.rb +149 -0
  42. data/lib/core_ext/deprecation/reporting.rb +105 -0
  43. data/lib/core_ext/deprecation.rb +43 -0
  44. data/lib/core_ext/digest/uuid.rb +51 -0
  45. data/lib/core_ext/duration.rb +157 -0
  46. data/lib/core_ext/enumerable.rb +106 -0
  47. data/lib/core_ext/file/atomic.rb +68 -0
  48. data/lib/core_ext/file.rb +1 -0
  49. data/lib/core_ext/hash/compact.rb +20 -0
  50. data/lib/core_ext/hash/conversions.rb +261 -0
  51. data/lib/core_ext/hash/deep_merge.rb +38 -0
  52. data/lib/core_ext/hash/except.rb +22 -0
  53. data/lib/core_ext/hash/indifferent_access.rb +23 -0
  54. data/lib/core_ext/hash/keys.rb +170 -0
  55. data/lib/core_ext/hash/reverse_merge.rb +22 -0
  56. data/lib/core_ext/hash/slice.rb +48 -0
  57. data/lib/core_ext/hash/transform_values.rb +29 -0
  58. data/lib/core_ext/hash.rb +9 -0
  59. data/lib/core_ext/hash_with_indifferent_access.rb +298 -0
  60. data/lib/core_ext/inflections.rb +70 -0
  61. data/lib/core_ext/inflector/inflections.rb +244 -0
  62. data/lib/core_ext/inflector/methods.rb +381 -0
  63. data/lib/core_ext/inflector/transliterate.rb +112 -0
  64. data/lib/core_ext/inflector.rb +7 -0
  65. data/lib/core_ext/integer/inflections.rb +29 -0
  66. data/lib/core_ext/integer/multiple.rb +10 -0
  67. data/lib/core_ext/integer/time.rb +29 -0
  68. data/lib/core_ext/integer.rb +3 -0
  69. data/lib/core_ext/json/decoding.rb +67 -0
  70. data/lib/core_ext/json/encoding.rb +127 -0
  71. data/lib/core_ext/json.rb +2 -0
  72. data/lib/core_ext/kernel/agnostics.rb +11 -0
  73. data/lib/core_ext/kernel/concern.rb +10 -0
  74. data/lib/core_ext/kernel/reporting.rb +41 -0
  75. data/lib/core_ext/kernel/singleton_class.rb +6 -0
  76. data/lib/core_ext/kernel.rb +4 -0
  77. data/lib/core_ext/load_error.rb +30 -0
  78. data/lib/core_ext/logger.rb +57 -0
  79. data/lib/core_ext/logger_silence.rb +24 -0
  80. data/lib/core_ext/marshal.rb +19 -0
  81. data/lib/core_ext/module/aliasing.rb +74 -0
  82. data/lib/core_ext/module/anonymous.rb +28 -0
  83. data/lib/core_ext/module/attr_internal.rb +36 -0
  84. data/lib/core_ext/module/attribute_accessors.rb +212 -0
  85. data/lib/core_ext/module/concerning.rb +135 -0
  86. data/lib/core_ext/module/delegation.rb +218 -0
  87. data/lib/core_ext/module/deprecation.rb +23 -0
  88. data/lib/core_ext/module/introspection.rb +62 -0
  89. data/lib/core_ext/module/method_transplanting.rb +3 -0
  90. data/lib/core_ext/module/qualified_const.rb +52 -0
  91. data/lib/core_ext/module/reachable.rb +8 -0
  92. data/lib/core_ext/module/remove_method.rb +35 -0
  93. data/lib/core_ext/module.rb +11 -0
  94. data/lib/core_ext/multibyte/chars.rb +231 -0
  95. data/lib/core_ext/multibyte/unicode.rb +388 -0
  96. data/lib/core_ext/multibyte.rb +21 -0
  97. data/lib/core_ext/name_error.rb +31 -0
  98. data/lib/core_ext/numeric/bytes.rb +64 -0
  99. data/lib/core_ext/numeric/conversions.rb +132 -0
  100. data/lib/core_ext/numeric/inquiry.rb +26 -0
  101. data/lib/core_ext/numeric/time.rb +74 -0
  102. data/lib/core_ext/numeric.rb +4 -0
  103. data/lib/core_ext/object/acts_like.rb +10 -0
  104. data/lib/core_ext/object/blank.rb +140 -0
  105. data/lib/core_ext/object/conversions.rb +4 -0
  106. data/lib/core_ext/object/deep_dup.rb +53 -0
  107. data/lib/core_ext/object/duplicable.rb +98 -0
  108. data/lib/core_ext/object/inclusion.rb +27 -0
  109. data/lib/core_ext/object/instance_variables.rb +28 -0
  110. data/lib/core_ext/object/json.rb +199 -0
  111. data/lib/core_ext/object/to_param.rb +1 -0
  112. data/lib/core_ext/object/to_query.rb +84 -0
  113. data/lib/core_ext/object/try.rb +146 -0
  114. data/lib/core_ext/object/with_options.rb +69 -0
  115. data/lib/core_ext/object.rb +14 -0
  116. data/lib/core_ext/option_merger.rb +25 -0
  117. data/lib/core_ext/ordered_hash.rb +48 -0
  118. data/lib/core_ext/ordered_options.rb +81 -0
  119. data/lib/core_ext/range/conversions.rb +34 -0
  120. data/lib/core_ext/range/each.rb +21 -0
  121. data/lib/core_ext/range/include_range.rb +23 -0
  122. data/lib/core_ext/range/overlaps.rb +8 -0
  123. data/lib/core_ext/range.rb +4 -0
  124. data/lib/core_ext/regexp.rb +5 -0
  125. data/lib/core_ext/rescuable.rb +119 -0
  126. data/lib/core_ext/securerandom.rb +23 -0
  127. data/lib/core_ext/security_utils.rb +20 -0
  128. data/lib/core_ext/string/access.rb +104 -0
  129. data/lib/core_ext/string/behavior.rb +6 -0
  130. data/lib/core_ext/string/conversions.rb +56 -0
  131. data/lib/core_ext/string/exclude.rb +11 -0
  132. data/lib/core_ext/string/filters.rb +102 -0
  133. data/lib/core_ext/string/indent.rb +43 -0
  134. data/lib/core_ext/string/inflections.rb +235 -0
  135. data/lib/core_ext/string/inquiry.rb +13 -0
  136. data/lib/core_ext/string/multibyte.rb +53 -0
  137. data/lib/core_ext/string/output_safety.rb +261 -0
  138. data/lib/core_ext/string/starts_ends_with.rb +4 -0
  139. data/lib/core_ext/string/strip.rb +23 -0
  140. data/lib/core_ext/string/zones.rb +14 -0
  141. data/lib/core_ext/string.rb +13 -0
  142. data/lib/core_ext/string_inquirer.rb +26 -0
  143. data/lib/core_ext/tagged_logging.rb +78 -0
  144. data/lib/core_ext/test_case.rb +88 -0
  145. data/lib/core_ext/testing/assertions.rb +99 -0
  146. data/lib/core_ext/testing/autorun.rb +12 -0
  147. data/lib/core_ext/testing/composite_filter.rb +54 -0
  148. data/lib/core_ext/testing/constant_lookup.rb +50 -0
  149. data/lib/core_ext/testing/declarative.rb +26 -0
  150. data/lib/core_ext/testing/deprecation.rb +36 -0
  151. data/lib/core_ext/testing/file_fixtures.rb +34 -0
  152. data/lib/core_ext/testing/isolation.rb +115 -0
  153. data/lib/core_ext/testing/method_call_assertions.rb +41 -0
  154. data/lib/core_ext/testing/setup_and_teardown.rb +50 -0
  155. data/lib/core_ext/testing/stream.rb +42 -0
  156. data/lib/core_ext/testing/tagged_logging.rb +25 -0
  157. data/lib/core_ext/testing/time_helpers.rb +134 -0
  158. data/lib/core_ext/time/acts_like.rb +8 -0
  159. data/lib/core_ext/time/calculations.rb +284 -0
  160. data/lib/core_ext/time/conversions.rb +66 -0
  161. data/lib/core_ext/time/zones.rb +95 -0
  162. data/lib/core_ext/time.rb +20 -0
  163. data/lib/core_ext/time_with_zone.rb +503 -0
  164. data/lib/core_ext/time_zone.rb +464 -0
  165. data/lib/core_ext/uri.rb +25 -0
  166. data/lib/core_ext/version.rb +3 -0
  167. data/lib/core_ext/xml_mini/jdom.rb +181 -0
  168. data/lib/core_ext/xml_mini/libxml.rb +79 -0
  169. data/lib/core_ext/xml_mini/libxmlsax.rb +85 -0
  170. data/lib/core_ext/xml_mini/nokogiri.rb +83 -0
  171. data/lib/core_ext/xml_mini/nokogirisax.rb +87 -0
  172. data/lib/core_ext/xml_mini/rexml.rb +130 -0
  173. data/lib/core_ext/xml_mini.rb +194 -0
  174. data/lib/core_ext.rb +3 -0
  175. 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,3 @@
1
+ ## core_ext
2
+
3
+ ActiveSupport's core_ext without ActiveSupport dependency
@@ -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, '&nbsp;') {|group| p group}
12
+ # ["1", "2"]
13
+ # ["3", "4"]
14
+ # ["5", "&nbsp;"]
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, '&nbsp;') {|group| p group}
52
+ # ["1", "2", "3", "4"]
53
+ # ["5", "6", "7", "&nbsp;"]
54
+ # ["8", "9", "10", "&nbsp;"]
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,7 @@
1
+ class Array
2
+ # The human way of thinking about adding stuff to the end of a list is with append.
3
+ alias_method :append, :<<
4
+
5
+ # The human way of thinking about adding stuff to the beginning of a list is with prepend.
6
+ alias_method :prepend, :unshift
7
+ 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,7 @@
1
+ require 'core_ext/array/wrap'
2
+ require 'core_ext/array/access'
3
+ require 'core_ext/array/conversions'
4
+ require 'core_ext/array/extract_options'
5
+ require 'core_ext/array/grouping'
6
+ require 'core_ext/array/prepend_and_append'
7
+ require 'core_ext/array/inquiry'
@@ -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,14 @@
1
+ require 'benchmark'
2
+
3
+ class << Benchmark
4
+ # Benchmark realtime in milliseconds.
5
+ #
6
+ # Benchmark.realtime { User.all }
7
+ # # => 8.0e-05
8
+ #
9
+ # Benchmark.ms { User.all }
10
+ # # => 0.074
11
+ def ms
12
+ 1000 * realtime { yield }
13
+ end
14
+ 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'
@@ -0,0 +1,6 @@
1
+ begin
2
+ require 'builder'
3
+ rescue LoadError => e
4
+ $stderr.puts "You don't have builder installed in your application. Please add it to your Gemfile and run bundle install"
5
+ raise e
6
+ end