philiprehberger-slug 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +24 -5
- data/lib/philiprehberger/slug/transliterator.rb +10 -7
- data/lib/philiprehberger/slug/version.rb +1 -1
- data/lib/philiprehberger/slug.rb +33 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c6417c2057ab93e96dd94c6427ea1176a9e90b0827a03e5b54d69cc88d2265b0
|
|
4
|
+
data.tar.gz: 34cd902c8265b577a5c991c5d49ef4e142b8cbf5a823d4645e055429202d715d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1a76c62679ff50297c41caec2943def332006ed1b04936807e4c437c4bc1b029ffdd0827380ad204721232b55144db4f999f7c828135c31373b596f65c07ad4d
|
|
7
|
+
data.tar.gz: 799fc05c9c45cf4e179bf9b116074fa378acb5523366b6539e64847d8f9d864a363fe3448d4fc9c58ec3e9e92f6736ccb1cd820478c30e097f3fbe06d19c370f
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.0] - 2026-04-13
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `Slug.valid_slug?(string, separator:)` method for validating well-formed slugs
|
|
14
|
+
- `Slug.humanize(slug, separator:, capitalize:)` method for converting slugs back to human-readable titles
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Optimize transliteration with pre-compiled regex instead of char-by-char iteration
|
|
18
|
+
- Remove unused `mapping_regex` private method from Transliterator
|
|
19
|
+
- Tighten RuboCop metrics to match guide defaults
|
|
20
|
+
|
|
10
21
|
## [0.2.0] - 2026-04-01
|
|
11
22
|
|
|
12
23
|
### Added
|
data/README.md
CHANGED
|
@@ -78,6 +78,26 @@ Philiprehberger::Slug.generate("Hello & World", custom_mapping: { "&" => "and" }
|
|
|
78
78
|
# => "hello-and-world"
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
+
### Validation
|
|
82
|
+
|
|
83
|
+
Check whether a string is already a well-formed slug:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
Philiprehberger::Slug.valid_slug?("hello-world") # => true
|
|
87
|
+
Philiprehberger::Slug.valid_slug?("Hello World") # => false
|
|
88
|
+
Philiprehberger::Slug.valid_slug?("hello--world") # => false
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Humanize
|
|
92
|
+
|
|
93
|
+
Convert a slug back to a human-readable title:
|
|
94
|
+
|
|
95
|
+
```ruby
|
|
96
|
+
Philiprehberger::Slug.humanize("hello-world") # => "Hello World"
|
|
97
|
+
Philiprehberger::Slug.humanize("hello-world", capitalize: :first) # => "Hello world"
|
|
98
|
+
Philiprehberger::Slug.humanize("hello_world", separator: "_") # => "Hello World"
|
|
99
|
+
```
|
|
100
|
+
|
|
81
101
|
### Transliteration
|
|
82
102
|
|
|
83
103
|
```ruby
|
|
@@ -88,12 +108,11 @@ Philiprehberger::Slug.transliterate("café résumé") # => "cafe resume"
|
|
|
88
108
|
|
|
89
109
|
| Method | Description |
|
|
90
110
|
|--------|-------------|
|
|
91
|
-
| `Slug.generate(string, separator
|
|
111
|
+
| `Slug.generate(string, separator:, max:, unique:, custom_mapping:)` | Generate a URL-safe slug from any string |
|
|
92
112
|
| `Slug.generate_batch(strings, separator:, max:, custom_mapping:)` | Generate unique slugs for an array of strings with deduplication |
|
|
93
|
-
| `Slug.
|
|
94
|
-
| `Slug
|
|
95
|
-
| `Slug
|
|
96
|
-
| `Slug::Transliterator::MAPPING` | Frozen hash of Unicode to ASCII character mappings |
|
|
113
|
+
| `Slug.valid_slug?(string, separator:)` | Check whether a string is a well-formed slug |
|
|
114
|
+
| `Slug.humanize(slug, separator:, capitalize:)` | Convert a slug back to a human-readable title |
|
|
115
|
+
| `Slug.transliterate(string, custom_mapping:)` | Transliterate Unicode characters to ASCII equivalents |
|
|
97
116
|
| `Slug::Error` | Error raised for invalid input (e.g. non-String argument) |
|
|
98
117
|
| `Slug::VERSION` | Current gem version string |
|
|
99
118
|
|
|
@@ -55,19 +55,22 @@ module Philiprehberger
|
|
|
55
55
|
'ϊ' => 'i', 'ϋ' => 'y', 'ΐ' => 'i', 'ΰ' => 'y'
|
|
56
56
|
}.freeze
|
|
57
57
|
|
|
58
|
+
MAPPING_REGEX = Regexp.union(MAPPING.keys).freeze
|
|
59
|
+
|
|
58
60
|
# Transliterate Unicode characters to ASCII equivalents
|
|
59
61
|
#
|
|
60
62
|
# @param string [String] input string
|
|
63
|
+
# @param custom_mapping [Hash, nil] custom character replacements
|
|
61
64
|
# @return [String] transliterated string
|
|
62
65
|
def self.call(string, custom_mapping: nil)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
if custom_mapping
|
|
67
|
+
merged = MAPPING.merge(custom_mapping)
|
|
68
|
+
regex = Regexp.union(merged.keys)
|
|
69
|
+
string.gsub(regex) { |match| merged[match] }
|
|
70
|
+
else
|
|
71
|
+
string.gsub(MAPPING_REGEX) { |match| MAPPING[match] }
|
|
72
|
+
end
|
|
69
73
|
end
|
|
70
|
-
private_class_method :mapping_regex
|
|
71
74
|
end
|
|
72
75
|
end
|
|
73
76
|
end
|
data/lib/philiprehberger/slug.rb
CHANGED
|
@@ -52,5 +52,38 @@ module Philiprehberger
|
|
|
52
52
|
def self.transliterate(string, custom_mapping: nil)
|
|
53
53
|
Transliterator.call(string, custom_mapping: custom_mapping)
|
|
54
54
|
end
|
|
55
|
+
|
|
56
|
+
# Check whether a string is a well-formed slug
|
|
57
|
+
#
|
|
58
|
+
# @param string [String] the string to validate
|
|
59
|
+
# @param separator [String] the allowed separator character (default: "-")
|
|
60
|
+
# @return [Boolean] true if the string is a valid slug
|
|
61
|
+
def self.valid_slug?(string, separator: '-')
|
|
62
|
+
return false unless string.is_a?(String)
|
|
63
|
+
return false if string.empty?
|
|
64
|
+
|
|
65
|
+
sep = Regexp.escape(separator)
|
|
66
|
+
string.match?(/\A[a-z0-9]+(?:#{sep}[a-z0-9]+)*\z/)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Convert a slug back to a human-readable title
|
|
70
|
+
#
|
|
71
|
+
# @param slug [String] the slug to humanize
|
|
72
|
+
# @param separator [String] the separator used in the slug (default: "-")
|
|
73
|
+
# @param capitalize [Symbol] capitalization strategy: :words, :first, or :none
|
|
74
|
+
# @return [String] the human-readable string
|
|
75
|
+
# @raise [Error] if input is not a String
|
|
76
|
+
def self.humanize(slug, separator: '-', capitalize: :words)
|
|
77
|
+
raise Error, "Input must be a String, got #{slug.class}" unless slug.is_a?(String)
|
|
78
|
+
return '' if slug.empty?
|
|
79
|
+
|
|
80
|
+
result = slug.gsub(separator, ' ')
|
|
81
|
+
case capitalize
|
|
82
|
+
when :words then result.gsub(/\b[a-z]/, &:upcase)
|
|
83
|
+
when :first then result.sub(/\A[a-z]/, &:upcase)
|
|
84
|
+
when :none then result
|
|
85
|
+
else raise Error, "Unknown capitalize option: #{capitalize}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
55
88
|
end
|
|
56
89
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: philiprehberger-slug
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Rehberger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Generate URL-safe slugs from any string with built-in Unicode transliteration,
|
|
14
14
|
configurable separators, word-boundary truncation, and collision-aware uniqueness.
|