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,128 @@
1
+ require 'core_ext/kernel/singleton_class'
2
+ require 'core_ext/module/remove_method'
3
+ require 'core_ext/array/extract_options'
4
+
5
+ class Class
6
+ # Declare a class-level attribute whose value is inheritable by subclasses.
7
+ # Subclasses can change their own value and it will not impact parent class.
8
+ #
9
+ # class Base
10
+ # class_attribute :setting
11
+ # end
12
+ #
13
+ # class Subclass < Base
14
+ # end
15
+ #
16
+ # Base.setting = true
17
+ # Subclass.setting # => true
18
+ # Subclass.setting = false
19
+ # Subclass.setting # => false
20
+ # Base.setting # => true
21
+ #
22
+ # In the above case as long as Subclass does not assign a value to setting
23
+ # by performing <tt>Subclass.setting = _something_ </tt>, <tt>Subclass.setting</tt>
24
+ # would read value assigned to parent class. Once Subclass assigns a value then
25
+ # the value assigned by Subclass would be returned.
26
+ #
27
+ # This matches normal Ruby method inheritance: think of writing an attribute
28
+ # on a subclass as overriding the reader method. However, you need to be aware
29
+ # when using +class_attribute+ with mutable structures as +Array+ or +Hash+.
30
+ # In such cases, you don't want to do changes in places but use setters:
31
+ #
32
+ # Base.setting = []
33
+ # Base.setting # => []
34
+ # Subclass.setting # => []
35
+ #
36
+ # # Appending in child changes both parent and child because it is the same object:
37
+ # Subclass.setting << :foo
38
+ # Base.setting # => [:foo]
39
+ # Subclass.setting # => [:foo]
40
+ #
41
+ # # Use setters to not propagate changes:
42
+ # Base.setting = []
43
+ # Subclass.setting += [:foo]
44
+ # Base.setting # => []
45
+ # Subclass.setting # => [:foo]
46
+ #
47
+ # For convenience, an instance predicate method is defined as well.
48
+ # To skip it, pass <tt>instance_predicate: false</tt>.
49
+ #
50
+ # Subclass.setting? # => false
51
+ #
52
+ # Instances may overwrite the class value in the same way:
53
+ #
54
+ # Base.setting = true
55
+ # object = Base.new
56
+ # object.setting # => true
57
+ # object.setting = false
58
+ # object.setting # => false
59
+ # Base.setting # => true
60
+ #
61
+ # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
62
+ #
63
+ # object.setting # => NoMethodError
64
+ # object.setting? # => NoMethodError
65
+ #
66
+ # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
67
+ #
68
+ # object.setting = false # => NoMethodError
69
+ #
70
+ # To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
71
+ def class_attribute(*attrs)
72
+ options = attrs.extract_options!
73
+ instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
74
+ instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
75
+ instance_predicate = options.fetch(:instance_predicate, true)
76
+
77
+ attrs.each do |name|
78
+ remove_possible_singleton_method(name)
79
+ define_singleton_method(name) { nil }
80
+
81
+ remove_possible_singleton_method("#{name}?")
82
+ define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
83
+
84
+ ivar = "@#{name}"
85
+
86
+ remove_possible_singleton_method("#{name}=")
87
+ define_singleton_method("#{name}=") do |val|
88
+ singleton_class.class_eval do
89
+ remove_possible_method(name)
90
+ define_method(name) { val }
91
+ end
92
+
93
+ if singleton_class?
94
+ class_eval do
95
+ remove_possible_method(name)
96
+ define_method(name) do
97
+ if instance_variable_defined? ivar
98
+ instance_variable_get ivar
99
+ else
100
+ singleton_class.send name
101
+ end
102
+ end
103
+ end
104
+ end
105
+ val
106
+ end
107
+
108
+ if instance_reader
109
+ remove_possible_method name
110
+ define_method(name) do
111
+ if instance_variable_defined?(ivar)
112
+ instance_variable_get ivar
113
+ else
114
+ self.class.public_send name
115
+ end
116
+ end
117
+
118
+ remove_possible_method "#{name}?"
119
+ define_method("#{name}?") { !!public_send(name) } if instance_predicate
120
+ end
121
+
122
+ if instance_writer
123
+ remove_possible_method "#{name}="
124
+ attr_writer name
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,4 @@
1
+ # cattr_* became mattr_* aliases in 7dfbd91b0780fbd6a1dd9bfbc176e10894871d2d,
2
+ # but we keep this around for libraries that directly require it knowing they
3
+ # want cattr_*. No need to deprecate.
4
+ require 'core_ext/module/attribute_accessors'
@@ -0,0 +1,42 @@
1
+ require 'core_ext/module/anonymous'
2
+ require 'core_ext/module/reachable'
3
+
4
+ class Class
5
+ begin
6
+ ObjectSpace.each_object(Class.new) {}
7
+
8
+ def descendants # :nodoc:
9
+ descendants = []
10
+ ObjectSpace.each_object(singleton_class) do |k|
11
+ descendants.unshift k unless k == self
12
+ end
13
+ descendants
14
+ end
15
+ rescue StandardError # JRuby
16
+ def descendants # :nodoc:
17
+ descendants = []
18
+ ObjectSpace.each_object(Class) do |k|
19
+ descendants.unshift k if k < self
20
+ end
21
+ descendants.uniq!
22
+ descendants
23
+ end
24
+ end
25
+
26
+ # Returns an array with the direct children of +self+.
27
+ #
28
+ # Integer.subclasses # => [Fixnum, Bignum]
29
+ #
30
+ # class Foo; end
31
+ # class Bar < Foo; end
32
+ # class Baz < Bar; end
33
+ #
34
+ # Foo.subclasses # => [Bar]
35
+ def subclasses
36
+ subclasses, chain = [], descendants
37
+ chain.each do |k|
38
+ subclasses << k unless chain.any? { |c| c > k }
39
+ end
40
+ subclasses
41
+ end
42
+ end
@@ -0,0 +1,2 @@
1
+ require 'core_ext/class/attribute'
2
+ require 'core_ext/class/subclasses'
@@ -0,0 +1,142 @@
1
+ module CoreExt
2
+ # A typical module looks like this:
3
+ #
4
+ # module M
5
+ # def self.included(base)
6
+ # base.extend ClassMethods
7
+ # base.class_eval do
8
+ # scope :disabled, -> { where(disabled: true) }
9
+ # end
10
+ # end
11
+ #
12
+ # module ClassMethods
13
+ # ...
14
+ # end
15
+ # end
16
+ #
17
+ # By using <tt>CoreExt::Concern</tt> the above module could instead be
18
+ # written as:
19
+ #
20
+ # require 'core_ext/concern'
21
+ #
22
+ # module M
23
+ # extend CoreExt::Concern
24
+ #
25
+ # included do
26
+ # scope :disabled, -> { where(disabled: true) }
27
+ # end
28
+ #
29
+ # class_methods do
30
+ # ...
31
+ # end
32
+ # end
33
+ #
34
+ # Moreover, it gracefully handles module dependencies. Given a +Foo+ module
35
+ # and a +Bar+ module which depends on the former, we would typically write the
36
+ # following:
37
+ #
38
+ # module Foo
39
+ # def self.included(base)
40
+ # base.class_eval do
41
+ # def self.method_injected_by_foo
42
+ # ...
43
+ # end
44
+ # end
45
+ # end
46
+ # end
47
+ #
48
+ # module Bar
49
+ # def self.included(base)
50
+ # base.method_injected_by_foo
51
+ # end
52
+ # end
53
+ #
54
+ # class Host
55
+ # include Foo # We need to include this dependency for Bar
56
+ # include Bar # Bar is the module that Host really needs
57
+ # end
58
+ #
59
+ # But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We
60
+ # could try to hide these from +Host+ directly including +Foo+ in +Bar+:
61
+ #
62
+ # module Bar
63
+ # include Foo
64
+ # def self.included(base)
65
+ # base.method_injected_by_foo
66
+ # end
67
+ # end
68
+ #
69
+ # class Host
70
+ # include Bar
71
+ # end
72
+ #
73
+ # Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt>
74
+ # is the +Bar+ module, not the +Host+ class. With <tt>CoreExt::Concern</tt>,
75
+ # module dependencies are properly resolved:
76
+ #
77
+ # require 'core_ext/concern'
78
+ #
79
+ # module Foo
80
+ # extend CoreExt::Concern
81
+ # included do
82
+ # def self.method_injected_by_foo
83
+ # ...
84
+ # end
85
+ # end
86
+ # end
87
+ #
88
+ # module Bar
89
+ # extend CoreExt::Concern
90
+ # include Foo
91
+ #
92
+ # included do
93
+ # self.method_injected_by_foo
94
+ # end
95
+ # end
96
+ #
97
+ # class Host
98
+ # include Bar # It works, now Bar takes care of its dependencies
99
+ # end
100
+ module Concern
101
+ class MultipleIncludedBlocks < StandardError #:nodoc:
102
+ def initialize
103
+ super "Cannot define multiple 'included' blocks for a Concern"
104
+ end
105
+ end
106
+
107
+ def self.extended(base) #:nodoc:
108
+ base.instance_variable_set(:@_dependencies, [])
109
+ end
110
+
111
+ def append_features(base)
112
+ if base.instance_variable_defined?(:@_dependencies)
113
+ base.instance_variable_get(:@_dependencies) << self
114
+ return false
115
+ else
116
+ return false if base < self
117
+ @_dependencies.each { |dep| base.include(dep) }
118
+ super
119
+ base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
120
+ base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
121
+ end
122
+ end
123
+
124
+ def included(base = nil, &block)
125
+ if base.nil?
126
+ raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)
127
+
128
+ @_included_block = block
129
+ else
130
+ super
131
+ end
132
+ end
133
+
134
+ def class_methods(&class_methods_module_definition)
135
+ mod = const_defined?(:ClassMethods, false) ?
136
+ const_get(:ClassMethods) :
137
+ const_set(:ClassMethods, Module.new)
138
+
139
+ mod.module_eval(&class_methods_module_definition)
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,148 @@
1
+ require 'core_ext/concern'
2
+ require 'core_ext/ordered_options'
3
+ require 'core_ext/array/extract_options'
4
+
5
+ module CoreExt
6
+ # Configurable provides a <tt>config</tt> method to store and retrieve
7
+ # configuration options as an <tt>OrderedHash</tt>.
8
+ module Configurable
9
+ extend CoreExt::Concern
10
+
11
+ class Configuration < CoreExt::InheritableOptions
12
+ def compile_methods!
13
+ self.class.compile_methods!(keys)
14
+ end
15
+
16
+ # Compiles reader methods so we don't have to go through method_missing.
17
+ def self.compile_methods!(keys)
18
+ keys.reject { |m| method_defined?(m) }.each do |key|
19
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
20
+ def #{key}; _get(#{key.inspect}); end
21
+ RUBY
22
+ end
23
+ end
24
+ end
25
+
26
+ module ClassMethods
27
+ def config
28
+ @_config ||= if respond_to?(:superclass) && superclass.respond_to?(:config)
29
+ superclass.config.inheritable_copy
30
+ else
31
+ # create a new "anonymous" class that will host the compiled reader methods
32
+ Class.new(Configuration).new
33
+ end
34
+ end
35
+
36
+ def configure
37
+ yield config
38
+ end
39
+
40
+ # Allows you to add shortcut so that you don't have to refer to attribute
41
+ # through config. Also look at the example for config to contrast.
42
+ #
43
+ # Defines both class and instance config accessors.
44
+ #
45
+ # class User
46
+ # include CoreExt::Configurable
47
+ # config_accessor :allowed_access
48
+ # end
49
+ #
50
+ # User.allowed_access # => nil
51
+ # User.allowed_access = false
52
+ # User.allowed_access # => false
53
+ #
54
+ # user = User.new
55
+ # user.allowed_access # => false
56
+ # user.allowed_access = true
57
+ # user.allowed_access # => true
58
+ #
59
+ # User.allowed_access # => false
60
+ #
61
+ # The attribute name must be a valid method name in Ruby.
62
+ #
63
+ # class User
64
+ # include CoreExt::Configurable
65
+ # config_accessor :"1_Badname"
66
+ # end
67
+ # # => NameError: invalid config attribute name
68
+ #
69
+ # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
70
+ # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
71
+ #
72
+ # class User
73
+ # include CoreExt::Configurable
74
+ # config_accessor :allowed_access, instance_reader: false, instance_writer: false
75
+ # end
76
+ #
77
+ # User.allowed_access = false
78
+ # User.allowed_access # => false
79
+ #
80
+ # User.new.allowed_access = true # => NoMethodError
81
+ # User.new.allowed_access # => NoMethodError
82
+ #
83
+ # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
84
+ #
85
+ # class User
86
+ # include CoreExt::Configurable
87
+ # config_accessor :allowed_access, instance_accessor: false
88
+ # end
89
+ #
90
+ # User.allowed_access = false
91
+ # User.allowed_access # => false
92
+ #
93
+ # User.new.allowed_access = true # => NoMethodError
94
+ # User.new.allowed_access # => NoMethodError
95
+ #
96
+ # Also you can pass a block to set up the attribute with a default value.
97
+ #
98
+ # class User
99
+ # include CoreExt::Configurable
100
+ # config_accessor :hair_colors do
101
+ # [:brown, :black, :blonde, :red]
102
+ # end
103
+ # end
104
+ #
105
+ # User.hair_colors # => [:brown, :black, :blonde, :red]
106
+ def config_accessor(*names)
107
+ options = names.extract_options!
108
+
109
+ names.each do |name|
110
+ raise NameError.new('invalid config attribute name') unless name =~ /\A[_A-Za-z]\w*\z/
111
+
112
+ reader, reader_line = "def #{name}; config.#{name}; end", __LINE__
113
+ writer, writer_line = "def #{name}=(value); config.#{name} = value; end", __LINE__
114
+
115
+ singleton_class.class_eval reader, __FILE__, reader_line
116
+ singleton_class.class_eval writer, __FILE__, writer_line
117
+
118
+ unless options[:instance_accessor] == false
119
+ class_eval reader, __FILE__, reader_line unless options[:instance_reader] == false
120
+ class_eval writer, __FILE__, writer_line unless options[:instance_writer] == false
121
+ end
122
+ send("#{name}=", yield) if block_given?
123
+ end
124
+ end
125
+ private :config_accessor
126
+ end
127
+
128
+ # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
129
+ #
130
+ # require 'active_support/configurable'
131
+ #
132
+ # class User
133
+ # include CoreExt::Configurable
134
+ # end
135
+ #
136
+ # user = User.new
137
+ #
138
+ # user.config.allowed_access = true
139
+ # user.config.level = 1
140
+ #
141
+ # user.config.allowed_access # => true
142
+ # user.config.level # => 1
143
+ def config
144
+ @_config ||= self.class.config.inheritable_copy
145
+ end
146
+ end
147
+ end
148
+
@@ -0,0 +1,8 @@
1
+ require 'core_ext/object/acts_like'
2
+
3
+ class Date
4
+ # Duck-types as a Date-like class. See Object#acts_like?.
5
+ def acts_like_date?
6
+ true
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ require 'date'
2
+
3
+ class Date #:nodoc:
4
+ # No Date is blank:
5
+ #
6
+ # Date.today.blank? # => false
7
+ #
8
+ # @return [false]
9
+ def blank?
10
+ false
11
+ end
12
+ end
@@ -0,0 +1,143 @@
1
+ require 'date'
2
+ require 'core_ext/duration'
3
+ require 'core_ext/object/acts_like'
4
+ require 'core_ext/date/zones'
5
+ require 'core_ext/time/zones'
6
+ require 'core_ext/date_and_time/calculations'
7
+
8
+ class Date
9
+ include DateAndTime::Calculations
10
+
11
+ class << self
12
+ attr_accessor :beginning_of_week_default
13
+
14
+ # Returns the week start (e.g. :monday) for the current request, if this has been set (via Date.beginning_of_week=).
15
+ # If <tt>Date.beginning_of_week</tt> has not been set for the current request, returns the week start specified in <tt>config.beginning_of_week</tt>.
16
+ # If no config.beginning_of_week was specified, returns :monday.
17
+ def beginning_of_week
18
+ Thread.current[:beginning_of_week] || beginning_of_week_default || :monday
19
+ end
20
+
21
+ # Sets <tt>Date.beginning_of_week</tt> to a week start (e.g. :monday) for current request/thread.
22
+ #
23
+ # This method accepts any of the following day symbols:
24
+ # :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
25
+ def beginning_of_week=(week_start)
26
+ Thread.current[:beginning_of_week] = find_beginning_of_week!(week_start)
27
+ end
28
+
29
+ # Returns week start day symbol (e.g. :monday), or raises an +ArgumentError+ for invalid day symbol.
30
+ def find_beginning_of_week!(week_start)
31
+ raise ArgumentError, "Invalid beginning of week: #{week_start}" unless ::Date::DAYS_INTO_WEEK.key?(week_start)
32
+ week_start
33
+ end
34
+
35
+ # Returns a new Date representing the date 1 day ago (i.e. yesterday's date).
36
+ def yesterday
37
+ ::Date.current.yesterday
38
+ end
39
+
40
+ # Returns a new Date representing the date 1 day after today (i.e. tomorrow's date).
41
+ def tomorrow
42
+ ::Date.current.tomorrow
43
+ end
44
+
45
+ # Returns Time.zone.today when <tt>Time.zone</tt> or <tt>config.time_zone</tt> are set, otherwise just returns Date.today.
46
+ def current
47
+ ::Time.zone ? ::Time.zone.today : ::Date.today
48
+ end
49
+ end
50
+
51
+ # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
52
+ # and then subtracts the specified number of seconds.
53
+ def ago(seconds)
54
+ in_time_zone.since(-seconds)
55
+ end
56
+
57
+ # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
58
+ # and then adds the specified number of seconds
59
+ def since(seconds)
60
+ in_time_zone.since(seconds)
61
+ end
62
+ alias :in :since
63
+
64
+ # Converts Date to a Time (or DateTime if necessary) with the time portion set to the beginning of the day (0:00)
65
+ def beginning_of_day
66
+ in_time_zone
67
+ end
68
+ alias :midnight :beginning_of_day
69
+ alias :at_midnight :beginning_of_day
70
+ alias :at_beginning_of_day :beginning_of_day
71
+
72
+ # Converts Date to a Time (or DateTime if necessary) with the time portion set to the middle of the day (12:00)
73
+ def middle_of_day
74
+ in_time_zone.middle_of_day
75
+ end
76
+ alias :midday :middle_of_day
77
+ alias :noon :middle_of_day
78
+ alias :at_midday :middle_of_day
79
+ alias :at_noon :middle_of_day
80
+ alias :at_middle_of_day :middle_of_day
81
+
82
+ # Converts Date to a Time (or DateTime if necessary) with the time portion set to the end of the day (23:59:59)
83
+ def end_of_day
84
+ in_time_zone.end_of_day
85
+ end
86
+ alias :at_end_of_day :end_of_day
87
+
88
+ def plus_with_duration(other) #:nodoc:
89
+ if CoreExt::Duration === other
90
+ other.since(self)
91
+ else
92
+ plus_without_duration(other)
93
+ end
94
+ end
95
+ alias_method :plus_without_duration, :+
96
+ alias_method :+, :plus_with_duration
97
+
98
+ def minus_with_duration(other) #:nodoc:
99
+ if CoreExt::Duration === other
100
+ plus_with_duration(-other)
101
+ else
102
+ minus_without_duration(other)
103
+ end
104
+ end
105
+ alias_method :minus_without_duration, :-
106
+ alias_method :-, :minus_with_duration
107
+
108
+ # Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
109
+ # any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>.
110
+ def advance(options)
111
+ options = options.dup
112
+ d = self
113
+ d = d >> options.delete(:years) * 12 if options[:years]
114
+ d = d >> options.delete(:months) if options[:months]
115
+ d = d + options.delete(:weeks) * 7 if options[:weeks]
116
+ d = d + options.delete(:days) if options[:days]
117
+ d
118
+ end
119
+
120
+ # Returns a new Date where one or more of the elements have been changed according to the +options+ parameter.
121
+ # The +options+ parameter is a hash with a combination of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>.
122
+ #
123
+ # Date.new(2007, 5, 12).change(day: 1) # => Date.new(2007, 5, 1)
124
+ # Date.new(2007, 5, 12).change(year: 2005, month: 1) # => Date.new(2005, 1, 12)
125
+ def change(options)
126
+ ::Date.new(
127
+ options.fetch(:year, year),
128
+ options.fetch(:month, month),
129
+ options.fetch(:day, day)
130
+ )
131
+ end
132
+
133
+ # Allow Date to be compared with Time by converting to DateTime and relying on the <=> from there.
134
+ def compare_with_coercion(other)
135
+ if other.is_a?(Time)
136
+ self.to_datetime <=> other
137
+ else
138
+ compare_without_coercion(other)
139
+ end
140
+ end
141
+ alias_method :compare_without_coercion, :<=>
142
+ alias_method :<=>, :compare_with_coercion
143
+ end