rakismet 0.4.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -2,6 +2,8 @@
2
2
  *.tmproj
3
3
  tmtags
4
4
  *.swp
5
+ *.swo
6
+ *.un~
5
7
  coverage
6
8
  rdoc
7
- pkg
9
+ pkg
data/README.md CHANGED
@@ -2,68 +2,72 @@ Rakismet
2
2
  ========
3
3
 
4
4
  **Akismet** (<http://akismet.com/>) is a collaborative spam filtering service.
5
- **Rakismet** is easy Akismet integration with your Rails app, including
6
- support for TypePad's AntiSpam service.
5
+ **Rakismet** is easy Akismet integration with Rails and rack apps. TypePad's
6
+ AntiSpam service and generic Akismet endpoints are supported.
7
7
 
8
+ Compatibility
9
+ =============
8
10
 
9
- Setup
10
- =====
11
+ **Rakismet 1.0.0** works with Rails 3 and other Rack-based frameworks.
12
+ **Rakismet 0.4.2** is compatible with Rails 2.
11
13
 
12
- As a plugin
13
- -----------
14
+ Getting Started
15
+ ===============
14
16
 
15
- Install with `script/plugin install git://github.com/joshfrench/rakismet`
17
+ Once you've installed the Rakismet gem and added it to your application's Gemfile,
18
+ you'll need an API key from the folks at WordPress. Head on over to
19
+ http://wordpress.com/api-keys/ and sign up for a new username.
16
20
 
17
- Rakismet installation should have created a file called rakismet.rb in
18
- config/initializers. If not, you can copy the template from:
19
- vendor/plugins/rakismet/generators/rakismet/templates/config/initializers/rakismet.rb.
21
+ Configure the Rakismet key and the URL of your application by setting the following
22
+ in an initializer or application.rb:
20
23
 
21
- As a gem
22
- --------
24
+ config.rakismet.key = 'your wordpress key'
25
+ config.rakismet.url = 'http://yourdomain.com/'
23
26
 
24
- `gem install rakismet`
27
+ If you wish to use another Akismet-compatible API provider such as TypePad's
28
+ antispam service, you'll also need to set `config.rakismet.host` to your service
29
+ provider's endpoint.
25
30
 
26
- In config/environment.rb, require the gem by adding `config.gem 'rakismet'`
27
- within the config block.
31
+ Checking For Spam
32
+ -----------------
28
33
 
29
- From your app root, run `./script/generate rakismet` to create the Rakismet
30
- initializer.
34
+ First, introduce Rakismet to your model:
31
35
 
32
- Getting Started
33
- ===============
36
+ class Comment
37
+ include Rakismet::Model
38
+ end
34
39
 
35
- Once you've installed Rakismet via your method of choice, you'll need an API
36
- key from the folks at WordPress. Head on over to http://wordpress.com/api-keys/
37
- and sign up for a new username.
40
+ With Rakismet mixed in to your model, you'll get three methods for interacting with
41
+ Akismet:
38
42
 
39
- Edit config/initializers/rakismet.rb and fill in `Rakismet::URL` and
40
- `Rakismet::KEY` with the URL of your application and the key you received
41
- from WordPress.
43
+ * `spam?`
42
44
 
43
- If you wish to use another Akismet-compatible API provider such as TypePad's
44
- antispam service, you'll also need to change the `Rakismet::HOST` to your
45
- service provider's endpoint.
45
+ Simply call `@comment.spam?` to get a true/false response. True means it's spam,
46
+ false means it's not.
46
47
 
47
- Rakismet::Model
48
- ---------------
48
+ * `ham!` and
49
+ * `spam!`
49
50
 
50
- First, introduce Rakismet to your model:
51
+ Akismet works best with your feedback. If you spot a comment that was
52
+ erroneously marked as spam, `@comment.ham!` will resubmit to Akismet, marked
53
+ as a false positive. Likewise if they missed a spammy comment,
54
+ `@comment.spam!` will resubmit marked as spam.
51
55
 
52
- class Comment
53
- include Rakismet::Model
54
- end
56
+
57
+ Configuring Your Model
58
+ ----------------------
55
59
 
56
60
  Rakismet sends the following information to the spam-hungry robots at Akismet:
57
61
 
58
62
  author : name submitted with the comment
59
63
  author_url : URL submitted with the comment
60
64
  author_email : email submitted with the comment
61
- comment_type : 'comment', 'trackback', 'pingback', or whatever you fancy
65
+ comment_type : Defaults to comment but you can set it to trackback, pingback, or something more appropriate
62
66
  content : the content submitted
63
67
  permalink : the permanent URL for the entry the comment belongs to
64
68
  user_ip : IP address used to submit this comment
65
69
  user_agent : user agent string
66
- referrer : http referer
70
+ referrer : referring URL (note the spelling)
67
71
 
68
72
  By default, Rakismet just looks for attributes or methods on your class that
69
73
  match these names. You don't have to have accessors that match these exactly,
@@ -85,72 +89,92 @@ Or you can pass in a proc, to access associations:
85
89
  :author_email => proc { author.email }
86
90
  end
87
91
 
88
- Rakismet::Controller
89
- --------------------
90
- Perhaps you want to check a comment's spam status at creation time, and you
91
- have no need to keep track of request-specific information such as the user's
92
- IP, user agent, or referrer.
92
+ You can even hard-code specific fields:
93
93
 
94
- You can add Rakismet to a controller and the IP, user agent, and referrer will
95
- be taken from the current request instead of your model instance.
94
+ class Trackback
95
+ include Rakismet::Model
96
+ rakismet_attrs :comment_type => "trackback"
97
+ end
96
98
 
97
- class MyController < ActionController::Base
98
- include Rakismet::Controller
99
- end
99
+ Optional Request Variables
100
+ --------------------------
100
101
 
101
- Since you probably won't be checking for spam in every action, Rakismet takes
102
- `:only` and `:except` options just like other filters. You can reduce overhead
103
- by specifying just the appropriate actions:
102
+ Akismet wants certain information about the request environment: remote IP, the
103
+ user agent string, and the HTTP referer when available. Normally, Rakismet
104
+ asks your model for these. Storing this information on your model allows you to
105
+ call the `spam?` method at a later time. For instance, maybe you're storing your
106
+ comments in an administrative queue or processing them with a background job.
104
107
 
105
- class MyController < ActionController::Base
106
- include Rakismet::Controller
107
- rakismet_filter :only => :create
108
- end
108
+ You don't need to have these three attributes on your model, however. If you
109
+ choose to omit them, Rakismet will instead look at the current request (if one
110
+ exists) and take the values from the request object instead.
109
111
 
110
- Checking For Spam
111
- =================
112
+ This means that if you are **not storing the request variables**, you must call
113
+ `spam?` from within the controller action that handles comment submissions. That
114
+ way the IP, user agent, and referer will belong to the person submitting the
115
+ comment. If you're not storing the request variables and you call `spam?` at a later
116
+ time, the request information will be missing or invalid and Akismet won't be
117
+ able to do its job properly.
112
118
 
113
- Rakismet provides three methods for interacting with Akismet:
119
+ If you've decided to handle the request variables yourself, you can add this to your
120
+ app initialization to disable the middleware responsible for tracking the request
121
+ information:
114
122
 
115
- * `spam?`
123
+ config.rakismet.use_middleware = false
116
124
 
117
- Simply call `@comment.spam?` to get a true/false response. True means it's spam, false means it's not. Well, usually; it's possible something went wrong
118
- and Akismet returned an error message. `@comment.spam?` will return false if
119
- this happens. You can check `@comment.akismet_response` to be certain;
120
- anything other than 'true' or 'false' means you got an error. That said, as
121
- long as you're collecting the data listed above it's probably sufficient to
122
- check `spam?` alone.
123
-
124
- Keep in mind that if you call `spam?` from within a controller action that
125
- uses the Rakismet filter, the user IP, user agent, and referrer will be taken
126
- from the current request regardless of what your model attributes are. In
127
- other words: if you're not verifying comments at the moment they're submitted,
128
- you probably want to store those attributes rather than rely on the controller
129
- methods.
130
-
131
- * `ham!` and
132
- * `spam!`
125
+ Verifying Responses
126
+ -------------------
133
127
 
134
- Akismet works best with your feedback. If you spot a comment that was
135
- erroneously marked as spam, `@comment.ham!` will resubmit to Akismet, marked
136
- as a false positive. Likewise if they missed a spammy comment,
137
- `@comment.spam!` will resubmit marked as spam.
128
+ If you want to see what's happening behind the scenes, after you call one of
129
+ `@comment.spam?`, `@comment.spam!` or `@comment.ham!` you can check
130
+ `@comment.akismet_response`.
131
+
132
+ This will contain the last response from the Akismet server. In the case of `spam?`
133
+ it should be `true` or `false.` For `spam!` and `ham!` it should be `Feedback received.`
134
+ If Akismet returned an error instead (e.g. if you left out some required information)
135
+ this will contain the error message.
136
+
137
+ FAQ
138
+ ===
139
+
140
+ Why does Akismet think all of my test data is spam?
141
+ ---------------------------------------------------
142
+
143
+ Akismet needs enough information to decide if your test data is spam or not.
144
+ Try to supply as much as possible, especially the author name and request
145
+ variables.
146
+
147
+ How can I simulate a spam submission?
148
+ -------------------------------------
149
+
150
+ Most people have the opposite problem, where Akismet doesn't think anything is
151
+ spam. The only guaranteed way to trigger a positive spam response is to set the
152
+ comment author to "viagra-test-123".
153
+
154
+ If you've done this and `spam?` is still returning false, you're probably
155
+ missing the user IP or one of the key/url config variables. One way to check is
156
+ to call `@comment.akismet_response`. If you are missing a required field or
157
+ there was another error, this will hold the Akismet error message. If your comment
158
+ was processed normally, this value will simply be `true` or `false`.
159
+
160
+ Can I use Rakismet with a different ORM or framework?
161
+ -----------------------------------------------------
162
+
163
+ Sure. Rakismet doesn't care what your persistence layer is. It will work with
164
+ Datamapper, a NoSQL store, or whatever next month's DB flavor is.
165
+
166
+ Rakismet also has no dependencies on Rails or any of its components, and only uses
167
+ a small Rack middleware object to do some of its magic. Depending on your
168
+ framework, you may have to modify this slightly and/or manually place it in your
169
+ stack.
138
170
 
139
- Updating from Rakismet < 0.4
140
- ----------------------------
141
- There were some significant changes to the API in version 0.4. This was done
142
- to make Rakismet easier to use with persistence layers other than
143
- ActiveRecord.
171
+ You'll also need to set a few config variables by hand. Instead of
172
+ `config.rakismet.key`, `config.rakismet.url`, and `config.rakismet.host`, set
173
+ these values directly with `Rakismet.key`, `Rakismet.url`, and `Rakismet.host`.
144
174
 
145
- If you're updating from an older version, please note:
175
+ ---------------------------------------------------------------------------
146
176
 
147
- * Rakismet is no longer automatically injected into ActiveRecord and
148
- ActionController. You'll need to manually include Rakismet with
149
- `include Rakismet::Model` and `include Rakismet::Controller`.
150
- * `ActiveRecord::Base#has_rakismet` now becomes
151
- `Rakismet::Model#rakismet_attrs`.
152
- * `ActionController::Base#has_rakismet` now becomes
153
- `Rakismet::Controller#rakismet_filter`.
177
+ If you have any implementation or usage questions, don't hesitate to get in
178
+ touch: josh@vitamin-j.com.
154
179
 
155
- --------------------------------------------------------------
156
180
  Copyright (c) 2008 Josh French, released under the MIT license
data/Rakefile CHANGED
@@ -17,10 +17,10 @@ rescue LoadError
17
17
  puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
18
  end
19
19
 
20
- require 'spec/rake/spectask'
21
- Spec::Rake::SpecTask.new(:spec) do |spec|
22
- spec.libs << 'lib' << 'spec'
23
- spec.spec_files = FileList['spec/**/*_spec.rb']
24
- end
20
+ #require 'spec/rake/spectask'
21
+ #Spec::Rake::SpecTask.new(:spec) do |spec|
22
+ # spec.libs << 'lib' << 'spec'
23
+ # spec.spec_files = FileList['spec/**/*_spec.rb']
24
+ #end
25
25
 
26
- task :default => :spec
26
+ #task :default => :spec
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
- :minor: 4
2
+ :minor: 0
3
3
  :build:
4
- :patch: 2
5
- :major: 0
4
+ :patch: 0
5
+ :major: 1
data/lib/rakismet.rb CHANGED
@@ -1,70 +1,88 @@
1
1
  require 'net/http'
2
2
  require 'uri'
3
+ require 'cgi'
3
4
  require 'yaml'
4
5
 
5
6
  require 'rakismet/model'
6
- require 'rakismet/filter'
7
- require 'rakismet/controller'
7
+ require 'rakismet/middleware'
8
+
9
+ require 'rakismet/railtie.rb' if defined?(Rails)
8
10
 
9
11
  module Rakismet
10
- def self.version
11
- @version ||= begin
12
- version = YAML.load_file(File.join(File.dirname(__FILE__), %w(.. VERSION.yml)))
13
- [version[:major], version[:minor], version[:patch]].join('.')
12
+ Request = Struct.new(:user_ip, :user_agent, :referrer)
13
+ Undefined = Class.new(NameError)
14
+
15
+ class << self
16
+ attr_accessor :key, :url, :host
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']
14
25
  end
15
- end
16
26
 
17
- class Base
18
- cattr_accessor :valid_key, :current_request
19
-
20
- class << self
21
- def validate_key
22
- validate_constants
23
- akismet = URI.parse(verify_url)
24
- _, valid = Net::HTTP.start(akismet.host) do |http|
25
- data = "key=#{Rakismet::KEY}&blog=#{Rakismet::URL}"
26
- http.post(akismet.path, data, Rakismet::HEADERS)
27
- end
28
- self.valid_key = (valid == 'valid')
27
+ def clear_request
28
+ @request = Request.new
29
+ end
30
+
31
+ def version
32
+ @version ||= begin
33
+ version = YAML.load_file(File.join(File.dirname(__FILE__), %w(.. VERSION.yml)))
34
+ [version[:major], version[:minor], version[:patch]].join('.')
29
35
  end
30
-
31
- def valid_key?
32
- @@valid_key == true
36
+ end
37
+
38
+ def headers
39
+ @headers ||= begin
40
+ user_agent = "Rakismet/#{Rakismet.version}"
41
+ user_agent = "Rails/#{Rails.version} | " + user_agent if defined?(Rails)
42
+ { 'User-Agent' => user_agent, 'Content-Type' => 'application/x-www-form-urlencoded' }
33
43
  end
34
-
35
- def akismet_call(function, args={})
36
- validate_constants
37
- args.merge!(:blog => Rakismet::URL)
38
- akismet = URI.parse(call_url(function))
39
- _, response = Net::HTTP.start(akismet.host) do |http|
40
- data = args.map { |k,v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&')
41
- http.post(akismet.path, data, Rakismet::HEADERS)
42
- end
43
- response
44
+ end
45
+
46
+ def validate_key
47
+ validate_config
48
+ akismet = URI.parse(verify_url)
49
+ _, valid = Net::HTTP.start(akismet.host) do |http|
50
+ data = "key=#{Rakismet.key}&blog=#{Rakismet.url}"
51
+ http.post(akismet.path, data, Rakismet.headers)
44
52
  end
45
-
46
- protected
47
-
48
- def verify_url
49
- "http://#{Rakismet::HOST}/1.1/verify-key"
50
- end
51
-
52
- def call_url(function)
53
- "http://#{Rakismet::KEY}.#{Rakismet::HOST}/1.1/#{function}"
54
- end
55
-
56
- def validate_constants
57
- raise Undefined, "Rakismet::KEY is not defined" if Rakismet::KEY.blank?
58
- raise Undefined, "Rakismet::URL is not defined" if Rakismet::URL.blank?
59
- raise Undefined, "Rakismet::HOST is not defined" if Rakismet::HOST.blank?
60
- end
53
+ @valid_key = (valid == 'valid')
54
+ end
55
+
56
+ def valid_key?
57
+ @valid_key == true
58
+ end
59
+
60
+ def akismet_call(function, args={})
61
+ validate_config
62
+ args.merge!(:blog => Rakismet.url)
63
+ akismet = URI.parse(call_url(function))
64
+ _, response = Net::HTTP.start(akismet.host) do |http|
65
+ data = args.map { |k,v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&')
66
+ http.post(akismet.path, data, Rakismet.headers)
67
+ end
68
+ response
69
+ end
70
+
71
+ protected
72
+
73
+ def verify_url
74
+ "http://#{Rakismet.host}/1.1/verify-key"
75
+ end
76
+
77
+ def call_url(function)
78
+ "http://#{Rakismet.key}.#{Rakismet.host}/1.1/#{function}"
79
+ end
80
+
81
+ def validate_config
82
+ raise Undefined, "Rakismet.key is not defined" if Rakismet.key.nil? || Rakismet.key.empty?
83
+ raise Undefined, "Rakismet.url is not defined" if Rakismet.url.nil? || Rakismet.url.empty?
84
+ raise Undefined, "Rakismet.host is not defined" if Rakismet.host.nil? || Rakismet.host.empty?
61
85
  end
62
86
  end
63
-
64
- Undefined = Class.new(NameError)
65
-
66
- HEADERS = {
67
- 'User-Agent' => "Rails/#{Rails::VERSION::STRING} | Rakismet/#{Rakismet.version}",
68
- 'Content-Type' => 'application/x-www-form-urlencoded'
69
- }
87
+
70
88
  end
@@ -0,0 +1,16 @@
1
+ module Rakismet
2
+ class Middleware
3
+
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ Rakismet.set_request_vars(env)
10
+ response = @app.call(env)
11
+ Rakismet.clear_request
12
+ response
13
+ end
14
+
15
+ end
16
+ end
@@ -4,7 +4,7 @@ module Rakismet
4
4
  def self.included(base)
5
5
  base.class_eval do
6
6
  attr_accessor :akismet_response
7
- class_inheritable_hash :akismet_attrs
7
+ class << self; attr_accessor :akismet_attrs; end
8
8
  extend ClassMethods
9
9
  include InstanceMethods
10
10
  self.rakismet_attrs
@@ -15,12 +15,12 @@ module Rakismet
15
15
  def rakismet_attrs(args={})
16
16
  self.akismet_attrs ||= {}
17
17
  [:comment_type, :author, :author_url, :author_email, :content].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
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
21
  end
22
22
  [:user_ip, :user_agent, :referrer].each do |field|
23
- self.akismet_attrs[field] = args.delete(field)
23
+ self.akismet_attrs[field] = args.delete(field) || field
24
24
  end
25
25
  args.each_pair do |f,v|
26
26
  self.akismet_attrs[f] = v
@@ -34,45 +34,47 @@ module Rakismet
34
34
  @_spam
35
35
  else
36
36
  data = akismet_data
37
-
38
- unless Rakismet::Base.current_request.nil?
39
- { :referrer => :referer, :user_ip => :remote_ip,
40
- :user_agent => :user_agent }.each_pair do |k,v|
41
- data[k] = Rakismet::Base.current_request.send(v) || ''
42
- end
43
- end
44
-
45
- self.akismet_response = Rakismet::Base.akismet_call('comment-check', data)
37
+ self.akismet_response = Rakismet.akismet_call('comment-check', data)
46
38
  @_spam = self.akismet_response == 'true'
47
39
  end
48
40
  end
49
41
 
50
42
  def spam!
51
- Rakismet::Base.akismet_call('submit-spam', akismet_data)
43
+ Rakismet.akismet_call('submit-spam', akismet_data)
52
44
  @_spam = true
53
45
  end
54
46
 
55
47
  def ham!
56
- Rakismet::Base.akismet_call('submit-ham', akismet_data)
48
+ Rakismet.akismet_call('submit-ham', akismet_data)
57
49
  @_spam = false
58
50
  end
59
51
 
60
52
  private
61
53
 
62
54
  def akismet_data
63
- self.class.akismet_attrs.keys.inject({}) do |data,attr|
64
- data.merge attr => if self.class.akismet_attrs[attr].is_a?(Proc)
65
- instance_eval(&self.class.akismet_attrs[attr])
66
- elsif !self.class.akismet_attrs[attr].nil? && respond_to?(self.class.akismet_attrs[attr])
67
- send(self.class.akismet_attrs[attr])
68
- elsif !self.class.akismet_attrs[attr].nil?
69
- self.class.akismet_attrs[attr]
55
+ akismet = self.class.akismet_attrs.keys.inject({}) do |data,attr|
56
+ mapped_field = self.class.akismet_attrs[attr]
57
+ data.merge attr => if mapped_field.is_a?(Proc)
58
+ instance_eval(&mapped_field)
59
+ elsif !mapped_field.nil? && respond_to?(mapped_field)
60
+ send(mapped_field)
61
+ elsif not [:comment_type, :author, :author_email,
62
+ :author_url, :content, :user_ip, :referrer,
63
+ :user_agent].include?(mapped_field)
64
+ # we've excluded any fields that appear to
65
+ # have their default unmapped values
66
+ mapped_field
70
67
  elsif respond_to?(attr)
71
68
  send(attr)
69
+ elsif Rakismet.request.respond_to?(attr)
70
+ Rakismet.request.send(attr)
72
71
  end
73
- end.delete_if { |k,v| v.blank? }
72
+ end
73
+ akismet.delete_if { |k,v| v.nil? || v.empty? }
74
+ akismet[:comment_type] ||= 'comment'
75
+ akismet
74
76
  end
75
77
  end
76
78
 
77
79
  end
78
- end
80
+ end
@@ -0,0 +1,19 @@
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
+ app.middleware.use Rakismet::Middleware if app.config.rakismet.use_middleware
16
+ end
17
+
18
+ end
19
+ end
data/spec/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,27 @@
1
+ require File.dirname(__FILE__) + '/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
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
2
  require 'ostruct'
3
3
 
4
4
  class AkismetModel
@@ -16,23 +16,27 @@ describe AkismetModel do
16
16
  @model = AkismetModel.new
17
17
  comment_attrs.each_pair { |k,v| @model.stub!(k).and_return(v) }
18
18
  end
19
-
19
+
20
20
  it "should have default mappings" do
21
21
  [:comment_type, :author, :author_email, :author_url, :content].each do |field|
22
22
  fieldname = field.to_s =~ %r(^comment_) ? field : "comment_#{field}".intern
23
23
  AkismetModel.akismet_attrs[fieldname].should eql(field)
24
24
  end
25
25
  end
26
-
27
- it "should have nil placeholders for optional binding variables" do
26
+
27
+ it "should have request mappings" do
28
28
  [:user_ip, :user_agent, :referrer].each do |field|
29
- AkismetModel.akismet_attrs.should have_key(field)
29
+ AkismetModel.akismet_attrs[field].should eql(field)
30
30
  end
31
31
  end
32
32
 
33
+ it "should populate comment type" do
34
+ @model.send(:akismet_data)[:comment_type].should == comment_attrs[:comment_type]
35
+ end
36
+
33
37
  mapped_params = { :comment_type => :type2, :author => :author2, :content => :content2,
34
38
  :author_email => :author_email2, :author_url => :author_url2 }
35
-
39
+
36
40
  describe override = AkismetModel.subclass('Override') { rakismet_attrs(mapped_params.dup) } do
37
41
  it "should override default mappings" do
38
42
  [:comment_type, :author, :author_url, :author_email, :content].each do |field|
@@ -46,31 +50,32 @@ describe AkismetModel do
46
50
  :referrer => :stored_referrer }
47
51
 
48
52
  describe extended = AkismetModel.subclass('Extended') { rakismet_attrs(extended_params.dup) } do
49
-
53
+
50
54
  before do
51
55
  @extended = extended.new
52
56
  attrs = comment_attrs(:stored_ip => '127.0.0.1', :stored_agent => 'RSpec', :stored_referrer => 'http://test.host/')
53
57
  attrs.each_pair { |k,v| @extended.stub!(k).and_return(v) }
58
+ Rakismet.stub(:request).and_return(empty_request)
54
59
  end
55
-
60
+
56
61
  it "should extend optional mappings" do
57
62
  [:user_ip, :user_agent, :referrer].each do |field|
58
63
  extended.akismet_attrs[field].should eql(extended_params[field])
59
64
  end
60
65
  end
61
-
66
+
62
67
  describe ".spam!" do
63
68
  it "should use stored request vars if available" do
64
- Rakismet::Base.should_receive(:akismet_call).
69
+ Rakismet.should_receive(:akismet_call).
65
70
  with('submit-spam', akismet_attrs(:user_ip => '127.0.0.1', :user_agent => 'RSpec',
66
71
  :referrer => 'http://test.host/'))
67
72
  @extended.spam!
68
73
  end
69
74
  end
70
-
75
+
71
76
  describe ".ham!" do
72
77
  it "should use stored request vars if available" do
73
- Rakismet::Base.should_receive(:akismet_call).
78
+ Rakismet.should_receive(:akismet_call).
74
79
  with('submit-ham', akismet_attrs(:user_ip => '127.0.0.1', :user_agent => 'RSpec',
75
80
  :referrer => 'http://test.host/'))
76
81
  @extended.ham!
@@ -123,75 +128,75 @@ describe AkismetModel do
123
128
  end
124
129
 
125
130
  describe ".spam?" do
126
-
127
- before do
128
- Rakismet::Base.current_request = request
129
- end
130
-
131
- it "should eval request variables in context of Base.rakismet_binding" do
132
- Rakismet::Base.should_receive(:akismet_call).
133
- with('comment-check', akismet_attrs.merge(:user_ip => '127.0.0.1',
134
- :user_agent => 'RSpec',
131
+
132
+ it "should use request variables from Rakismet.request if absent in model" do
133
+ [:user_ip, :user_agent, :referrer].each do |field|
134
+ @model.should_not respond_to(:field)
135
+ end
136
+ Rakismet.stub!(:request).and_return(request)
137
+ Rakismet.should_receive(:akismet_call).
138
+ with('comment-check', akismet_attrs.merge(:user_ip => '127.0.0.1',
139
+ :user_agent => 'RSpec',
135
140
  :referrer => 'http://test.host/referrer'))
136
141
  @model.spam?
137
142
  end
138
-
143
+
139
144
  it "should cache result of #spam?" do
140
- Rakismet::Base.should_receive(:akismet_call).once
145
+ Rakismet.should_receive(:akismet_call).once
141
146
  @model.spam?
142
147
  @model.spam?
143
148
  end
144
149
 
145
150
  it "should be true if comment is spam" do
146
- Rakismet::Base.stub!(:akismet_call).and_return('true')
151
+ Rakismet.stub!(:akismet_call).and_return('true')
147
152
  @model.should be_spam
148
153
  end
149
-
154
+
150
155
  it "should be false if comment is not spam" do
151
- Rakismet::Base.stub!(:akismet_call).and_return('false')
156
+ Rakismet.stub!(:akismet_call).and_return('false')
152
157
  @model.should_not be_spam
153
158
  end
154
-
155
- it "should set last_akismet_response" do
156
- Rakismet::Base.stub!(:akismet_call).and_return('response')
159
+
160
+ it "should set akismet_response" do
161
+ Rakismet.stub!(:akismet_call).and_return('response')
157
162
  @model.spam?
158
163
  @model.akismet_response.should eql('response')
159
164
  end
160
165
 
161
166
  it "should not throw an error if request vars are missing" do
162
- Rakismet::Base.current_request = empty_request
167
+ Rakismet.stub!(:request).and_return(empty_request)
163
168
  lambda { @model.spam? }.should_not raise_error(NoMethodError)
164
169
  end
165
170
  end
166
-
171
+
167
172
  describe StoredParams do
168
173
  before do
169
- Rakismet::Base.current_request = nil
170
174
  @model = StoredParams.new
171
175
  comment_attrs.each_pair { |k,v| @model.stub!(k).and_return(v) }
172
176
  end
173
177
 
174
- it "should use local values if Rakismet binding is not present" do
175
- @model.user_ip = '127.0.0.1'
176
- @model.user_agent = 'RSpec'
177
- @model.referrer = 'http://test.host/referrer'
178
+ it "should use local values even if Rakismet.request is populated" do
179
+ Rakismet.stub!(:request).and_return(request)
180
+ @model.user_ip = '192.168.0.1'
181
+ @model.user_agent = 'Rakismet'
182
+ @model.referrer = 'http://localhost/referrer'
178
183
 
179
- Rakismet::Base.should_receive(:akismet_call).
180
- with('comment-check', akismet_attrs.merge(:user_ip => '127.0.0.1',
181
- :user_agent => 'RSpec',
182
- :referrer => 'http://test.host/referrer'))
184
+ Rakismet.should_receive(:akismet_call).
185
+ with('comment-check', akismet_attrs.merge(:user_ip => '192.168.0.1',
186
+ :user_agent => 'Rakismet',
187
+ :referrer => 'http://localhost/referrer'))
183
188
  @model.spam?
184
189
  end
185
190
  end
186
191
 
187
192
  describe ".spam!" do
188
193
  it "should call Base.akismet_call with submit-spam" do
189
- Rakismet::Base.should_receive(:akismet_call).with('submit-spam', akismet_attrs)
194
+ Rakismet.should_receive(:akismet_call).with('submit-spam', akismet_attrs)
190
195
  @model.spam!
191
196
  end
192
197
 
193
198
  it "should mutate #spam?" do
194
- Rakismet::Base.stub!(:akismet_call)
199
+ Rakismet.stub!(:akismet_call)
195
200
  @model.instance_variable_set(:@_spam, false)
196
201
  @model.spam!
197
202
  @model.should be_spam
@@ -200,42 +205,42 @@ describe AkismetModel do
200
205
 
201
206
  describe ".ham!" do
202
207
  it "should call Base.akismet_call with submit-ham" do
203
- Rakismet::Base.should_receive(:akismet_call).with('submit-ham', akismet_attrs)
208
+ Rakismet.should_receive(:akismet_call).with('submit-ham', akismet_attrs)
204
209
  @model.ham!
205
210
  end
206
211
 
207
212
  it "should mutate #spam?" do
208
- Rakismet::Base.stub!(:akismet_call)
213
+ Rakismet.stub!(:akismet_call)
209
214
  @model.instance_variable_set(:@_spam, true)
210
215
  @model.ham!
211
216
  @model.should_not be_spam
212
217
  end
213
218
  end
214
-
219
+
215
220
  private
216
-
221
+
217
222
  def comment_attrs(attrs={})
218
223
  { :comment_type => 'test', :author => 'Rails test',
219
224
  :author_email => 'test@test.host', :author_url => 'test.host',
220
- :content => 'comment content', :blog => Rakismet::URL }.merge(attrs)
225
+ :content => 'comment content', :blog => Rakismet.url }.merge(attrs)
221
226
  end
222
-
227
+
223
228
  def akismet_attrs(attrs={})
224
229
  { :comment_type => 'test', :comment_author_email => 'test@test.host',
225
230
  :comment_author => 'Rails test', :comment_author_url => 'test.host',
226
231
  :comment_content => 'comment content' }.merge(attrs)
227
232
  end
228
-
229
- def request
230
- OpenStruct.new(:remote_ip => '127.0.0.1',
233
+
234
+ let(:request) {
235
+ OpenStruct.new(:user_ip => '127.0.0.1',
231
236
  :user_agent => 'RSpec',
232
- :referer => 'http://test.host/referrer')
233
- end
237
+ :referrer => 'http://test.host/referrer')
238
+ }
234
239
 
235
- def empty_request
236
- OpenStruct.new(:remote_ip => nil,
240
+ let(:empty_request) {
241
+ OpenStruct.new(:user_ip => nil,
237
242
  :user_agent => nil,
238
- :referer => nil)
239
- end
243
+ :referrer => nil)
244
+ }
240
245
 
241
- end
246
+ end
@@ -0,0 +1,80 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Rakismet do
4
+
5
+ let(:http) { double(:http, :to_ary => [nil, 'akismet response']).as_null_object }
6
+
7
+ after do
8
+ Rakismet.key = 'dummy-key'
9
+ Rakismet.url = 'test.localhost'
10
+ Rakismet.host = 'endpoint.localhost'
11
+ end
12
+
13
+ describe ".validate_config" do
14
+ it "should raise an error if key is not found" do
15
+ Rakismet.key = ''
16
+ lambda { Rakismet.send(:validate_config) }.should raise_error(Rakismet::Undefined)
17
+ end
18
+
19
+ it "should raise an error if url is not found" do
20
+ Rakismet.url = ''
21
+ lambda { Rakismet.send(:validate_config) }.should raise_error(Rakismet::Undefined)
22
+ end
23
+
24
+ it "should raise an error if host is not found" do
25
+ Rakismet.host = ''
26
+ lambda { Rakismet.send(:validate_config) }.should raise_error(Rakismet::Undefined)
27
+ end
28
+ end
29
+
30
+ describe ".validate_key" do
31
+ it "should set @@valid_key = true if key is valid" do
32
+ Net::HTTP.stub!(:start).and_return([nil, 'valid'])
33
+ Rakismet.validate_key
34
+ Rakismet.valid_key?.should be_true
35
+ end
36
+
37
+ it "should set @@valid_key = false if key is invalid" do
38
+ Net::HTTP.stub!(:start).and_return([nil, 'invalid'])
39
+ Rakismet.validate_key
40
+ Rakismet.valid_key?.should be_false
41
+ end
42
+
43
+ it "should build url with host" do
44
+ host = "api.antispam.typepad.com"
45
+ Rakismet.host = host
46
+ Net::HTTP.should_receive(:start).with(host).and_yield(http)
47
+ Rakismet.validate_key
48
+ end
49
+ end
50
+
51
+ describe ".akismet_call" do
52
+ before do
53
+ Net::HTTP.stub(:start).and_yield(http)
54
+ end
55
+
56
+ it "should build url with API key for the correct host" do
57
+ host = 'api.antispam.typepad.com'
58
+ Rakismet.host = host
59
+ Net::HTTP.should_receive(:start).with("#{Rakismet.key}.#{host}")
60
+ Rakismet.send(:akismet_call, 'bogus-function')
61
+ end
62
+
63
+ it "should post data to named function" do
64
+ http.should_receive(:post).with('/1.1/bogus-function', %r(foo=#{CGI.escape 'escape//this'}), Rakismet.headers)
65
+ Rakismet.send(:akismet_call, 'bogus-function', { :foo => 'escape//this' })
66
+ end
67
+
68
+ it "should return response.body" do
69
+ #Net::HTTP.stub!(:start).and_return([nil, 'akismet response'])
70
+ Rakismet.send(:akismet_call, 'bogus-function').should eql('akismet response')
71
+ end
72
+
73
+ it "should build query string when params are nil" do
74
+ lambda {
75
+ Rakismet.send(:akismet_call, 'bogus-function', { :nil_param => nil })
76
+ }.should_not raise_error(NoMethodError)
77
+ end
78
+ end
79
+
80
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,21 +1,10 @@
1
- ENV["RAILS_ENV"] = "test"
2
- require File.expand_path(File.dirname(__FILE__) + "/../../../../config/environment")
3
- require 'spec'
4
- require 'spec/rails'
5
-
6
- Spec::Runner.configure do |config|
1
+ require File.expand_path "../lib/rakismet"
7
2
 
3
+ RSpec.configure do |config|
4
+ config.mock_with :rspec
8
5
  end
9
6
 
10
7
  class Class
11
- # Creates a new subclass of self, with a name "under" our own name. Example:
12
- #
13
- # x = Foo::Bar.subclass('Zap'){}
14
- # x.name # => Foo::Bar::Zap_1
15
- # x.superclass.name # => Foo::Bar
16
- #
17
- # Removed from RSpec after 1.1.something; reproduced here because much of the
18
- # spec suite was already written with dynamic class creation.
19
8
  def subclass(base_name, &body)
20
9
  klass = Class.new(self)
21
10
  class_name = "#{self.name}_#{base_name}"
@@ -25,4 +14,4 @@ class Class
25
14
  klass.instance_eval(&body)
26
15
  klass
27
16
  end
28
- end
17
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rakismet
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
+ - 1
7
8
  - 0
8
- - 4
9
- - 2
10
- version: 0.4.2
9
+ - 0
10
+ version: 1.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Josh French
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-22 00:00:00 -04:00
18
+ date: 2010-10-23 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -34,20 +34,15 @@ files:
34
34
  - README.md
35
35
  - Rakefile
36
36
  - VERSION.yml
37
- - generators/rakismet/rakismet_generator.rb
38
- - generators/rakismet/templates/config/initializers/rakismet.rb
39
- - install.rb
40
37
  - lib/rakismet.rb
41
- - lib/rakismet/controller.rb
42
- - lib/rakismet/filter.rb
38
+ - lib/rakismet/middleware.rb
43
39
  - lib/rakismet/model.rb
44
- - spec/controllers/rakismet_controller_spec.rb
45
- - spec/models/base_spec.rb
46
- - spec/models/rakismet_filter_spec.rb
47
- - spec/models/rakismet_model_spec.rb
48
- - spec/spec.opts
40
+ - lib/rakismet/railtie.rb
41
+ - spec/.rspec
42
+ - spec/rakismet_middleware_spec.rb
43
+ - spec/rakismet_model_spec.rb
44
+ - spec/rakismet_spec.rb
49
45
  - spec/spec_helper.rb
50
- - uninstall.rb
51
46
  has_rdoc: true
52
47
  homepage: http://github.com/joshfrench/rakismet
53
48
  licenses: []
@@ -83,8 +78,7 @@ signing_key:
83
78
  specification_version: 3
84
79
  summary: Akismet and TypePad AntiSpam integration for Rails.
85
80
  test_files:
86
- - spec/controllers/rakismet_controller_spec.rb
87
- - spec/models/base_spec.rb
88
- - spec/models/rakismet_filter_spec.rb
89
- - spec/models/rakismet_model_spec.rb
81
+ - spec/rakismet_middleware_spec.rb
82
+ - spec/rakismet_model_spec.rb
83
+ - spec/rakismet_spec.rb
90
84
  - spec/spec_helper.rb
@@ -1,7 +0,0 @@
1
- class RakismetGenerator < Rails::Generator::Base
2
- def manifest
3
- record do |m|
4
- m.file "config/initializers/rakismet.rb", "config/initializers/rakismet.rb"
5
- end
6
- end
7
- end
@@ -1,3 +0,0 @@
1
- Rakismet::KEY = ''
2
- Rakismet::URL = ''
3
- Rakismet::HOST = 'rest.akismet.com'
data/install.rb DELETED
@@ -1,7 +0,0 @@
1
- File.open(File.join(RAILS_ROOT, %w(config initializers rakismet.rb)) , 'w') do |f|
2
- f.puts "Rakismet::KEY = ''"
3
- f.puts "Rakismet::URL = ''"
4
- f.puts "Rakismet::HOST = 'rest.akismet.com'"
5
- end
6
-
7
- puts "If you're updating from Rakismet < 0.4, please see the README for important changes to the API."
@@ -1,20 +0,0 @@
1
- module Rakismet
2
- module Controller
3
-
4
- def self.included(base)
5
- base.class_eval do
6
- extend ClassMethods
7
- around_filter Rakismet::Filter
8
- end
9
- end
10
-
11
- module ClassMethods
12
- def rakismet_filter(opts={})
13
- skip_filter Rakismet::Filter # in case we're inheriting/overriding an existing Rakismet filter
14
- opts.assert_valid_keys(:only, :except)
15
- self.around_filter Rakismet::Filter, opts
16
- end
17
- end
18
-
19
- end
20
- end
@@ -1,10 +0,0 @@
1
- class Rakismet::Filter
2
- def self.filter(controller)
3
- begin
4
- Rakismet::Base.current_request = controller.request
5
- yield
6
- ensure
7
- Rakismet::Base.current_request = nil
8
- end
9
- end
10
- end
@@ -1,43 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
2
-
3
- ActionController::Routing::Routes.draw do |map|
4
- map.connect ':controller/:action/:id'
5
- end
6
-
7
- class StubController < ActionController::Base
8
- include Rakismet::Controller
9
- def one ; render :nothing => true; end
10
- def two ; render :nothing => true; end
11
- end
12
-
13
- describe StubController do
14
- it "should add around_filter" do
15
- StubController.filter_chain.map(&:method).should include(Rakismet::Filter)
16
- end
17
- end
18
-
19
- describe StubController.subclass('OnlyActions') { rakismet_filter(:only => :one) } do
20
-
21
- it "should add around filter to specified actions" do
22
- Rakismet::Base.should_receive(:current_request=).twice
23
- get :one
24
- end
25
-
26
- it "should not add around filter to unspecified actions" do
27
- Rakismet::Base.should_not_receive(:current_request=)
28
- get :two
29
- end
30
- end
31
-
32
- describe StubController.subclass('ExceptActions') { rakismet_filter(:except => :one) } do
33
-
34
- it "should not add around filter to specified actions" do
35
- Rakismet::Base.should_not_receive(:current_request=)
36
- get :one
37
- end
38
-
39
- it "should add around filter to other actions" do
40
- Rakismet::Base.should_receive(:current_request=).twice
41
- get :two
42
- end
43
- end
@@ -1,77 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
2
-
3
- describe Rakismet::Base do
4
-
5
- before :all do
6
- load File.join(RAILS_ROOT, 'config', 'initializers', 'rakismet.rb')
7
- end
8
-
9
- describe ".validate_constants" do
10
- it "should raise an error if key is not found" do
11
- Rakismet::KEY = ""
12
- lambda { Rakismet::Base.send(:validate_constants) }.should raise_error(Rakismet::Undefined)
13
- end
14
-
15
- it "should raise an error if url is not found" do
16
- Rakismet::URL = ""
17
- lambda { Rakismet::Base.send(:validate_constants) }.should raise_error(Rakismet::Undefined)
18
- end
19
-
20
- it "should raise an error if host is not found" do
21
- Rakismet::HOST = ""
22
- lambda { Rakismet::Base.send(:validate_constants) }.should raise_error(Rakismet::Undefined)
23
- end
24
- end
25
-
26
- describe ".validate_key" do
27
- it "should set @@valid_key = true if key is valid" do
28
- Net::HTTP.stub!(:start).and_return([nil, 'valid'])
29
- Rakismet::Base.validate_key
30
- Rakismet::Base.valid_key?.should be_true
31
- end
32
-
33
- it "should set @@valid_key = false if key is invalid" do
34
- Net::HTTP.stub!(:start).and_return([nil, 'invalid'])
35
- Rakismet::Base.validate_key
36
- Rakismet::Base.valid_key?.should be_false
37
- end
38
-
39
- it "should build url with host" do
40
- host = "api.antispam.typepad.com"
41
- Rakismet::HOST = host
42
- Net::HTTP.should_receive(:start).with(host).and_yield(mock(:http).as_null_object)
43
- Rakismet::Base.validate_key
44
- end
45
- end
46
-
47
- describe ".akismet_call" do
48
- before do
49
- @http = mock(:http)
50
- Net::HTTP.stub!(:start).and_yield(@http)
51
- end
52
-
53
- it "should build url with API key for the correct host" do
54
- host = "api.antispam.typepad.com"
55
- Rakismet::HOST = host
56
- Net::HTTP.should_receive(:start).with("#{Rakismet::KEY}.#{host}").and_yield(mock(:http).as_null_object)
57
- Rakismet::Base.send(:akismet_call, 'bogus-function')
58
- end
59
-
60
- it "should post data to named function" do
61
- @http.should_receive(:post).with('/1.1/bogus-function', %r(foo=#{CGI.escape 'escape//this'}), Rakismet::HEADERS)
62
- Rakismet::Base.send(:akismet_call, 'bogus-function', { :foo => 'escape//this' })
63
- end
64
-
65
- it "should return response.body" do
66
- Net::HTTP.stub!(:start).and_return([nil, 'akismet response'])
67
- Rakismet::Base.send(:akismet_call, 'bogus-function').should eql('akismet response')
68
- end
69
-
70
- it "should build query string when params are nil" do
71
- lambda {
72
- Rakismet::Base.send(:akismet_call, 'bogus-function', { :nil_param => nil })
73
- }.should_not raise_error(NoMethodError)
74
- end
75
- end
76
-
77
- end
@@ -1,24 +0,0 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
2
-
3
- Rakismet::TestingError = Class.new(StandardError)
4
-
5
- describe Rakismet::Base do
6
- before do
7
- @request = mock('request')
8
- @controller = mock('controller', :request => @request)
9
- end
10
-
11
- it "should set Rakismet::Base.current_request" do
12
- Rakismet::Base.should_receive(:current_request=).with(@request).ordered
13
- Rakismet::Base.should_receive(:current_request=).with(nil).ordered
14
- Rakismet::Filter.filter(@controller, &lambda{})
15
- end
16
-
17
- it "should not retain the request object in case of error" do
18
- begin
19
- Rakismet::Filter.filter(@controller, &lambda{ raise Rakismet::TestingError })
20
- rescue Rakismet::TestingError
21
- Rakismet::Base.current_request.should be_nil
22
- end
23
- end
24
- end
data/spec/spec.opts DELETED
@@ -1,6 +0,0 @@
1
- --colour
2
- --format
3
- progress
4
- --loadby
5
- mtime
6
- --reverse
data/uninstall.rb DELETED
@@ -1 +0,0 @@
1
- File.delete(File.join(RAILS_ROOT, %w(config initializers rakismet.rb)))