core_ext 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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