acts_as_textcaptcha 4.2.0 → 4.5.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.rubocop.yml +1165 -0
  4. data/.simplecov +11 -0
  5. data/.travis.yml +30 -8
  6. data/Appraisals +9 -6
  7. data/CHANGELOG.md +94 -34
  8. data/CODE_OF_CONDUCT.md +54 -31
  9. data/CONTRIBUTING.md +14 -9
  10. data/Gemfile +2 -2
  11. data/LICENSE +165 -0
  12. data/PULL_REQUEST_TEMPLATE.md +16 -0
  13. data/README.md +206 -228
  14. data/Rakefile +26 -19
  15. data/acts_as_textcaptcha.gemspec +57 -41
  16. data/bin/console +2 -5
  17. data/bin/setup +7 -0
  18. data/gemfiles/rails_3.gemfile +1 -0
  19. data/gemfiles/rails_4.gemfile +2 -1
  20. data/gemfiles/rails_5.gemfile +2 -1
  21. data/gemfiles/rails_6.gemfile +8 -0
  22. data/lib/acts_as_textcaptcha.rb +9 -4
  23. data/lib/acts_as_textcaptcha/errors.rb +21 -0
  24. data/lib/acts_as_textcaptcha/framework/rails.rb +3 -1
  25. data/lib/acts_as_textcaptcha/railtie.rb +9 -0
  26. data/lib/acts_as_textcaptcha/tasks/textcaptcha.rake +17 -0
  27. data/lib/acts_as_textcaptcha/textcaptcha.rb +75 -72
  28. data/lib/acts_as_textcaptcha/textcaptcha_api.rb +39 -45
  29. data/lib/acts_as_textcaptcha/textcaptcha_cache.rb +12 -16
  30. data/lib/acts_as_textcaptcha/textcaptcha_config.rb +47 -0
  31. data/lib/acts_as_textcaptcha/textcaptcha_helper.rb +13 -14
  32. data/lib/acts_as_textcaptcha/version.rb +3 -1
  33. metadata +68 -46
  34. data/.coveralls.yml +0 -1
  35. data/LICENSE.txt +0 -21
  36. data/config/textcaptcha.yml +0 -34
  37. data/lib/tasks/textcaptcha.rake +0 -21
  38. data/test/schema.rb +0 -34
  39. data/test/test_helper.rb +0 -44
  40. data/test/test_models.rb +0 -69
  41. data/test/textcaptcha_api_test.rb +0 -46
  42. data/test/textcaptcha_cache_test.rb +0 -25
  43. data/test/textcaptcha_helper_test.rb +0 -68
  44. data/test/textcaptcha_test.rb +0 -198
@@ -0,0 +1,16 @@
1
+
2
+ Explain what you're changing and why here.
3
+
4
+ ---
5
+ #### :memo: Checklist
6
+
7
+ Please check this list and leave it intact for the reviewer. Thanks! :heart:
8
+
9
+ - [ ] Commit messages provide context (why not just what, some tips [here](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)).
10
+ - [ ] If relevant, mention GitHub issue number above and include in a commit message.
11
+ - [ ] Latest code from master merged.
12
+ - [ ] New behaviour has test coverage.
13
+ - [ ] Avoid duplicating code.
14
+ - [ ] No commented out code.
15
+ - [ ] Avoid comments for your code, write code that explains itself.
16
+ - [ ] Changes are simple, useful, clear and brief.
data/README.md CHANGED
@@ -1,290 +1,268 @@
1
1
  ## ActAsTextcaptcha
2
2
 
3
- [![Gem Version](https://img.shields.io/gem/v/acts_as_textcaptcha.svg?style=flat)](http://rubygems.org/gems/acts_as_textcaptcha)
4
- [![Travis Build Status](https://img.shields.io/travis/matthutchinson/acts_as_textcaptcha.svg?style=flat)](https://travis-ci.org/matthutchinson/acts_as_textcaptcha)
5
- [![Coverage Status](https://coveralls.io/repos/github/matthutchinson/acts_as_textcaptcha/badge.svg?branch=master)](https://coveralls.io/github/matthutchinson/acts_as_textcaptcha?branch=master)
6
- [![Code Climate](https://codeclimate.com/github/matthutchinson/acts_as_textcaptcha/badges/gpa.svg)](https://codeclimate.com/github/matthutchinson/acts_as_textcaptcha)
7
- [![Gem Dependencies](https://img.shields.io/gemnasium/matthutchinson/acts_as_textcaptcha.svg?style=flat)](https://gemnasium.com/matthutchinson/acts_as_textcaptcha)
8
-
9
- ActsAsTextcaptcha provides spam protection for your Rails models using logic
10
- questions from the excellent [TextCaptcha](http://textcaptcha.com/) web service
11
- (by [Rob Tuley](https://twitter.com/robtuley). It is also possible to configure your
12
- own captcha questions (instead, or as a fallback in the event of any API
13
- issues).
14
-
15
- This gem is actively maintained, has good test coverage and is compatible with
16
- Rails >= 3 (including Rails 4 & 5) and Ruby >= 2.1. If you have issues
17
- please report them
18
- [here](https://github.com/matthutchinson/acts_as_textcaptcha/issues/new).
19
-
20
- Logic questions from the web service are aimed at a child's age of 7, so they
21
- can be solved easily by even the most cognitively impaired users. As they
22
- involve human logic, questions cannot be solved by a robot. There are both
23
- advantages and disadvantages in using logic questions over image based
24
- captchas, find out more at [TextCaptcha](http://textcaptcha.com/).
3
+ [![Gem](https://img.shields.io/gem/v/acts_as_textcaptcha.svg?style=flat)](http://rubygems.org/gems/acts_as_textcaptcha)
4
+ [![Travis](https://img.shields.io/travis/com/matthutchinson/acts_as_textcaptcha/master.svg?style=flat)](https://travis-ci.com/matthutchinson/acts_as_textcaptcha)
5
+ [![Depfu](https://img.shields.io/depfu/matthutchinson/acts_as_textcaptcha.svg?style=flat)](https://depfu.com/github/matthutchinson/acts_as_textcaptcha)
6
+ [![Maintainability](https://api.codeclimate.com/v1/badges/c67969dd7b921477bdcc/maintainability)](https://codeclimate.com/github/matthutchinson/acts_as_textcaptcha/maintainability)
7
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/c67969dd7b921477bdcc/test_coverage)](https://codeclimate.com/github/matthutchinson/acts_as_textcaptcha/test_coverage)
8
+
9
+ ActsAsTextcaptcha provides spam protection for Rails models with text-based
10
+ logic question captchas. Questions are fetched from [Rob
11
+ Tuley's](https://twitter.com/robtuley)
12
+ [textcaptcha.com](https://textcaptcha.com/). They can be solved easily by humans
13
+ but are tough for robots to crack.
14
+
15
+ The gem can also be configured with your own questions; as an alternative, or as
16
+ a fallback to handle any API issues. For reasons on why logic based captchas
17
+ are a good idea visit [textcaptcha.com](https://textcaptcha.com).
18
+
19
+ ## Requirements
20
+
21
+ * [Ruby](http://ruby-lang.org/) >= 2.5
22
+ * [Rails](http://github.com/rails/rails) >= 4
23
+ * A valid [Rails.cache](http://guides.rubyonrails.org/caching_with_rails.html#cache-stores) (not `:null_store`)
25
24
 
26
25
  ## Demo
27
26
 
28
27
  Try a [working demo here](https://acts-as-textcaptcha-demo.herokuapp.com)!
29
-
30
- **Or** click below to deploy your own example Rails app to Heroku (already
31
- configured with acts_as_textcaptcha). See
32
- [here](https://github.com/matthutchinson/acts_as_textcaptcha_demo) for more
33
- details.
28
+ Or one-click deploy your own [demo app](https://github.com/matthutchinson/acts_as_textcaptcha_demo) to Heroku.
34
29
 
35
30
  [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://www.heroku.com/deploy?template=https://github.com/matthutchinson/acts_as_textcaptcha_demo/tree/master)
36
31
 
37
- ## Installing
32
+ ## Installation
38
33
 
39
- First add the following to your Gemfile, then `bundle install`;
34
+ Add this line to your Gemfile and run `bundle install`:
40
35
 
41
- gem 'acts_as_textcaptcha'
36
+ ```ruby
37
+ gem 'acts_as_textcaptcha'
38
+ ```
42
39
 
43
- Add the following code to models you would like to protect;
40
+ Add this to models you'd like to protect:
44
41
 
45
- class Comment < ApplicationRecord
46
- # (this is the simplest way to configure the gem)
47
- acts_as_textcaptcha :api_key => 'TEXTCAPTCHA_API_IDENTITY'
48
- end
42
+ ```ruby
43
+ class Comment < ApplicationRecord
44
+ acts_as_textcaptcha api_key: 'TEXTCAPTCHA_API_IDENTITY'
45
+ # see below for more config options
46
+ end
47
+ ```
49
48
 
50
- Your `TEXTCAPTCHA_API_IDENTITY` should be some reference to yourself (e.g. an
51
- email address, domain or similar where if there are problems with your usage you
52
- can be contacted).
49
+ [Rob](https://twitter.com/robtuley) requests that your
50
+ `TEXTCAPTCHA_API_IDENTITY` be some reference to yourself (e.g. an email address,
51
+ domain or similar) so you can be contacted should any usage problem occur.
53
52
 
54
- Next, in your controller's *new* action generate and assign the logic question
55
- for the record, like so;
53
+ In your controller's `new` action call the `textcaptcha` method:
56
54
 
57
- def new
58
- @comment = Comment.new
59
- @comment.textcaptcha
60
- end
55
+ ```ruby
56
+ def new
57
+ @comment = Comment.new
58
+ @comment.textcaptcha  
59
+ end
60
+ ```
61
61
 
62
- Finally, in the view add the textcaptcha question and answer fields to your form
63
- using the `textcaptcha_fields` helper. Feel free to arrange the HTML within this
64
- block as you like;
62
+ Add the question and answer fields to your form using the
63
+ `textcaptcha_fields` helper. Arrange the HTML within this block as you like.
65
64
 
66
- <%= textcaptcha_fields(f) do %>
67
- <div class="field">
68
- <%= f.label :textcaptcha_answer, @comment.textcaptcha_question %><br/>
69
- <%= f.text_field :textcaptcha_answer, :value => '' %>
70
- </div>
71
- <% end %>
65
+ ```ruby
66
+ <%= textcaptcha_fields(f) do %>
67
+ <div class="field">
68
+ <%= f.label :textcaptcha_answer, @comment.textcaptcha_question %><br/>
69
+ <%= f.text_field :textcaptcha_answer, :value => '' %>
70
+ </div>
71
+ <% end %>
72
+ ```
72
73
 
73
- *NOTE:* If you'd rather NOT use this helper and prefer to write your own form
74
- elements, take a look at the HTML produced from this helper method
74
+ If you'd prefer to construct your own form elements, take a look at the HTML
75
+ produced
75
76
  [here](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_helper.rb).
76
77
 
77
- *NOTE:* The defaults for [cache
78
- configuration](http://guides.rubyonrails.org/caching_with_rails.html#cache-stores)
79
- changed with Rails 5 and this gem **requires** a working Rails.cache store to
80
- exist.
78
+ Finally set a valid [cache
79
+ store](https://guides.rubyonrails.org/caching_with_rails.html#cache-stores) (not `:null_store`) for your environments:
81
80
 
82
- *NOTE:* These installation steps changed with v4.0.0 of this gem. If you are
83
- having problems please refer to the 3.0 [upgrade
84
- guide](https://github.com/matthutchinson/acts_as_textcaptcha/wiki/Upgrading-from-3.0.10).
81
+ ```ruby
82
+ # e.g. in each config/environments/*.rb
83
+ config.cache_store = :memory_store
84
+ ```
85
85
 
86
- ### Toggling TextCaptcha
86
+ You can run `rails dev:cache` on a modern generated Rails app to enable
87
+ a memory store cache in the development environment.
87
88
 
88
- You can toggle textcaptcha on/off for your models by overriding the
89
- `perform_textcaptcha?` method. If it returns false, no questions will be fetched
90
- from the web service and captcha validation is disabled.
89
+ ## Configuration
91
90
 
92
- This is useful for writing your own custom logic for toggling spam protection
93
- on/off e.g. for logged in users. By default the `perform_textcaptcha?` method
94
- [checks if the object is a new (unsaved)
95
- record](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha.rb#L54).
91
+ The following options are available (only `api_key` is required):
96
92
 
97
- So out of the box, spam protection is only enabled for creating new records (not
98
- updating). Here is a typical example showing how to overwrite the
99
- `perform_textcaptcha?` method, while maintaining the new record check.
93
+ * **api_key** (_required_) - a reference to yourself (e.g. your email or domain).
94
+ * **questions** (_optional_) - array of your own questions and answers (see below).
95
+ * **cache_expiry_minutes** (_optional_) - how long valid answers are cached for (default 10 minutes).
96
+ * **raise_errors** (_optional_) - if true, API or network errors are raised (default false, errors logged).
97
+ * **api_endpoint** (_optional_) - set your own JSON API endpoint to fetch from (see below).
100
98
 
101
- class Comment < ApplicationRecord
102
- acts_as_textcaptcha :api_key => 'TEXTCAPTCHA_API_IDENTITY'
99
+ For example:
103
100
 
104
- def perform_textcaptcha?
105
- super && user.admin?
106
- end
107
- end
101
+ ```ruby
102
+ class Comment < ApplicationRecord
103
+ acts_as_textcaptcha api_key: 'TEXTCAPTCHA_API_IDENTITY_KEY',
104
+ raise_errors: false,
105
+ cache_expiry_minutes: 10,
106
+ questions: [
107
+ { 'question' => '1+1', 'answers' => '2,two' },
108
+ { 'question' => 'The green hat is what color?', 'answers' => 'green' }
109
+ ]
110
+ end
111
+ ```
108
112
 
109
- ### Configuration options
113
+ ### YAML config
110
114
 
111
- You can configure captchas with the following options;
115
+ You can apply an app wide config with a `config/textcaptcha.yml` file. Use this
116
+ rake task to add one from a
117
+ [template](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_config.rb):
112
118
 
113
- * *api_key* (_required_) - reference to yourself (e.g. your email - to identify calls to the textcaptcha.com API)
114
- * *questions* (_optional_) - array of question and answer hashes (see below) A random question from this array will be asked if the web service fails OR if no `api_key` has been set. Multiple answers to the same question are comma separated (e.g. 2,two). Don't use commas in your answers!
115
- * *cache_expiry_minutes* (_optional_) - minutes for answers to persist in the cache (default 10 minutes), see [below for details](https://github.com/matthutchinson/acts_as_textcaptcha#what-does-the-code-do)
116
- * *http_read_timeout* (_optional_) - Net::HTTP option, seconds to wait for one block to be read from the remote API
117
- * *http_open_timeout* (_optional_) - Net::HTTP option, seconds to wait for the connection to open to the remote API
119
+ $ bundle exec rake textcaptcha:config
118
120
 
119
- For example;
121
+ **NOTE**: Any options set in models take preference over this config.
120
122
 
121
- class Comment < ApplicationRecord
122
- acts_as_textcaptcha :api_key => 'TEXTCAPTCHA_API_IDENTITY',
123
- :http_read_timeout => 60,
124
- :http_read_timeout => 10,
125
- :cache_expiry_minutes => 10,
126
- :questions => [{ 'question' => '1+1', 'answers' => '2,two' },
127
- { 'question' => 'The green hat is what color?', 'answers' => 'green' }]
128
- end
123
+ ### Config without the TextCaptcha service
129
124
 
130
- #### YAML config
125
+ To use __only__ your own logic questions, omit the `api_key` and set them in the
126
+ config (see above). Multiple answers to the same question must be comma
127
+ separated e.g. `2,two` (so do not include commas in answers).
131
128
 
132
- The gem can be configured for models individually (as shown above) or with a
133
- config/textcaptcha.yml file. The config file must have an `api_key` defined
134
- and/or an array of questions and answers. Any options defined inline in model
135
- classes take preference over the global configuration in textcaptcha.yml.
129
+ You can optionally set your own `api_endpoint` to fetch questions and answers
130
+ from. The URL must respond with a JSON object like this:
131
+
132
+ ```ruby
133
+ {
134
+ "q": "What number is 4th in the series 39, 11, 31 and nineteen?",
135
+ "a": ["1f0e3dad99908345f7439f8ffabdffc4","1d56cec552bf111de57687e4b5f8c795"]
136
+ }
137
+ ```
138
+
139
+ With `"a"` being an array of answer strings, MD5'd, and lower-cased. The
140
+ `api_key` option is ignored if an `api_endpoint` is set.
141
+
142
+ ### Toggling TextCaptcha
136
143
 
137
- The gem comes with a handy rake task to copy over a
138
- [textcaptcha.yml](http://github.com/matthutchinson/acts_as_textcaptcha/raw/master/config/textcaptcha.yml)
139
- template to your config directory;
144
+ Enable or disable captchas by overriding the `perform_textcaptcha?` method (in
145
+ models). By default the method checks if the object is a new (unsaved) record.
146
+ So spam protection is __only__ enabled for creating new records (not updating).
140
147
 
141
- rake textcaptcha:config
148
+ Here's an example overriding the default behaviour but maintaining the new
149
+ record check.
142
150
 
143
- #### Configuring _without_ the TextCaptcha web service
151
+ ```ruby
152
+ class Comment < ApplicationRecord
153
+ acts_as_textcaptcha :api_key => 'TEXTCAPTCHA_API_IDENTITY'
144
154
 
145
- To use only your own logic questions, simply omit the `api_key` from the
146
- configuration and define at least one logic question and answer (see above).
155
+ def perform_textcaptcha?
156
+ super && user.admin?
157
+ end
158
+ end
159
+ ```
147
160
 
148
161
  ## Translations
149
162
 
150
- The gem uses the standard Rails I18n translation approach (with a fall-back to
151
- English). Unfortunately at present, the TextCaptcha web service only provides
152
- logic questions in English.
153
-
154
- en:
155
- activerecord:
156
- errors:
157
- models:
158
- comment:
159
- attributes:
160
- textcaptcha_answer:
161
- incorrect: "is incorrect, try another question instead"
162
- expired: "was not submitted quickly enough, try another question instead"
163
- activemodel:
164
- attributes:
165
- comment:
166
- textcaptcha_answer: "TextCaptcha answer"
167
-
168
- ## Without ActiveRecord
169
-
170
- It is possible to use this gem without ActiveRecord. As an example, take a look at the
171
- [Contact](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/test/test_models.rb#L44)
172
- model used in the test suite
173
- [here](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/test/test_models.rb#L44).
174
-
175
- ## Testing and docs
176
-
177
- In development you can run the tests and rdoc tasks like so;
178
-
179
- * `rake test` (all tests)
180
- * `rake test:coverage` (all tests with code coverage reporting)
181
- * `appraisal rake test` (all tests with all gemfile variations)
182
- * `appraisal rails-3 rake test` (all tests using a specific gemfile)
183
- * `rake rdoc` (generate docs)
184
-
185
- This gem uses [appraisal](https://github.com/thoughtbot/appraisal) to run the
186
- test suite with multiple versions of Rails.
187
-
188
- ## What does the code do?
189
-
190
- The gem contains two parts, a module for your ActiveRecord models, and a single
191
- view helper method. The ActiveRecord module makes use of two futher classes,
192
- [TextcaptchaApi](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_api.rb)
193
- and
194
- [TextcaptchaCache](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_cache.rb).
195
-
196
- A call to `@model.textcaptcha` in your controller will query the TextCaptcha web
197
- service. A GET request is made with Net::HTTP and parsed using the default Rails
198
- `ActiveSupport::XMLMini` backend. A textcaptcha_question and a random cache key
199
- are assigned to the record. An array of possible answers is also stored in the
200
- TextcaptchaCache with this random key. The cached answers have (by default) a 10
201
- minute TTL in your cache. If your forms take more than 10 minutes to be
202
- completed you can adjust this value setting the `cache_expiry_minutes` option.
203
- Internally TextcaptchaCache wraps
204
- [Rails.cache](http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html)
205
- and all cache keys are name spaced.
206
-
207
- On saving, `validate_textcaptcha` is called on @model.validate checking that the
208
- `@model.textcaptcha_answer` matches one of the possible answers (retrieved from
209
- the cache). By default, this validation is _only_ carried out on new records,
210
- i.e. never on update, only on create. All attempted answers are case-insensitive
211
- and have trailing/leading white-space removed.
212
-
213
- Regardless of a correct, or incorrect answer the possible answers are cleared
214
- from the cache and a new random key is generated and assigned. An incorrect
215
- answer will cause a new question to be prompted. After one correct answer, the
216
- answer and a mutating key are sent on further form requests, and no question is
217
- presented in the form.
218
-
219
- If an error or timeout occurs during API fetching, ActsAsTextcaptcha will fall
220
- back to choose a random logic question defined in your options (see above). If
221
- the web service fails or no API key is specified AND no alternate questions are
222
- configured, the @model will not require textcaptcha checking and will pass as
223
- valid.
224
-
225
- For more details on the code please check the
226
- [documentation](http://rdoc.info/projects/matthutchinson/acts_as_textcaptcha).
227
- Tests are written with [MiniTest](https://rubygems.org/gems/minitest). Pull
228
- requests and bug reports are welcome.
163
+ The following strings are translatable (with Rails I18n translations):
229
164
 
230
- ## Requirements
165
+ ```yaml
166
+ en:
167
+ activerecord:
168
+ errors:
169
+ models:
170
+ comment:
171
+ attributes:
172
+ textcaptcha_answer:
173
+ incorrect: "is incorrect, try another question instead"
174
+ expired: "was not submitted quickly enough, try another question instead"
175
+ activemodel:
176
+ attributes:
177
+ comment:
178
+ textcaptcha_answer: "TextCaptcha answer"
179
+ ```
180
+
181
+ **NOTE**: The textcaptcha.com API only provides logic questions in English.
182
+
183
+ ## Handling Errors
184
+
185
+ The API may be unresponsive or return an unexpected response. If you've set
186
+ `raise_errors: true`, consider handling these errors:
187
+
188
+ * `ActsAsTextcaptcha::ResponseError`
189
+ * `ActsAsTextcaptcha::ParseError`
190
+ * `ActsAsTextcaptcha::ApiKeyError`
191
+
192
+ ## Development
193
+
194
+ Check out this repo and run `bin/setup`, this will install gem dependencies and
195
+ generate docs. Use `bundle exec rake` to run tests and generate a coverage
196
+ report.
197
+
198
+ You can also run `bin/console` for an interactive prompt to experiment with the
199
+ code.
200
+
201
+ ## Tests
231
202
 
232
- What do you need?
203
+ MiniTest is used for testing. Run the test suite with:
233
204
 
234
- * [Rails](http://github.com/rails/rails) >= 3 (including Rails 4 & 5)
235
- * [Rails.cache](http://guides.rubyonrails.org/caching_with_rails.html#cache-stores) - a basic cache configuration is necessary
236
- * [Ruby](http://ruby-lang.org/) >= 2.1
205
+ $ rake test
237
206
 
238
- *NOTE:* The built-in
239
- [TextcaptchaCache](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_cache.rb)
240
- class directly wraps the
241
- [Rails.cache](http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html).
242
- An alternative TextcaptchaCache implementation will be necessary if
243
- `Rails.cache` is not available.
207
+ This gem uses [appraisal](https://github.com/thoughtbot/appraisal) to test
208
+ against multiple versions of Rails.
244
209
 
210
+ * `appraisal rake test` (run tests against all Gemfile variations)
211
+ * `appraisal rails-3 rake test` (run tests against a specific Gemfile)
245
212
 
246
- ## Rails 2 Support
213
+ ## Docs
247
214
 
248
- Support for Rails 2 was dropped with the release of `v4.1.0`. If you would like
249
- to continue to use this gem with an older version of Rails (>= 2.3.8), please
250
- lock your Gemfile with version `4.0.0`. Like so;
215
+ Generate docs for this gem with:
251
216
 
252
- # in your Gemfile
253
- gem 'acts_as_textcaptcha', '=4.0.0'
217
+ $ rake rdoc
254
218
 
255
- # or in config/environment.rb
256
- config.gem 'acts_as_textcaptcha', :version => '=4.0.0'
219
+ ## Troubles?
257
220
 
258
- Check out the
259
- [README](https://github.com/matthutchinson/acts_as_textcaptcha/tree/v4.0.0) for
260
- this release for further instructions.
221
+ If you think something is broken or missing, please raise a new
222
+ [issue](https://github.com/matthutchinson/acts_as_textcaptcha/issues). Please
223
+ remember to check it hasn't already been raised.
224
+
225
+ ## Contributing
226
+
227
+ Bug [reports](https://github.com/matthutchinson/acts_as_textcaptcha/issues) and
228
+ [pull requests](https://github.com/matthutchinson/acts_as_textcaptcha/pulls) are
229
+ welcome on GitHub. When submitting pull requests, remember to add tests covering
230
+ any new behaviour, and ensure all tests are passing on
231
+ [Travis](https://travis-ci.com/matthutchinson/acts_as_textcaptcha). Read the
232
+ [contributing
233
+ guidelines](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/CONTRIBUTING.md)
234
+ for more details.
235
+
236
+ This project is intended to be a safe, welcoming space for collaboration, and
237
+ contributors are expected to adhere to the [Contributor
238
+ Covenant](http://contributor-covenant.org) code of conduct. See
239
+ [here](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/CODE_OF_CONDUCT.md)
240
+ for more details.
241
+
242
+ ## Todo
243
+
244
+ * Allow translatable user supplied questions and answers in config
245
+ * Allow `Net::HTTP` to be swapped out for any another HTTP client.
246
+
247
+ ## License
248
+
249
+ The code is available as open source under the terms of
250
+ [LGPL-3](https://opensource.org/licenses/LGPL-3.0).
251
+
252
+ ## Who's who?
253
+
254
+ * [ActsAsTextcaptcha](http://github.com/matthutchinson/acts_as_textcaptcha) and [little robot drawing](http://www.flickr.com/photos/hiddenloop/4541195635/) by [Matthew Hutchinson](http://matthewhutchinson.net)
255
+ * [TextCaptcha](https://textcaptcha.com) API and service by [Rob Tuley](https://twitter.com/robtuley)
261
256
 
262
257
  ## Links
263
258
 
264
259
  * [Demo](https://acts-as-textcaptcha-demo.herokuapp.com)
265
- * [Travis CI](http://travis-ci.org/#!/matthutchinson/acts_as_textcaptcha)
266
- * [Test Coverage](https://coveralls.io/r/matthutchinson/acts_as_textcaptcha?branch=master)
267
- * [Code Climate](https://codeclimate.com/github/matthutchinson/acts_as_textcaptcha)
260
+ * [Travis CI](http://travis-ci.com/matthutchinson/acts_as_textcaptcha)
261
+ * [Maintainability](https://codeclimate.com/github/matthutchinson/acts_as_textcaptcha/maintainability)
262
+ * [Test Coverage](https://codeclimate.com/github/matthutchinson/acts_as_textcaptcha/test_coverage)
268
263
  * [RDoc](http://rdoc.info/projects/matthutchinson/acts_as_textcaptcha)
269
264
  * [Wiki](http://wiki.github.com/matthutchinson/acts_as_textcaptcha/)
270
265
  * [Issues](http://github.com/matthutchinson/acts_as_textcaptcha/issues)
271
266
  * [Report a bug](http://github.com/matthutchinson/acts_as_textcaptcha/issues/new)
272
267
  * [Gem](http://rubygems.org/gems/acts_as_textcaptcha)
273
268
  * [GitHub](http://github.com/matthutchinson/acts_as_textcaptcha)
274
-
275
- ## Who's who?
276
-
277
- * [ActsAsTextcaptcha](http://github.com/matthutchinson/acts_as_textcaptcha) and [little robot drawing](http://www.flickr.com/photos/hiddenloop/4541195635/) by [Matthew Hutchinson](http://matthewhutchinson.net)
278
- * [TextCaptcha](http://textcaptcha.com) API and service by [Rob Tuley](https://twitter.com/robtuley)
279
-
280
- ## Usage
281
-
282
- This gem is used in a number of production websites and apps. It was originally
283
- extracted from code developed for [Bugle](http://bugleblogs.com). If you're
284
- happily using acts_as_textcaptcha in production, please let me know and I'll add
285
- you to this list!
286
-
287
- * [matthewhutchinson.net](http://matthewhutchinson.net)
288
- * [pmFAQtory.com](http://pmfaqtory.com)
289
- * [The FAQtory](http://faqtoryapp.com)
290
- * [DPT Watch, San Francisco](http://www.dptwatch.com)