hanami-view 2.1.0.rc1 → 2.1.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/hanami-view.gemspec +0 -1
  4. data/lib/hanami/view/cache.rb +8 -1
  5. data/lib/hanami/view/context.rb +5 -0
  6. data/lib/hanami/view/decorated_attributes.rb +8 -0
  7. data/lib/hanami/view/erb/engine.rb +1 -1
  8. data/lib/hanami/view/erb/filters/block.rb +1 -1
  9. data/lib/hanami/view/erb/filters/trimming.rb +1 -1
  10. data/lib/hanami/view/erb/parser.rb +1 -1
  11. data/lib/hanami/view/erb/template.rb +1 -1
  12. data/lib/hanami/view/errors.rb +12 -20
  13. data/lib/hanami/view/exposure.rb +32 -0
  14. data/lib/hanami/view/exposures.rb +19 -0
  15. data/lib/hanami/view/helpers/escape_helper.rb +15 -15
  16. data/lib/hanami/view/helpers/number_formatting_helper.rb +13 -13
  17. data/lib/hanami/view/helpers/tag_helper/tag_builder.rb +21 -21
  18. data/lib/hanami/view/helpers/tag_helper.rb +8 -8
  19. data/lib/hanami/view/html.rb +14 -9
  20. data/lib/hanami/view/html_safe_string_buffer.rb +1 -1
  21. data/lib/hanami/view/part.rb +29 -12
  22. data/lib/hanami/view/part_builder.rb +6 -4
  23. data/lib/hanami/view/path.rb +14 -0
  24. data/lib/hanami/view/rendered.rb +13 -7
  25. data/lib/hanami/view/renderer.rb +17 -0
  26. data/lib/hanami/view/rendering.rb +17 -0
  27. data/lib/hanami/view/rendering_missing.rb +15 -0
  28. data/lib/hanami/view/scope.rb +23 -16
  29. data/lib/hanami/view/scope_builder.rb +5 -3
  30. data/lib/hanami/view/tilt/haml_adapter.rb +2 -0
  31. data/lib/hanami/view/tilt/slim_adapter.rb +2 -0
  32. data/lib/hanami/view/tilt.rb +5 -0
  33. data/lib/hanami/view/version.rb +3 -2
  34. data/lib/hanami/view.rb +69 -30
  35. metadata +3 -18
  36. data/lib/hanami/view/application_view.rb +0 -89
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cae3eed9f786bf94040d22363976ef28f957fb05ca8d91d0cb2f68510c0da09d
4
- data.tar.gz: f9619a535228de48ebd401597faae311f7c66acaface839b10530623ca2147b9
3
+ metadata.gz: 1f2fe4be0c1444d008d0a1f263b665469931fc7446ef53a581e40b9903b3d59b
4
+ data.tar.gz: 530f9ef13f2c7f30e31c6f47276dfb5b63280167b237af607616138216d5d47a
5
5
  SHA512:
6
- metadata.gz: 57141a4749d8bdc68066fc1a182cc193a1a032f04288e9de0c197c0f426a3ffa57cef7af90fef25a5994a79711cd669d29ca20e1376c1036b0ed39c0f544689e
7
- data.tar.gz: f2b295fa290d9e898fd924d9a1ef39cb73e986a1efe3df4bbbfa2b24ef3cea7bff298ca811c9e5a5948adafd1a84bab7644530b33099d21ecba9ed9a8b12cfaa
6
+ metadata.gz: 632c35a2934a68d891a6adafa04bf77692242c118c97ef67f67729047915ea2322e6d3d95a31fb56f207367d66f4dae844278caf3d3d98184ee8339d3762eb73
7
+ data.tar.gz: 7657dac57505121f31eea7f7c3a6dfaac22e157094353bcd5ad9baa62d52e32a687b7d697512fe99aef4baa500e37ea7fb6f053b872b9d3f08c28a17b3e49b60
data/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  View layer for Hanami
4
4
 
5
+ ## v2.1.0.rc2 - 2023-11-08
6
+
7
+ ### Changed
8
+ - [Tim Riley] Remove `LayoutNotFoundError` and raise `TemplateNotFoundError` for all kinds of missing templates, including layouts.
9
+
5
10
  ## v2.1.0.rc1 - 2023-11-01
6
11
 
7
12
  ### Fixed
data/hanami-view.gemspec CHANGED
@@ -27,7 +27,6 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  spec.required_ruby_version = ">= 3.0"
29
29
 
30
- spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
31
30
  spec.add_runtime_dependency "dry-configurable", "~> 1.0"
32
31
  spec.add_runtime_dependency "dry-core", "~> 1.0"
33
32
  spec.add_runtime_dependency "dry-inflector", "~> 1.0", "< 2"
@@ -4,10 +4,17 @@ require "dry/core/cache"
4
4
 
5
5
  module Hanami
6
6
  class View
7
- # @api private
7
+ # Shared cache for views.
8
+ #
9
+ # @api public
10
+ # @since 2.1.0
8
11
  class Cache
9
12
  extend Dry::Core::Cache
10
13
 
14
+ # Clears the view cache.
15
+ #
16
+ # @api public
17
+ # @since 2.1.0
11
18
  def self.clear
12
19
  cache.clear
13
20
  end
@@ -9,13 +9,16 @@ module Hanami
9
9
  # `#initialize` if you wish to inject dependencies)
10
10
  #
11
11
  # @api public
12
+ # @since 2.1.0
12
13
  class Context
13
14
  include DecoratedAttributes
14
15
 
15
16
  # @api private
17
+ # @since 2.1.0
16
18
  attr_reader :_rendering
17
19
 
18
20
  # @api private
21
+ # @since 2.1.0
19
22
  def self.new(rendering: RenderingMissing.new, **args)
20
23
  allocate.tap do |obj|
21
24
  obj.instance_variable_set(:@_rendering, rendering)
@@ -26,10 +29,12 @@ module Hanami
26
29
  # Returns a new instance of Context
27
30
  #
28
31
  # @api public
32
+ # @since 2.1.0
29
33
  def initialize(**)
30
34
  end
31
35
 
32
36
  # @api private
37
+ # @since 2.1.0
33
38
  def dup_for_rendering(rendering)
34
39
  dup.tap do |obj|
35
40
  obj.instance_variable_set(:@_rendering, rendering)
@@ -5,13 +5,20 @@ require "set"
5
5
  module Hanami
6
6
  class View
7
7
  # Decorates attributes in Parts.
8
+ #
9
+ # @api public
10
+ # @since 2.1.0
8
11
  module DecoratedAttributes
9
12
  # @api private
13
+ # @since 2.1.0
10
14
  def self.included(klass)
11
15
  klass.extend ClassInterface
12
16
  end
13
17
 
14
18
  # Decorated attributes class-level interface.
19
+ #
20
+ # @api public
21
+ # @since 2.1.0
15
22
  module ClassInterface
16
23
  # @api private
17
24
  MODULE_NAME = :DecoratedAttributes
@@ -31,6 +38,7 @@ module Hanami
31
38
  # matching Part
32
39
  #
33
40
  # @api public
41
+ # @since 2.1.0
34
42
  def decorate(*names, **options)
35
43
  decorated_attributes.decorate(*names, **options)
36
44
  end
@@ -8,7 +8,7 @@ module Hanami
8
8
  # Hanami::View ERB engine.
9
9
  #
10
10
  # @api private
11
- # @since 2.0.0
11
+ # @since 2.1.0
12
12
  class Engine < Temple::Engine
13
13
  define_options capture_generator: Hanami::View::HTMLSafeStringBuffer
14
14
 
@@ -9,7 +9,7 @@ module Hanami
9
9
  #
10
10
  # Inspired by Slim's Slim::Controls::Filter#on_slim_output.
11
11
  #
12
- # @since 2.0.0
12
+ # @since 2.1.0
13
13
  # @api private
14
14
  class Block < Temple::Filter
15
15
  END_LINE_RE = /\bend\b/
@@ -18,7 +18,7 @@ module Hanami
18
18
  # `:multi` sexps with their own nested content.
19
19
  #
20
20
  # @api private
21
- # @since 2.0.0
21
+ # @since 2.1.0
22
22
  class Trimming < Temple::Filter
23
23
  define_options trim: true
24
24
 
@@ -78,7 +78,7 @@ module Hanami
78
78
  # remain, which is the value returned.
79
79
  #
80
80
  # @api private
81
- # @since 2.0.0
81
+ # @since 2.1.0
82
82
  class Parser < Temple::Parser
83
83
  ERB_PATTERN = /(\n|<%%|%%>)|<%(==?|\#)?(.*?)?-?%>/m
84
84
 
@@ -21,7 +21,7 @@ module Hanami
21
21
  # Hanami::View::ERB::Template.new { "<%= 'Hello, world!' %>" }.render
22
22
  #
23
23
  # @api private
24
- # @since 2.0.0
24
+ # @since 2.1.0
25
25
  module ERB
26
26
  # ERB Template class
27
27
  Template = Temple::Templates::Tilt(Engine)
@@ -2,24 +2,27 @@
2
2
 
3
3
  module Hanami
4
4
  class View
5
- # @since 2.0.0
5
+ # Base error for views.
6
+ #
7
+ # @since 2.1.0
6
8
  # @api public
7
9
  class Error < StandardError
8
10
  end
9
11
 
10
- # Error raised when critical settings are not configured
12
+ # Error raised when critical settings are not configured.
11
13
  #
12
- # @api private
14
+ # @api public
15
+ # @since 2.1.0
13
16
  class UndefinedConfigError < StandardError
14
17
  def initialize(key)
15
18
  super("no +#{key}+ configured")
16
19
  end
17
20
  end
18
21
 
19
- # Error raised when template could not be found within a view's configured
20
- # paths
22
+ # Error raised when template could not be found within a view's configured paths.
21
23
  #
22
- # @api private
24
+ # @api public
25
+ # @since 2.1.0
23
26
  class TemplateNotFoundError < StandardError
24
27
  def initialize(template_name, format, lookup_paths)
25
28
  msg = [
@@ -31,21 +34,10 @@ module Hanami
31
34
  end
32
35
  end
33
36
 
34
- # Error raised when layout could not be found within a view's configured
35
- # paths
37
+ # Error raised when a rendering is required but not given.
36
38
  #
37
- # @api private
38
- class LayoutNotFoundError < StandardError
39
- def initialize(layout_name, lookup_paths)
40
- msg = [
41
- "Layout +#{layout_name}+ could not be found in paths:",
42
- lookup_paths.map { |path| " - #{path}" }
43
- ].join("\n\n")
44
-
45
- super(msg)
46
- end
47
- end
48
-
39
+ # @api public
40
+ # @since 2.1.0
49
41
  class RenderingMissingError < Error
50
42
  def message
51
43
  "a +rendering+ must be provided"
@@ -7,17 +7,31 @@ module Hanami
7
7
  # An exposure defined on a view
8
8
  #
9
9
  # @api private
10
+ # @since 2.1.0
10
11
  class Exposure
11
12
  include Dry::Equalizer(:name, :proc, :object, :options)
12
13
 
13
14
  EXPOSURE_DEPENDENCY_PARAMETER_TYPES = %i[req opt].freeze
14
15
  INPUT_PARAMETER_TYPES = %i[key keyreq keyrest].freeze
15
16
 
17
+ # @api private
18
+ # @since 2.1.0
16
19
  attr_reader :name
20
+
21
+ # @api private
22
+ # @since 2.1.0
17
23
  attr_reader :proc
24
+
25
+ # @api private
26
+ # @since 2.1.0
18
27
  attr_reader :object
28
+
29
+ # @api private
30
+ # @since 2.1.0
19
31
  attr_reader :options
20
32
 
33
+ # @api private
34
+ # @since 2.1.0
21
35
  def initialize(name, proc = nil, object = nil, **options)
22
36
  @name = name
23
37
  @proc = prepare_proc(proc, object)
@@ -25,10 +39,14 @@ module Hanami
25
39
  @options = options
26
40
  end
27
41
 
42
+ # @api private
43
+ # @since 2.1.0
28
44
  def bind(obj)
29
45
  self.class.new(name, proc, obj, **options)
30
46
  end
31
47
 
48
+ # @api private
49
+ # @since 2.1.0
32
50
  def dependency_names
33
51
  @dependency_names ||=
34
52
  if proc
@@ -40,10 +58,14 @@ module Hanami
40
58
  end
41
59
  end
42
60
 
61
+ # @api private
62
+ # @since 2.1.0
43
63
  def dependencies?
44
64
  !dependency_names.empty?
45
65
  end
46
66
 
67
+ # @api private
68
+ # @since 2.1.0
47
69
  def input_keys
48
70
  @input_keys ||=
49
71
  if proc
@@ -55,22 +77,32 @@ module Hanami
55
77
  end
56
78
  end
57
79
 
80
+ # @api private
81
+ # @since 2.1.0
58
82
  def for_layout?
59
83
  options.fetch(:layout, false)
60
84
  end
61
85
 
86
+ # @api private
87
+ # @since 2.1.0
62
88
  def decorate?
63
89
  options.fetch(:decorate, true)
64
90
  end
65
91
 
92
+ # @api private
93
+ # @since 2.1.0
66
94
  def private?
67
95
  options.fetch(:private, false)
68
96
  end
69
97
 
98
+ # @api private
99
+ # @since 2.1.0
70
100
  def default_value
71
101
  options[:default]
72
102
  end
73
103
 
104
+ # @api private
105
+ # @since 2.1.0
74
106
  def call(input, locals = {})
75
107
  if proc
76
108
  call_proc(input, locals)
@@ -6,36 +6,53 @@ require "dry/core/equalizer"
6
6
  module Hanami
7
7
  class View
8
8
  # @api private
9
+ # @since 2.1.0
9
10
  class Exposures
10
11
  include Dry::Equalizer(:exposures)
11
12
  include TSort
12
13
 
14
+ # @api private
15
+ # @since 2.1.0
13
16
  attr_reader :exposures
14
17
 
18
+ # @api private
19
+ # @since 2.1.0
15
20
  def initialize(exposures = {})
16
21
  @exposures = exposures
17
22
  end
18
23
 
24
+ # @api private
25
+ # @since 2.1.0
19
26
  def key?(name)
20
27
  exposures.key?(name)
21
28
  end
22
29
 
30
+ # @api private
31
+ # @since 2.1.0
23
32
  def [](name)
24
33
  exposures[name]
25
34
  end
26
35
 
36
+ # @api private
37
+ # @since 2.1.0
27
38
  def each(&block)
28
39
  exposures.each(&block)
29
40
  end
30
41
 
42
+ # @api private
43
+ # @since 2.1.0
31
44
  def add(name, proc = nil, **options)
32
45
  exposures[name] = Exposure.new(name, proc, **options)
33
46
  end
34
47
 
48
+ # @api private
49
+ # @since 2.1.0
35
50
  def import(name, exposure)
36
51
  exposures[name] = exposure.dup
37
52
  end
38
53
 
54
+ # @api private
55
+ # @since 2.1.0
39
56
  def bind(obj)
40
57
  bound_exposures = exposures.each_with_object({}) { |(name, exposure), memo|
41
58
  memo[name] = exposure.bind(obj)
@@ -44,6 +61,8 @@ module Hanami
44
61
  self.class.new(bound_exposures)
45
62
  end
46
63
 
64
+ # @api private
65
+ # @since 2.1.0
47
66
  def call(input)
48
67
  # Avoid performance cost of tsorting when we don't need it
49
68
  names =
@@ -29,7 +29,7 @@ module Hanami
29
29
  # end
30
30
  #
31
31
  # @api public
32
- # @since 2.0.0
32
+ # @since 2.1.0
33
33
  module EscapeHelper
34
34
  extend self
35
35
 
@@ -56,13 +56,13 @@ module Hanami
56
56
  # # => "<p>Not escaped</p>"
57
57
  #
58
58
  # @api public
59
- # @since 2.0.0
59
+ # @since 2.1.0
60
60
  def escape_html(input)
61
61
  Temple::Utils.escape_html_safe(input)
62
62
  end
63
63
 
64
64
  # @api public
65
- # @since 2.0.0
65
+ # @since 2.1.0
66
66
  alias_method :h, :escape_html
67
67
 
68
68
  # Returns an escaped string from joining the elements in a given array.
@@ -86,7 +86,7 @@ module Hanami
86
86
  # @see #escape_html
87
87
  #
88
88
  # @api public
89
- # @since 2.0.0
89
+ # @since 2.1.0
90
90
  def escape_join(array, separator = $,)
91
91
  separator = escape_html(separator)
92
92
 
@@ -116,7 +116,7 @@ module Hanami
116
116
  # # => "gemini://gemini.circumlunar.space/"
117
117
  #
118
118
  # @api public
119
- # @since 2.0.0
119
+ # @since 2.1.0
120
120
  def sanitize_url(input, permitted_schemes = PERMITTED_URL_SCHEMES)
121
121
  return input if input.html_safe?
122
122
 
@@ -127,7 +127,7 @@ module Hanami
127
127
  end
128
128
 
129
129
  # @api private
130
- # @since 2.0.0
130
+ # @since 2.1.0
131
131
  PERMITTED_URL_SCHEMES = %w[http https mailto].freeze
132
132
  private_constant :PERMITTED_URL_SCHEMES
133
133
 
@@ -142,7 +142,7 @@ module Hanami
142
142
  # escape_xml_name("1 < 2 & 3") # => "1___2___3"
143
143
  #
144
144
  # @api public
145
- # @since 2.0.0
145
+ # @since 2.1.0
146
146
  def escape_xml_name(name)
147
147
  name = name.to_s
148
148
  return "" if name.match?(BLANK_STRING_REGEXP)
@@ -160,12 +160,12 @@ module Hanami
160
160
  end
161
161
 
162
162
  # @api private
163
- # @since 2.0.0
163
+ # @since 2.1.0
164
164
  BLANK_STRING_REGEXP = /\A\s*\z/
165
165
 
166
166
  # Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
167
167
  # @api private
168
- # @since 2.0.0
168
+ # @since 2.1.0
169
169
  TAG_NAME_START_CODEPOINTS = \
170
170
  "@:A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \
171
171
  "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
@@ -173,27 +173,27 @@ module Hanami
173
173
  private_constant :TAG_NAME_START_CODEPOINTS
174
174
 
175
175
  # @api private
176
- # @since 2.0.0
176
+ # @since 2.1.0
177
177
  INVALID_TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_CODEPOINTS}]/
178
178
  private_constant :INVALID_TAG_NAME_START_REGEXP
179
179
 
180
180
  # @api private
181
- # @since 2.0.0
181
+ # @since 2.1.0
182
182
  TAG_NAME_FOLLOWING_CODEPOINTS = "#{TAG_NAME_START_CODEPOINTS}\\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}"
183
183
  private_constant :TAG_NAME_FOLLOWING_CODEPOINTS
184
184
 
185
185
  # @api private
186
- # @since 2.0.0
186
+ # @since 2.1.0
187
187
  INVALID_TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_FOLLOWING_CODEPOINTS}]/
188
188
  private_constant :INVALID_TAG_NAME_FOLLOWING_REGEXP
189
189
 
190
190
  # @api private
191
- # @since 2.0.0
191
+ # @since 2.1.0
192
192
  SAFE_XML_TAG_NAME_REGEXP = /\A[#{TAG_NAME_START_CODEPOINTS}][#{TAG_NAME_FOLLOWING_CODEPOINTS}]*\z/
193
193
  private_constant :INVALID_TAG_NAME_FOLLOWING_REGEXP
194
194
 
195
195
  # @api private
196
- # @since 2.0.0
196
+ # @since 2.1.0
197
197
  TAG_NAME_REPLACEMENT_CHAR = "_"
198
198
  private_constant :TAG_NAME_REPLACEMENT_CHAR
199
199
 
@@ -211,7 +211,7 @@ module Hanami
211
211
  # raw(user.name).html_safe? # => true
212
212
  #
213
213
  # @api public
214
- # @since 2.0.0
214
+ # @since 2.1.0
215
215
  def raw(input)
216
216
  input.to_s.html_safe
217
217
  end
@@ -26,7 +26,7 @@ module Hanami
26
26
  # end
27
27
  #
28
28
  # @api public
29
- # @since 2.0.0
29
+ # @since 2.1.0
30
30
  module NumberFormattingHelper
31
31
  extend self
32
32
 
@@ -34,7 +34,7 @@ module Hanami
34
34
  #
35
35
  # @return [String] default delimiter
36
36
  #
37
- # @since 2.0.0
37
+ # @since 2.1.0
38
38
  # @api private
39
39
  DEFAULT_DELIMITER = ","
40
40
  private_constant :DEFAULT_DELIMITER
@@ -43,7 +43,7 @@ module Hanami
43
43
  #
44
44
  # @return [String] default separator
45
45
  #
46
- # @since 2.0.0
46
+ # @since 2.1.0
47
47
  # @api private
48
48
  DEFAULT_SEPARATOR = "."
49
49
  private_constant :DEFAULT_SEPARATOR
@@ -52,7 +52,7 @@ module Hanami
52
52
  #
53
53
  # @return [Integer] default rounding precision
54
54
  #
55
- # @since 2.0.0
55
+ # @since 2.1.0
56
56
  # @api private
57
57
  DEFAULT_PRECISION = 2
58
58
  private_constant :DEFAULT_PRECISION
@@ -82,7 +82,7 @@ module Hanami
82
82
  # format_number(1256.95, delimiter: ".", separator: ",") # => "1.256,95"
83
83
  #
84
84
  # @api public
85
- # @since 2.0.0
85
+ # @since 2.1.0
86
86
  def format_number(number, delimiter: DEFAULT_DELIMITER, separator: DEFAULT_SEPARATOR, precision: DEFAULT_PRECISION) # rubocop:disable Layout/LineLength
87
87
  Formatter.call(number, delimiter: delimiter, separator: separator, precision: precision)
88
88
  end
@@ -91,26 +91,26 @@ module Hanami
91
91
 
92
92
  # Formatter
93
93
  #
94
- # @since 2.0.0
94
+ # @since 2.1.0
95
95
  # @api private
96
96
  class Formatter
97
97
  # Regex to delimit the integer part of a number into groups of three digits.
98
98
  #
99
- # @since 2.0.0
99
+ # @since 2.1.0
100
100
  # @api private
101
101
  DELIMITING_REGEX = /(\d)(?=(\d{3})+$)/
102
102
  private_constant :DELIMITING_REGEX
103
103
 
104
104
  # Regex to guess if the number is a integer.
105
105
  #
106
- # @since 2.0.0
106
+ # @since 2.1.0
107
107
  # @api private
108
108
  INTEGER_REGEXP = /\A\d+\z/
109
109
  private_constant :INTEGER_REGEXP
110
110
 
111
111
  # @see NumberFormattingHelper#format_number
112
112
  #
113
- # @since 2.0.0
113
+ # @since 2.1.0
114
114
  # @api private
115
115
  def self.call(number, delimiter:, separator:, precision:)
116
116
  number = coerce(number)
@@ -122,7 +122,7 @@ module Hanami
122
122
 
123
123
  # Coerces the given number or string into a number.
124
124
  #
125
- # @since 2.0.0
125
+ # @since 2.1.0
126
126
  # @api private
127
127
  def self.coerce(number)
128
128
  case number
@@ -143,7 +143,7 @@ module Hanami
143
143
 
144
144
  # Formats the given number as a string.
145
145
  #
146
- # @since 2.0.0
146
+ # @since 2.1.0
147
147
  # @api private
148
148
  def self.to_str(number, precision)
149
149
  case number
@@ -156,7 +156,7 @@ module Hanami
156
156
 
157
157
  # Returns the integer and fractional parts of the given number string.
158
158
  #
159
- # @since 2.0.0
159
+ # @since 2.1.0
160
160
  # @api private
161
161
  def self.parts(string, delimiter)
162
162
  integer_part, fractional_part = string.split(DEFAULT_SEPARATOR)
@@ -170,7 +170,7 @@ module Hanami
170
170
  #
171
171
  # @return [String] delimited integer string
172
172
  #
173
- # @since 2.0.0
173
+ # @since 2.1.0
174
174
  # @api private
175
175
  def self.delimit_integer(integer_part, delimiter)
176
176
  integer_part.gsub(DELIMITING_REGEX) { |digit| "#{digit}#{delimiter}" }