kamcaptcha 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile CHANGED
@@ -1,6 +1,7 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  group :test do
4
+ gem "rmagick"
4
5
  gem "ruby-debug", "~> 0.10.4", :require => nil, :platforms => :ruby_18
5
6
  gem "debugger", "~> 1.1.1", :require => nil, :platforms => :ruby_19
6
7
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Kamcaptcha
1
+ # Kamcaptcha [![Build Status](https://secure.travis-ci.org/morten/kamcaptcha.png)](http://travis-ci.org/morten/kamcaptcha)
2
2
 
3
3
  A captcha system that uses less ridiculous images than ReCAPTCHA. Kamcaptcha has two somewhat independent parts to it, a generator for building the word images to present, and then a runtime configuration for checking validity of what gets submitted.
4
4
 
data/bin/kamcaptcha CHANGED
@@ -21,7 +21,7 @@ Usage examples:
21
21
  kamcaptcha tmp/
22
22
  kamcaptcha --count 100 tmp/
23
23
  kamcaptcha --height 100 --width 300 tmp/
24
- kamcaptcha --length 8 --format gif tmp/
24
+ kamcaptcha --length 8-10 --source random --format gif tmp/
25
25
 
26
26
  A default run creates a "./tmp" directory and generates 10 random five character word PNG images, each 240x50 pixels in size.
27
27
 
@@ -32,7 +32,8 @@ EOS
32
32
  opt :count, "How many words to generate", :default => 10
33
33
  opt :height, "Height of the word image in pixels", :default => 50
34
34
  opt :width, "Width of the word image in pixesks", :default => 240
35
- opt :length, "Length of the word in number of characters", :default => 5
35
+ opt :source, "How to generate words, [dictionary|random]", :default => "dictionary"
36
+ opt :length, "Length of the word in number of characters, or as a range e.g. 7-9", :default => "5"
36
37
  opt :format, "Image file format", :default => "png"
37
38
  end
38
39
 
@@ -43,10 +44,11 @@ end
43
44
 
44
45
  Kamcaptcha.salt = opts[:salt] || Digest::SHA2.hexdigest((0...64).map { rand(150).chr }.join)
45
46
 
46
- puts "Generating #{opts[:count]} words into #{ARGV[0]}\n\n"
47
+ puts "Generating #{opts[:count]} words into #{ARGV[0]} - hang tight...\n\n"
47
48
 
48
- opts[:count].times do |i|
49
- puts "\t#{i+1}\t"+Kamcaptcha::Generator.generate(ARGV[0], opts)
49
+ files = Kamcaptcha::Generator.generate(ARGV[0], opts)
50
+ files.each_with_index do |file, index|
51
+ puts "\t#{index+1}\t#{file}"
50
52
  end
51
53
 
52
54
  puts "\nRemember to set Kamcaptcha.salt = '#{Kamcaptcha.salt}' in your application\n"
data/kamcaptcha.gemspec CHANGED
@@ -1,4 +1,4 @@
1
- Gem::Specification.new "kamcaptcha", "0.0.1" do |s|
1
+ Gem::Specification.new "kamcaptcha", "0.1.0" do |s|
2
2
  s.summary = "A captcha image generator that's a little less retarded"
3
3
  s.description = "Helps humankind with simpler captchas"
4
4
  s.authors = [ "Morten Primdahl" ]
@@ -1,39 +1,104 @@
1
- require "rubygems"
2
-
3
1
  begin
4
- require "rmagick"
2
+ require "RMagick"
5
3
  rescue LoadError => e
6
4
  puts "RMagick required to run the generator, gem install rmagick"
7
- return
5
+ exit
8
6
  end
9
7
 
10
8
  module Kamcaptcha
11
9
  class Generator
10
+ class WordGenerator
11
+ attr_reader :min, :max
12
+
13
+ def initialize(length)
14
+ if length.to_s =~ /^(\d+)$/
15
+ @min = @max = $1.to_i
16
+ elsif length =~ /^(\d+)-(\d+)$/
17
+ @min = [$1.to_i, $2.to_i].min
18
+ @max = [$1.to_i, $2.to_i].max
19
+ else
20
+ raise ArgumentError.new("Invalid word length specified: #{length}")
21
+ end
22
+ end
23
+ end
24
+
25
+ class RandomWordGenerator < WordGenerator
26
+ CHARS = "23456789ABCDEFGHJKLMNPQRSTUVXYZ".split("")
27
+
28
+ def generate
29
+ length = min
30
+ length += Kernel.rand(max - min) unless max == min
31
+
32
+ (1..length).map { CHARS[rand(CHARS.size)] }.join(" ")
33
+ end
34
+ end
35
+
36
+ class DictionaryWordGenerator < WordGenerator
37
+ class << self
38
+ attr_accessor :dict # Use this to set a custom dictionary or dictionary generating function
39
+ end
40
+
41
+ def generate
42
+ words[rand(words.size)].split("").join(" ")
43
+ end
44
+
45
+ def words
46
+ @words ||= begin
47
+ if self.class.dict
48
+ if self.class.dict.respond_to?(:call)
49
+ w = self.class.dict.call
50
+ else
51
+ w = self.class.dict
52
+ end
53
+ else
54
+ w = default_dict
55
+ end
56
+
57
+ w.each_with_index { |word, i| w[i] = word.upcase }
58
+ w.select { |w| w.size >= min && w.size <= max && w !~ /O/ }
59
+ end
60
+ end
61
+
62
+ def default_dict
63
+ return File.read("/usr/share/dict/words").split("\n") if File.exists?("/usr/share/dict/words")
64
+ return File.read("/usr/dict/words").split("\n") if File.exists?("/usr/dict/words")
65
+
66
+ raise ArgumentError.new("Sorry, need a dictionary file")
67
+ end
68
+ end
69
+
12
70
  DEFAULTS = {
13
- :chars => "23456789ABCDEFGHJKLMNPQRSTUVXYZ".split(""),
14
71
  :width => 240,
15
72
  :height => 50,
16
73
  :length => 5,
17
- :format => "png"
74
+ :format => "png",
75
+ :count => 1
18
76
  }
19
77
 
20
78
  def self.generate(path, options = {})
21
79
  options = DEFAULTS.merge(options)
22
80
 
23
- word = generate_word(options[:chars], options[:length])
24
- image = build_image(word, options[:width], options[:height])
81
+ if options[:source] != "random"
82
+ source = DictionaryWordGenerator.new(options[:length])
83
+ else
84
+ source = RandomWordGenerator.new(options[:length])
85
+ end
86
+
87
+ files = []
25
88
 
26
- name = word.delete(" ").downcase
27
- file = File.join(path, Kamcaptcha.encrypt(name) + ".#{options[:format]}")
89
+ options[:count].times do
90
+ word = source.generate
91
+ image = build_image(word, options[:width], options[:height])
92
+ name = word.delete(" ").downcase
93
+ file = File.join(path, Kamcaptcha.encrypt(name) + ".#{options[:format]}")
28
94
 
29
- image.write(file)
30
- image.destroy!
95
+ image.write(file)
96
+ image.destroy!
31
97
 
32
- file
33
- end
98
+ files << file
99
+ end
34
100
 
35
- def self.generate_word(chars, size)
36
- (1..size).map { chars[rand(chars.size)] }.join(" ")
101
+ files
37
102
  end
38
103
 
39
104
  def self.build_image(word, width, height)
data/test/test_helper.rb CHANGED
@@ -6,6 +6,7 @@ require "minitest/autorun"
6
6
 
7
7
  Bundler.require
8
8
 
9
+ require "RMagick"
9
10
  require "debugger" unless ENV["TRAVIS"]
10
11
 
11
12
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
@@ -1,15 +1,42 @@
1
+ require File.expand_path("test/test_helper")
2
+
1
3
  describe Kamcaptcha::Generator do
2
- describe "#generate_word" do
3
- it "builds a word by the given chars and length" do
4
- word = Kamcaptcha::Generator.generate_word([ "a", "b" ], 6)
5
- assert_equal 6, word.split(" ").size
6
- assert_match /[ab ]+/, word
4
+
5
+ describe Kamcaptcha::Generator::RandomWordGenerator do
6
+ subject { Kamcaptcha::Generator::RandomWordGenerator.new("3-10") }
7
+
8
+ it "delivers words of the specified size range" do
9
+ 20.times do
10
+ word = subject.generate.delete(" ")
11
+
12
+ assert word.size >= 3, "Size mismatch #{word}"
13
+ assert word.size <= 10, "Size mismatch #{word}"
14
+
15
+ assert_match /[0-9A-Z]+/, word
16
+ end
17
+ end
18
+ end
19
+
20
+ describe Kamcaptcha::Generator::DictionaryWordGenerator do
21
+ after do
22
+ Kamcaptcha::Generator::DictionaryWordGenerator.dict = nil
23
+ end
24
+
25
+ subject { Kamcaptcha::Generator::DictionaryWordGenerator.new("1-5") }
26
+
27
+ it "delivers words from the dict" do
28
+ Kamcaptcha::Generator::DictionaryWordGenerator.dict = [ "foo", "fum" ]
29
+
30
+ 20.times do
31
+ word = subject.generate.delete(" ")
32
+ assert [ "FOO", "FUM" ].member?(word), "Word #{word} not found"
33
+ end
7
34
  end
8
35
  end
9
36
 
10
37
  describe "#generate" do
11
38
  it "generates a file" do
12
- file = Kamcaptcha::Generator.generate("/tmp")
39
+ file = Kamcaptcha::Generator.generate("/tmp", :source => "random").first
13
40
  assert File.exist?(file)
14
41
  File.unlink(file)
15
42
  end
@@ -1,3 +1,5 @@
1
+ require File.expand_path("test/test_helper")
2
+
1
3
  describe Kamcaptcha::Helper do
2
4
  include Kamcaptcha::Helper
3
5
 
@@ -1,3 +1,5 @@
1
+ require File.expand_path("test/test_helper")
2
+
1
3
  describe Kamcaptcha do
2
4
 
3
5
  describe "#images" do
@@ -1,3 +1,5 @@
1
+ require File.expand_path("test/test_helper")
2
+
1
3
  describe Kamcaptcha::Validation do
2
4
  def params
3
5
  @params
metadata CHANGED
@@ -1,119 +1,118 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: kamcaptcha
3
- version: !ruby/object:Gem::Version
4
- version: 0.0.1
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Morten Primdahl
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-09-11 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2012-09-12 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: trollop
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '2.0'
22
- type: :runtime
23
22
  prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
23
+ requirement: &id001 !ruby/object:Gem::Requirement
25
24
  none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '2.0'
30
- - !ruby/object:Gem::Dependency
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 2
31
+ - 0
32
+ version: "2.0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
31
36
  name: rake
32
- requirement: !ruby/object:Gem::Requirement
33
- none: false
34
- requirements:
35
- - - ! '>='
36
- - !ruby/object:Gem::Version
37
- version: '0'
38
- type: :development
39
37
  prerelease: false
40
- version_requirements: !ruby/object:Gem::Requirement
38
+ requirement: &id002 !ruby/object:Gem::Requirement
41
39
  none: false
42
- requirements:
43
- - - ! '>='
44
- - !ruby/object:Gem::Version
45
- version: '0'
46
- - !ruby/object:Gem::Dependency
47
- name: bundler
48
- requirement: !ruby/object:Gem::Requirement
49
- none: false
50
- requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
54
47
  type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: bundler
55
51
  prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- - !ruby/object:Gem::Dependency
63
- name: rmagick
64
- requirement: !ruby/object:Gem::Requirement
52
+ requirement: &id003 !ruby/object:Gem::Requirement
65
53
  none: false
66
- requirements:
67
- - - ! '>='
68
- - !ruby/object:Gem::Version
69
- version: '0'
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
70
61
  type: :development
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: rmagick
71
65
  prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ! '>='
76
- - !ruby/object:Gem::Version
77
- version: '0'
78
- - !ruby/object:Gem::Dependency
79
- name: minitest
80
- requirement: !ruby/object:Gem::Requirement
66
+ requirement: &id004 !ruby/object:Gem::Requirement
81
67
  none: false
82
- requirements:
83
- - - ! '>='
84
- - !ruby/object:Gem::Version
85
- version: '0'
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
86
75
  type: :development
76
+ version_requirements: *id004
77
+ - !ruby/object:Gem::Dependency
78
+ name: minitest
87
79
  prerelease: false
88
- version_requirements: !ruby/object:Gem::Requirement
80
+ requirement: &id005 !ruby/object:Gem::Requirement
89
81
  none: false
90
- requirements:
91
- - - ! '>='
92
- - !ruby/object:Gem::Version
93
- version: '0'
94
- - !ruby/object:Gem::Dependency
95
- name: uuidtools
96
- requirement: !ruby/object:Gem::Requirement
97
- none: false
98
- requirements:
99
- - - ! '>='
100
- - !ruby/object:Gem::Version
101
- version: 2.1.3
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
102
89
  type: :development
90
+ version_requirements: *id005
91
+ - !ruby/object:Gem::Dependency
92
+ name: uuidtools
103
93
  prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
94
+ requirement: &id006 !ruby/object:Gem::Requirement
105
95
  none: false
106
- requirements:
107
- - - ! '>='
108
- - !ruby/object:Gem::Version
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ hash: 13
100
+ segments:
101
+ - 2
102
+ - 1
103
+ - 3
109
104
  version: 2.1.3
105
+ type: :development
106
+ version_requirements: *id006
110
107
  description: Helps humankind with simpler captchas
111
108
  email: primdahl@me.com
112
- executables:
109
+ executables:
113
110
  - kamcaptcha
114
111
  extensions: []
112
+
115
113
  extra_rdoc_files: []
116
- files:
114
+
115
+ files:
117
116
  - .gitignore
118
117
  - .travis.yml
119
118
  - Gemfile
@@ -132,28 +131,37 @@ files:
132
131
  - test/unit/test_kamcaptcha.rb
133
132
  - test/unit/test_validation.rb
134
133
  homepage: http://github.com/morten/kamcaptcha
135
- licenses:
134
+ licenses:
136
135
  - MIT
137
136
  post_install_message:
138
137
  rdoc_options: []
139
- require_paths:
138
+
139
+ require_paths:
140
140
  - lib
141
- required_ruby_version: !ruby/object:Gem::Requirement
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
142
  none: false
143
- requirements:
144
- - - ! '>='
145
- - !ruby/object:Gem::Version
146
- version: '0'
147
- required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ hash: 3
147
+ segments:
148
+ - 0
149
+ version: "0"
150
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
151
  none: false
149
- requirements:
150
- - - ! '>='
151
- - !ruby/object:Gem::Version
152
- version: '0'
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ hash: 3
156
+ segments:
157
+ - 0
158
+ version: "0"
153
159
  requirements: []
160
+
154
161
  rubyforge_project:
155
- rubygems_version: 1.8.23
162
+ rubygems_version: 1.8.15
156
163
  signing_key:
157
164
  specification_version: 3
158
165
  summary: A captcha image generator that's a little less retarded
159
166
  test_files: []
167
+