activesupport-refinements 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 (120) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +6 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +32 -0
  5. data/Rakefile +1 -0
  6. data/activesupport-refinements.gemspec +21 -0
  7. data/lib/active_support/refinements/core_ext/array.rb +7 -0
  8. data/lib/active_support/refinements/core_ext/array/access.rb +56 -0
  9. data/lib/active_support/refinements/core_ext/array/conversions.rb +224 -0
  10. data/lib/active_support/refinements/core_ext/array/extract_options.rb +31 -0
  11. data/lib/active_support/refinements/core_ext/array/grouping.rb +101 -0
  12. data/lib/active_support/refinements/core_ext/array/prepend_and_append.rb +9 -0
  13. data/lib/active_support/refinements/core_ext/array/uniq_by.rb +21 -0
  14. data/lib/active_support/refinements/core_ext/array/wrap.rb +48 -0
  15. data/lib/active_support/refinements/core_ext/benchmark.rb +7 -0
  16. data/lib/active_support/refinements/core_ext/big_decimal.rb +1 -0
  17. data/lib/active_support/refinements/core_ext/big_decimal/conversions.rb +32 -0
  18. data/lib/active_support/refinements/core_ext/class.rb +4 -0
  19. data/lib/active_support/refinements/core_ext/class/attribute.rb +119 -0
  20. data/lib/active_support/refinements/core_ext/class/attribute_accessors.rb +172 -0
  21. data/lib/active_support/refinements/core_ext/class/delegating_attributes.rb +42 -0
  22. data/lib/active_support/refinements/core_ext/class/subclasses.rb +44 -0
  23. data/lib/active_support/refinements/core_ext/date.rb +5 -0
  24. data/lib/active_support/refinements/core_ext/date/acts_like.rb +10 -0
  25. data/lib/active_support/refinements/core_ext/date/calculations.rb +123 -0
  26. data/lib/active_support/refinements/core_ext/date/conversions.rb +86 -0
  27. data/lib/active_support/refinements/core_ext/date/zones.rb +17 -0
  28. data/lib/active_support/refinements/core_ext/date_and_time/calculations.rb +232 -0
  29. data/lib/active_support/refinements/core_ext/date_time.rb +4 -0
  30. data/lib/active_support/refinements/core_ext/date_time/acts_like.rb +15 -0
  31. data/lib/active_support/refinements/core_ext/date_time/calculations.rb +143 -0
  32. data/lib/active_support/refinements/core_ext/date_time/conversions.rb +93 -0
  33. data/lib/active_support/refinements/core_ext/date_time/zones.rb +26 -0
  34. data/lib/active_support/refinements/core_ext/enumerable.rb +82 -0
  35. data/lib/active_support/refinements/core_ext/exception.rb +5 -0
  36. data/lib/active_support/refinements/core_ext/file.rb +1 -0
  37. data/lib/active_support/refinements/core_ext/file/atomic.rb +60 -0
  38. data/lib/active_support/refinements/core_ext/hash.rb +8 -0
  39. data/lib/active_support/refinements/core_ext/hash/conversions.rb +161 -0
  40. data/lib/active_support/refinements/core_ext/hash/deep_merge.rb +29 -0
  41. data/lib/active_support/refinements/core_ext/hash/diff.rb +15 -0
  42. data/lib/active_support/refinements/core_ext/hash/except.rb +17 -0
  43. data/lib/active_support/refinements/core_ext/hash/indifferent_access.rb +24 -0
  44. data/lib/active_support/refinements/core_ext/hash/keys.rb +140 -0
  45. data/lib/active_support/refinements/core_ext/hash/reverse_merge.rb +24 -0
  46. data/lib/active_support/refinements/core_ext/hash/slice.rb +42 -0
  47. data/lib/active_support/refinements/core_ext/integer.rb +3 -0
  48. data/lib/active_support/refinements/core_ext/integer/inflections.rb +31 -0
  49. data/lib/active_support/refinements/core_ext/integer/multiple.rb +12 -0
  50. data/lib/active_support/refinements/core_ext/integer/time.rb +43 -0
  51. data/lib/active_support/refinements/core_ext/kernel.rb +4 -0
  52. data/lib/active_support/refinements/core_ext/kernel/agnostics.rb +13 -0
  53. data/lib/active_support/refinements/core_ext/kernel/debugger.rb +12 -0
  54. data/lib/active_support/refinements/core_ext/kernel/reporting.rb +97 -0
  55. data/lib/active_support/refinements/core_ext/kernel/singleton_class.rb +8 -0
  56. data/lib/active_support/refinements/core_ext/load_error.rb +27 -0
  57. data/lib/active_support/refinements/core_ext/logger.rb +86 -0
  58. data/lib/active_support/refinements/core_ext/module.rb +10 -0
  59. data/lib/active_support/refinements/core_ext/module/aliasing.rb +69 -0
  60. data/lib/active_support/refinements/core_ext/module/anonymous.rb +21 -0
  61. data/lib/active_support/refinements/core_ext/module/attr_internal.rb +40 -0
  62. data/lib/active_support/refinements/core_ext/module/attribute_accessors.rb +68 -0
  63. data/lib/active_support/refinements/core_ext/module/delegation.rb +172 -0
  64. data/lib/active_support/refinements/core_ext/module/deprecation.rb +27 -0
  65. data/lib/active_support/refinements/core_ext/module/introspection.rb +80 -0
  66. data/lib/active_support/refinements/core_ext/module/qualified_const.rb +54 -0
  67. data/lib/active_support/refinements/core_ext/module/reachable.rb +10 -0
  68. data/lib/active_support/refinements/core_ext/module/remove_method.rb +14 -0
  69. data/lib/active_support/refinements/core_ext/name_error.rb +20 -0
  70. data/lib/active_support/refinements/core_ext/numeric.rb +3 -0
  71. data/lib/active_support/refinements/core_ext/numeric/bytes.rb +46 -0
  72. data/lib/active_support/refinements/core_ext/numeric/conversions.rb +137 -0
  73. data/lib/active_support/refinements/core_ext/numeric/time.rb +81 -0
  74. data/lib/active_support/refinements/core_ext/object.rb +14 -0
  75. data/lib/active_support/refinements/core_ext/object/acts_like.rb +12 -0
  76. data/lib/active_support/refinements/core_ext/object/blank.rb +107 -0
  77. data/lib/active_support/refinements/core_ext/object/conversions.rb +4 -0
  78. data/lib/active_support/refinements/core_ext/object/deep_dup.rb +48 -0
  79. data/lib/active_support/refinements/core_ext/object/duplicable.rb +92 -0
  80. data/lib/active_support/refinements/core_ext/object/inclusion.rb +27 -0
  81. data/lib/active_support/refinements/core_ext/object/instance_variables.rb +30 -0
  82. data/lib/active_support/refinements/core_ext/object/to_json.rb +27 -0
  83. data/lib/active_support/refinements/core_ext/object/to_param.rb +60 -0
  84. data/lib/active_support/refinements/core_ext/object/to_query.rb +29 -0
  85. data/lib/active_support/refinements/core_ext/object/try.rb +72 -0
  86. data/lib/active_support/refinements/core_ext/object/with_options.rb +44 -0
  87. data/lib/active_support/refinements/core_ext/proc.rb +19 -0
  88. data/lib/active_support/refinements/core_ext/range.rb +3 -0
  89. data/lib/active_support/refinements/core_ext/range/conversions.rb +21 -0
  90. data/lib/active_support/refinements/core_ext/range/include_range.rb +23 -0
  91. data/lib/active_support/refinements/core_ext/range/overlaps.rb +10 -0
  92. data/lib/active_support/refinements/core_ext/regexp.rb +7 -0
  93. data/lib/active_support/refinements/core_ext/string.rb +13 -0
  94. data/lib/active_support/refinements/core_ext/string/access.rb +106 -0
  95. data/lib/active_support/refinements/core_ext/string/behavior.rb +8 -0
  96. data/lib/active_support/refinements/core_ext/string/conversions.rb +60 -0
  97. data/lib/active_support/refinements/core_ext/string/encoding.rb +10 -0
  98. data/lib/active_support/refinements/core_ext/string/exclude.rb +13 -0
  99. data/lib/active_support/refinements/core_ext/string/filters.rb +54 -0
  100. data/lib/active_support/refinements/core_ext/string/indent.rb +45 -0
  101. data/lib/active_support/refinements/core_ext/string/inflections.rb +214 -0
  102. data/lib/active_support/refinements/core_ext/string/inquiry.rb +15 -0
  103. data/lib/active_support/refinements/core_ext/string/multibyte.rb +58 -0
  104. data/lib/active_support/refinements/core_ext/string/output_safety.rb +194 -0
  105. data/lib/active_support/refinements/core_ext/string/starts_ends_with.rb +6 -0
  106. data/lib/active_support/refinements/core_ext/string/strip.rb +28 -0
  107. data/lib/active_support/refinements/core_ext/string/xchar.rb +18 -0
  108. data/lib/active_support/refinements/core_ext/time.rb +5 -0
  109. data/lib/active_support/refinements/core_ext/time/acts_like.rb +10 -0
  110. data/lib/active_support/refinements/core_ext/time/calculations.rb +251 -0
  111. data/lib/active_support/refinements/core_ext/time/conversions.rb +65 -0
  112. data/lib/active_support/refinements/core_ext/time/marshal.rb +30 -0
  113. data/lib/active_support/refinements/core_ext/time/zones.rb +98 -0
  114. data/lib/active_support/refinements/core_ext/uri.rb +28 -0
  115. data/lib/activesupport-refinements.rb +9 -0
  116. data/lib/activesupport-refinements/version.rb +5 -0
  117. data/refine_core_ext.rb +45 -0
  118. data/spec/hwia_spec.rb +15 -0
  119. data/spec/try_spec.rb +18 -0
  120. metadata +182 -0
@@ -0,0 +1,15 @@
1
+ module StringExt; end; module StringExt::Inquiry
2
+ require 'active_support/string_inquirer'
3
+
4
+ refine String do
5
+ # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
6
+ # which gives you a prettier way to test for equality.
7
+ #
8
+ # env = 'production'.inquiry
9
+ # env.production? # => true
10
+ # env.development? # => false
11
+ def inquiry
12
+ ActiveSupport::StringInquirer.new(self)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,58 @@
1
+ module StringExt; end; module StringExt::Multibyte
2
+ # encoding: utf-8
3
+ require 'active_support/multibyte'
4
+
5
+ refine String do
6
+ # == Multibyte proxy
7
+ #
8
+ # +mb_chars+ is a multibyte safe proxy for string methods.
9
+ #
10
+ # In Ruby 1.8 and older it creates and returns an instance of the ActiveSupport::Multibyte::Chars class which
11
+ # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
12
+ # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
13
+ #
14
+ # name = 'Claus Müller'
15
+ # name.reverse # => "rell??M sualC"
16
+ # name.length # => 13
17
+ #
18
+ # name.mb_chars.reverse.to_s # => "rellüM sualC"
19
+ # name.mb_chars.length # => 12
20
+ #
21
+ # In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that
22
+ # it becomes easy to run one version of your code on multiple Ruby versions.
23
+ #
24
+ # == Method chaining
25
+ #
26
+ # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
27
+ # method chaining on the result of any of these methods.
28
+ #
29
+ # name.mb_chars.reverse.length # => 12
30
+ #
31
+ # == Interoperability and configuration
32
+ #
33
+ # The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
34
+ # String and Char work like expected. The bang! methods change the internal string representation in the Chars
35
+ # object. Interoperability problems can be resolved easily with a +to_s+ call.
36
+ #
37
+ # For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars. For
38
+ # information about how to change the default Multibyte behavior see ActiveSupport::Multibyte.
39
+ def mb_chars
40
+ if ActiveSupport::Multibyte.proxy_class.consumes?(self)
41
+ ActiveSupport::Multibyte.proxy_class.new(self)
42
+ else
43
+ self
44
+ end
45
+ end
46
+
47
+ def is_utf8?
48
+ case encoding
49
+ when Encoding::UTF_8
50
+ valid_encoding?
51
+ when Encoding::ASCII_8BIT, Encoding::US_ASCII
52
+ dup.force_encoding(Encoding::UTF_8).valid_encoding?
53
+ else
54
+ false
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,194 @@
1
+ require 'erb'
2
+ require 'active_support/refinements/core_ext/kernel/singleton_class'
3
+
4
+ class ERB
5
+ module Util
6
+ HTML_ESCAPE = { '&' => '&amp;', '>' => '&gt;', '<' => '&lt;', '"' => '&quot;', "'" => '&#39;' }
7
+ JSON_ESCAPE = { '&' => '\u0026', '>' => '\u003E', '<' => '\u003C' }
8
+ HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+));)/
9
+ JSON_ESCAPE_REGEXP = /[&"><]/
10
+
11
+ # A utility method for escaping HTML tag characters.
12
+ # This method is also aliased as <tt>h</tt>.
13
+ #
14
+ # In your ERB templates, use this method to escape any unsafe content. For example:
15
+ # <%=h @person.name %>
16
+ #
17
+ # puts html_escape('is a > 0 & a < 10?')
18
+ # # => is a &gt; 0 &amp; a &lt; 10?
19
+ def html_escape(s)
20
+ s = s.to_s
21
+ if s.html_safe?
22
+ s
23
+ else
24
+ s.gsub(/[&"'><]/, HTML_ESCAPE).html_safe
25
+ end
26
+ end
27
+
28
+ # Aliasing twice issues a warning "discarding old...". Remove first to avoid it.
29
+ remove_method(:h)
30
+ alias h html_escape
31
+
32
+ module_function :h
33
+
34
+ singleton_class.send(:remove_method, :html_escape)
35
+ module_function :html_escape
36
+
37
+ # A utility method for escaping HTML without affecting existing escaped entities.
38
+ #
39
+ # html_escape_once('1 < 2 &amp; 3')
40
+ # # => "1 &lt; 2 &amp; 3"
41
+ #
42
+ # html_escape_once('&lt;&lt; Accept & Checkout')
43
+ # # => "&lt;&lt; Accept &amp; Checkout"
44
+ def html_escape_once(s)
45
+ result = s.to_s.gsub(HTML_ESCAPE_ONCE_REGEXP) { |special| HTML_ESCAPE[special] }
46
+ s.html_safe? ? result.html_safe : result
47
+ end
48
+
49
+ module_function :html_escape_once
50
+
51
+ # A utility method for escaping HTML entities in JSON strings
52
+ # using \uXXXX JavaScript escape sequences for string literals:
53
+ #
54
+ # json_escape('is a > 0 & a < 10?')
55
+ # # => is a \u003E 0 \u0026 a \u003C 10?
56
+ #
57
+ # Note that after this operation is performed the output is not
58
+ # valid JSON. In particular double quotes are removed:
59
+ #
60
+ # json_escape('{"name":"john","created_at":"2010-04-28T01:39:31Z","id":1}')
61
+ # # => {name:john,created_at:2010-04-28T01:39:31Z,id:1}
62
+ def json_escape(s)
63
+ result = s.to_s.gsub(JSON_ESCAPE_REGEXP) { |special| JSON_ESCAPE[special] }
64
+ s.html_safe? ? result.html_safe : result
65
+ end
66
+
67
+ module_function :json_escape
68
+ end
69
+ end
70
+
71
+ class Object
72
+ def html_safe?
73
+ false
74
+ end
75
+ end
76
+
77
+ class Numeric
78
+ def html_safe?
79
+ true
80
+ end
81
+ end
82
+
83
+ module ActiveSupport #:nodoc:
84
+ class SafeBuffer < String
85
+ UNSAFE_STRING_METHODS = %w(
86
+ capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
87
+ slice squeeze strip sub succ swapcase tr tr_s upcase prepend
88
+ )
89
+
90
+ alias_method :original_concat, :concat
91
+ private :original_concat
92
+
93
+ class SafeConcatError < StandardError
94
+ def initialize
95
+ super 'Could not concatenate to the buffer because it is not html safe.'
96
+ end
97
+ end
98
+
99
+ def [](*args)
100
+ if args.size < 2
101
+ super
102
+ else
103
+ if html_safe?
104
+ new_safe_buffer = super
105
+ new_safe_buffer.instance_eval { @html_safe = true }
106
+ new_safe_buffer
107
+ else
108
+ to_str[*args]
109
+ end
110
+ end
111
+ end
112
+
113
+ def safe_concat(value)
114
+ raise SafeConcatError unless html_safe?
115
+ original_concat(value)
116
+ end
117
+
118
+ def initialize(*)
119
+ @html_safe = true
120
+ super
121
+ end
122
+
123
+ def initialize_copy(other)
124
+ super
125
+ @html_safe = other.html_safe?
126
+ end
127
+
128
+ def clone_empty
129
+ self[0, 0]
130
+ end
131
+
132
+ def concat(value)
133
+ if !html_safe? || value.html_safe?
134
+ super(value)
135
+ else
136
+ super(ERB::Util.h(value))
137
+ end
138
+ end
139
+ alias << concat
140
+
141
+ def +(other)
142
+ dup.concat(other)
143
+ end
144
+
145
+ def %(args)
146
+ args = Array(args).map do |arg|
147
+ if !html_safe? || arg.html_safe?
148
+ arg
149
+ else
150
+ ERB::Util.h(arg)
151
+ end
152
+ end
153
+
154
+ self.class.new(super(args))
155
+ end
156
+
157
+ def html_safe?
158
+ defined?(@html_safe) && @html_safe
159
+ end
160
+
161
+ def to_s
162
+ self
163
+ end
164
+
165
+ def to_param
166
+ to_str
167
+ end
168
+
169
+ def encode_with(coder)
170
+ coder.represent_scalar nil, to_str
171
+ end
172
+
173
+ UNSAFE_STRING_METHODS.each do |unsafe_method|
174
+ if 'String'.respond_to?(unsafe_method)
175
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
176
+ def #{unsafe_method}(*args, &block) # def capitalize(*args, &block)
177
+ to_str.#{unsafe_method}(*args, &block) # to_str.capitalize(*args, &block)
178
+ end # end
179
+
180
+ def #{unsafe_method}!(*args) # def capitalize!(*args)
181
+ @html_safe = false # @html_safe = false
182
+ super # super
183
+ end # end
184
+ EOT
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ class String
191
+ def html_safe
192
+ ActiveSupport::SafeBuffer.new(self)
193
+ end
194
+ end
@@ -0,0 +1,6 @@
1
+ module StringExt; end; module StringExt::StartsEndsWith
2
+ refine String do
3
+ # alias_method :starts_with?, :start_with?
4
+ # alias_method :ends_with?, :end_with?
5
+ end
6
+ end
@@ -0,0 +1,28 @@
1
+ module StringExt; end; module StringExt::Strip
2
+ require 'active_support/refinements/core_ext/object/try'
3
+
4
+ refine String do
5
+ # Strips indentation in heredocs.
6
+ #
7
+ # For example in
8
+ #
9
+ # if options[:usage]
10
+ # puts <<-USAGE.strip_heredoc
11
+ # This command does such and such.
12
+ #
13
+ # Supported options are:
14
+ # -h This message
15
+ # ...
16
+ # USAGE
17
+ # end
18
+ #
19
+ # the user would see the usage message aligned against the left margin.
20
+ #
21
+ # Technically, it looks for the least indented line in the whole string, and removes
22
+ # that amount of leading whitespace.
23
+ def strip_heredoc
24
+ indent = scan(/^[ \t]*(?=\S)/).min.try(:size) || 0
25
+ gsub(/^[ \t]{#{indent}}/, '')
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ begin
2
+ # See http://fast-xs.rubyforge.org/ by Eric Wong.
3
+ # Also included with hpricot.
4
+ require 'fast_xs'
5
+ rescue LoadError
6
+ # fast_xs extension unavailable
7
+ else
8
+ begin
9
+ require 'builder'
10
+ rescue LoadError
11
+ # builder demands the first shot at defining String#to_xs
12
+ end
13
+
14
+ class String
15
+ alias_method :original_xs, :to_xs if method_defined?(:to_xs)
16
+ alias_method :to_xs, :fast_xs
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ require 'active_support/refinements/core_ext/time/acts_like'
2
+ require 'active_support/refinements/core_ext/time/calculations'
3
+ require 'active_support/refinements/core_ext/time/conversions'
4
+ require 'active_support/refinements/core_ext/time/marshal'
5
+ require 'active_support/refinements/core_ext/time/zones'
@@ -0,0 +1,10 @@
1
+ module TimeExt; end; module TimeExt::ActsLike
2
+ require 'active_support/refinements/core_ext/object/acts_like'
3
+
4
+ refine Time do
5
+ # Duck-types as a Time-like class. See Object#acts_like?.
6
+ def acts_like_time?
7
+ true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,251 @@
1
+ module TimeExt; end; module TimeExt::Calculations
2
+ require 'active_support/duration'
3
+ require 'active_support/refinements/core_ext/time/conversions'
4
+ require 'active_support/time_with_zone'
5
+ require 'active_support/refinements/core_ext/time/zones'
6
+ require 'active_support/refinements/core_ext/date_and_time/calculations'
7
+
8
+ refine Time do
9
+ include DateAndTime::Calculations
10
+
11
+ COMMON_YEAR_DAYS_IN_MONTH = [nil, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
12
+
13
+ class << self
14
+ # Overriding case equality method so that it returns true for ActiveSupport::TimeWithZone instances
15
+ def ===(other)
16
+ super || (self == Time && other.is_a?(ActiveSupport::TimeWithZone))
17
+ end
18
+
19
+ # Return the number of days in the given month.
20
+ # If no year is specified, it will use the current year.
21
+ def days_in_month(month, year = now.year)
22
+ if month == 2 && ::Date.gregorian_leap?(year)
23
+ 29
24
+ else
25
+ COMMON_YEAR_DAYS_IN_MONTH[month]
26
+ end
27
+ end
28
+
29
+ # Returns a new Time if requested year can be accommodated by Ruby's Time class
30
+ # (i.e., if year is within either 1970..2038 or 1902..2038, depending on system architecture);
31
+ # otherwise returns a DateTime.
32
+ def time_with_datetime_fallback(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
33
+ time = ::Time.send(utc_or_local, year, month, day, hour, min, sec, usec)
34
+
35
+ # This check is needed because Time.utc(y) returns a time object in the 2000s for 0 <= y <= 138.
36
+ if time.year == year
37
+ time
38
+ else
39
+ ::DateTime.civil_from_format(utc_or_local, year, month, day, hour, min, sec)
40
+ end
41
+ rescue
42
+ ::DateTime.civil_from_format(utc_or_local, year, month, day, hour, min, sec)
43
+ end
44
+
45
+ # Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:utc</tt>.
46
+ def utc_time(*args)
47
+ time_with_datetime_fallback(:utc, *args)
48
+ end
49
+
50
+ # Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:local</tt>.
51
+ def local_time(*args)
52
+ time_with_datetime_fallback(:local, *args)
53
+ end
54
+
55
+ # Returns <tt>Time.zone.now</tt> when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns <tt>Time.now</tt>.
56
+ def current
57
+ ::Time.zone ? ::Time.zone.now : ::Time.now
58
+ end
59
+ end
60
+
61
+ # Seconds since midnight: Time.now.seconds_since_midnight
62
+ def seconds_since_midnight
63
+ to_i - change(:hour => 0).to_i + (usec / 1.0e+6)
64
+ end
65
+
66
+ # Returns a new Time where one or more of the elements have been changed according
67
+ # to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
68
+ # <tt>:sec</tt>, <tt>:usec</tt>) reset cascadingly, so if only the hour is passed,
69
+ # then minute, sec, and usec is set to 0. If the hour and minute is passed, then
70
+ # sec and usec is set to 0. The +options+ parameter takes a hash with any of these
71
+ # keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>,
72
+ # <tt>:sec</tt>, <tt>:usec</tt>.
73
+ #
74
+ # Time.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => Time.new(2012, 8, 1, 22, 35, 0)
75
+ # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => Time.new(1981, 8, 1, 22, 35, 0)
76
+ # Time.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => Time.new(1981, 8, 29, 0, 0, 0)
77
+ def change(options)
78
+ new_year = options.fetch(:year, year)
79
+ new_month = options.fetch(:month, month)
80
+ new_day = options.fetch(:day, day)
81
+ new_hour = options.fetch(:hour, hour)
82
+ new_min = options.fetch(:min, options[:hour] ? 0 : min)
83
+ new_sec = options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec)
84
+ new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
85
+
86
+ if utc?
87
+ ::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
88
+ elsif zone
89
+ ::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec, new_usec)
90
+ else
91
+ ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec + (new_usec.to_r / 1000000), utc_offset)
92
+ end
93
+ end
94
+
95
+ # Uses Date to provide precise Time calculations for years, months, and days.
96
+ # The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
97
+ # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
98
+ # <tt>:minutes</tt>, <tt>:seconds</tt>.
99
+ def advance(options)
100
+ unless options[:weeks].nil?
101
+ options[:weeks], partial_weeks = options[:weeks].divmod(1)
102
+ options[:days] = options.fetch(:days, 0) + 7 * partial_weeks
103
+ end
104
+
105
+ unless options[:days].nil?
106
+ options[:days], partial_days = options[:days].divmod(1)
107
+ options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
108
+ end
109
+
110
+ d = to_date.advance(options)
111
+ time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
112
+ seconds_to_advance = \
113
+ options.fetch(:seconds, 0) +
114
+ options.fetch(:minutes, 0) * 60 +
115
+ options.fetch(:hours, 0) * 3600
116
+
117
+ if seconds_to_advance.zero?
118
+ time_advanced_by_date
119
+ else
120
+ time_advanced_by_date.since(seconds_to_advance)
121
+ end
122
+ end
123
+
124
+ # Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension
125
+ def ago(seconds)
126
+ since(-seconds)
127
+ end
128
+
129
+ # Returns a new Time representing the time a number of seconds since the instance time
130
+ def since(seconds)
131
+ self + seconds
132
+ rescue
133
+ to_datetime.since(seconds)
134
+ end
135
+ # alias :in :since
136
+
137
+ # Returns a new Time representing the start of the day (0:00)
138
+ def beginning_of_day
139
+ #(self - seconds_since_midnight).change(usec: 0)
140
+ change(:hour => 0)
141
+ end
142
+ # alias :midnight :beginning_of_day
143
+ # alias :at_midnight :beginning_of_day
144
+ # alias :at_beginning_of_day :beginning_of_day
145
+
146
+ # Returns a new Time representing the end of the day, 23:59:59.999999 (.999999999 in ruby1.9)
147
+ def end_of_day
148
+ change(
149
+ :hour => 23,
150
+ :min => 59,
151
+ :sec => 59,
152
+ :usec => Rational(999999999, 1000)
153
+ )
154
+ end
155
+
156
+ # Returns a new Time representing the start of the hour (x:00)
157
+ def beginning_of_hour
158
+ change(:min => 0)
159
+ end
160
+ # alias :at_beginning_of_hour :beginning_of_hour
161
+
162
+ # Returns a new Time representing the end of the hour, x:59:59.999999 (.999999999 in ruby1.9)
163
+ def end_of_hour
164
+ change(
165
+ :min => 59,
166
+ :sec => 59,
167
+ :usec => Rational(999999999, 1000)
168
+ )
169
+ end
170
+
171
+ # Returns a Range representing the whole day of the current time.
172
+ def all_day
173
+ beginning_of_day..end_of_day
174
+ end
175
+
176
+ # Returns a Range representing the whole week of the current time.
177
+ # Week starts on start_day, default is <tt>Date.week_start</tt> or <tt>config.week_start</tt> when set.
178
+ def all_week(start_day = Date.beginning_of_week)
179
+ beginning_of_week(start_day)..end_of_week(start_day)
180
+ end
181
+
182
+ # Returns a Range representing the whole month of the current time.
183
+ def all_month
184
+ beginning_of_month..end_of_month
185
+ end
186
+
187
+ # Returns a Range representing the whole quarter of the current time.
188
+ def all_quarter
189
+ beginning_of_quarter..end_of_quarter
190
+ end
191
+
192
+ # Returns a Range representing the whole year of the current time.
193
+ def all_year
194
+ beginning_of_year..end_of_year
195
+ end
196
+
197
+ def plus_with_duration(other) #:nodoc:
198
+ if ActiveSupport::Duration === other
199
+ other.since(self)
200
+ else
201
+ plus_without_duration(other)
202
+ end
203
+ end
204
+ # alias_method :plus_without_duration, :+
205
+ # alias_method :+, :plus_with_duration
206
+
207
+ def minus_with_duration(other) #:nodoc:
208
+ if ActiveSupport::Duration === other
209
+ other.until(self)
210
+ else
211
+ minus_without_duration(other)
212
+ end
213
+ end
214
+ # alias_method :minus_without_duration, :-
215
+ # alias_method :-, :minus_with_duration
216
+
217
+ # Time#- can also be used to determine the number of seconds between two Time instances.
218
+ # We're layering on additional behavior so that ActiveSupport::TimeWithZone instances
219
+ # are coerced into values that Time#- will recognize
220
+ def minus_with_coercion(other)
221
+ other = other.comparable_time if other.respond_to?(:comparable_time)
222
+ other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
223
+ end
224
+ # alias_method :minus_without_coercion, :-
225
+ # alias_method :-, :minus_with_coercion
226
+
227
+ # Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
228
+ # can be chronologically compared with a Time
229
+ def compare_with_coercion(other)
230
+ # we're avoiding Time#to_datetime cause it's expensive
231
+ if other.is_a?(Time)
232
+ compare_without_coercion(other.to_time)
233
+ else
234
+ to_datetime <=> other
235
+ end
236
+ end
237
+ # alias_method :compare_without_coercion, :<=>
238
+ # alias_method :<=>, :compare_with_coercion
239
+
240
+ # Layers additional behavior on Time#eql? so that ActiveSupport::TimeWithZone instances
241
+ # can be eql? to an equivalent Time
242
+ def eql_with_coercion(other)
243
+ # if other is an ActiveSupport::TimeWithZone, coerce a Time instance from it so we can do eql? comparison
244
+ other = other.comparable_time if other.respond_to?(:comparable_time)
245
+ eql_without_coercion(other)
246
+ end
247
+ # alias_method :eql_without_coercion, :eql?
248
+ # alias_method :eql?, :eql_with_coercion
249
+
250
+ end
251
+ end