refinements 8.2.1 → 8.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3357c002920480a640ec080da0e8744f04a0883fa5ec54b75a88b77f7d2101d6
4
- data.tar.gz: f7bd7990e5f362ec9b08e06f42beca263bff1c78be5a68d834cf7dc4fe58e961
3
+ metadata.gz: 91c5c0e066eac0f4f01a1b28a73f8aa122cb51725ff510fe69466db4f2cd4dac
4
+ data.tar.gz: fc7b29eb6507fe08f2ebedd9a0b596c2bf70b7b9cd48a3b9de12cdae82613928
5
5
  SHA512:
6
- metadata.gz: 968fc32529ba33a2833b814d722e38e0a5caffcfc3eba154528838a75469a0701847e3a9419d395d632a4c47cf52d927420e95558b90e0cb1b0868066ee99cd9
7
- data.tar.gz: 3839e9d117a58251fd9304ad628a76aab0f22f7210542633e2e2fdc13abe38b38c25a126c111430f0c454bf29b5cc6c0b2a94d9473ed6caa59396dedeca8c2ba
6
+ metadata.gz: b9268d53d65140f5456f6c26521e7f55254480b58cfb30a73d9106aecb7a30977a02d03e8e37d6563904419a1a26d7dfec68f0f64a25f82baf294e817c01ac48
7
+ data.tar.gz: b564b642883464ed667be47ecef73be99ef48665d1f2be8f34ae5ec48b852c6b9a07ee3c4b0c542154a538f54ceaed4e1eca9d528841150469d2c8a5957b6c3e
checksums.yaml.gz.sig CHANGED
@@ -1,2 +1 @@
1
- VmT7 �:�UlVCȡ�]��0*���8Omr�;��VHR�Y'������ma͒X����O1���KW%��2U����0$�ٗ>[.T,F�@랉\��[&2ѯ�ƞ��r�X�˅(�O#7d�r#��g��0aJ��1yK1�bbV��N���sG��
2
- m��
1
+ `O+�b}_2^����'�}��q8Y���E:[(�^UMO�*@�z՚�߈ϡ �>�=�cc��At7Y����R �*�5��)yr�R���.���o(ꕚѝY���8� O�<h&��fyNT+f�~_C�lX��x�9K���V<|�@'�NC�W���|�v,����&� X-d���,TfQ�FD5�r�
data/README.adoc CHANGED
@@ -11,7 +11,9 @@ image::https://img.shields.io/badge/code_style-alchemists-brightgreen.svg[Alchem
11
11
  [link=https://circleci.com/gh/bkuhlmann/refinements]
12
12
  image::https://circleci.com/gh/bkuhlmann/refinements.svg?style=svg[Circle CI Status]
13
13
 
14
- A collection of refinements (enhancements) to primitive Ruby objects.
14
+ Refinements is a collection of enhancements to primitive Ruby objects without needing to resort
15
+ painful and hard to debug monkey patches. These refinements give you additional syntactic sugar to
16
+ build clean and concise implementations all while using less code.
15
17
 
16
18
  toc::[]
17
19
 
@@ -105,13 +107,14 @@ The following sections demonstrate how each refinement enriches your objects wit
105
107
 
106
108
  ===== #compress
107
109
 
108
- Removes `nil` and empty values without mutating itself.
110
+ Removes `nil` and empty objects without mutating itself.
109
111
 
110
112
  [source,ruby]
111
113
  ----
112
- example = ["An", nil, "", "Example"]
113
- example.compress # => ["An", "Example"]
114
- example # => ["An", nil, "", "Example"]
114
+ object = Object.new
115
+ example = [1, "blueberry", nil, "", [], {}, object]
116
+ example.compress # => [1, "blueberry", object]
117
+ example # => [1, "blueberry", nil, "", [], {}, object]
115
118
  ----
116
119
 
117
120
  ===== #compress!
@@ -120,9 +123,10 @@ Removes `nil` and empty values while mutating itself.
120
123
 
121
124
  [source,ruby]
122
125
  ----
123
- example = ["An", nil, "", "Example"]
124
- example.compress! # => ["An", "Example"]
125
- example # => ["An", "Example"]
126
+ object = Object.new
127
+ example = [1, "blueberry", nil, "", [], {}, object]
128
+ example.compress # => [1, "blueberry", object]
129
+ example # => [1, "blueberry", object]
126
130
  ----
127
131
 
128
132
  ===== #excluding
@@ -249,6 +253,22 @@ Allows one to inspect a big decimal with numeric representation.
249
253
  BigDecimal.new("5.0E-10").inspect # => "#<BigDecimal:3fd3d458fe84 0.0000000005>"
250
254
  ----
251
255
 
256
+ ==== Class
257
+
258
+ ===== #descendants
259
+
260
+ Answers descendants of a class.
261
+
262
+ [source,ruby]
263
+ ----
264
+ a = Class.new
265
+ b = Class.new a
266
+ c = Class.new a
267
+
268
+ a.descendants # => [b, c]
269
+ Class.new.descendants # => []
270
+ ----
271
+
252
272
  ==== DateTime
253
273
 
254
274
  ===== .utc
@@ -286,6 +306,30 @@ example = Hash.with_default []
286
306
  example[:b] # => []
287
307
  ----
288
308
 
309
+ ===== #compress
310
+
311
+ Removes `nil` and empty objects without mutating itself.
312
+
313
+ [source,ruby]
314
+ ----
315
+ object = Object.new
316
+ example = {a: 1, b: "blueberry", c: nil, d: "", e: [], f: {}, g: object}
317
+ example.compress # => {a: 1, b: "blueberry", g: object}
318
+ example # => {a: 1, b: "blueberry", c: nil, d: "", e: [], f: {}, g: object}
319
+ ----
320
+
321
+ ===== #compress!
322
+
323
+ Removes `nil` and empty objects while mutating itself.
324
+
325
+ [source,ruby]
326
+ ----
327
+ object = Object.new
328
+ example = {a: 1, b: "blueberry", c: nil, d: "", e: [], f: {}, g: object}
329
+ example.compress! # => {a: 1, b: "blueberry", g: object}
330
+ example # => {a: 1, b: "blueberry", g: object}
331
+ ----
332
+
289
333
  ===== #deep_merge
290
334
 
291
335
  Merges deeply nested hashes together without mutating itself.
@@ -352,6 +396,22 @@ example.deep_symbolize_keys! # => {a: {b: 1}}
352
396
  example # => {a: {b: 1}}
353
397
  ----
354
398
 
399
+ ===== #fetch_value
400
+
401
+ Fetches value for exiting or missing key. Behavior is identical to `#fetch` except when the value of
402
+ the key is `nil` you'll get the default value instead. This eliminates the need for using an _or_
403
+ expression `example.fetch(:desired_key) || "default_value"`.
404
+
405
+ [source,ruby]
406
+ ----
407
+ {a: "test"}.fetch_value :a, "default" # => "test"
408
+ {a: "test"}.fetch_value :a # => "test"
409
+ {a: nil}.fetch_value :a, "default" # => "default"
410
+ {}.fetch_value(:a) { "default" } # => "default"
411
+ {}.fetch_value :a # => KeyError
412
+ {a: "test"}.fetch_value # => ArgumentError
413
+ ----
414
+
355
415
  ===== #flatten_keys
356
416
 
357
417
  Flattens nested keys as top-level keys without mutating itself. Does not handle nested arrays,
@@ -535,7 +595,7 @@ Wraps `Dir.mktmpdir` with the following behavior (see
535
595
  link:https://rubyapi.org/o/Dir.mktmpdir#method-c-mktmpdir[Dir.mktmpdir] for details):
536
596
 
537
597
  * *Without Block* - Answers a newly created Pathname instance which is not automatically cleaned up.
538
- * *With Block* Yields a Pathname instance, answers result of given block, and automatidally cleans
598
+ * *With Block* Yields a Pathname instance, answers result of given block, and automatically cleans
539
599
  up temporary directory after block exits.
540
600
 
541
601
  The following examples use truncated temporary directories for illustration purposes only. In
@@ -614,6 +674,30 @@ Copies file from current location to new location while answering itself so it c
614
674
  Pathname("input.txt").copy Pathname("output.txt") # => Pathname("input.txt")
615
675
  ----
616
676
 
677
+ ===== #deep_touch
678
+
679
+ Has all of the same functionality as the `#touch` method while being able to create ancestor
680
+ directories no matter how deeply nested the file might be.
681
+
682
+ [source,ruby]
683
+ ----
684
+ Pathname("a/b/c/d.txt").touch # => Pathname("a/b/c/d.txt")
685
+ Pathname("a/b/c/d.txt").touch Time.now - 1 # => Pathname("a/b/c/d.txt")
686
+ ----
687
+
688
+ ===== #delete
689
+
690
+ Deletes file or directory and answers itself so it can be chained.
691
+
692
+ [source,ruby]
693
+ ----
694
+ # When path exists.
695
+ Pathname("/example.txt").touch.delete # => Pathname("/example")
696
+
697
+ # When path doesn't exist.
698
+ Pathname("/example.txt").delete # => Errno::ENOENT
699
+ ----
700
+
617
701
  ===== #directories
618
702
 
619
703
  Answers all directories or filtered directories for current path.
@@ -625,6 +709,20 @@ Pathname("/example").directories "a*" # => [Pathname("a")]
625
709
  Pathname("/example").directories flag: File::FNM_DOTMATCH # => [Pathname(".."), Pathname(".")]
626
710
  ----
627
711
 
712
+ ===== #empty
713
+
714
+ Empties a directory of children (i.e. folders, nested folders, or files) or clears an existing file
715
+ of contents. If a directory or file doesn't exist, it will be created.
716
+
717
+ [source,ruby]
718
+ ----
719
+ directory = Pathname("test").make_path
720
+ file = directory.join("test.txt").write("example")
721
+
722
+ file.empty.read # => ""
723
+ directory.empty.children # => []
724
+ ----
725
+
628
726
  ===== #extensions
629
727
 
630
728
  Answers file extensions as an array.
@@ -755,10 +853,13 @@ Pathname("/test.txt").rewrite { |body| body.sub "[token]", "example" } # => Pat
755
853
 
756
854
  ===== #touch
757
855
 
758
- Updates access and modification times for path. Defaults to current time.
856
+ Updates access and modification times for an existing path by defaulting to current time. When path
857
+ doesn't exist, it will be created as a file.
759
858
 
760
859
  [source,ruby]
761
860
  ----
861
+ Pathname("example").touch # => Pathname("example")
862
+ Pathname("example").touch Time.now - 1 # => Pathname("example")
762
863
  Pathname("example.txt").touch # => Pathname("example.txt")
763
864
  Pathname("example.txt").touch Time.now - 1 # => Pathname("example.txt")
764
865
  ----
@@ -837,6 +938,46 @@ Answers last character of a string or last set of characters if given a number.
837
938
  "instant".last 3 # => "ant"
838
939
  ----
839
940
 
941
+ ===== #pluralize
942
+
943
+ Answers plural form of self when given a suffix to add. The plural form of the word can be
944
+ dynamically calculated when given a count and a replacement pattern (i.e. string or regular
945
+ expression) can be supplied for further specificity. Usage is based on
946
+ link:https://en.wikipedia.org/wiki/English_plurals[plurals in English] which may or may not work
947
+ well in other languages.
948
+
949
+ [source,ruby]
950
+ ----
951
+ "apple".pluralize "s" # => apples
952
+ "apple".pluralize "s", count: 0 # => apples
953
+ "apple".pluralize "s", count: 1 # => apple
954
+ "apple".pluralize "s", count: -1 # => apple
955
+ "apple".pluralize "s", count: 2 # => apples
956
+ "apple".pluralize "s", count: -2 # => apples
957
+ "cactus".pluralize "i", replace: "us" # => cacti
958
+ "cul-de-sac".pluralize "ls", replace: "l" # => culs-de-sac
959
+ ----
960
+
961
+ ===== #singularize
962
+
963
+ Answers singular form of self when given a suffix to remove (can be a string or a regular
964
+ expression). The singular form of the word can be dynamically calculated when given a count and a
965
+ replacement string can be supplied for further specificity. Usage is based on
966
+ link:https://en.wikipedia.org/wiki/English_plurals[plurals in English] which may or may not work
967
+ well in other languages.
968
+
969
+ [source,ruby]
970
+ ----
971
+ "apples".singularize "s" # => apple
972
+ "apples".singularize "s", count: 0 # => apples
973
+ "apples".singularize "s", count: 1 # => apple
974
+ "apples".singularize "s", count: -1 # => apple
975
+ "apples".singularize "s", count: 2 # => apples
976
+ "apples".singularize "s", count: -2 # => apples
977
+ "cacti".singularize "i", replace: "us" # => cactus
978
+ "culs-de-sac".singularize "ls", replace: "l" # => cul-de-sac
979
+ ----
980
+
840
981
  ===== #snakecase
841
982
 
842
983
  Answers a snakecased string.
@@ -1031,6 +1172,24 @@ example.revalue! # => #<struct
1031
1172
  example # => #<struct a=1, b=2, c=3>
1032
1173
  ----
1033
1174
 
1175
+ ==== Symbol
1176
+
1177
+ ===== #call
1178
+
1179
+ Enhances symbol-to-proc by allowing you to send additional arguments and/or a block. This only works
1180
+ with public methods in order to not break encapsulation.
1181
+
1182
+ [source,ruby]
1183
+ ----
1184
+ %w[clue crow cow].map(&:tr.call("c", "b")) # => ["blue", "brow", "bow"]
1185
+ [%w[a b c], %w[c a b]].map(&:index.call { |element| element == "b" }) # => [1, 2]
1186
+ %w[1.outside 2.inside].map(&:sub.call(/\./) { |bullet| bullet + " " }) # => ["1. outside", "2. inside"]
1187
+ [1, 2, 3].map(&:to_s.call) # => ["1", "2", "3"]
1188
+ ----
1189
+
1190
+ ⚠️ Use of `#call` without any arguments or block should be avoided in order to not incur extra
1191
+ processing costs since the original symbol-to-proc call can used instead.
1192
+
1034
1193
  == Development
1035
1194
 
1036
1195
  To contribute, run:
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Refinements
4
+ # Provides additional enhancements to the Array primitive.
4
5
  module Arrays
5
6
  refine Array do
6
- def compress = compact.reject(&:empty?)
7
+ def compress = dup.compress!
7
8
 
8
- def compress! = replace(compress)
9
+ def compress!
10
+ compact!
11
+ delete_if { |element| element.respond_to?(:empty?) && element.empty? }
12
+ end
9
13
 
10
14
  def excluding(*elements) = self - elements.flatten
11
15
 
@@ -3,6 +3,7 @@
3
3
  require "bigdecimal"
4
4
 
5
5
  module Refinements
6
+ # Provides additional enhancements to the BigDecimal primitive.
6
7
  module BigDecimals
7
8
  refine BigDecimal do
8
9
  def inspect = format("#<BigDecimal:%{id} %{string}>", id: object_id, string: to_s("F"))
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Refinements
4
+ # Provides additional enhancements to Class objects.
5
+ module Classes
6
+ refine Class do
7
+ def descendants
8
+ ObjectSpace.each_object(singleton_class)
9
+ .reject { |klass| klass.singleton_class? || klass == self }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -3,6 +3,7 @@
3
3
  require "date"
4
4
 
5
5
  module Refinements
6
+ # Provides additional enhancements to the DateTime primitive.
6
7
  module DateTimes
7
8
  refine DateTime.singleton_class do
8
9
  def utc = now.new_offset(0)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Refinements
4
+ # Provides additional enhancements to the Hash primitive.
4
5
  module Hashes
5
6
  refine Hash.singleton_class do
6
7
  def infinite
@@ -11,6 +12,14 @@ module Refinements
11
12
  end
12
13
 
13
14
  refine Hash do
15
+ def compress = dup.compress!
16
+
17
+ def compress!
18
+ return self if empty?
19
+
20
+ compact!.delete_if { |_key, value| value.respond_to?(:empty?) && value.empty? }
21
+ end
22
+
14
23
  def deep_merge other
15
24
  clazz = self.class
16
25
 
@@ -33,6 +42,10 @@ module Refinements
33
42
 
34
43
  def deep_symbolize_keys! = replace(deep_symbolize_keys)
35
44
 
45
+ def fetch_value key, *default_value, &block
46
+ fetch(key, *default_value, &block) || default_value.first
47
+ end
48
+
36
49
  # :reek:TooManyStatements
37
50
  def flatten_keys prefix: nil, delimiter: "_", cast: :to_sym
38
51
  fail StandardError, "Unknown cast: #{cast}." unless %i[to_sym to_s].include? cast
@@ -62,13 +75,13 @@ module Refinements
62
75
  end
63
76
  end
64
77
 
65
- def stringify_keys = reduce({}) { |hash, (key, value)| hash.merge key.to_s => value }
78
+ def stringify_keys = transform_keys(&:to_s)
66
79
 
67
- def stringify_keys! = replace(stringify_keys)
80
+ def stringify_keys! = transform_keys!(&:to_s)
68
81
 
69
- def symbolize_keys = reduce({}) { |hash, (key, value)| hash.merge key.to_sym => value }
82
+ def symbolize_keys = transform_keys(&:to_sym)
70
83
 
71
- def symbolize_keys! = replace(symbolize_keys)
84
+ def symbolize_keys! = transform_keys!(&:to_sym)
72
85
 
73
86
  def use &block
74
87
  return [] unless block
@@ -5,7 +5,7 @@ module Refinements
5
5
  module Identity
6
6
  NAME = "refinements"
7
7
  LABEL = "Refinements"
8
- VERSION = "8.2.1"
9
- VERSION_LABEL = "#{LABEL} #{VERSION}"
8
+ VERSION = "8.5.0"
9
+ VERSION_LABEL = "#{LABEL} #{VERSION}".freeze
10
10
  end
11
11
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Refinements
4
+ # Provides additional enhancements to the IO primitive.
4
5
  module IOs
5
6
  refine IO.singleton_class do
6
7
  def void
@@ -3,9 +3,9 @@
3
3
  require "pathname"
4
4
 
5
5
  module Refinements
6
+ # Provides additional enhancements to the Pathname primitive.
6
7
  module Pathnames
7
8
  refine Kernel do
8
- # :reek:UncommunicativeMethodName
9
9
  def Pathname object
10
10
  return super(String(object)) unless object
11
11
 
@@ -24,7 +24,7 @@ module Refinements
24
24
  new(root).files(pattern).each { |path| require path.to_s }
25
25
  end
26
26
 
27
- def root = new("/")
27
+ def root = new(File::SEPARATOR)
28
28
  end
29
29
 
30
30
  refine Pathname do
@@ -38,10 +38,16 @@ module Refinements
38
38
  self
39
39
  end
40
40
 
41
+ def deep_touch(...) = make_ancestors.touch(...)
42
+
43
+ def delete = super && self
44
+
41
45
  def directories pattern = "*", flag: File::FNM_SYSCASE
42
46
  glob(pattern, flag).select(&:directory?).sort
43
47
  end
44
48
 
49
+ def empty = file? ? (truncate(0) and self) : remove_tree.make_dir
50
+
45
51
  def extensions = basename.to_s.split(/(?=\.)+/).tap(&:shift)
46
52
 
47
53
  def files(pattern = "*", flag: File::FNM_SYSCASE) = glob(pattern, flag).select(&:file?).sort
@@ -3,6 +3,7 @@
3
3
  require "stringio"
4
4
 
5
5
  module Refinements
6
+ # Provides additional enhancements to the StringIO primitive.
6
7
  module StringIOs
7
8
  refine StringIO do
8
9
  def reread(length = nil, buffer: nil) = tap(&:rewind).read(length, buffer)
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Refinements
4
+ # Provides additional enhancements to the String primitive.
4
5
  module Strings
5
6
  DELIMITERS = %r([a-z][A-Z]|\s*-\s*|\s*/\s*|\s*:+\s*|\s*_\s*|\s+)
6
7
 
7
8
  refine String do
8
- def blank? = match?(/\A\s*\z/)
9
+ def blank? = empty? || match?(/\A[[:space:]]*\z/)
9
10
 
10
11
  def camelcase
11
12
  return up unless match? DELIMITERS
@@ -35,7 +36,7 @@ module Refinements
35
36
  def indent multiplier = 1, padding: " "
36
37
  return self if multiplier.negative?
37
38
 
38
- padding * multiplier + self
39
+ (padding * multiplier) + self
39
40
  end
40
41
 
41
42
  def last number = 0
@@ -49,6 +50,10 @@ module Refinements
49
50
  self[(min + 1)..]
50
51
  end
51
52
 
53
+ def pluralize(suffix, replace: /$/, count: 0) = count.abs == 1 ? self : sub(replace, suffix)
54
+
55
+ def singularize(suffix, replace: "", count: 1) = count.abs == 1 ? sub(suffix, replace) : self
56
+
52
57
  def snakecase
53
58
  return downcase unless match? DELIMITERS
54
59
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Refinements
4
+ # Provides additional enhancements to the Struct primitive.
4
5
  module Structs
5
6
  refine Struct.singleton_class do
6
7
  def keyworded? = inspect.include?("keyword_init: true")
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Refinements
4
+ # Provides additional enhancements to the Symbol primitive.
5
+ module Symbols
6
+ refine Symbol do
7
+ def call *arguments, &block
8
+ proc { |receiver| receiver.public_send self, *arguments, &block }
9
+ end
10
+ end
11
+ end
12
+ end
data/lib/refinements.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "refinements/identity"
4
4
  require "refinements/arrays"
5
+ require "refinements/classes"
5
6
  require "refinements/big_decimals"
6
7
  require "refinements/date_times"
7
8
  require "refinements/hashes"
@@ -10,3 +11,4 @@ require "refinements/pathnames"
10
11
  require "refinements/strings"
11
12
  require "refinements/string_ios"
12
13
  require "refinements/structs"
14
+ require "refinements/symbols"
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: refinements
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.2.1
4
+ version: 8.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brooke Kuhlmann
@@ -28,7 +28,7 @@ cert_chain:
28
28
  lkHilIrX69jq8wMPpBhlaw2mRmeSL50Wv5u6xVBvOHhXFSP1crXM95vfLhLyRYod
29
29
  W2A=
30
30
  -----END CERTIFICATE-----
31
- date: 2021-08-08 00:00:00.000000000 Z
31
+ date: 2021-10-16 00:00:00.000000000 Z
32
32
  dependencies: []
33
33
  description:
34
34
  email:
@@ -44,6 +44,7 @@ files:
44
44
  - lib/refinements.rb
45
45
  - lib/refinements/arrays.rb
46
46
  - lib/refinements/big_decimals.rb
47
+ - lib/refinements/classes.rb
47
48
  - lib/refinements/date_times.rb
48
49
  - lib/refinements/hashes.rb
49
50
  - lib/refinements/identity.rb
@@ -52,6 +53,7 @@ files:
52
53
  - lib/refinements/string_ios.rb
53
54
  - lib/refinements/strings.rb
54
55
  - lib/refinements/structs.rb
56
+ - lib/refinements/symbols.rb
55
57
  homepage: https://www.alchemists.io/projects/refinements
56
58
  licenses:
57
59
  - Apache-2.0
@@ -75,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
77
  - !ruby/object:Gem::Version
76
78
  version: '0'
77
79
  requirements: []
78
- rubygems_version: 3.2.25
80
+ rubygems_version: 3.2.29
79
81
  signing_key:
80
82
  specification_version: 4
81
83
  summary: A collection of refinements to core Ruby objects.
metadata.gz.sig CHANGED
Binary file