fu-fu 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ /coverage
2
+ coverage.data
3
+ /test/*.sqlite*
4
+ /test/*.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in fu-fu.gemspec
4
+ gemspec
@@ -0,0 +1,14 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fu-fu (0.1.0)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+
10
+ PLATFORMS
11
+ ruby
12
+
13
+ DEPENDENCIES
14
+ fu-fu!
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Adam Bair and Intridea, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,81 @@
1
+ = Fu-fu: The Profanity Filter for Rails
2
+
3
+ This plugin will allow you to filter profanity using basic replacement or a dictionary term.
4
+
5
+ == Disclaimer
6
+
7
+ This plugin is provided as is - therefore, the creators and contributors of this plugin are not responsible for any damages that may result from it's usage. Use at your own risk; backup your data.
8
+
9
+ == Install
10
+
11
+ ./script/plugin install git://github.com/adambair/fu-fu.git
12
+
13
+ == Example
14
+
15
+ === You can use it in your models:
16
+
17
+ Notice -- there are two profanity filters, one is destructive. Beware the exclamation point (profanity_filter!).
18
+
19
+ Non-Destructive (filters content when called, original text remains in the database)
20
+
21
+ profanity_filter :foo, :bar
22
+ #=> banned words will be replaced with @#=>$%
23
+
24
+ profanity_filter :foo, :bar, :method => 'dictionary'
25
+ #=> banned words will be replaced by value in config/dictionary.yml
26
+
27
+ profanity_filter :foo, :bar, :method => 'vowels'
28
+ #=> banned words will have their vowels replaced
29
+
30
+ profanity_filter :foo, :bar, :method => 'hollow'
31
+ #=> all letters except the first and last will be replaced
32
+
33
+ The non-destructive profanity_filter provides different versions of the filtered attribute:
34
+ some_model.foo => 'filtered version'
35
+ some_model.foo_original => 'non-filtered version'
36
+
37
+ Destructive (saves the filtered content to the database)
38
+
39
+ profanity_filter! :foo, :bar
40
+ #=> banned words will be replaced with @#=>$%
41
+
42
+ profanity_filter! :foo, :bar, :method => 'dictionary'
43
+ #=> banned words will be replaced by value in config/dictionary.yml
44
+
45
+ profanity_filter! :foo, :bar, :method => 'vowels'
46
+ #=> banned words will have their vowels replaced
47
+
48
+ profanity_filter! :foo, :bar, :method => 'hollow'
49
+ #=> all letters except the first and last will be replaced
50
+
51
+ === You can also use the filter directly:
52
+
53
+ ProfanityFilter::Base.clean(text)
54
+ ProfanityFilter::Base.clean(text, 'dictionary')
55
+ ProfanityFilter::Base.clean(text, 'vowels')
56
+ ProfanityFilter::Base.clean(text, 'hollow')
57
+
58
+ ProfanityFilter::Base.profane?(text) #=> true/false
59
+
60
+ == Benchmarks
61
+
62
+ Inquiring minds can checkout the simple benchmarks I've included so you can have an idea of what kind of performance to expect. I've included some quick scenarios including strings of (100, 1000, 5000, 1000) words and dictionaries of (100, 1000, 5000, 25000, 50000, 100000) words.
63
+
64
+ You can run the benchmarks via:
65
+ ruby test/benchmark/fu-fu_benchmark.rb
66
+
67
+ == TODO
68
+
69
+ * Turn this into a gem
70
+ * May break ProfanityFilter out on it's own
71
+ * Clean up dictionary implementation and substitution (suboptimal and messy)
72
+ * Move benchmarks into a rake task
73
+ * Build out rdocs
74
+
75
+ == License
76
+
77
+ Fu-fu: The Profanity Filter for Rails uses the MIT License. Please see the MIT-LICENSE file.
78
+
79
+ == Resources
80
+
81
+ Created by Adam Bair (adam@intridea.com) of Intridea (http://www.intridea.com) in the open source room at RailsConf 2008.
@@ -0,0 +1,33 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ # require 'rake/rdoctask'
6
+ #
7
+ # desc 'Default: run unit tests.'
8
+ # task :default => :test
9
+ #
10
+ desc 'Test the Profanity Filter plugin.'
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << 'lib'
13
+ t.pattern = 'test/**/*_test.rb'
14
+ t.verbose = true
15
+ end
16
+ #
17
+ # desc 'Generate documentation for the happy plugin.'
18
+ # Rake::RDocTask.new(:rdoc) do |rdoc|
19
+ # rdoc.rdoc_dir = 'rdoc'
20
+ # rdoc.title = 'Profanity Filter'
21
+ # rdoc.options << '--line-numbers' << '--inline-source'
22
+ # rdoc.rdoc_files.include('README')
23
+ # rdoc.rdoc_files.include('lib/**/*.rb')
24
+ # end
25
+ #
26
+ # desc 'Measures test coverage using rcov'
27
+ # task :rcov do
28
+ # rm_f "coverage"
29
+ # rm_f "coverage.data"
30
+ # rcov = "rcov --rails --aggregate coverage.data --text-summary -Ilib"
31
+ # system("#{rcov} --html #{Dir.glob('test/**/*_test.rb').join(' ')}")
32
+ # system("open coverage/index.html") if PLATFORM['darwin']
33
+ # end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "fu-fu/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "fu-fu"
7
+ s.version = Fu::Fu::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Adam Bair", "Stefano B."]
10
+ s.email = ["stefano@challengepost.com"]
11
+ s.homepage = "https://github.com/adambair/fu-fu"
12
+ s.summary = %q{Gem version of Adam Bair's profanity filter plugin'}
13
+ s.description = %q{Fu-fu: The Profanity Filter for Rails.}
14
+
15
+ s.rubyforge_project = "fu-fu"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- test/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ end
@@ -0,0 +1,3 @@
1
+ require 'fu-fu/profanity_filter'
2
+
3
+ ActiveRecord::Base.send(:include, ProfanityFilter)
@@ -0,0 +1,200 @@
1
+ # the filter currently checks for words that are 3 or more characters.
2
+ ---
3
+ ass: "*ss"
4
+ asses: "*ss*s"
5
+ asshole: "*ssh*l*"
6
+ assholes: "*ssh*l*s"
7
+ bastard: b*st*rd
8
+ beastial: b**st**l
9
+ beastiality: b**st**l*ty
10
+ beastility: b**st*l*ty
11
+ bestial: b*st**l
12
+ bestiality: b*st**l*ty
13
+ bitch: b*tch
14
+ bitcher: b*tch*r
15
+ bitchers: b*tch*rs
16
+ bitches: b*tch*s
17
+ bitchin: b*tch*n
18
+ bitching: b*tch*ng
19
+ blowjob: bl*wj*b
20
+ blowjobs: bl*wj*bs
21
+ bullshit: b*llsh*t
22
+ clit: cl*t
23
+ cock: c*ck
24
+ cocks: c*cks
25
+ cocksuck: c*cks*ck
26
+ cocksucked: c*cks*ck*d
27
+ cocksucker: c*cks*ck*r
28
+ cocksucking: c*cks*ck*ng
29
+ cocksucks: c*cks*cks
30
+ cum: c*m
31
+ cummer: c*mm*r
32
+ cumming: c*mm*ng
33
+ cums: c*ms
34
+ cumshot: c*msh*t
35
+ cunillingus: c*n*ll*ng*s
36
+ cunnilingus: c*nn*l*ng*s
37
+ cunt: c*nt
38
+ cuntlick: c*ntl*ck
39
+ cuntlicker: c*ntl*ck*r
40
+ cuntlicking: c*ntl*ck*ng
41
+ cunts: c*nts
42
+ cyberfuc: cyb*rf*c
43
+ cyberfuck: cyb*rf*ck
44
+ cyberfucked: cyb*rf*ck*d
45
+ cyberfucker: cyb*rf*ck*r
46
+ cyberfuckers: cyb*rf*ck*rs
47
+ cyberfucking: cyb*rf*ck*ng
48
+ damn: d*mn
49
+ dildo: d*ld*
50
+ dildos: d*ld*s
51
+ dick: d*ck
52
+ dink: d*nk
53
+ dinks: d*nks
54
+ ejaculate: "*j*c*l*t*"
55
+ ejaculated: "*j*c*l*t*d"
56
+ ejaculates: "*j*c*l*t*s"
57
+ ejaculating: "*j*c*l*t*ng"
58
+ ejaculatings: "*j*c*l*t*ngs"
59
+ ejaculation: "*j*c*l*t**n"
60
+ fag: f*g
61
+ fagging: f*gg*ng
62
+ faggot: f*gg*t
63
+ faggs: f*ggs
64
+ fagot: f*g*t
65
+ fagots: f*g*ts
66
+ fags: f*gs
67
+ fart: f*rt
68
+ farted: f*rt*d
69
+ farting: f*rt*ng
70
+ fartings: f*rt*ngs
71
+ farts: f*rts
72
+ farty: f*rty
73
+ felatio: f*l*t**
74
+ fellatio: f*ll*t**
75
+ fingerfuck: f*ng*rf*ck
76
+ fingerfucked: f*ng*rf*ck*d
77
+ fingerfucker: f*ng*rf*ck*r
78
+ fingerfuckers: f*ng*rf*ck*rs
79
+ fingerfucking: f*ng*rf*ck*ng
80
+ fingerfucks: f*ng*rf*cks
81
+ fistfuck: f*stf*ck
82
+ fistfucked: f*stf*ck*d
83
+ fistfucker: f*stf*ck*r
84
+ fistfuckers: f*stf*ck*rs
85
+ fistfucking: f*stf*ck*ng
86
+ fistfuckings: f*stf*ck*ngs
87
+ fistfucks: f*stf*cks
88
+ fuck: f*ck
89
+ fucked: f*ck*d
90
+ fucker: f*ck*r
91
+ fuckers: f*ck*rs
92
+ fuckin: f*ck*n
93
+ fucking: f*ck*ng
94
+ fuckings: f*ck*ngs
95
+ fuckme: f*ckm*
96
+ fucks: f*cks
97
+ fuk: f*k
98
+ fuks: f*ks
99
+ gangbang: g*ngb*ng
100
+ gangbanged: g*ngb*ng*d
101
+ gangbangs: g*ngb*ngs
102
+ gaysex: g*ys*x
103
+ goddamn: g*dd*mn
104
+ hardcoresex: h*rdc*r*s*x
105
+ hell: h*ll
106
+ horniest: h*rn**st
107
+ horny: h*rny
108
+ hotsex: h*ts*x
109
+ jism: j*sm
110
+ jiz: j*z
111
+ jizm: j*zm
112
+ kock: k*ck
113
+ kondum: k*nd*m
114
+ kondums: k*nd*ms
115
+ kum: k*m
116
+ kumer: k*mm*r
117
+ kummer: k*mm*r
118
+ kumming: k*mm*ng
119
+ kums: k*ms
120
+ kunilingus: k*n*l*ng*s
121
+ lust: l*st
122
+ lusting: l*st*ng
123
+ mothafuck: m*th*f*ck
124
+ mothafucka: m*th*f*ck*
125
+ mothafuckas: m*th*f*ck*s
126
+ mothafuckaz: m*th*f*ck*z
127
+ mothafucked: m*th*f*ck*d
128
+ mothafucker: m*th*f*ck*r
129
+ mothafuckers: m*th*f*ck*rs
130
+ mothafuckin: m*th*f*ck*n
131
+ mothafucking: m*th*f*ck*ng
132
+ mothafuckings: m*th*f*ck*ngs
133
+ mothafucks: m*th*f*cks
134
+ motherfuck: m*th*rf*ck
135
+ motherfucked: m*th*rf*ck*d
136
+ motherfucker: m*th*rf*ck*r
137
+ motherfuckers: m*th*rf*ck*rs
138
+ motherfuckin: m*th*rf*ck*n
139
+ motherfucking: m*th*rf*ck*ng
140
+ motherfuckings: m*th*rf*ck*ngs
141
+ motherfucks: m*th*rf*cks
142
+ niger: n*gg*r
143
+ nigger: n*gg*r
144
+ niggers: n*gg*rs
145
+ orgasim: "*rg*s*m"
146
+ orgasims: "*rg*s*ms"
147
+ orgasm: "*rg*sm"
148
+ orgasms: "*rg*sms"
149
+ phonesex: ph*n*s*x
150
+ phuk: ph*k
151
+ phuked: ph*k*d
152
+ phuking: ph*k*ng
153
+ phukked: ph*kk*d
154
+ phukking: ph*kk*ng
155
+ phuks: ph*ks
156
+ phuq: ph*q
157
+ pis: p*ss
158
+ piss: p*ss
159
+ pisser: p*ss*r
160
+ pissed: p*ss*d
161
+ pisser: p*ss*r
162
+ pissers: p*ss*rs
163
+ pises: p*ss*s
164
+ pisses: p*ss*s
165
+ pisin: p*ss*n
166
+ pissin: p*ss*n
167
+ pising: p*ss*ng
168
+ pissing: p*ss*ng
169
+ pisof: p*ss*ff
170
+ pissoff: p*ss*ff
171
+ porn: p*rn
172
+ porno: p*rn*
173
+ pornography: p*rn*gr*phy
174
+ pornos: p*rn*s
175
+ prick: pr*ck
176
+ pricks: pr*cks
177
+ pussies: p*ss**s
178
+ pusies: p*ss**s
179
+ pussy: p*ssy
180
+ pusy: p*ssy
181
+ pussys: p*ssys
182
+ pusys: p*ssys
183
+ shit: sh*t
184
+ shited: sh*t*d
185
+ shitfull: sh*tf*ll
186
+ shiting: sh*t*ng
187
+ shitings: sh*t*ngs
188
+ shits: sh*ts
189
+ shitted: sh*tt*d
190
+ shitter: sh*tt*r
191
+ shitters: sh*tt*rs
192
+ shitting: sh*tt*ng
193
+ shittings: sh*tt*ngs
194
+ shitty: sh*tty
195
+ shity: sh*tty
196
+ slut: sl*t
197
+ sluts: sl*ts
198
+ smut: sm*t
199
+ spunk: sp*nk
200
+ twat: tw*t
@@ -0,0 +1,79 @@
1
+ module ProfanityFilter
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+
6
+ module ClassMethods
7
+ def profanity_filter!(*attr_names)
8
+ option = attr_names.pop[:method] if attr_names.last.is_a?(Hash)
9
+ attr_names.each { |attr_name| setup_callbacks_for(attr_name, option) }
10
+ end
11
+
12
+ def profanity_filter(*attr_names)
13
+ option = attr_names.pop[:method] if attr_names.last.is_a?(Hash)
14
+
15
+ attr_names.each do |attr_name|
16
+ instance_eval do
17
+ define_method "#{attr_name}_clean" do; ProfanityFilter::Base.clean(self[attr_name.to_sym], option); end
18
+ define_method "#{attr_name}_original"do; self[attr_name]; end
19
+ alias_method attr_name.to_sym, "#{attr_name}_clean".to_sym
20
+ end
21
+ end
22
+ end
23
+
24
+ def setup_callbacks_for(attr_name, option)
25
+ before_validation do |record|
26
+ record[attr_name.to_sym] = ProfanityFilter::Base.clean(record[attr_name.to_sym], option)
27
+ end
28
+ end
29
+ end
30
+
31
+ class Base
32
+ cattr_accessor :replacement_text, :dictionary_file, :dictionary
33
+ @@replacement_text = '@#$%'
34
+ @@dictionary_file = File.join(File.dirname(__FILE__), 'config/dictionary.yml')
35
+ @@dictionary = YAML.load_file(@@dictionary_file)
36
+
37
+ class << self
38
+ def profane?(text, replace_method='')
39
+ text != clean(text, replace_method)
40
+ end
41
+
42
+ def clean(text, replace_method = '')
43
+ return text if text.blank?
44
+ @replace_method = replace_method
45
+ text.split(/(\s)/).collect{ |word| clean_word(word) }.join
46
+ end
47
+
48
+ def clean_word(word)
49
+ return word unless(word.strip.size > 2)
50
+
51
+ if word.index(/[\W]/)
52
+ word = word.split(/(\W)/).collect{ |subword| clean_word(subword) }.join
53
+ concat = word.gsub(/\W/, '')
54
+ word = concat if is_banned? concat
55
+ end
56
+
57
+ is_banned?(word) ? replacement(word) : word
58
+ end
59
+
60
+ def replacement(word)
61
+ case @replace_method
62
+ when 'dictionary'
63
+ dictionary[word.downcase] || word
64
+ when 'vowels'
65
+ word.gsub(/[aeiou]/i, '*')
66
+ when 'hollow'
67
+ word[1..word.size-2] = '*' * (word.size-2) if word.size > 2
68
+ word
69
+ else
70
+ replacement_text
71
+ end
72
+ end
73
+
74
+ def is_banned?(word = '')
75
+ dictionary.include?(word.downcase)
76
+ end
77
+ end
78
+ end
79
+ end