perquackey 0.7.0 → 0.7.1
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/.gitignore +6 -0
- data/CHANGELOG.rdoc +8 -0
- data/Gemfile +8 -0
- data/README.rdoc +51 -1
- data/Rakefile +1 -9
- data/TODO.rdoc +0 -1
- data/bin/perquackey +2 -29
- data/{lib/perquackey/resources → data/perquackey/dict}/TWL06.txt +0 -0
- data/data/perquackey/templates/index.erb +29 -0
- data/data/perquackey/templates/layout.erb +24 -0
- data/ext/perquackey/anagrams.c +69 -0
- data/ext/perquackey/extconf.rb +1 -1
- data/lib/perquackey.rb +15 -47
- data/lib/perquackey/application.rb +48 -0
- data/lib/perquackey/console.rb +1 -2
- data/lib/perquackey/dictionary.rb +15 -0
- data/lib/perquackey/game.rb +17 -0
- data/lib/perquackey/server.rb +1 -2
- data/lib/perquackey/word_table.rb +31 -0
- data/perquackey.gemspec +27 -27
- data/test/dictionary_test.rb +3 -3
- data/test/{test_helper.rb → helper.rb} +1 -2
- data/test/word_table_test.rb +12 -6
- metadata +51 -22
- data/ext/perquackey/dictionary.c +0 -68
- data/lib/perquackey/dictionary.bundle +0 -0
- data/lib/perquackey/server/index.erb +0 -23
- data/lib/perquackey/server/layout.erb +0 -12
- data/lib/perquackey/version.rb +0 -3
data/.gitignore
ADDED
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
== Git
|
2
|
+
* Refactor Dictionary to have Ruby parts, with a C extension starting at the fgets on the IO stream.
|
3
|
+
* Reorganize code for autoloading.
|
4
|
+
* Reorganize code to properly use datadir.
|
5
|
+
* Begin scant documentation.
|
6
|
+
* Use HTML5 for web templates.
|
7
|
+
* Remove separate --port argument. It's now an optional part of --server.
|
8
|
+
|
1
9
|
== 0.7.0 -- 2010-03-30
|
2
10
|
* Switch from YAWL to TWL06 word list.
|
3
11
|
* Upgrade build system to use Bundler.
|
data/Gemfile
ADDED
data/README.rdoc
CHANGED
@@ -1,3 +1,53 @@
|
|
1
1
|
= Perquackey
|
2
2
|
|
3
|
-
The different word game.
|
3
|
+
Perquackey is "The different word game." I love it.
|
4
|
+
|
5
|
+
This tool helps you know what words you could have spelled, had you had more
|
6
|
+
time / vocabulary / clarity of thought. Sometimes it's helpful for learning,
|
7
|
+
and sometimes it's just annoying.
|
8
|
+
|
9
|
+
== Install
|
10
|
+
|
11
|
+
$ gem install perquackey
|
12
|
+
|
13
|
+
== Console Mode
|
14
|
+
|
15
|
+
$ perquackey
|
16
|
+
Type ctrl-d or quit to exit.
|
17
|
+
> foobar
|
18
|
+
abo barf
|
19
|
+
arb boar
|
20
|
+
arf boor
|
21
|
+
bar bora
|
22
|
+
boa broo
|
23
|
+
boo faro
|
24
|
+
bra fora
|
25
|
+
bro forb
|
26
|
+
fab roof
|
27
|
+
far
|
28
|
+
fob
|
29
|
+
for
|
30
|
+
fro
|
31
|
+
oaf
|
32
|
+
oar
|
33
|
+
oba
|
34
|
+
ora
|
35
|
+
orb
|
36
|
+
rob
|
37
|
+
> quit
|
38
|
+
Goodbye.
|
39
|
+
$
|
40
|
+
|
41
|
+
== Server Mode
|
42
|
+
|
43
|
+
$ perquackey --server
|
44
|
+
== Sinatra/1.0 has taken the stage on 3000 for development with backup from WEBrick
|
45
|
+
[2010-03-30 21:28:19] INFO WEBrick 1.3.1
|
46
|
+
[2010-03-30 21:28:19] INFO ruby 1.8.7 (2010-01-10) [i686-darwin10.2.0]
|
47
|
+
[2010-03-30 21:28:19] INFO WEBrick::HTTPServer#start: pid=37884 port=3000
|
48
|
+
...
|
49
|
+
|
50
|
+
== Rack It Up
|
51
|
+
|
52
|
+
require 'perquackey'
|
53
|
+
run Perquackey::Server
|
data/Rakefile
CHANGED
@@ -1,11 +1,3 @@
|
|
1
|
-
require 'perquackey/version'
|
2
1
|
require 'shoe'
|
3
2
|
|
4
|
-
Shoe.
|
5
|
-
spec.add_runtime_dependency('sinatra')
|
6
|
-
end
|
7
|
-
|
8
|
-
desc 'Run perquackey'
|
9
|
-
task :exec, :options, :needs => :compile do |_, arguments|
|
10
|
-
ruby "-rubygems -Iext -Ilib bin/perquackey #{arguments[:options]}"
|
11
|
-
end
|
3
|
+
Shoe::Tasks.define('perquackey.gemspec')
|
data/TODO.rdoc
CHANGED
data/bin/perquackey
CHANGED
@@ -1,31 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# To run this script in-project (rather than via rubygems wrapper), you'll
|
4
|
-
# need to say something like:
|
5
|
-
#
|
6
|
-
# RUBYOPT=rubygems RUBYLIB=ext:lib ./bin/perquackey
|
7
|
-
#
|
8
|
-
require 'optparse'
|
9
|
-
require 'ostruct'
|
10
2
|
|
11
|
-
|
12
|
-
|
13
|
-
opts = OptionParser.new do |opts|
|
14
|
-
opts.banner = "Usage: #{File.basename($0)} [options]"
|
15
|
-
opts.separator ''
|
16
|
-
opts.on('-s', '--server', 'Run as a web server') { conf.mode = :server }
|
17
|
-
opts.on('-p', '--port PORT', "Port for web server (defaults to #{conf.port})") { |port| conf.port = port }
|
18
|
-
opts.on('-h', '--help', 'Show this message') { puts opts; exit }
|
19
|
-
opts.separator ''
|
20
|
-
end
|
21
|
-
|
22
|
-
opts.parse! ARGV
|
23
|
-
|
24
|
-
case conf.mode
|
25
|
-
when :console
|
26
|
-
require 'perquackey/console'
|
27
|
-
Perquackey::Console.run!
|
28
|
-
when :server
|
29
|
-
require 'perquackey/server'
|
30
|
-
Perquackey::Server.run!(:port => conf.port)
|
31
|
-
end
|
3
|
+
require 'perquackey'
|
4
|
+
Perquackey::Application.run!(ARGV)
|
File without changes
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<form action="/" method="post">
|
2
|
+
<input name="letters"
|
3
|
+
value="<%= letters %>"
|
4
|
+
autocomplete="on"
|
5
|
+
autofocus="on"
|
6
|
+
maxlength="13"
|
7
|
+
pattern="[a-z]{10}([a-z]{3})?"
|
8
|
+
placeholder="Type your letters here."
|
9
|
+
required="on"
|
10
|
+
title="Perquackey rolls are 10 or 13 letters."
|
11
|
+
type="search"
|
12
|
+
/>
|
13
|
+
</form>
|
14
|
+
|
15
|
+
<table>
|
16
|
+
<tr>
|
17
|
+
<% words.headers.each do |header| %>
|
18
|
+
<th><%= header %></th>
|
19
|
+
<% end %>
|
20
|
+
</tr>
|
21
|
+
|
22
|
+
<% words.each do |row| %>
|
23
|
+
<tr>
|
24
|
+
<% row.each do |word| %>
|
25
|
+
<td><%= word %></td>
|
26
|
+
<% end %>
|
27
|
+
</tr>
|
28
|
+
<% end %>
|
29
|
+
</table>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8" />
|
5
|
+
<title>Perquackey</title>
|
6
|
+
</head>
|
7
|
+
|
8
|
+
<body>
|
9
|
+
<header>
|
10
|
+
<h1>Perquackey</h1>
|
11
|
+
</header>
|
12
|
+
|
13
|
+
<%= yield %>
|
14
|
+
|
15
|
+
<footer>
|
16
|
+
<p>
|
17
|
+
Now using the
|
18
|
+
<a href="http://en.wikipedia.org/wiki/Tournament_Word_List">TWL06 word list</a>
|
19
|
+
courtesy of the
|
20
|
+
<a href="http://www.isc.ro/en/commands/lists.html">Internet Scrabble Club</a>.
|
21
|
+
</p>
|
22
|
+
</footer>
|
23
|
+
</body>
|
24
|
+
</html>
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "rubyio.h"
|
3
|
+
|
4
|
+
#define MAX_LENGTH 40
|
5
|
+
#define XOUT '@'
|
6
|
+
#define FALSE 0
|
7
|
+
#define TRUE 1
|
8
|
+
|
9
|
+
static VALUE mPerquackey;
|
10
|
+
static VALUE mAnagrams;
|
11
|
+
|
12
|
+
void chop(char *string) {
|
13
|
+
int length = strlen(string);
|
14
|
+
|
15
|
+
if (length > 0 && string[length-1] == '\n') {
|
16
|
+
string[length-1] = '\0';
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
int anagram_p(char *letters, char *word) {
|
21
|
+
static char scratch_pad[MAX_LENGTH];
|
22
|
+
register char *scratch_pad_ptr;
|
23
|
+
|
24
|
+
strcpy(scratch_pad, letters);
|
25
|
+
|
26
|
+
while (*word) {
|
27
|
+
if ((scratch_pad_ptr = strchr(scratch_pad, *word++)) != NULL) {
|
28
|
+
*scratch_pad_ptr = XOUT;
|
29
|
+
} else {
|
30
|
+
return FALSE;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
return TRUE;
|
35
|
+
}
|
36
|
+
|
37
|
+
VALUE Anagrams_anagrams(VALUE self, VALUE letters) {
|
38
|
+
return rb_apply(
|
39
|
+
rb_apply(self,
|
40
|
+
rb_intern("enum_for"),
|
41
|
+
rb_ary_new3(2, rb_str_new2("each_anagram"), letters)),
|
42
|
+
rb_intern("to_a"),
|
43
|
+
rb_ary_new());
|
44
|
+
}
|
45
|
+
|
46
|
+
VALUE Anagrams_each_anagram(VALUE self, VALUE letters_value) {
|
47
|
+
rb_io_t *stream;
|
48
|
+
char word[MAX_LENGTH];
|
49
|
+
char *letters = RSTRING(letters_value)->ptr;
|
50
|
+
|
51
|
+
GetOpenFile(self, stream);
|
52
|
+
|
53
|
+
while (fgets(word, sizeof(word), stream->f) != NULL) {
|
54
|
+
chop(word);
|
55
|
+
|
56
|
+
if (anagram_p(letters, word)) {
|
57
|
+
rb_yield(rb_str_new2(word));
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
return Qnil;
|
62
|
+
}
|
63
|
+
|
64
|
+
void Init_anagrams() {
|
65
|
+
mPerquackey = rb_define_module("Perquackey");
|
66
|
+
mAnagrams = rb_define_module_under(mPerquackey, "Anagrams");
|
67
|
+
rb_define_method(mAnagrams, "anagrams", Anagrams_anagrams, 1);
|
68
|
+
rb_define_method(mAnagrams, "each_anagram", Anagrams_each_anagram, 1);
|
69
|
+
}
|
data/ext/perquackey/extconf.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
require 'mkmf'
|
2
|
-
create_makefile 'perquackey/
|
2
|
+
create_makefile 'perquackey/anagrams'
|
data/lib/perquackey.rb
CHANGED
@@ -1,51 +1,19 @@
|
|
1
|
-
require '
|
1
|
+
require 'pathname'
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'rbconfig/datadir'
|
2
4
|
|
3
5
|
module Perquackey
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
def minimum_length(letters)
|
18
|
-
letters.length > 10 ? 4 : 3
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class WordTable
|
23
|
-
include Enumerable
|
24
|
-
|
25
|
-
def initialize(list=[])
|
26
|
-
@table = Hash.new { |h, k| h[k] = [] }
|
27
|
-
|
28
|
-
list.each do |word|
|
29
|
-
@table[word.length] << word
|
30
|
-
end
|
31
|
-
|
32
|
-
if @table.empty?
|
33
|
-
@headers = []
|
34
|
-
@height = 0
|
35
|
-
else
|
36
|
-
@headers = @table.keys.min .. @table.keys.max
|
37
|
-
@height = @table.values.max { |a, b| a.length <=> b.length }.length
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def headers
|
42
|
-
@headers
|
43
|
-
end
|
44
|
-
|
45
|
-
def each
|
46
|
-
@height.times do |row_number|
|
47
|
-
yield headers.collect { |length| @table[length][row_number] or ' ' * length}
|
48
|
-
end
|
49
|
-
end
|
6
|
+
VERSION = '0.7.1'
|
7
|
+
|
8
|
+
autoload :Anagrams, 'perquackey/anagrams'
|
9
|
+
autoload :Application,'perquackey/application'
|
10
|
+
autoload :Console, 'perquackey/console'
|
11
|
+
autoload :Dictionary, 'perquackey/dictionary'
|
12
|
+
autoload :Game, 'perquackey/game'
|
13
|
+
autoload :Server, 'perquackey/server'
|
14
|
+
autoload :WordTable, 'perquackey/word_table'
|
15
|
+
|
16
|
+
def self.datadir
|
17
|
+
Pathname.new RbConfig.datadir('perquackey')
|
50
18
|
end
|
51
19
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Perquackey
|
4
|
+
class Application
|
5
|
+
def self.run!(argv) #:nodoc:
|
6
|
+
new.run!(argv)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@mode = :console
|
11
|
+
|
12
|
+
@options = OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: #{File.basename($0)} [OPTIONS]"
|
14
|
+
opts.separator ''
|
15
|
+
opts.separator 'Specific options:'
|
16
|
+
|
17
|
+
opts.on('-s', '--server [PORT]', 'Run a web server.') do |port|
|
18
|
+
@mode = :server
|
19
|
+
@port = port || 3000
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.separator ''
|
23
|
+
opts.separator 'Common options:'
|
24
|
+
|
25
|
+
opts.on_tail('-h', '--help', 'Show this message.') do
|
26
|
+
puts opts
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on_tail('-v', '--version', 'Print version and exit.') do
|
31
|
+
puts "perquackey #{Perquackey::VERSION}"
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run!(argv)
|
38
|
+
@options.parse!(argv)
|
39
|
+
|
40
|
+
case @mode
|
41
|
+
when :console
|
42
|
+
Perquackey::Console.run!
|
43
|
+
when :server
|
44
|
+
Perquackey::Server.run!(:port => @port)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/perquackey/console.rb
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Perquackey
|
2
|
+
class Dictionary
|
3
|
+
TOURNAMENT_WORD_LIST = Perquackey.datadir.join('dict', 'TWL06.txt')
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@word_list = TOURNAMENT_WORD_LIST
|
7
|
+
end
|
8
|
+
|
9
|
+
def words(letters)
|
10
|
+
@word_list.open do |stream|
|
11
|
+
stream.extend(Anagrams).anagrams(letters)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Perquackey
|
2
|
+
class Game
|
3
|
+
def initialize
|
4
|
+
@dictionary = Dictionary.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def words(letters)
|
8
|
+
WordTable.new(@dictionary.words(letters).reject { |word| word.length < minimum_length(letters) })
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def minimum_length(letters)
|
14
|
+
letters.length > 10 ? 4 : 3
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/perquackey/server.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
require 'perquackey'
|
2
1
|
require 'sinatra/base'
|
3
2
|
|
4
3
|
module Perquackey
|
5
4
|
class Server < Sinatra::Base
|
6
|
-
set :views,
|
5
|
+
set :views, Perquackey.datadir.join('templates')
|
7
6
|
|
8
7
|
get %r{^/([a-z]{0,13})$} do |letters|
|
9
8
|
erb :index, :locals => { :letters => letters, :words => Game.new.words(letters) }
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Perquackey
|
2
|
+
class WordTable
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize(list=[])
|
6
|
+
@table = Hash.new { |h, k| h[k] = [] }
|
7
|
+
|
8
|
+
list.each do |word|
|
9
|
+
@table[word.length] << word
|
10
|
+
end
|
11
|
+
|
12
|
+
if @table.empty?
|
13
|
+
@headers = []
|
14
|
+
@height = 0
|
15
|
+
else
|
16
|
+
@headers = @table.keys.min .. @table.keys.max
|
17
|
+
@height = @table.values.max { |a, b| a.length <=> b.length }.length
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def headers
|
22
|
+
@headers
|
23
|
+
end
|
24
|
+
|
25
|
+
def each
|
26
|
+
@height.times do |row_number|
|
27
|
+
yield headers.collect { |length| @table[length][row_number] or ' ' * length}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/perquackey.gemspec
CHANGED
@@ -1,33 +1,33 @@
|
|
1
|
-
|
1
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
2
|
+
require 'perquackey'
|
2
3
|
|
3
|
-
Gem::Specification.new do |
|
4
|
-
|
5
|
-
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = 'perquackey'
|
6
|
+
spec.version = Perquackey::VERSION
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
s.executables = ["perquackey"]
|
13
|
-
s.extensions = ["ext/perquackey/extconf.rb"]
|
14
|
-
s.extra_rdoc_files = ["CHANGELOG.rdoc", "README.rdoc", "TODO.rdoc"]
|
15
|
-
s.files = ["Rakefile", "lib/perquackey", "lib/perquackey/console.rb", "lib/perquackey/dictionary.bundle", "lib/perquackey/resources", "lib/perquackey/resources/TWL06.txt", "lib/perquackey/server", "lib/perquackey/server/index.erb", "lib/perquackey/server/layout.erb", "lib/perquackey/server.rb", "lib/perquackey/version.rb", "lib/perquackey.rb", "bin/perquackey", "CHANGELOG.rdoc", "README.rdoc", "TODO.rdoc", "perquackey.gemspec", "test/dictionary_test.rb", "test/test_helper.rb", "test/word_table_test.rb", "ext/perquackey/extconf.rb", "ext/perquackey/dictionary.c"]
|
16
|
-
s.rdoc_options = ["--main", "README.rdoc", "--title", "perquackey-0.7.0", "--inline-source"]
|
17
|
-
s.require_paths = ["lib"]
|
18
|
-
s.rubygems_version = %q{1.3.6}
|
19
|
-
s.summary = %q{Provides console session and simple webapp for looking up Perquackey word matches}
|
8
|
+
spec.summary = 'Provides console session and simple webapp for looking up Perquackey word matches'
|
9
|
+
spec.description = spec.summary
|
10
|
+
spec.author = 'Matthew Todd'
|
11
|
+
spec.email = 'matthew.todd@gmail.com'
|
12
|
+
spec.homepage = 'http://github.com/matthewtodd/perquackey'
|
20
13
|
|
21
|
-
|
22
|
-
|
23
|
-
|
14
|
+
spec.add_runtime_dependency 'sinatra'
|
15
|
+
spec.add_development_dependency 'redgreen'
|
16
|
+
spec.add_development_dependency 'shoe'
|
24
17
|
|
25
|
-
|
26
|
-
|
27
|
-
else
|
28
|
-
s.add_dependency(%q<sinatra>, [">= 0"])
|
29
|
-
end
|
30
|
-
else
|
31
|
-
s.add_dependency(%q<sinatra>, [">= 0"])
|
18
|
+
def spec.git_files(glob=nil)
|
19
|
+
`git ls-files -z --cached --other --exclude-standard #{glob}`.split("\0")
|
32
20
|
end
|
21
|
+
|
22
|
+
spec.files = spec.git_files
|
23
|
+
spec.executables = spec.git_files('bin/*').map &File.method(:basename)
|
24
|
+
spec.extensions = spec.git_files('ext/**/extconf.rb')
|
25
|
+
spec.test_files = spec.git_files('test/{,**/}*_test.rb')
|
26
|
+
|
27
|
+
spec.extra_rdoc_files = spec.git_files('{,**/}*.rdoc')
|
28
|
+
spec.rdoc_options = %W(
|
29
|
+
--main README.rdoc
|
30
|
+
--title #{spec.full_name}
|
31
|
+
--inline-source
|
32
|
+
)
|
33
33
|
end
|
data/test/dictionary_test.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require '
|
1
|
+
require 'test/helper'
|
2
2
|
|
3
3
|
class DictionaryTest < Test::Unit::TestCase
|
4
|
-
def
|
5
|
-
assert_equal ['ab', 'ba', 'cab'], Perquackey::Dictionary.new
|
4
|
+
def test_simple_search
|
5
|
+
assert_equal ['ab', 'ba', 'cab'], Perquackey::Dictionary.new.words('abc')
|
6
6
|
end
|
7
7
|
end
|
data/test/word_table_test.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
|
-
require '
|
1
|
+
require 'test/helper'
|
2
2
|
|
3
3
|
class WordTableTest < Test::Unit::TestCase
|
4
4
|
def test_handles_empty_list
|
5
|
-
empty_table = Perquackey::WordTable.new
|
5
|
+
empty_table = Perquackey::WordTable.new %w()
|
6
6
|
|
7
7
|
assert_equal [], empty_table.headers.to_a
|
8
|
-
assert_equal [], empty_table.
|
8
|
+
assert_equal [], empty_table.to_a
|
9
9
|
end
|
10
10
|
|
11
11
|
def test_handles_some_list
|
12
|
-
table = Perquackey::WordTable.new %w
|
12
|
+
table = Perquackey::WordTable.new %w(ape bear cat dog eagle fox goose hippo ibis)
|
13
13
|
|
14
14
|
assert_equal [3, 4, 5], table.headers.to_a
|
15
|
-
|
15
|
+
|
16
|
+
assert_equal [
|
17
|
+
'ape bear eagle',
|
18
|
+
'cat ibis goose',
|
19
|
+
'dog hippo',
|
20
|
+
'fox '
|
21
|
+
], table.collect { |row| row.join(' ') }
|
16
22
|
end
|
17
|
-
end
|
23
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 7
|
8
|
-
-
|
9
|
-
version: 0.7.
|
8
|
+
- 1
|
9
|
+
version: 0.7.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Matthew Todd
|
@@ -14,8 +14,8 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
18
|
-
default_executable:
|
17
|
+
date: 2010-04-16 00:00:00 +03:00
|
18
|
+
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: sinatra
|
@@ -29,7 +29,31 @@ dependencies:
|
|
29
29
|
version: "0"
|
30
30
|
type: :runtime
|
31
31
|
version_requirements: *id001
|
32
|
-
|
32
|
+
- !ruby/object:Gem::Dependency
|
33
|
+
name: redgreen
|
34
|
+
prerelease: false
|
35
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
segments:
|
40
|
+
- 0
|
41
|
+
version: "0"
|
42
|
+
type: :development
|
43
|
+
version_requirements: *id002
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: shoe
|
46
|
+
prerelease: false
|
47
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
segments:
|
52
|
+
- 0
|
53
|
+
version: "0"
|
54
|
+
type: :development
|
55
|
+
version_requirements: *id003
|
56
|
+
description: Provides console session and simple webapp for looking up Perquackey word matches
|
33
57
|
email: matthew.todd@gmail.com
|
34
58
|
executables:
|
35
59
|
- perquackey
|
@@ -40,27 +64,31 @@ extra_rdoc_files:
|
|
40
64
|
- README.rdoc
|
41
65
|
- TODO.rdoc
|
42
66
|
files:
|
43
|
-
-
|
44
|
-
- lib/perquackey/console.rb
|
45
|
-
- lib/perquackey/dictionary.bundle
|
46
|
-
- lib/perquackey/resources/TWL06.txt
|
47
|
-
- lib/perquackey/server/index.erb
|
48
|
-
- lib/perquackey/server/layout.erb
|
49
|
-
- lib/perquackey/server.rb
|
50
|
-
- lib/perquackey/version.rb
|
51
|
-
- lib/perquackey.rb
|
52
|
-
- bin/perquackey
|
67
|
+
- .gitignore
|
53
68
|
- CHANGELOG.rdoc
|
69
|
+
- Gemfile
|
54
70
|
- README.rdoc
|
71
|
+
- Rakefile
|
55
72
|
- TODO.rdoc
|
73
|
+
- bin/perquackey
|
74
|
+
- data/perquackey/dict/TWL06.txt
|
75
|
+
- data/perquackey/templates/index.erb
|
76
|
+
- data/perquackey/templates/layout.erb
|
77
|
+
- ext/perquackey/anagrams.c
|
78
|
+
- ext/perquackey/extconf.rb
|
79
|
+
- lib/perquackey.rb
|
80
|
+
- lib/perquackey/application.rb
|
81
|
+
- lib/perquackey/console.rb
|
82
|
+
- lib/perquackey/dictionary.rb
|
83
|
+
- lib/perquackey/game.rb
|
84
|
+
- lib/perquackey/server.rb
|
85
|
+
- lib/perquackey/word_table.rb
|
56
86
|
- perquackey.gemspec
|
57
87
|
- test/dictionary_test.rb
|
58
|
-
- test/
|
88
|
+
- test/helper.rb
|
59
89
|
- test/word_table_test.rb
|
60
|
-
- ext/perquackey/extconf.rb
|
61
|
-
- ext/perquackey/dictionary.c
|
62
90
|
has_rdoc: true
|
63
|
-
homepage:
|
91
|
+
homepage: http://github.com/matthewtodd/perquackey
|
64
92
|
licenses: []
|
65
93
|
|
66
94
|
post_install_message:
|
@@ -68,7 +96,7 @@ rdoc_options:
|
|
68
96
|
- --main
|
69
97
|
- README.rdoc
|
70
98
|
- --title
|
71
|
-
- perquackey-0.7.
|
99
|
+
- perquackey-0.7.1
|
72
100
|
- --inline-source
|
73
101
|
require_paths:
|
74
102
|
- lib
|
@@ -93,5 +121,6 @@ rubygems_version: 1.3.6
|
|
93
121
|
signing_key:
|
94
122
|
specification_version: 3
|
95
123
|
summary: Provides console session and simple webapp for looking up Perquackey word matches
|
96
|
-
test_files:
|
97
|
-
|
124
|
+
test_files:
|
125
|
+
- test/dictionary_test.rb
|
126
|
+
- test/word_table_test.rb
|
data/ext/perquackey/dictionary.c
DELETED
@@ -1,68 +0,0 @@
|
|
1
|
-
// After finding YAWL, I pretty much lifted this algorithm straight from its
|
2
|
-
// anagram.c. It's certainly much faster than the Ruby code I wrote, since
|
3
|
-
// it's not making tons of throwaway strings. Fun stuff.
|
4
|
-
#include "ruby.h"
|
5
|
-
|
6
|
-
#define MAX_LENGTH 40
|
7
|
-
#define XOUT '@'
|
8
|
-
#define FALSE 0
|
9
|
-
#define TRUE 1
|
10
|
-
|
11
|
-
static VALUE mPerquackey;
|
12
|
-
static VALUE cDictionary;
|
13
|
-
|
14
|
-
int spell(char *word, char *letters) {
|
15
|
-
static char letter_set[MAX_LENGTH];
|
16
|
-
register char *letter;
|
17
|
-
|
18
|
-
strcpy(letter_set, letters);
|
19
|
-
strcat(letter_set, "\n");
|
20
|
-
|
21
|
-
while (*word) {
|
22
|
-
if ((letter = strchr(letter_set, *word++)) != NULL) {
|
23
|
-
*letter = XOUT;
|
24
|
-
} else {
|
25
|
-
return FALSE;
|
26
|
-
}
|
27
|
-
}
|
28
|
-
|
29
|
-
return TRUE;
|
30
|
-
}
|
31
|
-
|
32
|
-
// It's very tempting to move Dictionary#initialize into Ruby-land, but part
|
33
|
-
// of me thinks that it's cognitively easier to deal with if all of the
|
34
|
-
// Dictionary code to be in one file instead of 2. (And this constructor's not
|
35
|
-
// all that hard to read / write.)
|
36
|
-
VALUE Dictionary_initialize(VALUE self, VALUE filename) {
|
37
|
-
rb_iv_set(self, "@filename", filename);
|
38
|
-
return self;
|
39
|
-
}
|
40
|
-
|
41
|
-
// It's tempting to move Dictionary#words method into Ruby-land, just
|
42
|
-
// delegating to C for the time-critical work done by spell (i.e.
|
43
|
-
// File.readlines(@filename).select { |word| spell(word, letters) }), but
|
44
|
-
// there's a second, subtler benefit to keeping things here: that we don't
|
45
|
-
// have to build a Ruby string ('word') for each line in @filename -- fgets is
|
46
|
-
// wicked fast!
|
47
|
-
VALUE Dictionary_words(VALUE self, VALUE letters) {
|
48
|
-
VALUE words = rb_ary_new();
|
49
|
-
|
50
|
-
char word[MAX_LENGTH];
|
51
|
-
|
52
|
-
FILE *file = fopen(RSTRING(rb_iv_get(self, "@filename"))->ptr, "rt");
|
53
|
-
while (fgets(word, MAX_LENGTH, file) != NULL) {
|
54
|
-
if (spell(word, RSTRING(letters)->ptr)) {
|
55
|
-
rb_ary_push(words, rb_str_new(word, strlen(word) - 1)); // strlen(word) - 1 to strip the trailing newline
|
56
|
-
}
|
57
|
-
}
|
58
|
-
fclose(file);
|
59
|
-
|
60
|
-
return words;
|
61
|
-
}
|
62
|
-
|
63
|
-
void Init_dictionary() {
|
64
|
-
mPerquackey = rb_define_module("Perquackey");
|
65
|
-
cDictionary = rb_define_class_under(mPerquackey, "Dictionary", rb_cObject);
|
66
|
-
rb_define_method(cDictionary, "initialize", Dictionary_initialize, 1);
|
67
|
-
rb_define_method(cDictionary, "words", Dictionary_words, 1);
|
68
|
-
}
|
Binary file
|
@@ -1,23 +0,0 @@
|
|
1
|
-
<form name="form" action="/" method="post">
|
2
|
-
<input name="letters" value="<%= letters %>" autocomplete="off">
|
3
|
-
</form>
|
4
|
-
|
5
|
-
<script type="text/javascript">
|
6
|
-
document.forms.form.letters.focus();
|
7
|
-
</script>
|
8
|
-
|
9
|
-
<table>
|
10
|
-
<tr>
|
11
|
-
<% words.headers.each do |header| %>
|
12
|
-
<th><%= header %></th>
|
13
|
-
<% end %>
|
14
|
-
</tr>
|
15
|
-
|
16
|
-
<% words.each do |row| %>
|
17
|
-
<tr>
|
18
|
-
<% row.each do |word| %>
|
19
|
-
<td><%= word %></td>
|
20
|
-
<% end %>
|
21
|
-
</tr>
|
22
|
-
<% end %>
|
23
|
-
</table>
|
@@ -1,12 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
-
<html lang="en-US" xml:lang="en-US" xmlns="http://www.w3.org/1999/xhtml">
|
4
|
-
<head>
|
5
|
-
<title>Perquackey</title>
|
6
|
-
</head>
|
7
|
-
<body>
|
8
|
-
<h1>Perquackey</h1>
|
9
|
-
<%= yield %>
|
10
|
-
<p>Now using the <a href="http://en.wikipedia.org/wiki/Tournament_Word_List">TWL06 word list</a> courtesy of the <a href="http://www.isc.ro/en/commands/lists.html">Internet Scrabble Club</a>.</p>
|
11
|
-
</body>
|
12
|
-
</html>
|
data/lib/perquackey/version.rb
DELETED