From 85e471ba05d5fb520d1f96650e01ab39b1a654b7 Mon Sep 17 00:00:00 2001 From: Daniel Kerwin Date: Fri, 9 Jan 2015 19:26:35 +0100 Subject: [PATCH 1/3] Feedback is submitted by assignment; Feedback can be given on missing extractions; Easier to test for extractions; closes #10 --- README.md | 10 +- lib/gini-api/document.rb | 1 + lib/gini-api/document/extractions.rb | 59 +++++++++++- spec/gini-api/document/extraction_spec.rb | 106 +++++++++++++++++++++- 4 files changed, 167 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9dba5d4..cb5a1f9 100644 --- a/README.md +++ b/README.md @@ -144,14 +144,18 @@ doc.extractions.candidates[:dates] # => Array of all found candidates doc.extractions.raw # => {:extractions=>{... +doc.extractions.undefinedLabel +# => nil ``` ### Submitting feedback ```ruby -doc.submit_feedback(:bic, 'XXXXXXXX') -# => nil -doc.submit_feedback(:unknownlabel, 'XXXXXXX') +doc.extractions.bic = 'XXXXXXXX' +# => 'XXXXXXXX' +doc.extractions.bic = { value: 'XXXXXXXX', :box=>{:top=>2176.0, :left=>2000.0, :width=>173.0, :height=>50.0, :page=>1 } +# => { value: 'XXXXXXXX', box: { top: 2176.0, left: 2000.0, width: 173.0, height: 50.0, page: 1 } +doc.extractions.unknownLabel = 'XXXXXXXX' # => raises Gini::Api::DocumentError ``` diff --git a/lib/gini-api/document.rb b/lib/gini-api/document.rb index fc0da31..82df15f 100644 --- a/lib/gini-api/document.rb +++ b/lib/gini-api/document.rb @@ -124,6 +124,7 @@ def pages # Submit feedback on extraction label # + # @deprecated Use 'doc.extractions.LABEL = VALUE' instead. Will be removed in next version # @param [String] label Extraction label to submit feedback on # @param [String] value The new value for the given label # diff --git a/lib/gini-api/document/extractions.rb b/lib/gini-api/document/extractions.rb index 1315459..66812e1 100644 --- a/lib/gini-api/document/extractions.rb +++ b/lib/gini-api/document/extractions.rb @@ -35,11 +35,9 @@ def update response.parsed[:extractions].each do |k,v| instance_variable_set("@#{k}", v) - self.class.send(:attr_reader, k) end instance_variable_set("@candidates", response.parsed[:candidates]) - self.class.send(:attr_reader, :candidates) end # Get filed value for given extraction key @@ -49,11 +47,66 @@ def update # def [](item) unless instance_variable_get("@#{item}") - raise Gini::Api::DocumentError.new("Invalid extraction key #{item}: Not found") + raise Gini::Api::DocumentError.new("Invalid extraction key '#{item}': Not found") + end + + # method_missing requires some additional checks + label = instance_variable_get("@#{item}") + + unless label.is_a? Hash and label.has_key? :value + raise Gini::Api::DocumentError.new("Extraction key '#{item}' has no :value defined") end instance_variable_get("@#{item}")[:value] end + + # Submit feedback on extraction label + # + # @param [String] label Extraction label to submit feedback on + # @param [Hash] feedback Hash containing at least key :value (:box is optional) + # + def submit_feedback(label, feedback) + response = @api.request( + :put, + "#{@location}/#{label}", + headers: { 'content-type' => @api.version_header[:accept] }, + body: feedback.to_json + ) + rescue Gini::Api::RequestError => e + if e.api_status == 422 + raise Gini::Api::DocumentError.new( + "Failed to submit feedback for label '#{label}' (code=#{e.api_status}, msg=#{e.api_response.body})", + response + ) + end + raise + end + + # Create setter and getter dynamically with method_missing + # + # @param [Symbol] m method name + # @param [Array] args method arguments + # @param [Block] block Block passed to the missing method + # @return [Hash, Nil] Return extraction hash or nil + # + def method_missing(m, *args, &block) + m_name = m.to_s + label = m_name.split('=')[0] + + if m_name.end_with? '=' + # setter method. Set instance variable and submit feedback + if args[0].is_a? Hash + feedback = args[0] + else + feedback = { value: args[0] } + end + instance_variable_set("@#{label}", feedback) + submit_feedback(label, feedback) + else + # getter. return instance variable or nil + instance_variable_get("@#{label}") + end + end end end end diff --git a/spec/gini-api/document/extraction_spec.rb b/spec/gini-api/document/extraction_spec.rb index c5e3628..299a9be 100644 --- a/spec/gini-api/document/extraction_spec.rb +++ b/spec/gini-api/document/extraction_spec.rb @@ -47,7 +47,10 @@ entity: 'date', value: '2012-06-20', candidates: 'dates' - } + }, + invalid: { + this_is: 'wrong' + }, }, candidates: { dates: [ @@ -99,11 +102,20 @@ describe '#[]' do - context 'with invalid key' do + context 'with missing key' do it 'raises exception' do expect { extractions[:unknown] }.to \ - raise_error(Gini::Api::DocumentError, /Invalid extraction key unknown/) + raise_error(Gini::Api::DocumentError, /Invalid extraction key 'unknown'/) + end + + end + + context 'with missing :value in response' do + + it 'raises exception' do + expect { extractions[:invalid] }.to \ + raise_error(Gini::Api::DocumentError, /Extraction key 'invalid' has no :value defined/) end end @@ -118,4 +130,92 @@ end + describe '#method_missing' do + + context 'with unknown extraction' do + + context 'and only value' do + + it 'will set instance variable to new hash' do + expect(extractions).to receive(:instance_variable_set).with('@test', {value: :test}) + expect(extractions).to receive(:submit_feedback).with('test', {:value=>:test}) + extractions.test = :test + end + + end + + context 'and hash' do + + it 'will set instance variable to supplied hash' do + expect(extractions).to receive(:instance_variable_set).with('@test', {value: 'test', box: {}}) + expect(extractions).to receive(:submit_feedback).with('test', {value: 'test', box: {}}) + extractions.test = {value: 'test', box: {} } + end + + end + + end + + end + + describe '#submit_feedback' do + + context 'with valid label' do + + before do + allow(api.token).to receive(:put).with( + "#{location}/test", + { + headers: { 'content-type' => header }, + body: { value: 'Johnny Bravo' }.to_json + } + ).and_return(OAuth2::Response.new(double('Response', status: 204))) + end + + it 'succeeds' do + expect(extractions.submit_feedback(:test, {value: 'Johnny Bravo'})).to be_a(OAuth2::Response) + end + + end + + context 'with invalid label (http code 422)' do + + before do + allow(api.token).to receive(:put).with( + "#{location}/test", + { + headers: { 'content-type' => header }, + body: { value: 'Johnny Bravo' }.to_json + } + ).and_raise(Gini::Api::RequestError.new('dummy', double('xxx', status: 422, env: {}, body: {}))) + end + + it 'raises Gini::Api::DocumentError' do + expect{extractions.submit_feedback(:test, {value: 'Johnny Bravo'})}.to \ + raise_error(Gini::Api::DocumentError, /Failed to submit feedback for label/) + end + + end + + context 'with undefined error' do + + before do + allow(api.token).to receive(:put).with( + "#{location}/test", + { + headers: { 'content-type' => header }, + body: { value: 'Johnny Bravo' }.to_json + } + ).and_raise(Gini::Api::RequestError.new('dummy', double('xxx', status: 500, env: {}, body: {}))) + end + + it 'raises Gini::Api::RequestError' do + expect{extractions.submit_feedback(:test, {value: 'Johnny Bravo'})}.to \ + raise_error(Gini::Api::RequestError) + end + + end + + end + end From b5573e542523d38637b0bcf33cfd0bc359939ae5 Mon Sep 17 00:00:00 2001 From: Daniel Kerwin Date: Fri, 9 Jan 2015 19:38:25 +0100 Subject: [PATCH 2/3] Version bump to 0.9.9 --- lib/gini-api/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gini-api/version.rb b/lib/gini-api/version.rb index 81c93aa..ecb2caf 100644 --- a/lib/gini-api/version.rb +++ b/lib/gini-api/version.rb @@ -1,6 +1,6 @@ module Gini module Api # Package version - VERSION = "0.9.8" + VERSION = "0.9.9" end end From b5633ef9442f25811fe47941b03359372e8f5333 Mon Sep 17 00:00:00 2001 From: Daniel Kerwin Date: Fri, 9 Jan 2015 19:42:47 +0100 Subject: [PATCH 3/3] Update Gemfile.lock --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 695c5aa..5b4bb02 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - gini-api (0.9.8) + gini-api (0.9.9) logger oauth2