motion-support 0.1.0 → 0.2.0
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.
- data/.gitignore +3 -0
- data/Gemfile +1 -1
- data/README.md +231 -2
- data/Rakefile +3 -3
- data/app/app_delegate.rb +0 -2
- data/examples/Inflector/.gitignore +16 -0
- data/examples/Inflector/Gemfile +5 -0
- data/examples/Inflector/Rakefile +13 -0
- data/examples/Inflector/app/app_delegate.rb +8 -0
- data/examples/Inflector/app/inflections.rb +5 -0
- data/examples/Inflector/app/inflector_view_controller.rb +120 -0
- data/examples/Inflector/app/words_view_controller.rb +101 -0
- data/examples/Inflector/resources/Default-568h@2x.png +0 -0
- data/examples/Inflector/spec/main_spec.rb +9 -0
- data/lib/motion-support/core_ext/array.rb +13 -0
- data/lib/motion-support/core_ext/class.rb +8 -0
- data/lib/motion-support/core_ext/hash.rb +16 -0
- data/lib/motion-support/core_ext/integer.rb +9 -0
- data/lib/motion-support/core_ext/module.rb +14 -0
- data/lib/motion-support/core_ext/numeric.rb +8 -0
- data/lib/motion-support/core_ext/object.rb +14 -0
- data/lib/motion-support/core_ext/range.rb +8 -0
- data/lib/motion-support/core_ext/string.rb +14 -0
- data/lib/motion-support/core_ext/time.rb +19 -0
- data/lib/motion-support/core_ext.rb +3 -0
- data/lib/motion-support/inflector.rb +12 -156
- data/lib/motion-support.rb +5 -5
- data/motion/_stdlib/cgi.rb +22 -0
- data/motion/_stdlib/date.rb +77 -0
- data/motion/_stdlib/time.rb +19 -0
- data/motion/core_ext/array/access.rb +28 -0
- data/motion/core_ext/array/conversions.rb +86 -0
- data/motion/core_ext/array/extract_options.rb +11 -0
- data/motion/core_ext/array/grouping.rb +99 -0
- data/motion/core_ext/array/prepend_and_append.rb +7 -0
- data/motion/core_ext/array/wrap.rb +45 -0
- data/{lib/motion-support → motion/core_ext}/array.rb +0 -4
- data/motion/core_ext/class/attribute.rb +119 -0
- data/motion/core_ext/class/attribute_accessors.rb +168 -0
- data/motion/core_ext/date/acts_like.rb +8 -0
- data/motion/core_ext/date/calculations.rb +117 -0
- data/motion/core_ext/date/conversions.rb +56 -0
- data/motion/core_ext/date_and_time/calculations.rb +232 -0
- data/motion/core_ext/enumerable.rb +90 -0
- data/motion/core_ext/hash/deep_merge.rb +27 -0
- data/motion/core_ext/hash/except.rb +15 -0
- data/motion/core_ext/hash/indifferent_access.rb +19 -0
- data/motion/core_ext/hash/keys.rb +138 -0
- data/motion/core_ext/hash/reverse_merge.rb +22 -0
- data/motion/core_ext/hash/slice.rb +40 -0
- data/motion/core_ext/integer/inflections.rb +27 -0
- data/motion/core_ext/integer/multiple.rb +10 -0
- data/motion/core_ext/integer/time.rb +41 -0
- data/{lib/motion-support → motion/core_ext}/metaclass.rb +0 -0
- data/motion/core_ext/module/aliasing.rb +69 -0
- data/motion/core_ext/module/anonymous.rb +19 -0
- data/motion/core_ext/module/attr_internal.rb +38 -0
- data/motion/core_ext/module/attribute_accessors.rb +64 -0
- data/motion/core_ext/module/delegation.rb +175 -0
- data/motion/core_ext/module/introspection.rb +60 -0
- data/motion/core_ext/module/reachable.rb +5 -0
- data/motion/core_ext/module/remove_method.rb +12 -0
- data/motion/core_ext/ns_dictionary.rb +11 -0
- data/motion/core_ext/numeric/bytes.rb +44 -0
- data/motion/core_ext/numeric/conversions.rb +7 -0
- data/motion/core_ext/numeric/time.rb +75 -0
- data/motion/core_ext/object/acts_like.rb +10 -0
- data/motion/core_ext/object/blank.rb +105 -0
- data/motion/core_ext/object/deep_dup.rb +44 -0
- data/motion/core_ext/object/duplicable.rb +83 -0
- data/motion/core_ext/object/instance_variables.rb +28 -0
- data/motion/core_ext/object/to_param.rb +58 -0
- data/motion/core_ext/object/to_query.rb +26 -0
- data/motion/core_ext/object/try.rb +78 -0
- data/motion/core_ext/range/include_range.rb +23 -0
- data/motion/core_ext/range/overlaps.rb +8 -0
- data/motion/core_ext/regexp.rb +5 -0
- data/motion/core_ext/string/access.rb +104 -0
- data/motion/core_ext/string/behavior.rb +6 -0
- data/motion/core_ext/string/exclude.rb +11 -0
- data/motion/core_ext/string/filters.rb +55 -0
- data/motion/core_ext/string/indent.rb +43 -0
- data/motion/core_ext/string/inflections.rb +195 -0
- data/motion/core_ext/string/starts_ends_with.rb +4 -0
- data/motion/core_ext/string/strip.rb +24 -0
- data/motion/core_ext/time/acts_like.rb +8 -0
- data/motion/core_ext/time/calculations.rb +215 -0
- data/motion/core_ext/time/conversions.rb +52 -0
- data/motion/duration.rb +104 -0
- data/motion/hash_with_indifferent_access.rb +251 -0
- data/motion/inflections.rb +67 -0
- data/motion/inflector/inflections.rb +203 -0
- data/motion/inflector/methods.rb +321 -0
- data/{lib/motion-support → motion}/logger.rb +0 -0
- data/{lib/motion-support → motion}/version.rb +1 -1
- data/motion-support.gemspec +2 -2
- data/spec/motion-support/_helpers/constantize_test_cases.rb +75 -0
- data/spec/motion-support/_helpers/inflector_test_cases.rb +313 -0
- data/spec/motion-support/core_ext/array/access_spec.rb +29 -0
- data/spec/motion-support/core_ext/array/conversion_spec.rb +60 -0
- data/spec/motion-support/core_ext/array/extract_options_spec.rb +15 -0
- data/spec/motion-support/core_ext/array/grouping_spec.rb +85 -0
- data/spec/motion-support/core_ext/array/prepend_and_append_spec.rb +25 -0
- data/spec/motion-support/core_ext/array/wrap_spec.rb +19 -0
- data/spec/motion-support/{array_spec.rb → core_ext/array_spec.rb} +0 -5
- data/spec/motion-support/core_ext/class/attribute_accessor_spec.rb +127 -0
- data/spec/motion-support/core_ext/class/attribute_spec.rb +92 -0
- data/spec/motion-support/core_ext/date/acts_like_spec.rb +11 -0
- data/spec/motion-support/core_ext/date/calculation_spec.rb +186 -0
- data/spec/motion-support/core_ext/date/conversion_spec.rb +18 -0
- data/spec/motion-support/core_ext/date_and_time/calculation_spec.rb +336 -0
- data/spec/motion-support/core_ext/enumerable_spec.rb +130 -0
- data/spec/motion-support/core_ext/hash/deep_merge_spec.rb +32 -0
- data/spec/motion-support/core_ext/hash/except_spec.rb +43 -0
- data/spec/motion-support/core_ext/hash/key_spec.rb +230 -0
- data/spec/motion-support/core_ext/hash/reverse_merge_spec.rb +26 -0
- data/spec/motion-support/core_ext/hash/slice_spec.rb +61 -0
- data/spec/motion-support/core_ext/integer/inflection_spec.rb +23 -0
- data/spec/motion-support/core_ext/integer/multiple_spec.rb +19 -0
- data/spec/motion-support/{metaclass_spec.rb → core_ext/metaclass_spec.rb} +0 -0
- data/spec/motion-support/core_ext/module/aliasing_spec.rb +143 -0
- data/spec/motion-support/core_ext/module/anonymous_spec.rb +29 -0
- data/spec/motion-support/core_ext/module/attr_internal_spec.rb +104 -0
- data/spec/motion-support/core_ext/module/attribute_accessor_spec.rb +86 -0
- data/spec/motion-support/core_ext/module/delegation_spec.rb +136 -0
- data/spec/motion-support/core_ext/module/introspection_spec.rb +70 -0
- data/spec/motion-support/core_ext/module/reachable_spec.rb +61 -0
- data/spec/motion-support/core_ext/module/remove_method_spec.rb +25 -0
- data/spec/motion-support/core_ext/numeric/bytes_spec.rb +43 -0
- data/spec/motion-support/core_ext/object/acts_like_spec.rb +21 -0
- data/spec/motion-support/core_ext/object/blank_spec.rb +54 -0
- data/spec/motion-support/core_ext/object/deep_dup_spec.rb +54 -0
- data/spec/motion-support/core_ext/object/duplicable_spec.rb +31 -0
- data/spec/motion-support/core_ext/object/instance_variable_spec.rb +19 -0
- data/spec/motion-support/core_ext/object/to_param_spec.rb +75 -0
- data/spec/motion-support/core_ext/object/to_query_spec.rb +37 -0
- data/spec/motion-support/core_ext/object/try_spec.rb +92 -0
- data/spec/motion-support/core_ext/range/include_range_spec.rb +31 -0
- data/spec/motion-support/core_ext/range/overlap_spec.rb +43 -0
- data/spec/motion-support/core_ext/regexp_spec.rb +7 -0
- data/spec/motion-support/core_ext/string/access_spec.rb +53 -0
- data/spec/motion-support/core_ext/string/behavior_spec.rb +7 -0
- data/spec/motion-support/core_ext/string/exclude_spec.rb +8 -0
- data/spec/motion-support/core_ext/string/filter_spec.rb +48 -0
- data/spec/motion-support/core_ext/string/indent_spec.rb +56 -0
- data/spec/motion-support/core_ext/string/inflection_spec.rb +142 -0
- data/spec/motion-support/core_ext/string/starts_end_with_spec.rb +14 -0
- data/spec/motion-support/core_ext/string/strip_spec.rb +34 -0
- data/spec/motion-support/core_ext/string_spec.rb +88 -0
- data/spec/motion-support/core_ext/time/acts_like_spec.rb +11 -0
- data/spec/motion-support/core_ext/time/calculation_spec.rb +201 -0
- data/spec/motion-support/core_ext/time/conversion_spec.rb +54 -0
- data/spec/motion-support/duration_spec.rb +107 -0
- data/spec/motion-support/hash_with_indifferent_access_spec.rb +605 -0
- data/spec/motion-support/inflector_spec.rb +474 -35
- data/spec/motion-support/ns_dictionary_spec.rb +29 -0
- metadata +212 -35
- data/lib/motion-support/cattr_accessor.rb +0 -19
- data/lib/motion-support/class_inheritable_accessor.rb +0 -23
- data/lib/motion-support/class_inheritable_array.rb +0 -29
- data/lib/motion-support/hash.rb +0 -31
- data/lib/motion-support/nilclass.rb +0 -5
- data/lib/motion-support/object.rb +0 -17
- data/lib/motion-support/string.rb +0 -71
- data/spec/motion-support/cattr_accessor_spec.rb +0 -49
- data/spec/motion-support/class_inheritable_accessor_spec.rb +0 -49
- data/spec/motion-support/class_inheritable_array_spec.rb +0 -61
- data/spec/motion-support/hash_spec.rb +0 -31
- data/spec/motion-support/nilclass_spec.rb +0 -5
- data/spec/motion-support/object_spec.rb +0 -43
- data/spec/motion-support/string_spec.rb +0 -145
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
class Module
|
|
2
|
+
# Provides a delegate class method to easily expose contained objects' public methods
|
|
3
|
+
# as your own. Pass one or more methods (specified as symbols or strings)
|
|
4
|
+
# and the name of the target object via the <tt>:to</tt> option (also a symbol
|
|
5
|
+
# or string). At least one method and the <tt>:to</tt> option are required.
|
|
6
|
+
#
|
|
7
|
+
# Delegation is particularly useful with Active Record associations:
|
|
8
|
+
#
|
|
9
|
+
# class Greeter < ActiveRecord::Base
|
|
10
|
+
# def hello
|
|
11
|
+
# 'hello'
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# def goodbye
|
|
15
|
+
# 'goodbye'
|
|
16
|
+
# end
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# class Foo < ActiveRecord::Base
|
|
20
|
+
# belongs_to :greeter
|
|
21
|
+
# delegate :hello, to: :greeter
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# Foo.new.hello # => "hello"
|
|
25
|
+
# Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
|
|
26
|
+
#
|
|
27
|
+
# Multiple delegates to the same target are allowed:
|
|
28
|
+
#
|
|
29
|
+
# class Foo < ActiveRecord::Base
|
|
30
|
+
# belongs_to :greeter
|
|
31
|
+
# delegate :hello, :goodbye, to: :greeter
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
34
|
+
# Foo.new.goodbye # => "goodbye"
|
|
35
|
+
#
|
|
36
|
+
# Methods can be delegated to instance variables, class variables, or constants
|
|
37
|
+
# by providing them as a symbols:
|
|
38
|
+
#
|
|
39
|
+
# class Foo
|
|
40
|
+
# CONSTANT_ARRAY = [0,1,2,3]
|
|
41
|
+
# @@class_array = [4,5,6,7]
|
|
42
|
+
#
|
|
43
|
+
# def initialize
|
|
44
|
+
# @instance_array = [8,9,10,11]
|
|
45
|
+
# end
|
|
46
|
+
# delegate :sum, to: :CONSTANT_ARRAY
|
|
47
|
+
# delegate :min, to: :@@class_array
|
|
48
|
+
# delegate :max, to: :@instance_array
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# Foo.new.sum # => 6
|
|
52
|
+
# Foo.new.min # => 4
|
|
53
|
+
# Foo.new.max # => 11
|
|
54
|
+
#
|
|
55
|
+
# It's also possible to delegate a method to the class by using +:class+:
|
|
56
|
+
#
|
|
57
|
+
# class Foo
|
|
58
|
+
# def self.hello
|
|
59
|
+
# "world"
|
|
60
|
+
# end
|
|
61
|
+
#
|
|
62
|
+
# delegate :hello, to: :class
|
|
63
|
+
# end
|
|
64
|
+
#
|
|
65
|
+
# Foo.new.hello # => "world"
|
|
66
|
+
#
|
|
67
|
+
# Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
|
|
68
|
+
# is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
|
|
69
|
+
# delegated to.
|
|
70
|
+
#
|
|
71
|
+
# Person = Struct.new(:name, :address)
|
|
72
|
+
#
|
|
73
|
+
# class Invoice < Struct.new(:client)
|
|
74
|
+
# delegate :name, :address, to: :client, prefix: true
|
|
75
|
+
# end
|
|
76
|
+
#
|
|
77
|
+
# john_doe = Person.new('John Doe', 'Vimmersvej 13')
|
|
78
|
+
# invoice = Invoice.new(john_doe)
|
|
79
|
+
# invoice.client_name # => "John Doe"
|
|
80
|
+
# invoice.client_address # => "Vimmersvej 13"
|
|
81
|
+
#
|
|
82
|
+
# It is also possible to supply a custom prefix.
|
|
83
|
+
#
|
|
84
|
+
# class Invoice < Struct.new(:client)
|
|
85
|
+
# delegate :name, :address, to: :client, prefix: :customer
|
|
86
|
+
# end
|
|
87
|
+
#
|
|
88
|
+
# invoice = Invoice.new(john_doe)
|
|
89
|
+
# invoice.customer_name # => 'John Doe'
|
|
90
|
+
# invoice.customer_address # => 'Vimmersvej 13'
|
|
91
|
+
#
|
|
92
|
+
# If the delegate object is +nil+ an exception is raised, and that happens
|
|
93
|
+
# no matter whether +nil+ responds to the delegated method. You can get a
|
|
94
|
+
# +nil+ instead with the +:allow_nil+ option.
|
|
95
|
+
#
|
|
96
|
+
# class Foo
|
|
97
|
+
# attr_accessor :bar
|
|
98
|
+
# def initialize(bar = nil)
|
|
99
|
+
# @bar = bar
|
|
100
|
+
# end
|
|
101
|
+
# delegate :zoo, to: :bar
|
|
102
|
+
# end
|
|
103
|
+
#
|
|
104
|
+
# Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
|
|
105
|
+
#
|
|
106
|
+
# class Foo
|
|
107
|
+
# attr_accessor :bar
|
|
108
|
+
# def initialize(bar = nil)
|
|
109
|
+
# @bar = bar
|
|
110
|
+
# end
|
|
111
|
+
# delegate :zoo, to: :bar, allow_nil: true
|
|
112
|
+
# end
|
|
113
|
+
#
|
|
114
|
+
# Foo.new.zoo # returns nil
|
|
115
|
+
def delegate(*methods)
|
|
116
|
+
options = methods.pop
|
|
117
|
+
unless options.is_a?(Hash) && to = options[:to]
|
|
118
|
+
raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
prefix, allow_nil = options.values_at(:prefix, :allow_nil)
|
|
122
|
+
unguarded = !allow_nil
|
|
123
|
+
|
|
124
|
+
if prefix == true && to =~ /^[^a-z_]/
|
|
125
|
+
raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
method_prefix = \
|
|
129
|
+
if prefix
|
|
130
|
+
"#{prefix == true ? to : prefix}_"
|
|
131
|
+
else
|
|
132
|
+
''
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
reference, *hierarchy = to.to_s.split('.')
|
|
136
|
+
entry = resolver =
|
|
137
|
+
case reference
|
|
138
|
+
when 'self'
|
|
139
|
+
->(_self) { _self }
|
|
140
|
+
when /^@@/
|
|
141
|
+
->(_self) { _self.class.class_variable_get(reference) }
|
|
142
|
+
when /^@/
|
|
143
|
+
->(_self) { _self.instance_variable_get(reference) }
|
|
144
|
+
when /^[A-Z]/
|
|
145
|
+
->(_self) { if reference.to_s =~ /::/ then reference.constantize else _self.class.const_get(reference) end }
|
|
146
|
+
else
|
|
147
|
+
->(_self) { _self.send(reference) }
|
|
148
|
+
end
|
|
149
|
+
resolver = ->(_self) { hierarchy.reduce(entry.call(_self)) { |obj, method| obj.public_send(method) } } unless hierarchy.empty?
|
|
150
|
+
|
|
151
|
+
methods.each do |method|
|
|
152
|
+
module_exec do
|
|
153
|
+
# def customer_name(*args, &block)
|
|
154
|
+
# begin
|
|
155
|
+
# if unguarded || client || client.respond_to?(:name)
|
|
156
|
+
# client.name(*args, &block)
|
|
157
|
+
# end
|
|
158
|
+
# rescue client.nil? && NoMethodError
|
|
159
|
+
# raise "..."
|
|
160
|
+
# end
|
|
161
|
+
# end
|
|
162
|
+
define_method("#{method_prefix}#{method}") do |*args, &block|
|
|
163
|
+
target = resolver.call(self)
|
|
164
|
+
if unguarded || target || target.respond_to?(method)
|
|
165
|
+
begin
|
|
166
|
+
target.public_send(method, *args, &block)
|
|
167
|
+
rescue target.nil? && NoMethodError # only rescue NoMethodError when target is nil
|
|
168
|
+
raise "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: #{self.inspect}"
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
class Module
|
|
2
|
+
# Returns the name of the module containing this one.
|
|
3
|
+
#
|
|
4
|
+
# M::N.parent_name # => "M"
|
|
5
|
+
def parent_name
|
|
6
|
+
if defined? @parent_name
|
|
7
|
+
@parent_name
|
|
8
|
+
else
|
|
9
|
+
@parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Returns the module which contains this one according to its name.
|
|
14
|
+
#
|
|
15
|
+
# module M
|
|
16
|
+
# module N
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
# X = M::N
|
|
20
|
+
#
|
|
21
|
+
# M::N.parent # => M
|
|
22
|
+
# X.parent # => M
|
|
23
|
+
#
|
|
24
|
+
# The parent of top-level and anonymous modules is Object.
|
|
25
|
+
#
|
|
26
|
+
# M.parent # => Object
|
|
27
|
+
# Module.new.parent # => Object
|
|
28
|
+
def parent
|
|
29
|
+
parent_name ? parent_name.constantize : Object
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns all the parents of this module according to its name, ordered from
|
|
33
|
+
# nested outwards. The receiver is not contained within the result.
|
|
34
|
+
#
|
|
35
|
+
# module M
|
|
36
|
+
# module N
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
# X = M::N
|
|
40
|
+
#
|
|
41
|
+
# M.parents # => [Object]
|
|
42
|
+
# M::N.parents # => [M, Object]
|
|
43
|
+
# X.parents # => [M, Object]
|
|
44
|
+
def parents
|
|
45
|
+
parents = []
|
|
46
|
+
if parent_name
|
|
47
|
+
parts = parent_name.split('::')
|
|
48
|
+
until parts.empty?
|
|
49
|
+
parents << (parts * '::').constantize
|
|
50
|
+
parts.pop
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
parents << Object unless parents.include? Object
|
|
54
|
+
parents
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def local_constants #:nodoc:
|
|
58
|
+
constants(false)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class Module
|
|
2
|
+
def remove_possible_method(method)
|
|
3
|
+
if method_defined?(method) || private_method_defined?(method)
|
|
4
|
+
undef_method(method)
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def redefine_method(method, &block)
|
|
9
|
+
remove_possible_method(method)
|
|
10
|
+
define_method(method, &block)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class Numeric
|
|
2
|
+
KILOBYTE = 1024
|
|
3
|
+
MEGABYTE = KILOBYTE * 1024
|
|
4
|
+
GIGABYTE = MEGABYTE * 1024
|
|
5
|
+
TERABYTE = GIGABYTE * 1024
|
|
6
|
+
PETABYTE = TERABYTE * 1024
|
|
7
|
+
EXABYTE = PETABYTE * 1024
|
|
8
|
+
|
|
9
|
+
# Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes
|
|
10
|
+
def bytes
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
alias :byte :bytes
|
|
14
|
+
|
|
15
|
+
def kilobytes
|
|
16
|
+
self * KILOBYTE
|
|
17
|
+
end
|
|
18
|
+
alias :kilobyte :kilobytes
|
|
19
|
+
|
|
20
|
+
def megabytes
|
|
21
|
+
self * MEGABYTE
|
|
22
|
+
end
|
|
23
|
+
alias :megabyte :megabytes
|
|
24
|
+
|
|
25
|
+
def gigabytes
|
|
26
|
+
self * GIGABYTE
|
|
27
|
+
end
|
|
28
|
+
alias :gigabyte :gigabytes
|
|
29
|
+
|
|
30
|
+
def terabytes
|
|
31
|
+
self * TERABYTE
|
|
32
|
+
end
|
|
33
|
+
alias :terabyte :terabytes
|
|
34
|
+
|
|
35
|
+
def petabytes
|
|
36
|
+
self * PETABYTE
|
|
37
|
+
end
|
|
38
|
+
alias :petabyte :petabytes
|
|
39
|
+
|
|
40
|
+
def exabytes
|
|
41
|
+
self * EXABYTE
|
|
42
|
+
end
|
|
43
|
+
alias :exabyte :exabytes
|
|
44
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
class Numeric
|
|
2
|
+
# Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years.
|
|
3
|
+
#
|
|
4
|
+
# These methods use Time#advance for precise date calculations when using from_now, ago, etc.
|
|
5
|
+
# as well as adding or subtracting their results from a Time object. For example:
|
|
6
|
+
#
|
|
7
|
+
# # equivalent to Time.now.advance(months: 1)
|
|
8
|
+
# 1.month.from_now
|
|
9
|
+
#
|
|
10
|
+
# # equivalent to Time.now.advance(years: 2)
|
|
11
|
+
# 2.years.from_now
|
|
12
|
+
#
|
|
13
|
+
# # equivalent to Time.now.advance(months: 4, years: 5)
|
|
14
|
+
# (4.months + 5.years).from_now
|
|
15
|
+
#
|
|
16
|
+
# While these methods provide precise calculation when used as in the examples above, care
|
|
17
|
+
# should be taken to note that this is not true if the result of `months', `years', etc is
|
|
18
|
+
# converted before use:
|
|
19
|
+
#
|
|
20
|
+
# # equivalent to 30.days.to_i.from_now
|
|
21
|
+
# 1.month.to_i.from_now
|
|
22
|
+
#
|
|
23
|
+
# # equivalent to 365.25.days.to_f.from_now
|
|
24
|
+
# 1.year.to_f.from_now
|
|
25
|
+
#
|
|
26
|
+
# In such cases, Ruby's core
|
|
27
|
+
# Date[http://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html] and
|
|
28
|
+
# Time[http://ruby-doc.org/stdlib/libdoc/time/rdoc/Time.html] should be used for precision
|
|
29
|
+
# date and time arithmetic.
|
|
30
|
+
def seconds
|
|
31
|
+
MotionSupport::Duration.new(self, [[:seconds, self]])
|
|
32
|
+
end
|
|
33
|
+
alias :second :seconds
|
|
34
|
+
|
|
35
|
+
def minutes
|
|
36
|
+
MotionSupport::Duration.new(self * 60, [[:seconds, self * 60]])
|
|
37
|
+
end
|
|
38
|
+
alias :minute :minutes
|
|
39
|
+
|
|
40
|
+
def hours
|
|
41
|
+
MotionSupport::Duration.new(self * 3600, [[:seconds, self * 3600]])
|
|
42
|
+
end
|
|
43
|
+
alias :hour :hours
|
|
44
|
+
|
|
45
|
+
def days
|
|
46
|
+
MotionSupport::Duration.new(self * 24.hours, [[:days, self]])
|
|
47
|
+
end
|
|
48
|
+
alias :day :days
|
|
49
|
+
|
|
50
|
+
def weeks
|
|
51
|
+
MotionSupport::Duration.new(self * 7.days, [[:days, self * 7]])
|
|
52
|
+
end
|
|
53
|
+
alias :week :weeks
|
|
54
|
+
|
|
55
|
+
def fortnights
|
|
56
|
+
MotionSupport::Duration.new(self * 2.weeks, [[:days, self * 14]])
|
|
57
|
+
end
|
|
58
|
+
alias :fortnight :fortnights
|
|
59
|
+
|
|
60
|
+
# Reads best without arguments: 10.minutes.ago
|
|
61
|
+
def ago(time = ::Time.now)
|
|
62
|
+
time - self
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Reads best with argument: 10.minutes.until(time)
|
|
66
|
+
alias :until :ago
|
|
67
|
+
|
|
68
|
+
# Reads best with argument: 10.minutes.since(time)
|
|
69
|
+
def since(time = ::Time.now)
|
|
70
|
+
time + self
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Reads best without arguments: 10.minutes.from_now
|
|
74
|
+
alias :from_now :since
|
|
75
|
+
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,105 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
class Object
|
|
4
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
|
5
|
+
# For example, '', ' ', +nil+, [], and {} are all blank.
|
|
6
|
+
#
|
|
7
|
+
# This simplifies:
|
|
8
|
+
#
|
|
9
|
+
# if address.nil? || address.empty?
|
|
10
|
+
#
|
|
11
|
+
# ...to:
|
|
12
|
+
#
|
|
13
|
+
# if address.blank?
|
|
14
|
+
def blank?
|
|
15
|
+
respond_to?(:empty?) ? empty? : !self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# An object is present if it's not <tt>blank?</tt>.
|
|
19
|
+
def present?
|
|
20
|
+
!blank?
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns object if it's <tt>present?</tt> otherwise returns +nil+.
|
|
24
|
+
# <tt>object.presence</tt> is equivalent to <tt>object.present? ? object : nil</tt>.
|
|
25
|
+
#
|
|
26
|
+
# This is handy for any representation of objects where blank is the same
|
|
27
|
+
# as not present at all. For example, this simplifies a common check for
|
|
28
|
+
# HTTP POST/query parameters:
|
|
29
|
+
#
|
|
30
|
+
# state = params[:state] if params[:state].present?
|
|
31
|
+
# country = params[:country] if params[:country].present?
|
|
32
|
+
# region = state || country || 'US'
|
|
33
|
+
#
|
|
34
|
+
# ...becomes:
|
|
35
|
+
#
|
|
36
|
+
# region = params[:state].presence || params[:country].presence || 'US'
|
|
37
|
+
def presence
|
|
38
|
+
self if present?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class NilClass
|
|
43
|
+
# +nil+ is blank:
|
|
44
|
+
#
|
|
45
|
+
# nil.blank? # => true
|
|
46
|
+
def blank?
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
class FalseClass
|
|
52
|
+
# +false+ is blank:
|
|
53
|
+
#
|
|
54
|
+
# false.blank? # => true
|
|
55
|
+
def blank?
|
|
56
|
+
true
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class TrueClass
|
|
61
|
+
# +true+ is not blank:
|
|
62
|
+
#
|
|
63
|
+
# true.blank? # => false
|
|
64
|
+
def blank?
|
|
65
|
+
false
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
class Array
|
|
70
|
+
# An array is blank if it's empty:
|
|
71
|
+
#
|
|
72
|
+
# [].blank? # => true
|
|
73
|
+
# [1,2,3].blank? # => false
|
|
74
|
+
alias_method :blank?, :empty?
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class Hash
|
|
78
|
+
# A hash is blank if it's empty:
|
|
79
|
+
#
|
|
80
|
+
# {}.blank? # => true
|
|
81
|
+
# { key: 'value' }.blank? # => false
|
|
82
|
+
alias_method :blank?, :empty?
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class String
|
|
86
|
+
# A string is blank if it's empty or contains whitespaces only:
|
|
87
|
+
#
|
|
88
|
+
# ''.blank? # => true
|
|
89
|
+
# ' '.blank? # => true
|
|
90
|
+
# ' '.blank? # => true
|
|
91
|
+
# ' something here '.blank? # => false
|
|
92
|
+
def blank?
|
|
93
|
+
self !~ /[^[:space:]]/
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
class Numeric #:nodoc:
|
|
98
|
+
# No number is blank:
|
|
99
|
+
#
|
|
100
|
+
# 1.blank? # => false
|
|
101
|
+
# 0.blank? # => false
|
|
102
|
+
def blank?
|
|
103
|
+
false
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class Object
|
|
2
|
+
# Returns a deep copy of object if it's duplicable. If it's
|
|
3
|
+
# not duplicable, returns +self+.
|
|
4
|
+
#
|
|
5
|
+
# object = Object.new
|
|
6
|
+
# dup = object.deep_dup
|
|
7
|
+
# dup.instance_variable_set(:@a, 1)
|
|
8
|
+
#
|
|
9
|
+
# object.instance_variable_defined?(:@a) #=> false
|
|
10
|
+
# dup.instance_variable_defined?(:@a) #=> true
|
|
11
|
+
def deep_dup
|
|
12
|
+
duplicable? ? dup : self
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Array
|
|
17
|
+
# Returns a deep copy of array.
|
|
18
|
+
#
|
|
19
|
+
# array = [1, [2, 3]]
|
|
20
|
+
# dup = array.deep_dup
|
|
21
|
+
# dup[1][2] = 4
|
|
22
|
+
#
|
|
23
|
+
# array[1][2] #=> nil
|
|
24
|
+
# dup[1][2] #=> 4
|
|
25
|
+
def deep_dup
|
|
26
|
+
map { |it| it.deep_dup }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class Hash
|
|
31
|
+
# Returns a deep copy of hash.
|
|
32
|
+
#
|
|
33
|
+
# hash = { a: { b: 'b' } }
|
|
34
|
+
# dup = hash.deep_dup
|
|
35
|
+
# dup[:a][:c] = 'c'
|
|
36
|
+
#
|
|
37
|
+
# hash[:a][:c] #=> nil
|
|
38
|
+
# dup[:a][:c] #=> "c"
|
|
39
|
+
def deep_dup
|
|
40
|
+
each_with_object(dup) do |(key, value), hash|
|
|
41
|
+
hash[key.deep_dup] = value.deep_dup
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
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, and number 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
|
+
class BigDecimal
|
|
80
|
+
def duplicable?
|
|
81
|
+
true
|
|
82
|
+
end
|
|
83
|
+
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 { |var| var.to_s }
|
|
27
|
+
end
|
|
28
|
+
end
|