simple_ext 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5f972070633ea700b9c69fc42ed84258ed68bbfe3fb95df8284c62dc3342db42
4
+ data.tar.gz: 7e19bc443f5f7ddc6658aaf20936ccfce95e108e4e6498e489d68ec1f7da9973
5
+ SHA512:
6
+ metadata.gz: 8778c40b09e43907f4da9cbfb7473a2d6add060632025925a77553daf61eb58249fe3f4afea0238d59ca0a29596207284d2388682c7fc70a7092d108247cfaa4
7
+ data.tar.gz: 8723bbf6360f6637382acae47b95d82bb1b7f6dddfcf8e0605670c449960ac0c36edb60621ed8d480c3fdbc441106cecb77655126328d8b4e58e72d385ea9f65
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ # Removes and returns the elements for which the block returns a true value.
5
+ # If no block is given, an Enumerator is returned instead.
6
+ #
7
+ # numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
8
+ # odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
9
+ # numbers # => [0, 2, 4, 6, 8]
10
+ def extract!
11
+ return to_enum(:extract!) { size } unless block_given?
12
+
13
+ extracted_elements = []
14
+
15
+ reject! do |element|
16
+ extracted_elements << element if yield(element)
17
+ end
18
+
19
+ extracted_elements
20
+ end
21
+
22
+ # Returns the tail of the array from +position+.
23
+ #
24
+ # %w( a b c d ).from(0) # => ["a", "b", "c", "d"]
25
+ # %w( a b c d ).from(2) # => ["c", "d"]
26
+ # %w( a b c d ).from(10) # => []
27
+ # %w().from(0) # => []
28
+ # %w( a b c d ).from(-2) # => ["c", "d"]
29
+ # %w( a b c ).from(-10) # => []
30
+ def from(position)
31
+ self[position, length] || []
32
+ end
33
+
34
+ # Returns the beginning of the array up to +position+.
35
+ #
36
+ # %w( a b c d ).to(0) # => ["a"]
37
+ # %w( a b c d ).to(2) # => ["a", "b", "c"]
38
+ # %w( a b c d ).to(10) # => ["a", "b", "c", "d"]
39
+ # %w().to(0) # => []
40
+ # %w( a b c d ).to(-2) # => ["a", "b", "c"]
41
+ # %w( a b c ).to(-10) # => []
42
+ def to(position)
43
+ if position >= 0
44
+ take position + 1
45
+ else
46
+ self[0..position]
47
+ end
48
+ end
49
+
50
+ # Returns a new array that includes the passed elements.
51
+ #
52
+ # [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
53
+ # [ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]
54
+ def including(*elements)
55
+ self + elements.flatten(1)
56
+ end
57
+
58
+ # Returns a copy of the Array excluding the specified elements.
59
+ #
60
+ # ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
61
+ # [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
62
+ #
63
+ # Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt>
64
+ # instead of <tt>Array#reject</tt> for performance reasons.
65
+ def excluding(*elements)
66
+ self - elements.flatten(1)
67
+ end
68
+
69
+ # Alias for #excluding.
70
+ def without(*elements)
71
+ excluding(*elements)
72
+ end
73
+
74
+ # Equal to <tt>self[1]</tt>.
75
+ #
76
+ # %w( a b c d e ).second # => "b"
77
+ def second
78
+ self[1]
79
+ end
80
+
81
+ # Equal to <tt>self[2]</tt>.
82
+ #
83
+ # %w( a b c d e ).third # => "c"
84
+ def third
85
+ self[2]
86
+ end
87
+
88
+ # Equal to <tt>self[3]</tt>.
89
+ #
90
+ # %w( a b c d e ).fourth # => "d"
91
+ def fourth
92
+ self[3]
93
+ end
94
+
95
+ # Equal to <tt>self[4]</tt>.
96
+ #
97
+ # %w( a b c d e ).fifth # => "e"
98
+ def fifth
99
+ self[4]
100
+ end
101
+
102
+ # Equal to <tt>self[41]</tt>. Also known as accessing "the reddit".
103
+ #
104
+ # (1..42).to_a.forty_two # => 42
105
+ def forty_two
106
+ self[41]
107
+ end
108
+
109
+ # Equal to <tt>self[-3]</tt>.
110
+ #
111
+ # %w( a b c d e ).third_to_last # => "c"
112
+ def third_to_last
113
+ self[-3]
114
+ end
115
+
116
+ # Equal to <tt>self[-2]</tt>.
117
+ #
118
+ # %w( a b c d e ).second_to_last # => "d"
119
+ def second_to_last
120
+ self[-2]
121
+ end
122
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'array/access.rb'
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+
5
+ module Digest
6
+ module UUID
7
+ DNS_NAMESPACE = "k\xA7\xB8\x10\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" #:nodoc:
8
+ URL_NAMESPACE = "k\xA7\xB8\x11\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" #:nodoc:
9
+ OID_NAMESPACE = "k\xA7\xB8\x12\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" #:nodoc:
10
+ X500_NAMESPACE = "k\xA7\xB8\x14\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" #:nodoc:
11
+
12
+ # Generates a v5 non-random UUID (Universally Unique IDentifier).
13
+ #
14
+ # Using Digest::MD5 generates version 3 UUIDs; Digest::SHA1 generates version 5 UUIDs.
15
+ # uuid_from_hash always generates the same UUID for a given name and namespace combination.
16
+ #
17
+ # See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt
18
+ def self.uuid_from_hash(hash_class, uuid_namespace, name)
19
+ if hash_class == Digest::MD5
20
+ version = 3
21
+ elsif hash_class == Digest::SHA1
22
+ version = 5
23
+ else
24
+ raise ArgumentError, "Expected Digest::SHA1 or Digest::MD5, got #{hash_class.name}."
25
+ end
26
+
27
+ hash = hash_class.new
28
+ hash.update(uuid_namespace)
29
+ hash.update(name)
30
+
31
+ ary = hash.digest.unpack("NnnnnN")
32
+ ary[2] = (ary[2] & 0x0FFF) | (version << 12)
33
+ ary[3] = (ary[3] & 0x3FFF) | 0x8000
34
+
35
+ "%08x-%04x-%04x-%04x-%04x%08x" % ary
36
+ end
37
+
38
+ # Convenience method for uuid_from_hash using Digest::MD5.
39
+ def self.uuid_v3(uuid_namespace, name)
40
+ uuid_from_hash(Digest::MD5, uuid_namespace, name)
41
+ end
42
+
43
+ # Convenience method for uuid_from_hash using Digest::SHA1.
44
+ def self.uuid_v5(uuid_namespace, name)
45
+ uuid_from_hash(Digest::SHA1, uuid_namespace, name)
46
+ end
47
+
48
+ # Convenience method for SecureRandom.uuid.
49
+ def self.uuid_v4
50
+ SecureRandom.uuid
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'digest/uuid.rb'
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
5
+ class File
6
+ # Write to a file atomically. Useful for situations where you don't
7
+ # want other processes or threads to see half-written files.
8
+ #
9
+ # File.atomic_write('important.file') do |file|
10
+ # file.write('hello')
11
+ # end
12
+ #
13
+ # This method needs to create a temporary file. By default it will create it
14
+ # in the same directory as the destination file. If you don't like this
15
+ # behavior you can provide a different directory but it must be on the
16
+ # same physical filesystem as the file you're trying to write.
17
+ #
18
+ # File.atomic_write('/data/something.important', '/data/tmp') do |file|
19
+ # file.write('hello')
20
+ # end
21
+ def self.atomic_write(file_name, temp_dir = dirname(file_name))
22
+ require "tempfile" unless defined?(Tempfile)
23
+
24
+ Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
25
+ temp_file.binmode
26
+ return_val = yield temp_file
27
+ temp_file.close
28
+
29
+ old_stat = if exist?(file_name)
30
+ # Get original file permissions
31
+ stat(file_name)
32
+ else
33
+ # If not possible, probe which are the default permissions in the
34
+ # destination directory.
35
+ probe_stat_in(dirname(file_name))
36
+ end
37
+
38
+ if old_stat
39
+ # Set correct permissions on new file
40
+ begin
41
+ chown(old_stat.uid, old_stat.gid, temp_file.path)
42
+ # This operation will affect filesystem ACL's
43
+ chmod(old_stat.mode, temp_file.path)
44
+ rescue Errno::EPERM, Errno::EACCES
45
+ # Changing file ownership failed, moving on.
46
+ end
47
+ end
48
+
49
+ # Overwrite original file with temp file
50
+ rename(temp_file.path, file_name)
51
+ return_val
52
+ end
53
+ end
54
+
55
+ # Private utility method.
56
+ def self.probe_stat_in(dir) #:nodoc:
57
+ basename = [
58
+ ".permissions_check",
59
+ Thread.current.object_id,
60
+ Process.pid,
61
+ rand(1000000)
62
+ ].join(".")
63
+
64
+ file_name = join(dir, basename)
65
+ FileUtils.touch(file_name)
66
+ stat(file_name)
67
+ ensure
68
+ FileUtils.rm_f(file_name) if file_name
69
+ end
70
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'file/atomic.rb'
@@ -0,0 +1,22 @@
1
+ class Hash
2
+ # Returns a hash that includes everything except given keys.
3
+ # hash = { a: true, b: false, c: nil }
4
+ # hash.except(:c) # => { a: true, b: false }
5
+ # hash.except(:a, :b) # => { c: nil }
6
+ # hash # => { a: true, b: false, c: nil }
7
+ #
8
+ # This is useful for limiting a set of parameters to everything but a few known toggles:
9
+ # @person.update(params[:person].except(:admin))
10
+ def except(*keys)
11
+ slice(*self.keys - keys)
12
+ end
13
+
14
+ # Removes the given keys from hash and returns it.
15
+ # hash = { a: true, b: false, c: nil }
16
+ # hash.except!(:c) # => { a: true, b: false }
17
+ # hash # => { a: true, b: false }
18
+ def except!(*keys)
19
+ keys.each { |key| delete(key) }
20
+ self
21
+ end
22
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Returns a new hash with all keys converted to strings.
5
+ #
6
+ # hash = { name: 'Rob', age: '28' }
7
+ #
8
+ # hash.stringify_keys
9
+ # # => {"name"=>"Rob", "age"=>"28"}
10
+ def stringify_keys
11
+ transform_keys(&:to_s)
12
+ end
13
+
14
+ # Destructively converts all keys to strings. Same as
15
+ # +stringify_keys+, but modifies +self+.
16
+ def stringify_keys!
17
+ transform_keys!(&:to_s)
18
+ end
19
+
20
+ # Returns a new hash with all keys converted to symbols, as long as
21
+ # they respond to +to_sym+.
22
+ #
23
+ # hash = { 'name' => 'Rob', 'age' => '28' }
24
+ #
25
+ # hash.symbolize_keys
26
+ # # => {:name=>"Rob", :age=>"28"}
27
+ def symbolize_keys
28
+ transform_keys { |key| key.to_sym rescue key }
29
+ end
30
+ alias_method :to_options, :symbolize_keys
31
+
32
+ # Destructively converts all keys to symbols, as long as they respond
33
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
34
+ def symbolize_keys!
35
+ transform_keys! { |key| key.to_sym rescue key }
36
+ end
37
+ alias_method :to_options!, :symbolize_keys!
38
+
39
+ # Validates all keys in a hash match <tt>*valid_keys</tt>, raising
40
+ # +ArgumentError+ on a mismatch.
41
+ #
42
+ # Note that keys are treated differently than HashWithIndifferentAccess,
43
+ # meaning that string and symbol keys will not match.
44
+ #
45
+ # { name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: :years. Valid keys are: :name, :age"
46
+ # { name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: :name. Valid keys are: 'name', 'age'"
47
+ # { name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
48
+ def assert_valid_keys(*valid_keys)
49
+ valid_keys.flatten!
50
+ each_key do |k|
51
+ unless valid_keys.include?(k)
52
+ raise ArgumentError.new("Unknown key: #{k.inspect}. Valid keys are: #{valid_keys.map(&:inspect).join(', ')}")
53
+ end
54
+ end
55
+ end
56
+
57
+ # Returns a new hash with all keys converted by the block operation.
58
+ # This includes the keys from the root hash and from all
59
+ # nested hashes and arrays.
60
+ #
61
+ # hash = { person: { name: 'Rob', age: '28' } }
62
+ #
63
+ # hash.deep_transform_keys{ |key| key.to_s.upcase }
64
+ # # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
65
+ def deep_transform_keys(&block)
66
+ _deep_transform_keys_in_object(self, &block)
67
+ end
68
+
69
+ # Destructively converts all keys by using the block operation.
70
+ # This includes the keys from the root hash and from all
71
+ # nested hashes and arrays.
72
+ def deep_transform_keys!(&block)
73
+ _deep_transform_keys_in_object!(self, &block)
74
+ end
75
+
76
+ # Returns a new hash with all keys converted to strings.
77
+ # This includes the keys from the root hash and from all
78
+ # nested hashes and arrays.
79
+ #
80
+ # hash = { person: { name: 'Rob', age: '28' } }
81
+ #
82
+ # hash.deep_stringify_keys
83
+ # # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
84
+ def deep_stringify_keys
85
+ deep_transform_keys(&:to_s)
86
+ end
87
+
88
+ # Destructively converts all keys to strings.
89
+ # This includes the keys from the root hash and from all
90
+ # nested hashes and arrays.
91
+ def deep_stringify_keys!
92
+ deep_transform_keys!(&:to_s)
93
+ end
94
+
95
+ # Returns a new hash with all keys converted to symbols, as long as
96
+ # they respond to +to_sym+. This includes the keys from the root hash
97
+ # and from all nested hashes and arrays.
98
+ #
99
+ # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
100
+ #
101
+ # hash.deep_symbolize_keys
102
+ # # => {:person=>{:name=>"Rob", :age=>"28"}}
103
+ def deep_symbolize_keys
104
+ deep_transform_keys { |key| key.to_sym rescue key }
105
+ end
106
+
107
+ # Destructively converts all keys to symbols, as long as they respond
108
+ # to +to_sym+. This includes the keys from the root hash and from all
109
+ # nested hashes and arrays.
110
+ def deep_symbolize_keys!
111
+ deep_transform_keys! { |key| key.to_sym rescue key }
112
+ end
113
+
114
+ private
115
+ # support methods for deep transforming nested hashes and arrays
116
+ def _deep_transform_keys_in_object(object, &block)
117
+ case object
118
+ when Hash
119
+ object.each_with_object({}) do |(key, value), result|
120
+ result[yield(key)] = _deep_transform_keys_in_object(value, &block)
121
+ end
122
+ when Array
123
+ object.map { |e| _deep_transform_keys_in_object(e, &block) }
124
+ else
125
+ object
126
+ end
127
+ end
128
+
129
+ def _deep_transform_keys_in_object!(object, &block)
130
+ case object
131
+ when Hash
132
+ object.keys.each do |key|
133
+ value = object.delete(key)
134
+ object[yield(key)] = _deep_transform_keys_in_object!(value, &block)
135
+ end
136
+ object
137
+ when Array
138
+ object.map! { |e| _deep_transform_keys_in_object!(e, &block) }
139
+ else
140
+ object
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Returns a new hash with +self+ and +other_hash+ merged recursively.
5
+ #
6
+ # h1 = { a: true, b: { c: [1, 2, 3] } }
7
+ # h2 = { a: false, b: { x: [3, 4, 5] } }
8
+ #
9
+ # h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
10
+ #
11
+ # Like with Hash#merge in the standard library, a block can be provided
12
+ # to merge values:
13
+ #
14
+ # h1 = { a: 100, b: 200, c: { c1: 100 } }
15
+ # h2 = { b: 250, c: { c1: 200 } }
16
+ # h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
17
+ # # => { a: 100, b: 450, c: { c1: 300 } }
18
+ def deep_merge(other_hash, &block)
19
+ dup.deep_merge!(other_hash, &block)
20
+ end
21
+
22
+ # Same as +deep_merge+, but modifies +self+.
23
+ def deep_merge!(other_hash, &block)
24
+ merge!(other_hash) do |key, this_val, other_val|
25
+ if this_val.is_a?(Hash) && other_val.is_a?(Hash)
26
+ this_val.deep_merge(other_val, &block)
27
+ elsif block_given?
28
+ block.call(key, this_val, other_val)
29
+ else
30
+ other_val
31
+ end
32
+ end
33
+ end
34
+
35
+ # Merges the caller into +other_hash+. For example,
36
+ #
37
+ # options = options.reverse_merge(size: 25, velocity: 10)
38
+ #
39
+ # is equivalent to
40
+ #
41
+ # options = { size: 25, velocity: 10 }.merge(options)
42
+ #
43
+ # This is particularly useful for initializing an options hash
44
+ # with default values.
45
+ def reverse_merge(other_hash)
46
+ other_hash.merge(self)
47
+ end
48
+ alias_method :with_defaults, :reverse_merge
49
+
50
+ # Destructive +reverse_merge+.
51
+ def reverse_merge!(other_hash)
52
+ replace(reverse_merge(other_hash))
53
+ end
54
+ alias_method :reverse_update, :reverse_merge!
55
+ alias_method :with_defaults!, :reverse_merge!
56
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Replaces the hash with only the given keys.
5
+ # Returns a hash containing the removed key/value pairs.
6
+ #
7
+ # hash = { a: 1, b: 2, c: 3, d: 4 }
8
+ # hash.slice!(:a, :b) # => {:c=>3, :d=>4}
9
+ # hash # => {:a=>1, :b=>2}
10
+ def slice!(*keys)
11
+ omit = slice(*self.keys - keys)
12
+ hash = slice(*keys)
13
+ hash.default = default
14
+ hash.default_proc = default_proc if default_proc
15
+ replace(hash)
16
+ omit
17
+ end
18
+
19
+ # Removes and returns the key/value pairs matching the given keys.
20
+ #
21
+ # { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => {:a=>1, :b=>2}
22
+ # { a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1}
23
+ def extract!(*keys)
24
+ keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
25
+ end
26
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Hash
4
+ # Returns a new hash with all values converted by the block operation.
5
+ # This includes the values from the root hash and from all
6
+ # nested hashes and arrays.
7
+ #
8
+ # hash = { person: { name: 'Rob', age: '28' } }
9
+ #
10
+ # hash.deep_transform_values{ |value| value.to_s.upcase }
11
+ # # => {person: {name: "ROB", age: "28"}}
12
+ def deep_transform_values(&block)
13
+ _deep_transform_values_in_object(self, &block)
14
+ end
15
+
16
+ # Destructively converts all values by using the block operation.
17
+ # This includes the values from the root hash and from all
18
+ # nested hashes and arrays.
19
+ def deep_transform_values!(&block)
20
+ _deep_transform_values_in_object!(self, &block)
21
+ end
22
+
23
+ private
24
+ # support methods for deep transforming nested hashes and arrays
25
+ def _deep_transform_values_in_object(object, &block)
26
+ case object
27
+ when Hash
28
+ object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
29
+ when Array
30
+ object.map { |e| _deep_transform_values_in_object(e, &block) }
31
+ else
32
+ yield(object)
33
+ end
34
+ end
35
+
36
+ def _deep_transform_values_in_object!(object, &block)
37
+ case object
38
+ when Hash
39
+ object.transform_values! { |value| _deep_transform_values_in_object!(value, &block) }
40
+ when Array
41
+ object.map! { |e| _deep_transform_values_in_object!(e, &block) }
42
+ else
43
+ yield(object)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'hash/except.rb'
4
+ require_relative 'hash/keys.rb'
5
+ require_relative 'hash/merge.rb'
6
+ require_relative 'hash/slice.rb'
7
+ require_relative 'hash/values.rb'
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Numeric
4
+ KILOBYTE = 1024
5
+ MEGABYTE = KILOBYTE * 1024
6
+ GIGABYTE = MEGABYTE * 1024
7
+ TERABYTE = GIGABYTE * 1024
8
+ PETABYTE = TERABYTE * 1024
9
+ EXABYTE = PETABYTE * 1024
10
+
11
+ # Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes
12
+ #
13
+ # 2.bytes # => 2
14
+ def bytes
15
+ self
16
+ end
17
+ alias :byte :bytes
18
+
19
+ # Returns the number of bytes equivalent to the kilobytes provided.
20
+ #
21
+ # 2.kilobytes # => 2048
22
+ def kilobytes
23
+ self * KILOBYTE
24
+ end
25
+ alias :kilobyte :kilobytes
26
+
27
+ # Returns the number of bytes equivalent to the megabytes provided.
28
+ #
29
+ # 2.megabytes # => 2_097_152
30
+ def megabytes
31
+ self * MEGABYTE
32
+ end
33
+ alias :megabyte :megabytes
34
+
35
+ # Returns the number of bytes equivalent to the gigabytes provided.
36
+ #
37
+ # 2.gigabytes # => 2_147_483_648
38
+ def gigabytes
39
+ self * GIGABYTE
40
+ end
41
+ alias :gigabyte :gigabytes
42
+
43
+ # Returns the number of bytes equivalent to the terabytes provided.
44
+ #
45
+ # 2.terabytes # => 2_199_023_255_552
46
+ def terabytes
47
+ self * TERABYTE
48
+ end
49
+ alias :terabyte :terabytes
50
+
51
+ # Returns the number of bytes equivalent to the petabytes provided.
52
+ #
53
+ # 2.petabytes # => 2_251_799_813_685_248
54
+ def petabytes
55
+ self * PETABYTE
56
+ end
57
+ alias :petabyte :petabytes
58
+
59
+ # Returns the number of bytes equivalent to the exabytes provided.
60
+ #
61
+ # 2.exabytes # => 2_305_843_009_213_693_952
62
+ def exabytes
63
+ self * EXABYTE
64
+ end
65
+ alias :exabyte :exabytes
66
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'numeric/bytes.rb'
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+ require 'concurrent/map'
3
+
4
+ class Object
5
+ # An object is blank if it's false, empty, or a whitespace string.
6
+ # For example, +nil+, '', ' ', [], {}, and +false+ are all blank.
7
+ #
8
+ # This simplifies
9
+ #
10
+ # !address || address.empty?
11
+ #
12
+ # to
13
+ #
14
+ # address.blank?
15
+ #
16
+ # @return [true, false]
17
+ def blank?
18
+ respond_to?(:empty?) ? !!empty? : !self
19
+ end
20
+
21
+ # An object is present if it's not blank.
22
+ #
23
+ # @return [true, false]
24
+ def present?
25
+ !blank?
26
+ end
27
+
28
+ # Returns the receiver if it's present otherwise returns +nil+.
29
+ # <tt>object.presence</tt> is equivalent to
30
+ #
31
+ # object.present? ? object : nil
32
+ #
33
+ # For example, something like
34
+ #
35
+ # state = params[:state] if params[:state].present?
36
+ # country = params[:country] if params[:country].present?
37
+ # region = state || country || 'US'
38
+ #
39
+ # becomes
40
+ #
41
+ # region = params[:state].presence || params[:country].presence || 'US'
42
+ #
43
+ # @return [Object]
44
+ def presence
45
+ self if present?
46
+ end
47
+ end
48
+
49
+ class NilClass
50
+ # +nil+ is blank:
51
+ #
52
+ # nil.blank? # => true
53
+ #
54
+ # @return [true]
55
+ def blank?
56
+ true
57
+ end
58
+ end
59
+
60
+ class FalseClass
61
+ # +false+ is blank:
62
+ #
63
+ # false.blank? # => true
64
+ #
65
+ # @return [true]
66
+ def blank?
67
+ true
68
+ end
69
+ end
70
+
71
+ class TrueClass
72
+ # +true+ is not blank:
73
+ #
74
+ # true.blank? # => false
75
+ #
76
+ # @return [false]
77
+ def blank?
78
+ false
79
+ end
80
+ end
81
+
82
+ class Array
83
+ # An array is blank if it's empty:
84
+ #
85
+ # [].blank? # => true
86
+ # [1,2,3].blank? # => false
87
+ #
88
+ # @return [true, false]
89
+ alias_method :blank?, :empty?
90
+ end
91
+
92
+ class Hash
93
+ # A hash is blank if it's empty:
94
+ #
95
+ # {}.blank? # => true
96
+ # { key: 'value' }.blank? # => false
97
+ #
98
+ # @return [true, false]
99
+ alias_method :blank?, :empty?
100
+ end
101
+
102
+ class String
103
+ BLANK_RE = /\A[[:space:]]*\z/
104
+ ENCODED_BLANKS = Concurrent::Map.new do |h, enc|
105
+ h[enc] = Regexp.new(BLANK_RE.source.encode(enc), BLANK_RE.options | Regexp::FIXEDENCODING)
106
+ end
107
+
108
+ # A string is blank if it's empty or contains whitespaces only:
109
+ #
110
+ # ''.blank? # => true
111
+ # ' '.blank? # => true
112
+ # "\t\n\r".blank? # => true
113
+ # ' blah '.blank? # => false
114
+ #
115
+ # Unicode whitespace is supported:
116
+ #
117
+ # "\u00a0".blank? # => true
118
+ #
119
+ # @return [true, false]
120
+ def blank?
121
+ # The regexp that matches blank strings is expensive. For the case of empty
122
+ # strings we can speed up this method (~3.5x) with an empty? call. The
123
+ # penalty for the rest of strings is marginal.
124
+ empty? ||
125
+ begin
126
+ BLANK_RE.match?(self)
127
+ rescue Encoding::CompatibilityError
128
+ ENCODED_BLANKS[self.encoding].match?(self)
129
+ end
130
+ end
131
+ end
132
+
133
+ class Numeric #:nodoc:
134
+ # No number is blank:
135
+ #
136
+ # 1.blank? # => false
137
+ # 0.blank? # => false
138
+ #
139
+ # @return [false]
140
+ def blank?
141
+ false
142
+ end
143
+ end
144
+
145
+ class Time #:nodoc:
146
+ # No Time is blank:
147
+ #
148
+ # Time.now.blank? # => false
149
+ #
150
+ # @return [false]
151
+ def blank?
152
+ false
153
+ end
154
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Object
4
+ # Returns true if this object is included in the argument. Argument must be
5
+ # any object which responds to +#include?+. Usage:
6
+ #
7
+ # characters = ["Konata", "Kagami", "Tsukasa"]
8
+ # "Konata".in?(characters) # => true
9
+ #
10
+ # This will throw an +ArgumentError+ if the argument doesn't respond
11
+ # to +#include?+.
12
+ def in?(another_object)
13
+ another_object.include?(self)
14
+ rescue NoMethodError
15
+ raise ArgumentError.new("The parameter passed to #in? must respond to #include?")
16
+ end
17
+
18
+ # Returns the receiver if it's included in the argument otherwise returns +nil+.
19
+ # Argument must be any object which responds to +#include?+. Usage:
20
+ #
21
+ # params[:bucket_type].presence_in %w( project calendar )
22
+ #
23
+ # This will throw an +ArgumentError+ if the argument doesn't respond to +#include?+.
24
+ #
25
+ # @return [Object]
26
+ def presence_in(another_object)
27
+ in?(another_object) ? self : nil
28
+ end
29
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Object
4
+ # Returns a hash with string keys that maps instance variable names without "@" to their
5
+ # corresponding values.
6
+ #
7
+ # class C
8
+ # def initialize(x, y)
9
+ # @x, @y = x, y
10
+ # end
11
+ # end
12
+ #
13
+ # C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
14
+ def instance_values
15
+ Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
16
+ end
17
+
18
+ # Returns an array of instance variable names as strings including "@".
19
+ #
20
+ # class C
21
+ # def initialize(x, y)
22
+ # @x, @y = x, y
23
+ # end
24
+ # end
25
+ #
26
+ # C.new(0, 1).instance_variable_names # => ["@y", "@x"]
27
+ def instance_variable_names
28
+ instance_variables.map(&:to_s)
29
+ end
30
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cgi"
4
+
5
+ class Object
6
+ # Alias of <tt>to_s</tt>.
7
+ def to_param
8
+ to_s
9
+ end
10
+
11
+ # Converts an object into a string suitable for use as a URL query string,
12
+ # using the given <tt>key</tt> as the param name.
13
+ def to_query(key)
14
+ "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
15
+ end
16
+ end
17
+
18
+ class NilClass
19
+ # Returns +self+.
20
+ def to_param
21
+ self
22
+ end
23
+ end
24
+
25
+ class TrueClass
26
+ # Returns +self+.
27
+ def to_param
28
+ self
29
+ end
30
+ end
31
+
32
+ class FalseClass
33
+ # Returns +self+.
34
+ def to_param
35
+ self
36
+ end
37
+ end
38
+
39
+ class Array
40
+ # Calls <tt>to_param</tt> on all its elements and joins the result with
41
+ # slashes. This is used by <tt>url_for</tt> in Action Pack.
42
+ def to_param
43
+ collect(&:to_param).join "/"
44
+ end
45
+
46
+ # Converts an array into a string suitable for use as a URL query string,
47
+ # using the given +key+ as the param name.
48
+ #
49
+ # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
50
+ def to_query(key)
51
+ prefix = "#{key}[]"
52
+
53
+ if empty?
54
+ nil.to_query(prefix)
55
+ else
56
+ collect { |value| value.to_query(prefix) }.join "&"
57
+ end
58
+ end
59
+ end
60
+
61
+ class Hash
62
+ # Returns a string representation of the receiver suitable for use as a URL
63
+ # query string:
64
+ #
65
+ # {name: 'David', nationality: 'Danish'}.to_query
66
+ # # => "name=David&nationality=Danish"
67
+ #
68
+ # An optional namespace can be passed to enclose key names:
69
+ #
70
+ # {name: 'David', nationality: 'Danish'}.to_query('user')
71
+ # # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
72
+ #
73
+ # The string pairs "key=value" that conform the query string
74
+ # are sorted lexicographically in ascending order.
75
+ #
76
+ # This method is also aliased as +to_param+.
77
+ def to_query(namespace = nil)
78
+ query = collect do |key, value|
79
+ unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
80
+ value.to_query(namespace ? "#{namespace}[#{key}]" : key)
81
+ end
82
+ end.compact
83
+
84
+ query.sort! unless namespace.to_s.include?("[]")
85
+ query.join("&")
86
+ end
87
+
88
+ alias_method :to_param, :to_query
89
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Object
4
+ ##
5
+ # :method: try
6
+ #
7
+ # :call-seq:
8
+ # try(*a, &b)
9
+ #
10
+ # Invokes the public method whose name goes as first argument just like
11
+ # +public_send+ does, except that if the receiver does not respond to it the
12
+ # call returns +nil+ rather than raising an exception.
13
+ #
14
+ # This method is defined to be able to write
15
+ #
16
+ # @person.try(:name)
17
+ #
18
+ # instead of
19
+ #
20
+ # @person.name if @person
21
+ #
22
+ # +try+ calls can be chained:
23
+ #
24
+ # @person.try(:spouse).try(:name)
25
+ #
26
+ # instead of
27
+ #
28
+ # @person.spouse.name if @person && @person.spouse
29
+ #
30
+ # +try+ will also return +nil+ if the receiver does not respond to the method:
31
+ #
32
+ # @person.try(:non_existing_method) # => nil
33
+ #
34
+ # instead of
35
+ #
36
+ # @person.non_existing_method if @person.respond_to?(:non_existing_method) # => nil
37
+ #
38
+ # +try+ returns +nil+ when called on +nil+ regardless of whether it responds
39
+ # to the method:
40
+ #
41
+ # nil.try(:to_i) # => nil, rather than 0
42
+ #
43
+ # Arguments and blocks are forwarded to the method if invoked:
44
+ #
45
+ # @posts.try(:each_slice, 2) do |a, b|
46
+ # ...
47
+ # end
48
+ #
49
+ # The number of arguments in the signature must match. If the object responds
50
+ # to the method the call is attempted and +ArgumentError+ is still raised
51
+ # in case of argument mismatch.
52
+ #
53
+ # If +try+ is called without arguments it yields the receiver to a given
54
+ # block unless it is +nil+:
55
+ #
56
+ # @person.try do |p|
57
+ # ...
58
+ # end
59
+ #
60
+ # You can also call try with a block without accepting an argument, and the block
61
+ # will be instance_eval'ed instead:
62
+ #
63
+ # @person.try { upcase.truncate(50) }
64
+ #
65
+ # Please also note that +try+ is defined on +Object+. Therefore, it won't work
66
+ # with instances of classes that do not have +Object+ among their ancestors,
67
+ # like direct subclasses of +BasicObject+.
68
+
69
+ ##
70
+ # :method: try!
71
+ #
72
+ # :call-seq:
73
+ # try!(*a, &b)
74
+ #
75
+ # Same as #try, but raises a +NoMethodError+ exception if the receiver is
76
+ # not +nil+ and does not implement the tried method.
77
+ #
78
+ # "a".try!(:upcase) # => "A"
79
+ # nil.try!(:upcase) # => nil
80
+ # 123.try!(:upcase) # => NoMethodError: undefined method `upcase' for 123:Integer
81
+ def try(method_name = nil, *args, &b)
82
+ if method_name.nil? && block_given?
83
+ if b.arity == 0
84
+ instance_eval(&b)
85
+ else
86
+ yield self
87
+ end
88
+ elsif respond_to?(method_name)
89
+ public_send(method_name, *args, &b)
90
+ end
91
+ end
92
+
93
+ def try!(method_name = nil, *args, &b)
94
+ if method_name.nil? && block_given?
95
+ if b.arity == 0
96
+ instance_eval(&b)
97
+ else
98
+ yield self
99
+ end
100
+ else
101
+ public_send(method_name, *args, &b)
102
+ end
103
+ end
104
+ end
105
+
106
+ class NilClass
107
+ # Calling +try+ on +nil+ always returns +nil+.
108
+ # It becomes especially helpful when navigating through associations that may return +nil+.
109
+ #
110
+ # nil.try(:name) # => nil
111
+ #
112
+ # Without +try+
113
+ # @person && @person.children.any? && @person.children.first.name
114
+ #
115
+ # With +try+
116
+ # @person.try(:children).try(:first).try(:name)
117
+ def try(method_name = nil, *args)
118
+ nil
119
+ end
120
+
121
+ # Calling +try!+ on +nil+ always returns +nil+.
122
+ #
123
+ # nil.try!(:name) # => nil
124
+ def try!(method_name = nil, *args)
125
+ nil
126
+ end
127
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'object/blank.rb'
4
+ require_relative 'object/inclusion.rb'
5
+ require_relative 'object/instance_variables.rb'
6
+ require_relative 'object/to_query.rb'
7
+ require_relative 'object/try.rb'
data/lib/simple_ext.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir.glob(File.expand_path('simple_ext/*.rb', __dir__)).each do |path|
4
+ require path
5
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple_ext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tushar Hawaldar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-02-05 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Core ruby extentions extracted from Rails ActiveSupport
14
+ email:
15
+ - kumartushar1111@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/simple_ext.rb
21
+ - lib/simple_ext/array.rb
22
+ - lib/simple_ext/array/access.rb
23
+ - lib/simple_ext/digest.rb
24
+ - lib/simple_ext/digest/uuid.rb
25
+ - lib/simple_ext/file.rb
26
+ - lib/simple_ext/file/atomic.rb
27
+ - lib/simple_ext/hash.rb
28
+ - lib/simple_ext/hash/except.rb
29
+ - lib/simple_ext/hash/keys.rb
30
+ - lib/simple_ext/hash/merge.rb
31
+ - lib/simple_ext/hash/slice.rb
32
+ - lib/simple_ext/hash/values.rb
33
+ - lib/simple_ext/numeric.rb
34
+ - lib/simple_ext/numeric/bytes.rb
35
+ - lib/simple_ext/object.rb
36
+ - lib/simple_ext/object/blank.rb
37
+ - lib/simple_ext/object/inclusion.rb
38
+ - lib/simple_ext/object/instance_variables.rb
39
+ - lib/simple_ext/object/to_query.rb
40
+ - lib/simple_ext/object/try.rb
41
+ homepage: https://github.com/kumartushar/simple_ext.git
42
+ licenses:
43
+ - MIT
44
+ metadata: {}
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 3.1.2
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Simple Ruby Extentions
64
+ test_files: []