matthewtodd-perquackey 0.4.0 → 0.5.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/CHANGELOG CHANGED
@@ -1,4 +1,7 @@
1
- == 0.3.3 -- 2009-04-18
1
+ == 0.5.0 -- 2009-05-27
2
+ * Removed dependency on RubyInline. (So I can deploy to Heroku.)
3
+
4
+ == 0.4.0 -- 2009-04-18
2
5
  * Removed mongrel dependency.
3
6
  * Switched console to use readline instead of irb.
4
7
  * Remove stdout usage. Console is the default.
data/TODO CHANGED
@@ -1,2 +1,3 @@
1
- * remove dependency on RubyInline?
1
+ * Dictionary should take some kind of IO object.
2
+ * Server script should just use Rack.
2
3
  * tabtab_definitions --> except tabtab's not working well with -- options.
data/bin/perquackey CHANGED
@@ -15,8 +15,9 @@ end
15
15
 
16
16
  opts.parse! ARGV
17
17
 
18
- LIB_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
19
- $:.unshift LIB_DIR
18
+ %w(ext lib).each do |dir|
19
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', dir))
20
+ end
20
21
 
21
22
  case conf.mode
22
23
  when :console
@@ -0,0 +1,58 @@
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
+ VALUE Dictionary_initialize(VALUE self, VALUE filename) {
33
+ rb_iv_set(self, "@filename", filename);
34
+ return self;
35
+ }
36
+
37
+ VALUE Dictionary_words(VALUE self, VALUE letters) {
38
+ VALUE words = rb_ary_new();
39
+
40
+ char word[MAX_LENGTH];
41
+
42
+ FILE *file = fopen(RSTRING(rb_iv_get(self, "@filename"))->ptr, "rt");
43
+ while (fgets(word, MAX_LENGTH, file) != NULL) {
44
+ if (spell(word, RSTRING(letters)->ptr)) {
45
+ rb_ary_push(words, rb_str_new(word, strlen(word) - 1));
46
+ }
47
+ }
48
+ fclose(file);
49
+
50
+ return words;
51
+ }
52
+
53
+ void Init_dictionary() {
54
+ mPerquackey = rb_define_module("Perquackey");
55
+ cDictionary = rb_define_class_under(mPerquackey, "Dictionary", rb_cObject);
56
+ rb_define_method(cDictionary, "initialize", Dictionary_initialize, 1);
57
+ rb_define_method(cDictionary, "words", Dictionary_words, 1);
58
+ }
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile 'dictionary'
data/lib/perquackey.rb CHANGED
@@ -1,9 +1,51 @@
1
- require 'rubygems'
2
- require 'inline'
1
+ require 'perquackey/dictionary'
3
2
 
4
3
  module Perquackey
5
- end
4
+ class Game
5
+ YAWL = File.join(File.dirname(__FILE__), '..', 'resources', 'yawl-0.3.2-word.list')
6
6
 
7
- require 'perquackey/dictionary'
8
- require 'perquackey/game'
9
- require 'perquackey/word_table'
7
+ def initialize
8
+ @dictionary = Dictionary.new(YAWL)
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
50
+ end
51
+ end
@@ -1,4 +1,4 @@
1
- %w(rubygems camping perquackey).each { |lib| require lib }
1
+ require 'perquackey'
2
2
 
3
3
  Camping.goes :Perquackey
4
4
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: matthewtodd-perquackey
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Todd
@@ -9,19 +9,9 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-18 00:00:00 -07:00
12
+ date: 2009-05-27 00:00:00 -07:00
13
13
  default_executable: perquackey
14
14
  dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: RubyInline
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
24
- version:
25
15
  - !ruby/object:Gem::Dependency
26
16
  name: camping
27
17
  type: :runtime
@@ -36,8 +26,8 @@ description:
36
26
  email: matthew.todd@gmail.com
37
27
  executables:
38
28
  - perquackey
39
- extensions: []
40
-
29
+ extensions:
30
+ - ext/perquackey/extconf.rb
41
31
  extra_rdoc_files:
42
32
  - README
43
33
  - CHANGELOG
@@ -47,21 +37,20 @@ files:
47
37
  - CHANGELOG
48
38
  - TODO
49
39
  - bin/perquackey
40
+ - ext/perquackey/dictionary.c
41
+ - ext/perquackey/extconf.rb
50
42
  - lib/perquackey/console.rb
51
- - lib/perquackey/dictionary.rb
52
- - lib/perquackey/game.rb
53
43
  - lib/perquackey/server.rb
54
- - lib/perquackey/word_table.rb
55
44
  - lib/perquackey.rb
56
45
  - resources/yawl-0.3.2-word.list
57
- has_rdoc: true
46
+ has_rdoc: false
58
47
  homepage:
59
48
  post_install_message:
60
49
  rdoc_options:
61
50
  - --main
62
51
  - README
63
52
  - --title
64
- - perquackey-0.4.0
53
+ - perquackey-0.5.0
65
54
  - --inline-source
66
55
  - --line-numbers
67
56
  require_paths:
@@ -1,57 +0,0 @@
1
- class Perquackey::Dictionary
2
- YAWL = File.join(File.dirname(__FILE__), '..', '..', 'resources', 'yawl-0.3.2-word.list')
3
-
4
- def words(letters)
5
- c_words(letters, YAWL)
6
- end
7
-
8
- # After finding YAWL, I pretty much lifted this algorithm straight from its
9
- # anagram.c. It's certainly much faster than the Ruby code I wrote, since
10
- # it's not making tons of throwaway strings. Fun stuff.
11
- inline do |builder|
12
- builder.prefix <<-END
13
- #define MAX_LENGTH 40
14
- #define XOUT '@'
15
- #define FALSE 0
16
- #define TRUE 1
17
- END
18
-
19
- builder.c_raw <<-END
20
- int c_spell(char *word, char *letters) {
21
- static char letter_set[MAX_LENGTH];
22
- register char *letter;
23
-
24
- strcpy(letter_set, letters);
25
- strcat(letter_set, "\\n");
26
-
27
- while (*word) {
28
- if ((letter = strchr(letter_set, *word++)) != NULL) {
29
- *letter = XOUT;
30
- } else {
31
- return FALSE;
32
- }
33
- }
34
-
35
- return TRUE;
36
- }
37
- END
38
-
39
- builder.c <<-END
40
- VALUE c_words(VALUE letters, VALUE filename) {
41
- VALUE words = rb_ary_new();
42
-
43
- char word[MAX_LENGTH];
44
-
45
- FILE *file = fopen(RSTRING(filename)->ptr, "rt");
46
- while (fgets(word, MAX_LENGTH, file) != NULL) {
47
- if (c_spell(word, RSTRING(letters)->ptr)) {
48
- rb_ary_push(words, rb_str_new(word, strlen(word) - 1));
49
- }
50
- }
51
- fclose(file);
52
-
53
- return words;
54
- }
55
- END
56
- end
57
- end
@@ -1,15 +0,0 @@
1
- class Perquackey::Game
2
- def initialize
3
- @dictionary = Perquackey::Dictionary.new
4
- end
5
-
6
- def words(letters)
7
- Perquackey::WordTable.new(@dictionary.words(letters).reject { |word| word.length < minimum_length(letters) })
8
- end
9
-
10
- private
11
-
12
- def minimum_length(letters)
13
- letters.length > 10 ? 4 : 3
14
- end
15
- end
@@ -1,29 +0,0 @@
1
- class Perquackey::WordTable
2
- include Enumerable
3
-
4
- def initialize(list=[])
5
- @table = Hash.new { |h, k| h[k] = [] }
6
-
7
- list.each do |word|
8
- @table[word.length] << word
9
- end
10
-
11
- if @table.empty?
12
- @headers = []
13
- @height = 0
14
- else
15
- @headers = @table.keys.min .. @table.keys.max
16
- @height = @table.values.max { |a, b| a.length <=> b.length }.length
17
- end
18
- end
19
-
20
- def headers
21
- @headers
22
- end
23
-
24
- def each
25
- @height.times do |row_number|
26
- yield headers.collect { |length| @table[length][row_number] or ' ' * length}
27
- end
28
- end
29
- end