simple_ext 0.1.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.
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: []