Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Idea jruby support #1

Closed
hiroyuki-sato opened this issue May 14, 2015 · 3 comments
Closed

Idea jruby support #1

hiroyuki-sato opened this issue May 14, 2015 · 3 comments

Comments

@hiroyuki-sato
Copy link

Hello

Some of reason, I'm planning to use groonga-client on jruby platform.
Unfortunately, yajl-ruby does not work on jruby-platform.

Idea on jruby platform

  • use json-stream parser instead of yajl-ruby.
  • It is jruby only. because yajl-ruby faster than json-stream (maybe)

Problem

  • How to write gemspec. install yajl-ruby on cruby, install json-stream on jruby platform.
  • How to modify json/stream/parser.rb class to use json-sream and yajl-ruby.

test

[7] pry(main)> require 'groonga/client'
=> true
[8] pry(main)> Groonga::Client.open(:host => 'localhost', :protocol => :gqtp) do |client|
[8] pry(main)*   tables = client.table_list  
[8] pry(main)*   tables.each do |table|  
[8] pry(main)*     puts table.name    
[8] pry(main)*   end    
[8] pry(main)* end  
Site
Terms
=> [#<struct Groonga::Client::Response::TableList::Table
  id=256,
  name="Site",
  path="chap4_1.db.0000100",
  flags="TABLE_HASH_KEY|PERSISTENT",
  domain="ShortText",
  range=nil,
  default_tokenizer=nil,
  normalizer=nil>,
 #<struct Groonga::Client::Response::TableList::Table
  id=258,
  name="Terms",
  path="chap4_1.db.0000102",
  flags="TABLE_PAT_KEY|PERSISTENT",
  domain="ShortText",
  range=nil,
  default_tokenizer="TokenBigram",
  normalizer="NormalizerAuto">]
[9] pry(main)> RUBY_ENGINE
=> "jruby"
diff --git a/groonga-command-parser.gemspec b/groonga-command-parser.gemspec
index 0a97286..2dca507 100644
--- a/groonga-command-parser.gemspec
+++ b/groonga-command-parser.gemspec
@@ -52,8 +52,9 @@ Gem::Specification.new do |spec|
   spec.licenses = ["LGPLv2.1+"]
   spec.require_paths = ["lib"]

-  spec.add_runtime_dependency("groonga-command", ">= 1.0.9")
-  spec.add_runtime_dependency("yajl-ruby")
+  spec.add_runtime_dependency("groonga-command", "~> 1.0", ">= 1.0.9")
+  spec.add_runtime_dependency('json-stream')
+  #spec.add_runtime_dependency("yajl-ruby")

   spec.add_development_dependency("test-unit")
   spec.add_development_dependency("test-unit-notify")
diff --git a/lib/groonga/command/parser.rb b/lib/groonga/command/parser.rb
index 10072e8..8a6835d 100644
--- a/lib/groonga/command/parser.rb
+++ b/lib/groonga/command/parser.rb
@@ -19,7 +19,9 @@
 require "English"
 require "cgi"

-require "yajl"
+#require "yajl"
+require 'json'
+require 'json/stream'

 require "groonga/command"

@@ -27,8 +29,99 @@ require "groonga/command/parser/error"
 require "groonga/command/parser/command-line-splitter"
 require "groonga/command/parser/version"

+module JSON
+  module Stream
+    class Parser
+      def reset
+        @state = :start_document
+      end
+    end
+  end
+end
+
 module Groonga
   module Command
+
+    # A parser listener that builds a full, in memory, object from a JSON
+    # document. This is similar to using the json gem's `JSON.parse` method.
+    #
+    # Examples
+    #
+    #   parser = JSON::Stream::Parser.new
+    #   builder = JSON::Stream::Builder.new(parser)
+    #   parser << '{"answer": 42, "question": false}'
+    #   obj = builder.result
+    class Builder
+      METHODS = %w[start_document end_document start_object end_object start_array end_array key value]
+
+      attr_reader :result
+
+      def initialize(parser)
+        @parser = parser
+        METHODS.each do |name|
+          parser.send(name, &method(name))
+        end
+        @callbacks = []
+      end
+
+#      def on_parse_complete(&block)
+      def on_parse_complete=(block)
+        @callbacks.push block
+      end
+
+      def start_document
+        @stack = []
+        @keys = []
+        @result = nil
+      end
+
+      def end_document
+        @result = @stack.pop
+        @callbacks.each { |c| c.call @result }
+        @parser.reset
+        @result
+      end
+
+      def start_object
+        @stack.push({})
+      end
+
+      def end_object
+        return if @stack.size == 1
+
+        node = @stack.pop
+        top = @stack[-1]
+
+        case top
+        when Hash
+          top[@keys.pop] = node
+        when Array
+          top << node
+        end
+      end
+      alias :end_array :end_object
+
+      def start_array
+        @stack.push([])
+      end
+
+      def key(key)
+        @keys << key
+      end
+
+      def value(value)
+        top = @stack[-1]
+        case top
+        when Hash
+          top[@keys.pop] = value
+        when Array
+          top << value
+        else
+          @stack << value
+        end
+      end
+    end
+
     class Parser
       class << self

@@ -91,7 +184,8 @@ module Groonga
           end
           parser.on_load_complete do |command|
             parsed_command = command
-            parsed_command[:values] ||= Yajl::Encoder.encode(values)
+            #parsed_command[:values] ||= Yajl::Encoder.encode(values)
+            parsed_command[:values] ||= values.to_json
           end

           consume_data(parser, data)
@@ -262,7 +356,20 @@ module Groonga
           else
             @command.original_source << spaces << start_json
             @buffer = rest
-            @json_parser = Yajl::Parser.new
+            #@json_parser = Yajl::Parser.new
+            @json_parser = JSON::Stream::Parser.new
+            @builder = Builder.new(@json_parser)
+#            @builder.on_parse_complete do |object|
+            @builder.on_parse_complete = lambda do |object|
+              if object.is_a?(::Array) and @command.columns.nil?
+                @command.columns = object
+                on_load_columns(@command, object)
+              else
+                on_load_value(@command, object)
+              end
+              @load_value_completed = true
+            end
+=begin
             @json_parser.on_parse_complete = lambda do |object|
               if object.is_a?(::Array) and @command.columns.nil?
                 @command.columns = object
@@ -272,6 +379,7 @@ module Groonga
               end
               @load_value_completed = true
             end
+=end
             @in_load_values = true
           end
         end
@@ -281,7 +389,7 @@ module Groonga
         @command.original_source << json
         begin
           @json_parser << json
-        rescue Yajl::ParseError
+        rescue JSON::Stream::ParserError
           before_json = @command.original_source[0..(-json.bytesize)]
           message = "invalid JSON: #{$!.message}: <#{json}>:\n"
           message << before_json
@@ -322,7 +430,8 @@ module Groonga
             on_load_columns(@command, @command.columns)
           end
           if @command[:values]
-            values = Yajl::Parser.parse(@command[:values])
+#            values = Yajl::Parser.parse(@command[:values])
+            values = JSON.parse(@command[:values])
             if @command.columns.nil? and values.first.is_a?(::Array)
               header = values.shift
               @command.columns = header
@hiroyuki-sato
Copy link
Author

I pushed modified files to json-stream branch.

@kou kou closed this as completed in ef5dc13 May 21, 2015
@hiroyuki-sato
Copy link
Author

Good improvement. Thanks!!.

@kou
Copy link
Member

kou commented May 21, 2015

Thanks for your suggestion!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants