acts_as_textcaptcha 2.2.2 → 3.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.
@@ -1,9 +1,25 @@
1
1
  module ActsAsTextcaptcha
2
2
  module TextcaptchaHelper
3
3
 
4
- # generates a spam question and possible answers for a model, answers are stored in session[:possible_answers]
5
- def spamify(model)
6
- session[:possible_answers] = model.generate_spam_question unless model.validate_spam_answer
4
+ # builds html fields for spam question, answer and hidden encrypted spam answers
5
+ def textcaptcha_fields(f, &block)
6
+ model = f.object
7
+ captcha_html = ''
8
+ if model.perform_textcaptcha?
9
+ captcha_html += f.hidden_field(:spam_answers)
10
+ if model.spam_answer
11
+ captcha_html += f.hidden_field(:spam_answer)
12
+ elsif model.spam_question
13
+ captcha_html += capture(&block)
14
+ end
15
+ end
16
+
17
+ # Rails 2 compatability
18
+ if Rails::VERSION::MAJOR < 3
19
+ concat captcha_html, &block.binding
20
+ else
21
+ captcha_html.html_safe
22
+ end
7
23
  end
8
24
  end
9
- end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module ActsAsTextcaptcha
2
- VERSION = "2.2.2"
3
- end
2
+ VERSION = "3.0.0"
3
+ end
@@ -1,23 +1,26 @@
1
+ require 'bcrypt'
2
+
1
3
  namespace :textcaptcha do
2
- desc "Adds a textcaptcha.yml template config file to ./config "
3
- task :generate_config do
4
4
 
5
+ desc "Creates a template config file in config/textcaptcha.yml"
6
+ task :config do
5
7
  src = File.join(File.dirname(__FILE__), '../..', 'config', 'textcaptcha.yml')
6
8
  dest = File.join(Rails.root, 'config', 'textcaptcha.yml')
7
9
  if File.exist?(dest)
8
- puts "\ntextcaptcha config file: #{dest}\n ... already exists. Aborting.\n\n"
10
+ puts "\nOoops, a textcaptcha config file at #{dest} already exists ... aborting.\n\n"
9
11
  else
10
- config_file = ''
12
+ config = ''
13
+ salt = BCrypt::Engine.generate_salt
11
14
  f = File.open(src, 'r')
12
- f.each_line { |line| config_file += line }
13
- config_file.gsub!(/api\_key\:(.+)$/, 'api_key: # get one at http://textcaptcha.com' )
14
- config_file.gsub!(/bcrypt\_salt\:(.+)$/, "bcrypt_salt: #{BCrypt::Engine.generate_salt}" ) if defined?(BCrypt)
15
+ f.each_line { |line| config += line }
16
+ config.gsub!(/RAKE_GENERATED_SALT_PLACEHOLDER/, salt)
17
+ config.gsub!(/ api_key:(.*)# for gem test purposes only$/, " api_key: PASTE_YOUR_TEXTCAPCHA_API_KEY_HERE")
18
+ config.gsub!(/ bcrypt_salt:(.*)# for gem test purposes only$/, " bcrypt_salt: #{salt}")
15
19
 
16
20
  f = File.new(dest, 'w')
17
- f.write(config_file)
21
+ f.write(config)
18
22
  f.close
19
- puts "\ntextcaptcha.yml generated at #{dest} (with a new BCrypt salt).\nNOTE: edit this file and add your textcaptcha api key (from http://textcaptcha.com)"
23
+ puts "\ntextcaptcha.yml generated at #{dest} (with a new BCrypt salt)\nNOTE: edit this file and add your textcaptcha api key, grab one from http://textcaptcha.com/api\n\n"
20
24
  end
21
-
22
25
  end
23
- end
26
+ end
@@ -15,4 +15,4 @@ ActiveRecord::Schema.define(:version => 0) do
15
15
  create_table :notes, :force => true do |t|
16
16
  t.string :name
17
17
  end
18
- end
18
+ end
@@ -0,0 +1,27 @@
1
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)+'./../lib'))
2
+
3
+ ENV['RAILS_ENV'] = 'test'
4
+
5
+ if ENV['COVERAGE']
6
+ require "simplecov"
7
+ SimpleCov.start do
8
+ add_filter '/test/'
9
+ end
10
+ SimpleCov.at_exit do
11
+ SimpleCov.result.format!
12
+ `open ./coverage/index.html` if RUBY_PLATFORM =~ /darwin/
13
+ end
14
+ end
15
+
16
+ require 'minitest/autorun'
17
+ require 'fakeweb'
18
+
19
+ require 'active_record'
20
+ require 'rails'
21
+
22
+ require 'acts_as_textcaptcha'
23
+ require './test/test_models'
24
+
25
+ # load and initialize test db schema
26
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'acts_as_textcaptcha.sqlite3.db')
27
+ load(File.dirname(__FILE__) + "/schema.rb")
@@ -0,0 +1,42 @@
1
+ # models for use in tests
2
+
3
+ class Widget < ActiveRecord::Base
4
+ # uses textcaptcha.yml file for configuration
5
+ acts_as_textcaptcha
6
+ end
7
+
8
+ class Comment < ActiveRecord::Base
9
+ # inline options (symbol keys) with api_key only
10
+ acts_as_textcaptcha :api_key => '8u5ixtdnq9csc84cok0owswgo',
11
+ :bcrypt_salt => '$2a$10$j0bmycH.SVfD1b5mpEGPpe'
12
+ end
13
+
14
+ class Review < ActiveRecord::Base
15
+ # inline options with all possible options
16
+ acts_as_textcaptcha 'api_key' => '8u5ixtdnq9csc84cok0owswgo',
17
+ 'bcrypt_salt' => '$2a$10$j0bmycH.SVfD1b5mpEGPpe',
18
+ 'bcrypt_cost' => '3',
19
+ 'questions' => [{ 'question' => 'The green hat is what color?', 'answers' => 'green' }]
20
+ end
21
+
22
+ class Note < ActiveRecord::Base
23
+ # inline options (string keys) with user defined questions only (no textcaptcha service)
24
+ acts_as_textcaptcha 'questions' => [{ 'question' => '1+1', 'answers' => '2,two' }],
25
+ 'bcrypt_salt' => '$2a$10$j0bmycH.SVfD1b5mpEGPpe'
26
+
27
+ # allows toggling perform_textcaptcha on/off (default on)
28
+ attr_accessor :turn_off_captcha
29
+
30
+ def perform_textcaptcha?
31
+ !turn_off_captcha
32
+ end
33
+ end
34
+
35
+ class Contact
36
+ # non active record object (symbol keys), no API used
37
+ include ActiveModel::Validations
38
+ include ActiveModel::Conversion
39
+ extend ActsAsTextcaptcha::Textcaptcha
40
+ acts_as_textcaptcha :questions => [{ :question => 'one+1', :answers => '2,two' }],
41
+ :bcrypt_salt => '$2a$10$j0bmycH.SVfD1b5mpEGPpe'
42
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path(File.dirname(__FILE__)+'/test_helper')
2
+ require 'action_controller'
3
+ require 'action_view'
4
+
5
+ class NotesController < ActionController::Base; end
6
+
7
+ class Template < ActionView::Base
8
+ def protect_against_forgery?; false; end
9
+ end
10
+
11
+
12
+ describe 'TextcaptchaHelper' do
13
+
14
+ before(:each) do
15
+ @controller = NotesController.new
16
+ @note = Note.new
17
+ @note.textcaptcha
18
+ end
19
+
20
+ def render_template(assigns)
21
+ template = <<-ERB
22
+ <%= form_for(@note, :url => '/') do |f| %>
23
+ <%= textcaptcha_fields(f) do %>
24
+ <div class="field textcaptcha">
25
+ <%= f.label :spam_answer, @note.spam_question %><br/>
26
+ <%= f.text_field :spam_answer, :value => '' %>
27
+ </div>
28
+ <% end %>
29
+ <% end %>
30
+ ERB
31
+
32
+ Template.new([], assigns, @controller).render(:inline => template)
33
+ end
34
+
35
+ it 'should render question and answer fields, with hidden spam_answers field' do
36
+ html = render_template({:note => @note})
37
+
38
+ html.must_match /\<label for\=\"note\_spam\_answer\"\>1\+1\<\/label\>/
39
+ html.must_match /\<input id\=\"note_spam_answers\" name\=\"note\[spam\_answers\]\" type\=\"hidden\" value\=\"(.*)\" \/\>/
40
+ end
41
+
42
+ it 'should render hidden answer and spam_answer fields when question has been answered OK (and not ask question)' do
43
+ @note.spam_answer = 2
44
+ html = render_template({:note => @note})
45
+
46
+ html.wont_match /\<label for\=\"note\_spam\_answer\"\>1\+1\<\/label\>/
47
+ html.must_match /\<input id\=\"note_spam_answers\" name\=\"note\[spam\_answers\]\" type\=\"hidden\" value\=\"(.*)\" \/\>/
48
+ html.must_match /\<input id\=\"note_spam_answer\" name\=\"note\[spam_answer\]\" type\=\"hidden\" value\=\"2\" \/\>/
49
+ end
50
+ end
@@ -0,0 +1,188 @@
1
+ require File.expand_path(File.dirname(__FILE__)+'/test_helper')
2
+
3
+ describe 'Textcaptcha' do
4
+
5
+ describe 'validations' do
6
+
7
+ before(:each) do
8
+ @note = Note.new
9
+ @note.textcaptcha
10
+ end
11
+
12
+ it 'should validate an ActiveRecord object (with multiple correct answers)' do
13
+ @note.spam_question.must_equal('1+1')
14
+ @note.valid?.must_equal false
15
+ @note.errors[:spam_answer].first.must_equal('is incorrect, try another question instead')
16
+
17
+ @note.spam_answer = 'two'
18
+ @note.valid?.must_equal true
19
+ @note.errors[:spam_answer].must_be_empty
20
+
21
+ @note.spam_answer = '2'
22
+ @note.valid?.must_equal true
23
+ @note.errors[:spam_answer].must_be_empty
24
+ end
25
+
26
+ it 'should strip whitespace and downcase spam answer' do
27
+ @note.spam_answer = ' tWo '
28
+ @note.valid?.must_equal true
29
+ @note.errors[:spam_answer].must_be_empty
30
+ end
31
+
32
+ it 'should always be valid when record has been saved' do
33
+ @note.spam_answer = '2'
34
+ @note.save!
35
+ @note.textcaptcha
36
+
37
+ @note.spam_answer = 'wrong answer'
38
+ @note.new_record?.must_equal false
39
+ @note.valid?.must_equal true
40
+ @note.errors[:spam_answer].must_be_empty
41
+ end
42
+
43
+ it 'should always be valid when perform_textcaptcha? is false' do
44
+ @note.turn_off_captcha = true
45
+ @note.valid?.must_equal true
46
+ @note.errors[:spam_answer].must_be_empty
47
+
48
+ @note.save.must_equal true
49
+ end
50
+
51
+ it 'should validate a non ActiveRecord object' do
52
+ @contact = Contact.new
53
+ @contact.textcaptcha
54
+
55
+ @contact.spam_question.must_equal('one+1')
56
+ @contact.spam_answer = 'wrong'
57
+ @contact.valid?.must_equal false
58
+
59
+ @contact.spam_answer = 'two'
60
+ @contact.valid?.must_equal true
61
+ @contact.errors[:spam_answer].must_be_empty
62
+ end
63
+ end
64
+
65
+ describe 'encryption' do
66
+
67
+ before(:each) do
68
+ @note = Note.new
69
+ end
70
+
71
+ it 'should encrypt spam_answers (joined by - seperator) MD5 digested and using BCrypt engine with salt' do
72
+ @note.spam_answers.must_be_nil
73
+ @note.textcaptcha
74
+ encrypted_answers = [2,' TwO '].collect { |answer| BCrypt::Engine.hash_secret(Digest::MD5.hexdigest(answer.to_s.strip.downcase), '$2a$10$j0bmycH.SVfD1b5mpEGPpe', 1) }.join('-')
75
+ @note.spam_answers.must_equal('$2a$10$j0bmycH.SVfD1b5mpEGPpePFe1wBxOn7Brr9lMuLRxv6lg4ZYjJ22-$2a$10$j0bmycH.SVfD1b5mpEGPpe8v5mqqpDaExuS/hZu8Xkq8krYL/T8P.')
76
+ @note.spam_answers.must_equal(encrypted_answers)
77
+ end
78
+
79
+ it 'should raise error if bcyrpt salt is invalid' do
80
+ @note.textcaptcha_config[:bcrypt_salt] = 'bad salt'
81
+ proc { @note.textcaptcha }.must_raise BCrypt::Errors::InvalidSalt
82
+ @note.textcaptcha_config[:bcrypt_salt] ='$2a$10$j0bmycH.SVfD1b5mpEGPpe'
83
+ end
84
+ end
85
+
86
+ describe 'textcaptcha API' do
87
+
88
+ after(:each) do
89
+ FakeWeb.clean_registry
90
+ end
91
+
92
+ it 'should generate spam question from the service' do
93
+ @review = Review.new
94
+
95
+ @review.textcaptcha
96
+ @review.spam_question.wont_be_nil
97
+ @review.spam_question.wont_equal('The green hat is what color?')
98
+
99
+ @review.spam_answers.wont_be_nil
100
+
101
+ @review.valid?.must_equal false
102
+ @review.errors[:spam_answer].first.must_equal('is incorrect, try another question instead')
103
+ end
104
+
105
+ it 'should parse a single answer from XML response' do
106
+ @review = Review.new
107
+ question = 'If tomorrow is Saturday, what day is today?'
108
+ body = "<captcha><question>#{question}</question><answer>f6f7fec07f372b7bd5eb196bbca0f3f4</answer></captcha>"
109
+ FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :body => body)
110
+
111
+ @review.textcaptcha
112
+ @review.spam_question.must_equal(question)
113
+ @review.spam_answers.must_equal('$2a$10$j0bmycH.SVfD1b5mpEGPpecvhlumIBvWXI4HQWk0xa74DebZDx772')
114
+ @review.spam_answers.split('-').length.must_equal(1)
115
+ end
116
+
117
+ it 'should parse multiple answers from XML response' do
118
+ @review = Review.new
119
+ question = 'If tomorrow is Saturday, what day is today?'
120
+ body = "<captcha><question>#{question}</question><answer>1</answer><answer>2</answer><answer>3</answer></captcha>"
121
+ FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :body => body)
122
+
123
+ @review.textcaptcha
124
+ @review.spam_question.must_equal(question)
125
+ @review.spam_answers.split('-').length.must_equal(3)
126
+ end
127
+
128
+ describe 'service is unavailable' do
129
+
130
+ describe 'should fallback to a user defined question' do
131
+
132
+ before(:each) do
133
+ @review = Review.new
134
+ end
135
+
136
+ it 'when errors occur' do
137
+ [SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Errno::ECONNREFUSED, Errno::ETIMEDOUT,
138
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError, URI::InvalidURIError].each do |error|
139
+ FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :exception => error)
140
+ @review.textcaptcha
141
+ @review.spam_question.must_equal('The green hat is what color?')
142
+ @review.spam_answers.wont_be_nil
143
+ end
144
+ end
145
+
146
+ it 'when response is OK but body cannot be parsed as XML' do
147
+ FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :body => 'here be gibberish')
148
+ @review.textcaptcha
149
+ @review.spam_question.must_equal('The green hat is what color?')
150
+ @review.spam_answers.wont_be_nil
151
+ end
152
+
153
+ it 'when response is OK but empty' do
154
+ FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :body => '')
155
+ @review.textcaptcha
156
+ @review.spam_question.must_equal('The green hat is what color?')
157
+ @review.spam_answers.wont_be_nil
158
+ end
159
+ end
160
+ end
161
+
162
+ it 'should not generate any spam question or answer when no user defined questions set' do
163
+ @comment = Comment.new
164
+
165
+ FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :exception => SocketError)
166
+ @comment.textcaptcha
167
+ @comment.spam_question.must_equal 'ActsAsTextcaptcha >> no API key (or questions) set and/or the textcaptcha service is currently unavailable (answer ok to bypass)'
168
+ @comment.spam_answers.must_equal 'ok'
169
+ end
170
+ end
171
+
172
+ describe 'configuration' do
173
+
174
+ it 'should be configured with inline hash' do
175
+ Review.textcaptcha_config.must_equal({ :api_key => '8u5ixtdnq9csc84cok0owswgo',
176
+ :bcrypt_salt => '$2a$10$j0bmycH.SVfD1b5mpEGPpe',
177
+ :bcrypt_cost => '3',
178
+ :questions => [{ 'question' => 'The green hat is what color?', 'answers' => 'green' }]})
179
+ end
180
+
181
+ it 'should be configured with textcaptcha.yml' do
182
+ Widget.textcaptcha_config[:api_key].must_equal '6eh1co0j12mi2ogcoggkkok4o'
183
+ Widget.textcaptcha_config[:bcrypt_salt].must_equal '$2a$10$qhSefD6gKtmq6M0AzXk4CO'
184
+ Widget.textcaptcha_config[:bcrypt_cost].must_equal 1
185
+ Widget.textcaptcha_config[:questions].length.must_equal 10
186
+ end
187
+ end
188
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_textcaptcha
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 3.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,23 +9,23 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-07-26 00:00:00.000000000 +01:00
12
+ date: 2011-08-06 00:00:00.000000000 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bcrypt-ruby
17
- requirement: &2152243920 !ruby/object:Gem::Requirement
17
+ requirement: &2156333440 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
21
21
  - !ruby/object:Gem::Version
22
- version: 2.1.2
22
+ version: 2.1.4
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2152243920
25
+ version_requirements: *2156333440
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rails
28
- requirement: &2152243500 !ruby/object:Gem::Requirement
28
+ requirement: &2156333020 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,21 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
- version_requirements: *2152243500
37
- - !ruby/object:Gem::Dependency
38
- name: activerecord
39
- requirement: &2152243040 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
42
- - - ! '>='
43
- - !ruby/object:Gem::Version
44
- version: '0'
45
- type: :development
46
- prerelease: false
47
- version_requirements: *2152243040
36
+ version_requirements: *2156333020
48
37
  - !ruby/object:Gem::Dependency
49
38
  name: bundler
50
- requirement: &2152242620 !ruby/object:Gem::Requirement
39
+ requirement: &2156332560 !ruby/object:Gem::Requirement
51
40
  none: false
52
41
  requirements:
53
42
  - - ! '>='
@@ -55,10 +44,10 @@ dependencies:
55
44
  version: '0'
56
45
  type: :development
57
46
  prerelease: false
58
- version_requirements: *2152242620
47
+ version_requirements: *2156332560
59
48
  - !ruby/object:Gem::Dependency
60
- name: rspec
61
- requirement: &2152242200 !ruby/object:Gem::Requirement
49
+ name: simplecov
50
+ requirement: &2156332140 !ruby/object:Gem::Requirement
62
51
  none: false
63
52
  requirements:
64
53
  - - ! '>='
@@ -66,10 +55,10 @@ dependencies:
66
55
  version: '0'
67
56
  type: :development
68
57
  prerelease: false
69
- version_requirements: *2152242200
58
+ version_requirements: *2156332140
70
59
  - !ruby/object:Gem::Dependency
71
- name: rcov
72
- requirement: &2152241780 !ruby/object:Gem::Requirement
60
+ name: rdoc
61
+ requirement: &2156331720 !ruby/object:Gem::Requirement
73
62
  none: false
74
63
  requirements:
75
64
  - - ! '>='
@@ -77,10 +66,10 @@ dependencies:
77
66
  version: '0'
78
67
  type: :development
79
68
  prerelease: false
80
- version_requirements: *2152241780
69
+ version_requirements: *2156331720
81
70
  - !ruby/object:Gem::Dependency
82
- name: rdoc
83
- requirement: &2152241360 !ruby/object:Gem::Requirement
71
+ name: sqlite3
72
+ requirement: &2156331300 !ruby/object:Gem::Requirement
84
73
  none: false
85
74
  requirements:
86
75
  - - ! '>='
@@ -88,10 +77,10 @@ dependencies:
88
77
  version: '0'
89
78
  type: :development
90
79
  prerelease: false
91
- version_requirements: *2152241360
80
+ version_requirements: *2156331300
92
81
  - !ruby/object:Gem::Dependency
93
- name: sqlite3
94
- requirement: &2152240940 !ruby/object:Gem::Requirement
82
+ name: fakeweb
83
+ requirement: &2156330880 !ruby/object:Gem::Requirement
95
84
  none: false
96
85
  requirements:
97
86
  - - ! '>='
@@ -99,13 +88,11 @@ dependencies:
99
88
  version: '0'
100
89
  type: :development
101
90
  prerelease: false
102
- version_requirements: *2152240940
103
- description: ! "Spam protection for your ActiveRecord models using logic questions
104
- and the excellent textcaptcha api. See textcaptcha.com for more details and to get
105
- your api key.\n The logic questions are aimed at a child's age of 7, so can be
106
- solved easily by all but the most cognitively impaired users. As they involve human
107
- logic, such questions cannot be solved by a robot.\n For more reasons on why logic
108
- questions are useful, see here; http://textcaptcha.com/why"
91
+ version_requirements: *2156330880
92
+ description: ! "Simple question/answer based spam protection for your Rails models.\n
93
+ \ You can define your own logic questions and/or fetch questions from the textcaptcha.com
94
+ API.\n The questions involve human logic and are tough for spam bots to crack.\n
95
+ \ For more reasons on why logic questions are a good idea visit; http://textcaptcha.com/why"
109
96
  email:
110
97
  - matt@hiddenloop.com
111
98
  executables: []
@@ -123,17 +110,17 @@ files:
123
110
  - config/textcaptcha.yml
124
111
  - init.rb
125
112
  - lib/acts_as_textcaptcha.rb
113
+ - lib/acts_as_textcaptcha/framework/rails.rb
126
114
  - lib/acts_as_textcaptcha/framework/rails2.rb
127
- - lib/acts_as_textcaptcha/framework/rails3.rb
128
115
  - lib/acts_as_textcaptcha/textcaptcha.rb
129
116
  - lib/acts_as_textcaptcha/textcaptcha_helper.rb
130
117
  - lib/acts_as_textcaptcha/version.rb
131
118
  - lib/tasks/textcaptcha.rake
132
- - spec/acts_as_textcaptcha_spec.rb
133
- - spec/database.yml
134
- - spec/schema.rb
135
- - spec/spec.opts
136
- - spec/spec_helper.rb
119
+ - test/schema.rb
120
+ - test/test_helper.rb
121
+ - test/test_models.rb
122
+ - test/textcaptcha_helper_test.rb
123
+ - test/textcaptcha_test.rb
137
124
  has_rdoc: true
138
125
  homepage: http://github.com/matthutchinson/acts_as_textcaptcha
139
126
  licenses: []
@@ -158,11 +145,6 @@ rubyforge_project:
158
145
  rubygems_version: 1.6.2
159
146
  signing_key:
160
147
  specification_version: 3
161
- summary: Spam protection for your models via logic questions and the excellent textcaptcha.com
162
- api
163
- test_files:
164
- - spec/acts_as_textcaptcha_spec.rb
165
- - spec/database.yml
166
- - spec/schema.rb
167
- - spec/spec.opts
168
- - spec/spec_helper.rb
148
+ summary: Spam protection for your models via logic questions and the textcaptcha.com
149
+ API
150
+ test_files: []