tins 1.38.0 → 1.51.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 (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +159 -0
  3. data/README.md +158 -6
  4. data/Rakefile +28 -18
  5. data/examples/let.rb +8 -40
  6. data/examples/mail.rb +0 -1
  7. data/examples/turing.rb +3 -1
  8. data/lib/tins/alias.rb +1 -0
  9. data/lib/tins/annotate.rb +37 -27
  10. data/lib/tins/ask_and_send.rb +41 -0
  11. data/lib/tins/attempt.rb +39 -0
  12. data/lib/tins/bijection.rb +34 -0
  13. data/lib/tins/case_predicate.rb +21 -0
  14. data/lib/tins/complete.rb +16 -0
  15. data/lib/tins/concern.rb +64 -0
  16. data/lib/tins/date_dummy.rb +36 -4
  17. data/lib/tins/date_time_dummy.rb +34 -2
  18. data/lib/tins/deep_dup.rb +9 -2
  19. data/lib/tins/deprecate.rb +12 -0
  20. data/lib/tins/dslkit.rb +563 -59
  21. data/lib/tins/duration.rb +120 -5
  22. data/lib/tins/expose.rb +54 -5
  23. data/lib/tins/extract_last_argument_options.rb +9 -0
  24. data/lib/tins/file_binary.rb +104 -21
  25. data/lib/tins/find.rb +114 -11
  26. data/lib/tins/generator.rb +10 -2
  27. data/lib/tins/go.rb +78 -14
  28. data/lib/tins/hash_bfs.rb +4 -2
  29. data/lib/tins/hash_symbolize_keys_recursive.rb +62 -4
  30. data/lib/tins/hash_union.rb +47 -2
  31. data/lib/tins/if_predicate.rb +31 -0
  32. data/lib/tins/implement.rb +50 -0
  33. data/lib/tins/limited.rb +63 -12
  34. data/lib/tins/lines_file.rb +81 -2
  35. data/lib/tins/lru_cache.rb +54 -17
  36. data/lib/tins/memoize.rb +86 -58
  37. data/lib/tins/method_description.rb +87 -4
  38. data/lib/tins/minimize.rb +39 -11
  39. data/lib/tins/module_group.rb +27 -2
  40. data/lib/tins/named_set.rb +20 -0
  41. data/lib/tins/null.rb +86 -15
  42. data/lib/tins/once.rb +61 -4
  43. data/lib/tins/p.rb +44 -8
  44. data/lib/tins/partial_application.rb +66 -7
  45. data/lib/tins/proc_compose.rb +58 -1
  46. data/lib/tins/proc_prelude.rb +97 -10
  47. data/lib/tins/range_plus.rb +30 -2
  48. data/lib/tins/require_maybe.rb +36 -0
  49. data/lib/tins/responding.rb +39 -0
  50. data/lib/tins/secure_write.rb +24 -4
  51. data/lib/tins/sexy_singleton.rb +45 -48
  52. data/lib/tins/string_byte_order_mark.rb +33 -2
  53. data/lib/tins/string_camelize.rb +31 -2
  54. data/lib/tins/string_named_placeholders.rb +70 -0
  55. data/lib/tins/string_underscore.rb +33 -2
  56. data/lib/tins/string_version.rb +190 -12
  57. data/lib/tins/subhash.rb +35 -10
  58. data/lib/tins/temp_io.rb +7 -0
  59. data/lib/tins/temp_io_enum.rb +19 -0
  60. data/lib/tins/terminal.rb +31 -9
  61. data/lib/tins/thread_local.rb +67 -5
  62. data/lib/tins/time_dummy.rb +46 -21
  63. data/lib/tins/to.rb +15 -0
  64. data/lib/tins/to_proc.rb +17 -4
  65. data/lib/tins/token.rb +74 -2
  66. data/lib/tins/unit.rb +304 -149
  67. data/lib/tins/version.rb +1 -1
  68. data/lib/tins/write.rb +14 -3
  69. data/lib/tins/xt/blank.rb +81 -2
  70. data/lib/tins/xt/concern.rb +51 -0
  71. data/lib/tins/xt/deep_dup.rb +4 -2
  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/secure_write.rb +0 -4
  79. data/lib/tins/xt/string.rb +1 -0
  80. data/lib/tins/xt/string_camelize.rb +4 -2
  81. data/lib/tins/xt/string_named_placeholders.rb +7 -0
  82. data/lib/tins/xt/string_underscore.rb +4 -2
  83. data/lib/tins/xt/subhash.rb +11 -0
  84. data/lib/tins/xt/time_freezer.rb +43 -6
  85. data/lib/tins/xt/write.rb +0 -4
  86. data/lib/tins/xt.rb +1 -3
  87. data/lib/tins.rb +17 -3
  88. data/tests/dslkit_test.rb +15 -0
  89. data/tests/duration_test.rb +4 -0
  90. data/tests/from_module_test.rb +30 -2
  91. data/tests/go_test.rb +4 -2
  92. data/tests/implement_test.rb +6 -8
  93. data/tests/limited_test.rb +1 -1
  94. data/tests/lines_file_test.rb +2 -0
  95. data/tests/lru_cache_test.rb +12 -0
  96. data/tests/method_description_test.rb +14 -20
  97. data/tests/partial_application_test.rb +4 -0
  98. data/tests/proc_prelude_test.rb +1 -1
  99. data/tests/scope_test.rb +1 -1
  100. data/tests/string_named_placeholders.rb +109 -0
  101. data/tests/string_version_test.rb +15 -0
  102. data/tests/test_helper.rb +4 -5
  103. data/tests/to_test.rb +6 -6
  104. data/tests/token_test.rb +32 -1
  105. data/tests/unit_test.rb +18 -0
  106. data/tins.gemspec +13 -11
  107. metadata +49 -33
  108. data/lib/tins/count_by.rb +0 -21
  109. data/lib/tins/deep_const_get.rb +0 -64
  110. data/lib/tins/timed_cache.rb +0 -51
  111. data/lib/tins/uniq_by.rb +0 -23
  112. data/lib/tins/xt/count_by.rb +0 -7
  113. data/lib/tins/xt/deep_const_get.rb +0 -7
  114. data/lib/tins/xt/uniq_by.rb +0 -25
  115. data/tests/count_by_test.rb +0 -17
  116. data/tests/deep_const_get_test.rb +0 -37
  117. data/tests/uniq_by_test.rb +0 -31
  118. /data/{COPYING → LICENSE} +0 -0
data/lib/tins/attempt.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  module Tins
2
+ # A module that provides functionality for attempting operations with error
3
+ # handling and retry logic.
2
4
  module Attempt
3
5
  # Attempts code in block *attempts* times, sleeping according to *sleep*
4
6
  # between attempts and catching the exception(s) in *exception_class*.
@@ -63,6 +65,11 @@ module Tins
63
65
 
64
66
  private
65
67
 
68
+ # The sleep_duration method handles sleeping for a specified duration or
69
+ # based on a proc call.
70
+ #
71
+ # @param duration [ Numeric, Proc ] the duration to sleep or a proc that
72
+ # returns the duration
66
73
  def sleep_duration(duration, count)
67
74
  case duration
68
75
  when Numeric
@@ -72,6 +79,26 @@ module Tins
72
79
  end
73
80
  end
74
81
 
82
+ # Computes the base for exponential backoff that results in a specific
83
+ # total sleep duration.
84
+ #
85
+ # This method solves for the base `x` in the geometric series:
86
+ # x^0 + x^1 + x^2 + ... + x^(attempts-1) = sleep
87
+ #
88
+ # The solution ensures that when using exponential delays with base `x`,
89
+ # the total time spent across all attempts equals approximately the
90
+ # specified sleep duration. This method of computation is used if a
91
+ # negative number of secondes was requested in the attempt method.
92
+ #
93
+ # @param sleep [Numeric] The total number of seconds to distribute across
94
+ # all attempts
95
+ # @param attempts [Integer] The number of attempts (must be > 2)
96
+ #
97
+ # @return [Float] The base for exponential backoff delays
98
+ # @raise [ArgumentError] If attempts <= 2, or if the sleep parameters are
99
+ # invalid
100
+ # @raise [ArgumentError] If the algorithm fails to converge after maximum
101
+ # iterations
75
102
  def compute_duration_base(sleep, attempts)
76
103
  x1, x2 = 1, sleep
77
104
  attempts <= sleep or raise ArgumentError,
@@ -98,6 +125,18 @@ module Tins
98
125
  result
99
126
  end
100
127
 
128
+ # The interpret_sleep method determines the sleep behavior for retry attempts.
129
+ #
130
+ # @param sleep [Numeric, Proc, nil] the sleep duration or proc to use
131
+ # between retries, nil if no sleep was requested
132
+ # @param attempts [Integer] the number of retry attempts
133
+ #
134
+ # @return [Proc, nil] a proc that calculates the sleep duration or nil if
135
+ # no sleep is needed
136
+ #
137
+ # @raise [ArgumentError] if a negative sleep value is provided with less
138
+ # than 3 attempts
139
+ # @raise [TypeError] if the sleep argument is not Numeric, Proc, or nil
101
140
  def interpret_sleep(sleep, attempts)
102
141
  case sleep
103
142
  when nil
@@ -1,5 +1,12 @@
1
1
  module Tins
2
+ # A hash subclass that ensures bijection between keys and values
2
3
  class Bijection < Hash
4
+ # Creates a new Bijection instance with key-value pairs.
5
+ #
6
+ # @param pairs [Array] an array of key-value pairs to populate the
7
+ # bijection
8
+ #
9
+ # @return [Bijection] a new bijection populated with the provided pairs
3
10
  def self.[](*pairs)
4
11
  pairs.size % 2 == 0 or
5
12
  raise ArgumentError, "odd number of arguments for #{self}"
@@ -15,10 +22,20 @@ module Tins
15
22
  end
16
23
  end
17
24
 
25
+ # The initialize method sets up a new instance with an inverted bijection.
26
+ #
27
+ # @param inverted [ Bijection ] the inverted bijection object, defaults to
28
+ # a new Bijection instance
18
29
  def initialize(inverted = Bijection.new(self))
19
30
  @inverted = inverted
20
31
  end
21
32
 
33
+ # The fill method populates the object with content from a block if it is
34
+ # empty.
35
+ #
36
+ # @return [ self ] returns the object itself after filling or if it was not
37
+ # empty
38
+ # @yield [ self ] yields self to the block for population
22
39
  def fill
23
40
  if empty?
24
41
  yield self
@@ -27,6 +44,9 @@ module Tins
27
44
  self
28
45
  end
29
46
 
47
+ # The freeze method freezes the current object and its inverted attribute.
48
+ #
49
+ # @return [Object] the frozen object
30
50
  def freeze
31
51
  r = super
32
52
  unless @inverted.frozen?
@@ -35,12 +55,26 @@ module Tins
35
55
  r
36
56
  end
37
57
 
58
+ # The []= method assigns a value to a key in the hash and maintains an
59
+ # inverted index.
60
+ #
61
+ # @param key [ Object ] the key to assign
62
+ # @param value [ Object ] the value to assign
63
+ #
64
+ # @return [ Object ] the assigned value
65
+ #
66
+ # @note This method will not overwrite existing keys, it will return early
67
+ # if the key already exists.
38
68
  def []=(key, value)
39
69
  key?(key) and return
40
70
  super
41
71
  @inverted[value] = key
42
72
  end
43
73
 
74
+ # The inverted attribute returns the inverted state of the object.
75
+ # Creates a new Bijection instance filled with key-value pairs.
76
+ #
77
+ # @return [Bijection] a new bijection instance with the specified key-value pairs
44
78
  attr_reader :inverted
45
79
  end
46
80
  end
@@ -1,5 +1,26 @@
1
1
  module Tins
2
+ # A module that provides a predicate method for checking if a value matches
3
+ # any of the given cases.
2
4
  module CasePredicate
5
+ # Checks if the object matches any of the given arguments using the ===
6
+ # operator.
7
+ #
8
+ # This method provides pattern matching functionality similar to Ruby's
9
+ # case/when statements, using the === operator for semantic equality
10
+ # checking.
11
+ #
12
+ # @example Basic type matching
13
+ # "hello".case?(String, Integer) # => String (matches first argument)
14
+ # 42.case?(String, Integer) # => Integer (matches first argument)
15
+ # nil.case?(String, Integer) # => nil (no matches)
16
+ #
17
+ # @example Range and pattern matching
18
+ # 15.case?(1..10, 11..20, 21..30) # => 11..20 (matches range)
19
+ # "hello world".case?(/foo/, /hello/) # => /hello/ (matches regex)
20
+ #
21
+ # @param args [Array] the arguments to check against using === operator
22
+ # @return [Object, nil] the first matching argument, or nil if no match is
23
+ # found
3
24
  def case?(*args)
4
25
  args.find { |a| a === self }
5
26
  end
data/lib/tins/complete.rb CHANGED
@@ -1,11 +1,27 @@
1
1
  require 'readline'
2
2
 
3
3
  module Tins
4
+ # A module that provides completion functionality for objects.
4
5
  module Complete
5
6
  module_function
6
7
 
7
8
  @@sync = Sync.new
8
9
 
10
+ # The complete method reads a line of input from the user with optional
11
+ # prompt and history support.
12
+ #
13
+ # @param prompt [ String ] the prompt string to display to the user
14
+ # @param add_hist [ Boolean ] whether to add the input to the command
15
+ # history
16
+ #
17
+ # @yield [ String ] the completion procedure to use for tab completion
18
+ #
19
+ # @return [ String ] the line of input entered by the user
20
+ #
21
+ # @example Prompt with easy tab completion
22
+ # complete(prompt: 'Pick a ruby file! ') {
23
+ # Dir['**/*.rb'].grep(/#{it}/)
24
+ # }.then { '%u lines' % File.new(it).each_line.count }
9
25
  def complete(prompt: '', add_hist: false, &block)
10
26
  @@sync.synchronize do
11
27
  Readline.completion_proc = block
data/lib/tins/concern.rb CHANGED
@@ -1,9 +1,49 @@
1
1
  module Tins
2
+ # A module concern implementation that supports dependency tracking, class
3
+ # method inclusion, and block execution hooks.
4
+ #
5
+ # This module provides a way to define reusable module functionality with
6
+ # automatic dependency management, class method injection, and lifecycle
7
+ # callbacks similar to ActiveSupport::Concern but with more control.
8
+ #
9
+ # @example Basic usage
10
+ # module MyConcern
11
+ # extend Tins::Concern
12
+ #
13
+ # included do
14
+ # attr_accessor :logger
15
+ # end
16
+ #
17
+ # def log(message)
18
+ # logger&.info message
19
+ # end
20
+ #
21
+ # class_methods do
22
+ # def my_class_method
23
+ # # ...
24
+ # end
25
+ # end
26
+ # end
27
+ #
28
+ # class MyClass
29
+ # include MyConcern
30
+ # end
2
31
  module Concern
32
+ # Extends the base object with dependency tracking capabilities.
33
+ #
34
+ # This method initializes an instance variable on the base object to store
35
+ # dependency information.
36
+ #
37
+ # @param base [ Object ] the object being extended
3
38
  def self.extended(base)
4
39
  base.instance_variable_set("@_dependencies", [])
5
40
  end
6
41
 
42
+ # The append_features method includes dependencies and class methods in the
43
+ # base class.
44
+ #
45
+ # @param base [ Object ] the base class to include features in
46
+ # @return [ Boolean ] true if features were appended, false otherwise
7
47
  def append_features(base)
8
48
  if base.instance_variable_defined?("@_dependencies")
9
49
  base.instance_variable_get("@_dependencies") << self
@@ -19,6 +59,14 @@ module Tins
19
59
  end
20
60
  end
21
61
 
62
+ # Prepends the features of this module to the base class.
63
+ #
64
+ # This method handles the inclusion of dependencies and class methods when
65
+ # a module is included in a class. It manages dependency tracking and
66
+ # ensures proper extension of the base class with ClassMethods.
67
+ #
68
+ # @param base [Class] the class that includes this module
69
+ # @return [Boolean] true if the module was successfully prepended, false otherwise
22
70
  def prepend_features(base)
23
71
  if base.instance_variable_defined?("@_dependencies")
24
72
  base.instance_variable_get("@_dependencies") << self
@@ -34,6 +82,11 @@ module Tins
34
82
  end
35
83
  end
36
84
 
85
+ # The included method is called when the module is included in a class or
86
+ # module.
87
+ #
88
+ # @param base [ Object ] the class or module that includes this module
89
+ # @param block [ Proc ] optional block to be executed when included
37
90
  def included(base = nil, &block)
38
91
  if base.nil?
39
92
  instance_variable_defined?(:@_included_block) and
@@ -44,6 +97,11 @@ module Tins
44
97
  end
45
98
  end
46
99
 
100
+ # The prepended method handles the setup of a block for prepend
101
+ # functionality or delegates to the superclass implementation
102
+ #
103
+ # @param base [ Object ] the base object to prepend to, or nil to set up a block
104
+ # @param block [ Proc ] the block to be used for prepend functionality
47
105
  def prepended(base = nil, &block)
48
106
  if base.nil?
49
107
  instance_variable_defined?(:@_prepended_block) and
@@ -54,6 +112,12 @@ module Tins
54
112
  end
55
113
  end
56
114
 
115
+ # Defines a ClassMethods module for the current class and evaluates the
116
+ # given block within it.
117
+ #
118
+ # @param block [Proc] The block to be evaluated in the context of the
119
+ # ClassMethods module
120
+ # @return [Module] The ClassMethods module that was defined or retrieved
57
121
  def class_methods(&block)
58
122
  modul = const_get(:ClassMethods) if const_defined?(:ClassMethods, false)
59
123
  unless modul
@@ -1,13 +1,34 @@
1
1
  require 'date'
2
2
 
3
3
  module Tins
4
+ # A module that provides dummy date functionality for testing purposes.
5
+ #
6
+ # @example Setting a dummy date
7
+ # Date.dummy = Date.parse('2009-09-09')
8
+ #
9
+ # @example Using a dummy date in a block
10
+ # Date.dummy Date.parse('2009-09-09') do
11
+ # # Your code here
12
+ # end
4
13
  module DateDummy
14
+ # The included method is a hook that gets called when this module is
15
+ # included in another class or module.
16
+ #
17
+ # It sets up date freezing functionality by extending the including
18
+ # class/module with special date handling methods. The method modifies the
19
+ # including class/module's singleton class to provide dummy date
20
+ # capabilities.
21
+ #
22
+ # @param modul [Object] the class or module that includes this module
5
23
  def self.included(modul)
6
24
  class << modul
7
25
  alias really_today today
8
26
 
9
27
  remove_method :today rescue nil
10
28
 
29
+ # Sets the dummy date value for date freezing functionality.
30
+ #
31
+ # @param value [Date, String] the date value to set as dummy
11
32
  def dummy=(value)
12
33
  if value.respond_to?(:to_str)
13
34
  value = Date.parse(value.to_str)
@@ -17,6 +38,16 @@ module Tins
17
38
  @dummy = value
18
39
  end
19
40
 
41
+ # The dummy method provides a way to set and temporarily override a
42
+ # dummy value within a block.
43
+ #
44
+ # @param value [Object] the dummy value to set, or nil to get the
45
+ # current dummy value
46
+ # @yield [] yields control to the block if a value is provided
47
+ # @return [Object] the current dummy value if no value parameter was
48
+ # provided
49
+ # @yieldparam value [Object] the dummy value to set within the block
50
+ # @yieldreturn [Object] the result of the block execution
20
51
  def dummy(value = nil)
21
52
  if value.nil?
22
53
  if defined?(@dummy)
@@ -33,6 +64,11 @@ module Tins
33
64
  end
34
65
  end
35
66
 
67
+ # The today method returns the current date. When a dummy date is set,
68
+ # it returns a duplicate of that date. Otherwise, it delegates to the
69
+ # actual today method implementation.
70
+ #
71
+ # @return [Date] the current date or the dummy date if set
36
72
  def today
37
73
  if dummy
38
74
  dummy.dup
@@ -42,12 +78,8 @@ module Tins
42
78
  really_today
43
79
  end
44
80
  end
45
-
46
81
  end
47
82
  super
48
83
  end
49
84
  end
50
85
  end
51
-
52
- require 'tins/alias'
53
-
@@ -1,13 +1,30 @@
1
1
  require 'date'
2
2
 
3
3
  module Tins
4
+ # A module that provides dummy functionality for DateTime class
5
+ #
6
+ # This module allows setting a fixed date and time that will be returned by
7
+ # DateTime.now instead of the actual current time. This is useful for testing
8
+ # purposes where consistent timestamps are required.
4
9
  module DateTimeDummy
10
+ # The included method is a hook that gets called when this module is
11
+ # included in another class or module.
12
+ #
13
+ # It sets up date time freezing functionality by extending the including
14
+ # class/module with special date time handling methods. The method modifies
15
+ # the including class/module's singleton class to provide dummy date time
16
+ # capabilities.
17
+ #
18
+ # @param modul [Object] the class or module that includes this module
5
19
  def self.included(modul)
6
20
  class << modul
7
21
  alias really_now now
8
22
 
9
23
  remove_method :now rescue nil
10
24
 
25
+ # Sets the dummy value for datetime handling.
26
+ #
27
+ # @param value [DateTime, String] the datetime value to set as dummy
11
28
  def dummy=(value)
12
29
  if value.respond_to?(:to_str)
13
30
  value = DateTime.parse(value.to_str)
@@ -17,6 +34,18 @@ module Tins
17
34
  @dummy = value
18
35
  end
19
36
 
37
+ # The dummy method provides a way to set and restore a dummy value
38
+ # within a block.
39
+ #
40
+ # @param value [Object] the dummy value to set, or nil to get the
41
+ # current dummy value
42
+ #
43
+ # @yield [void] yields control to the block if a value is provided
44
+ #
45
+ # @return [Object] the current dummy value if no value parameter is
46
+ # provided
47
+ # @return [Object] the result of the block if a value parameter is
48
+ # provided
20
49
  def dummy(value = nil)
21
50
  if value.nil?
22
51
  if defined?(@dummy)
@@ -33,6 +62,11 @@ module Tins
33
62
  end
34
63
  end
35
64
 
65
+ # The now method returns the current time, using a dummy time if one
66
+ # has been set. If no dummy time is set, it delegates to the actual
67
+ # time retrieval method.
68
+ #
69
+ # @return [Time] the current time or a mocked time if dummy is set
36
70
  def now
37
71
  if dummy
38
72
  dummy.dup
@@ -47,5 +81,3 @@ module Tins
47
81
  end
48
82
  end
49
83
  end
50
-
51
- require 'tins/alias'
data/lib/tins/deep_dup.rb CHANGED
@@ -1,5 +1,14 @@
1
1
  module Tins
2
+ # DeepDup module provides a method to deeply duplicate objects in Ruby.
3
+ #
4
+ # This module extends the Object class with a deep_dup method that creates a
5
+ # recursive copy of an object and all its nested objects.
2
6
  module DeepDup
7
+ # Duplicates an object deeply by marshaling and unmarshaling it. For
8
+ # objects that can't be marshaled, it returns the object itself.
9
+ #
10
+ # @return [Object] a deep duplicate of the object or the object itself if
11
+ # it can't be marshaled
3
12
  def deep_dup
4
13
  Marshal.load(Marshal.dump(self))
5
14
  rescue TypeError
@@ -7,5 +16,3 @@ module Tins
7
16
  end
8
17
  end
9
18
  end
10
-
11
- require 'tins/alias'
@@ -1,5 +1,17 @@
1
1
  module Tins
2
+ # A module for deprecating methods with customizable messages and warnings.
3
+ #
4
+ # @example
5
+ # class MyClass
6
+ # extend Tins::Deprecate
7
+ # deprecate method: :old_method, new_method: :new_method
8
+ # end
2
9
  module Deprecate
10
+ # Deprecates a method and issues a warning when called.
11
+ #
12
+ # @param method [ Symbol ] the name of the method to deprecate
13
+ # @param new_method [ Symbol ] the name of the replacement method
14
+ # @param message [ String ] the warning message to display
3
15
  def deprecate(method:, new_method: nil, message: nil)
4
16
  message ||= '[DEPRECATION] `%{method}` is deprecated. Please use `%{new_method}` instead.'
5
17
  message = message % { method: method, new_method: new_method }