ruby-akismet 0.9.3 → 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.
Files changed (4) hide show
  1. data/README.rdoc +38 -12
  2. data/lib/akismet.rb +101 -32
  3. data/test/akismet_test.rb +94 -25
  4. metadata +5 -5
@@ -1,9 +1,9 @@
1
- Akismet compatible library for checking spams.
1
+ Ruby library for the Akismet anti-spam service.
2
2
 
3
3
  = Usage
4
4
 
5
5
  First you need an Akismet (or Typepad Antispam) API key. Then you need
6
- to setup a few configuration variable:
6
+ to setup a few configuration variables:
7
7
 
8
8
  Akismet.key = '123456789'
9
9
  Akismet.blog = 'http://example.com'
@@ -12,37 +12,61 @@ To use Typepad Antispam, just specify the host:
12
12
 
13
13
  Akismet.host = 'api.antispam.typepad.com'
14
14
 
15
- Then you need to call any of the methods with a few attributes,
16
- and possibly an <code>ActionDispatch::Request</code> object.
15
+ Then you need to call any of the methods with a few attributes, and possibly
16
+ an ActionDispatch::Request object.
17
17
 
18
- = Documentation
18
+ == Documentation
19
+
20
+ Check rubydoc.info:
19
21
 
20
22
  http://rubydoc.info/github/ysbaddaden/ruby-akismet/master/frames
21
23
 
24
+ Or generate your own:
25
+
26
+ ~/src/ruby-akismet$ rake rdoc
27
+
22
28
  = Integrate with Ruby on Rails
23
29
 
24
- On rails 3, add this gem to your <code>Gemfile</code>:
30
+ ruby-akismet integrates nicely with Ruby on Rails, but isn't tied to it except
31
+ for the ActionDispatch::Request object, which isn't required. It should be
32
+ easily integratable with your favorite framework like Sinatra and Merb.
33
+
34
+ == Rails 3
35
+
36
+ Add this gem to your Gemfile:
25
37
 
26
38
  gem 'ruby-akismet', :require => 'akismet'
27
39
 
28
- On rails 2, first install the gem:
40
+ == Rails 2
41
+
42
+ First install the gem:
29
43
 
30
44
  gem install ruby-akismet
31
45
 
32
- Then add the gem to your app:
46
+ Then add it to your app:
33
47
 
34
48
  config.gem 'ruby-akismet', :lib => 'akismet'
35
49
 
36
- Create an initializer file like <code>config/initializers/akismet.rb</code>
50
+ == Configuration
51
+
52
+ Create an initializer file like <tt>config/initializers/akismet.rb</tt>
37
53
  with your configuration:
38
54
 
39
- Akismet.key = '123456789'
40
- Akismet.blog = 'http://example.com'
55
+ Akismet.key = '123456789'
56
+ Akismet.blog = 'http://example.com'
57
+ Akismet.logger = Rails.logger
58
+
59
+ == Usage
41
60
 
42
- Then in your controller call the appropriate methods (rails 3 example):
61
+ ruby-akismet is meant to be used on the controller side and not on the model
62
+ side, because the Akismet API requires some data that's only available from
63
+ the HTTP request --like the user and proxy IP, referer, etc.
64
+
65
+ Here is a Rails 3 example:
43
66
 
44
67
  class CommentsController < ApplicationController
45
68
  before_filter :set_post
69
+
46
70
  respond_to :html, :xml
47
71
 
48
72
  def create
@@ -84,6 +108,8 @@ Then in your controller call the appropriate methods (rails 3 example):
84
108
 
85
109
  = Author
86
110
 
111
+ - Julien Portalier <ysbaddaden@gmail.com>
112
+
87
113
  ruby-akismet is a complete rewrite of Akismetor by Ryan Bates and
88
114
  Levy Carneiro Jr. that you can find at http://github.com/levycarneiro/akismetor
89
115
 
@@ -1,46 +1,91 @@
1
1
  require 'net/http'
2
2
 
3
3
  # Akismet compatible library for checking spams.
4
+ #
5
+ # Before calling any method, you must configure a blog (your website
6
+ # homepage) and your Akismet or Typepad Antispam API key.
7
+ #
8
+ # Akismet.key = '123456789'
9
+ # Akismet.blog = 'http://example.com'
10
+ #
4
11
  class Akismet
5
- VERSION = '0.9.3'.freeze
6
- API_VERSION = '1.1'.freeze
12
+ # Raised whenever a command is issued but the API key hasn't been configured.
13
+ class MissingKey < StandardError
14
+ end
7
15
 
8
- @@host = 'rest.akismet.com'
9
- @@key = nil
10
- @@blog = nil
11
- @@extra_headers = [
12
- 'HTTP_REMOTE_ADDR',
13
- 'HTTP_CLIENT_IP',
14
- 'HTTP_X_FORWARDED_FOR',
15
- 'HTTP_CONNECTION'
16
- ]
16
+ VERSION = '1.0.0'.freeze
17
+ API_VERSION = '1.1'.freeze
17
18
 
18
19
  class << self
19
- # Configure an alternate API server.
20
+ # Configure an alternate API host server (defaults to
21
+ # <tt>'rest.akismet.com'</tt>).
20
22
  def host=(host)
21
23
  @@host = host
22
24
  end
23
25
 
26
+ def host
27
+ @@host
28
+ end
29
+
24
30
  # Configure your API key (required).
25
31
  def key=(key)
26
32
  @@key = key
27
33
  end
28
34
 
29
- # Configure your homepage URL (optional).
35
+ def key
36
+ @@key
37
+ end
38
+
39
+ # Configure your homepage URL (required).
30
40
  def blog=(blog)
31
41
  @@blog = blog
32
42
  end
33
43
 
34
- # Configure an array of extra HTTP headers to pass to Akismet from
35
- # the request.
44
+ def blog
45
+ @@blog
46
+ end
47
+
48
+ def logger=(logger)
49
+ @@logger = logger
50
+ end
51
+
52
+ def logger
53
+ @@logger
54
+ end
55
+
56
+ # Configure an Array of extra HTTP headers to pass to the Akismet server
57
+ # to extract from the request object.
58
+ #
59
+ # Defaults to:
60
+ #
61
+ # [
62
+ # 'HTTP_REMOTE_ADDR',
63
+ # 'HTTP_CLIENT_IP',
64
+ # 'HTTP_X_FORWARDED_FOR',
65
+ # 'HTTP_CONNECTION'
66
+ # ]
36
67
  #
37
- # Example:
68
+ # Examples:
69
+ #
70
+ # # replaces the actual list:
71
+ # Akismet.extra_headers = ['HTTP_REMOTE_ADDR']
72
+ #
73
+ # # appends a header to the list:
74
+ # Akismet.extra_headers << 'HTTP_ACCEPT_CHARSET'
75
+ #
76
+ # # appends multiple headers to the list:
77
+ # Akismet.extra_headers << ['HTTP_ACCEPT_CHARSET', 'HTTP_ACCEPT_LANGUAGE']
38
78
  #
39
- # Akismet.extra_headers = ['HTTP_REMOTE_ADDR', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR']
40
79
  def extra_headers=(headers)
41
80
  @@extra_headers = headers
42
81
  end
43
82
 
83
+ def extra_headers
84
+ @@extra_headers.flatten!
85
+ @@extra_headers.uniq!
86
+ @@extra_headers
87
+ end
88
+
44
89
  # Checks if a key is valid or not.
45
90
  def valid_key?(key)
46
91
  call('verify-key', :key => key) == "valid"
@@ -50,18 +95,25 @@ class Akismet
50
95
  #
51
96
  # Required attributes:
52
97
  #
53
- # - <code>:permalink</code>
54
- # - <code>:comment_author</code>
55
- # - <code>:comment_author_url</code>
56
- # - <code>:comment_author_email</code>
57
- # - <code>:comment_content</code>
98
+ # - <tt>:permalink</tt>
99
+ # - <tt>:comment_author</tt>
100
+ # - <tt>:comment_author_url</tt>
101
+ # - <tt>:comment_author_email</tt>
102
+ # - <tt>:comment_content</tt>
103
+ #
104
+ # Those are also required, but will be extracted from the
105
+ # +request+ object if available:
58
106
  #
59
- # Those are also required, but will be extracted from the request object:
107
+ # - <tt>:user_ip</tt>
108
+ # - <tt>:user_agent</tt>
109
+ # - <tt>:referrer</tt> (check spelling!)
60
110
  #
61
- # - <code>:user_ip</code>
62
- # - <code>:user_agent</code>
63
- # - <code>:referer</code>
64
- # - plus any more relevant HTTP header.
111
+ # Plus more relevant HTTP headers from extra_headers.
112
+ #
113
+ # Note that request is supposed to be an instance of
114
+ # ActionDispatch::Request or ActionController::Request. If not, the object
115
+ # must respond to +remote_ip+ (IP as string) and +headers+
116
+ # (an array of HTTP headers).
65
117
  #
66
118
  def spam?(attributes, request = nil)
67
119
  call('comment-check', attributes, request) == "true"
@@ -79,7 +131,7 @@ class Akismet
79
131
  end
80
132
 
81
133
  # Submits a false-positive comment as non-spam to Akismet.
82
- # Takes the same attributes than +spam+.
134
+ # Takes the same attributes than spam?.
83
135
  def submit_ham(attributes)
84
136
  call('submit-ham', attributes)
85
137
  end
@@ -90,6 +142,17 @@ class Akismet
90
142
  end
91
143
  end
92
144
 
145
+ self.host = 'rest.akismet.com'
146
+ self.key = nil
147
+ self.blog = nil
148
+ self.logger = nil
149
+ self.extra_headers = [
150
+ 'HTTP_REMOTE_ADDR',
151
+ 'HTTP_CLIENT_IP',
152
+ 'HTTP_X_FORWARDED_FOR',
153
+ 'HTTP_CONNECTION'
154
+ ]
155
+
93
156
  def initialize(command, attributes, request = nil)
94
157
  @command = command
95
158
  @attributes = attributes
@@ -97,13 +160,15 @@ class Akismet
97
160
  end
98
161
 
99
162
  def call
163
+ self.class.logger.debug { " AKISMET #{@command} #{post_attributes}" } if self.class.logger
164
+
100
165
  http = Net::HTTP.new(http_host, 80)
101
166
  http.post(http_path, post_attributes, http_headers).body
102
167
  end
103
168
 
104
169
  private
105
170
  def attributes
106
- @attributes[:blog] ||= @@blog
171
+ @attributes[:blog] ||= self.class.blog
107
172
 
108
173
  unless @command == 'verify-key'
109
174
  @attributes[:comment_type] ||= 'comment'
@@ -112,7 +177,10 @@ class Akismet
112
177
  @attributes[:user_ip] = @request.remote_ip
113
178
  @attributes[:user_agent] = @request.headers["HTTP_USER_AGENT"]
114
179
  @attributes[:referrer] = @request.headers["HTTP_REFERER"]
115
- @@extra_headers.each { |h| @attributes[h] = @request.headers[h] }
180
+
181
+ self.class.extra_headers.each do |h|
182
+ @attributes[h] = @request.headers[h]
183
+ end
116
184
  end
117
185
  end
118
186
 
@@ -133,9 +201,10 @@ class Akismet
133
201
 
134
202
  def http_host
135
203
  unless @command == 'verify-key'
136
- "#{@@key}.#{@@host}"
204
+ raise MissingKey.new("Required Akismet.key is nil.") unless self.class.key
205
+ "#{self.class.key}.#{self.class.host}"
137
206
  else
138
- "#{@@host}"
207
+ "#{self.class.host}"
139
208
  end
140
209
  end
141
210
 
@@ -1,60 +1,129 @@
1
1
  require 'test/unit'
2
+ require 'logger'
3
+
4
+ require 'rubygems'
5
+ gem 'actionpack'
6
+ gem 'rack'
7
+ require 'action_dispatch'
8
+
2
9
  require File.expand_path("../../lib/akismet.rb", __FILE__)
3
10
 
4
- # TODO: Test with an ActionDispatch::TestRequest object.
5
11
  class AkismetTest < Test::Unit::TestCase
6
12
  def setup
7
13
  Akismet.host = 'api.antispam.typepad.com'
8
14
  Akismet.key = '123456789'
9
15
  Akismet.blog = 'http://www.example.com/'
10
- end
11
-
12
- def valid_attributes
13
- {
14
- :user_ip => '127.0.0.1',
15
- :user_agent => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.5; en-US; rv:1.9.0.3) Gecko/2008092414 Firefox/3.0.3',
16
- :referrer => 'http://www.example.com/posts',
17
- :permalink => 'http://www.example.com/posts/1',
18
- :comment_author => 'Julien Portalier',
19
- :comment_author_url => 'http://ysbaddaden.wordpress.com/',
20
- :comment_author_email => 'julien@example.com',
21
- :comment_content => 'this is a normal comment',
22
- }
23
- end
24
-
25
- def invalid_attributes
26
- invalid = valid_attributes.dup
27
- invalid[:comment_author] = 'viagra-test-123'
28
- invalid
16
+
17
+ Akismet.logger = Logger.new(File.expand_path("../test.log", __FILE__))
18
+ Akismet.logger.level = Logger::DEBUG
29
19
  end
30
20
 
31
21
  def test_valid_key
32
- assert Akismet.valid_key?('123456789')
22
+ assert Akismet.valid_key?(Akismet.key)
33
23
  end
34
24
 
35
25
  # def test_invalid_key
36
26
  # assert !Akismet.valid_key?('abc123')
37
27
  # end
38
28
 
29
+ def test_should_not_fail_with_no_logger
30
+ Akismet.logger = nil
31
+ assert Akismet.valid_key?(Akismet.key)
32
+ end
33
+
34
+ def test_should_raise_missing_key
35
+ Akismet.key = nil
36
+ assert_raise(Akismet::MissingKey) { Akismet.spam?(full_spam_attributes) }
37
+ end
38
+
39
+ def test_should_not_raise_missing_key_for_valid_key
40
+ Akismet.key = nil
41
+ assert_nothing_raised { Akismet.valid_key?('123456789') }
42
+ end
43
+
44
+ def test_extra_headers
45
+ Akismet.extra_headers = ['HTTP_REMOTE_ADDR']
46
+ assert_equal ['HTTP_REMOTE_ADDR'], Akismet.extra_headers
47
+
48
+ Akismet.extra_headers << 'HTTP_CLIENT_IP'
49
+ assert_equal ['HTTP_REMOTE_ADDR', 'HTTP_CLIENT_IP'], Akismet.extra_headers
50
+
51
+ Akismet.extra_headers << ['HTTP_X_FORWARDED_FOR', 'HTTP_CONNECTION']
52
+ assert_equal ['HTTP_REMOTE_ADDR', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_CONNECTION'],
53
+ Akismet.extra_headers
54
+ end
55
+
56
+ def test_spam_with_actiondispatch_request
57
+ assert Akismet.spam?(spam_attributes, actiondispatch_request)
58
+ end
59
+
60
+ def test_ham_with_actiondispatch_request
61
+ assert !Akismet.spam?(ham_attributes, actiondispatch_request)
62
+ end
63
+
39
64
  def test_spam
40
- assert Akismet.spam?(invalid_attributes)
65
+ assert Akismet.spam?(full_spam_attributes)
41
66
  end
42
67
 
43
68
  def test_not_spam
44
- assert !Akismet.spam?(valid_attributes)
69
+ assert !Akismet.spam?(full_ham_attributes)
45
70
  end
46
71
 
47
72
  def test_ham
48
- assert Akismet.ham?(valid_attributes)
73
+ assert Akismet.ham?(full_ham_attributes)
49
74
  end
50
75
 
51
76
  def test_not_ham
52
- assert !Akismet.ham?(invalid_attributes)
77
+ assert !Akismet.ham?(full_spam_attributes)
53
78
  end
54
79
 
55
80
  def test_submit_spam
81
+ assert Akismet.submit_spam(spam_attributes)
56
82
  end
57
83
 
58
84
  def test_submit_ham
85
+ assert Akismet.submit_ham(ham_attributes)
59
86
  end
87
+
88
+ protected
89
+ def ham_attributes
90
+ {
91
+ :permalink => 'http://www.example.com/posts/1',
92
+ :comment_author => 'Julien Portalier',
93
+ :comment_author_url => 'http://ysbaddaden.wordpress.com/',
94
+ :comment_author_email => 'julien@example.com',
95
+ :comment_content => 'this is a normal comment'
96
+ }
97
+ end
98
+
99
+ def spam_attributes
100
+ ham_attributes.merge(:comment_author => 'viagra-test-123')
101
+ end
102
+
103
+ def additional_attributes
104
+ {
105
+ :user_ip => '127.0.0.1',
106
+ :user_agent => 'Mozilla/5.0 (X11; U; Linux i686; fr-FR) AppleWebKit/534.7 (KHTML, like Gecko) Ubuntu/10.04 Chromium/7.0.517.41 Chrome/7.0.517.41 Safari/534.7',
107
+ :referrer => 'http://www.example.com/posts'
108
+ }
109
+ end
110
+
111
+ def full_spam_attributes
112
+ spam_attributes.merge(additional_attributes)
113
+ end
114
+
115
+ def full_ham_attributes
116
+ ham_attributes.merge(additional_attributes)
117
+ end
118
+
119
+ def actiondispatch_request
120
+ request = ActionDispatch::TestRequest.new(
121
+ 'HTTP_REFERER' => 'http://www.example.com/posts/1',
122
+ 'HTTP_REMOTE_ADDR' => '127.0.0.1',
123
+ 'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; U; Linux i686; fr-FR) AppleWebKit/534.7 (KHTML, like Gecko) Ubuntu/10.04 Chromium/7.0.517.41 Chrome/7.0.517.41 Safari/534.7',
124
+ 'HTTP_CONNECTION' => 'close'
125
+ )
126
+ request.remote_addr = '127.0.0.1'
127
+ request
128
+ end
60
129
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-akismet
3
3
  version: !ruby/object:Gem::Version
4
- hash: 61
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
+ - 1
7
8
  - 0
8
- - 9
9
- - 3
10
- version: 0.9.3
9
+ - 0
10
+ version: 1.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Julien Portalier
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-23 00:00:00 +02:00
18
+ date: 2010-10-24 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies: []
21
21