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,74 @@
1
+ require 'core_ext/duration'
2
+ require 'core_ext/time/calculations'
3
+ require 'core_ext/time/acts_like'
4
+ require 'core_ext/date/calculations'
5
+ require 'core_ext/date/acts_like'
6
+
7
+ class Numeric
8
+ # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
9
+ #
10
+ # These methods use Time#advance for precise date calculations when using from_now, ago, etc.
11
+ # as well as adding or subtracting their results from a Time object. For example:
12
+ #
13
+ # # equivalent to Time.current.advance(months: 1)
14
+ # 1.month.from_now
15
+ #
16
+ # # equivalent to Time.current.advance(years: 2)
17
+ # 2.years.from_now
18
+ #
19
+ # # equivalent to Time.current.advance(months: 4, years: 5)
20
+ # (4.months + 5.years).from_now
21
+ def seconds
22
+ CoreExt::Duration.new(self, [[:seconds, self]])
23
+ end
24
+ alias :second :seconds
25
+
26
+ # Returns a Duration instance matching the number of minutes provided.
27
+ #
28
+ # 2.minutes # => 120 seconds
29
+ def minutes
30
+ CoreExt::Duration.new(self * 60, [[:seconds, self * 60]])
31
+ end
32
+ alias :minute :minutes
33
+
34
+ # Returns a Duration instance matching the number of hours provided.
35
+ #
36
+ # 2.hours # => 7_200 seconds
37
+ def hours
38
+ CoreExt::Duration.new(self * 3600, [[:seconds, self * 3600]])
39
+ end
40
+ alias :hour :hours
41
+
42
+ # Returns a Duration instance matching the number of days provided.
43
+ #
44
+ # 2.days # => 2 days
45
+ def days
46
+ CoreExt::Duration.new(self * 24.hours, [[:days, self]])
47
+ end
48
+ alias :day :days
49
+
50
+ # Returns a Duration instance matching the number of weeks provided.
51
+ #
52
+ # 2.weeks # => 14 days
53
+ def weeks
54
+ CoreExt::Duration.new(self * 7.days, [[:days, self * 7]])
55
+ end
56
+ alias :week :weeks
57
+
58
+ # Returns a Duration instance matching the number of fortnights provided.
59
+ #
60
+ # 2.fortnights # => 28 days
61
+ def fortnights
62
+ CoreExt::Duration.new(self * 2.weeks, [[:days, self * 14]])
63
+ end
64
+ alias :fortnight :fortnights
65
+
66
+ # Returns the number of milliseconds equivalent to the seconds provided.
67
+ # Used with the standard time durations, like 1.hour.in_milliseconds --
68
+ # so we can feed them to JavaScript functions like getTime().
69
+ #
70
+ # 2.in_milliseconds # => 2_000
71
+ def in_milliseconds
72
+ self * 1000
73
+ end
74
+ end
@@ -0,0 +1,4 @@
1
+ require 'core_ext/numeric/bytes'
2
+ require 'core_ext/numeric/time'
3
+ require 'core_ext/numeric/inquiry'
4
+ require 'core_ext/numeric/conversions'
@@ -0,0 +1,10 @@
1
+ class Object
2
+ # A duck-type assistant method. For example, Active Support extends Date
3
+ # to define an <tt>acts_like_date?</tt> method, and extends Time to define
4
+ # <tt>acts_like_time?</tt>. As a result, we can do <tt>x.acts_like?(:time)</tt> and
5
+ # <tt>x.acts_like?(:date)</tt> to do duck-type-safe comparisons, since classes that
6
+ # we want to act like Time simply need to define an <tt>acts_like_time?</tt> method.
7
+ def acts_like?(duck)
8
+ respond_to? :"acts_like_#{duck}?"
9
+ end
10
+ end
@@ -0,0 +1,140 @@
1
+ class Object
2
+ # An object is blank if it's false, empty, or a whitespace string.
3
+ # For example, +false+, '', ' ', +nil+, [], and {} are all blank.
4
+ #
5
+ # This simplifies
6
+ #
7
+ # !address || address.empty?
8
+ #
9
+ # to
10
+ #
11
+ # address.blank?
12
+ #
13
+ # @return [true, false]
14
+ def blank?
15
+ respond_to?(:empty?) ? !!empty? : !self
16
+ end
17
+
18
+ # An object is present if it's not blank.
19
+ #
20
+ # @return [true, false]
21
+ def present?
22
+ !blank?
23
+ end
24
+
25
+ # Returns the receiver if it's present otherwise returns +nil+.
26
+ # <tt>object.presence</tt> is equivalent to
27
+ #
28
+ # object.present? ? object : nil
29
+ #
30
+ # For example, something like
31
+ #
32
+ # state = params[:state] if params[:state].present?
33
+ # country = params[:country] if params[:country].present?
34
+ # region = state || country || 'US'
35
+ #
36
+ # becomes
37
+ #
38
+ # region = params[:state].presence || params[:country].presence || 'US'
39
+ #
40
+ # @return [Object]
41
+ def presence
42
+ self if present?
43
+ end
44
+ end
45
+
46
+ class NilClass
47
+ # +nil+ is blank:
48
+ #
49
+ # nil.blank? # => true
50
+ #
51
+ # @return [true]
52
+ def blank?
53
+ true
54
+ end
55
+ end
56
+
57
+ class FalseClass
58
+ # +false+ is blank:
59
+ #
60
+ # false.blank? # => true
61
+ #
62
+ # @return [true]
63
+ def blank?
64
+ true
65
+ end
66
+ end
67
+
68
+ class TrueClass
69
+ # +true+ is not blank:
70
+ #
71
+ # true.blank? # => false
72
+ #
73
+ # @return [false]
74
+ def blank?
75
+ false
76
+ end
77
+ end
78
+
79
+ class Array
80
+ # An array is blank if it's empty:
81
+ #
82
+ # [].blank? # => true
83
+ # [1,2,3].blank? # => false
84
+ #
85
+ # @return [true, false]
86
+ alias_method :blank?, :empty?
87
+ end
88
+
89
+ class Hash
90
+ # A hash is blank if it's empty:
91
+ #
92
+ # {}.blank? # => true
93
+ # { key: 'value' }.blank? # => false
94
+ #
95
+ # @return [true, false]
96
+ alias_method :blank?, :empty?
97
+ end
98
+
99
+ class String
100
+ BLANK_RE = /\A[[:space:]]*\z/
101
+
102
+ # A string is blank if it's empty or contains whitespaces only:
103
+ #
104
+ # ''.blank? # => true
105
+ # ' '.blank? # => true
106
+ # "\t\n\r".blank? # => true
107
+ # ' blah '.blank? # => false
108
+ #
109
+ # Unicode whitespace is supported:
110
+ #
111
+ # "\u00a0".blank? # => true
112
+ #
113
+ # @return [true, false]
114
+ def blank?
115
+ BLANK_RE === self
116
+ end
117
+ end
118
+
119
+ class Numeric #:nodoc:
120
+ # No number is blank:
121
+ #
122
+ # 1.blank? # => false
123
+ # 0.blank? # => false
124
+ #
125
+ # @return [false]
126
+ def blank?
127
+ false
128
+ end
129
+ end
130
+
131
+ class Time #:nodoc:
132
+ # No Time is blank:
133
+ #
134
+ # Time.now.blank? # => false
135
+ #
136
+ # @return [false]
137
+ def blank?
138
+ false
139
+ end
140
+ end
@@ -0,0 +1,4 @@
1
+ require 'core_ext/object/to_param'
2
+ require 'core_ext/object/to_query'
3
+ require 'core_ext/array/conversions'
4
+ require 'core_ext/hash/conversions'
@@ -0,0 +1,53 @@
1
+ require 'core_ext/object/duplicable'
2
+
3
+ class Object
4
+ # Returns a deep copy of object if it's duplicable. If it's
5
+ # not duplicable, returns +self+.
6
+ #
7
+ # object = Object.new
8
+ # dup = object.deep_dup
9
+ # dup.instance_variable_set(:@a, 1)
10
+ #
11
+ # object.instance_variable_defined?(:@a) # => false
12
+ # dup.instance_variable_defined?(:@a) # => true
13
+ def deep_dup
14
+ duplicable? ? dup : self
15
+ end
16
+ end
17
+
18
+ class Array
19
+ # Returns a deep copy of array.
20
+ #
21
+ # array = [1, [2, 3]]
22
+ # dup = array.deep_dup
23
+ # dup[1][2] = 4
24
+ #
25
+ # array[1][2] # => nil
26
+ # dup[1][2] # => 4
27
+ def deep_dup
28
+ map(&:deep_dup)
29
+ end
30
+ end
31
+
32
+ class Hash
33
+ # Returns a deep copy of hash.
34
+ #
35
+ # hash = { a: { b: 'b' } }
36
+ # dup = hash.deep_dup
37
+ # dup[:a][:c] = 'c'
38
+ #
39
+ # hash[:a][:c] # => nil
40
+ # dup[:a][:c] # => "c"
41
+ def deep_dup
42
+ hash = dup
43
+ each_pair do |key, value|
44
+ if key.frozen? && ::String === key
45
+ hash[key] = value.deep_dup
46
+ else
47
+ hash.delete(key)
48
+ hash[key.deep_dup] = value.deep_dup
49
+ end
50
+ end
51
+ hash
52
+ end
53
+ end
@@ -0,0 +1,98 @@
1
+ #--
2
+ # Most objects are cloneable, but not all. For example you can't dup +nil+:
3
+ #
4
+ # nil.dup # => TypeError: can't dup NilClass
5
+ #
6
+ # Classes may signal their instances are not duplicable removing +dup+/+clone+
7
+ # or raising exceptions from them. So, to dup an arbitrary object you normally
8
+ # use an optimistic approach and are ready to catch an exception, say:
9
+ #
10
+ # arbitrary_object.dup rescue object
11
+ #
12
+ # Rails dups objects in a few critical spots where they are not that arbitrary.
13
+ # That rescue is very expensive (like 40 times slower than a predicate), and it
14
+ # is often triggered.
15
+ #
16
+ # That's why we hardcode the following cases and check duplicable? instead of
17
+ # using that rescue idiom.
18
+ #++
19
+ class Object
20
+ # Can you safely dup this object?
21
+ #
22
+ # False for +nil+, +false+, +true+, symbol, number, method objects;
23
+ # true otherwise.
24
+ def duplicable?
25
+ true
26
+ end
27
+ end
28
+
29
+ class NilClass
30
+ # +nil+ is not duplicable:
31
+ #
32
+ # nil.duplicable? # => false
33
+ # nil.dup # => TypeError: can't dup NilClass
34
+ def duplicable?
35
+ false
36
+ end
37
+ end
38
+
39
+ class FalseClass
40
+ # +false+ is not duplicable:
41
+ #
42
+ # false.duplicable? # => false
43
+ # false.dup # => TypeError: can't dup FalseClass
44
+ def duplicable?
45
+ false
46
+ end
47
+ end
48
+
49
+ class TrueClass
50
+ # +true+ is not duplicable:
51
+ #
52
+ # true.duplicable? # => false
53
+ # true.dup # => TypeError: can't dup TrueClass
54
+ def duplicable?
55
+ false
56
+ end
57
+ end
58
+
59
+ class Symbol
60
+ # Symbols are not duplicable:
61
+ #
62
+ # :my_symbol.duplicable? # => false
63
+ # :my_symbol.dup # => TypeError: can't dup Symbol
64
+ def duplicable?
65
+ false
66
+ end
67
+ end
68
+
69
+ class Numeric
70
+ # Numbers are not duplicable:
71
+ #
72
+ # 3.duplicable? # => false
73
+ # 3.dup # => TypeError: can't dup Fixnum
74
+ def duplicable?
75
+ false
76
+ end
77
+ end
78
+
79
+ require 'bigdecimal'
80
+ class BigDecimal
81
+ # BigDecimals are duplicable:
82
+ #
83
+ # BigDecimal.new("1.2").duplicable? # => true
84
+ # BigDecimal.new("1.2").dup # => #<BigDecimal:...,'0.12E1',18(18)>
85
+ def duplicable?
86
+ true
87
+ end
88
+ end
89
+
90
+ class Method
91
+ # Methods are not duplicable:
92
+ #
93
+ # method(:puts).duplicable? # => false
94
+ # method(:puts).dup # => TypeError: allocator undefined for Method
95
+ def duplicable?
96
+ false
97
+ end
98
+ end
@@ -0,0 +1,27 @@
1
+ class Object
2
+ # Returns true if this object is included in the argument. Argument must be
3
+ # any object which responds to +#include?+. Usage:
4
+ #
5
+ # characters = ["Konata", "Kagami", "Tsukasa"]
6
+ # "Konata".in?(characters) # => true
7
+ #
8
+ # This will throw an +ArgumentError+ if the argument doesn't respond
9
+ # to +#include?+.
10
+ def in?(another_object)
11
+ another_object.include?(self)
12
+ rescue NoMethodError
13
+ raise ArgumentError.new("The parameter passed to #in? must respond to #include?")
14
+ end
15
+
16
+ # Returns the receiver if it's included in the argument otherwise returns +nil+.
17
+ # Argument must be any object which responds to +#include?+. Usage:
18
+ #
19
+ # params[:bucket_type].presence_in %w( project calendar )
20
+ #
21
+ # This will throw an +ArgumentError+ if the argument doesn't respond to +#include?+.
22
+ #
23
+ # @return [Object]
24
+ def presence_in(another_object)
25
+ self.in?(another_object) ? self : nil
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ class Object
2
+ # Returns a hash with string keys that maps instance variable names without "@" to their
3
+ # corresponding values.
4
+ #
5
+ # class C
6
+ # def initialize(x, y)
7
+ # @x, @y = x, y
8
+ # end
9
+ # end
10
+ #
11
+ # C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
12
+ def instance_values
13
+ Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
14
+ end
15
+
16
+ # Returns an array of instance variable names as strings including "@".
17
+ #
18
+ # class C
19
+ # def initialize(x, y)
20
+ # @x, @y = x, y
21
+ # end
22
+ # end
23
+ #
24
+ # C.new(0, 1).instance_variable_names # => ["@y", "@x"]
25
+ def instance_variable_names
26
+ instance_variables.map(&:to_s)
27
+ end
28
+ end
@@ -0,0 +1,199 @@
1
+ # Hack to load json gem first so we can overwrite its to_json.
2
+ require 'json'
3
+ require 'time'
4
+ require 'bigdecimal'
5
+ require 'core_ext/big_decimal/conversions' # for #to_s
6
+ require 'core_ext/hash/except'
7
+ require 'core_ext/hash/slice'
8
+ require 'core_ext/object/instance_variables'
9
+ require 'core_ext/time/conversions'
10
+ require 'core_ext/date_time/conversions'
11
+ require 'core_ext/date/conversions'
12
+
13
+ # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
14
+ # their default behavior. That said, we need to define the basic to_json method in all of them,
15
+ # otherwise they will always use to_json gem implementation, which is backwards incompatible in
16
+ # several cases (for instance, the JSON implementation for Hash does not work) with inheritance
17
+ # and consequently classes as CoreExt::OrderedHash cannot be serialized to json.
18
+ #
19
+ # On the other hand, we should avoid conflict with ::JSON.{generate,dump}(obj). Unfortunately, the
20
+ # JSON gem's encoder relies on its own to_json implementation to encode objects. Since it always
21
+ # passes a ::JSON::State object as the only argument to to_json, we can detect that and forward the
22
+ # calls to the original to_json method.
23
+ #
24
+ # It should be noted that when using ::JSON.{generate,dump} directly, CoreExt's encoder is
25
+ # bypassed completely. This means that as_json won't be invoked and the JSON gem will simply
26
+ # ignore any options it does not natively understand. This also means that ::JSON.{generate,dump}
27
+ # should give exactly the same results with or without active support.
28
+
29
+ module CoreExt
30
+ module ToJsonWithCoreExtEncoder # :nodoc:
31
+ def to_json(options = nil)
32
+ if options.is_a?(::JSON::State)
33
+ # Called from JSON.{generate,dump}, forward it to JSON gem's to_json
34
+ super(options)
35
+ else
36
+ # to_json is being invoked directly, use CoreExt's encoder
37
+ CoreExt::JSON.encode(self, options)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].reverse_each do |klass|
44
+ klass.prepend(CoreExt::ToJsonWithCoreExtEncoder)
45
+ end
46
+
47
+ class Object
48
+ def as_json(options = nil) #:nodoc:
49
+ if respond_to?(:to_hash)
50
+ to_hash.as_json(options)
51
+ else
52
+ instance_values.as_json(options)
53
+ end
54
+ end
55
+ end
56
+
57
+ class Struct #:nodoc:
58
+ def as_json(options = nil)
59
+ Hash[members.zip(values)].as_json(options)
60
+ end
61
+ end
62
+
63
+ class TrueClass
64
+ def as_json(options = nil) #:nodoc:
65
+ self
66
+ end
67
+ end
68
+
69
+ class FalseClass
70
+ def as_json(options = nil) #:nodoc:
71
+ self
72
+ end
73
+ end
74
+
75
+ class NilClass
76
+ def as_json(options = nil) #:nodoc:
77
+ self
78
+ end
79
+ end
80
+
81
+ class String
82
+ def as_json(options = nil) #:nodoc:
83
+ self
84
+ end
85
+ end
86
+
87
+ class Symbol
88
+ def as_json(options = nil) #:nodoc:
89
+ to_s
90
+ end
91
+ end
92
+
93
+ class Numeric
94
+ def as_json(options = nil) #:nodoc:
95
+ self
96
+ end
97
+ end
98
+
99
+ class Float
100
+ # Encoding Infinity or NaN to JSON should return "null". The default returns
101
+ # "Infinity" or "NaN" which are not valid JSON.
102
+ def as_json(options = nil) #:nodoc:
103
+ finite? ? self : nil
104
+ end
105
+ end
106
+
107
+ class BigDecimal
108
+ # A BigDecimal would be naturally represented as a JSON number. Most libraries,
109
+ # however, parse non-integer JSON numbers directly as floats. Clients using
110
+ # those libraries would get in general a wrong number and no way to recover
111
+ # other than manually inspecting the string with the JSON code itself.
112
+ #
113
+ # That's why a JSON string is returned. The JSON literal is not numeric, but
114
+ # if the other end knows by contract that the data is supposed to be a
115
+ # BigDecimal, it still has the chance to post-process the string and get the
116
+ # real value.
117
+ def as_json(options = nil) #:nodoc:
118
+ finite? ? to_s : nil
119
+ end
120
+ end
121
+
122
+ class Regexp
123
+ def as_json(options = nil) #:nodoc:
124
+ to_s
125
+ end
126
+ end
127
+
128
+ module Enumerable
129
+ def as_json(options = nil) #:nodoc:
130
+ to_a.as_json(options)
131
+ end
132
+ end
133
+
134
+ class Range
135
+ def as_json(options = nil) #:nodoc:
136
+ to_s
137
+ end
138
+ end
139
+
140
+ class Array
141
+ def as_json(options = nil) #:nodoc:
142
+ map { |v| options ? v.as_json(options.dup) : v.as_json }
143
+ end
144
+ end
145
+
146
+ class Hash
147
+ def as_json(options = nil) #:nodoc:
148
+ # create a subset of the hash by applying :only or :except
149
+ subset = if options
150
+ if attrs = options[:only]
151
+ slice(*Array(attrs))
152
+ elsif attrs = options[:except]
153
+ except(*Array(attrs))
154
+ else
155
+ self
156
+ end
157
+ else
158
+ self
159
+ end
160
+
161
+ Hash[subset.map { |k, v| [k.to_s, options ? v.as_json(options.dup) : v.as_json] }]
162
+ end
163
+ end
164
+
165
+ class Time
166
+ def as_json(options = nil) #:nodoc:
167
+ if CoreExt::JSON::Encoding.use_standard_json_time_format
168
+ xmlschema(CoreExt::JSON::Encoding.time_precision)
169
+ else
170
+ %(#{strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
171
+ end
172
+ end
173
+ end
174
+
175
+ class Date
176
+ def as_json(options = nil) #:nodoc:
177
+ if CoreExt::JSON::Encoding.use_standard_json_time_format
178
+ strftime("%Y-%m-%d")
179
+ else
180
+ strftime("%Y/%m/%d")
181
+ end
182
+ end
183
+ end
184
+
185
+ class DateTime
186
+ def as_json(options = nil) #:nodoc:
187
+ if CoreExt::JSON::Encoding.use_standard_json_time_format
188
+ xmlschema(CoreExt::JSON::Encoding.time_precision)
189
+ else
190
+ strftime('%Y/%m/%d %H:%M:%S %z')
191
+ end
192
+ end
193
+ end
194
+
195
+ class Process::Status #:nodoc:
196
+ def as_json(options = nil)
197
+ { :exitstatus => exitstatus, :pid => pid }
198
+ end
199
+ end
@@ -0,0 +1 @@
1
+ require 'core_ext/object/to_query'