naughty_words 0.1.2 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d84f228f93cc6af5a7794aa4c42a56a45d1d8dd575982a687672cefa9991341
4
- data.tar.gz: d2a64141e31b2a293fceef6fc5c58e8fe0a150db75c7d3be7227da5415948427
3
+ metadata.gz: 19600db4679a9894f5cebde198af0a4162aaa602b618189fcf26ef90f3b6cf28
4
+ data.tar.gz: 34828a7a2036b0f8a959e0ff41b7e6615c18c4d5cef49bb210cea3d6ed7ba7d2
5
5
  SHA512:
6
- metadata.gz: eecf8555f6d2cfff3951c386caf6bdd428a0abaa9742ff552b773b33df938116553ffe859cbd2f365a332f428b6ce1be4743304512e948a668a474ce3d1ba1a1
7
- data.tar.gz: 9817e7590058a2691b606acaecab6bff48a3a7abdd97ae3d914a96d53bf69c3fc4e2a2d943d7704902b6f7428ffb599c5fa771b732d3903413395628287c8cfe
6
+ metadata.gz: 97bc17c0ca656cbacf740519d3d9761342ae5fea4a4ac7858f2e018367f086db320a793d52c2fc59f3406190a7494ed33b9cfb3a9ea30114d98710824c255d18
7
+ data.tar.gz: fdb7d5fc29a1d10fb621d6efe6fc663e4a19b07ff5c5136d7b36a617af83254ace06d8740b3f689d9cf8ab3fcb24b3bd400cd71ed89ad5242458177e7705285f
data/README.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # NaughtyWords
2
2
 
3
- A super basic gem to check if a string has profanites.
3
+ A Ruby gem for filtering profanity from text. Features include:
4
+ - Built-in deny and allow lists
5
+ - Database integration for custom word lists
6
+ - Runtime word overrides
7
+ - Word boundary matching (for checks)
8
+ - Case insensitive matching
9
+ - Optional severity-based filtering for DB deny words
4
10
 
5
11
  ## Installation
6
12
 
@@ -11,75 +17,264 @@ gem 'naughty_words'
11
17
  ```
12
18
 
13
19
  And then execute:
14
-
15
- $ bundle install
20
+ ```bash
21
+ bundle install
22
+ ```
16
23
 
17
24
  Or install it yourself as:
25
+ ```bash
26
+ gem install naughty_words
27
+ ```
28
+
29
+ ## Basic Usage
30
+
31
+ ```ruby
32
+ # Check if a string contains profanity
33
+ NaughtyWords.check(string: "hello world") # => false
34
+ NaughtyWords.check(string: "fuck this") # => true
35
+
36
+ # Filter profanity from a string
37
+ NaughtyWords.filter(string: "hello world") # => "hello world"
38
+ NaughtyWords.filter(string: "fuck this") # => "**** this"
39
+
40
+ # Use custom replacement character
41
+ NaughtyWords.filter(string: "fuck this", replacement: "@") # => "@@@@ this"
42
+ ```
18
43
 
19
- $ gem install naughty_words
44
+ ## Configuration
20
45
 
21
- ## Usage
46
+ Configure the gem's behavior:
22
47
 
23
- **Check if a string includes a profanity**
24
- The `check` method takes in a `string:` argument and will return a boolean.
25
48
  ```ruby
26
- NaughtyWords.check(string: "ass")
27
- => true
49
+ NaughtyWords.configure do |config|
50
+ # Match whole words only (default: true)
51
+ # When true: "fuck" matches "fuck" but not "fuckthis"
52
+ # When false: "fuck" matches both "fuck" and "fuckthis"
53
+ config.word_boundaries = true
28
54
 
29
- NaughtyWords.check(string: "hello world")
30
- => false
55
+ # Use built-in word lists (default: true)
56
+ # Set to false to use only database or runtime overrides
57
+ config.use_built_in_lists = true
31
58
 
32
- NaughtyWords.check(string: "hello asshole")
33
- => true
59
+ # Only consider DB deny words at or above this severity (optional)
60
+ # One of: "high", "medium", "low". nil means all severities.
61
+ config.minimum_severity = nil
62
+ end
63
+
64
+ # For tests or to return to defaults
65
+ NaughtyWords::Config.reset!
34
66
  ```
35
67
 
36
- **Filter out words**
37
- The `filter` method takes a `string:` argument and an optional `replacement:` argument.
68
+ ## Database Integration
69
+
70
+ The gem can use a database (ActiveRecord) to store custom word lists.
38
71
 
39
- ``` ruby
40
- # passing a string with no profanity will return the string
41
- NaughtyWords.filter(string: "hello world")
42
- => "hello world"
43
-
44
- # passing a string with profanities will return the string with the profanity filtered out
45
- NaughtyWords.filter(string: "hello asshole")
46
- => "hello *******"
47
-
48
- # you can use in your own filter character by passing it in as an argument ("*" is by default)
49
- NaughtyWords.filter(string: "hello asshole", replacement: "!")
50
- => "hello !!!!!!!"
72
+ 1) Install migration, model, and initializer (recommended):
73
+ ```bash
74
+ rails generate naughty_words:install
51
75
  ```
52
76
 
53
- Note: Current, this is comically easy to circumvent. String like "shitshitshit" will only filter out the first match, returning "*****shitshit". A fix is enroute.
77
+ This adds:
78
+ - db/migrate/create_naughty_words_lists.rb
79
+ - app/models/naughty_words/word_list.rb
80
+ - config/initializers/naughty_words.rb
54
81
 
55
- ### Validating in Rails example
56
- We can use a custom validator in our User model to make sure a user cannot sign up with a username containing profanities in tandem with our normal `validates` methods.
82
+ 2) Add optional columns if you need them
83
+
84
+ If you plan to use `category`, `severity` ("high" | "medium" | "low"), or `metadata` (JSON), add these columns to your migration before running it. Example:
57
85
 
58
86
  ```ruby
59
- # app/models/user.rb
87
+ change_table :naughty_words_lists do |t|
88
+ t.string :category # optional
89
+ t.string :severity # optional, one of "high", "medium", "low"
90
+ t.json :metadata, default: {} # optional
91
+ end
92
+ ```
60
93
 
61
- validates :username, uniqueness: true, presence: true # basic username validation
62
- validate :username_profanity_check # our custom validator
94
+ Then run:
95
+ ```bash
96
+ rails db:migrate
97
+ ```
63
98
 
64
- ...
99
+ 3) Add words to your lists:
100
+ ```ruby
101
+ # Basic usage
102
+ NaughtyWords::WordList.create!(word: "badword", list_type: "deny")
103
+ NaughtyWords::WordList.create!(word: "scunthorpe", list_type: "allow")
65
104
 
66
- def username_profanity_check
67
- errors.add(:username, "contains profanity") if NaughtyWords.check(string: username)
68
- end
105
+ # With optional metadata (requires columns above)
106
+ NaughtyWords::WordList.create!(
107
+ word: "badword",
108
+ list_type: "deny",
109
+ context: "Added due to user complaints",
110
+ added_by: "john@example.com",
111
+ severity: "high",
112
+ category: "insults",
113
+ metadata: { reported_by: "forum_moderator" }
114
+ )
115
+ ```
116
+
117
+ 4) View your lists:
118
+ ```ruby
119
+ # Get just the words
120
+ NaughtyWords.show_list(list: "deny")
121
+ # => ["badword", "otherbadword", ...]
122
+
123
+ # Get full records with metadata
124
+ records = NaughtyWords.show_list(list: "deny", include_metadata: true)
125
+ records.first
126
+ # => #<NaughtyWords::WordList ... word: "badword", list_type: "deny", ...>
127
+
128
+ # Query with metadata (if you use it)
129
+ words = NaughtyWords::WordList.where(list_type: "deny")
130
+ .where(added_by: "john@example.com")
131
+ .where("metadata->>'category' = ?", "insults")
132
+ ```
133
+
134
+ ### View only the built-in default lists
135
+
136
+ If you want to see the gem's built-in lists (ignoring anything in your database):
137
+
138
+ ```ruby
139
+ # Ensure built-ins are enabled (default: true)
140
+ NaughtyWords::Config.use_built_in_lists = true
141
+
142
+ # If you have no DB entries, this already shows the built-ins
143
+ NaughtyWords.show_list(list: "deny") # => built-in deny words
144
+ NaughtyWords.show_list(list: "allow") # => built-in allow words
145
+
146
+ # If you DO have DB entries and want to isolate the built-ins only:
147
+ built_in_deny = NaughtyWords.show_list(list: "deny") - NaughtyWords::WordList.deny_list.pluck(:word)
148
+ built_in_allow = NaughtyWords.show_list(list: "allow") - NaughtyWords::WordList.allow_list.pluck(:word)
149
+
150
+ built_in_deny.first(10)
151
+ ```
152
+
153
+ 5) Severity-based checks from DB (optional)
154
+ ```ruby
155
+ # Only consider DB deny words at or above "medium"
156
+ NaughtyWords.configure { |c| c.minimum_severity = "medium" }
157
+
158
+ # Or query explicitly via scopes
159
+ NaughtyWords::WordList.by_severity("high").pluck(:word)
160
+ NaughtyWords::WordList.by_severity("high").by_category("insults").pluck(:word)
161
+ ```
162
+
163
+ If you don't install the DB table, the gem will work using only the built-in lists.
164
+
165
+ ## Runtime Overrides
166
+
167
+ Override word lists temporarily during runtime:
168
+
169
+ ```ruby
170
+ # Allow a word that's normally blocked
171
+ NaughtyWords::Config.allow_word("someword")
172
+
173
+ # Block a word that's normally allowed
174
+ NaughtyWords::Config.deny_word("otherword")
175
+
176
+ # Remove an override
177
+ NaughtyWords::Config.remove_override("someword")
178
+ ```
179
+
180
+ Overrides:
181
+ - Take precedence over both built-in lists and database lists
182
+ - Are case insensitive
183
+ - Reset when your application restarts
184
+ - Perfect for testing or temporary customizations
185
+
186
+ ## How It Works
187
+
188
+ 1) When checking/filtering text:
189
+ - First checks runtime overrides
190
+ - Then checks built-in lists (if enabled)
191
+ - Then checks database lists (if present)
192
+
193
+ 2) Word matching is:
194
+ - Always case insensitive
195
+ - Configurable for word boundaries (affects checks)
196
+ - Handles special characters and spaces
197
+
198
+ 3) Priority order:
199
+ 1. Runtime overrides (highest)
200
+ 2. Built-in lists
201
+ 3. Database lists (lowest)
202
+
203
+ 4) Filtering details:
204
+ - Replacement proceeds longest-to-shortest denied words.
205
+ - Filtering masks any occurrence of denied words (case-insensitive), regardless of `word_boundaries`.
206
+ - Example: with boundaries on, `check` may pass for “scunthorpe”, but if “cunt” is denied, `filter` will still mask “cunt” inside “scunthorpe”.
207
+
208
+ ## Default list philosophy
209
+
210
+ The built-in deny list is intentionally minimal and neutral by default.
211
+
212
+ - Focuses on single-word profanities and slurs only
213
+ - Avoids medical/sexual terms and general sexual content
214
+ - Avoids multi-word phrases and “moral policing”
215
+
216
+ Customize to your community via the database layer:
217
+ - Add phrases (e.g., “eat my ass”) to `naughty_words_lists` with `category`/`severity`
218
+ - Use `minimum_severity` to tune strictness globally
219
+ - Use runtime overrides for temporary exceptions
220
+
221
+ ## Examples
222
+
223
+ ### Basic Filtering
224
+ ```ruby
225
+ # Simple profanity check
226
+ NaughtyWords.check(string: "hello world") # => false
227
+ NaughtyWords.check(string: "fuck this") # => true
228
+
229
+ # Filter with default replacement (*)
230
+ NaughtyWords.filter(string: "fuck this") # => "**** this"
231
+
232
+ # Custom replacement character
233
+ NaughtyWords.filter(string: "fuck this", replacement: "@") # => "@@@@ this"
234
+ ```
235
+
236
+ ### Word Boundaries
237
+ ```ruby
238
+ # With word_boundaries = true (default)
239
+ NaughtyWords.check(string: "fuck") # => true
240
+ NaughtyWords.check(string: "fuckthis") # => false
241
+
242
+ # With word_boundaries = false
243
+ NaughtyWords.configure { |c| c.word_boundaries = false }
244
+ NaughtyWords.check(string: "fuckthis") # => true
69
245
  ```
70
246
 
71
- ## Development
247
+ ### Database Integration
248
+ ```ruby
249
+ # Add custom words
250
+ NaughtyWords::WordList.create!(word: "badword", list_type: "deny")
251
+ NaughtyWords::WordList.create!(word: "goodword", list_type: "allow")
252
+
253
+ # View lists with metadata
254
+ NaughtyWords.show_list(list: "deny", include_metadata: true)
255
+ # => [#<NaughtyWords::WordList id: 1, word: "badword", list_type: "deny", created_at: ...>]
256
+ ```
257
+
258
+ ### Runtime Overrides
259
+ ```ruby
260
+ # Override the built-in lists
261
+ NaughtyWords::Config.allow_word("fuck") # Allow this word
262
+ NaughtyWords.check(string: "fuck") # => false
72
263
 
73
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
264
+ # Multiple overrides
265
+ NaughtyWords::Config.allow_word("fuck")
266
+ NaughtyWords::Config.allow_word("shit")
267
+ NaughtyWords.filter(string: "fuck this shit") # => "fuck this shit"
268
+
269
+ # Remove overrides
270
+ NaughtyWords::Config.remove_override("fuck")
271
+ NaughtyWords.check(string: "fuck") # => true (back to default)
272
+ ```
74
273
 
75
274
  ## Contributing
76
275
 
77
- Bug reports and pull requests are welcome on GitHub at https://github.com/jaarnie/naughty_words. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/jaarnie/naughty_words/blob/master/CODE_OF_CONDUCT.md).
276
+ Bug reports and pull requests are welcome on GitHub at `https://github.com/jaarnie/naughty_words`.
78
277
 
79
278
  ## License
80
279
 
81
280
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
82
-
83
- ## Code of Conduct
84
-
85
- Everyone interacting in the NaughtyWords project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/naughty_words/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,32 @@
1
+
2
+ # frozen_string_literal: true
3
+
4
+ module NaughtyWords
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+
9
+ source_root File.expand_path("templates", __dir__)
10
+
11
+ def self.next_migration_number(path)
12
+ next_migration_number = current_migration_number(path) + 1
13
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
14
+ end
15
+
16
+ def copy_migrations
17
+ migration_template(
18
+ "create_naughty_words_lists.rb",
19
+ "db/migrate/create_naughty_words_lists.rb"
20
+ )
21
+ end
22
+
23
+ def copy_models
24
+ template "word_list.rb", "app/models/naughty_words/word_list.rb"
25
+ end
26
+
27
+ def copy_initializer
28
+ template "initializer.rb", "config/initializers/naughty_words.rb"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateNaughtyWordsLists < ActiveRecord::Migration[7.0]
4
+ def change
5
+ create_table :naughty_words_lists do |t|
6
+ t.string :word, null: false
7
+ t.string :list_type, null: false # 'deny' or 'allow'
8
+ t.string :category
9
+ t.string :severity # "high" | "medium" | "low"
10
+ t.text :context
11
+ t.string :added_by
12
+ t.json :metadata, default: {}
13
+ t.timestamps
14
+
15
+ t.index [:word, :list_type], unique: true
16
+ t.index :category
17
+ t.index :severity
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ NaughtyWords.configure do |config|
4
+ # Match whole words only (default: true). Set false to allow substrings.
5
+ config.word_boundaries = true
6
+
7
+ # Include built-in allow/deny lists (default: true).
8
+ config.use_built_in_lists = true
9
+
10
+ # Optional: only consider DB deny words at or above this severity.
11
+ # One of: "high", "medium", "low"; nil means all severities.
12
+ config.minimum_severity = nil
13
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NaughtyWords
4
+ class WordList < ActiveRecord::Base
5
+ self.table_name = "naughty_words_lists"
6
+
7
+ validates :word, presence: true
8
+ validates :list_type, presence: true, inclusion: { in: %w[deny allow] }
9
+ validates :word, uniqueness: { scope: :list_type }
10
+ validates :severity, inclusion: { in: %w[high medium low], allow_nil: true }
11
+
12
+ scope :deny_list, -> { where(list_type: "deny") }
13
+ scope :allow_list, -> { where(list_type: "allow") }
14
+ scope :by_category, ->(category) { where(category: category) }
15
+ scope :by_severity, ->(severity) { where(severity: severity) }
16
+ scope :added_by, ->(user) { where(added_by: user) }
17
+
18
+ before_save :normalize_word
19
+
20
+ private
21
+
22
+ def normalize_word
23
+ self.word = word.strip.downcase if word.present?
24
+ end
25
+ end
26
+ end
@@ -1,56 +1,160 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "config"
4
+
3
5
  module NaughtyWords
4
6
  class Base
5
7
  class << self
6
8
  def profanity?(string:)
7
- allow_list_array.each do |line|
8
- return false if string.include?(line)
9
+ validate_input!(string)
10
+ normalized_string = normalize_string(string)
11
+
12
+ return false if word_in_list?(normalized_string, Config.allow_overrides)
13
+ return true if word_in_list?(normalized_string, Config.deny_overrides)
14
+
15
+ return false if Config.use_built_in_lists && word_in_list?(normalized_string, allow_list_from_files)
16
+ return false if word_in_list?(normalized_string, allow_list_from_db)
17
+
18
+ return true if Config.use_built_in_lists && word_in_list?(normalized_string, deny_list_from_files)
19
+ return true if word_in_list?(normalized_string, deny_list_from_db)
20
+
21
+ false
22
+ end
23
+
24
+ def filter(string:, replacement: "*")
25
+ validate_input!(string)
26
+ validate_replacement!(replacement)
27
+ result = string.dup
28
+
29
+ denied_words = Config.deny_overrides.dup
30
+ denied_words += deny_list_from_files if Config.use_built_in_lists
31
+ denied_words += deny_list_from_db
32
+ denied_words -= Config.allow_overrides # Remove any allowed overrides
33
+ denied_words = denied_words.sort_by(&:length).reverse
34
+
35
+ denied_words.each do |word|
36
+ next if word.empty?
37
+ result.gsub!(/#{Regexp.escape(word)}/i, replacement * word.length)
9
38
  end
10
39
 
11
- deny_list_array.each do |line|
12
- return true if string.include?(line)
40
+ result
41
+ end
42
+
43
+ def show_list(list:, include_metadata: false)
44
+ validate_list!(list)
45
+
46
+ if include_metadata && defined?(WordList)
47
+ WordList.where(list_type: list)
48
+ else
49
+ words = []
50
+ words += (list == "deny" ? deny_list_from_files : allow_list_from_files) if Config.use_built_in_lists
51
+ words += (list == "deny" ? deny_list_from_db : allow_list_from_db)
52
+ words
13
53
  end
54
+ end
14
55
 
15
- false
56
+ private
57
+
58
+ def deny_list_from_files
59
+ @deny_list_from_files ||= load_list(deny_list_path)
60
+ end
61
+
62
+ def allow_list_from_files
63
+ @allow_list_from_files ||= load_list(allow_list_path)
16
64
  end
17
65
 
18
- def filter(string:, replacement:)
19
- # TODO: Fix filtering full words ending with 'ing' and repeated words such as 'fuckfuckfuck'
20
- deny_list_array.each do |line|
21
- word = line
22
- string.gsub!(word, replacement * word.length)
66
+ def deny_list_from_db
67
+ return [] unless db_table_available?
68
+ query = WordList.deny_list
69
+
70
+ if Config.minimum_severity
71
+ severities = %w[high medium low]
72
+ min_index = severities.index(Config.minimum_severity)
73
+ return [] unless min_index
74
+ allowed_severities = severities[0..min_index]
75
+ query = query.where(severity: allowed_severities)
23
76
  end
24
77
 
25
- string
78
+ query.pluck(:word)
79
+ rescue StandardError
80
+ []
81
+ end
82
+
83
+ def allow_list_from_db
84
+ return [] unless db_table_available?
85
+ WordList.allow_list.pluck(:word)
86
+ rescue StandardError
87
+ []
88
+ end
89
+
90
+ def deny_list_path
91
+ File.join(File.dirname(File.expand_path(__FILE__)), "config/deny_list.txt")
92
+ end
93
+
94
+ def allow_list_path
95
+ File.join(File.dirname(File.expand_path(__FILE__)), "config/allow_list.txt")
96
+ end
97
+
98
+ def load_list(path)
99
+ return [] unless Config.use_built_in_lists
100
+ File.readlines(path, chomp: true).reject(&:empty?)
101
+ rescue Errno::ENOENT
102
+ raise Error, "List file not found: #{path}"
103
+ rescue IOError => e
104
+ raise Error, "Failed to read list: #{e.message}"
26
105
  end
27
106
 
28
- def add_to_list(list:, string:)
29
- File.open(send(list), "a+") do |file|
30
- file.puts(string)
107
+ def word_in_list?(string, list)
108
+ list.any? do |word|
109
+ normalized_word = normalize_string(word)
110
+ word_match?(string, normalized_word)
31
111
  end
32
112
  end
33
113
 
34
- def show_list(list:)
35
- if list == "deny"
36
- deny_list_array
114
+ def normalize_string(str)
115
+ str.downcase
116
+ end
117
+
118
+ def word_pattern(word)
119
+ escaped = Regexp.escape(word)
120
+ if Config.word_boundaries
121
+ /(?:^|[^a-zA-Z0-9])#{escaped}(?:$|[^a-zA-Z0-9])/i
37
122
  else
38
- allow_list_array
123
+ /#{escaped}/i
39
124
  end
40
125
  end
41
126
 
42
- private
127
+ def word_match?(string, word)
128
+ pattern = Config.word_boundaries ?
129
+ /(?:^|[^a-zA-Z0-9])#{Regexp.escape(word)}(?:$|[^a-zA-Z0-9])/i :
130
+ /#{Regexp.escape(word)}/i
131
+ string.match?(pattern)
132
+ end
43
133
 
44
- def deny_list_array
45
- file = File.open(File.join(File.dirname(File.expand_path(__FILE__)), "config/deny_list.txt"))
134
+ def validate_input!(string)
135
+ raise ArgumentError, "Input string cannot be nil" if string.nil?
136
+ raise ArgumentError, "Input string must be a String" unless string.is_a?(String)
137
+ end
46
138
 
47
- @deny_list_array ||= File.readlines(file, chomp: true)
139
+ def validate_replacement!(replacement)
140
+ raise ArgumentError, "Replacement cannot be nil" if replacement.nil?
141
+ raise ArgumentError, "Replacement must be a String" unless replacement.is_a?(String)
142
+ raise ArgumentError, "Replacement cannot be empty" if replacement.empty?
48
143
  end
49
144
 
50
- def allow_list_array
51
- file = File.open(File.join(File.dirname(File.expand_path(__FILE__)), "config/allow_list.txt"))
145
+ def validate_list!(list)
146
+ valid_lists = ["deny", "allow"]
147
+ unless valid_lists.include?(list)
148
+ raise ArgumentError, "Invalid list type. Must be one of: #{valid_lists.join(', ')}"
149
+ end
150
+ end
52
151
 
53
- @allow_list_array ||= File.readlines(file, chomp: true)
152
+ def db_table_available?
153
+ return false unless defined?(WordList) && defined?(ActiveRecord::Base)
154
+ conn = ActiveRecord::Base.connection
155
+ conn.data_source_exists?(WordList.table_name)
156
+ rescue StandardError
157
+ false
54
158
  end
55
159
  end
56
160
  end