fts_fuzzy_match 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5ae4ec8437fae32168ace83c701014d8ad3172a9e31abbf68c4501f5b33b59eb
4
+ data.tar.gz: e4ca65980fda174f25361290429f8ebadf1a859b91b6c0723342464c7888f6b6
5
+ SHA512:
6
+ metadata.gz: e03afcccdf173c3106442247df9574aba34fe3b36fc9a3418a4b41c39714048f6e2f10314b53d66aaff10f7b101b657c4958efc97ba5f2b6178f2f0cd4d3ebc1
7
+ data.tar.gz: 952900929bfa9eb2282e81f47cb4ef0b65511f4d233f6ca99252f9050858b008d51f7486c61aebab2eeb28f3b0feb10c011683ca59e974604ceefda3ee105759
@@ -0,0 +1,26 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ - package-ecosystem: "bundler"
8
+ directory: "/fuzzy_match"
9
+ schedule:
10
+ interval: "weekly"
11
+ - package-ecosystem: "bundler"
12
+ directory: "/system"
13
+ schedule:
14
+ interval: "weekly"
15
+ - package-ecosystem: "bundler"
16
+ directory: "/packaged_source"
17
+ schedule:
18
+ interval: "weekly"
19
+ - package-ecosystem: "bundler"
20
+ directory: "/packaged_tarball"
21
+ schedule:
22
+ interval: "weekly"
23
+ - package-ecosystem: "bundler"
24
+ directory: "/precompiled"
25
+ schedule:
26
+ interval: "weekly"
@@ -0,0 +1,37 @@
1
+ name: fuzzy_match
2
+ concurrency:
3
+ group: "${{github.workflow}}-${{github.ref}}"
4
+ cancel-in-progress: true
5
+ on:
6
+ workflow_dispatch:
7
+ schedule:
8
+ - cron: "0 8 * * 3" # At 08:00 on Wednesday # https://crontab.guru/#0_8_*_*_3
9
+ push:
10
+ branches:
11
+ - main
12
+ - v*.*.x
13
+ tags:
14
+ - v*.*.*
15
+ pull_request:
16
+ types: [opened, synchronize]
17
+ branches:
18
+ - '*'
19
+ paths: ["fuzzy_match/**/*", ".github/workflows/fuzzy_match.yml"]
20
+
21
+ jobs:
22
+ fuzzy_match:
23
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ ruby: ["3.0", "3.1", "3.2", "3.3", "3.4", "head"]
27
+ runs-on: ["ubuntu-latest", "macos-latest", "windows-latest"]
28
+ runs-on: ${{matrix.runs-on}}
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: ruby/setup-ruby@v1
32
+ with:
33
+ working-directory: fuzzy_match
34
+ ruby-version: ${{matrix.ruby}}
35
+ bundler-cache: true
36
+ - run: bundle exec rake compile test
37
+ working-directory: fuzzy_match
@@ -0,0 +1,37 @@
1
+ name: packaged_source
2
+ concurrency:
3
+ group: "${{github.workflow}}-${{github.ref}}"
4
+ cancel-in-progress: true
5
+ on:
6
+ workflow_dispatch:
7
+ schedule:
8
+ - cron: "0 8 * * 3" # At 08:00 on Wednesday # https://crontab.guru/#0_8_*_*_3
9
+ push:
10
+ branches:
11
+ - main
12
+ - v*.*.x
13
+ tags:
14
+ - v*.*.*
15
+ pull_request:
16
+ types: [opened, synchronize]
17
+ branches:
18
+ - '*'
19
+ paths: ["packaged_source/**/*", ".github/workflows/packaged_source.yml"]
20
+
21
+ jobs:
22
+ packaged_source:
23
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ ruby: ["3.0", "3.1", "3.2", "3.3", "3.4", "head"]
27
+ runs-on: ["ubuntu-latest", "macos-latest", "windows-latest"]
28
+ runs-on: ${{matrix.runs-on}}
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: ruby/setup-ruby@v1
32
+ with:
33
+ working-directory: packaged_source
34
+ ruby-version: ${{matrix.ruby}}
35
+ bundler-cache: true
36
+ - run: bundle exec rake compile test
37
+ working-directory: packaged_source
@@ -0,0 +1,41 @@
1
+ name: packaged_tarball
2
+ concurrency:
3
+ group: "${{github.workflow}}-${{github.ref}}"
4
+ cancel-in-progress: true
5
+ on:
6
+ workflow_dispatch:
7
+ schedule:
8
+ - cron: "0 8 * * 3" # At 08:00 on Wednesday # https://crontab.guru/#0_8_*_*_3
9
+ push:
10
+ branches:
11
+ - main
12
+ - v*.*.x
13
+ tags:
14
+ - v*.*.*
15
+ pull_request:
16
+ types: [opened, synchronize]
17
+ branches:
18
+ - '*'
19
+ paths: ["packaged_tarball/**/*", ".github/workflows/packaged_tarball.yml"]
20
+
21
+ jobs:
22
+ packaged_tarball:
23
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ ruby: ["3.0", "3.1", "3.2", "3.3", "3.4", "head"]
27
+ runs-on: ["ubuntu-latest", "macos-13", "windows-latest"]
28
+ runs-on: ${{matrix.runs-on}}
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: ruby/setup-ruby@v1
32
+ with:
33
+ working-directory: packaged_tarball
34
+ ruby-version: ${{matrix.ruby}}
35
+ bundler-cache: true
36
+ - uses: actions/cache@v4
37
+ with:
38
+ path: packaged_tarball/ports
39
+ key: packaged_tarball-ports-${{matrix.runs-on}}-${{hashFiles('packaged_tarball/ext/packaged_tarball/extconf.rb')}}
40
+ - run: bundle exec rake compile test
41
+ working-directory: packaged_tarball
@@ -0,0 +1,232 @@
1
+ name: precompiled
2
+ concurrency:
3
+ group: "${{github.workflow}}-${{github.ref}}"
4
+ cancel-in-progress: true
5
+ on:
6
+ workflow_dispatch:
7
+ schedule:
8
+ - cron: "0 8 * * 3" # At 08:00 on Wednesday # https://crontab.guru/#0_8_*_*_3
9
+ push:
10
+ branches:
11
+ - main
12
+ - v*.*.x
13
+ tags:
14
+ - v*.*.*
15
+ pull_request:
16
+ types: [opened, synchronize]
17
+ branches:
18
+ - '*'
19
+ paths: ["precompiled/**/*", ".github/workflows/precompiled.yml"]
20
+
21
+ jobs:
22
+ ruby_versions:
23
+ outputs:
24
+ setup_ruby: "['3.1', '3.2', '3.3', '3.4']"
25
+ image_tag: "['3.1', '3.2', '3.3', '3.4']"
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - run: echo "generating rubies ..."
29
+
30
+ rcd_image_version:
31
+ runs-on: ubuntu-latest
32
+ outputs:
33
+ rcd_image_version: ${{steps.rcd_image_version.outputs.rcd_image_version}}
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: ruby/setup-ruby@v1
37
+ with:
38
+ working-directory: precompiled
39
+ ruby-version: "3.3"
40
+ bundler-cache: true
41
+ bundler: latest
42
+ - id: rcd_image_version
43
+ run: bundle exec ruby -e 'require "rake_compiler_dock"; puts "rcd_image_version=#{RakeCompilerDock::IMAGE_VERSION}"' >> $GITHUB_OUTPUT
44
+ working-directory: precompiled
45
+
46
+ test:
47
+ needs: ["ruby_versions"]
48
+ strategy:
49
+ fail-fast: false
50
+ matrix:
51
+ runs-on: ["ubuntu-latest", "macos-13", "windows-latest"]
52
+ ruby: ${{ fromJSON(needs.ruby_versions.outputs.setup_ruby) }}
53
+ runs-on: ${{matrix.runs-on}}
54
+ steps:
55
+ - uses: actions/checkout@v4
56
+ - uses: ruby/setup-ruby@v1
57
+ with:
58
+ working-directory: precompiled
59
+ ruby-version: ${{matrix.ruby}}
60
+ bundler-cache: true
61
+ - uses: actions/cache@v4
62
+ with:
63
+ path: precompiled/ports
64
+ key: precompiled-ports-${{matrix.runs-on}}-${{hashFiles('precompiled/ext/precompiled/extconf.rb')}}
65
+ - run: bundle exec rake compile test
66
+ working-directory: precompiled
67
+
68
+ generic-package:
69
+ runs-on: "ubuntu-latest"
70
+ steps:
71
+ - uses: actions/checkout@v4
72
+ - uses: actions/cache@v4
73
+ with:
74
+ path: precompiled/ports/archives
75
+ key: archives-ubuntu-${{hashFiles('precompiled/ext/precompiled/extconf.rb')}}
76
+ - uses: ruby/setup-ruby@v1
77
+ with:
78
+ working-directory: precompiled
79
+ ruby-version: "3.3"
80
+ bundler-cache: true
81
+ - run: ./bin/test-gem-build gems ruby
82
+ working-directory: precompiled
83
+ - uses: actions/upload-artifact@v4
84
+ with:
85
+ name: cruby-gem
86
+ path: precompiled/gems
87
+ retention-days: 1
88
+
89
+ generic-install:
90
+ needs: ["generic-package", "ruby_versions"]
91
+ strategy:
92
+ fail-fast: false
93
+ matrix:
94
+ os: ["ubuntu-latest", "macos-13", "windows-latest"]
95
+ ruby: ${{ fromJSON(needs.ruby_versions.outputs.setup_ruby) }}
96
+ runs-on: ${{ matrix.os }}
97
+ steps:
98
+ - uses: actions/checkout@v4
99
+ - uses: ruby/setup-ruby@v1
100
+ with:
101
+ working-directory: precompiled
102
+ ruby-version: "${{ matrix.ruby }}"
103
+ - uses: actions/download-artifact@v4
104
+ with:
105
+ name: cruby-gem
106
+ path: precompiled/gems
107
+ - run: ./bin/test-gem-install gems
108
+ working-directory: precompiled
109
+ shell: bash
110
+
111
+ native-package:
112
+ needs: ["rcd_image_version"]
113
+ strategy:
114
+ fail-fast: false
115
+ matrix:
116
+ platform:
117
+ - "aarch64-linux-gnu"
118
+ - "aarch64-linux-musl"
119
+ - "arm-linux-gnu"
120
+ - "arm-linux-musl"
121
+ - "x86-linux-gnu"
122
+ - "x86-linux-musl"
123
+ - "x86_64-linux-gnu"
124
+ - "x86_64-linux-musl"
125
+ - "arm64-darwin"
126
+ - "x86_64-darwin"
127
+ - "x64-mingw-ucrt"
128
+ runs-on: ubuntu-latest
129
+ steps:
130
+ - uses: actions/checkout@v4
131
+ - uses: actions/cache@v4
132
+ with:
133
+ path: precompiled/ports/archives
134
+ key: archives-ubuntu-${{hashFiles('precompiled/ext/precompiled/extconf.rb')}}
135
+ - run: |
136
+ docker run --rm -v $PWD/precompiled:/precompiled -w /precompiled \
137
+ ghcr.io/rake-compiler/rake-compiler-dock-image:${{ needs.rcd_image_version.outputs.rcd_image_version }}-mri-${{ matrix.platform }} \
138
+ ./bin/test-gem-build gems ${{ matrix.platform }}
139
+ - uses: actions/upload-artifact@v4
140
+ with:
141
+ name: "cruby-${{ matrix.platform }}-gem"
142
+ path: precompiled/gems
143
+ retention-days: 1
144
+
145
+ linux-install:
146
+ needs: ["native-package", "ruby_versions"]
147
+ strategy:
148
+ fail-fast: false
149
+ matrix:
150
+ platform:
151
+ - "aarch64-linux-gnu"
152
+ - "aarch64-linux-musl"
153
+ - "arm-linux-gnu"
154
+ - "arm-linux-musl"
155
+ - "x86-linux-gnu"
156
+ - "x86-linux-musl"
157
+ - "x86_64-linux-gnu"
158
+ - "x86_64-linux-musl"
159
+ ruby: ${{ fromJSON(needs.ruby_versions.outputs.image_tag) }}
160
+ include:
161
+ # declare docker image for each platform
162
+ - { platform: aarch64-linux-musl, docker_tag: "-alpine", bootstrap: "apk add bash &&" }
163
+ - { platform: arm-linux-musl, docker_tag: "-alpine", bootstrap: "apk add bash &&" }
164
+ - { platform: x86-linux-musl, docker_tag: "-alpine", bootstrap: "apk add bash &&" }
165
+ - { platform: x86_64-linux-musl, docker_tag: "-alpine", bootstrap: "apk add bash &&" }
166
+ # declare docker platform for each platform
167
+ - { platform: aarch64-linux-gnu, docker_platform: "--platform=linux/arm64" }
168
+ - { platform: aarch64-linux-musl, docker_platform: "--platform=linux/arm64" }
169
+ - { platform: arm-linux-gnu, docker_platform: "--platform=linux/arm/v7" }
170
+ - { platform: arm-linux-musl, docker_platform: "--platform=linux/arm/v7" }
171
+ - { platform: x86-linux-gnu, docker_platform: "--platform=linux/386" }
172
+ - { platform: x86-linux-musl, docker_platform: "--platform=linux/386" }
173
+ runs-on: ubuntu-latest
174
+ steps:
175
+ - uses: actions/checkout@v4
176
+ - uses: actions/download-artifact@v4
177
+ with:
178
+ name: cruby-${{ matrix.platform }}-gem
179
+ path: precompiled/gems
180
+ - run: |
181
+ docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
182
+ docker run --rm -v $PWD/precompiled:/precompiled -w /precompiled \
183
+ ${{ matrix.docker_platform }} ruby:${{ matrix.ruby }}${{ matrix.docker_tag }} \
184
+ sh -c "
185
+ gem update --system &&
186
+ ${{ matrix.bootstrap }}
187
+ ./bin/test-gem-install gems
188
+ "
189
+
190
+ darwin-install:
191
+ needs: ["native-package", "ruby_versions"]
192
+ strategy:
193
+ fail-fast: false
194
+ matrix:
195
+ platform:
196
+ - arm64-darwin
197
+ - x86_64-darwin
198
+ ruby: ${{ fromJSON(needs.ruby_versions.outputs.setup_ruby) }}
199
+ include:
200
+ - { platform: arm64-darwin, os: macos-14 }
201
+ - { platform: x86_64-darwin, os: macos-13 }
202
+ runs-on: ${{matrix.os}}
203
+ steps:
204
+ - uses: actions/checkout@v4
205
+ - uses: ruby/setup-ruby@v1
206
+ with:
207
+ ruby-version: "${{matrix.ruby}}"
208
+ - uses: actions/download-artifact@v4
209
+ with:
210
+ name: cruby-${{matrix.platform}}-gem
211
+ path: precompiled/gems
212
+ - run: ./bin/test-gem-install gems
213
+ working-directory: precompiled
214
+
215
+ windows-install:
216
+ needs: ["native-package", "ruby_versions"]
217
+ strategy:
218
+ fail-fast: false
219
+ matrix:
220
+ ruby: ${{ fromJSON(needs.ruby_versions.outputs.setup_ruby) }}
221
+ runs-on: windows-2022
222
+ steps:
223
+ - uses: actions/checkout@v4
224
+ - uses: ruby/setup-ruby@v1
225
+ with:
226
+ ruby-version: "${{matrix.ruby}}"
227
+ - uses: actions/download-artifact@v4
228
+ with:
229
+ name: cruby-x64-mingw-ucrt-gem
230
+ path: precompiled/gems
231
+ - run: ./bin/test-gem-install gems
232
+ working-directory: precompiled
@@ -0,0 +1,40 @@
1
+ name: system
2
+ concurrency:
3
+ group: "${{github.workflow}}-${{github.ref}}"
4
+ cancel-in-progress: true
5
+ on:
6
+ workflow_dispatch:
7
+ schedule:
8
+ - cron: "0 8 * * 3" # At 08:00 on Wednesday # https://crontab.guru/#0_8_*_*_3
9
+ push:
10
+ branches:
11
+ - main
12
+ - v*.*.x
13
+ tags:
14
+ - v*.*.*
15
+ pull_request:
16
+ types: [opened, synchronize]
17
+ branches:
18
+ - '*'
19
+ paths: ["system/**/*", ".github/workflows/system.yml"]
20
+
21
+ jobs:
22
+ system:
23
+ strategy:
24
+ fail-fast: false
25
+ matrix:
26
+ ruby: ["3.0", "3.1", "3.2", "3.3", "3.4", "head"]
27
+ runs-on: ["ubuntu-latest", "macos-13", "windows-latest"]
28
+ runs-on: ${{matrix.runs-on}}
29
+ steps:
30
+ - uses: actions/checkout@v4
31
+ - uses: MSP-Greg/setup-ruby-pkgs@v1
32
+ with:
33
+ working-directory: system
34
+ ruby-version: ${{matrix.ruby}}
35
+ bundler-cache: true
36
+ mingw: "libyaml" # windows
37
+ apt-get: "libyaml-dev" # linux
38
+ brew: "libyaml" # macos
39
+ - run: bundle exec rake compile test
40
+ working-directory: system
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.bundle
10
+ *.so
11
+ *.o
12
+ *.a
13
+ mkmf.log
14
+ /fuzzy_match-*.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,314 @@
1
+ plugins:
2
+ - rubocop-minitest
3
+ - rubocop-performance
4
+ - rubocop-rake
5
+
6
+ inherit_mode:
7
+ merge:
8
+ - Exclude
9
+
10
+ AllCops:
11
+ SuggestExtensions: false
12
+ Exclude:
13
+ - "data/**/*"
14
+
15
+ # All cops except your using extensions are disabled by default.
16
+ Bundler:
17
+ Enabled: false
18
+ Gemspec:
19
+ Enabled: false
20
+ Layout:
21
+ Enabled: false
22
+ Lint:
23
+ Enabled: false
24
+ Metrics:
25
+ Enabled: false
26
+ Naming:
27
+ Enabled: false
28
+ Performance:
29
+ Enabled: false
30
+ Exclude:
31
+ - "test/**/*"
32
+ Security:
33
+ Enabled: false
34
+ Style:
35
+ Enabled: false
36
+
37
+ # Align `when` with `end`.
38
+ Layout/CaseIndentation:
39
+ Enabled: true
40
+ EnforcedStyle: end
41
+
42
+ # Align comments with method definitions.
43
+ Layout/CommentIndentation:
44
+ Enabled: true
45
+
46
+ Layout/ElseAlignment:
47
+ Enabled: true
48
+
49
+ Layout/EmptyLineAfterMagicComment:
50
+ Enabled: true
51
+
52
+ Layout/EmptyLinesAroundBlockBody:
53
+ Enabled: true
54
+
55
+ # In a regular class definition, no empty lines around the body.
56
+ Layout/EmptyLinesAroundClassBody:
57
+ Enabled: true
58
+
59
+ # In a regular method definition, no empty lines around the body.
60
+ Layout/EmptyLinesAroundMethodBody:
61
+ Enabled: true
62
+
63
+ # In a regular module definition, no empty lines around the body.
64
+ Layout/EmptyLinesAroundModuleBody:
65
+ Enabled: true
66
+
67
+ # Align `end` with the matching keyword or starting expression except for
68
+ # assignments, where it should be aligned with the LHS.
69
+ Layout/EndAlignment:
70
+ Enabled: true
71
+ EnforcedStyleAlignWith: variable
72
+
73
+ # Method definitions after `private` or `protected` isolated calls need one
74
+ # extra level of indentation.
75
+ #
76
+ # We break this rule in context, though, e.g. for private-only concerns,
77
+ # so we leave it disabled.
78
+ Layout/IndentationConsistency:
79
+ Enabled: false
80
+ EnforcedStyle: indented_internal_methods
81
+
82
+ # Detect hard tabs, no hard tabs.
83
+ Layout/IndentationStyle:
84
+ Enabled: true
85
+
86
+ # Two spaces, no tabs (for indentation).
87
+ #
88
+ # Doesn't behave properly with private-only concerns, so it's disabled.
89
+ Layout/IndentationWidth:
90
+ Enabled: false
91
+
92
+ Layout/LeadingCommentSpace:
93
+ Enabled: true
94
+
95
+ Layout/SpaceAfterColon:
96
+ Enabled: true
97
+
98
+ Layout/SpaceAfterComma:
99
+ Enabled: true
100
+
101
+ Layout/SpaceAroundEqualsInParameterDefault:
102
+ Enabled: true
103
+
104
+ Layout/SpaceAroundKeyword:
105
+ Enabled: true
106
+
107
+ # Use `foo {}` not `foo{}`.
108
+ Layout/SpaceBeforeBlockBraces:
109
+ Enabled: true
110
+
111
+ Layout/SpaceBeforeComma:
112
+ Enabled: true
113
+
114
+ Layout/SpaceBeforeFirstArg:
115
+ Enabled: true
116
+
117
+ # Use `->(x, y) { x + y }` not `-> (x, y) { x + y }`
118
+ Layout/SpaceInLambdaLiteral:
119
+ Enabled: true
120
+
121
+ # Use `[ a, [ b, c ] ]` not `[a, [b, c]]`
122
+ # Use `[]` not `[ ]`
123
+ Layout/SpaceInsideArrayLiteralBrackets:
124
+ Enabled: true
125
+ EnforcedStyle: space
126
+ EnforcedStyleForEmptyBrackets: no_space
127
+
128
+ # Use `%w[ a b ]` not `%w[ a b ]`.
129
+ Layout/SpaceInsideArrayPercentLiteral:
130
+ Enabled: true
131
+
132
+ # Use `foo { bar }` not `foo {bar}`.
133
+ # Use `foo { }` not `foo {}`.
134
+ Layout/SpaceInsideBlockBraces:
135
+ Enabled: true
136
+ EnforcedStyleForEmptyBraces: space
137
+
138
+ # Use `{ a: 1 }` not `{a:1}`.
139
+ # Use `{}` not `{ }`.
140
+ Layout/SpaceInsideHashLiteralBraces:
141
+ Enabled: true
142
+ EnforcedStyle: space
143
+ EnforcedStyleForEmptyBraces: no_space
144
+
145
+ # Use `foo(bar)` not `foo( bar )`
146
+ Layout/SpaceInsideParens:
147
+ Enabled: true
148
+
149
+ # Requiring a space is not yet supported as of 0.59.2
150
+ # Use `%w[ foo ]` not `%w[foo]`
151
+ Layout/SpaceInsidePercentLiteralDelimiters:
152
+ Enabled: false
153
+ #EnforcedStyle: space
154
+
155
+ # Use `hash[:key]` not `hash[ :key ]`
156
+ Layout/SpaceInsideReferenceBrackets:
157
+ Enabled: true
158
+
159
+ # Blank lines should not have any spaces.
160
+ Layout/TrailingEmptyLines:
161
+ Enabled: true
162
+
163
+ # No trailing whitespace.
164
+ Layout/TrailingWhitespace:
165
+ Enabled: true
166
+
167
+ Lint/RedundantStringCoercion:
168
+ Enabled: true
169
+
170
+ # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
171
+ Lint/RequireParentheses:
172
+ Enabled: true
173
+
174
+ Lint/UriEscapeUnescape:
175
+ Enabled: true
176
+
177
+ Performance/FlatMap:
178
+ Enabled: true
179
+
180
+ # We generally prefer &&/|| but like low-precedence and/or in context
181
+ Style/AndOr:
182
+ Enabled: false
183
+
184
+ # Prefer Foo.method over Foo::method
185
+ Style/ColonMethodCall:
186
+ Enabled: true
187
+
188
+ Style/DefWithParentheses:
189
+ Enabled: true
190
+
191
+ # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
192
+ Style/HashSyntax:
193
+ Enabled: true
194
+ EnforcedShorthandSyntax: either
195
+
196
+ # Defining a method with parameters needs parentheses.
197
+ Style/MethodDefParentheses:
198
+ Enabled: true
199
+
200
+ Style/ParenthesesAroundCondition:
201
+ Enabled: true
202
+
203
+ Style/PercentLiteralDelimiters:
204
+ Enabled: true
205
+ PreferredDelimiters:
206
+ default: "()"
207
+ "%i": "[]"
208
+ "%I": "[]"
209
+ "%r": "{}"
210
+ "%w": "[]"
211
+ "%W": "[]"
212
+
213
+ # Use quotes for string literals when they are enough.
214
+ Style/RedundantPercentQ:
215
+ Enabled: false
216
+
217
+ Style/RedundantReturn:
218
+ Enabled: true
219
+ AllowMultipleReturnValues: true
220
+
221
+ Style/Semicolon:
222
+ Enabled: true
223
+ AllowAsExpressionSeparator: true
224
+
225
+ Style/StabbyLambdaParentheses:
226
+ Enabled: true
227
+
228
+ # Use `"foo"` not `'foo'` unless escaping is required
229
+ Style/StringLiterals:
230
+ Enabled: true
231
+ EnforcedStyle: double_quotes
232
+ Include:
233
+ - "app/**/*"
234
+ - "config/**/*"
235
+ - "lib/**/*"
236
+ - "test/**/*"
237
+ - "Gemfile"
238
+
239
+ Style/TrailingCommaInArrayLiteral:
240
+ Enabled: true
241
+
242
+ Style/TrailingCommaInHashLiteral:
243
+ Enabled: true
244
+
245
+ Minitest/AssertInDelta: # new in 0.10
246
+ Enabled: true
247
+ Minitest/AssertKindOf: # new in 0.10
248
+ Enabled: true
249
+ Minitest/AssertOperator: # new in 0.32
250
+ Enabled: true
251
+ Minitest/AssertOutput: # new in 0.10
252
+ Enabled: true
253
+ Minitest/AssertPathExists: # new in 0.10
254
+ Enabled: true
255
+ Minitest/AssertPredicate: # new in 0.18
256
+ Enabled: true
257
+ Minitest/AssertRaisesCompoundBody: # new in 0.21
258
+ Enabled: true
259
+ Minitest/AssertRaisesWithRegexpArgument: # new in 0.22
260
+ Enabled: true
261
+ Minitest/AssertSame: # new in 0.26
262
+ Enabled: true
263
+ Minitest/AssertSilent: # new in 0.10
264
+ Enabled: true
265
+ Minitest/AssertWithExpectedArgument: # new in 0.11
266
+ Enabled: true
267
+ Minitest/AssertionInLifecycleHook: # new in 0.10
268
+ Enabled: true
269
+ Minitest/DuplicateTestRun: # new in 0.19
270
+ Enabled: true
271
+ Minitest/EmptyLineBeforeAssertionMethods: # new in 0.23
272
+ Enabled: true
273
+ Minitest/Focus: # new in 0.35
274
+ Enabled: true
275
+ Minitest/LifecycleHooksOrder: # new in 0.28
276
+ Enabled: true
277
+ Minitest/LiteralAsActualArgument: # new in 0.10
278
+ Enabled: true
279
+ Minitest/MultipleAssertions: # new in 0.10
280
+ Enabled: true
281
+ Minitest/NonExecutableTestMethod: # new in 0.34
282
+ Enabled: true
283
+ Minitest/NonPublicTestMethod: # new in 0.27
284
+ Enabled: true
285
+ Minitest/RedundantMessageArgument: # new in 0.34
286
+ Enabled: true
287
+ Minitest/RefuteInDelta: # new in 0.10
288
+ Enabled: true
289
+ Minitest/RefuteKindOf: # new in 0.10
290
+ Enabled: true
291
+ Minitest/RefuteOperator: # new in 0.32
292
+ Enabled: true
293
+ Minitest/RefutePathExists: # new in 0.10
294
+ Enabled: true
295
+ Minitest/RefutePredicate: # new in 0.18
296
+ Enabled: true
297
+ Minitest/RefuteSame: # new in 0.26
298
+ Enabled: true
299
+ Minitest/ReturnInTestMethod: # new in 0.31
300
+ Enabled: true
301
+ Minitest/SkipEnsure: # new in 0.20
302
+ Enabled: true
303
+ Minitest/SkipWithoutReason: # new in 0.24
304
+ Enabled: true
305
+ Minitest/TestFileName: # new in 0.26
306
+ Enabled: true
307
+ Minitest/TestMethodName: # new in 0.10
308
+ Enabled: true
309
+ Minitest/UnreachableAssertion: # new in 0.14
310
+ Enabled: true
311
+ Minitest/UnspecifiedException: # new in 0.10
312
+ Enabled: true
313
+ Minitest/UselessAssertion: # new in 0.26
314
+ Enabled: true
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in fts_fuzzy_match.gemspec
6
+ gemspec
7
+
8
+ gem 'rake', '~> 13.0'
9
+ gem 'rake-compiler'
10
+ gem 'minitest', '~> 5.0'
11
+ gem 'json'
12
+
13
+ gem 'rubocop-minitest'
14
+ gem 'rubocop-performance'
15
+ gem 'rubocop-rake'
data/Gemfile.lock ADDED
@@ -0,0 +1,70 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fts_fuzzy_match (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.3)
10
+ json (2.12.2)
11
+ language_server-protocol (3.17.0.5)
12
+ lint_roller (1.1.0)
13
+ minitest (5.25.5)
14
+ parallel (1.27.0)
15
+ parser (3.3.8.0)
16
+ ast (~> 2.4.1)
17
+ racc
18
+ prism (1.4.0)
19
+ racc (1.8.1)
20
+ rainbow (3.1.1)
21
+ rake (13.3.0)
22
+ rake-compiler (1.3.0)
23
+ rake
24
+ regexp_parser (2.10.0)
25
+ rubocop (1.76.0)
26
+ json (~> 2.3)
27
+ language_server-protocol (~> 3.17.0.2)
28
+ lint_roller (~> 1.1.0)
29
+ parallel (~> 1.10)
30
+ parser (>= 3.3.0.2)
31
+ rainbow (>= 2.2.2, < 4.0)
32
+ regexp_parser (>= 2.9.3, < 3.0)
33
+ rubocop-ast (>= 1.45.0, < 2.0)
34
+ ruby-progressbar (~> 1.7)
35
+ unicode-display_width (>= 2.4.0, < 4.0)
36
+ rubocop-ast (1.45.1)
37
+ parser (>= 3.3.7.2)
38
+ prism (~> 1.4)
39
+ rubocop-minitest (0.38.1)
40
+ lint_roller (~> 1.1)
41
+ rubocop (>= 1.75.0, < 2.0)
42
+ rubocop-ast (>= 1.38.0, < 2.0)
43
+ rubocop-performance (1.25.0)
44
+ lint_roller (~> 1.1)
45
+ rubocop (>= 1.75.0, < 2.0)
46
+ rubocop-ast (>= 1.38.0, < 2.0)
47
+ rubocop-rake (0.7.1)
48
+ lint_roller (~> 1.1)
49
+ rubocop (>= 1.72.1)
50
+ ruby-progressbar (1.13.0)
51
+ unicode-display_width (3.1.4)
52
+ unicode-emoji (~> 4.0, >= 4.0.4)
53
+ unicode-emoji (4.0.4)
54
+
55
+ PLATFORMS
56
+ arm64-darwin-24
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ fts_fuzzy_match!
61
+ json
62
+ minitest (~> 5.0)
63
+ rake (~> 13.0)
64
+ rake-compiler
65
+ rubocop-minitest
66
+ rubocop-performance
67
+ rubocop-rake
68
+
69
+ BUNDLED WITH
70
+ 2.6.9
data/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # FtsFuzzyMatch
2
+
3
+ This will return a match score from a pattern and string. These scores are only
4
+ useful for sorting against each other.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ## Credits
11
+
12
+ - This gem was started by using the Ruby C Extensions Explained project at
13
+ https://github.com/flavorjones/ruby-c-extensions-explained
14
+ - This gem used the fts fuzzy_match library from
15
+ https://github.com/forrestthewoods/lib_fts/tree/master
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rubygems/package_task"
5
+ require "rake/testtask"
6
+ require "rake/extensiontask"
7
+
8
+ fts_fuzzy_match_spec = Bundler.load_gemspec("fts_fuzzy_match.gemspec")
9
+ Gem::PackageTask.new(fts_fuzzy_match_spec).define
10
+
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << "test"
13
+ t.libs << "lib"
14
+ t.test_files = FileList["test/**/*_test.rb"]
15
+ end
16
+
17
+ Rake::ExtensionTask.new("fts_fuzzy_match") do |ext|
18
+ ext.lib_dir = "lib/fts_fuzzy_match"
19
+ end
20
+
21
+ task default: [:clobber, :compile, :test]
22
+
23
+ CLEAN.add("{ext,lib}/**/*.{o,so}", "pkg")
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'mkmf'
4
+
5
+ create_makefile('fts_fuzzy_match/fts_fuzzy_match')
@@ -0,0 +1,82 @@
1
+ #include "fts_fuzzy_match.h"
2
+ #define FTS_FUZZY_MATCH_IMPLEMENTATION
3
+ #include "fts_fuzzy_match_impl.h"
4
+
5
+ VALUE rb_mFtsFuzzyMatch;
6
+ VALUE rb_cFtsFuzzyMatchExtension;
7
+
8
+ static VALUE
9
+ rb_fts_fuzzy_match_extension_class_fuzzy_match(VALUE self, VALUE pattern, VALUE str)
10
+ {
11
+ char* patternPtr;
12
+ patternPtr = StringValueCStr(pattern);
13
+ char* strPtr;
14
+ strPtr = StringValueCStr(str);
15
+
16
+ int outScore;
17
+ int matched = fts_fuzzy_match_simple(patternPtr, strPtr, &outScore);
18
+ // return rb_sprintf("Matched: %d\nScore: %d\n", matched, outScore);
19
+ if (matched) {
20
+ return INT2FIX(outScore);
21
+ } else {
22
+ return Qfalse;
23
+ }
24
+ }
25
+
26
+ struct StringScore {
27
+ VALUE str;
28
+ bool matched;
29
+ int score;
30
+ };
31
+
32
+ int comp(const void *a, const void *b) {
33
+ const struct StringScore *aa = (const struct StringScore *)a;
34
+ const struct StringScore *bb = (const struct StringScore *)b;
35
+ if (!aa->matched && !bb->matched) {
36
+ return 0;
37
+ } else if (aa->matched && !bb->matched) {
38
+ return -1;
39
+ } else if (!aa->matched && bb->matched) {
40
+ return 1;
41
+ }
42
+ return bb->score - aa->score;
43
+ }
44
+
45
+ static VALUE
46
+ rb_fts_fuzzy_match_extension_class_sort_n(VALUE self, VALUE pattern, VALUE strings, VALUE n)
47
+ {
48
+ char* patternPtr;
49
+ patternPtr = StringValueCStr(pattern);
50
+ long stringsLen = RARRAY_LEN(strings);
51
+
52
+ struct StringScore *scores = (struct StringScore *)malloc(stringsLen * sizeof(struct StringScore));
53
+ for (long i=0; i<stringsLen; i++) {
54
+ const VALUE str = RARRAY_AREF(strings, i);
55
+ const char* strPtr = StringValueCStr(str);
56
+ scores[i].str = str;
57
+ scores[i].matched = fts_fuzzy_match_simple(patternPtr, strPtr, &scores[i].score);
58
+ }
59
+
60
+ qsort(scores, stringsLen, sizeof(struct StringScore), comp);
61
+
62
+ long n2 = NUM2INT(n);
63
+ if (n2 > stringsLen) n2 = stringsLen;
64
+
65
+ VALUE result = rb_ary_new_capa(n2);
66
+ for (long i=0; i<n2; i++) {
67
+ rb_ary_push(result, scores[i].str);
68
+ }
69
+
70
+ return result;
71
+ }
72
+
73
+ void
74
+ Init_fts_fuzzy_match(void)
75
+ {
76
+ rb_mFtsFuzzyMatch = rb_define_module("FtsFuzzyMatch");
77
+ rb_cFtsFuzzyMatchExtension = rb_define_class_under(rb_mFtsFuzzyMatch, "Extension", rb_cObject);
78
+ rb_define_singleton_method(rb_cFtsFuzzyMatchExtension, "fuzzy_match",
79
+ rb_fts_fuzzy_match_extension_class_fuzzy_match, 2);
80
+ rb_define_singleton_method(rb_cFtsFuzzyMatchExtension, "sort_n",
81
+ rb_fts_fuzzy_match_extension_class_sort_n, 3);
82
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef FUZZY_MATCH_H
2
+ #define FUZZY_MATCH_H 1
3
+
4
+ #include "ruby.h"
5
+
6
+ #endif /* FUZZY_MATCH_H */
@@ -0,0 +1,203 @@
1
+ // LICENSE
2
+ //
3
+ // This software is dual-licensed to the public domain and under the following
4
+ // license: you are granted a perpetual, irrevocable license to copy, modify,
5
+ // publish, and distribute this file as you see fit.
6
+ //
7
+ // VERSION
8
+ // 0.2.0 (2017-02-18) Scored matches perform exhaustive search for best score
9
+ // 0.1.0 (2016-03-28) Initial release
10
+ //
11
+ // AUTHOR
12
+ // Forrest Smith
13
+ //
14
+ // NOTES
15
+ // Compiling
16
+ // You MUST add '#define FTS_FUZZY_MATCH_IMPLEMENTATION' before including this header in ONE source file to create implementation.
17
+ //
18
+ // fts_fuzzy_match_simple(...)
19
+ // Simplified version of fts_fuzzy_match
20
+ //
21
+ // fts_fuzzy_match(...)
22
+ // Returns true if pattern is found AND calculates a score.
23
+ // Performs exhaustive search via recursion to find all possible matches and match with highest score.
24
+ // Scores values have no intrinsic meaning. Possible score range is not normalized and varies with pattern.
25
+ // Recursion is limited internally (default=10) to prevent degenerate cases (pattern="aaaaaa" str="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
26
+ // Uses uint8_t for match indices. Therefore patterns are limited to 256 characters.
27
+ // Score system should be tuned for YOUR use case. Words, sentences, file names, or method names all prefer different tuning.
28
+
29
+
30
+ #ifndef FTS_FUZZY_MATCH_H
31
+ #define FTS_FUZZY_MATCH_H
32
+
33
+
34
+ #include <ctype.h> // tolower, toupper
35
+
36
+ // Public interface
37
+ static bool fts_fuzzy_match_simple(char const * pattern, char const * str, int * outScore);
38
+ static bool fts_fuzzy_match(char const * pattern, char const * str, int * outScore, uint8_t * matches, int maxMatches);
39
+
40
+ #ifdef FTS_FUZZY_MATCH_IMPLEMENTATION
41
+
42
+ // Private interface
43
+ static bool fts_fuzzy_match_recursive(const char * pattern, const char * str, int * outScore,
44
+ const char * strBegin, uint8_t const * srcMatches, uint8_t * matches, int maxMatches,
45
+ int nextMatch, int * recursionCount, int recursionLimit);
46
+
47
+ static bool fts_fuzzy_match_simple(char const * pattern, char const * str, int * outScore) {
48
+ uint8_t matches[256];
49
+ return fts_fuzzy_match(pattern, str, outScore, matches, sizeof(matches));
50
+ }
51
+
52
+ static bool fts_fuzzy_match(char const * pattern, char const * str, int * outScore, uint8_t * matches, int maxMatches) {
53
+ int recursionCount = 0;
54
+ int recursionLimit = 10;
55
+
56
+ return fts_fuzzy_match_recursive(pattern, str, outScore, str, NULL, matches, maxMatches, 0, &recursionCount, recursionLimit);
57
+ }
58
+
59
+ // Private implementation
60
+ static bool fts_fuzzy_match_recursive(const char * pattern, const char * str, int * outScore,
61
+ const char * strBegin, uint8_t const * srcMatches, uint8_t * matches, int maxMatches,
62
+ int nextMatch, int * recursionCount, int recursionLimit)
63
+ {
64
+ // Count recursions
65
+ ++*recursionCount;
66
+ if (*recursionCount >= recursionLimit)
67
+ return false;
68
+
69
+ // Detect end of strings
70
+ if (*pattern == '\0' || *str == '\0')
71
+ return false;
72
+
73
+ unsigned long stringLength = strlen(str);
74
+
75
+ // Recursion params
76
+ bool recursiveMatch = false;
77
+ uint8_t bestRecursiveMatches[256];
78
+ int bestRecursiveScore = 0;
79
+
80
+ // Loop through pattern and str looking for a match
81
+ bool first_match = true;
82
+ while (*pattern != '\0' && *str != '\0') {
83
+
84
+ // Found match
85
+ if (tolower(*pattern) == tolower(*str)) {
86
+
87
+ // Supplied matches buffer was too short
88
+ if (nextMatch >= maxMatches)
89
+ return false;
90
+
91
+ // "Copy-on-Write" srcMatches into matches
92
+ if (first_match && srcMatches) {
93
+ memcpy(matches, srcMatches, nextMatch);
94
+ first_match = false;
95
+ }
96
+
97
+ // Recursive call that "skips" this match
98
+ uint8_t recursiveMatches[256];
99
+ int recursiveScore;
100
+ if (fts_fuzzy_match_recursive(pattern, str + 1, &recursiveScore, strBegin, matches, recursiveMatches, sizeof(recursiveMatches), nextMatch, recursionCount, recursionLimit)) {
101
+
102
+ // Pick best recursive score
103
+ if (!recursiveMatch || recursiveScore > bestRecursiveScore) {
104
+ memcpy(bestRecursiveMatches, recursiveMatches, 256);
105
+ bestRecursiveScore = recursiveScore;
106
+ }
107
+ recursiveMatch = true;
108
+ }
109
+
110
+ // Advance
111
+ matches[nextMatch++] = (uint8_t)(str - strBegin);
112
+ ++pattern;
113
+ }
114
+ ++str;
115
+ }
116
+
117
+ // Determine if full pattern was matched
118
+ bool matched = *pattern == '\0' ? true : false;
119
+
120
+ // Calculate score
121
+ if (matched) {
122
+ const int sequential_bonus = 20; // bonus for adjacent matches (DEFAULT: 15)
123
+ const int separator_bonus = 30; // bonus if match occurs after a separator
124
+ const int camel_bonus = 0; // bonus if match is uppercase and prev is lower (DEFAULT: 30)
125
+ const int first_letter_bonus = 15; // bonus if the first letter is matched
126
+
127
+ const int leading_letter_penalty = -5; // penalty applied for every letter in str before the first match
128
+ const int max_leading_letter_penalty = -15; // maximum penalty for leading letters
129
+ const int unmatched_letter_penalty = -1; // penalty for every letter that doesn't matter
130
+ const int string_length_penalty = -1; // (DEFAULT: 0)
131
+
132
+ // Iterate str to end
133
+ while (*str != '\0')
134
+ ++str;
135
+
136
+ // Initialize score
137
+ *outScore = 100;
138
+
139
+ // Apply length penalty
140
+ *outScore += stringLength * string_length_penalty;
141
+
142
+ // Apply leading letter penalty
143
+ int penalty = leading_letter_penalty * matches[0];
144
+ if (penalty < max_leading_letter_penalty)
145
+ penalty = max_leading_letter_penalty;
146
+ *outScore += penalty;
147
+
148
+ // Apply unmatched penalty
149
+ int unmatched = (int)(str - strBegin) - nextMatch;
150
+ *outScore += unmatched_letter_penalty * unmatched;
151
+
152
+ // Apply ordering bonuses
153
+ for (int i = 0; i < nextMatch; ++i) {
154
+ uint8_t currIdx = matches[i];
155
+
156
+ if (i > 0) {
157
+ uint8_t prevIdx = matches[i - 1];
158
+
159
+ // Sequential
160
+ if (currIdx == (prevIdx + 1))
161
+ *outScore += sequential_bonus;
162
+ }
163
+
164
+ // Check for bonuses based on neighbor character value
165
+ if (currIdx > 0) {
166
+ // Camel case
167
+ char neighbor = strBegin[currIdx - 1];
168
+ char curr = strBegin[currIdx];
169
+ if (islower(neighbor) && isupper(curr))
170
+ *outScore += camel_bonus;
171
+
172
+ // Separator
173
+ bool neighborSeparator = neighbor == '_' || neighbor == ' ';
174
+ if (neighborSeparator)
175
+ *outScore += separator_bonus;
176
+ }
177
+ else {
178
+ // First letter
179
+ *outScore += first_letter_bonus;
180
+ }
181
+ }
182
+ }
183
+
184
+ // Return best result
185
+ if (recursiveMatch && (!matched || bestRecursiveScore > *outScore)) {
186
+ // Recursive score is better than "this"
187
+ memcpy(matches, bestRecursiveMatches, maxMatches);
188
+ *outScore = bestRecursiveScore;
189
+ return true;
190
+ }
191
+ else if (matched) {
192
+ // "this" score is better than recursive
193
+ return true;
194
+ }
195
+ else {
196
+ // no match
197
+ return false;
198
+ }
199
+ }
200
+
201
+ #endif // FTS_FUZZY_MATCH_IMPLEMENTATION
202
+
203
+ #endif // FTS_FUZZY_MATCH_H
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/fts_fuzzy_match/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fts_fuzzy_match"
7
+ spec.version = FtsFuzzyMatch::VERSION
8
+ spec.authors = ["Dave Goddard"]
9
+ spec.email = ["dave@goddard.au"]
10
+
11
+ spec.summary = "Gem to use FTS for fuzzy matching."
12
+ spec.description = "Gem to use FTS for fuzzy matching."
13
+ spec.homepage = "https://github.com/dgodd/fuzzy_match"
14
+ spec.required_ruby_version = ">= 3.3.0"
15
+ spec.license = "MIT"
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+ spec.extensions = ["ext/fts_fuzzy_match/extconf.rb"]
26
+
27
+ # Uncomment to register a new dependency of your gem
28
+ # spec.add_dependency "example-gem", "~> 1.0"
29
+
30
+ # For more information and examples about making a new gem, checkout our
31
+ # guide at: https://bundler.io/guides/creating_gem.html
32
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FtsFuzzyMatch
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "fts_fuzzy_match/version"
4
+ require_relative "fts_fuzzy_match/fts_fuzzy_match"
5
+
6
+ # FTS Fuzzy Match module. Can score or sort
7
+ module FtsFuzzyMatch
8
+ class Error < StandardError; end
9
+
10
+ def self.sort_in_ruby(pattern, strings)
11
+ # fuzzy_match is -50..50 so -200 is the lowest possible score
12
+ strings.sort_by { |string| -1 * (::FtsFuzzyMatch::Extension.fuzzy_match(pattern, string) || -200) }
13
+ end
14
+
15
+ def self.sort_n(pattern, strings, n)
16
+ ::FtsFuzzyMatch::Extension.sort_n(pattern, strings, n)
17
+ end
18
+
19
+ def self.sort(pattern, strings)
20
+ ::FtsFuzzyMatch::Extension.sort_n(pattern, strings, strings.length)
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fts_fuzzy_match
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dave Goddard
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Gem to use FTS for fuzzy matching.
13
+ email:
14
+ - dave@goddard.au
15
+ executables: []
16
+ extensions:
17
+ - ext/fts_fuzzy_match/extconf.rb
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".github/dependabot.yml"
21
+ - ".github/workflows/fuzzy_match.yml"
22
+ - ".github/workflows/packaged_source.yml"
23
+ - ".github/workflows/packaged_tarball.yml"
24
+ - ".github/workflows/precompiled.yml"
25
+ - ".github/workflows/system.yml"
26
+ - ".gitignore"
27
+ - ".rubocop.yml"
28
+ - Gemfile
29
+ - Gemfile.lock
30
+ - README.md
31
+ - Rakefile
32
+ - ext/fts_fuzzy_match/extconf.rb
33
+ - ext/fts_fuzzy_match/fts_fuzzy_match.c
34
+ - ext/fts_fuzzy_match/fts_fuzzy_match.h
35
+ - ext/fts_fuzzy_match/fts_fuzzy_match_impl.h
36
+ - fts_fuzzy_match.gemspec
37
+ - lib/fts_fuzzy_match.rb
38
+ - lib/fts_fuzzy_match/version.rb
39
+ homepage: https://github.com/dgodd/fuzzy_match
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 3.3.0
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubygems_version: 3.6.9
58
+ specification_version: 4
59
+ summary: Gem to use FTS for fuzzy matching.
60
+ test_files: []