Permalink
Browse files

[BUGFIX] Fix failing specs on item repeats

Fix #7

* Use a C or Java extension
* Kill a lot of yucky, poorly performing and error prone code
  • Loading branch information...
1 parent d3bf708 commit 1630fce1352660e06c0dffabeec525bc5a7a276f @benlangfeld benlangfeld committed Mar 3, 2013
View
@@ -1,6 +1,7 @@
.DS_Store
*.gem
-.bundle
+*.bundle
+*.jar
Gemfile.lock
pkg/*
spec/reports
View
@@ -7,5 +7,8 @@ rvm:
- rbx-19mode
- ruby-head
+before_install:
+ - sudo apt-get install libpcre3 libpcre3-dev
+
notifications:
irc: "irc.freenode.org#adhearsion-dev"
View
@@ -1,3 +1,7 @@
+guard 'rake', :task => 'compile' do
+ watch(%r{^ext/(.+)\.c$})
+end
+
guard 'rspec', :cli => '--format documentation' do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
View
@@ -15,8 +15,20 @@ RSpec::Core::RakeTask.new(:rcov) do |spec|
spec.rspec_opts = '--color'
end
-task :default => :spec
-task :ci => ['ci:setup:rspec', :spec]
+task :default => [:compile, :spec]
+task :ci => ['ci:setup:rspec', :compile, :spec]
require 'yard'
YARD::Rake::YardocTask.new
+
+if RUBY_PLATFORM =~ /java/
+ require 'rake/javaextensiontask'
+ Rake::JavaExtensionTask.new 'ruby_speech' do |ext|
+ ext.lib_dir = 'lib/ruby_speech'
+ end
+else
+ require 'rake/extensiontask'
+ Rake::ExtensionTask.new 'ruby_speech' do |ext|
+ ext.lib_dir = 'lib/ruby_speech'
+ end
+end
@@ -0,0 +1,42 @@
+package com.benlangfeld.ruby_speech;
+
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.anno.JRubyClass;
+import org.jruby.anno.JRubyMethod;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.ThreadContext;
+import org.jruby.runtime.Visibility;
+import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.javasupport.util.RuntimeHelpers;
+
+import java.util.regex.*;
+
+@JRubyClass(name="RubySpeech::GRXML::Matcher")
+public class RubySpeechGRXMLMatcher extends RubyObject {
+
+ public RubySpeechGRXMLMatcher(final Ruby runtime, RubyClass rubyClass) {
+ super(runtime, rubyClass);
+ }
+
+ @JRubyMethod(visibility=Visibility.PRIVATE)
+ public IRubyObject check_potential_match(ThreadContext context, IRubyObject buffer)
+ {
+ Ruby runtime = context.getRuntime();
+
+ IRubyObject regex = getInstanceVariable("@regex");
+
+ Pattern p = Pattern.compile(regex.toString());
+ Matcher m = p.matcher(buffer.toString());
+
+ if (m.matches()) {
+ } else if (m.hitEnd()) {
+ RubyModule potential_match = runtime.getClassFromPath("RubySpeech::GRXML::PotentialMatch");
+ return RuntimeHelpers.invoke(context, potential_match, "new");
+ }
+ return runtime.getNil();
+ }
+
+}
@@ -0,0 +1,23 @@
+package com.benlangfeld.ruby_speech;
+
+import org.jruby.Ruby;
+import org.jruby.RubyClass;
+import org.jruby.RubyModule;
+import org.jruby.RubyObject;
+import org.jruby.runtime.ObjectAllocator;
+import org.jruby.runtime.builtin.IRubyObject;
+import org.jruby.runtime.load.BasicLibraryService;
+
+public class RubySpeechService implements BasicLibraryService {
+ public boolean basicLoad(Ruby ruby) {
+ RubyModule ruby_speech = ruby.defineModule("RubySpeech");
+ RubyModule grxml = ruby_speech.defineModuleUnder("GRXML");
+ RubyClass matcher = grxml.defineClassUnder("Matcher", ruby.getObject(), new ObjectAllocator() {
+ public IRubyObject allocate(Ruby runtime, RubyClass rubyClass) {
+ return new RubySpeechGRXMLMatcher(runtime, rubyClass);
+ }
+ });
+ matcher.defineAnnotatedMethods(RubySpeechGRXMLMatcher.class);
+ return true;
+ }
+}
@@ -0,0 +1,7 @@
+require 'mkmf'
+
+$LIBS << " -lpcre"
+
+abort "-----\n#{lib} is missing.\n-----" unless find_header('pcre.h')
+
+create_makefile 'ruby_speech'
@@ -0,0 +1,41 @@
+#include "ruby.h"
+#include "pcre.h"
+#include <stdio.h>
+
+static VALUE method_check_potential_match(VALUE self, VALUE buffer)
+{
+ int erroffset = 0;
+ const char *errptr = "";
+ int options = 0;
+ VALUE regex_string = rb_funcall(rb_iv_get(self, "@regex"), rb_intern("to_s"), 0);
+ const char *regex = StringValueCStr(regex_string);
+
+ pcre *compiled_regex = pcre_compile(regex, options, &errptr, &erroffset, NULL);
+
+ int result = 0;
+ int ovector[30];
+ int workspace[1024];
+ char *input = StringValueCStr(buffer);
+ result = pcre_dfa_exec(compiled_regex, NULL, input, strlen(input), 0, PCRE_PARTIAL,
+ ovector, sizeof(ovector) / sizeof(ovector[0]),
+ workspace, sizeof(workspace) / sizeof(workspace[0]));
+ pcre_free(compiled_regex);
+
+ if (result == PCRE_ERROR_PARTIAL) {
+ VALUE RubySpeech = rb_const_get(rb_cObject, rb_intern("RubySpeech"));
+ VALUE GRXML = rb_const_get(RubySpeech, rb_intern("GRXML"));
+ VALUE PotentialMatch = rb_const_get(GRXML, rb_intern("PotentialMatch"));
+
+ return rb_class_new_instance(0, NULL, PotentialMatch);
+ }
+ return Qnil;
+}
+
+void Init_ruby_speech()
+{
+ VALUE RubySpeech = rb_define_module("RubySpeech");
+ VALUE GRXML = rb_define_module_under(RubySpeech, "GRXML");
+ VALUE Matcher = rb_define_class_under(GRXML, "Matcher", rb_cObject);
+
+ rb_define_method(Matcher, "check_potential_match", method_check_potential_match, 1);
+}
@@ -24,23 +24,6 @@ def self.module
def regexp_content # :nodoc:
children.map(&:regexp_content).join
end
-
- def potential_match?(other)
- false
- end
-
- def max_input_length
- 0
- end
-
- def longest_potential_match(input)
- input.dup.tap do |longest_input|
- begin
- return longest_input if potential_match? longest_input
- longest_input.chop!
- end until longest_input.length.zero?
- end
- end
end # Element
end # GRXML
end # RubySpeech
@@ -139,27 +139,6 @@ def regexp_content # :nodoc:
super
end
end
-
- def potential_match?(other)
- tokens = children
- return false if other.length > max_input_length
- other.chars.each_with_index do |digit, index|
- index -= tokens.size until index < tokens.size if repeat
- return false unless tokens[index].potential_match?(digit)
- end
- true
- end
-
- def max_input_length # :nodoc:
- case repeat
- when Range
- children.size * repeat.max
- when Integer
- children.size * repeat
- else
- children.size
- end
- end
end # Item
end # GRXML
end # RubySpeech
@@ -1,3 +1,10 @@
+require 'ruby_speech/ruby_speech'
+
+if RUBY_PLATFORM =~ /java/
+ require 'jruby'
+ com.benlangfeld.ruby_speech.RubySpeechService.new.basicLoad(JRuby.runtime)
+end
+
module RubySpeech
module GRXML
class Matcher
@@ -104,17 +111,6 @@ def check_full_match(buffer)
:interpretation => interpret_utterance(buffer)
end
- def check_potential_match(buffer)
- grammar.root_rule.children.each do |token|
- p "Checking buffer #{buffer} against token #{token} which has a longest potential match #{token.longest_potential_match(buffer)}"
- break if buffer.length.zero?
- longest_potential_match = token.longest_potential_match buffer
- return if longest_potential_match.length.zero?
- buffer.gsub! /^#{Regexp.escape longest_potential_match}/, ''
- end
- buffer.length.zero? ? PotentialMatch.new : nil
- end
-
def regexp_content
grammar.root_rule.children.map &:regexp_content
end
@@ -26,10 +26,6 @@ def <<(arg)
def regexp_content # :nodoc:
"(#{children.map(&:regexp_content).join '|'})"
end
-
- def potential_match?(input)
- children.any? { |c| c.potential_match? input }
- end
end # OneOf
end # GRXML
end # RubySpeech
@@ -26,10 +26,6 @@ def normalize_whitespace
def regexp_content # :nodoc:
Regexp.escape content
end
-
- def potential_match?(other)
- other == content
- end
end # Token
end # GRXML
end # RubySpeech
View
@@ -18,6 +18,13 @@ Gem::Specification.new do |s|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
+ if RUBY_PLATFORM =~ /java/
+ s.platform = "java"
+ s.files << "lib/ruby_speech/ruby_speech.jar"
+ else
+ s.extensions = ['ext/ruby_speech/extconf.rb']
+ end
+
s.add_runtime_dependency %q<niceogiri>, ["~> 1.1", ">= 1.1.1"]
s.add_runtime_dependency %q<nokogiri>, ["~> 1.5", ">= 1.5.6"]
s.add_runtime_dependency %q<activesupport>, [">= 3.0.7"]
@@ -32,4 +39,6 @@ Gem::Specification.new do |s|
s.add_development_dependency %q<guard>, [">= 0.9.0"]
s.add_development_dependency %q<guard-rspec>, [">= 0"]
s.add_development_dependency %q<ruby_gntp>, [">= 0"]
+ s.add_development_dependency %q<guard-rake>, [">= 0"]
+ s.add_development_dependency %q<rake-compiler>, [">= 0"]
end
Oops, something went wrong.

0 comments on commit 1630fce

Please sign in to comment.