acts_as_textcaptcha 4.2.0 → 4.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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)