active_object 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.gitignore +14 -0
- data/.rspec +4 -0
- data/.travis.yml +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +1361 -0
- data/Rakefile +1 -0
- data/active_object.gemspec +25 -0
- data/lib/active_object.rb +9 -0
- data/lib/active_object/array.rb +118 -0
- data/lib/active_object/enumerable.rb +172 -0
- data/lib/active_object/hash.rb +203 -0
- data/lib/active_object/integer.rb +7 -0
- data/lib/active_object/numeric.rb +523 -0
- data/lib/active_object/object.rb +41 -0
- data/lib/active_object/string.rb +311 -0
- data/lib/active_object/time.rb +150 -0
- data/lib/active_object/version.rb +3 -0
- data/spec/lib/array_spec.rb +125 -0
- data/spec/lib/enumerable_spec.rb +326 -0
- data/spec/lib/hash_spec.rb +191 -0
- data/spec/lib/integer_spec.rb +11 -0
- data/spec/lib/numeric_spec.rb +604 -0
- data/spec/lib/object_spec.rb +85 -0
- data/spec/lib/string_spec.rb +459 -0
- data/spec/lib/time_spec.rb +455 -0
- data/spec/spec_helper.rb +4 -0
- metadata +137 -0
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'active_object/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "active_object"
|
8
|
+
spec.version = ActiveObject::VERSION
|
9
|
+
spec.authors = ["Juan Gomez"]
|
10
|
+
spec.email = ["j.gomez@drexed.com"]
|
11
|
+
spec.summary = %q{Commonly used ruby object helpers.}
|
12
|
+
spec.description = %q{Class extensions of commonly used ruby object helpers.}
|
13
|
+
spec.homepage = "https://github.com/drexed/active_object"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler"
|
22
|
+
spec.add_development_dependency "coveralls"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'active_object/version'
|
2
|
+
require 'active_object/array'
|
3
|
+
require 'active_object/enumerable'
|
4
|
+
require 'active_object/hash'
|
5
|
+
require 'active_object/integer'
|
6
|
+
require 'active_object/numeric'
|
7
|
+
require 'active_object/object'
|
8
|
+
require 'active_object/string'
|
9
|
+
require 'active_object/time'
|
@@ -0,0 +1,118 @@
|
|
1
|
+
class Array
|
2
|
+
|
3
|
+
def delete_first
|
4
|
+
self[1..-1]
|
5
|
+
end
|
6
|
+
|
7
|
+
def delete_last
|
8
|
+
self[0...-1]
|
9
|
+
end
|
10
|
+
|
11
|
+
unless method_defined?(:from)
|
12
|
+
def from(position)
|
13
|
+
self[position, size] || []
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def groups(number)
|
18
|
+
return([]) if number <= 0
|
19
|
+
n, r = size.divmod(number)
|
20
|
+
collection = (0..(n - 1)).collect { |i| self[(i * number), number] }
|
21
|
+
r > 0 ? collection << self[-r, r] : collection
|
22
|
+
end
|
23
|
+
|
24
|
+
unless method_defined?(:in_groups)
|
25
|
+
def in_groups(number, fill_with=nil)
|
26
|
+
collection_size = size
|
27
|
+
division = collection_size.div(number)
|
28
|
+
modulo = collection_size % number
|
29
|
+
|
30
|
+
collection = []
|
31
|
+
start = 0
|
32
|
+
number.times do |i|
|
33
|
+
grouping = division + (modulo > 0 && modulo > i ? 1 : 0)
|
34
|
+
collection << last_group = slice(start, grouping)
|
35
|
+
last_group << fill_with if fill_with != false && modulo > 0 && grouping == division
|
36
|
+
start += grouping
|
37
|
+
end
|
38
|
+
|
39
|
+
block_given? ? collection.each { |g| yield(g) } : collection
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
unless method_defined?(:in_groups_of)
|
44
|
+
def in_groups_of(number, fill_with=nil)
|
45
|
+
if number.to_i <= 0
|
46
|
+
raise ArgumentError,
|
47
|
+
"Group size must be a positive integer, was #{number.inspect}"
|
48
|
+
end
|
49
|
+
|
50
|
+
if fill_with == false
|
51
|
+
collection = self
|
52
|
+
else
|
53
|
+
padding = (number - size % number) % number
|
54
|
+
collection = dup.concat(Array.new(padding, fill_with))
|
55
|
+
end
|
56
|
+
|
57
|
+
block_given? ? collection.each_slice(number) { |slice| yield(slice) } : collection.each_slice(number).to_a
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
unless method_defined?(:split)
|
62
|
+
def split(number=nil)
|
63
|
+
if block_given?
|
64
|
+
inject([[]]) do |results, element|
|
65
|
+
yield(element) ? results << [] : results.last << element
|
66
|
+
results
|
67
|
+
end
|
68
|
+
else
|
69
|
+
results, arr = [[]], dup
|
70
|
+
until arr.empty?
|
71
|
+
if (idx = arr.index(number))
|
72
|
+
results.last.concat(arr.shift(idx))
|
73
|
+
arr.shift
|
74
|
+
results << []
|
75
|
+
else
|
76
|
+
results.last.concat(arr.shift(arr.size))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
results
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def strip
|
85
|
+
reject { |v| v.blank? }
|
86
|
+
end
|
87
|
+
|
88
|
+
unless method_defined?(:to)
|
89
|
+
def to(position)
|
90
|
+
position >= 0 ? first(position + 1) : self[0..position]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
unless method_defined?(:to_sentence)
|
95
|
+
def to_sentence(options={})
|
96
|
+
options.assert_valid_keys(:words_connector, :two_words_connector, :last_word_connector)
|
97
|
+
|
98
|
+
default_connectors = {
|
99
|
+
words_connector: ', ',
|
100
|
+
two_words_connector: ' and ',
|
101
|
+
last_word_connector: ', and '
|
102
|
+
}
|
103
|
+
options = default_connectors.merge!(options)
|
104
|
+
|
105
|
+
case size
|
106
|
+
when 0
|
107
|
+
''
|
108
|
+
when 1
|
109
|
+
self[0].to_s.dup
|
110
|
+
when 2
|
111
|
+
"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
|
112
|
+
else
|
113
|
+
"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
module Enumerable
|
2
|
+
|
3
|
+
def difference(identity=0, &block)
|
4
|
+
if block_given?
|
5
|
+
map(&block).difference(identity)
|
6
|
+
else
|
7
|
+
inject { |d,v| d - v } || identity
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def divisible(identity=0, &block)
|
12
|
+
if block_given?
|
13
|
+
map(&block).divisible(identity)
|
14
|
+
else
|
15
|
+
inject { |d,v| d / v } || identity
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def drop_last(n)
|
20
|
+
collection_size = to_a.size
|
21
|
+
return(self) if n > collection_size
|
22
|
+
self[0...(collection_size - n)]
|
23
|
+
end
|
24
|
+
|
25
|
+
def drop_last_if
|
26
|
+
return(to_enum(:drop_last_if)) unless block_given?
|
27
|
+
|
28
|
+
result = []
|
29
|
+
dropping = true
|
30
|
+
reverse_each do |value|
|
31
|
+
result.unshift(value) unless dropping &&= yield(value)
|
32
|
+
end
|
33
|
+
result
|
34
|
+
end
|
35
|
+
|
36
|
+
def exactly?(n)
|
37
|
+
found_count = 0
|
38
|
+
block_given? ? each { |*o| found_count += 1 if yield(*o) } : each { |o| found_count += 1 if o }
|
39
|
+
(found_count > n) ? false : n == found_count
|
40
|
+
end
|
41
|
+
|
42
|
+
unless method_defined?(:exclude?)
|
43
|
+
def exclude?(object)
|
44
|
+
!include?(object)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def exponential(identity=0, &block)
|
49
|
+
if block_given?
|
50
|
+
map(&block).exponential(identity)
|
51
|
+
else
|
52
|
+
inject { |d,v| d ** v } || identity
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def frequencies
|
57
|
+
each_with_object(Hash.new(0)) { |e, a| a[e] += 1 }
|
58
|
+
end
|
59
|
+
|
60
|
+
unless method_defined?(:many?)
|
61
|
+
def many?
|
62
|
+
found_count = 0
|
63
|
+
if block_given?
|
64
|
+
any? do |v|
|
65
|
+
found_count += 1 if yield v
|
66
|
+
found_count > 1
|
67
|
+
end
|
68
|
+
else
|
69
|
+
any? { (found_count += 1) > 1 }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def max(identity=0)
|
75
|
+
size > 0 ? sort.last : identity
|
76
|
+
end
|
77
|
+
|
78
|
+
def min(identity=0)
|
79
|
+
size > 0 ? sort.first : identity
|
80
|
+
end
|
81
|
+
|
82
|
+
def mean(identity=0)
|
83
|
+
return(identity) unless size > 0
|
84
|
+
collection_size = size
|
85
|
+
sum / collection_size.to_f
|
86
|
+
end
|
87
|
+
|
88
|
+
def median(identity=0)
|
89
|
+
collection_size = size
|
90
|
+
collection_sorted = sort
|
91
|
+
|
92
|
+
return(identity) unless collection_size > 0
|
93
|
+
|
94
|
+
if (collection_size % 2).zero?
|
95
|
+
(collection_sorted[(collection_size / 2.0) -1.0] + collection_sorted[collection_size / 2.0]) / 2.0
|
96
|
+
else
|
97
|
+
collection_sorted[collection_size / 2.0]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def mode(identity=0)
|
102
|
+
return(identity) unless size > 0
|
103
|
+
|
104
|
+
frequency_distribution = inject(Hash.new(0)) { |h,v| h[v] += 1; h }
|
105
|
+
frequency_top_two = frequency_distribution.sort { |k,v| v[1] <=> k[1] }.take(2)
|
106
|
+
|
107
|
+
if frequency_top_two.size == 1
|
108
|
+
frequency_top_two.first.first
|
109
|
+
elsif frequency_top_two.first.last == frequency_top_two.last.last
|
110
|
+
nil
|
111
|
+
else
|
112
|
+
frequency_top_two.first.first
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def multiple(identity=0, &block)
|
117
|
+
if block_given?
|
118
|
+
map(&block).multiple(identity)
|
119
|
+
else
|
120
|
+
inject { |d,v| d * v } || identity
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def range(identity=0)
|
125
|
+
return(identity) unless size > 0
|
126
|
+
collection_sorted = sort
|
127
|
+
collection_sorted.last - collection_sorted.first
|
128
|
+
end
|
129
|
+
|
130
|
+
def several?
|
131
|
+
found_count = 0
|
132
|
+
block_given? ? each { |*o| found_count += 1 if yield(*o) } : each { |o| found_count += 1 if o }
|
133
|
+
(found_count > 1) ? true : false
|
134
|
+
end
|
135
|
+
|
136
|
+
def standard_deviation(identity=0)
|
137
|
+
return(identity) if size < 2
|
138
|
+
Math.sqrt(variance)
|
139
|
+
end
|
140
|
+
|
141
|
+
unless method_defined?(:sum)
|
142
|
+
def sum(identity=0, &block)
|
143
|
+
if block_given?
|
144
|
+
map(&block).sum(identity)
|
145
|
+
else
|
146
|
+
inject { |s,v| s + v } || identity
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def take_last(n)
|
152
|
+
collection_size = to_a.size
|
153
|
+
return(self) if n > collection_size
|
154
|
+
self[(collection_size - n)..-1]
|
155
|
+
end
|
156
|
+
|
157
|
+
def take_last_if
|
158
|
+
return(to_enum(:take_last_if)) unless block_given?
|
159
|
+
|
160
|
+
result = []
|
161
|
+
reverse_each { |e| yield(e) ? result.unshift(e) : break }
|
162
|
+
result
|
163
|
+
end
|
164
|
+
|
165
|
+
def variance(identity=0)
|
166
|
+
collection_size = size
|
167
|
+
return(identity) if collection_size <= 1
|
168
|
+
sum = inject(0.0) { |s,v| s + (v - mean) ** 2.0 }
|
169
|
+
sum / (collection_size.to_f - 1.0)
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
unless method_defined?(:assert_valid_keys)
|
4
|
+
def assert_valid_keys(*valid_keys)
|
5
|
+
valid_keys.flatten!
|
6
|
+
each_key do |k|
|
7
|
+
unless valid_keys.include?(k)
|
8
|
+
raise ArgumentError, "Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
unless method_defined?(:compact)
|
15
|
+
def compact
|
16
|
+
select { |k,v| !v.nil? }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
unless method_defined?(:compact!)
|
21
|
+
def compact!
|
22
|
+
reject! { |k,v| v.nil? }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
unless method_defined?(:deep_merge)
|
27
|
+
def deep_merge(other_hash, &block)
|
28
|
+
dup.deep_merge!(other_hash, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
unless method_defined?(:deep_merge!)
|
33
|
+
def deep_merge!(other_hash, &block)
|
34
|
+
other_hash.each_pair do |current_key, other_value|
|
35
|
+
this_value = self[current_key]
|
36
|
+
|
37
|
+
self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
|
38
|
+
this_value.deep_merge(other_value, &block)
|
39
|
+
else
|
40
|
+
block_given? && key?(current_key) ? block.call(current_key, this_value, other_value) : other_value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
unless method_defined?(:except)
|
48
|
+
def except(*keys)
|
49
|
+
dup.except!(*keys)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
unless method_defined?(:except!)
|
54
|
+
def except!(*keys)
|
55
|
+
keys.each { |k| delete(k) }
|
56
|
+
self
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def nillify
|
61
|
+
dup.nillify!
|
62
|
+
end
|
63
|
+
|
64
|
+
def nillify!
|
65
|
+
each do |k, v|
|
66
|
+
if !v.nil? && ((v.respond_to?(:blank?) && v.blank?) || (v.respond_to?(:to_s) && v.to_s.blank?))
|
67
|
+
self[k] = nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
unless method_defined?(:only)
|
73
|
+
def only(*keys)
|
74
|
+
dup.only!(*keys)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
unless method_defined?(:only!)
|
79
|
+
def only!(*args)
|
80
|
+
hash = {}
|
81
|
+
args.each {|k| hash[k] = self[k] if self.has_key?(k) }
|
82
|
+
hash
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def rename_keys(*args)
|
87
|
+
dup.rename_keys!(*args)
|
88
|
+
end
|
89
|
+
|
90
|
+
def rename_keys!(*args)
|
91
|
+
keys = Hash[*args.flatten]
|
92
|
+
keys.each { |k, v| self[v] = delete(k) if self[k] }
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
unless method_defined?(:reverse_merge)
|
97
|
+
def reverse_merge(other_hash)
|
98
|
+
other_hash.merge(self)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
unless method_defined?(:reverse_merge!)
|
103
|
+
def reverse_merge!(other_hash)
|
104
|
+
merge!(other_hash) { |k,l,r| l }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
unless method_defined?(:slice)
|
109
|
+
def slice(*keys)
|
110
|
+
keys.each_with_object(self.class.new) { |k, h| h[k] = self[k] if has_key?(k) }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
unless method_defined?(:slice!)
|
115
|
+
def slice!(*keys)
|
116
|
+
omit = slice(*self.keys - keys)
|
117
|
+
hash = slice(*keys)
|
118
|
+
|
119
|
+
hash.default = default
|
120
|
+
hash.default_proc = default_proc if default_proc
|
121
|
+
|
122
|
+
replace(hash)
|
123
|
+
omit
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
unless method_defined?(:stringify_keys)
|
128
|
+
def stringify_keys
|
129
|
+
dup.stringify_keys!
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
unless method_defined?(:stringify_keys!)
|
134
|
+
def stringify_keys!
|
135
|
+
inject({}) do |options,(k,v)|
|
136
|
+
options[k.to_s] = v
|
137
|
+
options
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def strip
|
143
|
+
select { |k,v| !v.blank? }
|
144
|
+
end
|
145
|
+
|
146
|
+
def strip!
|
147
|
+
reject! { |k,v| v.blank? }
|
148
|
+
end
|
149
|
+
|
150
|
+
unless method_defined?(:symbolize_keys)
|
151
|
+
def symbolize_keys
|
152
|
+
dup.symbolize_keys!
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
unless method_defined?(:symbolize_keys!)
|
157
|
+
def symbolize_keys!
|
158
|
+
inject({}) do |options, (k,v)|
|
159
|
+
options[(k.to_sym rescue k) || k] = v
|
160
|
+
options
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def symbolize_and_underscore_keys
|
166
|
+
dup.symbolize_and_underscore_keys!
|
167
|
+
end
|
168
|
+
|
169
|
+
def symbolize_and_underscore_keys!
|
170
|
+
inject({}) do |options, (k,v)|
|
171
|
+
options[(k.to_s.gsub(" ", "_").underscore.to_sym rescue k) || k] = v
|
172
|
+
options
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
unless method_defined?(:transform_keys)
|
177
|
+
def transform_keys(&block)
|
178
|
+
dup.transform_keys!(&block)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
unless method_defined?(:transform_keys!)
|
183
|
+
def transform_keys!(&block)
|
184
|
+
return(enum_for(:transform_keys!)) unless block_given?
|
185
|
+
keys.each { |k| self[yield(k)] = delete(k) }
|
186
|
+
self
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
unless method_defined?(:transform_values)
|
191
|
+
def transform_values(&block)
|
192
|
+
dup.transform_values!(&block)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
unless method_defined?(:transform_values!)
|
197
|
+
def transform_values!(&block)
|
198
|
+
return(enum_for(:transform_values!)) unless block_given?
|
199
|
+
each { |k,v| self[k] = yield(v) }
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|