much-slug 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.l.yml +8 -0
- data/.rubocop.yml +3 -0
- data/.ruby-version +1 -0
- data/.t.yml +4 -0
- data/Gemfile +4 -2
- data/README.md +10 -20
- data/lib/much-slug.rb +11 -8
- data/lib/much-slug/activerecord.rb +48 -49
- data/lib/much-slug/has_slug_registry.rb +37 -24
- data/lib/much-slug/slug.rb +17 -15
- data/lib/much-slug/version.rb +3 -1
- data/log/{.gitkeep → .keep} +0 -0
- data/much-slug.gemspec +10 -7
- data/test/helper.rb +4 -11
- data/test/support/factory.rb +4 -3
- data/test/unit/activerecord_tests.rb +161 -126
- data/test/unit/has_slug_registry_tests.rb +43 -48
- data/test/unit/much-slug_tests.rb +7 -8
- data/test/unit/slug_tests.rb +62 -46
- metadata +33 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d01ea124052633b468872a2c8ab13273d39999bd8fa4a068fbb009c777b41451
|
4
|
+
data.tar.gz: c1f745df34088bfb001719692c5033deaef9346c857046e9f756da65859c7d23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 95199593bb0065a2d17f926a910cd3175657522f07f07aac8b776c69289693cb4568d3f619f46aa96493763efa1d50250dd9260de0d2f886aaafb780704df984
|
7
|
+
data.tar.gz: d6cdb5f3e2b35665f59b8daf266cd560e3eded1dc30584519b45b2d2769f7db6f38e7d6a31a96d4b58f1792bc3481ce7471c4e687055138297e9d7f730c43164
|
data/.l.yml
ADDED
data/.rubocop.yml
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.5.8
|
data/.t.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -11,7 +11,7 @@ MuchSlug creates derived slug values on database records. Typically this means d
|
|
11
11
|
Given a `:slug` field on a record:
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
class AddSlugToProjects < ActiveRecord::Migration[
|
14
|
+
class AddSlugToProjects < ActiveRecord::Migration[6.1]
|
15
15
|
def change
|
16
16
|
add_column(:projects, :slug, :string, index: { unique: true })
|
17
17
|
end
|
@@ -21,14 +21,12 @@ end
|
|
21
21
|
Mix-in `MuchSlug::ActiveRecord` and configure:
|
22
22
|
|
23
23
|
```ruby
|
24
|
-
require "much-slug/activerecord"
|
25
|
-
|
26
24
|
class ProjectRecord < ApplicationRecord
|
27
25
|
self.table_name = "projects"
|
28
26
|
|
29
27
|
include MuchSlug::ActiveRecord
|
30
28
|
has_slug(
|
31
|
-
source: -> { "#{
|
29
|
+
source: -> { "#{id}-#{name}" },
|
32
30
|
)
|
33
31
|
|
34
32
|
# ...
|
@@ -66,18 +64,16 @@ project.slug # => "124-Do-The-Things"
|
|
66
64
|
By default, the record attribute for a slug is `"slug"`. You can override this when configuring slugs:
|
67
65
|
|
68
66
|
```ruby
|
69
|
-
require "much-slug/activerecord"
|
70
|
-
|
71
67
|
class ProjectRecord < ApplicationRecord
|
72
68
|
self.table_name = "projects"
|
73
69
|
|
74
70
|
include MuchSlug::ActiveRecord
|
75
71
|
has_slug(
|
76
|
-
source: -> { "#{
|
72
|
+
source: -> { "#{id}-#{name}" },
|
77
73
|
)
|
78
74
|
has_slug(
|
79
75
|
attribute: :full_slug
|
80
|
-
source: -> { "#{
|
76
|
+
source: -> { "#{id}-#{full_name}" },
|
81
77
|
)
|
82
78
|
|
83
79
|
# ...
|
@@ -89,19 +85,17 @@ end
|
|
89
85
|
By default, MuchSlug doesn't pre-process the slug value source before generating the slug value. You can specify a custom pre-processor by passing any Proc-like object:
|
90
86
|
|
91
87
|
```ruby
|
92
|
-
require "much-slug/activerecord"
|
93
|
-
|
94
88
|
class ProjectRecord < ApplicationRecord
|
95
89
|
self.table_name = "projects"
|
96
90
|
|
97
91
|
include MuchSlug::ActiveRecord
|
98
92
|
has_slug(
|
99
|
-
source: -> { "#{
|
93
|
+
source: -> { "#{id}-#{name}" },
|
100
94
|
preprocessor: :downcase
|
101
95
|
)
|
102
96
|
has_slug(
|
103
97
|
attribute: :full_slug
|
104
|
-
source: -> { "#{
|
98
|
+
source: -> { "#{id}-#{full_name}" },
|
105
99
|
preprocessor: -> { |source_value| source_value[0..30] }
|
106
100
|
)
|
107
101
|
|
@@ -114,14 +108,12 @@ end
|
|
114
108
|
MuchSlug replaces any non-word characters with a separator. This helps make slugs URL-friendly. By default, MuchSlug uses `"-"` for the separator. You can specify a custom separator value when configuring slugs:
|
115
109
|
|
116
110
|
```ruby
|
117
|
-
require "much-slug/activerecord"
|
118
|
-
|
119
111
|
class ProjectRecord < ApplicationRecord
|
120
112
|
self.table_name = "projects"
|
121
113
|
|
122
114
|
include MuchSlug::ActiveRecord
|
123
115
|
has_slug(
|
124
|
-
source: -> { "#{
|
116
|
+
source: -> { "#{id}.#{name}" },
|
125
117
|
separator: "."
|
126
118
|
)
|
127
119
|
|
@@ -140,18 +132,16 @@ project.slug # => "123.Sprockets.2.0"
|
|
140
132
|
By default, MuchSlug doesn't allow underscores in source values and treats them like non-word characters. This means it replaces underscores with the separator. You can override this to allow underscores when configuring slugs:
|
141
133
|
|
142
134
|
```ruby
|
143
|
-
require "much-slug/activerecord"
|
144
|
-
|
145
135
|
class ProjectRecord < ApplicationRecord
|
146
136
|
self.table_name = "projects"
|
147
137
|
|
148
138
|
include MuchSlug::ActiveRecord
|
149
139
|
has_slug(
|
150
|
-
source: -> { "#{
|
140
|
+
source: -> { "#{id}-#{name}" }
|
151
141
|
)
|
152
142
|
has_slug(
|
153
143
|
attribute: :full_slug
|
154
|
-
source: -> { "#{
|
144
|
+
source: -> { "#{id}-#{full_name}" },
|
155
145
|
allow_underscores: true
|
156
146
|
|
157
147
|
# ...
|
@@ -183,7 +173,7 @@ project.slug # => "123-Sprockets-2-0"
|
|
183
173
|
|
184
174
|
Add this line to your application's Gemfile:
|
185
175
|
|
186
|
-
gem
|
176
|
+
gem "much-slug"
|
187
177
|
|
188
178
|
And then execute:
|
189
179
|
|
data/lib/much-slug.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "much-slug/activerecord"
|
2
4
|
require "much-slug/has_slug_registry"
|
3
5
|
require "much-slug/slug"
|
6
|
+
require "much-slug/version"
|
4
7
|
|
5
8
|
module MuchSlug
|
6
9
|
def self.default_attribute
|
@@ -12,7 +15,7 @@ module MuchSlug
|
|
12
15
|
end
|
13
16
|
|
14
17
|
def self.default_separator
|
15
|
-
"-"
|
18
|
+
"-"
|
16
19
|
end
|
17
20
|
|
18
21
|
def self.default_allow_underscores
|
@@ -24,8 +27,8 @@ module MuchSlug
|
|
24
27
|
true
|
25
28
|
end
|
26
29
|
|
27
|
-
def self.has_slug_changed_slug_values(
|
28
|
-
|
30
|
+
def self.has_slug_changed_slug_values(record)
|
31
|
+
record.class.much_slug_has_slug_registry.each do |attribute, entry|
|
29
32
|
# ArgumentError: no receiver given` raised when calling `instance_exec`
|
30
33
|
# on non-lambda Procs, specifically e.g :downcase.to_proc.
|
31
34
|
# Can't call `instance_eval` on stabby lambdas b/c `instance_eval` auto
|
@@ -33,9 +36,9 @@ module MuchSlug
|
|
33
36
|
# lambdas may not expect that and will ArgumentError.
|
34
37
|
slug_source_value =
|
35
38
|
if entry.source_proc.lambda?
|
36
|
-
|
39
|
+
record.instance_exec(&entry.source_proc)
|
37
40
|
else
|
38
|
-
|
41
|
+
record.instance_eval(&entry.source_proc)
|
39
42
|
end
|
40
43
|
|
41
44
|
slug_value =
|
@@ -43,9 +46,9 @@ module MuchSlug
|
|
43
46
|
slug_source_value,
|
44
47
|
preprocessor: entry.preprocessor_proc,
|
45
48
|
separator: entry.separator,
|
46
|
-
allow_underscores: entry.allow_underscores
|
49
|
+
allow_underscores: entry.allow_underscores,
|
47
50
|
)
|
48
|
-
next if
|
51
|
+
next if record.public_send(attribute) == slug_value
|
49
52
|
yield attribute, slug_value
|
50
53
|
end
|
51
54
|
end
|
@@ -1,64 +1,63 @@
|
|
1
|
-
|
2
|
-
require "much-slug"
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
include MuchPlugin
|
3
|
+
require "much-mixin"
|
4
|
+
require "much-slug"
|
7
5
|
|
8
|
-
|
9
|
-
@much_slug_has_slug_registry = MuchSlug::HasSlugRegistry.new
|
10
|
-
end
|
6
|
+
module MuchSlug; end
|
11
7
|
|
12
|
-
|
13
|
-
|
14
|
-
source:,
|
15
|
-
attribute: nil,
|
16
|
-
preprocessor: nil,
|
17
|
-
separator: nil,
|
18
|
-
allow_underscores: nil,
|
19
|
-
skip_unique_validation: false,
|
20
|
-
unique_scope: nil)
|
21
|
-
registered_attribute =
|
22
|
-
self.much_slug_has_slug_registry.register(
|
23
|
-
attribute: attribute,
|
24
|
-
source: source,
|
25
|
-
preprocessor: preprocessor,
|
26
|
-
separator: separator,
|
27
|
-
allow_underscores: allow_underscores,
|
28
|
-
)
|
8
|
+
module MuchSlug::ActiveRecord
|
9
|
+
include MuchMixin
|
29
10
|
|
30
|
-
|
31
|
-
|
32
|
-
|
11
|
+
mixin_class_methods do
|
12
|
+
def much_slug_has_slug_registry
|
13
|
+
@much_slug_has_slug_registry ||= MuchSlug::HasSlugRegistry.new
|
14
|
+
end
|
33
15
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
16
|
+
def has_slug(
|
17
|
+
source:,
|
18
|
+
attribute: nil,
|
19
|
+
preprocessor: nil,
|
20
|
+
separator: nil,
|
21
|
+
allow_underscores: nil,
|
22
|
+
skip_unique_validation: false,
|
23
|
+
unique_scope: nil)
|
24
|
+
registered_attribute =
|
25
|
+
much_slug_has_slug_registry.register(
|
26
|
+
attribute: attribute,
|
27
|
+
source: source,
|
28
|
+
preprocessor: preprocessor,
|
29
|
+
separator: separator,
|
30
|
+
allow_underscores: allow_underscores,
|
31
|
+
)
|
42
32
|
|
43
|
-
|
44
|
-
|
33
|
+
# since the slug isn't written until an after callback we can't always
|
34
|
+
# validate presence of it
|
35
|
+
validates_presence_of(registered_attribute, on: :update)
|
45
36
|
|
46
|
-
|
37
|
+
unless skip_unique_validation
|
38
|
+
validates_uniqueness_of(
|
39
|
+
registered_attribute,
|
40
|
+
case_sensitive: true,
|
41
|
+
scope: unique_scope,
|
42
|
+
allow_nil: true,
|
43
|
+
allow_blank: true,
|
44
|
+
)
|
47
45
|
end
|
48
46
|
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
after_create :much_slug_has_slug_update_slug_values
|
48
|
+
after_update :much_slug_has_slug_update_slug_values
|
49
|
+
|
50
|
+
registered_attribute
|
52
51
|
end
|
52
|
+
end
|
53
53
|
|
54
|
-
|
55
|
-
|
54
|
+
mixin_instance_methods do
|
55
|
+
private
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
57
|
+
def much_slug_has_slug_update_slug_values
|
58
|
+
MuchSlug.has_slug_changed_slug_values(self) do |attribute, slug_value|
|
59
|
+
public_send("#{attribute}=", slug_value)
|
60
|
+
update_column(attribute, slug_value)
|
62
61
|
end
|
63
62
|
end
|
64
63
|
end
|
@@ -1,32 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "much-slug"
|
2
4
|
|
3
|
-
module MuchSlug
|
4
|
-
class HasSlugRegistry < ::Hash
|
5
|
-
def initialize
|
6
|
-
super{ |h, k| h[k] = Entry.new }
|
7
|
-
end
|
5
|
+
module MuchSlug; end
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
separator:,
|
14
|
-
allow_underscores:)
|
15
|
-
(attribute || MuchSlug.default_attribute).to_s.tap do |a|
|
16
|
-
if allow_underscores.nil?
|
17
|
-
allow_underscores = MuchSlug.default_allow_underscores
|
18
|
-
end
|
7
|
+
class MuchSlug::HasSlugRegistry < ::Hash
|
8
|
+
def initialize
|
9
|
+
super(){ |h, k| h[k] = Entry.new }
|
10
|
+
end
|
19
11
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
def register(
|
13
|
+
attribute:,
|
14
|
+
source:,
|
15
|
+
preprocessor:,
|
16
|
+
separator:,
|
17
|
+
allow_underscores:)
|
18
|
+
attribute = (attribute || MuchSlug.default_attribute).to_s
|
19
|
+
source_proc = source.to_proc
|
20
|
+
preprocessor_proc = (preprocessor || MuchSlug.default_preprocessor).to_proc
|
21
|
+
separator ||= MuchSlug.default_separator
|
22
|
+
allow_underscores =
|
23
|
+
if allow_underscores.nil?
|
24
|
+
MuchSlug.default_allow_underscores
|
25
|
+
else
|
26
|
+
!!allow_underscores
|
25
27
|
end
|
26
|
-
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
entry = self[attribute]
|
30
|
+
entry.source_proc = source_proc
|
31
|
+
entry.preprocessor_proc = preprocessor_proc
|
32
|
+
entry.separator = separator
|
33
|
+
entry.allow_underscores = allow_underscores
|
34
|
+
|
35
|
+
attribute
|
31
36
|
end
|
37
|
+
|
38
|
+
Entry =
|
39
|
+
Struct.new(
|
40
|
+
:source_proc,
|
41
|
+
:preprocessor_proc,
|
42
|
+
:separator,
|
43
|
+
:allow_underscores,
|
44
|
+
)
|
32
45
|
end
|
data/lib/much-slug/slug.rb
CHANGED
@@ -1,18 +1,20 @@
|
|
1
|
-
|
2
|
-
module Slug
|
3
|
-
def self.new(string, preprocessor:, separator:, allow_underscores: true)
|
4
|
-
regexp_escaped_sep = Regexp.escape(separator)
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
3
|
+
module MuchSlug; end
|
4
|
+
|
5
|
+
module MuchSlug::Slug
|
6
|
+
def self.new(string, preprocessor:, separator:, allow_underscores: true)
|
7
|
+
regexp_escaped_sep = Regexp.escape(separator)
|
8
|
+
|
9
|
+
slug = preprocessor.call(string.to_s.dup)
|
10
|
+
# Turn unwanted chars into the separator
|
11
|
+
slug.gsub!(/[^\w#{regexp_escaped_sep}]+/, separator)
|
12
|
+
# Turn underscores into the separator, unless allowing
|
13
|
+
slug.gsub!(/_/, separator) unless allow_underscores
|
14
|
+
# No more than one of the separator in a row.
|
15
|
+
slug.gsub!(/#{regexp_escaped_sep}{2,}/, separator)
|
16
|
+
# Remove leading/trailing separator.
|
17
|
+
slug.gsub!(/\A#{regexp_escaped_sep}|#{regexp_escaped_sep}\z/, "")
|
18
|
+
slug
|
17
19
|
end
|
18
20
|
end
|
data/lib/much-slug/version.rb
CHANGED
data/log/{.gitkeep → .keep}
RENAMED
File without changes
|
data/much-slug.gemspec
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
5
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
6
|
require "much-slug/version"
|
5
7
|
|
@@ -11,17 +13,18 @@ Gem::Specification.new do |gem|
|
|
11
13
|
gem.summary = "Friendly, human-readable identifiers for database records."
|
12
14
|
gem.description = "Friendly, human-readable identifiers for database records."
|
13
15
|
gem.homepage = "https://github.com/redding/much-slug"
|
14
|
-
gem.license =
|
16
|
+
gem.license = "MIT"
|
15
17
|
|
16
|
-
gem.files = `git ls-files`.split(
|
18
|
+
gem.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
19
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
20
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
19
21
|
gem.require_paths = ["lib"]
|
20
22
|
|
21
|
-
gem.required_ruby_version = "~> 2.
|
23
|
+
gem.required_ruby_version = "~> 2.5"
|
22
24
|
|
23
|
-
gem.
|
25
|
+
gem.add_development_dependency("ardb", ["~> 0.29.2"])
|
26
|
+
gem.add_development_dependency("assert", ["~> 2.19.3"])
|
27
|
+
gem.add_development_dependency("much-style-guide", ["~> 0.6.0"])
|
24
28
|
|
25
|
-
gem.
|
26
|
-
gem.add_development_dependency("ardb", ["~> 0.28.3"])
|
29
|
+
gem.add_dependency("much-mixin", ["~> 0.2.4"])
|
27
30
|
end
|