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.
@@ -0,0 +1,6 @@
1
+ .rvmrc
2
+ Makefile
3
+ *.bundle
4
+ *.gem
5
+ *.o
6
+ rdoc
@@ -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
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+
3
+ gem 'perquackey', :path => File.expand_path('.')
4
+
5
+ group :development do
6
+ gem 'redgreen'
7
+ gem 'shoe', '0.5.0'
8
+ end
@@ -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.tie('perquackey', Perquackey::VERSION, 'Provides console session and simple webapp for looking up Perquackey word matches') do |spec|
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
@@ -1,6 +1,5 @@
1
1
  * Dictionary should take some kind of IO object.
2
2
  * Include the C extension in the rdoc.
3
- * Push a release to gemcutter.
4
3
  * Use the web interface for in-game support:
5
4
  * Capture words
6
5
  * Calculate score
@@ -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
- conf = OpenStruct.new(:mode => :console, :port => 3000)
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)
@@ -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
+ }
@@ -1,2 +1,2 @@
1
1
  require 'mkmf'
2
- create_makefile 'perquackey/dictionary'
2
+ create_makefile 'perquackey/anagrams'
@@ -1,51 +1,19 @@
1
- require 'perquackey/dictionary'
1
+ require 'pathname'
2
+ require 'rbconfig'
3
+ require 'rbconfig/datadir'
2
4
 
3
5
  module Perquackey
4
- class Game
5
- TWL = File.expand_path('../perquackey/resources/TWL06.txt', __FILE__)
6
-
7
- def initialize
8
- @dictionary = Dictionary.new(TWL)
9
- end
10
-
11
- def words(letters)
12
- WordTable.new(@dictionary.words(letters).reject { |word| word.length < minimum_length(letters) })
13
- end
14
-
15
- private
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
@@ -1,4 +1,3 @@
1
- require 'perquackey'
2
1
  require 'readline'
3
2
 
4
3
  module Perquackey
@@ -8,7 +7,7 @@ module Perquackey
8
7
  end
9
8
 
10
9
  def initialize
11
- @game = Perquackey::Game.new
10
+ @game = Game.new
12
11
  end
13
12
 
14
13
  def run
@@ -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
@@ -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, File.dirname(__FILE__) + '/server'
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
@@ -1,33 +1,33 @@
1
- # -*- encoding: utf-8 -*-
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+ require 'perquackey'
2
3
 
3
- Gem::Specification.new do |s|
4
- s.name = %q{perquackey}
5
- s.version = "0.7.0"
4
+ Gem::Specification.new do |spec|
5
+ spec.name = 'perquackey'
6
+ spec.version = Perquackey::VERSION
6
7
 
7
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.authors = ["Matthew Todd"]
9
- s.date = %q{2010-03-30}
10
- s.default_executable = %q{perquackey}
11
- s.email = %q{matthew.todd@gmail.com}
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
- if s.respond_to? :specification_version then
22
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
- s.specification_version = 3
14
+ spec.add_runtime_dependency 'sinatra'
15
+ spec.add_development_dependency 'redgreen'
16
+ spec.add_development_dependency 'shoe'
24
17
 
25
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
26
- s.add_runtime_dependency(%q<sinatra>, [">= 0"])
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
@@ -1,7 +1,7 @@
1
- require 'test_helper'
1
+ require 'test/helper'
2
2
 
3
3
  class DictionaryTest < Test::Unit::TestCase
4
- def test_simple_search_with_twl
5
- assert_equal ['ab', 'ba', 'cab'], Perquackey::Dictionary.new(Perquackey::Game::TWL).words('abc')
4
+ def test_simple_search
5
+ assert_equal ['ab', 'ba', 'cab'], Perquackey::Dictionary.new.words('abc')
6
6
  end
7
7
  end
@@ -1,7 +1,6 @@
1
1
  require 'perquackey'
2
2
  require 'test/unit'
3
3
 
4
- if $stdin.tty?
5
- require 'rubygems'
4
+ if $stdout.tty?
6
5
  require 'redgreen'
7
6
  end
@@ -1,17 +1,23 @@
1
- require 'test_helper'
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.collect { |row| row }
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[ape bear cat dog eagle fox goose hippo ibis]
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
- assert_equal ['ape bear eagle', 'cat ibis goose', 'dog hippo', 'fox '], table.collect { |row| row.join(' ') }
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
- - 0
9
- version: 0.7.0
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-03-30 00:00:00 +03:00
18
- default_executable: perquackey
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
- description:
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
- - Rakefile
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/test_helper.rb
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.0
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
@@ -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
- }
@@ -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>
@@ -1,3 +0,0 @@
1
- module Perquackey
2
- VERSION = '0.7.0'
3
- end