core_ext 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +3 -0
- data/lib/core_ext/array/access.rb +76 -0
- data/lib/core_ext/array/conversions.rb +211 -0
- data/lib/core_ext/array/extract_options.rb +29 -0
- data/lib/core_ext/array/grouping.rb +116 -0
- data/lib/core_ext/array/inquiry.rb +17 -0
- data/lib/core_ext/array/prepend_and_append.rb +7 -0
- data/lib/core_ext/array/wrap.rb +46 -0
- data/lib/core_ext/array.rb +7 -0
- data/lib/core_ext/array_inquirer.rb +44 -0
- data/lib/core_ext/benchmark.rb +14 -0
- data/lib/core_ext/benchmarkable.rb +49 -0
- data/lib/core_ext/big_decimal/conversions.rb +14 -0
- data/lib/core_ext/big_decimal.rb +1 -0
- data/lib/core_ext/builder.rb +6 -0
- data/lib/core_ext/callbacks.rb +770 -0
- data/lib/core_ext/class/attribute.rb +128 -0
- data/lib/core_ext/class/attribute_accessors.rb +4 -0
- data/lib/core_ext/class/subclasses.rb +42 -0
- data/lib/core_ext/class.rb +2 -0
- data/lib/core_ext/concern.rb +142 -0
- data/lib/core_ext/configurable.rb +148 -0
- data/lib/core_ext/date/acts_like.rb +8 -0
- data/lib/core_ext/date/blank.rb +12 -0
- data/lib/core_ext/date/calculations.rb +143 -0
- data/lib/core_ext/date/conversions.rb +93 -0
- data/lib/core_ext/date/zones.rb +6 -0
- data/lib/core_ext/date.rb +5 -0
- data/lib/core_ext/date_and_time/calculations.rb +328 -0
- data/lib/core_ext/date_and_time/zones.rb +40 -0
- data/lib/core_ext/date_time/acts_like.rb +14 -0
- data/lib/core_ext/date_time/blank.rb +12 -0
- data/lib/core_ext/date_time/calculations.rb +177 -0
- data/lib/core_ext/date_time/conversions.rb +104 -0
- data/lib/core_ext/date_time/zones.rb +6 -0
- data/lib/core_ext/date_time.rb +5 -0
- data/lib/core_ext/deprecation/behaviors.rb +86 -0
- data/lib/core_ext/deprecation/instance_delegator.rb +24 -0
- data/lib/core_ext/deprecation/method_wrappers.rb +70 -0
- data/lib/core_ext/deprecation/proxy_wrappers.rb +149 -0
- data/lib/core_ext/deprecation/reporting.rb +105 -0
- data/lib/core_ext/deprecation.rb +43 -0
- data/lib/core_ext/digest/uuid.rb +51 -0
- data/lib/core_ext/duration.rb +157 -0
- data/lib/core_ext/enumerable.rb +106 -0
- data/lib/core_ext/file/atomic.rb +68 -0
- data/lib/core_ext/file.rb +1 -0
- data/lib/core_ext/hash/compact.rb +20 -0
- data/lib/core_ext/hash/conversions.rb +261 -0
- data/lib/core_ext/hash/deep_merge.rb +38 -0
- data/lib/core_ext/hash/except.rb +22 -0
- data/lib/core_ext/hash/indifferent_access.rb +23 -0
- data/lib/core_ext/hash/keys.rb +170 -0
- data/lib/core_ext/hash/reverse_merge.rb +22 -0
- data/lib/core_ext/hash/slice.rb +48 -0
- data/lib/core_ext/hash/transform_values.rb +29 -0
- data/lib/core_ext/hash.rb +9 -0
- data/lib/core_ext/hash_with_indifferent_access.rb +298 -0
- data/lib/core_ext/inflections.rb +70 -0
- data/lib/core_ext/inflector/inflections.rb +244 -0
- data/lib/core_ext/inflector/methods.rb +381 -0
- data/lib/core_ext/inflector/transliterate.rb +112 -0
- data/lib/core_ext/inflector.rb +7 -0
- data/lib/core_ext/integer/inflections.rb +29 -0
- data/lib/core_ext/integer/multiple.rb +10 -0
- data/lib/core_ext/integer/time.rb +29 -0
- data/lib/core_ext/integer.rb +3 -0
- data/lib/core_ext/json/decoding.rb +67 -0
- data/lib/core_ext/json/encoding.rb +127 -0
- data/lib/core_ext/json.rb +2 -0
- data/lib/core_ext/kernel/agnostics.rb +11 -0
- data/lib/core_ext/kernel/concern.rb +10 -0
- data/lib/core_ext/kernel/reporting.rb +41 -0
- data/lib/core_ext/kernel/singleton_class.rb +6 -0
- data/lib/core_ext/kernel.rb +4 -0
- data/lib/core_ext/load_error.rb +30 -0
- data/lib/core_ext/logger.rb +57 -0
- data/lib/core_ext/logger_silence.rb +24 -0
- data/lib/core_ext/marshal.rb +19 -0
- data/lib/core_ext/module/aliasing.rb +74 -0
- data/lib/core_ext/module/anonymous.rb +28 -0
- data/lib/core_ext/module/attr_internal.rb +36 -0
- data/lib/core_ext/module/attribute_accessors.rb +212 -0
- data/lib/core_ext/module/concerning.rb +135 -0
- data/lib/core_ext/module/delegation.rb +218 -0
- data/lib/core_ext/module/deprecation.rb +23 -0
- data/lib/core_ext/module/introspection.rb +62 -0
- data/lib/core_ext/module/method_transplanting.rb +3 -0
- data/lib/core_ext/module/qualified_const.rb +52 -0
- data/lib/core_ext/module/reachable.rb +8 -0
- data/lib/core_ext/module/remove_method.rb +35 -0
- data/lib/core_ext/module.rb +11 -0
- data/lib/core_ext/multibyte/chars.rb +231 -0
- data/lib/core_ext/multibyte/unicode.rb +388 -0
- data/lib/core_ext/multibyte.rb +21 -0
- data/lib/core_ext/name_error.rb +31 -0
- data/lib/core_ext/numeric/bytes.rb +64 -0
- data/lib/core_ext/numeric/conversions.rb +132 -0
- data/lib/core_ext/numeric/inquiry.rb +26 -0
- data/lib/core_ext/numeric/time.rb +74 -0
- data/lib/core_ext/numeric.rb +4 -0
- data/lib/core_ext/object/acts_like.rb +10 -0
- data/lib/core_ext/object/blank.rb +140 -0
- data/lib/core_ext/object/conversions.rb +4 -0
- data/lib/core_ext/object/deep_dup.rb +53 -0
- data/lib/core_ext/object/duplicable.rb +98 -0
- data/lib/core_ext/object/inclusion.rb +27 -0
- data/lib/core_ext/object/instance_variables.rb +28 -0
- data/lib/core_ext/object/json.rb +199 -0
- data/lib/core_ext/object/to_param.rb +1 -0
- data/lib/core_ext/object/to_query.rb +84 -0
- data/lib/core_ext/object/try.rb +146 -0
- data/lib/core_ext/object/with_options.rb +69 -0
- data/lib/core_ext/object.rb +14 -0
- data/lib/core_ext/option_merger.rb +25 -0
- data/lib/core_ext/ordered_hash.rb +48 -0
- data/lib/core_ext/ordered_options.rb +81 -0
- data/lib/core_ext/range/conversions.rb +34 -0
- data/lib/core_ext/range/each.rb +21 -0
- data/lib/core_ext/range/include_range.rb +23 -0
- data/lib/core_ext/range/overlaps.rb +8 -0
- data/lib/core_ext/range.rb +4 -0
- data/lib/core_ext/regexp.rb +5 -0
- data/lib/core_ext/rescuable.rb +119 -0
- data/lib/core_ext/securerandom.rb +23 -0
- data/lib/core_ext/security_utils.rb +20 -0
- data/lib/core_ext/string/access.rb +104 -0
- data/lib/core_ext/string/behavior.rb +6 -0
- data/lib/core_ext/string/conversions.rb +56 -0
- data/lib/core_ext/string/exclude.rb +11 -0
- data/lib/core_ext/string/filters.rb +102 -0
- data/lib/core_ext/string/indent.rb +43 -0
- data/lib/core_ext/string/inflections.rb +235 -0
- data/lib/core_ext/string/inquiry.rb +13 -0
- data/lib/core_ext/string/multibyte.rb +53 -0
- data/lib/core_ext/string/output_safety.rb +261 -0
- data/lib/core_ext/string/starts_ends_with.rb +4 -0
- data/lib/core_ext/string/strip.rb +23 -0
- data/lib/core_ext/string/zones.rb +14 -0
- data/lib/core_ext/string.rb +13 -0
- data/lib/core_ext/string_inquirer.rb +26 -0
- data/lib/core_ext/tagged_logging.rb +78 -0
- data/lib/core_ext/test_case.rb +88 -0
- data/lib/core_ext/testing/assertions.rb +99 -0
- data/lib/core_ext/testing/autorun.rb +12 -0
- data/lib/core_ext/testing/composite_filter.rb +54 -0
- data/lib/core_ext/testing/constant_lookup.rb +50 -0
- data/lib/core_ext/testing/declarative.rb +26 -0
- data/lib/core_ext/testing/deprecation.rb +36 -0
- data/lib/core_ext/testing/file_fixtures.rb +34 -0
- data/lib/core_ext/testing/isolation.rb +115 -0
- data/lib/core_ext/testing/method_call_assertions.rb +41 -0
- data/lib/core_ext/testing/setup_and_teardown.rb +50 -0
- data/lib/core_ext/testing/stream.rb +42 -0
- data/lib/core_ext/testing/tagged_logging.rb +25 -0
- data/lib/core_ext/testing/time_helpers.rb +134 -0
- data/lib/core_ext/time/acts_like.rb +8 -0
- data/lib/core_ext/time/calculations.rb +284 -0
- data/lib/core_ext/time/conversions.rb +66 -0
- data/lib/core_ext/time/zones.rb +95 -0
- data/lib/core_ext/time.rb +20 -0
- data/lib/core_ext/time_with_zone.rb +503 -0
- data/lib/core_ext/time_zone.rb +464 -0
- data/lib/core_ext/uri.rb +25 -0
- data/lib/core_ext/version.rb +3 -0
- data/lib/core_ext/xml_mini/jdom.rb +181 -0
- data/lib/core_ext/xml_mini/libxml.rb +79 -0
- data/lib/core_ext/xml_mini/libxmlsax.rb +85 -0
- data/lib/core_ext/xml_mini/nokogiri.rb +83 -0
- data/lib/core_ext/xml_mini/nokogirisax.rb +87 -0
- data/lib/core_ext/xml_mini/rexml.rb +130 -0
- data/lib/core_ext/xml_mini.rb +194 -0
- data/lib/core_ext.rb +3 -0
- metadata +310 -0
@@ -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,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,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'
|