schnecke 0.1.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 +7 -0
- data/.circleci/config.yml +116 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +53 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +90 -0
- data/LICENSE.txt +21 -0
- data/README.md +166 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/schnecke/schnecke.rb +206 -0
- data/lib/schnecke/version.rb +5 -0
- data/lib/schnecke.rb +9 -0
- data/schnecke.gemspec +60 -0
- metadata +246 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f2e509bff01283a06b873a93ce83938d8b1330534f661d5fe13dc8235f764da7
|
|
4
|
+
data.tar.gz: d2fb750754fa8959baca1ff1236a9ecb83b9e908ca749d3fa25b94b8cc2dab17
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 9f8280a41d8289520a8a2f99a2fed9c0713c075805d134b16e66b02dbb53121d070f2acf3d7458744d1bf4517eaf5c2eacaf8d880ba73ad0167e3334ef82d2d3
|
|
7
|
+
data.tar.gz: 8f526df3095aa6e092eb95aee7c52258824ce4dccd8c312ff20660a14cfe1d60251f528b80a0b3ce8c22238f4f96222a525605cf81f899b69338fd50abe87f4b
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
version: 2.1
|
|
2
|
+
|
|
3
|
+
# ----------------------------------------------------------------------------
|
|
4
|
+
#
|
|
5
|
+
# REUSABLE CUSTOM DEFINITIONS & COMMANDS
|
|
6
|
+
#
|
|
7
|
+
# ----------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
commands:
|
|
10
|
+
attach-dependencies:
|
|
11
|
+
steps:
|
|
12
|
+
- checkout
|
|
13
|
+
- run:
|
|
14
|
+
name: Set up bundler
|
|
15
|
+
command: |
|
|
16
|
+
gem install bundler:2.3.22
|
|
17
|
+
- run:
|
|
18
|
+
name: Bundle Install
|
|
19
|
+
command: |
|
|
20
|
+
bundle config set --local clean 'true'
|
|
21
|
+
bundle config set --local deployment 'true'
|
|
22
|
+
bundle check || bundle install --jobs=4 --retry=3
|
|
23
|
+
- attach_workspace:
|
|
24
|
+
at: .
|
|
25
|
+
|
|
26
|
+
save-results:
|
|
27
|
+
steps:
|
|
28
|
+
- store_test_results:
|
|
29
|
+
path: test/reports
|
|
30
|
+
- store_artifacts:
|
|
31
|
+
name: "Store artifacts: test reports"
|
|
32
|
+
path: reports
|
|
33
|
+
destination: reports
|
|
34
|
+
|
|
35
|
+
# ----------------------------------------------------------------------------
|
|
36
|
+
#
|
|
37
|
+
# JOB DEFINITIONS
|
|
38
|
+
#
|
|
39
|
+
# ----------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
jobs:
|
|
42
|
+
#
|
|
43
|
+
# QUALITY: Make sure that the code is safe, secure, and clean.
|
|
44
|
+
#
|
|
45
|
+
quality:
|
|
46
|
+
resource_class: small
|
|
47
|
+
|
|
48
|
+
docker:
|
|
49
|
+
- image: cimg/ruby:3.1.2
|
|
50
|
+
|
|
51
|
+
steps:
|
|
52
|
+
# --------- SETUP ---------
|
|
53
|
+
|
|
54
|
+
- attach-dependencies
|
|
55
|
+
|
|
56
|
+
# --------- QUALITY CHECKS ---------
|
|
57
|
+
|
|
58
|
+
- run:
|
|
59
|
+
name: Ruby Audit
|
|
60
|
+
command: bundle exec ruby-audit check
|
|
61
|
+
- run:
|
|
62
|
+
name: Bundle Audit
|
|
63
|
+
command: bundle exec bundle-audit check --update
|
|
64
|
+
- run:
|
|
65
|
+
name: Rubocop
|
|
66
|
+
command: bundle exec rubocop
|
|
67
|
+
|
|
68
|
+
# --------- SAVE RESULTS ---------
|
|
69
|
+
|
|
70
|
+
- save-results
|
|
71
|
+
|
|
72
|
+
test:
|
|
73
|
+
resource_class: small
|
|
74
|
+
|
|
75
|
+
docker:
|
|
76
|
+
- image: cimg/ruby:3.1.2
|
|
77
|
+
|
|
78
|
+
steps:
|
|
79
|
+
# --------- SETUP ---------
|
|
80
|
+
|
|
81
|
+
- attach-dependencies
|
|
82
|
+
|
|
83
|
+
# --------- RUN TESTS ---------
|
|
84
|
+
|
|
85
|
+
- run:
|
|
86
|
+
name: Run tests
|
|
87
|
+
command: bundle exec rake test
|
|
88
|
+
|
|
89
|
+
# --------- SAVE RESULTS ---------
|
|
90
|
+
|
|
91
|
+
- save-results
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
# ----------------------------------------------------------------------------
|
|
95
|
+
#
|
|
96
|
+
# WORKFLOW DEFINITIONS
|
|
97
|
+
#
|
|
98
|
+
# ----------------------------------------------------------------------------
|
|
99
|
+
|
|
100
|
+
workflows:
|
|
101
|
+
version: 2
|
|
102
|
+
commit:
|
|
103
|
+
jobs:
|
|
104
|
+
- quality
|
|
105
|
+
- test
|
|
106
|
+
nightly:
|
|
107
|
+
jobs:
|
|
108
|
+
- quality
|
|
109
|
+
- test
|
|
110
|
+
triggers:
|
|
111
|
+
- schedule:
|
|
112
|
+
cron: "0 2 * * *"
|
|
113
|
+
filters:
|
|
114
|
+
branches:
|
|
115
|
+
only:
|
|
116
|
+
- main
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require:
|
|
2
|
+
- 'rubocop-performance'
|
|
3
|
+
- 'rubocop-rails'
|
|
4
|
+
- 'rubocop-minitest'
|
|
5
|
+
- 'rubocop-rake'
|
|
6
|
+
|
|
7
|
+
AllCops:
|
|
8
|
+
NewCops: enable
|
|
9
|
+
# Don't run rubocop on these files/directories
|
|
10
|
+
Exclude:
|
|
11
|
+
- '**/templates/**/*'
|
|
12
|
+
- '**/vendor/**/*'
|
|
13
|
+
- 'actionpack/lib/action_dispatch/journey/parser.rb'
|
|
14
|
+
- 'lib/templates/**/*'
|
|
15
|
+
- 'db/**/*'
|
|
16
|
+
- 'config/**/*'
|
|
17
|
+
- 'vendor/**/*'
|
|
18
|
+
- 'bin/**/*'
|
|
19
|
+
- 'node_modules/**/*'
|
|
20
|
+
|
|
21
|
+
Layout/LineLength:
|
|
22
|
+
Max: 80
|
|
23
|
+
|
|
24
|
+
Metrics/AbcSize:
|
|
25
|
+
Max: 30
|
|
26
|
+
Exclude:
|
|
27
|
+
- 'test/**/*'
|
|
28
|
+
|
|
29
|
+
Metrics/BlockLength:
|
|
30
|
+
Max: 40
|
|
31
|
+
Exclude:
|
|
32
|
+
- 'test/**/*'
|
|
33
|
+
- 'schnecke.gemspec'
|
|
34
|
+
|
|
35
|
+
Metrics/ClassLength:
|
|
36
|
+
Max: 150
|
|
37
|
+
Exclude:
|
|
38
|
+
- 'test/**/*'
|
|
39
|
+
|
|
40
|
+
Metrics/MethodLength:
|
|
41
|
+
Max: 35
|
|
42
|
+
Exclude:
|
|
43
|
+
- 'test/**/*'
|
|
44
|
+
|
|
45
|
+
Metrics/ModuleLength:
|
|
46
|
+
Max: 100
|
|
47
|
+
|
|
48
|
+
Minitest/MultipleAssertions:
|
|
49
|
+
Max: 10
|
|
50
|
+
|
|
51
|
+
Rails/RefuteMethods:
|
|
52
|
+
Exclude:
|
|
53
|
+
- 'test/**/*'
|
data/.ruby-gemset
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
schnecke
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ruby-3.1.2
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
schnecke (0.1.0)
|
|
5
|
+
activerecord (> 4.2.0)
|
|
6
|
+
activesupport (> 4.2.0)
|
|
7
|
+
|
|
8
|
+
GEM
|
|
9
|
+
remote: https://rubygems.org/
|
|
10
|
+
specs:
|
|
11
|
+
activemodel (7.0.4)
|
|
12
|
+
activesupport (= 7.0.4)
|
|
13
|
+
activerecord (7.0.4)
|
|
14
|
+
activemodel (= 7.0.4)
|
|
15
|
+
activesupport (= 7.0.4)
|
|
16
|
+
activesupport (7.0.4)
|
|
17
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
18
|
+
i18n (>= 1.6, < 2)
|
|
19
|
+
minitest (>= 5.1)
|
|
20
|
+
tzinfo (~> 2.0)
|
|
21
|
+
ast (2.4.2)
|
|
22
|
+
bundler-audit (0.9.1)
|
|
23
|
+
bundler (>= 1.2.0, < 3)
|
|
24
|
+
thor (~> 1.0)
|
|
25
|
+
concurrent-ruby (1.1.10)
|
|
26
|
+
i18n (1.12.0)
|
|
27
|
+
concurrent-ruby (~> 1.0)
|
|
28
|
+
json (2.6.2)
|
|
29
|
+
minitest (5.16.3)
|
|
30
|
+
parallel (1.22.1)
|
|
31
|
+
parser (3.1.2.1)
|
|
32
|
+
ast (~> 2.4.1)
|
|
33
|
+
rack (3.0.0)
|
|
34
|
+
rainbow (3.1.1)
|
|
35
|
+
rake (12.3.3)
|
|
36
|
+
regexp_parser (2.6.0)
|
|
37
|
+
rexml (3.2.5)
|
|
38
|
+
rubocop (1.36.0)
|
|
39
|
+
json (~> 2.3)
|
|
40
|
+
parallel (~> 1.10)
|
|
41
|
+
parser (>= 3.1.2.1)
|
|
42
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
43
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
44
|
+
rexml (>= 3.2.5, < 4.0)
|
|
45
|
+
rubocop-ast (>= 1.20.1, < 2.0)
|
|
46
|
+
ruby-progressbar (~> 1.7)
|
|
47
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
|
48
|
+
rubocop-ast (1.21.0)
|
|
49
|
+
parser (>= 3.1.1.0)
|
|
50
|
+
rubocop-minitest (0.22.1)
|
|
51
|
+
rubocop (>= 0.90, < 2.0)
|
|
52
|
+
rubocop-performance (1.15.0)
|
|
53
|
+
rubocop (>= 1.7.0, < 2.0)
|
|
54
|
+
rubocop-ast (>= 0.4.0)
|
|
55
|
+
rubocop-rails (2.16.1)
|
|
56
|
+
activesupport (>= 4.2.0)
|
|
57
|
+
rack (>= 1.1)
|
|
58
|
+
rubocop (>= 1.33.0, < 2.0)
|
|
59
|
+
rubocop-rake (0.6.0)
|
|
60
|
+
rubocop (~> 1.0)
|
|
61
|
+
ruby-progressbar (1.11.0)
|
|
62
|
+
ruby_audit (2.1.0)
|
|
63
|
+
bundler-audit (~> 0.9.0)
|
|
64
|
+
sqlite3 (1.5.1-x86_64-darwin)
|
|
65
|
+
sqlite3 (1.5.1-x86_64-linux)
|
|
66
|
+
thor (1.2.1)
|
|
67
|
+
tzinfo (2.0.5)
|
|
68
|
+
concurrent-ruby (~> 1.0)
|
|
69
|
+
unicode-display_width (2.3.0)
|
|
70
|
+
|
|
71
|
+
PLATFORMS
|
|
72
|
+
x86_64-darwin-21
|
|
73
|
+
x86_64-linux
|
|
74
|
+
|
|
75
|
+
DEPENDENCIES
|
|
76
|
+
bundler (~> 2.3)
|
|
77
|
+
bundler-audit
|
|
78
|
+
minitest (~> 5.0)
|
|
79
|
+
rake (~> 12.3)
|
|
80
|
+
rubocop
|
|
81
|
+
rubocop-minitest
|
|
82
|
+
rubocop-performance
|
|
83
|
+
rubocop-rails
|
|
84
|
+
rubocop-rake
|
|
85
|
+
ruby_audit
|
|
86
|
+
schnecke!
|
|
87
|
+
sqlite3
|
|
88
|
+
|
|
89
|
+
BUNDLED WITH
|
|
90
|
+
2.3.22
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 TODO: Write your name
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Schnecke
|
|
2
|
+
|
|
3
|
+
[](https://dl.circleci.com/status-badge/redirect/gh/prschmid/schnecke/tree/main)
|
|
4
|
+
|
|
5
|
+
A very simple gem to enable ActiveRecord models to have slugs.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add this line to your application's Gemfile:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem 'schnecke'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
And then execute:
|
|
16
|
+
|
|
17
|
+
$ bundle
|
|
18
|
+
|
|
19
|
+
Or install it yourself as:
|
|
20
|
+
|
|
21
|
+
$ gem install schnecke
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
Given a class `A` which has the attribute `name` and has a `slug` column defined, we can do the following:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
class A
|
|
29
|
+
include Schnecke
|
|
30
|
+
slug :name
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This will take the value in `name` and automatically set the slug based on it. If the slug needs to be based on multiple attributes of a model, simply pass in the array of attributes as follows:
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
class A
|
|
38
|
+
include Schnecke
|
|
39
|
+
slug [:first_name, :last_name]
|
|
40
|
+
end
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Slug column
|
|
44
|
+
|
|
45
|
+
By default it is assumed that the generated slug will be assigned to the `slug` attribute of the model. If one needs to place the slug in a different columm, this can be done by defining the `column` attribute:
|
|
46
|
+
|
|
47
|
+
```ruby
|
|
48
|
+
class A
|
|
49
|
+
include Schnecke
|
|
50
|
+
slug :name, column: :some_other_column
|
|
51
|
+
end
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The above will place the generated slug in `some_other_column`.
|
|
55
|
+
|
|
56
|
+
### Slug Uniquness
|
|
57
|
+
|
|
58
|
+
By default slugs are unique to the object that defines the slug. For example if we have the 2 objects, `A` and `B` as defined as below, then the slugs will be unique for all slugs for all type `A` objcets and all type `B` objects.
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
class A
|
|
62
|
+
include Schnecke
|
|
63
|
+
slug :name
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
class B
|
|
67
|
+
include Schnecke
|
|
68
|
+
slug :name
|
|
69
|
+
end
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This means that the slug `foo` can exists 2 times; once for any object of type `A` and once for any object of type `B`. Currently there is no way to create globally unique slugs. If this is something that is required, then something like [`friendly_id`](https://github.com/norman/friendly_id) might be more appropriate for your use case.
|
|
73
|
+
|
|
74
|
+
### Handling non-unique slugs
|
|
75
|
+
|
|
76
|
+
If a duplicate slug is to be created, a number is automatically appended to the end of the slug. For example, if there is a slug `foo`, the second one would become `foo-2`, the third `foo-3`, and so forth.
|
|
77
|
+
|
|
78
|
+
### Defining a custom uniqueness scope
|
|
79
|
+
|
|
80
|
+
There are times when we want slugs not be unique for all objects of type `A`, but rather for a smaller scope. For example, let's say we have a system with multiple `Accounts`, each containing `Record`s. If we want the slug for the `Record` to be unique only within the scope of an `account` we can do by providing the uniqueness scope when setting up the slug.
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
class Record
|
|
84
|
+
include Schnecke
|
|
85
|
+
slug :name, uniqueness: { scope: :account}
|
|
86
|
+
|
|
87
|
+
belongs_to :account
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
When we do this, this will let us have the same slug 'foo' for multiple `record` objects as long as they belong todifferent `accounts`. Note, we can also pass an array so that we can define the scope even more narrowly. For example:
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
class Tag
|
|
95
|
+
include Schnecke
|
|
96
|
+
slug :name, uniqueness: { scope: [:account, :record]}
|
|
97
|
+
|
|
98
|
+
belongs_to :account
|
|
99
|
+
belongs_to :record
|
|
100
|
+
end
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Advanced Usage
|
|
104
|
+
|
|
105
|
+
If you need to change how the slug is generated, how duplicates are handled, etc., you can overwrite the methods in your class. For example to change how slugs are generated you can overwrite the `slugify` method.
|
|
106
|
+
|
|
107
|
+
```ruby
|
|
108
|
+
class A
|
|
109
|
+
include Schnecke
|
|
110
|
+
slug :name
|
|
111
|
+
|
|
112
|
+
# Overwrite the `slugify` method. In this case the slug will always be 'foo'
|
|
113
|
+
def slugify(str)
|
|
114
|
+
'foo'
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Note, by default the library will validate to ensure that the slug only contains lowercase alpphanumeric letters and '-' or '_'. If your new method changes the alloweable set of characters you can either disable this validation, or pass in your own validation pattern.
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
class A
|
|
123
|
+
include Schnecke
|
|
124
|
+
slug :name, require_format: false
|
|
125
|
+
|
|
126
|
+
def slugify(str)
|
|
127
|
+
'This#Would/NormallyF@!l'
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
class B
|
|
132
|
+
include Schnecke
|
|
133
|
+
slug :name, require_format: /\A[a-z]+\z/
|
|
134
|
+
|
|
135
|
+
def slugify(str)
|
|
136
|
+
'lettersonly'
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The methods that can be overwritten are
|
|
142
|
+
|
|
143
|
+
* `slugify(str)`: This is used to turn a string into a slug
|
|
144
|
+
* `slugify_blank`: This is used when the slug returned is blank and we need some default slug generated
|
|
145
|
+
* `slugify_duplicate(slug)`: This will take a slug generated by `slugify` and generate a unique version of it
|
|
146
|
+
* `slug_concat(parts)`: This takes an array of slugs and combines them into 1 string
|
|
147
|
+
|
|
148
|
+
For details, please see the actual code.
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
153
|
+
|
|
154
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
155
|
+
|
|
156
|
+
## Contributing
|
|
157
|
+
|
|
158
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/prschmid/schnecke.
|
|
159
|
+
|
|
160
|
+
## Acknowledgements
|
|
161
|
+
|
|
162
|
+
This work is based on the [`slug`](https://github.com/bkoski/slug) gem.
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
require 'schnecke'
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
+
# require "pry"
|
|
12
|
+
# Pry.start
|
|
13
|
+
|
|
14
|
+
require 'irb'
|
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'active_support/concern'
|
|
4
|
+
|
|
5
|
+
# Adds the necessary functionality for an ActiveRecord object to have a slug
|
|
6
|
+
#
|
|
7
|
+
# See the README for usage instructions and details.
|
|
8
|
+
module Schnecke
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
DEFAULT_SLUG_COLUMN = :slug
|
|
12
|
+
DEFAULT_SLUG_SEPARATOR = '-'
|
|
13
|
+
DEFAULT_REQUIRED_FORMAT = /\A[a-z0-9\-_]+\z/
|
|
14
|
+
|
|
15
|
+
class_methods do
|
|
16
|
+
def slug(source, opts = {})
|
|
17
|
+
class_attribute :schnecke_config
|
|
18
|
+
|
|
19
|
+
# Save the configuration
|
|
20
|
+
self.schnecke_config = {
|
|
21
|
+
slug_source: source,
|
|
22
|
+
slug_column: opts.fetch(:column, DEFAULT_SLUG_COLUMN),
|
|
23
|
+
slug_separator: opts.fetch(:separator, DEFAULT_SLUG_SEPARATOR),
|
|
24
|
+
required: opts.fetch(:required, true),
|
|
25
|
+
generate_on_blank: opts.fetch(:generate_on_blank, true),
|
|
26
|
+
require_format: opts.fetch(:require_format, DEFAULT_REQUIRED_FORMAT),
|
|
27
|
+
uniqueness: opts.fetch(:uniqueness, {})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
# Setup the validations for the slug
|
|
31
|
+
validates_uniqueness_of schnecke_config[:slug_column],
|
|
32
|
+
schnecke_config[:uniqueness]
|
|
33
|
+
|
|
34
|
+
if schnecke_config[:required]
|
|
35
|
+
validates schnecke_config[:slug_column],
|
|
36
|
+
presence: true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if schnecke_config[:require_format]
|
|
40
|
+
validates \
|
|
41
|
+
schnecke_config[:slug_column],
|
|
42
|
+
format: { with: schnecke_config[:require_format],
|
|
43
|
+
message: 'contains invalid characters. Only ' \
|
|
44
|
+
"#{schnecke_config[:require_format]} are allowed" }
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Ensure the slug gets created automatically
|
|
48
|
+
before_validation :assign_slug, on: :create
|
|
49
|
+
|
|
50
|
+
include InstanceMethods
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Instance methods to include
|
|
55
|
+
module InstanceMethods
|
|
56
|
+
# Assign the slug
|
|
57
|
+
#
|
|
58
|
+
# This is automatically called before model validation.
|
|
59
|
+
#
|
|
60
|
+
# Note, a slug will not be assigned if one already exists. If one needs to
|
|
61
|
+
# force the assignment of a slug, pass `force: true`
|
|
62
|
+
def assign_slug(opts = {})
|
|
63
|
+
validate_source
|
|
64
|
+
validate_slug_column
|
|
65
|
+
|
|
66
|
+
return if !should_create_slug? && !opts[:force]
|
|
67
|
+
|
|
68
|
+
# Generate the slug
|
|
69
|
+
candidate_slug = slugify_source(schnecke_config[:slug_source])
|
|
70
|
+
|
|
71
|
+
# If slugify returned a blank string, create one not based on the
|
|
72
|
+
# source
|
|
73
|
+
if candidate_slug.blank? && schnecke_config[:generate_on_blank]
|
|
74
|
+
candidate_slug = slugify_blank
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# If there is a duplicate, create a unique one
|
|
78
|
+
if slug_exists?(candidate_slug)
|
|
79
|
+
candidate_slug = slugify_duplicate(candidate_slug)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
self[schnecke_config[:slug_column]] = candidate_slug
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Reassign the slug
|
|
86
|
+
#
|
|
87
|
+
# Unlike assign_slug, this will cause a slug to be created even if one
|
|
88
|
+
# already exists.
|
|
89
|
+
def reassign_slug
|
|
90
|
+
assign_slug(force: true)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
protected
|
|
94
|
+
|
|
95
|
+
# Slugify a string
|
|
96
|
+
#
|
|
97
|
+
# This will take a string and convert it to a slug by removing punctuation
|
|
98
|
+
# and then ensuring it is downcased and has the special characters removed
|
|
99
|
+
#
|
|
100
|
+
# This can be overriden if a different slug generation method is needed
|
|
101
|
+
def slugify(str)
|
|
102
|
+
return if str.blank?
|
|
103
|
+
|
|
104
|
+
str.gsub!(/[\p{Pc}\p{Ps}\p{Pe}\p{Pi}\p{Pf}\p{Po}]/, '')
|
|
105
|
+
str.parameterize
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Default slug for blank strings.
|
|
109
|
+
#
|
|
110
|
+
# The slug to use if the string we were to use to slugify returns a blank
|
|
111
|
+
# slug.
|
|
112
|
+
#
|
|
113
|
+
# This can be overriden if a different slug generation method is needed
|
|
114
|
+
def slugify_blank
|
|
115
|
+
self.class.to_s.demodulize.underscore.dasherize
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Handle the creation of a unique slug
|
|
119
|
+
#
|
|
120
|
+
# This assumes that the slug has already been generated with `slugify` but
|
|
121
|
+
# that this value is non-unique. As such we will append '-n' to the end of
|
|
122
|
+
# the slug to make it unique. The second instance gets a '-2' suffix, the
|
|
123
|
+
# third will get a '-3', and so forth.
|
|
124
|
+
#
|
|
125
|
+
# This can be overriden if a different behavior is desired
|
|
126
|
+
def slugify_duplicate(slug)
|
|
127
|
+
return if slug.blank?
|
|
128
|
+
|
|
129
|
+
seq = 2
|
|
130
|
+
new_slug = slug_concat([slug, seq])
|
|
131
|
+
while slug_exists?(new_slug)
|
|
132
|
+
seq += 1
|
|
133
|
+
new_slug = slug_concat([slug, seq])
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
new_slug
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Concatenate multiple slugified parts together
|
|
140
|
+
#
|
|
141
|
+
# This is used in, if the slug is to be generated from multiple
|
|
142
|
+
# attributes of the model (e.g. [:first_name, :last_name]) and when we
|
|
143
|
+
# append a number to the end of a slug if the initial slug wsa non-unique.
|
|
144
|
+
#
|
|
145
|
+
# This can be overriden if a different behavior is desired
|
|
146
|
+
def slug_concat(parts)
|
|
147
|
+
parts.join(schnecke_config[:slug_separator])
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
private
|
|
151
|
+
|
|
152
|
+
def validate_source
|
|
153
|
+
source = arrayify(schnecke_config[:slug_source])
|
|
154
|
+
source.each do |attr|
|
|
155
|
+
unless respond_to?(attr)
|
|
156
|
+
raise ArgumentError,
|
|
157
|
+
"Source '#{attr}' does not exist."
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def validate_slug_column
|
|
163
|
+
return if respond_to?("#{schnecke_config[:slug_column]}=")
|
|
164
|
+
|
|
165
|
+
raise ArgumentError,
|
|
166
|
+
"Slug column '#{schnecke_config[:slug_column]}' does not " \
|
|
167
|
+
'exist.'
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def should_create_slug?
|
|
171
|
+
self[schnecke_config[:slug_column]].blank?
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def slugify_source(source)
|
|
175
|
+
parts = arrayify(source).map do |part|
|
|
176
|
+
slugify(send(part))
|
|
177
|
+
end
|
|
178
|
+
parts.join(schnecke_config[:slug_separator])
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def slug_exists?(slug)
|
|
182
|
+
slug_scope.exists?(schnecke_config[:slug_column] => slug)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def slug_scope
|
|
186
|
+
query = self.class.base_class
|
|
187
|
+
if schnecke_config[:uniqueness].present?
|
|
188
|
+
if schnecke_config[:uniqueness][:scope].present?
|
|
189
|
+
scopes = arrayify(schnecke_config[:uniqueness][:scope])
|
|
190
|
+
scopes.each do |scope|
|
|
191
|
+
query = query.where(scope => send(scope))
|
|
192
|
+
end
|
|
193
|
+
elsif schnecke_config[:uniqueness][:conditions].present?
|
|
194
|
+
raise 'Cannot handle uniqueness constraint parameter `:conditions`'
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
query
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def arrayify(obj)
|
|
201
|
+
return obj if obj.is_a?(Array)
|
|
202
|
+
|
|
203
|
+
[obj]
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
data/lib/schnecke.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'schnecke/version'
|
|
4
|
+
require File.join(File.dirname(__FILE__), 'schnecke', 'schnecke')
|
|
5
|
+
|
|
6
|
+
ActiveRecord::Base.instance_eval { include Schnecke }
|
|
7
|
+
if defined?(Rails) && Rails.version.to_i < 4
|
|
8
|
+
raise 'This version of schnecke requires Rails 4 or higher'
|
|
9
|
+
end
|
data/schnecke.gemspec
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
+
require 'schnecke/version'
|
|
6
|
+
|
|
7
|
+
Gem::Specification.new do |spec|
|
|
8
|
+
spec.name = 'schnecke'
|
|
9
|
+
spec.version = Schnecke::VERSION
|
|
10
|
+
spec.authors = ['Patrick R. Schmid']
|
|
11
|
+
spec.email = ['prschmid@gmail.com']
|
|
12
|
+
|
|
13
|
+
spec.summary = 'Simple and straightforward way to add slugs to ' \
|
|
14
|
+
'ActiveRecod models.'
|
|
15
|
+
spec.description = 'A simple and straightforward way to add slugs to ' \
|
|
16
|
+
'ActiveRecod models.'
|
|
17
|
+
spec.homepage = 'https://github.com/prschmid/schnecke'
|
|
18
|
+
spec.license = 'MIT'
|
|
19
|
+
|
|
20
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the
|
|
21
|
+
# 'allowed_push_host' to allow pushing to a single host or delete this
|
|
22
|
+
# section to allow pushing to any host.
|
|
23
|
+
if spec.respond_to?(:metadata)
|
|
24
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
25
|
+
spec.metadata['source_code_uri'] = 'https://github.com/prschmid/schnecke'
|
|
26
|
+
spec.metadata['changelog_uri'] = 'https://github.com/prschmid/schnecke'
|
|
27
|
+
else
|
|
28
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
|
29
|
+
'public gem pushes.'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Specify which files should be added to the gem when it is released.
|
|
33
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added
|
|
34
|
+
# into git.
|
|
35
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
36
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
37
|
+
f.match(%r{^(test|spec|features)/})
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
spec.bindir = 'exe'
|
|
41
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
42
|
+
spec.require_paths = ['lib']
|
|
43
|
+
|
|
44
|
+
spec.required_ruby_version = '>= 3.1'
|
|
45
|
+
|
|
46
|
+
spec.add_development_dependency('bundler', '~> 2.3')
|
|
47
|
+
spec.add_development_dependency('bundler-audit', '>= 0')
|
|
48
|
+
spec.add_development_dependency('minitest', '~> 5.0')
|
|
49
|
+
spec.add_development_dependency('rake', '~> 12.3')
|
|
50
|
+
spec.add_development_dependency('rubocop', '>= 0')
|
|
51
|
+
spec.add_development_dependency('rubocop-minitest', '>= 0')
|
|
52
|
+
spec.add_development_dependency('rubocop-performance', '>= 0')
|
|
53
|
+
spec.add_development_dependency('rubocop-rails', '>= 0')
|
|
54
|
+
spec.add_development_dependency('rubocop-rake', '>= 0')
|
|
55
|
+
spec.add_development_dependency('ruby_audit', '>= 0')
|
|
56
|
+
spec.add_development_dependency('sqlite3', '>= 0')
|
|
57
|
+
spec.add_runtime_dependency('activerecord', '> 4.2.0')
|
|
58
|
+
spec.add_runtime_dependency('activesupport', '> 4.2.0')
|
|
59
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
60
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: schnecke
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Patrick R. Schmid
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2022-10-01 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.3'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.3'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler-audit
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: minitest
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '5.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '5.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: rake
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '12.3'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '12.3'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rubocop
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: rubocop-minitest
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: rubocop-performance
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - ">="
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
- !ruby/object:Gem::Dependency
|
|
112
|
+
name: rubocop-rails
|
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
|
114
|
+
requirements:
|
|
115
|
+
- - ">="
|
|
116
|
+
- !ruby/object:Gem::Version
|
|
117
|
+
version: '0'
|
|
118
|
+
type: :development
|
|
119
|
+
prerelease: false
|
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
- !ruby/object:Gem::Dependency
|
|
126
|
+
name: rubocop-rake
|
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
|
128
|
+
requirements:
|
|
129
|
+
- - ">="
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
+
requirements:
|
|
136
|
+
- - ">="
|
|
137
|
+
- !ruby/object:Gem::Version
|
|
138
|
+
version: '0'
|
|
139
|
+
- !ruby/object:Gem::Dependency
|
|
140
|
+
name: ruby_audit
|
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
|
142
|
+
requirements:
|
|
143
|
+
- - ">="
|
|
144
|
+
- !ruby/object:Gem::Version
|
|
145
|
+
version: '0'
|
|
146
|
+
type: :development
|
|
147
|
+
prerelease: false
|
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
+
requirements:
|
|
150
|
+
- - ">="
|
|
151
|
+
- !ruby/object:Gem::Version
|
|
152
|
+
version: '0'
|
|
153
|
+
- !ruby/object:Gem::Dependency
|
|
154
|
+
name: sqlite3
|
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
|
156
|
+
requirements:
|
|
157
|
+
- - ">="
|
|
158
|
+
- !ruby/object:Gem::Version
|
|
159
|
+
version: '0'
|
|
160
|
+
type: :development
|
|
161
|
+
prerelease: false
|
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
+
requirements:
|
|
164
|
+
- - ">="
|
|
165
|
+
- !ruby/object:Gem::Version
|
|
166
|
+
version: '0'
|
|
167
|
+
- !ruby/object:Gem::Dependency
|
|
168
|
+
name: activerecord
|
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
|
170
|
+
requirements:
|
|
171
|
+
- - ">"
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: 4.2.0
|
|
174
|
+
type: :runtime
|
|
175
|
+
prerelease: false
|
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
+
requirements:
|
|
178
|
+
- - ">"
|
|
179
|
+
- !ruby/object:Gem::Version
|
|
180
|
+
version: 4.2.0
|
|
181
|
+
- !ruby/object:Gem::Dependency
|
|
182
|
+
name: activesupport
|
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
|
184
|
+
requirements:
|
|
185
|
+
- - ">"
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: 4.2.0
|
|
188
|
+
type: :runtime
|
|
189
|
+
prerelease: false
|
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - ">"
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: 4.2.0
|
|
195
|
+
description: A simple and straightforward way to add slugs to ActiveRecod models.
|
|
196
|
+
email:
|
|
197
|
+
- prschmid@gmail.com
|
|
198
|
+
executables: []
|
|
199
|
+
extensions: []
|
|
200
|
+
extra_rdoc_files: []
|
|
201
|
+
files:
|
|
202
|
+
- ".circleci/config.yml"
|
|
203
|
+
- ".gitignore"
|
|
204
|
+
- ".rubocop.yml"
|
|
205
|
+
- ".ruby-gemset"
|
|
206
|
+
- ".ruby-version"
|
|
207
|
+
- ".travis.yml"
|
|
208
|
+
- Gemfile
|
|
209
|
+
- Gemfile.lock
|
|
210
|
+
- LICENSE.txt
|
|
211
|
+
- README.md
|
|
212
|
+
- Rakefile
|
|
213
|
+
- bin/console
|
|
214
|
+
- bin/setup
|
|
215
|
+
- lib/schnecke.rb
|
|
216
|
+
- lib/schnecke/schnecke.rb
|
|
217
|
+
- lib/schnecke/version.rb
|
|
218
|
+
- schnecke.gemspec
|
|
219
|
+
homepage: https://github.com/prschmid/schnecke
|
|
220
|
+
licenses:
|
|
221
|
+
- MIT
|
|
222
|
+
metadata:
|
|
223
|
+
homepage_uri: https://github.com/prschmid/schnecke
|
|
224
|
+
source_code_uri: https://github.com/prschmid/schnecke
|
|
225
|
+
changelog_uri: https://github.com/prschmid/schnecke
|
|
226
|
+
rubygems_mfa_required: 'true'
|
|
227
|
+
post_install_message:
|
|
228
|
+
rdoc_options: []
|
|
229
|
+
require_paths:
|
|
230
|
+
- lib
|
|
231
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
232
|
+
requirements:
|
|
233
|
+
- - ">="
|
|
234
|
+
- !ruby/object:Gem::Version
|
|
235
|
+
version: '3.1'
|
|
236
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
237
|
+
requirements:
|
|
238
|
+
- - ">="
|
|
239
|
+
- !ruby/object:Gem::Version
|
|
240
|
+
version: '0'
|
|
241
|
+
requirements: []
|
|
242
|
+
rubygems_version: 3.3.7
|
|
243
|
+
signing_key:
|
|
244
|
+
specification_version: 4
|
|
245
|
+
summary: Simple and straightforward way to add slugs to ActiveRecod models.
|
|
246
|
+
test_files: []
|