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
@@ -0,0 +1,112 @@
1
+ require 'core_ext/string/multibyte'
2
+ require 'i18n'
3
+
4
+ module CoreExt
5
+ module Inflector
6
+
7
+ # Replaces non-ASCII characters with an ASCII approximation, or if none
8
+ # exists, a replacement character which defaults to "?".
9
+ #
10
+ # transliterate('Ærøskøbing')
11
+ # # => "AEroskobing"
12
+ #
13
+ # Default approximations are provided for Western/Latin characters,
14
+ # e.g, "ø", "ñ", "é", "ß", etc.
15
+ #
16
+ # This method is I18n aware, so you can set up custom approximations for a
17
+ # locale. This can be useful, for example, to transliterate German's "ü"
18
+ # and "ö" to "ue" and "oe", or to add support for transliterating Russian
19
+ # to ASCII.
20
+ #
21
+ # In order to make your custom transliterations available, you must set
22
+ # them as the <tt>i18n.transliterate.rule</tt> i18n key:
23
+ #
24
+ # # Store the transliterations in locales/de.yml
25
+ # i18n:
26
+ # transliterate:
27
+ # rule:
28
+ # ü: "ue"
29
+ # ö: "oe"
30
+ #
31
+ # # Or set them using Ruby
32
+ # I18n.backend.store_translations(:de, i18n: {
33
+ # transliterate: {
34
+ # rule: {
35
+ # 'ü' => 'ue',
36
+ # 'ö' => 'oe'
37
+ # }
38
+ # }
39
+ # })
40
+ #
41
+ # The value for <tt>i18n.transliterate.rule</tt> can be a simple Hash that
42
+ # maps characters to ASCII approximations as shown above, or, for more
43
+ # complex requirements, a Proc:
44
+ #
45
+ # I18n.backend.store_translations(:de, i18n: {
46
+ # transliterate: {
47
+ # rule: ->(string) { MyTransliterator.transliterate(string) }
48
+ # }
49
+ # })
50
+ #
51
+ # Now you can have different transliterations for each locale:
52
+ #
53
+ # I18n.locale = :en
54
+ # transliterate('Jürgen')
55
+ # # => "Jurgen"
56
+ #
57
+ # I18n.locale = :de
58
+ # transliterate('Jürgen')
59
+ # # => "Juergen"
60
+ def transliterate(string, replacement = "?".freeze)
61
+ I18n.transliterate(CoreExt::Multibyte::Unicode.normalize(
62
+ CoreExt::Multibyte::Unicode.tidy_bytes(string), :c),
63
+ :replacement => replacement)
64
+ end
65
+
66
+ # Replaces special characters in a string so that it may be used as part of
67
+ # a 'pretty' URL.
68
+ #
69
+ # parameterize("Donald E. Knuth") # => "donald-e-knuth"
70
+ # parameterize("^trés|Jolie-- ") # => "tres-jolie"
71
+ #
72
+ # To use a custom separator, override the `separator` argument.
73
+ #
74
+ # parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth"
75
+ # parameterize("^trés|Jolie-- ", separator: '_') # => "tres_jolie"
76
+ #
77
+ # To preserve the case of the characters in a string, use the `preserve_case` argument.
78
+ #
79
+ # parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth"
80
+ # parameterize("^trés|Jolie-- ", preserve_case: true) # => "tres-Jolie"
81
+ #
82
+ def parameterize(string, sep = :unused, separator: '-', preserve_case: false)
83
+ unless sep == :unused
84
+ CoreExt::Deprecation.warn("Passing the separator argument as a positional parameter is deprecated and will soon be removed. Use `separator: '#{sep}'` instead.")
85
+ separator = sep
86
+ end
87
+ # Replace accented chars with their ASCII equivalents.
88
+ parameterized_string = transliterate(string)
89
+
90
+ # Turn unwanted chars into the separator.
91
+ parameterized_string.gsub!(/[^a-z0-9\-_]+/i, separator)
92
+
93
+ unless separator.nil? || separator.empty?
94
+ if separator == "-".freeze
95
+ re_duplicate_separator = /-{2,}/
96
+ re_leading_trailing_separator = /^-|-$/i
97
+ else
98
+ re_sep = Regexp.escape(separator)
99
+ re_duplicate_separator = /#{re_sep}{2,}/
100
+ re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i
101
+ end
102
+ # No more than one of the separator in a row.
103
+ parameterized_string.gsub!(re_duplicate_separator, separator)
104
+ # Remove leading/trailing separator.
105
+ parameterized_string.gsub!(re_leading_trailing_separator, ''.freeze)
106
+ end
107
+
108
+ parameterized_string.downcase! unless preserve_case
109
+ parameterized_string
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,7 @@
1
+ # in case active_support/inflector is required without the rest of active_support
2
+ require 'core_ext/inflector/inflections'
3
+ require 'core_ext/inflector/transliterate'
4
+ require 'core_ext/inflector/methods'
5
+
6
+ require 'core_ext/inflections'
7
+ require 'core_ext/string/inflections'
@@ -0,0 +1,29 @@
1
+ require 'core_ext/inflector'
2
+
3
+ class Integer
4
+ # Ordinalize turns a number into an ordinal string used to denote the
5
+ # position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
6
+ #
7
+ # 1.ordinalize # => "1st"
8
+ # 2.ordinalize # => "2nd"
9
+ # 1002.ordinalize # => "1002nd"
10
+ # 1003.ordinalize # => "1003rd"
11
+ # -11.ordinalize # => "-11th"
12
+ # -1001.ordinalize # => "-1001st"
13
+ def ordinalize
14
+ CoreExt::Inflector.ordinalize(self)
15
+ end
16
+
17
+ # Ordinal returns the suffix used to denote the position
18
+ # in an ordered sequence such as 1st, 2nd, 3rd, 4th.
19
+ #
20
+ # 1.ordinal # => "st"
21
+ # 2.ordinal # => "nd"
22
+ # 1002.ordinal # => "nd"
23
+ # 1003.ordinal # => "rd"
24
+ # -11.ordinal # => "th"
25
+ # -1001.ordinal # => "st"
26
+ def ordinal
27
+ CoreExt::Inflector.ordinal(self)
28
+ end
29
+ end
@@ -0,0 +1,10 @@
1
+ class Integer
2
+ # Check whether the integer is evenly divisible by the argument.
3
+ #
4
+ # 0.multiple_of?(0) # => true
5
+ # 6.multiple_of?(5) # => false
6
+ # 10.multiple_of?(2) # => true
7
+ def multiple_of?(number)
8
+ number != 0 ? self % number == 0 : zero?
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ require 'core_ext/duration'
2
+ require 'core_ext/numeric/time'
3
+
4
+ class Integer
5
+ # Enables the use of time calculations and declarations, like <tt>45.minutes +
6
+ # 2.hours + 4.years</tt>.
7
+ #
8
+ # These methods use Time#advance for precise date calculations when using
9
+ # <tt>from_now</tt>, +ago+, etc. as well as adding or subtracting their
10
+ # results from a Time object.
11
+ #
12
+ # # equivalent to Time.now.advance(months: 1)
13
+ # 1.month.from_now
14
+ #
15
+ # # equivalent to Time.now.advance(years: 2)
16
+ # 2.years.from_now
17
+ #
18
+ # # equivalent to Time.now.advance(months: 4, years: 5)
19
+ # (4.months + 5.years).from_now
20
+ def months
21
+ CoreExt::Duration.new(self * 30.days, [[:months, self]])
22
+ end
23
+ alias :month :months
24
+
25
+ def years
26
+ CoreExt::Duration.new(self * 365.25.days.to_i, [[:years, self]])
27
+ end
28
+ alias :year :years
29
+ end
@@ -0,0 +1,3 @@
1
+ require 'core_ext/integer/multiple'
2
+ require 'core_ext/integer/inflections'
3
+ require 'core_ext/integer/time'
@@ -0,0 +1,67 @@
1
+ require 'core_ext/module/attribute_accessors'
2
+ require 'core_ext/module/delegation'
3
+ require 'json'
4
+
5
+ module CoreExt
6
+ # Look for and parse json strings that look like ISO 8601 times.
7
+ mattr_accessor :parse_json_times
8
+
9
+ module JSON
10
+ # matches YAML-formatted dates
11
+ DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/
12
+
13
+ class << self
14
+ # Parses a JSON string (JavaScript Object Notation) into a hash.
15
+ # See http://www.json.org for more info.
16
+ #
17
+ # CoreExt::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}")
18
+ # => {"team" => "rails", "players" => "36"}
19
+ def decode(json)
20
+ data = ::JSON.parse(json, quirks_mode: true)
21
+
22
+ if CoreExt.parse_json_times
23
+ convert_dates_from(data)
24
+ else
25
+ data
26
+ end
27
+ end
28
+
29
+ # Returns the class of the error that will be raised when there is an
30
+ # error in decoding JSON. Using this method means you won't directly
31
+ # depend on the CoreExt's JSON implementation, in case it changes
32
+ # in the future.
33
+ #
34
+ # begin
35
+ # obj = CoreExt::JSON.decode(some_string)
36
+ # rescue CoreExt::JSON.parse_error
37
+ # Rails.logger.warn("Attempted to decode invalid JSON: #{some_string}")
38
+ # end
39
+ def parse_error
40
+ ::JSON::ParserError
41
+ end
42
+
43
+ private
44
+
45
+ def convert_dates_from(data)
46
+ case data
47
+ when nil
48
+ nil
49
+ when DATE_REGEX
50
+ begin
51
+ DateTime.parse(data)
52
+ rescue ArgumentError
53
+ data
54
+ end
55
+ when Array
56
+ data.map! { |d| convert_dates_from(d) }
57
+ when Hash
58
+ data.each do |key, value|
59
+ data[key] = convert_dates_from(value)
60
+ end
61
+ else
62
+ data
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,127 @@
1
+ require 'core_ext/object/json'
2
+ require 'core_ext/module/delegation'
3
+
4
+ module CoreExt
5
+ class << self
6
+ delegate :use_standard_json_time_format, :use_standard_json_time_format=,
7
+ :time_precision, :time_precision=,
8
+ :escape_html_entities_in_json, :escape_html_entities_in_json=,
9
+ :json_encoder, :json_encoder=,
10
+ :to => :'CoreExt::JSON::Encoding'
11
+ end
12
+
13
+ module JSON
14
+ # Dumps objects in JSON (JavaScript Object Notation).
15
+ # See http://www.json.org for more info.
16
+ #
17
+ # CoreExt::JSON.encode({ team: 'rails', players: '36' })
18
+ # # => "{\"team\":\"rails\",\"players\":\"36\"}"
19
+ def self.encode(value, options = nil)
20
+ Encoding.json_encoder.new(options).encode(value)
21
+ end
22
+
23
+ module Encoding #:nodoc:
24
+ class JSONGemEncoder #:nodoc:
25
+ attr_reader :options
26
+
27
+ def initialize(options = nil)
28
+ @options = options || {}
29
+ end
30
+
31
+ # Encode the given object into a JSON string
32
+ def encode(value)
33
+ stringify jsonify value.as_json(options.dup)
34
+ end
35
+
36
+ private
37
+ # Rails does more escaping than the JSON gem natively does (we
38
+ # escape \u2028 and \u2029 and optionally >, <, & to work around
39
+ # certain browser problems).
40
+ ESCAPED_CHARS = {
41
+ "\u2028" => '\u2028',
42
+ "\u2029" => '\u2029',
43
+ '>' => '\u003e',
44
+ '<' => '\u003c',
45
+ '&' => '\u0026',
46
+ }
47
+
48
+ ESCAPE_REGEX_WITH_HTML_ENTITIES = /[\u2028\u2029><&]/u
49
+ ESCAPE_REGEX_WITHOUT_HTML_ENTITIES = /[\u2028\u2029]/u
50
+
51
+ # This class wraps all the strings we see and does the extra escaping
52
+ class EscapedString < String #:nodoc:
53
+ def to_json(*)
54
+ if Encoding.escape_html_entities_in_json
55
+ super.gsub ESCAPE_REGEX_WITH_HTML_ENTITIES, ESCAPED_CHARS
56
+ else
57
+ super.gsub ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, ESCAPED_CHARS
58
+ end
59
+ end
60
+
61
+ def to_s
62
+ self
63
+ end
64
+ end
65
+
66
+ # Mark these as private so we don't leak encoding-specific constructs
67
+ private_constant :ESCAPED_CHARS, :ESCAPE_REGEX_WITH_HTML_ENTITIES,
68
+ :ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, :EscapedString
69
+
70
+ # Convert an object into a "JSON-ready" representation composed of
71
+ # primitives like Hash, Array, String, Numeric, and true/false/nil.
72
+ # Recursively calls #as_json to the object to recursively build a
73
+ # fully JSON-ready object.
74
+ #
75
+ # This allows developers to implement #as_json without having to
76
+ # worry about what base types of objects they are allowed to return
77
+ # or having to remember to call #as_json recursively.
78
+ #
79
+ # Note: the +options+ hash passed to +object.to_json+ is only passed
80
+ # to +object.as_json+, not any of this method's recursive +#as_json+
81
+ # calls.
82
+ def jsonify(value)
83
+ case value
84
+ when String
85
+ EscapedString.new(value)
86
+ when Numeric, NilClass, TrueClass, FalseClass
87
+ value
88
+ when Hash
89
+ Hash[value.map { |k, v| [jsonify(k), jsonify(v)] }]
90
+ when Array
91
+ value.map { |v| jsonify(v) }
92
+ else
93
+ jsonify value.as_json
94
+ end
95
+ end
96
+
97
+ # Encode a "jsonified" Ruby data structure using the JSON gem
98
+ def stringify(jsonified)
99
+ ::JSON.generate(jsonified, quirks_mode: true, max_nesting: false)
100
+ end
101
+ end
102
+
103
+ class << self
104
+ # If true, use ISO 8601 format for dates and times. Otherwise, fall back
105
+ # to the Active Support legacy format.
106
+ attr_accessor :use_standard_json_time_format
107
+
108
+ # If true, encode >, <, & as escaped unicode sequences (e.g. > as \u003e)
109
+ # as a safety measure.
110
+ attr_accessor :escape_html_entities_in_json
111
+
112
+ # Sets the precision of encoded time values.
113
+ # Defaults to 3 (equivalent to millisecond precision)
114
+ attr_accessor :time_precision
115
+
116
+ # Sets the encoder used by Rails to encode Ruby objects into JSON strings
117
+ # in +Object#to_json+ and +CoreExt::JSON.encode+.
118
+ attr_accessor :json_encoder
119
+ end
120
+
121
+ self.use_standard_json_time_format = true
122
+ self.escape_html_entities_in_json = true
123
+ self.json_encoder = JSONGemEncoder
124
+ self.time_precision = 3
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,2 @@
1
+ require 'core_ext/json/decoding'
2
+ require 'core_ext/json/encoding'
@@ -0,0 +1,11 @@
1
+ class Object
2
+ # Makes backticks behave (somewhat more) similarly on all platforms.
3
+ # On win32 `nonexistent_command` raises Errno::ENOENT; on Unix, the
4
+ # spawned shell prints a message to stderr and sets $?. We emulate
5
+ # Unix on the former but not the latter.
6
+ def `(command) #:nodoc:
7
+ super
8
+ rescue Errno::ENOENT => e
9
+ STDERR.puts "#$0: #{e}"
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ require 'core_ext/module/concerning'
2
+
3
+ module Kernel
4
+ # A shortcut to define a toplevel concern, not within a module.
5
+ #
6
+ # See Module::Concerning for more.
7
+ def concern(topic, &module_definition)
8
+ Object.concern topic, &module_definition
9
+ end
10
+ end
@@ -0,0 +1,41 @@
1
+ module Kernel
2
+ # Sets $VERBOSE to nil for the duration of the block and back to its original
3
+ # value afterwards.
4
+ #
5
+ # silence_warnings do
6
+ # value = noisy_call # no warning voiced
7
+ # end
8
+ #
9
+ # noisy_call # warning voiced
10
+ def silence_warnings
11
+ with_warnings(nil) { yield }
12
+ end
13
+
14
+ # Sets $VERBOSE to +true+ for the duration of the block and back to its
15
+ # original value afterwards.
16
+ def enable_warnings
17
+ with_warnings(true) { yield }
18
+ end
19
+
20
+ # Sets $VERBOSE for the duration of the block and back to its original
21
+ # value afterwards.
22
+ def with_warnings(flag)
23
+ old_verbose, $VERBOSE = $VERBOSE, flag
24
+ yield
25
+ ensure
26
+ $VERBOSE = old_verbose
27
+ end
28
+
29
+ # Blocks and ignores any exception passed as argument if raised within the block.
30
+ #
31
+ # suppress(ZeroDivisionError) do
32
+ # 1/0
33
+ # puts 'This code is NOT reached'
34
+ # end
35
+ #
36
+ # puts 'This code gets executed and nothing related to ZeroDivisionError was seen'
37
+ def suppress(*exception_classes)
38
+ yield
39
+ rescue *exception_classes
40
+ end
41
+ end
@@ -0,0 +1,6 @@
1
+ module Kernel
2
+ # class_eval on an object acts like singleton_class.class_eval.
3
+ def class_eval(*args, &block)
4
+ singleton_class.class_eval(*args, &block)
5
+ end
6
+ end
@@ -0,0 +1,4 @@
1
+ require 'core_ext/kernel/agnostics'
2
+ require 'core_ext/kernel/concern'
3
+ require 'core_ext/kernel/reporting'
4
+ require 'core_ext/kernel/singleton_class'
@@ -0,0 +1,30 @@
1
+ require 'core_ext/deprecation/proxy_wrappers'
2
+
3
+ class LoadError
4
+ REGEXPS = [
5
+ /^no such file to load -- (.+)$/i,
6
+ /^Missing \w+ (?:file\s*)?([^\s]+.rb)$/i,
7
+ /^Missing API definition file in (.+)$/i,
8
+ /^cannot load such file -- (.+)$/i,
9
+ ]
10
+
11
+ unless method_defined?(:path)
12
+ # Returns the path which was unable to be loaded.
13
+ def path
14
+ @path ||= begin
15
+ REGEXPS.find do |regex|
16
+ message =~ regex
17
+ end
18
+ $1
19
+ end
20
+ end
21
+ end
22
+
23
+ # Returns true if the given path name (except perhaps for the ".rb"
24
+ # extension) is the missing file which caused the exception to be raised.
25
+ def is_missing?(location)
26
+ location.sub(/\.rb$/, ''.freeze) == path.sub(/\.rb$/, ''.freeze)
27
+ end
28
+ end
29
+
30
+ MissingSourceFile = CoreExt::Deprecation::DeprecatedConstantProxy.new('MissingSourceFile', 'LoadError')
@@ -0,0 +1,57 @@
1
+ require 'core_ext/module/attribute_accessors'
2
+ require 'core_ext/logger_silence'
3
+ require 'logger'
4
+
5
+ module CoreExt
6
+ class Logger < ::Logger
7
+ include LoggerSilence
8
+
9
+ # Broadcasts logs to multiple loggers.
10
+ def self.broadcast(logger) # :nodoc:
11
+ Module.new do
12
+ define_method(:add) do |*args, &block|
13
+ logger.add(*args, &block)
14
+ super(*args, &block)
15
+ end
16
+
17
+ define_method(:<<) do |x|
18
+ logger << x
19
+ super(x)
20
+ end
21
+
22
+ define_method(:close) do
23
+ logger.close
24
+ super()
25
+ end
26
+
27
+ define_method(:progname=) do |name|
28
+ logger.progname = name
29
+ super(name)
30
+ end
31
+
32
+ define_method(:formatter=) do |formatter|
33
+ logger.formatter = formatter
34
+ super(formatter)
35
+ end
36
+
37
+ define_method(:level=) do |level|
38
+ logger.level = level
39
+ super(level)
40
+ end
41
+ end
42
+ end
43
+
44
+ def initialize(*args)
45
+ super
46
+ @formatter = SimpleFormatter.new
47
+ end
48
+
49
+ # Simple formatter which only displays the message.
50
+ class SimpleFormatter < ::Logger::Formatter
51
+ # This method is invoked when a log event occurs
52
+ def call(severity, timestamp, progname, msg)
53
+ "#{String === msg ? msg : msg.inspect}\n"
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,24 @@
1
+ require 'core_ext/concern'
2
+
3
+ module CoreExt::LoggerSilence
4
+ extend CoreExt::Concern
5
+
6
+ included do
7
+ cattr_accessor :silencer
8
+ self.silencer = true
9
+ end
10
+
11
+ # Silences the logger for the duration of the block.
12
+ def silence(temporary_level = Logger::ERROR)
13
+ if silencer
14
+ begin
15
+ old_logger_level, self.level = level, temporary_level
16
+ yield self
17
+ ensure
18
+ self.level = old_logger_level
19
+ end
20
+ else
21
+ yield self
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ module CoreExt
2
+ module MarshalWithAutoloading # :nodoc:
3
+ def load(source)
4
+ super(source)
5
+ rescue ArgumentError, NameError => exc
6
+ if exc.message.match(%r|undefined class/module (.+)|)
7
+ # try loading the class/module
8
+ $1.constantize
9
+ # if it is an IO we need to go back to read the object
10
+ source.rewind if source.respond_to?(:rewind)
11
+ retry
12
+ else
13
+ raise exc
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Marshal.singleton_class.prepend(CoreExt::MarshalWithAutoloading)
@@ -0,0 +1,74 @@
1
+ class Module
2
+ # NOTE: This method is deprecated. Please use <tt>Module#prepend</tt> that
3
+ # comes with Ruby 2.0 or newer instead.
4
+ #
5
+ # Encapsulates the common pattern of:
6
+ #
7
+ # alias_method :foo_without_feature, :foo
8
+ # alias_method :foo, :foo_with_feature
9
+ #
10
+ # With this, you simply do:
11
+ #
12
+ # alias_method_chain :foo, :feature
13
+ #
14
+ # And both aliases are set up for you.
15
+ #
16
+ # Query and bang methods (foo?, foo!) keep the same punctuation:
17
+ #
18
+ # alias_method_chain :foo?, :feature
19
+ #
20
+ # is equivalent to
21
+ #
22
+ # alias_method :foo_without_feature?, :foo?
23
+ # alias_method :foo?, :foo_with_feature?
24
+ #
25
+ # so you can safely chain foo, foo?, foo! and/or foo= with the same feature.
26
+ def alias_method_chain(target, feature)
27
+ CoreExt::Deprecation.warn("alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super.")
28
+
29
+ # Strip out punctuation on predicates, bang or writer methods since
30
+ # e.g. target?_without_feature is not a valid method name.
31
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
32
+ yield(aliased_target, punctuation) if block_given?
33
+
34
+ with_method = "#{aliased_target}_with_#{feature}#{punctuation}"
35
+ without_method = "#{aliased_target}_without_#{feature}#{punctuation}"
36
+
37
+ alias_method without_method, target
38
+ alias_method target, with_method
39
+
40
+ case
41
+ when public_method_defined?(without_method)
42
+ public target
43
+ when protected_method_defined?(without_method)
44
+ protected target
45
+ when private_method_defined?(without_method)
46
+ private target
47
+ end
48
+ end
49
+
50
+ # Allows you to make aliases for attributes, which includes
51
+ # getter, setter, and a predicate.
52
+ #
53
+ # class Content < ActiveRecord::Base
54
+ # # has a title attribute
55
+ # end
56
+ #
57
+ # class Email < Content
58
+ # alias_attribute :subject, :title
59
+ # end
60
+ #
61
+ # e = Email.find(1)
62
+ # e.title # => "Superstars"
63
+ # e.subject # => "Superstars"
64
+ # e.subject? # => true
65
+ # e.subject = "Megastars"
66
+ # e.title # => "Megastars"
67
+ def alias_attribute(new_name, old_name)
68
+ module_eval <<-STR, __FILE__, __LINE__ + 1
69
+ def #{new_name}; self.#{old_name}; end # def subject; self.title; end
70
+ def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end
71
+ def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end
72
+ STR
73
+ end
74
+ end