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.
data/Rakefile CHANGED
@@ -1,29 +1,15 @@
1
1
  gem 'rdoc'
2
2
 
3
- # default rake
4
- task :default => [:test]
5
-
6
- # helpful console
7
- desc "Irb console that requires this gem"
8
- task :console do
9
- require 'irb'
10
- require 'irb/completion'
11
- require 'acts_as_textcaptcha'
12
- ARGV.clear
13
- IRB.start
14
- end
15
-
16
-
17
- # bundler tasks
18
- require 'bundler'
19
- Bundler::GemHelper.install_tasks
20
-
21
- # run all tests
3
+ require 'bundler/gem_tasks'
22
4
  require 'rake/testtask'
23
- Rake::TestTask.new do |t|
24
- t.pattern = "test/*_test.rb"
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.libs << "test"
7
+ t.libs << "lib"
8
+ t.test_files = FileList['test/**/*_test.rb']
25
9
  end
26
10
 
11
+ task :default => [:test]
12
+
27
13
  # code coverage
28
14
  namespace :test do
29
15
  desc "Run all tests and generate a code coverage report (simplecov)"
@@ -1,36 +1,44 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
4
  require "acts_as_textcaptcha/version"
4
5
 
5
6
  Gem::Specification.new do |s|
6
7
  s.name = "acts_as_textcaptcha"
7
8
  s.version = ActsAsTextcaptcha::VERSION
8
- s.platform = Gem::Platform::RUBY
9
9
  s.authors = ["Matthew Hutchinson"]
10
10
  s.email = ["matt@hiddenloop.com"]
11
11
  s.homepage = "http://github.com/matthutchinson/acts_as_textcaptcha"
12
+ s.license = 'MIT'
12
13
  s.summary = %q{Spam protection for your models via logic questions and the textcaptcha.com API}
14
+
13
15
  s.description = %q{Simple question/answer based spam protection for your Rails models.
14
16
  You can define your own logic questions and/or fetch questions from the textcaptcha.com API.
15
17
  The questions involve human logic and are tough for spam bots to crack.
16
18
  For more reasons on why logic questions are a good idea visit; http://textcaptcha.com/why}
17
19
 
18
- s.extra_rdoc_files = ['README.rdoc', 'LICENSE']
20
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the
21
+ # 'allowed_push_host' to allow pushing to a single host or delete this section
22
+ # to allow pushing to any host.
23
+ if s.respond_to?(:metadata)
24
+ s.metadata['allowed_push_host'] = "https://rubygems.org"
25
+ else
26
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
27
+ end
19
28
 
20
29
  s.files = `git ls-files`.split("\n")
21
30
  s.test_files = `git ls-files -- {test}/*`.split("\n")
22
31
  s.require_paths = ["lib"]
23
32
 
24
- # lock mime-types to pre 2.0 since we want to support 1.8.7/REE in tests
33
+ # always test against latest rails version
34
+ s.add_development_dependency('rails', '~> 4.2.6')
35
+
25
36
  s.add_development_dependency('mime-types')
26
- s.add_development_dependency('rails')
27
37
  s.add_development_dependency('bundler')
28
38
  s.add_development_dependency('minitest')
29
39
  s.add_development_dependency('simplecov')
30
40
  s.add_development_dependency('rdoc')
31
41
  s.add_development_dependency('sqlite3')
32
- s.add_development_dependency('fakeweb')
33
- s.add_development_dependency('strong_parameters')
42
+ s.add_development_dependency('webmock')
34
43
  s.add_development_dependency('coveralls')
35
- s.add_development_dependency('pry')
36
44
  end
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "acts_as_textcaptcha"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # start irb
10
+ require "irb"
11
+ IRB.start
@@ -28,7 +28,7 @@ module ActsAsTextcaptcha
28
28
  begin
29
29
  self.textcaptcha_config = YAML.load(File.read("#{Rails.root ? Rails.root.to_s : '.'}/config/textcaptcha.yml"))[Rails.env].symbolize_keys!
30
30
  rescue
31
- raise 'could not find any textcaptcha options, in config/textcaptcha.yml or model - run rake textcaptcha:config to generate a template config file'
31
+ raise ArgumentError.new('could not find any textcaptcha options, in config/textcaptcha.yml or model - run rake textcaptcha:config to generate a template config file')
32
32
  end
33
33
  end
34
34
 
@@ -24,7 +24,7 @@ module ActsAsTextcaptcha
24
24
  end
25
25
 
26
26
  response = http.get(url.path)
27
- if response.body.empty?
27
+ if response.body.to_s.empty?
28
28
  raise ActsAsTextcaptcha::EmptyResponseError
29
29
  else
30
30
  return parse(response.body)
@@ -1,3 +1,3 @@
1
1
  module ActsAsTextcaptcha
2
- VERSION = "4.1.2"
2
+ VERSION = "4.1.3"
3
3
  end
@@ -24,7 +24,11 @@ ActiveRecord::Schema.define(:version => 0) do
24
24
  t.string :name
25
25
  end
26
26
 
27
- create_table :strong_widgets, :force => true do |t|
27
+ create_table :strong_protected_widgets, :force => true do |t|
28
+ t.string :name
29
+ end
30
+
31
+ create_table :strong_accessible_widgets, :force => true do |t|
28
32
  t.string :name
29
33
  end
30
34
  end
@@ -19,7 +19,7 @@ elsif ENV['TRAVIS']
19
19
  end
20
20
 
21
21
  require 'minitest/autorun'
22
- require 'fakeweb'
22
+ require 'webmock/minitest'
23
23
 
24
24
  require 'rails/all'
25
25
 
@@ -27,13 +27,13 @@ require 'acts_as_textcaptcha'
27
27
  require './test/test_models'
28
28
 
29
29
  # load and initialize test db schema
30
- ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'acts_as_textcaptcha.sqlite3.db')
30
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => 'tmp/test_db/acts_as_textcaptcha.sqlite3.db')
31
31
  load(File.dirname(__FILE__) + "/schema.rb")
32
32
 
33
33
  # initialize a Rails.cache (use a basic memory store in tests)
34
- RAILS_CACHE = ActiveSupport::Cache::MemoryStore.new
34
+ Rails.cache = ActiveSupport::Cache::MemoryStore.new
35
35
 
36
36
  # additional helper methods for use in tests
37
37
  def find_in_cache(key)
38
- RAILS_CACHE.read("#{ActsAsTextcaptcha::TextcaptchaCache::CACHE_KEY_PREFIX}#{key}")
38
+ Rails.cache.read("#{ActsAsTextcaptcha::TextcaptchaCache::CACHE_KEY_PREFIX}#{key}")
39
39
  end
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  # models for use in tests
3
2
 
4
3
  class Widget < ActiveRecord::Base
@@ -49,10 +48,19 @@ class Contact
49
48
  acts_as_textcaptcha :questions => [{ :question => 'one+1', :answers => "2,two,апельсин" }]
50
49
  end
51
50
 
52
- # ActiveRecord model using the strong parameters gem
53
- require 'strong_parameters'
51
+ class StrongAccessibleWidget < ActiveRecord::Base
52
+
53
+ # stub out attr_accessbile interface for testing
54
+ def self.accessible_attributes(role = :default); end
55
+ def self.attr_accessible(*args); end
56
+
57
+ acts_as_textcaptcha 'questions' => [{ 'question' => '1+1', 'answers' => '2,two' }]
58
+ end
59
+
60
+ class StrongProtectedWidget < StrongAccessibleWidget
61
+
62
+ # stub out attr_protected interface for testing
63
+ def self.attr_protected(*args); end
54
64
 
55
- class StrongWidget < ActiveRecord::Base
56
- include ActiveModel::ForbiddenAttributesProtection
57
65
  acts_as_textcaptcha 'questions' => [{ 'question' => '1+1', 'answers' => '2,two' }]
58
66
  end
@@ -2,15 +2,11 @@ require File.expand_path(File.dirname(__FILE__)+'/test_helper')
2
2
 
3
3
  describe 'TextcaptchaApi' do
4
4
 
5
- after(:each) do
6
- FakeWeb.clean_registry
7
- end
8
-
9
5
  describe 'with a valid xml response' do
10
6
 
11
7
  before(:each) do
12
8
  body = "<captcha><question>1+1?</question><answer>1</answer><answer>2</answer><answer>3</answer></captcha>"
13
- FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/abc|, :body => body)
9
+ stub_request(:get, "http://textcaptcha.com/api/abc").to_return(:body => body)
14
10
  end
15
11
 
16
12
  it 'should fetch and parse an answer from the service' do
@@ -33,18 +29,18 @@ describe 'TextcaptchaApi' do
33
29
  Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError,
34
30
  URI::InvalidURIError
35
31
  ].each do |error|
36
- FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/xyz|, :exception => error)
32
+ stub_request(:get, "http://textcaptcha.com/api/xyz").to_raise(error)
37
33
  ActsAsTextcaptcha::TextcaptchaApi.fetch('xyz').must_equal nil
38
34
  end
39
35
  end
40
36
 
41
37
  it 'should return nil when body cannot be parsed as XML' do
42
- FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/jibber|, :body => 'here be gibberish')
38
+ stub_request(:get, "http://textcaptcha.com/api/jibber").to_return(:body => 'here be gibberish')
43
39
  ActsAsTextcaptcha::TextcaptchaApi.fetch('jibber').must_equal nil
44
40
  end
45
41
 
46
42
  it 'should return nil when body is empty' do
47
- FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/empty|, :body => '')
43
+ stub_request(:get, "http://textcaptcha.com/api/empty").to_return(:body => '')
48
44
  ActsAsTextcaptcha::TextcaptchaApi.fetch('empty').must_equal nil
49
45
  end
50
46
  end
@@ -35,9 +35,9 @@ describe 'TextcaptchaHelper' do
35
35
  it 'should render question and answer fields, with hidden textcaptcha_key field' do
36
36
  html = render_template
37
37
 
38
- assert_match /\<label for\=\"note_textcaptcha_answer\"\>1\+1\<\/label\>/, html
39
- assert_match /\<input id\=\"note_textcaptcha_answer\" name\=\"note\[textcaptcha_answer\]\" size\=\"30\" type\=\"text\" value\=\"\" \/>/, html
40
- assert_match /\<input id\=\"note_textcaptcha_key\" name\=\"note\[textcaptcha_key\]\" type\=\"hidden\" value\=\"([0-9a-f]{32})\" \/\>/, html
38
+ assert_match(/\<label for\=\"note_textcaptcha_answer\"\>1\+1\<\/label\>/, html)
39
+ assert_match(/\<input value\=\"\" type\=\"text\" name\=\"note\[textcaptcha_answer\]\" id\=\"note_textcaptcha_answer\" \/\>/, html)
40
+ assert_match(/\<input type\=\"hidden\" value\=\"([0-9a-f]{32})\" name\=\"note\[textcaptcha_key\]\" id\=\"note_textcaptcha_key\" \/\>/, html)
41
41
  end
42
42
 
43
43
  it 'should render hidden answer and textcaptcha_key when only answer is present' do
@@ -45,24 +45,24 @@ describe 'TextcaptchaHelper' do
45
45
  @note.textcaptcha_answer = 2
46
46
  html = render_template
47
47
 
48
- refute_match /\<label for\=\"note_textcaptcha_answer\"\>1\+1\<\/label\>/, html
49
- assert_match /\<input id\=\"note_textcaptcha_answer\" name\=\"note\[textcaptcha_answer\]\" type\=\"hidden\" value\=\"2\" \/>/, html
50
- assert_match /\<input id\=\"note_textcaptcha_key\" name\=\"note\[textcaptcha_key\]\" type\=\"hidden\" value\=\"([0-9a-f]{32})\" \/\>/, html
48
+ refute_match(/\<label for\=\"note_textcaptcha_answer\"\>1\+1\<\/label\>/, html)
49
+ assert_match(/\<input type\=\"hidden\" value\=\"2\" name\=\"note\[textcaptcha_answer\]\" id\=\"note_textcaptcha_answer\" \/\>/, html)
50
+ assert_match(/\<input type\=\"hidden\" value\=\"([0-9a-f]{32})\" name\=\"note\[textcaptcha_key\]\" id\=\"note_textcaptcha_key\" \/\>/, html)
51
51
  end
52
52
 
53
53
  it 'should not render any question or answer when perform_textcaptcha? is false' do
54
54
  @note.turn_off_captcha = true
55
55
  html = render_template
56
56
 
57
- refute_match /note_textcaptcha_answer/, html
58
- refute_match /note_textcaptcha_key/, html
57
+ refute_match(/note_textcaptcha_answer/, html)
58
+ refute_match(/note_textcaptcha_key/, html)
59
59
  end
60
60
 
61
61
  it 'should not render any question or answer when textcaptcha_key is missing' do
62
62
  @note.textcaptcha_key = nil
63
63
  html = render_template
64
64
 
65
- refute_match /note_textcaptcha_answer/, html
66
- refute_match /note_textcaptcha_key/, html
65
+ refute_match(/note_textcaptcha_answer/, html)
66
+ refute_match(/note_textcaptcha_key/, html)
67
67
  end
68
68
  end
@@ -62,24 +62,6 @@ describe 'Textcaptcha' do
62
62
  end
63
63
  end
64
64
 
65
- describe 'with strong parameters' do
66
-
67
- before(:each) do
68
- @widget = StrongWidget.new
69
- end
70
-
71
- it 'should work' do
72
- @widget.textcaptcha
73
- @widget.textcaptcha_question.must_equal('1+1')
74
- @widget.valid?.must_equal false
75
- @widget.errors[:textcaptcha_answer].first.must_equal('is incorrect, try another question instead')
76
-
77
- @widget.textcaptcha_answer = 'two'
78
- @widget.valid?.must_equal true
79
- @widget.errors[:textcaptcha_answer].must_be_empty
80
- end
81
- end
82
-
83
65
  describe 'with fast expiry time' do
84
66
 
85
67
  before(:each) do
@@ -99,12 +81,10 @@ describe 'Textcaptcha' do
99
81
 
100
82
  describe 'textcaptcha API' do
101
83
 
102
- after(:each) do
103
- FakeWeb.clean_registry
104
- end
105
-
106
84
  it 'should generate a question from the service' do
107
85
  @review = Review.new
86
+ body = "<captcha><question>Something?</question><answer>f6f7fec07f372b7bd5eb196bbca0f3f4</answer></captcha>"
87
+ stub_request(:get, %r{http://textcaptcha.com/api/}).and_return(:body => body)
108
88
 
109
89
  @review.textcaptcha
110
90
  @review.textcaptcha_question.wont_be_nil
@@ -120,7 +100,7 @@ describe 'Textcaptcha' do
120
100
  @review = Review.new
121
101
  question = 'If tomorrow is Saturday, what day is today?'
122
102
  body = "<captcha><question>#{question}</question><answer>f6f7fec07f372b7bd5eb196bbca0f3f4</answer></captcha>"
123
- FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :body => body)
103
+ stub_request(:get, %r{http://textcaptcha.com/api/}).and_return(:body => body)
124
104
 
125
105
  @review.textcaptcha
126
106
  @review.textcaptcha_question.must_equal(question)
@@ -131,7 +111,7 @@ describe 'Textcaptcha' do
131
111
  @review = Review.new
132
112
  question = 'If tomorrow is Saturday, what day is today?'
133
113
  body = "<captcha><question>#{question}</question><answer>1</answer><answer>2</answer><answer>3</answer></captcha>"
134
- FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :body => body)
114
+ stub_request(:get, %r{http://textcaptcha.com/api}).and_return(:body => body)
135
115
 
136
116
  @review.textcaptcha
137
117
  @review.textcaptcha_question.must_equal(question)
@@ -140,7 +120,7 @@ describe 'Textcaptcha' do
140
120
 
141
121
  it 'should fallback to a user defined question when api returns nil' do
142
122
  @review = Review.new
143
- FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :body => '')
123
+ stub_request(:get, %r{http://textcaptcha.com/api}).and_return(:body => '')
144
124
  @review.textcaptcha
145
125
  @review.textcaptcha_question.must_equal('The green hat is what color?')
146
126
  find_in_cache(@review.textcaptcha_key).wont_be_nil
@@ -149,7 +129,7 @@ describe 'Textcaptcha' do
149
129
  it 'should not generate any question or answer when no user defined questions set' do
150
130
  @comment = Comment.new
151
131
 
152
- FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :exception => SocketError)
132
+ stub_request(:get, %r{http://textcaptcha.com/api/}).to_raise(SocketError)
153
133
  @comment.textcaptcha
154
134
  @comment.textcaptcha_question.must_equal nil
155
135
  @comment.textcaptcha_key.must_equal nil
@@ -158,7 +138,7 @@ describe 'Textcaptcha' do
158
138
  it 'should not generate any question or answer when user defined questions set incorrectly' do
159
139
  @comment = MovieReview.new
160
140
 
161
- FakeWeb.register_uri(:get, %r|http://textcaptcha\.com/api/|, :exception => SocketError)
141
+ stub_request(:get, %r{http://textcaptcha.com/api/}).to_raise(SocketError)
162
142
  @comment.textcaptcha
163
143
  @comment.textcaptcha_question.must_equal nil
164
144
  @comment.textcaptcha_key.must_equal nil
@@ -173,8 +153,46 @@ describe 'Textcaptcha' do
173
153
  end
174
154
 
175
155
  it 'should be configured with textcaptcha.yml' do
176
- Widget.textcaptcha_config[:api_key].must_equal '6eh1co0j12mi2ogcoggkkok4o'
177
- Widget.textcaptcha_config[:questions].length.must_equal 10
156
+ Widget.textcaptcha_config[:api_key].must_equal('6eh1co0j12mi2ogcoggkkok4o')
157
+ Widget.textcaptcha_config[:questions].length.must_equal(10)
158
+ end
159
+ end
160
+
161
+ describe 'with strong parameters' do
162
+
163
+ it 'should work with accessible_attr widget ' do
164
+ @widget = StrongAccessibleWidget.new
165
+
166
+ @widget.textcaptcha
167
+ @widget.textcaptcha_question.must_equal('1+1')
168
+ @widget.valid?.must_equal false
169
+ end
170
+
171
+ it 'should work with protected_attr widget ' do
172
+ @widget = StrongProtectedWidget.new
173
+
174
+ @widget.textcaptcha
175
+ @widget.textcaptcha_question.must_equal('1+1')
176
+ @widget.valid?.must_equal false
177
+ end
178
+ end
179
+
180
+ describe 'when missing config' do
181
+
182
+ it 'should raise an error' do
183
+ YAML.stub :load, -> { raise 'some bad things happened' } do
184
+
185
+ error = assert_raises(ArgumentError) do
186
+ class NoConfig
187
+ include ActiveModel::Validations
188
+ include ActiveModel::Conversion
189
+ extend ActsAsTextcaptcha::Textcaptcha
190
+ acts_as_textcaptcha
191
+ end
192
+ end
193
+
194
+ error.message.must_match(/could not find any textcaptcha options/)
195
+ end
178
196
  end
179
197
  end
180
198
  end
metadata CHANGED
@@ -1,31 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_textcaptcha
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.2
4
+ version: 4.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Hutchinson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-05-11 00:00:00.000000000 Z
11
+ date: 2016-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: mime-types
14
+ name: rails
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 4.2.6
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 4.2.6
27
27
  - !ruby/object:Gem::Dependency
28
- name: rails
28
+ name: mime-types
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -109,21 +109,7 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: fakeweb
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
125
- - !ruby/object:Gem::Dependency
126
- name: strong_parameters
112
+ name: webmock
127
113
  requirement: !ruby/object:Gem::Requirement
128
114
  requirements:
129
115
  - - ">="
@@ -150,20 +136,6 @@ dependencies:
150
136
  - - ">="
151
137
  - !ruby/object:Gem::Version
152
138
  version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: pry
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
139
  description: |-
168
140
  Simple question/answer based spam protection for your Rails models.
169
141
  You can define your own logic questions and/or fetch questions from the textcaptcha.com API.
@@ -173,19 +145,20 @@ email:
173
145
  - matt@hiddenloop.com
174
146
  executables: []
175
147
  extensions: []
176
- extra_rdoc_files:
177
- - README.rdoc
178
- - LICENSE
148
+ extra_rdoc_files: []
179
149
  files:
180
150
  - ".coveralls.yml"
181
151
  - ".gitignore"
182
152
  - ".travis.yml"
183
- - CHANGELOG
153
+ - CHANGELOG.md
154
+ - CODE_OF_CONDUCT.md
155
+ - CONTRIBUTING.md
184
156
  - Gemfile
185
- - LICENSE
186
- - README.rdoc
157
+ - LICENSE.txt
158
+ - README.md
187
159
  - Rakefile
188
160
  - acts_as_textcaptcha.gemspec
161
+ - bin/console
189
162
  - config/textcaptcha.yml
190
163
  - init.rb
191
164
  - lib/acts_as_textcaptcha.rb
@@ -204,8 +177,10 @@ files:
204
177
  - test/textcaptcha_helper_test.rb
205
178
  - test/textcaptcha_test.rb
206
179
  homepage: http://github.com/matthutchinson/acts_as_textcaptcha
207
- licenses: []
208
- metadata: {}
180
+ licenses:
181
+ - MIT
182
+ metadata:
183
+ allowed_push_host: https://rubygems.org
209
184
  post_install_message:
210
185
  rdoc_options: []
211
186
  require_paths: