tins 1.32.0 → 1.44.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.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.contexts/code_comment.rb +23 -0
  3. data/.contexts/full.rb +31 -0
  4. data/.contexts/lib.rb +24 -0
  5. data/.contexts/yard.md +92 -0
  6. data/.github/workflows/codeql-analysis.yml +72 -0
  7. data/CHANGES.md +194 -0
  8. data/README.md +161 -90
  9. data/Rakefile +23 -19
  10. data/examples/let.rb +8 -40
  11. data/examples/mail.rb +0 -1
  12. data/examples/ones_difference.stm +0 -1
  13. data/examples/turing.rb +3 -1
  14. data/lib/tins/alias.rb +1 -0
  15. data/lib/tins/annotate.rb +37 -27
  16. data/lib/tins/ask_and_send.rb +41 -0
  17. data/lib/tins/attempt.rb +39 -0
  18. data/lib/tins/bijection.rb +34 -0
  19. data/lib/tins/case_predicate.rb +21 -0
  20. data/lib/tins/complete.rb +16 -0
  21. data/lib/tins/concern.rb +100 -0
  22. data/lib/tins/date_dummy.rb +36 -4
  23. data/lib/tins/date_time_dummy.rb +34 -2
  24. data/lib/tins/deep_dup.rb +9 -2
  25. data/lib/tins/deprecate.rb +27 -0
  26. data/lib/tins/dslkit.rb +563 -59
  27. data/lib/tins/duration.rb +160 -3
  28. data/lib/tins/expose.rb +54 -5
  29. data/lib/tins/extract_last_argument_options.rb +9 -0
  30. data/lib/tins/file_binary.rb +108 -25
  31. data/lib/tins/find.rb +114 -11
  32. data/lib/tins/generator.rb +10 -2
  33. data/lib/tins/go.rb +81 -4
  34. data/lib/tins/hash_bfs.rb +69 -0
  35. data/lib/tins/hash_symbolize_keys_recursive.rb +62 -4
  36. data/lib/tins/hash_union.rb +47 -2
  37. data/lib/tins/if_predicate.rb +31 -0
  38. data/lib/tins/implement.rb +50 -0
  39. data/lib/tins/limited.rb +105 -29
  40. data/lib/tins/lines_file.rb +81 -2
  41. data/lib/tins/lru_cache.rb +54 -17
  42. data/lib/tins/memoize.rb +86 -58
  43. data/lib/tins/method_description.rb +87 -4
  44. data/lib/tins/minimize.rb +39 -11
  45. data/lib/tins/module_group.rb +27 -2
  46. data/lib/tins/named_set.rb +20 -0
  47. data/lib/tins/null.rb +86 -15
  48. data/lib/tins/once.rb +61 -4
  49. data/lib/tins/p.rb +44 -8
  50. data/lib/tins/partial_application.rb +66 -7
  51. data/lib/tins/proc_compose.rb +58 -1
  52. data/lib/tins/proc_prelude.rb +97 -10
  53. data/lib/tins/range_plus.rb +30 -2
  54. data/lib/tins/require_maybe.rb +36 -0
  55. data/lib/tins/responding.rb +39 -0
  56. data/lib/tins/secure_write.rb +25 -5
  57. data/lib/tins/sexy_singleton.rb +46 -48
  58. data/lib/tins/string_byte_order_mark.rb +33 -2
  59. data/lib/tins/string_camelize.rb +31 -2
  60. data/lib/tins/string_named_placeholders.rb +70 -0
  61. data/lib/tins/string_underscore.rb +33 -2
  62. data/lib/tins/string_version.rb +183 -10
  63. data/lib/tins/subhash.rb +35 -10
  64. data/lib/tins/temp_io.rb +7 -0
  65. data/lib/tins/temp_io_enum.rb +19 -0
  66. data/lib/tins/terminal.rb +34 -12
  67. data/lib/tins/thread_local.rb +69 -11
  68. data/lib/tins/time_dummy.rb +47 -21
  69. data/lib/tins/to.rb +15 -0
  70. data/lib/tins/to_proc.rb +17 -4
  71. data/lib/tins/token.rb +61 -2
  72. data/lib/tins/unit.rb +288 -149
  73. data/lib/tins/version.rb +1 -1
  74. data/lib/tins/write.rb +14 -3
  75. data/lib/tins/xt/blank.rb +81 -2
  76. data/lib/tins/xt/concern.rb +51 -0
  77. data/lib/tins/xt/deep_dup.rb +4 -2
  78. data/lib/tins/xt/deprecate.rb +5 -0
  79. data/lib/tins/xt/full.rb +56 -11
  80. data/lib/tins/xt/hash_bfs.rb +7 -0
  81. data/lib/tins/xt/irb.rb +46 -2
  82. data/lib/tins/xt/method_description.rb +0 -12
  83. data/lib/tins/xt/minimize.rb +7 -0
  84. data/lib/tins/xt/named.rb +71 -16
  85. data/lib/tins/xt/proc_compose.rb +4 -0
  86. data/lib/tins/xt/secure_write.rb +0 -4
  87. data/lib/tins/xt/string.rb +1 -0
  88. data/lib/tins/xt/string_camelize.rb +4 -2
  89. data/lib/tins/xt/string_named_placeholders.rb +7 -0
  90. data/lib/tins/xt/string_underscore.rb +4 -2
  91. data/lib/tins/xt/subhash.rb +11 -0
  92. data/lib/tins/xt/time_freezer.rb +43 -6
  93. data/lib/tins/xt/write.rb +0 -4
  94. data/lib/tins/xt.rb +3 -3
  95. data/lib/tins.rb +19 -3
  96. data/tests/annotate_test.rb +0 -1
  97. data/tests/bijection_test.rb +0 -1
  98. data/tests/concern_test.rb +63 -4
  99. data/tests/date_dummy_test.rb +0 -1
  100. data/tests/date_time_dummy_test.rb +0 -1
  101. data/tests/delegate_test.rb +0 -1
  102. data/tests/deprecate_test.rb +41 -0
  103. data/tests/dslkit_test.rb +15 -1
  104. data/tests/duration_test.rb +23 -2
  105. data/tests/dynamic_scope_test.rb +0 -1
  106. data/tests/extract_last_argument_options_test.rb +0 -1
  107. data/tests/find_test.rb +0 -1
  108. data/tests/from_module_test.rb +30 -3
  109. data/tests/generator_test.rb +0 -1
  110. data/tests/go_test.rb +0 -1
  111. data/tests/hash_bfs_test.rb +34 -0
  112. data/tests/hash_symbolize_keys_recursive_test.rb +0 -1
  113. data/tests/implement_test.rb +6 -9
  114. data/tests/limited_test.rb +12 -12
  115. data/tests/lines_file_test.rb +2 -1
  116. data/tests/lru_cache_test.rb +12 -1
  117. data/tests/memoize_test.rb +0 -1
  118. data/tests/method_description_test.rb +14 -20
  119. data/tests/minimize_test.rb +0 -1
  120. data/tests/module_group_test.rb +0 -1
  121. data/tests/named_set_test.rb +0 -1
  122. data/tests/null_test.rb +0 -1
  123. data/tests/partial_application_test.rb +4 -0
  124. data/tests/proc_prelude_test.rb +1 -1
  125. data/tests/require_maybe_test.rb +0 -1
  126. data/tests/scope_test.rb +1 -2
  127. data/tests/secure_write_test.rb +6 -1
  128. data/tests/sexy_singleton_test.rb +1 -1
  129. data/tests/string_named_placeholders.rb +109 -0
  130. data/tests/string_version_test.rb +3 -1
  131. data/tests/subhash_test.rb +0 -1
  132. data/tests/test_helper.rb +4 -7
  133. data/tests/time_dummy_test.rb +0 -1
  134. data/tests/time_freezer_test.rb +1 -1
  135. data/tests/to_test.rb +6 -6
  136. data/tests/token_test.rb +0 -1
  137. data/tests/unit_test.rb +0 -1
  138. data/tins.gemspec +18 -30
  139. metadata +55 -38
  140. data/lib/tins/count_by.rb +0 -8
  141. data/lib/tins/deep_const_get.rb +0 -50
  142. data/lib/tins/timed_cache.rb +0 -51
  143. data/lib/tins/uniq_by.rb +0 -10
  144. data/lib/tins/xt/count_by.rb +0 -11
  145. data/lib/tins/xt/deep_const_get.rb +0 -7
  146. data/lib/tins/xt/uniq_by.rb +0 -15
  147. data/tests/count_by_test.rb +0 -17
  148. data/tests/deep_const_get_test.rb +0 -37
  149. data/tests/uniq_by_test.rb +0 -31
  150. /data/{COPYING → LICENSE} +0 -0
data/lib/tins/memoize.rb CHANGED
@@ -1,91 +1,119 @@
1
1
  require 'tins/extract_last_argument_options'
2
+ require 'mize'
2
3
 
3
4
  module Tins
5
+ # Provides memoization functionality for methods and functions with support
6
+ # for instance-level and class-level caching respectively.
7
+ #
8
+ # @example Basic method memoization
9
+ # class Calculator
10
+ # def expensive_calculation(x, y)
11
+ # # Some expensive computation
12
+ # x * y
13
+ # end
14
+ # memoize_method :expensive_calculation
15
+ # end
16
+ #
17
+ # @example Function memoization (shared across instances)
18
+ # class MathUtils
19
+ # def self.factorial(n)
20
+ # n <= 1 ? 1 : n * factorial(n - 1)
21
+ # end
22
+ # memoize_function :factorial
23
+ # end
24
+ #
25
+ # @example With freezing results
26
+ # class DataProcessor
27
+ # def process_data(input)
28
+ # # Process data and return result
29
+ # input.dup
30
+ # end
31
+ # memoize_method :process_data, freeze: true
32
+ # end
33
+ #
34
+ # @note This module is deprecated in favor of the {https://github.com/flori/mize mize} gem.
35
+ # Use `memoize method:` or `memoize function:` from the mize gem directly.
4
36
  module Memoize
37
+ # Provides cache management methods for memoized functions and methods.
38
+ # This module is included in classes that use memoization functionality.
39
+ #
40
+ # @example Using cache methods directly
41
+ # class Example
42
+ # include Tins::Memoize::CacheMethods
43
+ #
44
+ # def expensive_method
45
+ # # Some expensive computation
46
+ # end
47
+ # memoize_method :expensive_method
48
+ # end
49
+ #
50
+ # obj = Example.new
51
+ # obj.memoize_cache_clear # Clear all cached values
52
+ # obj.__memoize_cache__ # Access the internal cache object
5
53
  module CacheMethods
6
- # Return the cache object.
54
+ # Return the cache object used for memoization.
55
+ #
56
+ # @return [Object] The cache instance
7
57
  def __memoize_cache__
8
- @__memoize_cache__ ||= {}
58
+ if @__memoize_cache__
59
+ @__memoize_cache__
60
+ else
61
+ @__memoize_cache__ = __mize_cache__
62
+ def @__memoize_cache__.empty?
63
+ @data.empty?
64
+ end
65
+ @__memoize_cache__
66
+ end
9
67
  end
10
68
 
11
- # Clear cached values for all methods/functions.
69
+ # Clear cached values for all methods/functions of this object.
70
+ #
71
+ # @return [self] For chaining
12
72
  def memoize_cache_clear
13
73
  __memoize_cache__.clear
14
74
  self
15
75
  end
16
-
17
- def memoize_apply_visibility(id)
18
- visibility = instance_eval do
19
- case
20
- when private_method_defined?(id)
21
- :private
22
- when protected_method_defined?(id)
23
- :protected
24
- end
25
- end
26
- yield
27
- ensure
28
- visibility and __send__(visibility, id)
29
- end
30
76
  end
31
77
 
32
78
  class ::Module
33
- # Automatically memoize calls of the the methods +method_ids+. The
34
- # memoized results do NOT ONLY depend on the arguments, but ALSO on the
35
- # object the method is called on.
79
+ # Memoize a method so that its return value is cached based on the arguments
80
+ # and the object instance. Each instance maintains its own cache.
81
+ #
82
+ # @param method_ids [Array<Symbol>] One or more method names to memoize
83
+ # @option opts [Boolean] :freeze (false) Whether to freeze results
84
+ # @return [Symbol, Array<Symbol>] The memoized method name(s)
85
+ #
86
+ # @deprecated Use `memoize method:` from the mize gem instead.
36
87
  def memoize_method(*method_ids)
88
+ warn "[DEPRECATION] `memoize_method` is deprecated. Please use `memoize method:` from mize gem."
37
89
  method_ids.extend(ExtractLastArgumentOptions)
38
90
  method_ids, opts = method_ids.extract_last_argument_options
39
- include CacheMethods
40
- method_ids.each do |method_id|
41
- method_id = method_id.to_s.to_sym
42
- memoize_apply_visibility method_id do
43
- orig_method = instance_method(method_id)
44
- __send__(:define_method, method_id) do |*args|
45
- mc = __memoize_cache__
46
- if mc.key?(method_id) and result = mc[method_id][args]
47
- result
48
- else
49
- (mc[method_id] ||= {})[args] = result = orig_method.bind(self).call(*args)
50
- $DEBUG and warn "#{self.class} cached method #{method_id}(#{args.inspect unless args.empty?}) = #{result.inspect} [#{__id__}]"
51
- opts[:freeze] and result.freeze
52
- end
53
- result
54
- end
55
- end
91
+ method_ids.each do |method|
92
+ memoize method:, **opts.slice(:freeze)
56
93
  end
94
+ include CacheMethods
57
95
  method_ids.size == 1 ? method_ids.first : method_ids
58
96
  end
59
97
 
60
98
  include CacheMethods
61
99
 
62
- # Automatically memoize calls of the functions +function_ids+. The
63
- # memoized result does ONLY depend on the arguments given to the
64
- # function.
100
+ # Memoize a function (class method) so that its return value is cached
101
+ # based only on the arguments, shared across all instances of the class.
102
+ #
103
+ # @param function_ids [Array<Symbol>] One or more function names to memoize
104
+ # @option opts [Boolean] :freeze (false) Whether to freeze results
105
+ # @return [Symbol, Array<Symbol>] The memoized function name(s)
106
+ #
107
+ # @deprecated Use `memoize function:` from the mize gem instead.
65
108
  def memoize_function(*function_ids)
109
+ warn "[DEPRECATION] `memoize_function` is deprecated. Please use `memoize function:` from mize gem."
66
110
  function_ids.extend(ExtractLastArgumentOptions)
67
111
  function_ids, opts = function_ids.extract_last_argument_options
68
- mc = __memoize_cache__
69
- function_ids.each do |function_id|
70
- function_id = function_id.to_s.to_sym
71
- memoize_apply_visibility function_id do
72
- orig_function = instance_method(function_id)
73
- __send__(:define_method, function_id) do |*args|
74
- if mc.key?(function_id) and result = mc[function_id][args]
75
- result
76
- else
77
- (mc[function_id] ||= {})[args] = result = orig_function.bind(self).call(*args)
78
- opts[:freeze] and result.freeze
79
- $DEBUG and warn "#{self.class} cached function #{function_id}(#{args.inspect unless args.empty?}) = #{result.inspect}"
80
- end
81
- result
82
- end
83
- end
112
+ function_ids.each do |function|
113
+ memoize function:, **opts.slice(:freeze)
84
114
  end
85
115
  function_ids.size == 1 ? function_ids.first : function_ids
86
116
  end
87
117
  end
88
118
  end
89
119
  end
90
-
91
- require 'tins/alias'
@@ -1,64 +1,115 @@
1
1
  module Tins
2
+ # Provides methods for describing method signatures and parameters.
3
+ #
4
+ # This module is designed to be included in method objects to provide
5
+ # introspection capabilities, particularly useful for generating
6
+ # documentation or debugging method signatures.
2
7
  module MethodDescription
8
+ # Represents individual parameters with specific types and names.
3
9
  class Parameters
10
+ # Base class for all parameter types.
4
11
  class Parameter < Struct.new(:type, :name)
12
+ # Compares two parameters by their type.
13
+ #
14
+ # @param other [Parameter] The other parameter to compare against
15
+ # @return [Boolean] Whether the types are equal
5
16
  def ==(other)
6
17
  type == other.type
7
18
  end
8
19
 
20
+ # Returns a string representation of the parameter for debugging.
21
+ #
22
+ # @return [String] A debug-friendly representation
9
23
  def inspect
10
24
  "#<#{self.class} #{to_s.inspect}>"
11
25
  end
12
26
  end
13
27
 
28
+ # Represents a splat parameter (*args).
14
29
  class RestParameter < Parameter
30
+ # Converts the parameter to its string form.
31
+ #
32
+ # @return [String] Formatted as "*name"
15
33
  def to_s
16
34
  "*#{name}"
17
35
  end
18
36
  end
19
37
 
38
+ # Represents a keyword rest parameter (**kwargs).
20
39
  class KeyrestParameter < Parameter
40
+ # Converts the parameter to its string form.
41
+ #
42
+ # @return [String] Formatted as "**name"
21
43
  def to_s
22
44
  "**#{name}"
23
45
  end
24
46
  end
25
47
 
48
+ # Represents a required parameter.
26
49
  class ReqParameter < Parameter
50
+ # Converts the parameter to its string form.
51
+ #
52
+ # @return [String] The parameter name
27
53
  def to_s
28
54
  name.to_s
29
55
  end
30
56
  end
31
57
 
58
+ # Represents an optional parameter (with default value).
32
59
  class OptParameter < Parameter
60
+ # Converts the parameter to its string form.
61
+ #
62
+ # @return [String] Formatted as "name=..."
33
63
  def to_s
34
- "#{name}=?"
64
+ "#{name}=…"
35
65
  end
36
66
  end
37
67
 
68
+ # Represents a keyword parameter.
38
69
  class KeyParameter < Parameter
70
+ # Converts the parameter to its string form.
71
+ #
72
+ # @return [String] Formatted as "name:..."
39
73
  def to_s
40
- "#{name}:?"
74
+ "#{name}:…"
41
75
  end
42
76
  end
43
77
 
78
+ # Represents a required keyword parameter (without default).
44
79
  class KeyreqParameter < Parameter
80
+ # Converts the parameter to its string form.
81
+ #
82
+ # @return [String] Formatted as "name:"
45
83
  def to_s
46
84
  "#{name}:"
47
85
  end
48
86
  end
49
87
 
88
+ # Represents a block parameter (&block).
50
89
  class BlockParameter < Parameter
90
+ # Converts the parameter to its string form.
91
+ #
92
+ # @return [String] Formatted as "&name"
51
93
  def to_s
52
94
  "&#{name}"
53
95
  end
54
96
  end
55
97
 
98
+ # Represents a generic parameter type not covered by other classes.
56
99
  class GenericParameter < Parameter
100
+ # Converts the parameter to its string form.
101
+ #
102
+ # @return [String] Formatted as "name:type"
57
103
  def to_s
58
104
  [ name, type ] * ?:
59
105
  end
60
106
  end
61
107
 
108
+ # Builds a parameter instance based on type and name.
109
+ #
110
+ # @param type [Symbol] The type of parameter (e.g., :req, :opt)
111
+ # @param name [String, Symbol] The parameter name
112
+ # @return [Parameter] An appropriate Parameter subclass or GenericParameter
62
113
  def self.build(type, name)
63
114
  parameter_classname = "#{type.to_s.capitalize}Parameter"
64
115
  parameter_class =
@@ -71,38 +122,70 @@ module Tins
71
122
  end
72
123
  end
73
124
 
125
+ # Represents the signature of a method including all its parameters.
74
126
  class Signature
127
+ # Initializes a new signature with given parameters.
128
+ #
129
+ # @param parameters [Array<Parameters::Parameter>] The list of parameters
75
130
  def initialize(*parameters)
76
131
  @parameters = parameters
77
132
  end
78
133
 
134
+ # Returns the parameters associated with this signature.
135
+ #
136
+ # @return [Array<Parameters::Parameter>] The method's parameters
79
137
  attr_reader :parameters
80
138
 
139
+ # Checks if two signatures are equal based on their parameters.
140
+ #
141
+ # @param other [Signature] The other signature to compare against
142
+ # @return [Boolean] Whether the signatures are equal
81
143
  def eql?(other)
82
144
  @parameters.eql? other.parameters
83
145
  end
84
146
 
147
+ # Checks if two signatures are equal (alias for eql?).
148
+ #
149
+ # @param other [Signature] The other signature to compare against
150
+ # @return [Boolean] Whether the signatures are equal
85
151
  def ==(other)
86
152
  @parameters == other.parameters
87
153
  end
88
154
 
155
+ # Pattern matching operator for comparing with a method's signature.
156
+ #
157
+ # @param method [Method] The method whose signature we're checking
158
+ # @return [Boolean] Whether this signature matches the method's signature
89
159
  def ===(method)
90
160
  self == method.signature
91
161
  end
92
162
 
163
+ # Converts the signature to a comma-separated string.
164
+ #
165
+ # @return [String] The parameters formatted as a string
93
166
  def to_s
94
167
  @parameters * ?,
95
168
  end
96
169
 
170
+ # Returns a detailed string representation for debugging.
171
+ #
172
+ # @return [String] A debug-friendly representation of the signature
97
173
  def inspect
98
174
  "#<#{self.class} (#{to_s})>"
99
175
  end
100
176
  end
101
177
 
178
+ # Retrieves the signature of the method this module is included in.
179
+ #
180
+ # @return [Signature] The method's signature
102
181
  def signature
103
182
  description style: :parameters
104
183
  end
105
184
 
185
+ # Generates a human-readable description of the method.
186
+ #
187
+ # @param style [:namespace, :name, :parameters] The output format style
188
+ # @return [String, Signature] The formatted description or signature object
106
189
  def description(style: :namespace)
107
190
  valid_styles = %i[ namespace name parameters ]
108
191
  valid_styles.include?(style) or
@@ -122,10 +205,10 @@ module Tins
122
205
  return signature
123
206
  end
124
207
  end
125
- result = ''
208
+ result = +''
126
209
  if style == :namespace
127
210
  if owner <= Module
128
- result << receiver.to_s << ?. # XXX Better to use owner here as well?
211
+ result << receiver.to_s << ?.
129
212
  else
130
213
  result << owner.name.to_s << ?#
131
214
  end
data/lib/tins/minimize.rb CHANGED
@@ -1,19 +1,43 @@
1
1
  module Tins
2
- # This module can be mixed into all classes, whose instances respond to the
3
- # [] and size-methods, like for example Array. The returned elements from []
4
- # should respond to the succ method.
2
+ # Tins::Minimize provides methods for compressing sequential data into ranges
3
+ # and expanding ranges back into individual elements.
4
+ #
5
+ # This module is designed for objects that respond to `[]` and `size` methods,
6
+ # such as Array, and whose elements respond to the `succ` method (like String
7
+ # and Numeric types). It's particularly useful for representing sequential data
8
+ # more compactly and efficiently.
9
+ #
10
+ # @example Basic minimization
11
+ # [ 'A', 'B', 'C', 'G', 'K', 'L', 'M' ].minimize
12
+ # # => [ 'A'..'C', 'G'..'G', 'K'..'M' ]
13
+ #
14
+ # @example Numeric minimization
15
+ # [ 1, 2, 3, 7, 9, 10, 11 ].minimize
16
+ # # => [ 1..3, 7..7, 9..11 ]
17
+ #
18
+ # @example Sorting before minimization
19
+ # [ 5, 1, 4, 2 ].sort.minimize
20
+ # # => [ 1..2, 4..5 ]
21
+ #
22
+ # @example Unminimization
23
+ # [ 'A'..'C', 'G'..'G', 'K'..'M' ].unminimize
24
+ # # => [ 'A', 'B', 'C', 'G', 'K', 'L', 'M' ]
5
25
  module Minimize
6
26
  # Returns a minimized version of this object, that is successive elements
7
27
  # are substituted with ranges a..b. In the situation ..., x, y,... and y !=
8
28
  # x.succ a range x..x is created, to make it easier to iterate over all the
9
- # ranges in one run. A small example:
10
- # [ 'A', 'B', 'C', 'G', 'K', 'L', 'M' ].minimize # => [ 'A'..'C', 'G'..'G', 'K'..'M' ]
29
+ # ranges in one run.
11
30
  #
12
- # If the order of the original elements doesn't matter, it's a good idea to
13
- # first sort them and then minimize:
14
- # [ 5, 1, 4, 2 ].sort.minimize # => [ 1..2, 4..5 ]
31
+ # @return [Array<Range>] An array of ranges representing the minimized data
32
+ # @example Sequential string elements
33
+ # [ 'A', 'B', 'C', 'G', 'K', 'L', 'M' ].minimize
34
+ # # => [ 'A'..'C', 'G'..'G', 'K'..'M' ]
35
+ #
36
+ # @example Numeric elements
37
+ # [ 1, 2, 3, 7, 9, 10, 11 ].minimize
38
+ # # => [ 1..3, 7..7, 9..11 ]
15
39
  def minimize
16
- result = []
40
+ result = []
17
41
  last_index = size - 1
18
42
  size.times do |i|
19
43
  result << [ self[0] ] if i == 0
@@ -27,6 +51,8 @@ module Tins
27
51
 
28
52
  # First minimizes this object, then calls the replace method with the
29
53
  # result.
54
+ #
55
+ # @return [Object] Returns self (modified in place)
30
56
  def minimize!
31
57
  replace minimize
32
58
  end
@@ -35,6 +61,8 @@ module Tins
35
61
  # [ 'A'..'C', 'G'..'G', 'K'..'M' ].unminimize # => [ 'A', 'B', 'C', 'G', 'K', 'L', 'M' ]
36
62
  # and
37
63
  # [ 1..2, 4..5 ].unminimize # => [ 1, 2, 4, 5 ]
64
+ #
65
+ # @return [Array] An array of individual elements expanded from ranges
38
66
  def unminimize
39
67
  result = []
40
68
  for range in self
@@ -46,10 +74,10 @@ module Tins
46
74
  end
47
75
 
48
76
  # Invert a minimized version of this object in place.
77
+ #
78
+ # @return [Object] Returns self (modified in place)
49
79
  def unminimize!
50
80
  replace unminimize
51
81
  end
52
82
  end
53
83
  end
54
-
55
- require 'tins/alias'
@@ -1,5 +1,32 @@
1
1
  module Tins
2
+ # A module that allows grouping multiple modules together for type checking.
3
+ #
4
+ # This implementation creates a shared module that gets included in each of the
5
+ # specified modules, enabling the use of `===` for type checking across all
6
+ # grouped modules simultaneously.
2
7
  module ModuleGroup
8
+ # Creates a new module group from the given modules.
9
+ #
10
+ # This method dynamically creates an anonymous module and includes it in
11
+ # each of the provided modules. The returned module can then be used with
12
+ # the `===` operator for type checking across all grouped modules.
13
+ #
14
+ # @note This modifies the included modules by adding the new module to their
15
+ # inheritance chain, which can have side effects in complex class hierarchies.
16
+ #
17
+ # @param modules [Array<Module>] One or more modules to include in this group
18
+ # @return [Module] A new anonymous module that is included in all passed modules
19
+ #
20
+ # @example Creating a module group
21
+ # MyGroup = Tins::ModuleGroup[Array, String, Hash]
22
+ # MyGroup === [] # => true
23
+ # MyGroup === "" # => true
24
+ # MyGroup === {} # => true
25
+ #
26
+ # case some_value
27
+ # when MyGroup
28
+ # handle_collection_or_string(some_value)
29
+ # end
3
30
  def self.[](*modules)
4
31
  modul = Module.new
5
32
  modules.each do |m|
@@ -9,5 +36,3 @@ module Tins
9
36
  end
10
37
  end
11
38
  end
12
-
13
- require 'tins/alias'
@@ -1,12 +1,32 @@
1
1
  require 'set'
2
2
 
3
3
  module Tins
4
+ # NamedSet extends Ruby's Set class to include a descriptive name.
5
+ #
6
+ # This class provides all the functionality of Ruby's standard Set while
7
+ # adding a named identifier that can be useful for debugging, logging, and
8
+ # identification purposes. The name is stored as an instance variable and can
9
+ # be accessed or modified
10
+ # through the `name` accessor.
11
+ #
12
+ # @example Basic usage
13
+ # set = Tins::NamedSet.new("user_roles")
14
+ # set.add(:admin)
15
+ # set.add(:user)
16
+ # puts set.name # => "user_roles"
17
+ # puts set.to_a # => [:admin, :user]
4
18
  class NamedSet < Set
19
+ # Initializes a new NamedSet with the given name.
20
+ #
21
+ # @param name [String] A descriptive name for this set
5
22
  def initialize(name)
6
23
  @name = name
7
24
  super()
8
25
  end
9
26
 
27
+ # Gets or sets the name of this NamedSet.
28
+ #
29
+ # @return [String] The current name of the set
10
30
  attr_accessor :name
11
31
  end
12
32
  end