beans-rakismet 1.2.2
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.
- data/.gitignore +11 -0
- data/CHANGELOG +35 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +20 -0
- data/README.md +229 -0
- data/Rakefile +9 -0
- data/lib/rakismet.rb +88 -0
- data/lib/rakismet/middleware.rb +16 -0
- data/lib/rakismet/model.rb +86 -0
- data/lib/rakismet/railtie.rb +22 -0
- data/lib/rakismet/version.rb +3 -0
- data/rakismet.gemspec +25 -0
- data/spec/.rspec +1 -0
- data/spec/models/block_params_spec.rb +25 -0
- data/spec/models/custom_params_spec.rb +20 -0
- data/spec/models/extended_params_spec.rb +16 -0
- data/spec/models/rakismet_model_spec.rb +98 -0
- data/spec/models/request_params_spec.rb +23 -0
- data/spec/models/subclass_spec.rb +14 -0
- data/spec/rakismet_middleware_spec.rb +27 -0
- data/spec/rakismet_spec.rb +123 -0
- data/spec/spec_helper.rb +34 -0
- metadata +140 -0
data/.gitignore
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
* Clean up gemspec and load paths [Steven Harman]
|
2
|
+
* Add Akismet is_test param [Steven Harman]
|
3
|
+
* Add Akismet user_role attribute [Steven Harman]
|
4
|
+
= 1.2.1
|
5
|
+
* Fix deprecated usage of HTTPResponse for Ruby 1.9.3 [Leonid Shevtsov]
|
6
|
+
= 1.2.0
|
7
|
+
* Rakismet attribute mappings are now inheritable
|
8
|
+
= 1.1.2
|
9
|
+
* Explicitly load version
|
10
|
+
= 1.1.1
|
11
|
+
* Fix SafeBuffer error under Rails 3.0.8 and 3.0.9 [Brandon Ferguson]
|
12
|
+
* Readme cleanup [Zeke Sikelianos]
|
13
|
+
* Drop Jeweler in favor of Bundler's gem tasks
|
14
|
+
= 1.1.0
|
15
|
+
* Add HTTP Proxy support [Francisco Trindade]
|
16
|
+
= 1.0.1
|
17
|
+
* Fix hash access for Ruby 1.9 [Alex Crichton]
|
18
|
+
= 1.0.0
|
19
|
+
* Update for Rails 3
|
20
|
+
* Remove filters and replace with middleware
|
21
|
+
* Remove initializers and replace with Railtie
|
22
|
+
= 0.4.0
|
23
|
+
* Rakismet is no longer injected into ActiveRecord or ActionController
|
24
|
+
* API changes to support newly decoupled modules
|
25
|
+
* Use Jeweler to manage gemspec
|
26
|
+
= 0.3.6
|
27
|
+
* Allow attributes to fall through to methods or AR attributes
|
28
|
+
= 0.3.5
|
29
|
+
* Added gemspec and rails/init.rb so rakismet can work as a gem [Michael Air]
|
30
|
+
* Added generator template and manifest [Michael Air]
|
31
|
+
= 0.3.0
|
32
|
+
* Abstract out Rakismet version string
|
33
|
+
* Set default Akismet Host
|
34
|
+
* Abstract out the Akismet host [Mike Burns]
|
35
|
+
* Started keeping a changelog :P
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Josh French
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
Rakismet
|
2
|
+
========
|
3
|
+
|
4
|
+
**Akismet** (<http://akismet.com/>) is a collaborative spam filtering service.
|
5
|
+
**Rakismet** is easy Akismet integration with Rails and rack apps. TypePad's
|
6
|
+
AntiSpam service and generic Akismet endpoints are supported.
|
7
|
+
|
8
|
+
Compatibility
|
9
|
+
=============
|
10
|
+
|
11
|
+
**Rakismet >= 1.0.0** work with Rails 3 and other Rack-based frameworks.
|
12
|
+
|
13
|
+
**Rakismet <= 0.4.2** is compatible with Rails 2.
|
14
|
+
|
15
|
+
Getting Started
|
16
|
+
===============
|
17
|
+
|
18
|
+
Once you've installed the Rakismet gem and added it to your application's Gemfile,
|
19
|
+
you'll need an API key. Head on over to http://akismet.com/signup/ and sign up
|
20
|
+
for a new username.
|
21
|
+
|
22
|
+
Configure the Rakismet key and the URL of your application by setting the following
|
23
|
+
in application.rb:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
config.rakismet.key = 'your wordpress key'
|
27
|
+
config.rakismet.url = 'http://yourdomain.com/'
|
28
|
+
```
|
29
|
+
|
30
|
+
or an initializer, for example `config/initializers/rakismet.rb`:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
YourApp::Application.config.rakismet.key = 'your wordpress key'
|
34
|
+
YourApp::Application.config.rakismet.url = 'http://yourdomain.com/'
|
35
|
+
```
|
36
|
+
|
37
|
+
If you wish to use another Akismet-compatible API provider such as TypePad's
|
38
|
+
antispam service, you'll also need to set `config.rakismet.host` to your service
|
39
|
+
provider's endpoint.
|
40
|
+
|
41
|
+
If you want to use a proxy to access akismet (i.e. your application is behind a
|
42
|
+
firewall), set the proxy_host and proxy_port option.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
config.rakismet.proxy_host = 'http://yourdomain.com/'
|
46
|
+
config.rakismet.proxy_port = '8080'
|
47
|
+
```
|
48
|
+
|
49
|
+
Checking For Spam
|
50
|
+
-----------------
|
51
|
+
|
52
|
+
First, introduce Rakismet to your model:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
class Comment
|
56
|
+
include Rakismet::Model
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
With Rakismet mixed in to your model, you'll get three instance methods for interacting with
|
61
|
+
Akismet:
|
62
|
+
|
63
|
+
* `spam?` submits the comment to Akismet and returns true if Akismet thinks the comment is spam, false if not.
|
64
|
+
* `ham!` resubmits a valid comment that Akismet erroneously marked as spam (marks it as a false positive.)
|
65
|
+
* `spam!` resubmits a spammy comment that Akismet missed (marks it as a false negative.)
|
66
|
+
|
67
|
+
The `ham!` and `spam!` methods will change the value of `spam?` but their
|
68
|
+
primary purpose is to send feedback to Akismet. The service works best when you
|
69
|
+
help correct the rare mistake; please consider using these methods if you're
|
70
|
+
moderating comments or otherwise reviewing the Akismet responses.
|
71
|
+
|
72
|
+
Configuring Your Model
|
73
|
+
----------------------
|
74
|
+
|
75
|
+
Rakismet sends the following information to the spam-hungry robots at Akismet:
|
76
|
+
|
77
|
+
author : name submitted with the comment
|
78
|
+
author_url : URL submitted with the comment
|
79
|
+
author_email : email submitted with the comment
|
80
|
+
comment_type : Defaults to comment but you can set it to trackback, pingback, or something more appropriate
|
81
|
+
content : the content submitted
|
82
|
+
permalink : the permanent URL for the entry the comment belongs to
|
83
|
+
user_ip : IP address used to submit this comment
|
84
|
+
user_agent : user agent string
|
85
|
+
referrer : referring URL (note the spelling)
|
86
|
+
|
87
|
+
By default, Rakismet just looks for attributes or methods on your class that
|
88
|
+
match these names. You don't have to have accessors that match these exactly,
|
89
|
+
however. If yours differ, just tell Rakismet what to call them:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
class Comment
|
93
|
+
include Rakismet::Model
|
94
|
+
attr_accessor :commenter_name, :commenter_email
|
95
|
+
rakismet_attrs :author => :commenter_name, :author_email => :commenter_email
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
Or you can pass in a proc, to access associations:
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
class Comment < ActiveRecord::Base
|
103
|
+
include Rakismet::Model
|
104
|
+
belongs_to :author
|
105
|
+
rakismet_attrs :author => proc { author.name },
|
106
|
+
:author_email => proc { author.email }
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
You can even hard-code specific fields:
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
class Trackback
|
114
|
+
include Rakismet::Model
|
115
|
+
rakismet_attrs :comment_type => "trackback"
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
Optional Request Variables
|
120
|
+
--------------------------
|
121
|
+
|
122
|
+
Akismet wants certain information about the request environment: remote IP, the
|
123
|
+
user agent string, and the HTTP referer when available. Normally, Rakismet
|
124
|
+
asks your model for these. Storing this information on your model allows you to
|
125
|
+
call the `spam?` method at a later time. For instance, maybe you're storing your
|
126
|
+
comments in an administrative queue or processing them with a background job.
|
127
|
+
|
128
|
+
You don't need to have these three attributes on your model, however. If you
|
129
|
+
choose to omit them, Rakismet will instead look at the current request (if one
|
130
|
+
exists) and take the values from the request object instead.
|
131
|
+
|
132
|
+
This means that if you are **not storing the request variables**, you must call
|
133
|
+
`spam?` from within the controller action that handles comment submissions. That
|
134
|
+
way the IP, user agent, and referer will belong to the person submitting the
|
135
|
+
comment. If you're not storing the request variables and you call `spam?` at a
|
136
|
+
later time, the request information will be missing or invalid and Akismet won't
|
137
|
+
be able to do its job properly.
|
138
|
+
|
139
|
+
If you've decided to handle the request variables yourself, you can disable the
|
140
|
+
middleware responsible for tracking the request information by adding this to
|
141
|
+
your app initialization:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
config.rakismet.use_middleware = false
|
145
|
+
```
|
146
|
+
|
147
|
+
Testing
|
148
|
+
-------
|
149
|
+
|
150
|
+
Rakismet can be configued to tell Akismet that it should operate in test mode -
|
151
|
+
so Akismet will not change its behavior based on any test API calls, meaning
|
152
|
+
they will have no training effect. That means your tests can be somewhat
|
153
|
+
repeatable in the sense that one test won't influence subsequent calls.
|
154
|
+
|
155
|
+
You can configure Rakismet for test mode via application.rb:
|
156
|
+
|
157
|
+
```ruby
|
158
|
+
config.rakismet.test = false # <- default
|
159
|
+
config.rakismet.test = true
|
160
|
+
```
|
161
|
+
|
162
|
+
Or via an initializer:
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
YourApp::Application.config.rakismet.test = false # <- default
|
166
|
+
YourApp::Application.config.rakismet.test = true
|
167
|
+
```
|
168
|
+
|
169
|
+
**NOTE**: When running in Rails, Rakismet will run in test mode when your Rails
|
170
|
+
environment is `test` or `development`, unless explictly configured otherwise.
|
171
|
+
Outside of Rails Rakismet defaults to test mode turned **off**.
|
172
|
+
|
173
|
+
|
174
|
+
Verifying Responses
|
175
|
+
-------------------
|
176
|
+
|
177
|
+
If you want to see what's happening behind the scenes, after you call one of
|
178
|
+
`@comment.spam?`, `@comment.spam!` or `@comment.ham!` you can check
|
179
|
+
`@comment.akismet_response`.
|
180
|
+
|
181
|
+
This will contain the last response from the Akismet server. In the case of
|
182
|
+
`spam?` it should be `true` or `false.` For `spam!` and `ham!` it should be
|
183
|
+
`Feedback received.` If Akismet returned an error instead (e.g. if you left out
|
184
|
+
some required information) this will contain the error message.
|
185
|
+
|
186
|
+
FAQ
|
187
|
+
===
|
188
|
+
|
189
|
+
Why does Akismet think all of my test data is spam?
|
190
|
+
---------------------------------------------------
|
191
|
+
|
192
|
+
Akismet needs enough information to decide if your test data is spam or not.
|
193
|
+
Try to supply as much as possible, especially the author name and request
|
194
|
+
variables.
|
195
|
+
|
196
|
+
How can I simulate a spam submission?
|
197
|
+
-------------------------------------
|
198
|
+
|
199
|
+
Most people have the opposite problem, where Akismet doesn't think anything is
|
200
|
+
spam. The only guaranteed way to trigger a positive spam response is to set the
|
201
|
+
comment author to "viagra-test-123".
|
202
|
+
|
203
|
+
If you've done this and `spam?` is still returning false, you're probably
|
204
|
+
missing the user IP or one of the key/url config variables. One way to check is
|
205
|
+
to call `@comment.akismet_response`. If you are missing a required field or
|
206
|
+
there was another error, this will hold the Akismet error message. If your comment
|
207
|
+
was processed normally, this value will simply be `true` or `false`.
|
208
|
+
|
209
|
+
Can I use Rakismet with a different ORM or framework?
|
210
|
+
-----------------------------------------------------
|
211
|
+
|
212
|
+
Sure. Rakismet doesn't care what your persistence layer is. It will work with
|
213
|
+
Datamapper, a NoSQL store, or whatever next month's DB flavor is.
|
214
|
+
|
215
|
+
Rakismet also has no dependencies on Rails or any of its components, and only
|
216
|
+
uses a small Rack middleware object to do some of its magic. Depending on your
|
217
|
+
framework, you may have to modify this slightly and/or manually place it in your
|
218
|
+
stack.
|
219
|
+
|
220
|
+
You'll also need to set a few config variables by hand. Instead of
|
221
|
+
`config.rakismet.key`, `config.rakismet.url`, and `config.rakismet.host`, set
|
222
|
+
these values directly with `Rakismet.key`, `Rakismet.url`, and `Rakismet.host`.
|
223
|
+
|
224
|
+
---------------------------------------------------------------------------
|
225
|
+
|
226
|
+
If you have any implementation or usage questions, don't hesitate to get in
|
227
|
+
touch: josh@vitamin-j.com.
|
228
|
+
|
229
|
+
Copyright (c) 2008 Josh French, released under the MIT license
|
data/Rakefile
ADDED
data/lib/rakismet.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'cgi'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
require 'rakismet/model'
|
7
|
+
require 'rakismet/middleware'
|
8
|
+
require 'rakismet/version'
|
9
|
+
require 'rakismet/railtie.rb' if defined?(Rails)
|
10
|
+
|
11
|
+
module Rakismet
|
12
|
+
Request = Struct.new(:user_ip, :user_agent, :referrer)
|
13
|
+
Undefined = Class.new(NameError)
|
14
|
+
|
15
|
+
class << self
|
16
|
+
attr_accessor :key, :url, :host, :proxy_host, :proxy_port, :test
|
17
|
+
|
18
|
+
def request
|
19
|
+
@request ||= Request.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_request_vars(env)
|
23
|
+
request.user_ip, request.user_agent, request.referrer =
|
24
|
+
env['REMOTE_ADDR'], env['HTTP_USER_AGENT'], env['HTTP_REFERER']
|
25
|
+
end
|
26
|
+
|
27
|
+
def clear_request
|
28
|
+
@request = Request.new
|
29
|
+
end
|
30
|
+
|
31
|
+
def headers
|
32
|
+
@headers ||= begin
|
33
|
+
user_agent = "Rakismet/#{Rakismet::VERSION}"
|
34
|
+
user_agent = "Rails/#{Rails.version} | " + user_agent if defined?(Rails)
|
35
|
+
{ 'User-Agent' => user_agent, 'Content-Type' => 'application/x-www-form-urlencoded' }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate_key
|
40
|
+
validate_config
|
41
|
+
akismet = URI.parse(verify_url)
|
42
|
+
response = Net::HTTP::Proxy(proxy_host, proxy_port).start(akismet.host) do |http|
|
43
|
+
data = "key=#{Rakismet.key}&blog=#{Rakismet.url}"
|
44
|
+
http.post(akismet.path, data, Rakismet.headers)
|
45
|
+
end
|
46
|
+
@valid_key = (response.body == 'valid')
|
47
|
+
end
|
48
|
+
|
49
|
+
def valid_key?
|
50
|
+
@valid_key == true
|
51
|
+
end
|
52
|
+
|
53
|
+
def akismet_call(function, args={})
|
54
|
+
validate_config
|
55
|
+
args.merge!(:blog => Rakismet.url, :is_test => Rakismet.test_mode)
|
56
|
+
akismet = URI.parse(call_url(function))
|
57
|
+
response = Net::HTTP::Proxy(proxy_host, proxy_port).start(akismet.host) do |http|
|
58
|
+
params = args.map do |k,v|
|
59
|
+
param = v.class < String ? v.to_str : v.to_s # for ActiveSupport::SafeBuffer and Nil, respectively
|
60
|
+
"#{k}=#{CGI.escape(param)}"
|
61
|
+
end
|
62
|
+
http.post(akismet.path, params.join('&'), Rakismet.headers)
|
63
|
+
end
|
64
|
+
response.body
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def verify_url
|
70
|
+
"http://#{Rakismet.host}/1.1/verify-key"
|
71
|
+
end
|
72
|
+
|
73
|
+
def call_url(function)
|
74
|
+
"http://#{Rakismet.key}.#{Rakismet.host}/1.1/#{function}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def validate_config
|
78
|
+
raise Undefined, "Rakismet.key is not defined" if Rakismet.key.nil? || Rakismet.key.empty?
|
79
|
+
raise Undefined, "Rakismet.url is not defined" if Rakismet.url.nil? || Rakismet.url.empty?
|
80
|
+
raise Undefined, "Rakismet.host is not defined" if Rakismet.host.nil? || Rakismet.host.empty?
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_mode
|
84
|
+
test ? 1 : 0
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Rakismet
|
2
|
+
module Model
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.class_eval do
|
6
|
+
attr_accessor :akismet_response
|
7
|
+
class << self; attr_accessor :akismet_attrs; end
|
8
|
+
extend ClassMethods
|
9
|
+
include InstanceMethods
|
10
|
+
self.rakismet_attrs
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def rakismet_attrs(args={})
|
16
|
+
self.akismet_attrs ||= {}
|
17
|
+
[:comment_type, :author, :author_url, :author_email, :content, :user_role].each do |field|
|
18
|
+
# clunky, but throwing around +type+ will break your heart
|
19
|
+
fieldname = field.to_s =~ %r(^comment_) ? field : "comment_#{field}".intern
|
20
|
+
self.akismet_attrs[fieldname] = args.delete(field) || field
|
21
|
+
end
|
22
|
+
[:user_ip, :user_agent, :referrer].each do |field|
|
23
|
+
self.akismet_attrs[field] = args.delete(field) || field
|
24
|
+
end
|
25
|
+
args.each_pair do |f,v|
|
26
|
+
self.akismet_attrs[f] = v
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def inherited(subclass)
|
31
|
+
super
|
32
|
+
subclass.rakismet_attrs akismet_attrs.dup
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module InstanceMethods
|
37
|
+
def spam?
|
38
|
+
if instance_variable_defined? :@_spam
|
39
|
+
@_spam
|
40
|
+
else
|
41
|
+
data = akismet_data
|
42
|
+
self.akismet_response = Rakismet.akismet_call('comment-check', data)
|
43
|
+
@_spam = self.akismet_response == 'true'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def spam!
|
48
|
+
Rakismet.akismet_call('submit-spam', akismet_data)
|
49
|
+
@_spam = true
|
50
|
+
end
|
51
|
+
|
52
|
+
def ham!
|
53
|
+
Rakismet.akismet_call('submit-ham', akismet_data)
|
54
|
+
@_spam = false
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def akismet_data
|
60
|
+
akismet = self.class.akismet_attrs.keys.inject({}) do |data,attr|
|
61
|
+
mapped_field = self.class.akismet_attrs[attr]
|
62
|
+
data.merge attr => if mapped_field.is_a?(Proc)
|
63
|
+
instance_eval(&mapped_field)
|
64
|
+
elsif !mapped_field.nil? && respond_to?(mapped_field)
|
65
|
+
send(mapped_field)
|
66
|
+
elsif not [:comment_type, :author, :author_email,
|
67
|
+
:author_url, :content, :user_role,
|
68
|
+
:user_ip, :referrer,
|
69
|
+
:user_agent].include?(mapped_field)
|
70
|
+
# we've excluded any fields that appear to
|
71
|
+
# have their default unmapped values
|
72
|
+
mapped_field
|
73
|
+
elsif respond_to?(attr)
|
74
|
+
send(attr)
|
75
|
+
elsif Rakismet.request.respond_to?(attr)
|
76
|
+
Rakismet.request.send(attr)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
akismet.delete_if { |k,v| v.nil? || v.empty? }
|
80
|
+
akismet[:comment_type] ||= 'comment'
|
81
|
+
akismet
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'rakismet'
|
3
|
+
|
4
|
+
module Rakismet
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
|
7
|
+
config.rakismet = ActiveSupport::OrderedOptions.new
|
8
|
+
config.rakismet.host = 'rest.akismet.com'
|
9
|
+
config.rakismet.use_middleware = true
|
10
|
+
|
11
|
+
initializer 'rakismet.setup', :after => :load_config_initializers do |app|
|
12
|
+
Rakismet.key = app.config.rakismet[:key]
|
13
|
+
Rakismet.url = app.config.rakismet[:url]
|
14
|
+
Rakismet.host = app.config.rakismet[:host]
|
15
|
+
Rakismet.proxy_host = app.config.rakismet[:proxy_host]
|
16
|
+
Rakismet.proxy_port = app.config.rakismet[:proxy_port]
|
17
|
+
Rakismet.test = app.config.rakismet.fetch(:test) { Rails.env.test? || Rails.env.development? }
|
18
|
+
app.middleware.use Rakismet::Middleware if app.config.rakismet.use_middleware
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
data/rakismet.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/rakismet/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "beans-rakismet"
|
6
|
+
s.version = Rakismet::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Josh French"]
|
9
|
+
s.email = "josh@vitamin-j.com"
|
10
|
+
s.homepage = "http://github.com/joshfrench/rakismet"
|
11
|
+
s.summary = "Akismet and TypePad AntiSpam integration for Rails."
|
12
|
+
s.description = "Rakismet is the easiest way to integrate Akismet or TypePad's AntiSpam into your Rails app."
|
13
|
+
s.date = "2012-04-22"
|
14
|
+
|
15
|
+
s.rubyforge_project = "rakismet"
|
16
|
+
s.add_development_dependency "rake"
|
17
|
+
s.add_development_dependency "rspec", "~> 2.11"
|
18
|
+
|
19
|
+
s.files = `git ls-files`.split("\n")
|
20
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
21
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
|
+
s.require_paths = ["lib"]
|
23
|
+
s.extra_rdoc_files = ["README.md"]
|
24
|
+
end
|
25
|
+
|
data/spec/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
PROC = proc { author.reverse }
|
4
|
+
|
5
|
+
class BlockAkismetModel
|
6
|
+
include Rakismet::Model
|
7
|
+
rakismet_attrs :author => PROC
|
8
|
+
end
|
9
|
+
|
10
|
+
describe BlockAkismetModel do
|
11
|
+
|
12
|
+
before do
|
13
|
+
@block = BlockAkismetModel.new
|
14
|
+
comment_attrs.each_pair { |k,v| @block.stub!(k).and_return(v) }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should accept a block" do
|
18
|
+
BlockAkismetModel.akismet_attrs[:comment_author].should eql(PROC)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should eval block with self = instance" do
|
22
|
+
data = @block.send(:akismet_data)
|
23
|
+
data[:comment_author].should eql(comment_attrs[:author].reverse)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
MAPPED_PARAMS = { :comment_type => :type2, :author => :author2, :content => :content2,
|
4
|
+
:author_email => :author_email2, :author_url => :author_url2,
|
5
|
+
:user_role => :user_role2 }
|
6
|
+
|
7
|
+
class CustomAkismetModel
|
8
|
+
include Rakismet::Model
|
9
|
+
rakismet_attrs MAPPED_PARAMS.dup
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
describe CustomAkismetModel do
|
14
|
+
it "should override default mappings" do
|
15
|
+
[:comment_type, :author, :author_url, :author_email, :content, :user_role].each do |field|
|
16
|
+
fieldname = field.to_s =~ %r(^comment_) ? field : "comment_#{field}".intern
|
17
|
+
CustomAkismetModel.akismet_attrs[fieldname].should eql(MAPPED_PARAMS[field])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
EXTRA = { :extra => :extra, :another => lambda { } }
|
4
|
+
|
5
|
+
class ExtendedAkismetModel
|
6
|
+
include Rakismet::Model
|
7
|
+
rakismet_attrs EXTRA.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ExtendedAkismetModel do
|
11
|
+
it "should include additional attributes" do
|
12
|
+
[:extra, :another].each do |field|
|
13
|
+
ExtendedAkismetModel.akismet_attrs[field].should eql(EXTRA[field])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe AkismetModel do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@model = AkismetModel.new
|
7
|
+
comment_attrs.each_pair { |k,v| @model.stub!(k).and_return(v) }
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have default mappings" do
|
11
|
+
[:comment_type, :author, :author_email, :author_url, :content, :user_role].each do |field|
|
12
|
+
fieldname = field.to_s =~ %r(^comment_) ? field : "comment_#{field}".intern
|
13
|
+
AkismetModel.akismet_attrs[fieldname].should eql(field)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have request mappings" do
|
18
|
+
[:user_ip, :user_agent, :referrer].each do |field|
|
19
|
+
AkismetModel.akismet_attrs[field].should eql(field)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should populate comment type" do
|
24
|
+
@model.send(:akismet_data)[:comment_type].should == comment_attrs[:comment_type]
|
25
|
+
end
|
26
|
+
|
27
|
+
describe ".spam?" do
|
28
|
+
|
29
|
+
it "should use request variables from Rakismet.request if absent in model" do
|
30
|
+
[:user_ip, :user_agent, :referrer].each do |field|
|
31
|
+
@model.should_not respond_to(:field)
|
32
|
+
end
|
33
|
+
Rakismet.stub!(:request).and_return(request)
|
34
|
+
Rakismet.should_receive(:akismet_call).
|
35
|
+
with('comment-check', akismet_attrs.merge(:user_ip => '127.0.0.1',
|
36
|
+
:user_agent => 'RSpec',
|
37
|
+
:referrer => 'http://test.host/referrer'))
|
38
|
+
@model.spam?
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should cache result of #spam?" do
|
42
|
+
Rakismet.should_receive(:akismet_call).once
|
43
|
+
@model.spam?
|
44
|
+
@model.spam?
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should be true if comment is spam" do
|
48
|
+
Rakismet.stub!(:akismet_call).and_return('true')
|
49
|
+
@model.should be_spam
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should be false if comment is not spam" do
|
53
|
+
Rakismet.stub!(:akismet_call).and_return('false')
|
54
|
+
@model.should_not be_spam
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should set akismet_response" do
|
58
|
+
Rakismet.stub!(:akismet_call).and_return('response')
|
59
|
+
@model.spam?
|
60
|
+
@model.akismet_response.should eql('response')
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should not throw an error if request vars are missing" do
|
64
|
+
Rakismet.stub!(:request).and_return(empty_request)
|
65
|
+
lambda { @model.spam? }.should_not raise_error(NoMethodError)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
describe ".spam!" do
|
71
|
+
it "should call Base.akismet_call with submit-spam" do
|
72
|
+
Rakismet.should_receive(:akismet_call).with('submit-spam', akismet_attrs)
|
73
|
+
@model.spam!
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should mutate #spam?" do
|
77
|
+
Rakismet.stub!(:akismet_call)
|
78
|
+
@model.instance_variable_set(:@_spam, false)
|
79
|
+
@model.spam!
|
80
|
+
@model.should be_spam
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe ".ham!" do
|
85
|
+
it "should call Base.akismet_call with submit-ham" do
|
86
|
+
Rakismet.should_receive(:akismet_call).with('submit-ham', akismet_attrs)
|
87
|
+
@model.ham!
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should mutate #spam?" do
|
91
|
+
Rakismet.stub!(:akismet_call)
|
92
|
+
@model.instance_variable_set(:@_spam, true)
|
93
|
+
@model.ham!
|
94
|
+
@model.should_not be_spam
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class RequestParams
|
4
|
+
include Rakismet::Model
|
5
|
+
attr_accessor :user_ip, :user_agent, :referrer
|
6
|
+
end
|
7
|
+
|
8
|
+
describe RequestParams do
|
9
|
+
before do
|
10
|
+
@model = RequestParams.new
|
11
|
+
attrs = comment_attrs(:user_ip => '192.168.0.1', :user_agent => 'Rakismet', :referrer => 'http://localhost/referrer')
|
12
|
+
attrs.each_pair { |k,v| @model.stub!(k).and_return(v) }
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should use local values even if Rakismet.request is populated" do
|
16
|
+
Rakismet.stub(:request).and_return(request)
|
17
|
+
Rakismet.should_receive(:akismet_call).
|
18
|
+
with('comment-check', akismet_attrs.merge(:user_ip => '192.168.0.1',
|
19
|
+
:user_agent => 'Rakismet',
|
20
|
+
:referrer => 'http://localhost/referrer'))
|
21
|
+
@model.spam?
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Subclass < AkismetModel
|
4
|
+
end
|
5
|
+
|
6
|
+
describe Subclass do
|
7
|
+
it "should inherit parent's rakismet attrs" do
|
8
|
+
Subclass.akismet_attrs.should eql AkismetModel.akismet_attrs # key/value equality
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should get a new copy of parent's rakismet attrs" do
|
12
|
+
Subclass.akismet_attrs.should_not equal AkismetModel.akismet_attrs # object equality
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rakismet::Middleware do
|
4
|
+
|
5
|
+
let(:env) { { 'REMOTE_ADDR' => '127.0.0.1', 'HTTP_USER_AGENT' => 'RSpec', 'HTTP_REFERER' => 'http://test.host/referrer' } }
|
6
|
+
let(:app) { double(:app, :call => nil) }
|
7
|
+
let(:request) { double(:request).as_null_object }
|
8
|
+
|
9
|
+
before do
|
10
|
+
@middleware = Rakismet::Middleware.new(app)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should set set Rakismet.request variables" do
|
14
|
+
Rakismet.stub(:request).and_return(request)
|
15
|
+
request.should_receive(:user_ip=).with('127.0.0.1')
|
16
|
+
request.should_receive(:user_agent=).with('RSpec')
|
17
|
+
request.should_receive(:referrer=).with('http://test.host/referrer')
|
18
|
+
@middleware.call(env)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should clear Rakismet.request after request is complete" do
|
22
|
+
@middleware.call(env)
|
23
|
+
Rakismet.request.user_ip.should be_nil
|
24
|
+
Rakismet.request.user_agent.should be_nil
|
25
|
+
Rakismet.request.referrer.should be_nil
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rakismet do
|
4
|
+
|
5
|
+
def mock_response(body)
|
6
|
+
double(:response, :body => body)
|
7
|
+
end
|
8
|
+
let(:http) { double(:http, :post => mock_response('akismet response')) }
|
9
|
+
|
10
|
+
before do
|
11
|
+
Rakismet.key = 'dummy-key'
|
12
|
+
Rakismet.url = 'test.localhost'
|
13
|
+
Rakismet.host = 'endpoint.localhost'
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "proxy host" do
|
17
|
+
it "should have proxy host and port as nil by default" do
|
18
|
+
Rakismet.proxy_host.should be_nil
|
19
|
+
Rakismet.proxy_port.should be_nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe ".validate_config" do
|
24
|
+
it "should raise an error if key is not found" do
|
25
|
+
Rakismet.key = ''
|
26
|
+
lambda { Rakismet.send(:validate_config) }.should raise_error(Rakismet::Undefined)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should raise an error if url is not found" do
|
30
|
+
Rakismet.url = ''
|
31
|
+
lambda { Rakismet.send(:validate_config) }.should raise_error(Rakismet::Undefined)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should raise an error if host is not found" do
|
35
|
+
Rakismet.host = ''
|
36
|
+
lambda { Rakismet.send(:validate_config) }.should raise_error(Rakismet::Undefined)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe ".validate_key" do
|
41
|
+
before (:each) do
|
42
|
+
@proxy = mock(Net::HTTP)
|
43
|
+
Net::HTTP.stub!(:Proxy).and_return(@proxy)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should use proxy host and port" do
|
47
|
+
Rakismet.proxy_host = 'proxy_host'
|
48
|
+
Rakismet.proxy_port = 'proxy_port'
|
49
|
+
@proxy.stub!(:start).and_return(mock_response('valid'))
|
50
|
+
Net::HTTP.should_receive(:Proxy).with('proxy_host', 'proxy_port').and_return(@proxy)
|
51
|
+
Rakismet.validate_key
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should set @@valid_key = true if key is valid" do
|
55
|
+
@proxy.stub!(:start).and_return(mock_response('valid'))
|
56
|
+
Rakismet.validate_key
|
57
|
+
Rakismet.valid_key?.should be_true
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should set @@valid_key = false if key is invalid" do
|
61
|
+
@proxy.stub!(:start).and_return(mock_response('invalid'))
|
62
|
+
Rakismet.validate_key
|
63
|
+
Rakismet.valid_key?.should be_false
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should build url with host" do
|
67
|
+
host = "api.antispam.typepad.com"
|
68
|
+
Rakismet.host = host
|
69
|
+
@proxy.should_receive(:start).with(host).and_yield(http)
|
70
|
+
Rakismet.validate_key
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe ".akismet_call" do
|
75
|
+
before do
|
76
|
+
@proxy = mock(Net::HTTP)
|
77
|
+
Net::HTTP.stub!(:Proxy).and_return(@proxy)
|
78
|
+
@proxy.stub(:start).and_yield(http)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should use proxy host and port" do
|
82
|
+
Rakismet.proxy_host = 'proxy_host'
|
83
|
+
Rakismet.proxy_port = 'proxy_port'
|
84
|
+
@proxy.stub!(:start).and_return(mock_response('valid'))
|
85
|
+
Net::HTTP.should_receive(:Proxy).with('proxy_host', 'proxy_port').and_return(@proxy)
|
86
|
+
Rakismet.send(:akismet_call, 'bogus-function')
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should build url with API key for the correct host" do
|
90
|
+
host = 'api.antispam.typepad.com'
|
91
|
+
Rakismet.host = host
|
92
|
+
@proxy.should_receive(:start).with("#{Rakismet.key}.#{host}")
|
93
|
+
Rakismet.send(:akismet_call, 'bogus-function')
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should post data to named function" do
|
97
|
+
http.should_receive(:post).with('/1.1/bogus-function', %r(foo=#{CGI.escape 'escape//this'}), Rakismet.headers)
|
98
|
+
Rakismet.send(:akismet_call, 'bogus-function', { :foo => 'escape//this' })
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should default to not being in test mode" do
|
102
|
+
http.should_receive(:post).with(anything, %r(is_test=0), anything)
|
103
|
+
Rakismet.send(:akismet_call, 'bogus-function')
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should be in test mode when configured" do
|
107
|
+
Rakismet.test = true
|
108
|
+
http.should_receive(:post).with(anything, %r(is_test=1), anything)
|
109
|
+
Rakismet.send(:akismet_call, 'bogus-function')
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should return response.body" do
|
113
|
+
Rakismet.send(:akismet_call, 'bogus-function').should eql('akismet response')
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should build query string when params are nil" do
|
117
|
+
lambda {
|
118
|
+
Rakismet.send(:akismet_call, 'bogus-function', { :nil_param => nil })
|
119
|
+
}.should_not raise_error(NoMethodError)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path "lib/rakismet"
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
config.mock_with :rspec
|
6
|
+
end
|
7
|
+
|
8
|
+
class AkismetModel
|
9
|
+
include Rakismet::Model
|
10
|
+
end
|
11
|
+
|
12
|
+
def comment_attrs(attrs={})
|
13
|
+
{ :comment_type => 'test', :author => 'Rails test',
|
14
|
+
:author_email => 'test@test.host', :author_url => 'test.host',
|
15
|
+
:content => 'comment content', :blog => Rakismet.url }.merge(attrs)
|
16
|
+
end
|
17
|
+
|
18
|
+
def akismet_attrs(attrs={})
|
19
|
+
{ :comment_type => 'test', :comment_author_email => 'test@test.host',
|
20
|
+
:comment_author => 'Rails test', :comment_author_url => 'test.host',
|
21
|
+
:comment_content => 'comment content' }.merge(attrs)
|
22
|
+
end
|
23
|
+
|
24
|
+
def request
|
25
|
+
OpenStruct.new(:user_ip => '127.0.0.1',
|
26
|
+
:user_agent => 'RSpec',
|
27
|
+
:referrer => 'http://test.host/referrer')
|
28
|
+
end
|
29
|
+
|
30
|
+
def empty_request
|
31
|
+
OpenStruct.new(:user_ip => nil,
|
32
|
+
:user_agent => nil,
|
33
|
+
:referrer => nil)
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: beans-rakismet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Josh French
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-04-22 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '2.11'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '2.11'
|
46
|
+
description: Rakismet is the easiest way to integrate Akismet or TypePad's AntiSpam
|
47
|
+
into your Rails app.
|
48
|
+
email: josh@vitamin-j.com
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.md
|
53
|
+
files:
|
54
|
+
- !binary |-
|
55
|
+
LmdpdGlnbm9yZQ==
|
56
|
+
- !binary |-
|
57
|
+
Q0hBTkdFTE9H
|
58
|
+
- !binary |-
|
59
|
+
R2VtZmlsZQ==
|
60
|
+
- !binary |-
|
61
|
+
TUlULUxJQ0VOU0U=
|
62
|
+
- !binary |-
|
63
|
+
UkVBRE1FLm1k
|
64
|
+
- !binary |-
|
65
|
+
UmFrZWZpbGU=
|
66
|
+
- !binary |-
|
67
|
+
bGliL3Jha2lzbWV0LnJi
|
68
|
+
- !binary |-
|
69
|
+
bGliL3Jha2lzbWV0L21pZGRsZXdhcmUucmI=
|
70
|
+
- !binary |-
|
71
|
+
bGliL3Jha2lzbWV0L21vZGVsLnJi
|
72
|
+
- !binary |-
|
73
|
+
bGliL3Jha2lzbWV0L3JhaWx0aWUucmI=
|
74
|
+
- !binary |-
|
75
|
+
bGliL3Jha2lzbWV0L3ZlcnNpb24ucmI=
|
76
|
+
- !binary |-
|
77
|
+
cmFraXNtZXQuZ2Vtc3BlYw==
|
78
|
+
- !binary |-
|
79
|
+
c3BlYy8ucnNwZWM=
|
80
|
+
- !binary |-
|
81
|
+
c3BlYy9tb2RlbHMvYmxvY2tfcGFyYW1zX3NwZWMucmI=
|
82
|
+
- !binary |-
|
83
|
+
c3BlYy9tb2RlbHMvY3VzdG9tX3BhcmFtc19zcGVjLnJi
|
84
|
+
- !binary |-
|
85
|
+
c3BlYy9tb2RlbHMvZXh0ZW5kZWRfcGFyYW1zX3NwZWMucmI=
|
86
|
+
- !binary |-
|
87
|
+
c3BlYy9tb2RlbHMvcmFraXNtZXRfbW9kZWxfc3BlYy5yYg==
|
88
|
+
- !binary |-
|
89
|
+
c3BlYy9tb2RlbHMvcmVxdWVzdF9wYXJhbXNfc3BlYy5yYg==
|
90
|
+
- !binary |-
|
91
|
+
c3BlYy9tb2RlbHMvc3ViY2xhc3Nfc3BlYy5yYg==
|
92
|
+
- !binary |-
|
93
|
+
c3BlYy9yYWtpc21ldF9taWRkbGV3YXJlX3NwZWMucmI=
|
94
|
+
- !binary |-
|
95
|
+
c3BlYy9yYWtpc21ldF9zcGVjLnJi
|
96
|
+
- !binary |-
|
97
|
+
c3BlYy9zcGVjX2hlbHBlci5yYg==
|
98
|
+
homepage: http://github.com/joshfrench/rakismet
|
99
|
+
licenses: []
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project: rakismet
|
118
|
+
rubygems_version: 1.8.24
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: Akismet and TypePad AntiSpam integration for Rails.
|
122
|
+
test_files:
|
123
|
+
- !binary |-
|
124
|
+
c3BlYy9tb2RlbHMvYmxvY2tfcGFyYW1zX3NwZWMucmI=
|
125
|
+
- !binary |-
|
126
|
+
c3BlYy9tb2RlbHMvY3VzdG9tX3BhcmFtc19zcGVjLnJi
|
127
|
+
- !binary |-
|
128
|
+
c3BlYy9tb2RlbHMvZXh0ZW5kZWRfcGFyYW1zX3NwZWMucmI=
|
129
|
+
- !binary |-
|
130
|
+
c3BlYy9tb2RlbHMvcmFraXNtZXRfbW9kZWxfc3BlYy5yYg==
|
131
|
+
- !binary |-
|
132
|
+
c3BlYy9tb2RlbHMvcmVxdWVzdF9wYXJhbXNfc3BlYy5yYg==
|
133
|
+
- !binary |-
|
134
|
+
c3BlYy9tb2RlbHMvc3ViY2xhc3Nfc3BlYy5yYg==
|
135
|
+
- !binary |-
|
136
|
+
c3BlYy9yYWtpc21ldF9taWRkbGV3YXJlX3NwZWMucmI=
|
137
|
+
- !binary |-
|
138
|
+
c3BlYy9yYWtpc21ldF9zcGVjLnJi
|
139
|
+
- !binary |-
|
140
|
+
c3BlYy9zcGVjX2hlbHBlci5yYg==
|