tins 1.43.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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/.contexts/code_comment.rb +5 -8
  3. data/.contexts/lib.rb +0 -2
  4. data/CHANGES.md +12 -0
  5. data/README.md +158 -6
  6. data/Rakefile +19 -16
  7. data/examples/let.rb +8 -40
  8. data/examples/mail.rb +0 -1
  9. data/examples/turing.rb +3 -1
  10. data/lib/tins/alias.rb +1 -0
  11. data/lib/tins/annotate.rb +37 -27
  12. data/lib/tins/ask_and_send.rb +41 -0
  13. data/lib/tins/attempt.rb +39 -0
  14. data/lib/tins/bijection.rb +34 -0
  15. data/lib/tins/case_predicate.rb +21 -0
  16. data/lib/tins/complete.rb +16 -0
  17. data/lib/tins/concern.rb +64 -0
  18. data/lib/tins/date_dummy.rb +36 -4
  19. data/lib/tins/date_time_dummy.rb +34 -2
  20. data/lib/tins/deep_dup.rb +9 -2
  21. data/lib/tins/deprecate.rb +12 -0
  22. data/lib/tins/dslkit.rb +559 -83
  23. data/lib/tins/duration.rb +120 -5
  24. data/lib/tins/expose.rb +54 -5
  25. data/lib/tins/extract_last_argument_options.rb +9 -0
  26. data/lib/tins/file_binary.rb +104 -21
  27. data/lib/tins/find.rb +114 -11
  28. data/lib/tins/generator.rb +10 -2
  29. data/lib/tins/go.rb +81 -4
  30. data/lib/tins/hash_bfs.rb +4 -2
  31. data/lib/tins/hash_symbolize_keys_recursive.rb +62 -4
  32. data/lib/tins/hash_union.rb +47 -2
  33. data/lib/tins/if_predicate.rb +31 -0
  34. data/lib/tins/implement.rb +50 -0
  35. data/lib/tins/limited.rb +54 -5
  36. data/lib/tins/lines_file.rb +81 -2
  37. data/lib/tins/lru_cache.rb +54 -17
  38. data/lib/tins/memoize.rb +86 -58
  39. data/lib/tins/method_description.rb +87 -4
  40. data/lib/tins/minimize.rb +39 -11
  41. data/lib/tins/module_group.rb +27 -2
  42. data/lib/tins/named_set.rb +20 -0
  43. data/lib/tins/null.rb +86 -15
  44. data/lib/tins/once.rb +61 -4
  45. data/lib/tins/p.rb +44 -8
  46. data/lib/tins/partial_application.rb +66 -7
  47. data/lib/tins/proc_compose.rb +58 -1
  48. data/lib/tins/proc_prelude.rb +97 -10
  49. data/lib/tins/range_plus.rb +30 -2
  50. data/lib/tins/require_maybe.rb +36 -0
  51. data/lib/tins/responding.rb +39 -0
  52. data/lib/tins/secure_write.rb +24 -4
  53. data/lib/tins/sexy_singleton.rb +45 -48
  54. data/lib/tins/string_byte_order_mark.rb +33 -2
  55. data/lib/tins/string_camelize.rb +31 -2
  56. data/lib/tins/string_underscore.rb +33 -2
  57. data/lib/tins/string_version.rb +179 -10
  58. data/lib/tins/subhash.rb +35 -10
  59. data/lib/tins/temp_io.rb +7 -0
  60. data/lib/tins/temp_io_enum.rb +19 -0
  61. data/lib/tins/terminal.rb +31 -9
  62. data/lib/tins/thread_local.rb +67 -5
  63. data/lib/tins/time_dummy.rb +46 -21
  64. data/lib/tins/to.rb +15 -0
  65. data/lib/tins/to_proc.rb +17 -4
  66. data/lib/tins/token.rb +56 -1
  67. data/lib/tins/unit.rb +288 -149
  68. data/lib/tins/version.rb +1 -1
  69. data/lib/tins/write.rb +14 -3
  70. data/lib/tins/xt/blank.rb +81 -2
  71. data/lib/tins/xt/concern.rb +51 -0
  72. data/lib/tins/xt/full.rb +56 -11
  73. data/lib/tins/xt/irb.rb +46 -2
  74. data/lib/tins/xt/method_description.rb +0 -12
  75. data/lib/tins/xt/minimize.rb +7 -0
  76. data/lib/tins/xt/named.rb +71 -16
  77. data/lib/tins/xt/proc_compose.rb +4 -0
  78. data/lib/tins/xt/subhash.rb +11 -0
  79. data/lib/tins/xt/time_freezer.rb +43 -6
  80. data/lib/tins/xt.rb +1 -3
  81. data/lib/tins.rb +16 -3
  82. data/tests/duration_test.rb +4 -0
  83. data/tests/from_module_test.rb +30 -2
  84. data/tests/implement_test.rb +6 -8
  85. data/tests/lines_file_test.rb +2 -0
  86. data/tests/lru_cache_test.rb +12 -0
  87. data/tests/method_description_test.rb +14 -20
  88. data/tests/partial_application_test.rb +4 -0
  89. data/tests/proc_prelude_test.rb +1 -1
  90. data/tests/scope_test.rb +1 -1
  91. data/tests/string_version_test.rb +2 -0
  92. data/tests/to_test.rb +6 -6
  93. data/tins.gemspec +9 -9
  94. metadata +23 -41
  95. data/lib/tins/count_by.rb +0 -21
  96. data/lib/tins/deep_const_get.rb +0 -64
  97. data/lib/tins/timed_cache.rb +0 -51
  98. data/lib/tins/uniq_by.rb +0 -23
  99. data/lib/tins/xt/count_by.rb +0 -7
  100. data/lib/tins/xt/deep_const_get.rb +0 -7
  101. data/lib/tins/xt/uniq_by.rb +0 -25
  102. data/tests/count_by_test.rb +0 -17
  103. data/tests/deep_const_get_test.rb +0 -37
  104. data/tests/uniq_by_test.rb +0 -31
  105. /data/{COPYING → LICENSE} +0 -0
@@ -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
data/lib/tins/null.rb CHANGED
@@ -1,68 +1,131 @@
1
1
  module Tins
2
- # Implementation of the null object pattern in Ruby.
2
+ # Tins::Null provides an implementation of the null object pattern in Ruby.
3
+ #
4
+ # The null object pattern is a behavioral design pattern that allows you to
5
+ # avoid null references by providing a default object that implements the
6
+ # expected interface but does nothing. This eliminates the need for null
7
+ # checks throughout your codebase.
8
+ #
9
+ # This module provides the core functionality for null objects, including:
10
+ # - Method missing behavior that returns self
11
+ # - Type conversion methods that return appropriate default values
12
+ # - Debugging support through NullPlus
13
+ #
14
+ # @example Basic usage
15
+ # # Instead of checking for nil:
16
+ # user = find_user(id)
17
+ # if user
18
+ # user.name
19
+ # else
20
+ # "Unknown"
21
+ # end
22
+ #
23
+ # # You can use the null object:
24
+ # user = find_user(id) || Tins::NULL
25
+ # user.name # => "" (instead of nil)
26
+ #
27
+ # @example With NullPlus for debugging
28
+ # user = find_user(id) || Tins::NullPlus.new(value: "Unknown", caller: caller)
29
+ # user.value # => "Unknown"
3
30
  module Null
31
+ # Handle missing methods by returning self, allowing method chaining.
32
+ #
33
+ # @return [self] Always returns self to allow chaining
4
34
  def method_missing(*)
5
35
  self
6
36
  end
7
37
 
38
+ # Handle missing constants by returning self.
39
+ #
40
+ # @return [self] Always returns self
8
41
  def const_missing(*)
9
42
  self
10
43
  end
11
44
 
45
+ # Convert to string representation.
46
+ #
47
+ # @return [String] Empty string
12
48
  def to_s
13
49
  ''
14
50
  end
15
51
 
16
- def to_str
17
- nil
18
- end
19
-
52
+ # Convert to float.
53
+ #
54
+ # @return [Float] Zero as float
20
55
  def to_f
21
56
  0.0
22
57
  end
23
58
 
59
+ # Convert to integer.
60
+ #
61
+ # @return [Integer] Zero
24
62
  def to_i
25
63
  0
26
64
  end
27
65
 
28
- def to_int
29
- nil
30
- end
31
-
66
+ # Convert to array.
67
+ #
68
+ # @return [Array] Empty array
32
69
  def to_a
33
70
  []
34
71
  end
35
72
 
36
- def to_ary
37
- nil
38
- end
39
-
73
+ # Inspect representation.
74
+ #
75
+ # @return [String] "NULL"
40
76
  def inspect
41
77
  'NULL'
42
78
  end
43
79
 
80
+ # Check if object is nil.
81
+ #
82
+ # @return [Boolean] Always returns true
44
83
  def nil?
45
84
  true
46
85
  end
47
86
 
87
+ # Check if object is blank.
88
+ #
89
+ # @return [Boolean] Always returns true
48
90
  def blank?
49
91
  true
50
92
  end
51
93
 
94
+ # Convert to JSON (for compatibility with JSON serialization).
95
+ #
96
+ # @return [nil] returns nil value
52
97
  def as_json(*)
98
+ nil
53
99
  end
54
100
 
101
+ # Convert to JSON string.
102
+ #
103
+ # @return [String] "null"
55
104
  def to_json(*)
56
105
  'null'
57
106
  end
58
107
 
108
+ # Kernel extensions for null object creation.
59
109
  module Kernel
110
+ # Create a null object or return the provided value if not nil.
111
+ #
112
+ # @param value [Object] The value to check
113
+ # @return [Object] Tins::NULL if value is nil, otherwise value
60
114
  def null(value = nil)
61
115
  value.nil? ? Tins::NULL : value
62
116
  end
63
117
 
64
118
  alias Null null
65
119
 
120
+ # Create a null object with additional debugging information.
121
+ #
122
+ # This creates a NullPlus object that includes caller information for
123
+ # debugging purposes when the null object is used.
124
+ #
125
+ # @param opts [Hash] Options for the null object
126
+ # @option opts [Object] :value The value to return from the null object
127
+ # @option opts [Array] :caller Caller information
128
+ # @return [Object] Tins::NullPlus if value is nil, otherwise value
66
129
  def null_plus(opts = {})
67
130
  value = opts[:value]
68
131
  opts[:caller] = caller
@@ -77,17 +140,27 @@ module Tins
77
140
  end
78
141
  end
79
142
 
143
+ # NullClass represents the singleton null object instance.
80
144
  class NullClass < Module
81
145
  include Tins::Null
82
146
  end
83
147
 
148
+ # The singleton null object instance.
84
149
  NULL = NullClass.new
85
150
 
151
+ # Freeze the singleton to prevent modification.
86
152
  NULL.freeze
87
153
 
154
+ # Enhanced null object with debugging capabilities.
155
+ #
156
+ # NullPlus extends the basic null object with additional features for debugging,
157
+ # including caller information and custom attribute access.
88
158
  class NullPlus
89
159
  include Tins::Null
90
160
 
161
+ # Initialize a NullPlus object with options.
162
+ #
163
+ # @param opts [Hash] Configuration options
91
164
  def initialize(opts = {})
92
165
  singleton_class.class_eval do
93
166
  opts.each do |name, value|
@@ -97,5 +170,3 @@ module Tins
97
170
  end
98
171
  end
99
172
  end
100
-
101
- require 'tins/alias'
data/lib/tins/once.rb CHANGED
@@ -1,9 +1,52 @@
1
1
  module Tins
2
+ # A module for ensuring exclusive execution of code blocks using file-based
3
+ # locking.
4
+ #
5
+ # This module provides mechanisms to prevent multiple instances of a script
6
+ # from running simultaneously by using file system locks on the script itself
7
+ # or a specified lock file.
8
+ #
9
+ # @example Basic usage with automatic lock file detection
10
+ # Tins::Once.only_once do
11
+ # # Critical section - only one instance runs at a time
12
+ # perform_backup()
13
+ # end
14
+ #
15
+ # @example Using custom lock file
16
+ # Tins::Once.only_once("/var/run/myapp.lock") do
17
+ # # Custom lock file
18
+ # process_data()
19
+ # end
20
+ #
21
+ # @example Non-blocking attempt
22
+ # begin
23
+ # Tins::Once.try_only_once do
24
+ # # Will raise if another instance holds the lock
25
+ # update_cache()
26
+ # end
27
+ # rescue => e
28
+ # puts "Another instance is running"
29
+ # end
2
30
  module Once
3
31
  include File::Constants
4
32
 
5
- module_function
6
-
33
+ # Executes a block of code exclusively, ensuring only one instance runs at
34
+ # a time.
35
+ #
36
+ # Uses the script name (or specified lock file) as the locking mechanism.
37
+ # The first invocation will acquire an exclusive lock and execute the
38
+ # block, while subsequent invocations will block until the lock is
39
+ # released.
40
+ #
41
+ # @param lock_filename [String] Optional custom lock filename.
42
+ # Defaults to `$0` (the script name), which means the script itself
43
+ # is used as the lock file.
44
+ # @param locking_constant [Integer] File locking constant.
45
+ # Defaults to `LOCK_EX` for exclusive locking.
46
+ # @yield [void] The block of code to execute exclusively
47
+ # @return [Object] The return value of the yielded block
48
+ # @raise [Errno::ENOENT] If the lock file doesn't exist
49
+ # @raise [SystemCallError] If file locking fails
7
50
  def only_once(lock_filename = nil, locking_constant = nil)
8
51
  lock_filename ||= $0
9
52
  locking_constant ||= LOCK_EX
@@ -16,10 +59,24 @@ module Tins
16
59
  end
17
60
  end
18
61
 
62
+ # Attempts to execute a block of code exclusively, but fails immediately
63
+ # if another instance holds the lock.
64
+ #
65
+ # This is a non-blocking version that will raise an exception if the lock
66
+ # cannot be acquired immediately.
67
+ #
68
+ # @param lock_filename [String] Optional custom lock filename.
69
+ # Defaults to `$0` (the script name).
70
+ # @param locking_constant [Integer] File locking constant.
71
+ # Defaults to `LOCK_EX | LOCK_NB` for non-blocking exclusive locking.
72
+ # @yield [void] The block of code to execute exclusively
73
+ # @return [Object] The return value of the yielded block
74
+ # @raise [Errno::EAGAIN] If another process holds the lock
75
+ # @raise [Errno::ENOENT] If the lock file doesn't exist
19
76
  def try_only_once(lock_filename = nil, locking_constant = nil, &block)
20
77
  only_once(lock_filename, locking_constant || LOCK_EX | LOCK_NB, &block)
21
78
  end
79
+
80
+ module_function :only_once, :try_only_once
22
81
  end
23
82
  end
24
-
25
- require 'tins/alias'
data/lib/tins/p.rb CHANGED
@@ -1,23 +1,59 @@
1
1
  require 'pp'
2
2
 
3
3
  module Tins
4
+ # A module that provides debugging methods for inspecting objects by raising
5
+ # exceptions with their inspected representations.
6
+ #
7
+ # This module adds p! and pp! methods that raise RuntimeError exceptions
8
+ # containing the inspected or pretty-inspected output of objects, making it
9
+ # easy to quickly debug values during development without printing to stdout.
10
+ #
11
+ # @example Using p! to inspect a single object
12
+ # p!(some_variable)
13
+ #
14
+ # @example Using pp! to inspect multiple objects
15
+ # pp!(first_var, second_var)
4
16
  module P
5
17
  private
6
18
 
7
- # Raise a runtime error with the inspected objects +objs+ (obtained by
8
- # calling the #inspect method) as their message text. This is useful for
9
- # quick debugging.
19
+ # Raises a RuntimeError with the inspected representation of the given
20
+ # objects.
21
+ #
22
+ # This method is useful for quick debugging by raising an exception that
23
+ # contains the inspected output of the provided objects. It behaves
24
+ # similarly to Ruby's built-in +p+ method but raises an exception instead
25
+ # of printing to stdout.
26
+ #
27
+ # @example Basic usage with single object
28
+ # p!(some_variable)
29
+ #
30
+ # @example Basic usage with multiple objects
31
+ # p!(first_var, second_var)
32
+ #
33
+ # @param objs [Array<Object>] One or more objects to inspect and raise
34
+ # @raise [RuntimeError] Always raises a RuntimeError with inspected content
10
35
  def p!(*objs)
11
36
  raise((objs.size < 2 ? objs.first : objs).inspect)
12
37
  end
13
38
 
14
- # Raise a runtime error with the inspected objects +objs+ (obtained by
15
- # calling the #pretty_inspect method) as their message text. This is useful
16
- # for quick debugging.
39
+ # Raises a RuntimeError with the pretty-inspected representation of the
40
+ # given objects.
41
+ #
42
+ # This method is useful for quick debugging by raising an exception that
43
+ # contains the pretty-printed output of the provided objects. It behaves
44
+ # similarly to Ruby's built-in +pp+ method but raises an exception instead
45
+ # of printing to stdout.
46
+ #
47
+ # @example Basic usage with single object
48
+ # pp!(some_variable)
49
+ #
50
+ # @example Basic usage with multiple objects
51
+ # pp!(first_var, second_var)
52
+ #
53
+ # @param objs [Array<Object>] One or more objects to pretty-inspect and raise
54
+ # @raise [RuntimeError] Always raises a RuntimeError with pretty-inspected content
17
55
  def pp!(*objs)
18
56
  raise("\n" + (objs.size < 2 ? objs.first : objs).pretty_inspect.chomp)
19
57
  end
20
58
  end
21
59
  end
22
-
23
- require 'tins/alias'