acts_as_textcaptcha 4.1.2 → 4.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f35995a8199f3941f0f25e19493b8ce0ace5e9f4
4
- data.tar.gz: e7ab7133d65ac5a2b18ab957604a43fdb9055dd6
3
+ metadata.gz: b2f39dcac098efd1d5cffccf5e963cff7e3c3c63
4
+ data.tar.gz: 433df07a2b0d681f25d5484a24081bfaa0e918c4
5
5
  SHA512:
6
- metadata.gz: 22513b29f7bca5cd3fdafcc008e2b28706043460f1ec5c5f5ee5257700e5391e490d6b1c4788f9589daa13cacfe7b127936f687595e348626a0eb3da55e3f7e5
7
- data.tar.gz: 3c7abfa93194c776ee1ba6d241093224637d6fed600245b6cb216faa45081fe7d3a409a04cf5ddfc17ca0c56e9c2e9c6cc32da65cdb97213ec189e4f077f614b
6
+ metadata.gz: 27b234f2a1935fbfc23835e18d88a145193daa8177120812a6b4b8faa21974fbe3e19d1b1485634383363d9198b4d75c479151dbec02eb1ae6ebf519a85541a1
7
+ data.tar.gz: d308be3a0e327e4c121fed11a7f827cef33617cea5f1dce197dd248b572869e862c74433efb8aaa2151e34b6667c03c1454dfc2936aa5d35f99db747f84b2e8c
data/.gitignore CHANGED
@@ -1,9 +1,9 @@
1
- *.*.db
2
- *.db
3
- doc
4
- *.gem
5
- Gemfile.lock
6
- pkg/*
7
- coverage
8
- coverage.data
9
- .rvmrc
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -1,10 +1,13 @@
1
+ sudo: false
1
2
  language: ruby
2
3
  before_install:
3
- - gem update --system
4
- - gem install json sqlite3
5
- - gem --version
4
+ - mkdir -p ./tmp/test_db
6
5
  rvm:
7
- - 1.9.2
8
- - 1.9.3
9
6
  - 2.0.0
10
- - 2.1.1
7
+ - 2.1.9
8
+ - 2.2.5
9
+ - 2.3.1
10
+
11
+ branches:
12
+ except:
13
+ - gh-pages
@@ -0,0 +1,45 @@
1
+ ### ActsAsTextcaptcha Change Log
2
+
3
+ All notable changes to this project will be documented in this file. This
4
+ project adheres to [Semantic Versioning][Semver].
5
+
6
+ ## [Unreleased]
7
+
8
+ * Your contribution here!
9
+
10
+ ## [4.1.3][] (28 May 2016)
11
+ * Updated gem dependencies
12
+ * Switched from FakeWeb to Webmock
13
+ * Added bin/console
14
+ * Cleaned up Rakefile
15
+ * Added MIT license and Code of Conduct
16
+ * README now in markdown, badges fixed up
17
+ * Removed Pry gem (development dependency)
18
+
19
+ ## [4.1.2][] (11 May 2014)
20
+ * Updated gem dependencies
21
+ * Added `rake console` for helpful debugging
22
+
23
+ ## [4.1.1][] (13 January 2014)
24
+ * Dropped gem [signing & cert](http://tinyurl.com/p98owwz)
25
+
26
+ ## [4.1.0][] (2 January 2014)
27
+ * Dropping support for Rails 2
28
+ * README updated
29
+ * CHANGELOG (this file) added
30
+
31
+ ## [4.0.0][] (1 January 2014)
32
+ * Using a cache store to persist answers between requests
33
+ * README updated
34
+ * Test coverage improved
35
+
36
+ (further change log details for older releases are unavailable)
37
+
38
+ [Unreleased]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.1.3...HEAD
39
+ [4.1.3]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.1.2...v4.1.3
40
+ [4.1.2]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.1.1...v4.1.2
41
+ [4.1.1]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.1.0...v4.1.1
42
+ [4.1.0]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v4.0.0...v4.1.0
43
+ [4.0.0]: https://github.com/matthutchinson/acts_as_textcaptcha/compare/v3.0.11...v4.0.0
44
+
45
+ [Semver]: http://semver.org
@@ -0,0 +1,50 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer via [GitHub][maintainer]. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [maintainer]: https://github.com/matthutchinson
49
+ [homepage]: http://contributor-covenant.org
50
+ [version]: http://contributor-covenant.org/version/1/3/0/
@@ -0,0 +1,31 @@
1
+ ### Contributing
2
+
3
+ Pull Requests are welcome! To start helping out on this project:
4
+
5
+ Fork then clone the repository:
6
+
7
+ git clone git@github.com:your-username/acts_as_textcaptcha.git
8
+
9
+ Create your feature branch:
10
+
11
+ git checkout -b my-new-feature
12
+
13
+ Commit your changes, push and submit a new [Pull
14
+ Request](https://github.com/matthutchinson/acts_as_textcaptcha/compare/):
15
+
16
+ git commit -am 'Added some feature'
17
+ git push origin my-new-feature
18
+
19
+ At this point you'll be waiting for me to review it. I try to reply to new Pull
20
+ Requests within 5 days. I may suggest some changes, improvements or
21
+ alternatives. To increase the chance that your pull request gets accepted:
22
+
23
+ * Explain what your are doing (and why) in your Pull Request description.
24
+ * If you are fixing an
25
+ [issue](https://github.com/matthutchinson/acts_as_textcaptcha/issues), link to
26
+ it in your description and [mention
27
+ it](https://help.github.com/articles/closing-issues-via-commit-messages/) in
28
+ the commit message.
29
+ * Write a good [commit
30
+ message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
31
+ * Write tests.
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
1
  source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in acts_as_textcaptcha.gemspec
2
4
  gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Matthew Hutchinson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,278 @@
1
+ ## ActAsTextcaptcha
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 [Text CAPTCHA](http://textcaptcha.com/) web service
11
+ (by [Rob Tuley](http://openknot.com/me/) of [Openknot](http://openknot.com/)).
12
+ It is also possible to configure your own text captcha questions (instead, or as
13
+ a fall back in the event of any remote API issues).
14
+
15
+ This gem is actively maintained, has good test coverage and is compatible with
16
+ Rails >= 3.0.0 (including Rails 4). If you have any issues please report them
17
+ [here](https://github.com/matthutchinson/acts_as_textcaptcha/issues/new).
18
+
19
+ Logic questions from the web service are aimed at a child's age of 7, so they
20
+ can be solved easily by even the most cognitively impaired users. As they
21
+ involve human logic, questions cannot be solved by a robot. There are both
22
+ advantages and disadvantages for using logic questions over image based
23
+ captchas, find out more at [TextCAPTCHA](http://textcaptcha.com/why).
24
+
25
+ ## Demo
26
+
27
+ Try a [working demo here](http://textcaptcha.herokuapp.com)!
28
+
29
+ ## Installing
30
+
31
+ *NOTE:* The steps to configure your app changed with the v4.0.0 release. If you
32
+ are having problems please carefully check the steps below or refer to the [upgrade
33
+ instructions](https://github.com/matthutchinson/acts_as_textcaptcha/wiki/Upgrading-from-3.0.10).
34
+
35
+ First add the following to your Gemfile, then `bundle install`;
36
+
37
+ gem 'acts_as_textcaptcha'
38
+
39
+ Next [grab an API key for your website](http://textcaptcha.com/api), then add
40
+ the following code to models you would like to protect;
41
+
42
+ class Comment < ActiveRecord::Base
43
+ # (this is the simplest way to configure the gem, with an API key only)
44
+ acts_as_textcaptcha :api_key => 'PASTE_YOUR_TEXTCAPTCHA_API_KEY_HERE'
45
+ end
46
+
47
+ Next in your controller's *new* action you'll want to generate and assign the
48
+ logic question for the new record, like so;
49
+
50
+ def new
51
+ @comment = Comment.new
52
+ @comment.textcaptcha
53
+ end
54
+
55
+ Finally, in your form view add the textcaptcha question and answer fields using
56
+ the textcaptcha_fields helper. Feel free to arrange the HTML within this block
57
+ as you like;
58
+
59
+ <%= textcaptcha_fields(f) do %>
60
+ <div class="field">
61
+ <%= f.label :textcaptcha_answer, @comment.textcaptcha_question %><br/>
62
+ <%= f.text_field :textcaptcha_answer, :value => '' %>
63
+ </div>
64
+ <% end %>
65
+
66
+ *NOTE:* If you'd rather NOT use this helper and would prefer to write your own
67
+ form view code, see the html produced from the textcaptcha_fields method in the
68
+ [source
69
+ code](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_helper.rb).
70
+
71
+ ### Toggling Textcaptcha
72
+
73
+ You can toggle textcaptcha on/off for your models by overriding the
74
+ `perform_textcaptcha?` method. If it returns false, no questions will be fetched
75
+ from the web service and textcaptcha validation is disabled.
76
+
77
+ This is useful for writing your own custom logic for toggling spam protection
78
+ on/off e.g. for logged in users. By default the `perform_textcaptcha?` method
79
+ [checks if the form object is a new (unsaved)
80
+ record](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha.rb#L54).
81
+
82
+ So out of the box, spam protection is only enabled for creating new records (not
83
+ updating). Here is a typical example showing how to overwrite the
84
+ `perform_textcaptcha?` method, while maintaining the new record check.
85
+
86
+ class Comment < ActiveRecord::Base
87
+ acts_as_textcaptcha :api_key => 'YOUR_TEXTCAPTCHA_API_KEY'
88
+
89
+ def perform_textcaptcha?
90
+ super && user.admin?
91
+ end
92
+ end
93
+
94
+ ## More configuration options
95
+
96
+ You can configure captchas with the following options;
97
+
98
+ * *api_key* (_required_) - get a free key from http://textcaptcha.com/api
99
+ * *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). So do not use commas in your answers!
100
+ * *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)
101
+ * *http_read_timeout* (_optional_) - Net::HTTP option, seconds to wait for one block to be read from the remote API
102
+ * *http_open_timeout* (_optional_) - Net::HTTP option, seconds to wait for the connection to open to the remote API
103
+
104
+ For example;
105
+
106
+ class Comment < ActiveRecord::Base
107
+ acts_as_textcaptcha :api_key => 'YOUR_TEXTCAPTCHA_API_KEY',
108
+ :http_read_timeout => 60,
109
+ :http_read_timeout => 10,
110
+ :cache_expiry_minutes => 10,
111
+ :questions => [{ 'question' => '1+1', 'answers' => '2,two' },
112
+ { 'question' => 'The green hat is what color?', 'answers' => 'green' }]
113
+ end
114
+
115
+ ### YAML config
116
+
117
+ The gem can be configured for models individually (as shown above) or with a
118
+ config/textcaptcha.yml file. The config file must have an api_key defined and
119
+ optional array of questions. Options definied inline in model classes take
120
+ preference over the configuration in textcaptcha.yml. The gem comes with a
121
+ handy rake task to copy over a
122
+ [textcaptcha.yml](http://github.com/matthutchinson/acts_as_textcaptcha/raw/master/config/textcaptcha.yml)
123
+ template to your config directory;
124
+
125
+ rake textcaptcha:config
126
+
127
+ ### Configuring _without_ the TextCAPTCHA web service
128
+
129
+ To use only your own logic questions, simply ommit the api_key from the
130
+ configuration and define at least 1 logic question and answer (see above).
131
+
132
+ ## Translations
133
+
134
+ The gem uses the standard Rails I18n translation approach (with a fall-back to
135
+ English). Unfortunately at present, the Text CAPTCHA web service only provides
136
+ logic questions in English.
137
+
138
+ en:
139
+ activerecord:
140
+ errors:
141
+ models:
142
+ comment:
143
+ attributes:
144
+ textcaptcha_answer:
145
+ incorrect: "is incorrect, try another question instead"
146
+ expired: "was not submitted quickly enough, try another question instead"
147
+ activemodel:
148
+ attributes:
149
+ comment:
150
+ textcaptcha_answer: "Textcaptcha answer"
151
+
152
+ ## Without Rails or ActiveRecord
153
+
154
+ Although this gem has been built with Rails in mind, is entirely possible to use
155
+ it without ActiveRecord, or Rails. As an example, take a look at the
156
+ [Contact](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/test/test_models.rb#L44)
157
+ model used in the test suite
158
+ [here](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/test/test_models.rb#L44).
159
+
160
+ Please note that the built-in
161
+ [TextcaptchaCache](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_cache.rb)
162
+ class directly wraps the
163
+ [Rails.cache](http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html).
164
+ An alternative TextcaptchaCache implementation will be necessary if Rails.cache
165
+ is not available.
166
+
167
+ ## Testing and docs
168
+
169
+ In development you can run the tests and rdoc tasks like so;
170
+
171
+ * rake test (all tests)
172
+ * rake test:coverage (all tests with code coverage)
173
+ * rake rdoc (generate docs)
174
+
175
+ ## What does the code do?
176
+
177
+ The gem contains two parts, a module for your ActiveRecord models, and a single
178
+ view helper method. The ActiveRecord module makes use of two futher classes,
179
+ [TextcaptchaApi](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_api.rb)
180
+ and
181
+ [TextcaptchaCache](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_cache.rb).
182
+
183
+ A call to @model.textcaptcha in your controller will query the Text CAPTCHA web
184
+ service. A GET request is made with Net::HTTP and parsed using the default
185
+ Rails ActiveSupport::XMLMini backend. A textcaptcha_question and a random cache
186
+ key is assigned to the record. An array of possible answers is stored in the
187
+ TextcaptchaCache with this random key. The cached answers have (by default) a
188
+ 10 minute TTL in your cache. If your forms take more than 10 minutes to be
189
+ completed you can adjust this value setting the `cache_expiry_minutes` option.
190
+ Internally TextcaptchaCache wraps
191
+ [Rails.cache](http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html)
192
+ and all cache keys are namespaced.
193
+
194
+ On saving, validate_textcaptcha is called on @model.validate checking that the
195
+ @model.textcaptcha_answer matches one of the possible answers (retrieved from
196
+ the cache). By default, this validation is _only_ carried out on new records,
197
+ i.e. never on edit, only on create. All attempted answers are case-insensitive
198
+ and have trailing/leading white-space removed.
199
+
200
+ Regardless of a correct, or incorrect answer the possible answers are cleared
201
+ from the cache and a new random key is generated and assigned. An incorrect
202
+ answer will cause a new question to be prompted. After one correct answer, the
203
+ answer and a mutating key are sent on further form requests, and no question is
204
+ presented in the form.
205
+
206
+ If an error or timeout occurs during API fetching, ActsAsTextcaptcha will fall
207
+ back to choose a random logic question defined in your options (see above). If
208
+ the web service fails or no API key is specified AND no alternate questions are
209
+ configured, the @model will not require textcaptcha checking and will pass as
210
+ valid.
211
+
212
+ For more details on the code please check the
213
+ [documentation](http://rdoc.info/projects/matthutchinson/acts_as_textcaptcha).
214
+ Tests are written with [MiniTest](https://rubygems.org/gems/minitest). Pull
215
+ requests and bug reports are welcome.
216
+
217
+ ## Requirements
218
+
219
+ What do you need?
220
+
221
+ * [Rails](http://github.com/rails/rails) >= 3.0.0 (including Rails 4)
222
+ * [Rails.cache](http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html) - some basic cache configuration is necessary
223
+ * [Ruby](http://ruby-lang.org/) >= 2.0.0 (tested with stable versions of 2.0, 2.1, 2.2, 2.3) - 1.8/1.9 support ended at version 4.1.1
224
+ * [Text CAPTCHA API key](http://textcaptcha.com/register) (_optional_, since you can define your own logic questions)
225
+ * [MiniTest](https://rubygems.org/gems/minitest) (_optional_ if you want to run the tests)
226
+ * [SimpleCov](https://rubygems.org/gems/simplecov) (_optional_ if you want to run the tests with code coverage reporting)
227
+
228
+ *Note*: The built-in
229
+ [TextcaptchaCache](https://github.com/matthutchinson/acts_as_textcaptcha/blob/master/lib/acts_as_textcaptcha/textcaptcha_cache.rb)
230
+ class directly wraps the
231
+ [Rails.cache](http://api.rubyonrails.org/classes/ActiveSupport/Cache/Store.html)
232
+ object.
233
+
234
+ ## Rails 2 support
235
+
236
+ Support for Rails 2 was dropped with the release of v4.1.0. If you would like to
237
+ continue to use this gem with an older version of Rails (>= 2.3.8), please lock
238
+ the version to `4.0.0`. Like so;
239
+
240
+ # in your Gemfile
241
+ gem 'acts_as_textcaptcha', '=4.0.0'
242
+
243
+ # or in environment.rb
244
+ config.gem 'acts_as_textcaptcha', :version => '=4.0.0'
245
+
246
+ Check out the
247
+ [README](https://github.com/matthutchinson/acts_as_textcaptcha/tree/v4.0.0) for
248
+ this release for more information.
249
+
250
+ ## Links
251
+
252
+ * [Demo](http://textcaptcha.herokuapp.com)
253
+ * [Travis CI](http://travis-ci.org/#!/matthutchinson/acts_as_textcaptcha)
254
+ * [Test Coverage](https://coveralls.io/r/matthutchinson/acts_as_textcaptcha?branch=master)
255
+ * [Code Climate](https://codeclimate.com/github/matthutchinson/acts_as_textcaptcha)
256
+ * [RDoc](http://rdoc.info/projects/matthutchinson/acts_as_textcaptcha)
257
+ * [Wiki](http://wiki.github.com/matthutchinson/acts_as_textcaptcha/)
258
+ * [Issues](http://github.com/matthutchinson/acts_as_textcaptcha/issues)
259
+ * [Report a bug](http://github.com/matthutchinson/acts_as_textcaptcha/issues/new)
260
+ * [Gem](http://rubygems.org/gems/acts_as_textcaptcha)
261
+ * [GitHub](http://github.com/matthutchinson/acts_as_textcaptcha)
262
+
263
+ ## Who's who?
264
+
265
+ * [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)
266
+ * [Text CAPTCHA](http://textcaptcha.com) API and service by [Rob Tuley](http://openknot.com/me/) at [Openknot](http://openknot.com)
267
+
268
+ ## Usage
269
+
270
+ This gem is used in a number of production websites and apps. It was originally
271
+ extracted from code developed for [Bugle](http://bugleblogs.com). If you're
272
+ happily using acts_as_textcaptcha in production, let me know and I'll add you to
273
+ this list!
274
+
275
+ * [matthewhutchinson.net](http://matthewhutchinson.net)
276
+ * [pmFAQtory.com](http://pmfaqtory.com)
277
+ * [The FAQtory](http://faqtoryapp.com)
278
+ * [DPT Watch, San Francisco](http://www.dptwatch.com)