diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e4e3007..3023156 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2024-01-11 22:13:12 UTC using RuboCop version 1.59.0. +# on 2026-03-05 13:36:13 UTC using RuboCop version 1.85.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -9,28 +9,35 @@ # Offense count: 4 # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. Metrics/AbcSize: - Max: 45 + Max: 50 # Offense count: 10 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. # AllowedMethods: refine Metrics/BlockLength: Max: 786 + #TODO check rubocop-rspec extension + Exclude: + - 'tests/tests_spec.rb' # Offense count: 2 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: - Max: 232 + Max: 250 # Offense count: 1 # Configuration parameters: AllowedMethods, AllowedPatterns. Metrics/CyclomaticComplexity: - Max: 8 + Max: 10 + +Metrics/PerceivedComplexity: + Max: 10 + -# Offense count: 11 +# Offense count: 10 # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. Metrics/MethodLength: - Max: 51 + Max: 50 # Offense count: 1 # Configuration parameters: CountKeywordArgs, MaxOptionalParameters. @@ -43,6 +50,7 @@ Metrics/ParameterLists: # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS Naming/FileName: Exclude: + - 'Rakefile.rb' - 'examples/morphology_compound-components.rb' - 'examples/morphology_han-readings.rb' - 'examples/morphology_parts-of-speech.rb' @@ -60,18 +68,19 @@ Style/CommentedKeyword: - 'lib/name_parameter.rb' - 'lib/name_similarity_parameters.rb' - 'lib/name_translation_parameters.rb' + - 'lib/record_similarity_parameters.rb' - 'lib/rosette_api_error.rb' # Offense count: 14 -# This cop supports safe autocorrection (--autocorrect). +# This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AllowedCompactTypes. # SupportedStyles: compact, exploded Style/RaiseArgs: EnforcedStyle: compact -# Offense count: 11 +# Offense count: 18 # This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. +# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings. # URISchemes: http, https Layout/LineLength: Max: 772 diff --git a/CI.Jenkinsfile b/CI.Jenkinsfile index 0cfa02d..cc7399a 100644 --- a/CI.Jenkinsfile +++ b/CI.Jenkinsfile @@ -1,9 +1,9 @@ -def versions = [3.0, 3.1, 3.2, 3.3] +def versions = [3.2, 3.3, 3.4, 4.0] def runSonnarForPythonVersion(sourceDir, ver){ - mySonarOpts="-Dsonar.sources=/source -Dsonar.host.url=${env.SONAR_HOST_URL} -Dsonar.login=${env.SONAR_AUTH_TOKEN}" + mySonarOpts="-Dsonar.sources=/source -Dsonar.host.url=${env.SONAR_HOST_URL} -Dsonar.login=${env.SONAR_AUTH_TOKEN} -Dsonar.ruby.coverage.reportPaths=coverage/coverage.json" if("${env.CHANGE_ID}" != "null"){ mySonarOpts = "$mySonarOpts -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.branch=${env.BRANCH_NAME}" } else { @@ -15,12 +15,13 @@ def runSonnarForPythonVersion(sourceDir, ver){ // Only run Sonar once. // Check for new versions at https://binaries.sonarsource.com/?prefix=Distribution/sonar-scanner-cli/ + sonarScannerVersion = "6.2.1.4610-linux-x64" if(ver == 3.3) { sonarExec="cd /root/ && \ - wget -q https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-4.8.1.3023-linux.zip && \ - unzip -q sonar-scanner-cli-4.8.1.3023-linux.zip && \ + wget -q https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${sonarScannerVersion}.zip && \ + unzip -q sonar-scanner-cli-${sonarScannerVersion}.zip && \ cd /source && \ - /root/sonar-scanner-4.8.1.3023-linux/bin/sonar-scanner ${mySonarOpts}" + /root/sonar-scanner-${sonarScannerVersion}/bin/sonar-scanner ${mySonarOpts}" } else { sonarExec="echo Skipping Sonar for this version." } @@ -43,7 +44,7 @@ def runSonnarForPythonVersion(sourceDir, ver){ apt-get update -qq && \ echo && \ echo [INFO] Installing required OS packages. && \ - apt-get -qq install -y gcc make wget unzip > /dev/null && \ + apt-get -qq install -y gcc make wget unzip libyaml-dev > /dev/null && \ echo && \ echo [INFO] Installing gems needed for CI. && \ gem install --silent --quiet bundler rspec rubocop && \ @@ -70,7 +71,7 @@ def runSonnarForPythonVersion(sourceDir, ver){ ${sonarExec} && \ echo && \ echo [INFO] Re-permission files for cleanup. && \ - chown -R jenkins:jenkins /source\"" + chown -R 9960:9960 /source\"" } node ("docker-light") { diff --git a/DEVELOPER.md b/DEVELOPER.md index 7551882..e574085 100644 --- a/DEVELOPER.md +++ b/DEVELOPER.md @@ -4,7 +4,7 @@ Modify `.rubocop_todo.yml` as you fix issues. Generate a new config file with `rubocop --auto-gen-config` as needed. ``` -docker run -it -v $(pwd):/source --entrypoint bash ruby:3.3-slim +docker run -it -v $(pwd):/source --entrypoint bash ruby:3.4-slim apt-get update apt-get install -y gcc make @@ -14,12 +14,32 @@ rubocop ``` +#### Check dependencies for CVEs + +This uses `bundler-audit`, which checks your `Gemfile.lock` against the RubySec advisory DB. + +``` +docker run -it -v $(pwd):/source --entrypoint bash ruby:3.4-slim +apt-get update +apt-get install -y gcc make git ca-certificates libyaml-dev + +cd /source +bundle install + +gem install bundler-audit +bundle audit update +bundle audit check --verbose + +``` + + + #### Run tests locally ``` -docker run -it -v $(pwd):/source --entrypoint bash ruby:3.3-slim +docker run -it -v $(pwd):/source --entrypoint bash ruby:3.4-slim apt-get update -apt-get install -y gcc make +apt-get install -y gcc make libyaml-dev gem install rspec cd /source @@ -31,7 +51,9 @@ rspec tests #### Run a single example ``` -docker run -it -v $(pwd):/source --entrypoint bash ruby:3.3-slim +docker run -it -v $(pwd):/source --entrypoint bash ruby:3.4-slim +apt-get update +apt-get install -y gcc make libyaml-dev cd /source bundle install @@ -47,7 +69,9 @@ ruby ping.rb ${API_KEY} #### Run all examples ``` -docker run -it -v $(pwd):/source --entrypoint bash ruby:3.3-slim +docker run -it -v $(pwd):/source --entrypoint bash ruby:3.4-slim +apt-get update +apt-get install -y gcc make libyaml-dev cd /source bundle install diff --git a/Gemfile b/Gemfile index b65bfbe..15e4d0d 100644 --- a/Gemfile +++ b/Gemfile @@ -2,10 +2,9 @@ source 'https://rubygems.org' -gem 'rdoc', '6.6.2' -gem 'rubysl-securerandom', '2.0.0' +gem 'rdoc' -gem 'rspec', '3.12.0', group: [:test] +gem 'rspec', group: [:test] gem 'simplecov', require: false, group: :test gem 'simplecov_json_formatter', require: false, group: :test -gem 'webmock', '3.19.1', group: [:test] +gem 'webmock', group: [:test] diff --git a/LICENSE b/LICENSE index b31b71a..cc2be2e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2024 Basis Technology Corporation. +Copyright (c) 2016-2026 Basis Technology Corporation. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 6bd3ba3..3e6b740 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,26 @@ - + + Babel Street Logo + ---- +# Analytics by Babel Street [![Gem Version](https://badge.fury.io/rb/rosette_api.svg)](https://badge.fury.io/rb/rosette_api) -## Rosette API -The Rosette Text Analytics Platform uses natural language processing, statistical modeling, and machine learning to -analyze unstructured and semi-structured text across 364 language-encoding-script combinations, revealing valuable -information and actionable data. Rosette provides endpoints for extracting entities and relationships, translating and -comparing the similarity of names, categorizing and adding linguistic tags to text and more. +Our product is a full text processing pipeline from data preparation to extracting the most relevant information and +analysis utilizing precise, focused AI that has built-in human understanding. Text Analytics provides foundational +linguistic analysis for identifying languages and relating words. The result is enriched and normalized text for +high-speed search and processing without translation. -## Rosette API Access -- Rosette Cloud [Sign Up](https://developer.rosette.com/signup) +Text Analytics extracts events and entities — people, organizations, and places — from unstructured text and adds the +structure of associating those entities into events that deliver only the necessary information for near real-time +decision making. Accompanying tools shorten the process of training AI models to recognize domain-specific events. + +The product delivers a multitude of ways to sharpen and expand search results. Semantic similarity expands search +beyond keywords to words with the same meaning, even in other languages. Sentiment analysis and topic extraction help +filter results to what’s relevant. + +## Analytics API Access +- Analytics Cloud [Sign Up](https://developer.babelstreet.com/signup) ## Quick Start @@ -20,16 +29,15 @@ comparing the similarity of names, categorizing and adding linguistic tags to te `gem install rosette_api` #### Examples -View small example programs for each Rosette endpoint +View small example programs for each Analytics endpoint in the [examples](https://github.com/rosette-api/ruby/tree/develop/examples) directory. #### Documentation & Support - [Binding API](https://rosette-api.github.io/ruby/) -- [Rosette Platform API](https://developer.rosette.com/features-and-functions) +- [Analytics Platform API](https://documentation.babelstreet.com/analytics) - [Binding Release Notes](https://github.com/rosette-api/ruby/wiki/Release-Notes) -- [Rosette Platform Release Notes](https://support.rosette.com/hc/en-us/articles/360018354971-Release-Notes) -- [Binding/Rosette Platform Compatibility](https://developer.rosette.com/features-and-functions?ruby#) -- [Support](https://support.rosette.com) +- [Analytics Platform Release Notes](https://docs.babelstreet.com/r/Hosted-Services-Release-Notes) +- [Support](https://babelstreet.my.site.com/support/s/contactsupport) - [Binding License: Apache 2.0](https://github.com/rosette-api/ruby/blob/develop/LICENSE) ## Binding Developer Information diff --git a/examples/README.md b/examples/README.md index 1ecfa40..ee403e3 100644 --- a/examples/README.md +++ b/examples/README.md @@ -13,7 +13,7 @@ A note on prerequisites. Rosette API only suports TLS 1.2 so ensure your toolcha ``` git clone git@github.com:rosette-api/ruby.git cd ruby -docker run -it -v $(pwd):/source --entrypoint bash ruby:3.3-slim +docker run -it -v $(pwd):/source --entrypoint bash ruby:3.4-slim gem install rosette_api @@ -25,7 +25,7 @@ ruby ping.rb $API_KEY ``` git clone git@github.com:rosette-api/ruby.git cd ruby -docker run -it -v $(pwd):/source --entrypoint bash ruby:3.3-slim +docker run -it -v $(pwd):/source --entrypoint bash ruby:3.4-slim cd /source gem build rosette_api.gemspec diff --git a/examples/address_similarity.rb b/examples/address_similarity.rb index 32d23f7..31615cc 100644 --- a/examples/address_similarity.rb +++ b/examples/address_similarity.rb @@ -4,11 +4,11 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end begin address1 = AddressParameter.new( @@ -20,7 +20,7 @@ ) address2 = '160 Pennsilvana Avenue, Washington, D.C., 20500' params = AddressSimilarityParameters.new(address1, address2) - response = rosette_api.get_address_similarity(params) + response = analytics_api.get_address_similarity(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/categories.rb b/examples/categories.rb index b9f5de1..d887088 100644 --- a/examples/categories.rb +++ b/examples/categories.rb @@ -4,16 +4,16 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end categories_text_data = 'If you are a fan of the British television series Downton Abbey and you are planning to be in New York anytime before April 2nd, there is a perfect stop for you while in town.' begin params = DocumentParameters.new(content: categories_text_data) - response = rosette_api.get_categories(params) + response = analytics_api.get_categories(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/entities.rb b/examples/entities.rb index 0d6386f..e47d4b4 100644 --- a/examples/entities.rb +++ b/examples/entities.rb @@ -4,16 +4,16 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end entities_text_data = 'The Securities and Exchange Commission today announced the leadership of the agency\'s trial unit. Bridget Fitzpatrick has been named Chief Litigation Counsel of the SEC and David Gottesman will continue to serve as the agency\'s Deputy Chief Litigation Counsel. Since December 2016, Ms. Fitzpatrick and Mr. Gottesman have served as Co-Acting Chief Litigation Counsel. In that role, they were jointly responsible for supervising the trial unit at the agency\'s Washington D.C. headquarters as well as coordinating with litigators in the SEC\'s 11 regional offices around the country.' begin params = DocumentParameters.new(content: entities_text_data) - response = rosette_api.get_entities(params) + response = analytics_api.get_entities(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/events.rb b/examples/events.rb new file mode 100644 index 0000000..c2836fd --- /dev/null +++ b/examples/events.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'rosette_api' + +api_key, url = ARGV + +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end + +events_text_data = 'Bill Gates went to the store.' +begin + params = DocumentParameters.new(content: events_text_data) + response = analytics_api.get_events(params) + puts JSON.pretty_generate(response) +rescue RosetteAPIError => e + printf('Rosette API Error (%s): %s', + status_code: e.status_code, + message: e.message) +end diff --git a/examples/info.rb b/examples/info.rb index feae303..932b0bb 100644 --- a/examples/info.rb +++ b/examples/info.rb @@ -4,13 +4,13 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end -response = rosette_api.info +response = analytics_api.info begin puts JSON.pretty_generate(response) rescue RosetteAPIError => e diff --git a/examples/language.rb b/examples/language.rb index 74e43d4..4c42e67 100644 --- a/examples/language.rb +++ b/examples/language.rb @@ -4,17 +4,17 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end language_data = 'Por favor Señorita, says the man.' begin params = DocumentParameters.new(content: language_data) params.custom_headers = { 'X-RosetteAPI-App' => 'ruby-app' } - response = rosette_api.get_language(params) + response = analytics_api.get_language(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/language_multilingual.rb b/examples/language_multilingual.rb index 7bc1be4..21edf27 100644 --- a/examples/language_multilingual.rb +++ b/examples/language_multilingual.rb @@ -4,11 +4,11 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end language_multilingual_data = 'On Thursday, as protesters gathered in Washington D.C., the United States Federal Communications Commission under Chairman Ajit Pai voted 3-2 to overturn a 2015 decision, commonly called Net Neutrality, that forbade Internet service providers (ISPs) such as Verizon, Comcast, and AT&T from blocking individual websites or charging websites or customers more for faster load times. Quatre femmes ont été nommées au Conseil de rédaction de la loi du Qatar. Jeudi, le décret royal du Qatar a annoncé que 28 nouveaux membres ont été nommés pour le Conseil de la Choura du pays. ذكرت مصادر أمنية يونانية، أن 9 موقوفين من منظمة \"د هـ ك ب ج\" الذين كانت قد أوقفتهم الشرطة اليونانية في وقت سابق كانوا يخططون لاغتيال الرئيس التركي رجب طيب أردوغان.' @@ -16,7 +16,7 @@ params = DocumentParameters.new(content: language_multilingual_data) params.rosette_options = { 'multilingual' => 'true' } params.custom_headers = { 'X-RosetteAPI-App' => 'ruby-app' } - response = rosette_api.get_language(params) + response = analytics_api.get_language(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/morphology_complete.rb b/examples/morphology_complete.rb index 1e505ad..7826d52 100644 --- a/examples/morphology_complete.rb +++ b/examples/morphology_complete.rb @@ -4,16 +4,16 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end morphology_complete_data = 'The quick brown fox jumped over the lazy dog. 👍🏾 Yes he did. B)' begin params = DocumentParameters.new(content: morphology_complete_data) - response = rosette_api.get_morphology_complete(params) + response = analytics_api.get_morphology_complete(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/morphology_compound-components.rb b/examples/morphology_compound-components.rb index 175c7a3..6850d40 100644 --- a/examples/morphology_compound-components.rb +++ b/examples/morphology_compound-components.rb @@ -4,18 +4,18 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end morphology_compound_components_data = 'Rechtsschutzversicherungsgesellschaften' begin params = DocumentParameters.new( content: morphology_compound_components_data ) - response = rosette_api.get_compound_components(params) + response = analytics_api.get_compound_components(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/morphology_han-readings.rb b/examples/morphology_han-readings.rb index bf4366e..4f7934f 100644 --- a/examples/morphology_han-readings.rb +++ b/examples/morphology_han-readings.rb @@ -4,16 +4,16 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end morphology_han_readings_data = '北京大学生物系主任办公室内部会议' begin params = DocumentParameters.new(content: morphology_han_readings_data) - response = rosette_api.get_han_readings(params) + response = analytics_api.get_han_readings(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/morphology_lemmas.rb b/examples/morphology_lemmas.rb index bd68690..c5088fb 100644 --- a/examples/morphology_lemmas.rb +++ b/examples/morphology_lemmas.rb @@ -4,16 +4,16 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end morphology_lemmas_data = 'The fact is that the geese just went back to get a rest and I\'m not banking on their return soon' begin params = DocumentParameters.new(content: morphology_lemmas_data) - response = rosette_api.get_lemmas(params) + response = analytics_api.get_lemmas(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/morphology_parts-of-speech.rb b/examples/morphology_parts-of-speech.rb index 0c69e98..e0c515a 100644 --- a/examples/morphology_parts-of-speech.rb +++ b/examples/morphology_parts-of-speech.rb @@ -4,16 +4,16 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end morphology_parts_of_speech_data = 'The fact is that the geese just went back to get a rest and I\'m not banking on their return soon' begin params = DocumentParameters.new(content: morphology_parts_of_speech_data) - response = rosette_api.get_parts_of_speech(params) + response = analytics_api.get_parts_of_speech(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/multipart_language_file.rb b/examples/multipart_language_file.rb new file mode 100644 index 0000000..648c63b --- /dev/null +++ b/examples/multipart_language_file.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'rosette_api' +require 'fileutils' + +api_key, url = ARGV + +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end + +begin + # Create a sample file to upload (so the example is runnable as-is). + file_path = File.expand_path('sample.txt', __dir__) + File.write(file_path, "Bonjour tout le monde.\n") + + params = DocumentParameters.new(file_path: file_path) + response = analytics_api.get_language(params) + puts JSON.pretty_generate(response) +rescue RosetteAPIError => e + printf('Rosette API Error (%s): %s', + status_code: e.status_code, + message: e.message) +ensure + FileUtils.rm_f(file_path) +end diff --git a/examples/name_deduplication.rb b/examples/name_deduplication.rb index ff4ca7f..6195a63 100644 --- a/examples/name_deduplication.rb +++ b/examples/name_deduplication.rb @@ -4,11 +4,11 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end name_dedupe_data = 'Alice Terry,Alice Thierry,Betty Grable,Betty Gable,Norma Shearer,Norm Shearer,Brigitte Helm,Bridget Helem,Judy Holliday,Julie Halliday' @@ -16,7 +16,7 @@ names = name_dedupe_data.split(',').map { |n| NameParameter.new(n) } begin params = NameDeduplicationParameters.new(names, threshold) - response = rosette_api.get_name_deduplication(params) + response = analytics_api.get_name_deduplication(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/name_similarity.rb b/examples/name_similarity.rb index 1264067..f0ec486 100644 --- a/examples/name_similarity.rb +++ b/examples/name_similarity.rb @@ -4,11 +4,11 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end matched_name_data1 = 'Michael Jackson' matched_name_data2 = '迈克尔·杰克逊' @@ -19,7 +19,7 @@ language: 'eng' ) params = NameSimilarityParameters.new(name1, matched_name_data2) - response = rosette_api.get_name_similarity(params) + response = analytics_api.get_name_similarity(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/name_translation.rb b/examples/name_translation.rb index 86ad6b7..babb8da 100644 --- a/examples/name_translation.rb +++ b/examples/name_translation.rb @@ -4,11 +4,11 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end translated_name_data = 'معمر محمد أبو منيار القذاف' begin @@ -17,7 +17,7 @@ 'eng', target_script: 'Latn' ) - response = rosette_api.get_name_translation(params) + response = analytics_api.get_name_translation(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/ping.rb b/examples/ping.rb index 156f8e7..45a9d80 100644 --- a/examples/ping.rb +++ b/examples/ping.rb @@ -4,14 +4,14 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end begin - response = rosette_api.ping + response = analytics_api.ping puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/record_similarity.rb b/examples/record_similarity.rb new file mode 100644 index 0000000..f56d74e --- /dev/null +++ b/examples/record_similarity.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +require 'rosette_api' + +api_key, url = ARGV + +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end + +begin + # Field names + primary_name_field = 'primaryName' + dob_field = 'dob' + dob2_field = 'dob2' + addr_field = 'addr' + str_field = 'jobTitle' + number_field = 'age' + bool_field = 'isRetired' + + dob_hyphen = '1993-04-16' + + # Request fields definition + fields = { + primary_name_field => { type: 'rni_name', weight: 0.5 }, + dob_field => { type: 'rni_date', weight: 0.2 }, + dob2_field => { type: 'rni_date', weight: 0.1 }, + addr_field => { type: 'rni_address', weight: 0.5 }, + str_field => { type: 'rni_string', weight: 0.2 }, + number_field => { type: 'rni_number', weight: 0.4 }, + bool_field => { type: 'rni_boolean', weight: 0.05 } + } + + # Request properties + properties = { + threshold: 0.7, + includeExplainInfo: true + } + + # Records payload. This shape mirrors the Java example's left/right lists. + # + # NOTE: The exact record field object schemas are API-specific. This example + # uses descriptive hashes that are intended to serialize cleanly to JSON. + records = { + left: [ + { + primary_name_field => { + text: 'Ethan R', + entityType: 'PERSON', + language: 'eng', + languageOfOrigin: 'eng', + script: 'Latn' + }, + dob_field => dob_hyphen, + dob2_field => { + date: '04161993', + format: 'MMddyyyy' + }, + addr_field => '123 Roadlane Ave', + str_field => 'software engineer' + }, + { + primary_name_field => { + text: 'Evan R' + }, + dob_field => { + date: dob_hyphen + }, + number_field => 47, + bool_field => false + } + ], + right: [ + { + primary_name_field => { + text: 'Seth R', + language: 'eng' + }, + dob_field => { + date: dob_hyphen + }, + str_field => 'manager', + bool_field => true + }, + { + primary_name_field => 'Ivan R', + dob_field => { + date: dob_hyphen + }, + dob2_field => { + date: '1993/04/16' + }, + addr_field => { + houseNumber: '123', + road: 'Roadlane Ave', + cityDistrict: 'Alpha' + }, + number_field => 72, + bool_field => true + } + ] + } + + params = RecordSimilarityParameters.new(fields, records, properties) + response = analytics_api.get_record_similarity(params) + puts JSON.pretty_generate(response) +rescue RosetteAPIError => e + printf('Rosette API Error (%s): %s', + status_code: e.status_code, + message: e.message) +end diff --git a/examples/relationships.rb b/examples/relationships.rb index 6505290..c8123bf 100644 --- a/examples/relationships.rb +++ b/examples/relationships.rb @@ -4,17 +4,17 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end relationships_text_data = 'FLIR Systems is headquartered in Oregon and produces thermal imaging, night vision, and infrared cameras and sensor systems. According to the SEC\'s order instituting a settled administrative proceeding, FLIR entered into a multi-million dollar contract to provide thermal binoculars to the Saudi government in November 2008. Timms and Ramahi were the primary sales employees responsible for the contract, and also were involved in negotiations to sell FLIR\'s security cameras to the same government officials. At the time, Timms was the head of FLIR\'s Middle East office in Dubai.' begin params = DocumentParameters.new(content: relationships_text_data) - response = rosette_api.get_relationships(params) + response = analytics_api.get_relationships(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/semantic_vectors.rb b/examples/semantic_vectors.rb index 041fc90..dc007ee 100644 --- a/examples/semantic_vectors.rb +++ b/examples/semantic_vectors.rb @@ -4,16 +4,16 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end semantic_vectors_data = 'Cambridge, Massachusetts' begin params = DocumentParameters.new(content: semantic_vectors_data) - response = rosette_api.get_semantic_vectors(params) + response = analytics_api.get_semantic_vectors(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/sentences.rb b/examples/sentences.rb index 7a22b69..5e9b7d3 100644 --- a/examples/sentences.rb +++ b/examples/sentences.rb @@ -4,18 +4,18 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end sentences_data = 'This land is your land. This land is my land, from California to the New York island; from the red wood forest to the Gulf Stream waters. This land was made for you and Me. As I was walking that ribbon of highway, I saw above me that endless skyway: I saw below me that golden valley: This land was made for you and me.' begin params = DocumentParameters.new params.content = sentences_data - response = rosette_api.get_sentences(params) + response = analytics_api.get_sentences(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/sentiment.rb b/examples/sentiment.rb index d03cb13..07cc57e 100644 --- a/examples/sentiment.rb +++ b/examples/sentiment.rb @@ -5,11 +5,11 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end file = Tempfile.new(%w[foo .html]) sentiment_file_data = 'New Ghostbusters Film

Original Ghostbuster Dan Aykroyd, who also co-wrote the 1984 Ghostbusters film, couldn\'t be more pleased with the new all-female Ghostbusters cast, telling The Hollywood Reporter, "The Aykroyd family is delighted by this inheritance of the Ghostbusters torch by these most magnificent women in comedy."

' @@ -17,7 +17,7 @@ file.close begin params = DocumentParameters.new(file_path: file.path, language: 'eng') - response = rosette_api.get_sentiment(params) + response = analytics_api.get_sentiment(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/similar_terms.rb b/examples/similar_terms.rb index 5657c51..dd7d678 100644 --- a/examples/similar_terms.rb +++ b/examples/similar_terms.rb @@ -4,17 +4,17 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end similar_terms_data = 'spy' begin params = DocumentParameters.new(content: similar_terms_data) params.rosette_options = { 'resultLanguages' => %w[spa deu jpn] } - response = rosette_api.get_similar_terms(params) + response = analytics_api.get_similar_terms(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/syntax_dependencies.rb b/examples/syntax_dependencies.rb index 140d1fb..ebe032e 100644 --- a/examples/syntax_dependencies.rb +++ b/examples/syntax_dependencies.rb @@ -4,17 +4,17 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end syntax_dependencies_data = 'Yoshinori Ohsumi, a Japanese cell biologist, was awarded the Nobel Prize in Physiology or Medicine on Monday.' begin params = DocumentParameters.new(content: syntax_dependencies_data) - response = rosette_api.get_syntax_dependencies(params) + response = analytics_api.get_syntax_dependencies(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/tokens.rb b/examples/tokens.rb index 020c465..17998c1 100644 --- a/examples/tokens.rb +++ b/examples/tokens.rb @@ -4,16 +4,16 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end tokens_data = '北京大学生物系主任办公室内部会议' begin params = DocumentParameters.new(content: tokens_data) - response = rosette_api.get_tokens(params) + response = analytics_api.get_tokens(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/topics.rb b/examples/topics.rb index 76f1356..e0fb08c 100644 --- a/examples/topics.rb +++ b/examples/topics.rb @@ -4,17 +4,17 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end topics_data = 'Lily Collins is in talks to join Nicholas Hoult in Chernin Entertainment and Fox Searchlight\'s J.R.R. Tolkien biopic Tolkien. Anthony Boyle, known for playing Scorpius Malfoy in the British play Harry Potter and the Cursed Child, also has signed on for the film centered on the famed author. In Tolkien, Hoult will play the author of the Hobbit and Lord of the Rings book series that were later adapted into two Hollywood trilogies from Peter Jackson. Dome Karukoski is directing the project.' begin params = DocumentParameters.new(content: topics_data) - response = rosette_api.get_topics(params) + response = analytics_api.get_topics(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/examples/transliteration.rb b/examples/transliteration.rb index 887b46f..9f1dec9 100644 --- a/examples/transliteration.rb +++ b/examples/transliteration.rb @@ -4,18 +4,18 @@ api_key, url = ARGV -rosette_api = if url - RosetteAPI.new(api_key, url) - else - RosetteAPI.new(api_key) - end +analytics_api = if url + RosetteAPI.new(api_key, url) + else + RosetteAPI.new(api_key) + end transliteration_content_data = 'ana r2ye7 el gam3a el sa3a 3 el 3asr' begin params = DocumentParameters.new params.content = transliteration_content_data - response = rosette_api.get_transliteration(params) + response = analytics_api.get_transliteration(params) puts JSON.pretty_generate(response) rescue RosetteAPIError => e printf('Rosette API Error (%s): %s', diff --git a/lib/address_parameter.rb b/lib/address_parameter.rb index 19a79c5..e66f677 100644 --- a/lib/address_parameter.rb +++ b/lib/address_parameter.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# This class represents an address in Rosette API. +# This class represents an address in Analytics API. class AddressParameter # house (optional) attr_accessor :house diff --git a/lib/address_similarity_parameters.rb b/lib/address_similarity_parameters.rb index 18cf882..265ae92 100644 --- a/lib/address_similarity_parameters.rb +++ b/lib/address_similarity_parameters.rb @@ -4,16 +4,20 @@ require_relative 'address_parameter' # This class encapsulates parameters that are needed for address-similarity in -# Rosette API. +# Analytics API. class AddressSimilarityParameters # Address to be compared to address2 attr_accessor :address1 # Address to be compared to address1 attr_accessor :address2 - def initialize(address1, address2) # :notnew: + # Parameters map sent to the API (optional, should be a hash) + attr_accessor :parameters + + def initialize(address1, address2, address_parameters = nil) # :notnew: @address1 = address1 @address2 = address2 + @parameters = address_parameters end # Validates the parameters by checking if address1 and address2 are instances @@ -24,6 +28,9 @@ def validate_params a2_msg = 'address2 option can only be an instance of an AddressParameter or a String' raise BadRequestError.new(a2_msg) if [String, AddressParameter].none? { |clazz| @address2.is_a? clazz } + + opt_msg = 'parameters can only be an instance of a Hash' + raise BadRequestError.new(opt_msg) if @parameters && !(@parameters.is_a? Hash) end # Converts this class to Hash with its keys in lower CamelCase. @@ -42,7 +49,8 @@ def load_params def to_hash { address1: @address1.is_a?(AddressParameter) ? @address1.load_param : @address1, - address2: @address2.is_a?(AddressParameter) ? @address2.load_param : @address2 + address2: @address2.is_a?(AddressParameter) ? @address2.load_param : @address2, + parameters: @parameters } end end diff --git a/lib/bad_request_error.rb b/lib/bad_request_error.rb index 473e0e8..4660001 100644 --- a/lib/bad_request_error.rb +++ b/lib/bad_request_error.rb @@ -2,7 +2,7 @@ require_relative 'rosette_api_error' -# This class represents Rosette API errors with badRequest status_code. +# This class represents Analytics API errors with badRequest status_code. class BadRequestError < RosetteAPIError def initialize(message) # :notnew: super('badRequest', message) diff --git a/lib/bad_request_format_error.rb b/lib/bad_request_format_error.rb index 1a6fb45..f4a088f 100644 --- a/lib/bad_request_format_error.rb +++ b/lib/bad_request_format_error.rb @@ -2,7 +2,7 @@ require_relative 'rosette_api_error' -# This class represents Rosette API errors with badRequestFormat status_code. +# This class represents Analytics API errors with badRequestFormat status_code. class BadRequestFormatError < RosetteAPIError def initialize(message) # :notnew: super('badRequestFormat', message) diff --git a/lib/document_parameters.rb b/lib/document_parameters.rb index 1bdf941..cef0268 100644 --- a/lib/document_parameters.rb +++ b/lib/document_parameters.rb @@ -17,9 +17,9 @@ class DocumentParameters attr_accessor :genre # ISO 639-3 language code of the provided content (optional) attr_accessor :language - # Rosette API options (optional, should be a hash) + # API options (optional, should be a hash) attr_accessor :rosette_options - # custom Rosette API headers + # custom API headers attr_accessor :custom_headers def initialize(options = {}) # :notnew: @@ -55,8 +55,8 @@ def validate_params raise BadRequestFormatError.new(content_msg) elsif [@content, @content_uri, @file_path].all?(&:nil?) raise BadRequestFormatError.new(no_content_msg) - elsif @rosette_options - raise BadRequestError.new(opt_msg) unless @rosette_options.is_a? Hash + elsif @rosette_options && !@rosette_options.is_a?(Hash) + raise BadRequestError.new(opt_msg) end end @@ -78,7 +78,6 @@ def to_hash content: @content, content_uri: @content_uri, file_path: @file_path, - genre: @genre, language: @language, options: @rosette_options, custom_headers: @custom_headers diff --git a/lib/name_deduplication_parameters.rb b/lib/name_deduplication_parameters.rb index e6baa33..4755d7d 100644 --- a/lib/name_deduplication_parameters.rb +++ b/lib/name_deduplication_parameters.rb @@ -4,9 +4,9 @@ require_relative 'name_parameter' # This class encapsulates parameters that are needed for name-deduplication in -# Rosette API. +# Analytics API. class NameDeduplicationParameters - # Rosette API options (optional, should be a hash) + # API options (optional, should be a hash) attr_accessor :rosette_options # List of Name objects to be de-duplicated attr_accessor :names diff --git a/lib/name_parameter.rb b/lib/name_parameter.rb index 9778e22..5b0715e 100644 --- a/lib/name_parameter.rb +++ b/lib/name_parameter.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# This class represents an entity name in Rosette API. +# This class represents an entity name in Analytics API. class NameParameter # Name's entity type (PERSON, LOCATION, ORGANIZATION) (optional) attr_accessor :entity_type @@ -8,19 +8,36 @@ class NameParameter attr_accessor :language # ISO 15924 code of the name's script (optional) attr_accessor :script + # Name's gender (male, female, nonbinary) (optional) + attr_accessor :gender # Name to be analyzed attr_accessor :text + VALID_GENDERS = %w[male female nonbinary].freeze + def initialize(text, options = {}) # :notnew: options = { entity_type: nil, language: nil, - script: nil + script: nil, + gender: nil }.update options @text = text @entity_type = options[:entity_type] @language = options[:language] @script = options[:script] + @gender = options[:gender] + + validate_gender + end + + def validate_gender + return if @gender.nil? + + normalized = @gender.to_s.downcase + return if VALID_GENDERS.include?(normalized) + + raise ArgumentError.new("gender must be one of: #{VALID_GENDERS.join(', ')}") end # Converts this class to Hash with its keys in lower CamelCase. @@ -40,6 +57,7 @@ def to_hash entity_type: @entity_type, language: @language, script: @script, + gender: @gender, text: @text } end diff --git a/lib/name_similarity_parameters.rb b/lib/name_similarity_parameters.rb index 6efca25..9236acc 100644 --- a/lib/name_similarity_parameters.rb +++ b/lib/name_similarity_parameters.rb @@ -4,26 +4,29 @@ require_relative 'name_parameter' # This class encapsulates parameters that are needed for name-similarity in -# Rosette API. +# Analytics API. class NameSimilarityParameters # genre to categorize the input data attr_accessor :genre - # Rosette API options (optional, should be a hash) - attr_accessor :rosette_options + + # Parameters map sent to the API (optional, should be a hash) + attr_accessor :parameters + # Name to be compared to name2 attr_accessor :name1 # Name to be compared to name1 attr_accessor :name2 - def initialize(name1, name2, options = {}) # :notnew: + def initialize(name1, name2, match_parameters = nil, options = {}) # :notnew: options = { - genre: nil, - rosette_options: nil + genre: nil }.update options @genre = options[:genre] + @name1 = name1 @name2 = name2 - @rosette_options = options[:rosette_options] + + @parameters = match_parameters end # Validates the parameters by checking if name1 and name2 are instances of @@ -35,8 +38,8 @@ def validate_params n2_msg = 'name2 option can only be an instance of a String or NameParameter' raise BadRequestError.new(n2_msg) if [String, NameParameter].none? { |clazz| @name2.is_a? clazz } - opt_msg = 'rosette_options can only be an instance of a Hash' - raise BadRequestError.new(opt_msg) if @rosette_options && !(@rosette_options.is_a? Hash) + opt_msg = 'parameters can only be an instance of a Hash' + raise BadRequestError.new(opt_msg) if @parameters && !(@parameters.is_a? Hash) end # Converts this class to Hash with its keys in lower CamelCase. @@ -54,10 +57,9 @@ def load_params # Returns the new Hash. def to_hash { - genre: @genre, name1: @name1.is_a?(NameParameter) ? @name1.load_param : @name1, name2: @name2.is_a?(NameParameter) ? @name2.load_param : @name2, - options: @rosette_options + parameters: @parameters } end end diff --git a/lib/name_translation_parameters.rb b/lib/name_translation_parameters.rb index aaeb0c1..aa4fb09 100644 --- a/lib/name_translation_parameters.rb +++ b/lib/name_translation_parameters.rb @@ -3,7 +3,7 @@ require_relative 'rosette_api_error' # This class encapsulates parameters that are needed for name-translation in -# Rosette API. +# Analytics API. class NameTranslationParameters # Name's entity type (PERSON, LOCATION, ORGANIZATION) (optional) attr_accessor :entity_type @@ -11,7 +11,7 @@ class NameTranslationParameters attr_accessor :genre # Name to translate attr_accessor :name - # Rosette API options (optional, should be a hash) + # API options (optional, should be a hash) attr_accessor :rosette_options # ISO 693-3 code of the name's native language the name originates in # (optional) @@ -26,11 +26,14 @@ class NameTranslationParameters attr_accessor :target_scheme # ISO 15924 code of name's script (optional) attr_accessor :target_script + # Maximum number of results to return (optional) + attr_accessor :maximum_results def initialize(name, target_language, options = {}) # :notnew: options = { entity_type: nil, genre: nil, + maximum_results: nil, rosette_options: nil, source_language_of_origin: nil, source_language_of_use: nil, @@ -41,6 +44,7 @@ def initialize(name, target_language, options = {}) # :notnew: @name = name @entity_type = options[:entity_type] @genre = options[:genre] + @maximum_results = options[:maximum_results] @rosette_options = options[:rosette_options] @source_language_of_origin = options[:source_language_of_origin] @source_language_of_use = options[:source_language_of_use] @@ -55,6 +59,12 @@ def initialize(name, target_language, options = {}) # :notnew: def validate_params msg = 'rosette_options can only be an instance of a Hash' raise BadRequestError.new(msg) if @rosette_options && !(@rosette_options.is_a? Hash) + + max_msg = 'maximum_results can only be an instance of an Integer' + raise BadRequestError.new(max_msg) if @maximum_results && !(@maximum_results.is_a? Integer) + + max_range_msg = 'maximum_results must be greater than or equal to 0' + raise BadRequestError.new(max_range_msg) if @maximum_results&.negative? end # Converts this class to Hash with its keys in lower CamelCase. @@ -73,7 +83,6 @@ def load_params def to_hash { entity_type: @entity_type, - genre: @genre, name: @name, options: @rosette_options, source_language_of_origin: @source_language_of_origin, @@ -81,7 +90,8 @@ def to_hash source_script: @source_script, target_language: @target_language, target_scheme: @target_scheme, - target_script: @target_script + target_script: @target_script, + maximum_results: @maximum_results } end end diff --git a/lib/record_similarity_parameters.rb b/lib/record_similarity_parameters.rb new file mode 100644 index 0000000..6b68dc0 --- /dev/null +++ b/lib/record_similarity_parameters.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require_relative 'bad_request_error' + +# This class encapsulates parameters that are needed for record-similarity in +# Analytics API. +class RecordSimilarityParameters + # Records to be compared (required) + attr_accessor :records + + # Field names/definitions used for similarity scoring (required) + attr_accessor :fields + + # Optional properties map sent to the API (optional, should be a hash) + attr_accessor :properties + + def initialize(fields, records, properties = nil) # :notnew: + @fields = fields + @records = records + @properties = properties + end + + # Validates the parameters by checking if required fields are present and + # optional properties is a Hash if provided. + def validate_params + f_msg = 'fields option is required' + raise BadRequestError.new(f_msg) if @fields.nil? + + f_type_msg = 'fields can only be an instance of a Hash' + raise BadRequestError.new(f_type_msg) unless @fields.is_a? Hash + + f_empty_msg = 'fields must not be empty' + raise BadRequestError.new(f_empty_msg) if @fields.empty? + + r_msg = 'records option is required' + raise BadRequestError.new(r_msg) if @records.nil? + + r_type_msg = 'records can only be an instance of a Hash' + raise BadRequestError.new(r_type_msg) unless @records.is_a? Hash + + r_empty_msg = 'records must not be empty' + raise BadRequestError.new(r_empty_msg) if @records.empty? + + p_msg = 'properties can only be an instance of a Hash' + raise BadRequestError.new(p_msg) if @properties && !(@properties.is_a? Hash) + end + + # Converts this class to Hash with its keys in lower CamelCase. + # + # Returns the new Hash. + def load_params + validate_params + to_hash + .compact + .transform_keys { |key| key.to_s.split('_').map(&:capitalize).join.sub!(/\D/, &:downcase) } + end + + # Converts this class to Hash. + # + # Returns the new Hash. + def to_hash + { + fields: @fields, + records: @records, + properties: @properties + } + end +end diff --git a/lib/request_builder.rb b/lib/request_builder.rb index 6b28366..105d4e7 100644 --- a/lib/request_builder.rb +++ b/lib/request_builder.rb @@ -6,17 +6,45 @@ require 'securerandom' require_relative 'rosette_api_error' -# This class handles all Rosette API requests. +# This class handles all Analytics API requests. class RequestBuilder - # Alternate Rosette API URL + CONNECTION_ERROR_CODE = 'connectionError' + CONNECTION_ERROR_MESSAGE = 'Failed to establish connection with Analytics server.' + + INVALID_HEADER_CODE = 'invalidHeader' + INVALID_HEADER_MESSAGE = 'Custom header must begin with "X-RosetteAPI-" or "X-BabelStreetAPI-"' + + READ_MULTIPART_ERROR_CODE = 'readMultipartError' + + HEADER_API_KEY = 'X-BabelStreetAPI-Key' + HEADER_CONTENT_TYPE = 'Content-Type' + HEADER_ACCEPT = 'Accept' + HEADER_USER_AGENT = 'User-Agent' + HEADER_BINDING_LEGACY = 'X-RosetteAPI-Binding' + HEADER_BINDING = 'X-BabelStreetAPI-Binding' + HEADER_BINDING_VERSION_LEGACY = 'X-RosetteAPI-Binding-Version' + HEADER_BINDING_VERSION = 'X-BabelStreetAPI-Binding-Version' + + BINDING_NAME = 'ruby' + + CONTENT_TYPE_JSON = 'application/json' + CONTENT_TYPE_TEXT_PLAIN = 'text/plain' + ACCEPT_JSON = 'application/json' + + MULTIPART_FORM_DATA = 'multipart/form-data' + + CUSTOM_HEADER_PREFIX_ROSETTE = /^X-RosetteAPI-/ + CUSTOM_HEADER_PREFIX_BABELSTREET = /^X-BabelStreetAPI-/ + + # Alternate API URL attr_reader :alternate_url - # Rosette API HTTP client + # API HTTP client attr_reader :http_client # Parameters to build the body of the request from attr_accessor :params - # Rosette API key + # API key attr_accessor :user_key - # Rosette API binding version + # API binding version attr_accessor :binding_version # User-Agent string attr_reader :user_agent @@ -35,7 +63,7 @@ def initialize(user_key, alternate_url, http_client, binding_version, @alternate_url = "#{@alternate_url}?#{URI.encode_www_form(url_parameters)}" end - # Prepares a plain POST request for Rosette API. + # Prepares a plain POST request for Analytics API. # # ==== Attributes # @@ -50,8 +78,8 @@ def prepare_plain_request(params) # Not ideal. Consider switching to a different library. # https://stackoverflow.com/a/11802674 raise RosetteAPIError.new( - 'connectionError', - 'Failed to establish connection with Rosette server.' + CONNECTION_ERROR_CODE, + CONNECTION_ERROR_MESSAGE ) end @@ -60,30 +88,32 @@ def prepare_plain_request(params) if custom_headers keys_array = custom_headers.keys keys_array.each do |key| - if key.to_s =~ /^X-RosetteAPI-/ + if key.to_s =~ CUSTOM_HEADER_PREFIX_ROSETTE || key.to_s =~ CUSTOM_HEADER_PREFIX_BABELSTREET request[key] = custom_headers[key] else raise RosetteAPIError.new( - 'invalidHeader', - 'Custom header must begin with "X-RosetteAPI-"' + INVALID_HEADER_CODE, + INVALID_HEADER_MESSAGE ) end end params.delete 'customHeaders' end - request['X-RosetteAPI-Key'] = @user_key - request['Content-Type'] = 'application/json' - request['Accept'] = 'application/json' - request['User-Agent'] = @user_agent - request['X-RosetteAPI-Binding'] = 'ruby' - request['X-RosetteAPI-Binding-Version'] = @binding_version + request[HEADER_API_KEY] = @user_key + request[HEADER_CONTENT_TYPE] = CONTENT_TYPE_JSON + request[HEADER_ACCEPT] = ACCEPT_JSON + request[HEADER_USER_AGENT] = @user_agent + request[HEADER_BINDING_LEGACY] = BINDING_NAME + request[HEADER_BINDING] = BINDING_NAME + request[HEADER_BINDING_VERSION_LEGACY] = @binding_version + request[HEADER_BINDING_VERSION] = @binding_version request.body = params.to_json [@http_client, request] end - # Prepares a multipart/form-data POST request for Rosette API. + # Prepares a multipart/form-data POST request for Analytics API. # # ==== Attributes # @@ -91,29 +121,25 @@ def prepare_plain_request(params) # # Returns a HTTP connection and the built POST request. def prepare_multipart_request(params) - begin - file = File.open params['filePath'], 'r' - text = file.read - rescue StandardError => e - raise RosetteAPIError.new('readMultipartError', e) - end + text = read_multipart_file params['filePath'] boundary = SecureRandom.hex post_body = [] - params.delete 'filePath' - request_file = params.to_json # Add the content data post_body << "--#{boundary}\r\n" post_body << 'Content-Disposition: form-data; name="content"; ' \ - "filename=\"#{File.basename(file)}\"\r\n" - post_body << "Content-Type: text/plain\r\n\r\n" + "filename=\"#{File.basename(params['filePath'])}\"\r\n" + post_body << "#{HEADER_CONTENT_TYPE}: #{CONTENT_TYPE_TEXT_PLAIN}\r\n\r\n" post_body << text # Add the request data + params.delete 'filePath' + request_file = params.to_json + post_body << "\r\n\r\n--#{boundary}\r\n" post_body << "Content-Disposition: form-data; name=\"request\"\r\n" - post_body << "Content-Type: application/json\r\n\r\n" + post_body << "#{HEADER_CONTENT_TYPE}: #{CONTENT_TYPE_JSON}\r\n\r\n" post_body << request_file post_body << "\r\n\r\n--#{boundary}--\r\n" @@ -125,8 +151,8 @@ def prepare_multipart_request(params) # Not ideal. Consider switching to a different library. # https://stackoverflow.com/a/11802674 raise RosetteAPIError.new( - 'connectionError', - 'Failed to establish connection with Rosette API server.' + CONNECTION_ERROR_CODE, + CONNECTION_ERROR_MESSAGE ) end @@ -134,30 +160,43 @@ def prepare_multipart_request(params) unless params['customHeaders'].nil? keys_array = params['customHeaders'].keys keys_array.each do |k| - if k.to_s =~ /^X-RosetteAPI-/ + if k.to_s =~ CUSTOM_HEADER_PREFIX_ROSETTE || k.to_s =~ CUSTOM_HEADER_PREFIX_BABELSTREET request.add_field k, params['customHeaders'][k] else raise RosetteAPIError.new( - 'invalidHeader', - 'Custom header must begin with "X-RosetteAPI-"' + INVALID_HEADER_CODE, + INVALID_HEADER_MESSAGE ) end end params.delete 'customHeaders' end - request.add_field 'Content-Type', - "multipart/form-data; boundary=#{boundary}" - request.add_field 'User-Agent', @user_agent - request.add_field 'X-RosetteAPI-Key', @user_key - request.add_field 'X-RosetteAPI-Binding', 'ruby' - request.add_field 'X-RosetteAPI-Binding-Version', @binding_version + request.add_field HEADER_CONTENT_TYPE, + "#{MULTIPART_FORM_DATA}; boundary=#{boundary}" + request.add_field HEADER_USER_AGENT, @user_agent + request.add_field HEADER_API_KEY, @user_key + request.add_field HEADER_BINDING_LEGACY, BINDING_NAME + request.add_field HEADER_BINDING, BINDING_NAME + request.add_field HEADER_BINDING_VERSION_LEGACY, @binding_version + request.add_field HEADER_BINDING_VERSION, @binding_version request.body = post_body.join [@http_client, request] end - # Sends a GET request to Rosette API. + # Reads the content of a file given its path. + # + # Returns the content of the file or raises error if encountered. + def read_multipart_file(file_path) + File.open(file_path, 'r') do |f| + return f.read + end + rescue StandardError => e + raise RosetteAPIError.new(READ_MULTIPART_ERROR_CODE, e) + end + + # Sends a GET request to Analytics API. # # Returns JSON response or raises RosetteAPIError if encountered. def send_get_request @@ -168,17 +207,17 @@ def send_get_request # Not ideal. Consider switching to a different library. # https://stackoverflow.com/a/11802674 raise RosetteAPIError.new( - 'connectionError', - 'Failed to establish connection with Rosette API server.' + CONNECTION_ERROR_CODE, + CONNECTION_ERROR_MESSAGE ) end - request['X-RosetteAPI-Key'] = @user_key - request['User-Agent'] = @user_agent + request[HEADER_API_KEY] = @user_key + request[HEADER_USER_AGENT] = @user_agent get_response @http_client, request end - # Sends a POST request to Rosette API. + # Sends a POST request to Analytics API. # # Returns JSON response or raises RosetteAPIError if encountered. def send_post_request @@ -197,7 +236,7 @@ def send_post_request # # * +http+ - HTTP connection. # - # * +request+ - Prepared Rosette API request. + # * +request+ - Prepared API request. # # Returns JSON response or raises RosetteAPIError if encountered. def get_response(http, request) diff --git a/lib/rosette_api.rb b/lib/rosette_api.rb index 81cb1a3..24ac10c 100644 --- a/lib/rosette_api.rb +++ b/lib/rosette_api.rb @@ -5,67 +5,72 @@ require_relative 'name_deduplication_parameters' require_relative 'name_translation_parameters' require_relative 'name_similarity_parameters' +require_relative 'record_similarity_parameters' require_relative 'address_similarity_parameters' require_relative 'rosette_api_error' require_relative 'bad_request_error' require_relative 'bad_request_format_error' require 'logger' -# This class allows you to access all Rosette API endpoints. +# This class allows you to access all Analytics API endpoints. class RosetteAPI # Version of Ruby binding - BINDING_VERSION = '1.27.1' - # Rosette API language endpoint + BINDING_VERSION = '1.37.0' + # API address-similarity endpoint + ADDRESS_SIMILARITY_ENDPOINT = '/address-similarity' + # API categories endpoint + CATEGORIES_ENDPOINT = '/categories' + # API entities endpoint + ENTITIES_ENDPOINT = '/entities' + # API events endpoint + EVENTS_ENDPOINT = '/events' + # API info endpoint + INFO = '/info' + # API language endpoint LANGUAGE_ENDPOINT = '/language' - # Rosette API morphology endpoint + # API morphology endpoint MORPHOLOGY_ENDPOINT = '/morphology' - # Rosette API entities endpoint - ENTITIES_ENDPOINT = '/entities' - # Rosette API categories endpoint - CATEGORIES_ENDPOINT = '/categories' - # Rosette API relationships endpoint - RELATIONSHIPS_ENDPOINT = '/relationships' - # Rosette API sentiment endpoint - SENTIMENT_ENDPOINT = '/sentiment' # Name Deduplication endpoint NAME_DEDUPLICATION_ENDPOINT = '/name-deduplication' - # Rosette API name-translation endpoint - NAME_TRANSLATION_ENDPOINT = '/name-translation' - # Rosette API name-similarity endpoint + # API name-similarity endpoint NAME_SIMILARITY_ENDPOINT = '/name-similarity' - # Rosette API address-similarity endpoint - ADDRESS_SIMILARITY_ENDPOINT = '/address-similarity' - # Rosette API tokens endpoint - TOKENS_ENDPOINT = '/tokens' - # Rosette API sentences endpoint - SENTENCES_ENDPOINT = '/sentences' - # Rosette API info endpoint - INFO = '/info' - # Rosette API ping endpoint + # API name-translation endpoint + NAME_TRANSLATION_ENDPOINT = '/name-translation' + # API ping endpoint PING = '/ping' - # Text Embedding endpoint (deprecated) - TEXT_EMBEDDING = '/text-embedding' + # Record Similarity endpoint + RECORD_SIMILARITY_ENDPOINT = '/record-similarity' + # API relationships endpoint + RELATIONSHIPS_ENDPOINT = '/relationships' # Semantic Vectors endpoint (replaces /text-embedding) SEMANTIC_VECTORS = '/semantics/vector' + # API sentences endpoint + SENTENCES_ENDPOINT = '/sentences' + # API sentiment endpoint + SENTIMENT_ENDPOINT = '/sentiment' # Similar Terms endpoint SIMILAR_TERMS_ENDPOINT = '/semantics/similar' # Syntactic Dependencies endpoint SYNTACTIC_DEPENDENCIES_ENDPOINT = '/syntax/dependencies' - # Transliteration endpoint - TRANSLITERATION_ENDPOINT = '/transliteration' + # Text Embedding endpoint (deprecated) + TEXT_EMBEDDING = '/text-embedding' + # API tokens endpoint + TOKENS_ENDPOINT = '/tokens' # Topics endpoint TOPICS_ENDPOINT = '/topics' + # Transliteration endpoint + TRANSLITERATION_ENDPOINT = '/transliteration' - # Rosette API key + # API key attr_accessor :user_key - # Alternate Rosette API URL + # Alternate API URL attr_accessor :alternate_url - # custom Rosette API headers + # custom API headers attr_accessor :custom_headers # URL query parameter(s) attr_accessor :url_parameters - def initialize(user_key, alternate_url = 'https://api.rosette.com/rest/v1') + def initialize(user_key, alternate_url = 'https://analytics.babelstreet.com/rest/v1') @log = Logger.new($stdout) @user_key = user_key @alternate_url = alternate_url @@ -350,6 +355,26 @@ def get_address_similarity(params) .send_post_request end + # Compares records and returns similarity information. + # + # ==== Attributes + # + # * +params+ - RecordSimilarityParameters helps to build the request body in + # RequestBuilder. + # + # Returns record similarity results. + def get_record_similarity(params) + check_params params, + 'Expects a RecordSimilarityParameters type as an argument', + RecordSimilarityParameters + + params = params.load_params + + RequestBuilder.new(@user_key, @alternate_url + RECORD_SIMILARITY_ENDPOINT, + @http_client, BINDING_VERSION, params, @url_parameters) + .send_post_request + end + # Divides the input into tokens. # # ==== Attributes @@ -501,7 +526,25 @@ def get_similar_terms(params) .send_post_request end - # Gets information about the Rosette API, returns name, build number + # Returns the events of the input + # + # ==== Attributes + # + # * +params+ - DocumentParameters helps to build the request body in + # RequestBuilder. + # + # Returns the events of the input + def get_events(params) + check_params params + + params = params.load_params + + RequestBuilder.new(@user_key, @alternate_url + EVENTS_ENDPOINT, + @http_client, BINDING_VERSION, params, @url_parameters) + .send_post_request + end + + # Gets information about the API, returns name, build number # and build time. def info RequestBuilder.new(@user_key, @alternate_url + INFO, @http_client, @@ -509,7 +552,7 @@ def info .send_get_request end - # Pings the Rosette API for a response indicting that the service is + # Pings the API for a response indicting that the service is # available. def ping RequestBuilder.new(@user_key, @alternate_url + PING, @http_client, diff --git a/lib/rosette_api_error.rb b/lib/rosette_api_error.rb index 427e4cd..cb5abcb 100644 --- a/lib/rosette_api_error.rb +++ b/lib/rosette_api_error.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -# This class encapsulates all Rosette API server errors encountered during +# This class encapsulates all API server errors encountered during # requests. class RosetteAPIError < StandardError - # Rosette API error's status code + # API error's status code attr_accessor :status_code - # Rosette API error's message + # API error's message attr_accessor :message def initialize(status_code, message) # :notnew: diff --git a/rosette_api.gemspec b/rosette_api.gemspec index 3045f10..add7b68 100644 --- a/rosette_api.gemspec +++ b/rosette_api.gemspec @@ -10,25 +10,26 @@ Gem::Specification.new do |spec| } spec.name = 'rosette_api' - spec.version = '1.27.1' + spec.version = '1.37.0' spec.license = 'Apache-2.0' - spec.summary = 'A Ruby interface for Rosette Text Analytics Platform.' + spec.summary = 'A Ruby interface for Babel Street Analytics Server and Hosted Services' spec.description = - 'The Rosette Text Analytics Platform uses natural language processing, ' \ - 'statistical modeling, and machine learning to analyze unstructured and ' \ - 'semi-structured text across 364 language-encoding-script combinations, ' \ - 'revealing valuable information and actionable data. Rosette provides ' \ - 'endpoints for extracting entities and relationships, translating and ' \ - 'comparing the similarity of names, categorizing and adding linguistic ' \ - 'tags to text and more.' + 'Our product is a full text processing pipeline from data preparation to extracting the most relevant information and' \ + 'analysis utilizing precise, focused AI that has built-in human understanding. Text Analytics provides foundational' \ + 'linguistic analysis for identifying languages and relating words. The result is enriched and normalized text for' \ + 'high-speed search and processing without translation.' \ + 'Text Analytics extracts events and entities — people, organizations, and places — from unstructured text and adds the' \ + 'structure of associating those entities into events that deliver only the necessary information for near real-time' \ + 'decision making. Accompanying tools shorten the process of training AI models to recognize domain-specific events.' \ + 'The product delivers a multitude of ways to sharpen and expand search results. Semantic similarity expands search' \ + 'beyond keywords to words with the same meaning, even in other languages. Sentiment analysis and topic extraction help' \ + 'filter results to what’s relevant.' - spec.authors = ['Basis Technology Corp'] - spec.email = 'support@rosette.com' - spec.homepage = 'https://developer.rosette.com/' + spec.authors = ['Analytics by Babel Street'] + spec.email = 'analyticssupport@babelstreet.com' + spec.homepage = 'https://developer.babelstreet.com/' spec.files = Dir['LICENSE', 'README.md', 'lib/**/*', 'examples/**/*'] spec.require_paths = ['lib'] - - spec.add_runtime_dependency('rubysl-securerandom', '~> 2.0') end diff --git a/sonar-project.properties b/sonar-project.properties index d23e709..500f06a 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,4 +1,2 @@ sonar.projectKey=rosette-api-ruby-binding -sonar.ruby.coverage.reportPaths=coverage/.resultset.json -#sonar.ruby.coverage.reportPaths=coverage/coverage.json sonar.exclusions=**/tests/**,**/examples/** diff --git a/tests/tests_spec.rb b/tests/tests_spec.rb index d7ce909..2899dd9 100644 --- a/tests/tests_spec.rb +++ b/tests/tests_spec.rb @@ -30,7 +30,7 @@ describe '.get_language' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/language') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/language') .with( body: @json, headers: { @@ -38,9 +38,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "language"}', headers: {}) @@ -69,7 +71,7 @@ describe '.get_morphology_complete' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/morphology/complete') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/morphology/complete') .with( body: @json, headers: { @@ -77,9 +79,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, @@ -96,7 +100,7 @@ describe '.get_compound_components' do before do - url = 'https://api.rosette.com/rest/v1/morphology/compound-components' + url = 'https://analytics.babelstreet.com/rest/v1/morphology/compound-components' stub_request(:post, url) .with( body: @json, @@ -105,9 +109,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, @@ -124,7 +130,7 @@ describe '.get_han_readings' do before do - url = 'https://api.rosette.com/rest/v1/morphology/han-readings' + url = 'https://analytics.babelstreet.com/rest/v1/morphology/han-readings' stub_request(:post, url) .with( body: @json, @@ -133,9 +139,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, @@ -152,7 +160,7 @@ describe '.get_parts_of_speech' do before do - url = 'https://api.rosette.com/rest/v1/morphology/parts-of-speech' + url = 'https://analytics.babelstreet.com/rest/v1/morphology/parts-of-speech' stub_request(:post, url) .with( body: @json, @@ -161,9 +169,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, @@ -180,7 +190,7 @@ describe '.get_lemmas' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/morphology/lemmas') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/morphology/lemmas') .with( body: @json, headers: { @@ -188,9 +198,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, @@ -207,7 +219,7 @@ describe '.get_entities' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/entities') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/entities') .with( body: @json, headers: { @@ -215,9 +227,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "entities"}', headers: {}) @@ -234,7 +248,7 @@ before do no_qids_json = { content: 'Sample Content', options: { linkEntities: false } }.to_json - stub_request(:post, 'https://api.rosette.com/rest/v1/entities') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/entities') .with( body: no_qids_json, headers: { @@ -242,9 +256,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "entities"}', headers: {}) @@ -271,7 +287,7 @@ describe '.get_categories' do before do categories_json = { contentUri: 'http://google.com' }.to_json - stub_request(:post, 'https://api.rosette.com/rest/v1/categories') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/categories') .with( body: categories_json, headers: { @@ -279,9 +295,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "categories"}', headers: {}) @@ -294,9 +312,96 @@ end end + describe '.get_events' do + before do + events_json = { contentUri: 'http://google.com' }.to_json + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/events') + .with( + body: events_json, + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent, + 'X-BabelStreetAPI-Key' => '0123456789', + 'X-Rosetteapi-Binding' => 'ruby', + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' + } + ) + .to_return(status: 200, body: '{"test": "events"}', headers: {}) + end + + it 'test events' do + params = DocumentParameters.new + params.content_uri = 'http://google.com' + response = RosetteAPI.new('0123456789').get_events(params) + expect(response).instance_of? Hash + end + end + + describe '.get_sentiment' do + before do + sentiment_json = { contentUri: 'http://google.com' }.to_json + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/sentiment') + .with( + body: sentiment_json, + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent, + 'X-BabelStreetAPI-Key' => '0123456789', + 'X-Rosetteapi-Binding' => 'ruby', + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' + } + ) + .to_return(status: 200, body: '{"test": "sentiment"}', headers: {}) + end + + it 'test sentiment' do + params = DocumentParameters.new + params.content_uri = 'http://google.com' + response = RosetteAPI.new('0123456789').get_sentiment(params) + expect(response).instance_of? Hash + end + end + + describe '.get_text_embedding' do + before do + text_embedding_json = { contentUri: 'http://google.com' }.to_json + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/text-embedding') + .with( + body: text_embedding_json, + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent, + 'X-BabelStreetAPI-Key' => '0123456789', + 'X-Rosetteapi-Binding' => 'ruby', + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' + } + ) + .to_return(status: 200, body: '{"test": "text-embedding"}', headers: {}) + end + + it 'test text embedding' do + params = DocumentParameters.new + params.content_uri = 'http://google.com' + response = RosetteAPI.new('0123456789').get_text_embedding(params) + expect(response).instance_of? Hash + end + end + describe '.get_relationships' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/relationships') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/relationships') .with( body: @json, headers: { @@ -304,9 +409,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "relationships"}', headers: {}) @@ -324,7 +431,7 @@ name_translation_json = { name: 'معمر محمد أبو منيار القذاف', targetLanguage: 'eng', targetScript: 'Latn' }.to_json - stub_request(:post, 'https://api.rosette.com/rest/v1/name-translation') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/name-translation') .with( body: name_translation_json, headers: { @@ -332,15 +439,41 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' + } + ) + .to_return(status: 200, + body: '{"test": "name-translation"}', + headers: {}) + + name_translation_max_results_json = { name: 'معمر محمد أبو منيار القذاف', + targetLanguage: 'eng', + targetScript: 'Latn', + maximumResults: 5 }.to_json + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/name-translation') + .with( + body: name_translation_max_results_json, + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent, + 'X-BabelStreetAPI-Key' => '0123456789', + 'X-Rosetteapi-Binding' => 'ruby', + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "name-translation"}', headers: {}) end + it 'test name translation' do params = NameTranslationParameters.new('معمر محمد أبو منيار القذاف' .encode('UTF-8'), 'eng') @@ -349,6 +482,27 @@ expect(response).instance_of? Hash end + it 'test name translation with maximumResults' do + params = NameTranslationParameters.new( + 'معمر محمد أبو منيار القذاف'.encode('UTF-8'), + 'eng', + maximum_results: 5 + ) + params.target_script = 'Latn' + response = RosetteAPI.new('0123456789').get_name_translation(params) + expect(response).instance_of? Hash + end + + it 'badRequest: maximum_results must be greater than or equal to 0' do + params = NameTranslationParameters.new( + 'معمر محمد أبو منيار القذاف'.encode('UTF-8'), + 'eng', + maximum_results: -1 + ) + expect { RosetteAPI.new('0123456789').get_name_translation(params) } + .to raise_error(BadRequestError) + end + it 'badRequest: Expects NameTranslationParameters type as an argument' do params = NameSimilarityParameters.new('Michael Jackson', '迈克尔·杰克逊') expect { RosetteAPI.new('0123456789').get_name_translation(params) } @@ -358,19 +512,22 @@ describe '.name_similarity' do before do - name_similarity_json = { name1: 'Michael Jackson', - name2: '迈克尔·杰克逊' }.to_json - stub_request(:post, 'https://api.rosette.com/rest/v1/name-similarity') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/name-similarity') .with( - body: name_similarity_json, + body: hash_including( + name1: 'Michael Jackson', + name2: '迈克尔·杰克逊' + ), headers: { 'Accept' => 'application/json', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, @@ -383,6 +540,21 @@ expect(response).instance_of? Hash end + it 'sends parameters in the request body when provided' do + params = NameSimilarityParameters.new( + 'Michael Jackson', + '迈克尔·杰克逊', + { finalBias: '0.0003' } + ) + + RosetteAPI.new('0123456789').get_name_similarity(params) + + expect( + a_request(:post, 'https://analytics.babelstreet.com/rest/v1/name-similarity') + .with(body: hash_including(parameters: { finalBias: '0.0003' })) + ).to have_been_made.once + end + it 'badRequestFormat: name1 option can only be an instance of a String..' do params = NameSimilarityParameters.new(123, 'Michael Jackson') expect { RosetteAPI.new('0123456789').get_name_similarity(params) } @@ -409,7 +581,7 @@ before do names_json = { names: names.map(&:load_param), threshold: 0.75 }.to_json - stub_request(:post, 'https://api.rosette.com/rest/v1/name-deduplication') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/name-deduplication') .with( body: names_json, headers: { @@ -417,9 +589,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, @@ -428,7 +602,7 @@ nothresh_json = { names: names.map(&:load_param) }.to_json - stub_request(:post, 'https://api.rosette.com/rest/v1/name-deduplication') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/name-deduplication') .with( body: nothresh_json, headers: { @@ -436,9 +610,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, @@ -489,7 +665,7 @@ before do transliteration_json = { content: content }.to_json - stub_request(:post, 'https://api.rosette.com/rest/v1/transliteration') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/transliteration') .with( body: transliteration_json, headers: { @@ -497,9 +673,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, @@ -530,7 +708,7 @@ describe '.get_tokens' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/tokens') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/tokens') .with( body: @json, headers: { @@ -538,9 +716,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "tokens"}', headers: {}) @@ -555,7 +735,7 @@ describe '.get_topics' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/topics') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/topics') .with( body: @json, headers: { @@ -563,9 +743,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "topics"}', headers: {}) @@ -580,7 +762,7 @@ describe '.get_sentences' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/sentences') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/sentences') .with( body: @json, headers: { @@ -588,9 +770,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "sentences"}', headers: {}) @@ -605,13 +789,13 @@ describe '.info' do before do - stub_request(:get, 'https://api.rosette.com/rest/v1/info') + stub_request(:get, 'https://analytics.babelstreet.com/rest/v1/info') .with( headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789' + 'X-BabelStreetAPI-Key' => '0123456789' } ) .to_return(status: 200, body: '{"test": "info"}', headers: {}) @@ -624,13 +808,13 @@ describe '.ping' do before do - stub_request(:get, 'https://api.rosette.com/rest/v1/ping') + stub_request(:get, 'https://analytics.babelstreet.com/rest/v1/ping') .with( headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789' + 'X-BabelStreetAPI-Key' => '0123456789' } ) .to_return(status: 200, body: '{"test": "ping"}', headers: {}) @@ -643,7 +827,7 @@ describe '.get_language_custom_header' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/language') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/language') .with( body: @json, headers: { @@ -651,18 +835,87 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1', - 'X-RosetteApi-App' => 'ruby-app' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0', + 'X-RosetteAPI-App' => 'ruby-app' } ) .to_return(status: 200, body: '{"test": "language"}', headers: {}) end + it 'sends custom header with X-RosetteAPI- prefix' do + params = DocumentParameters.new + params.content = @content + params.custom_headers = { 'X-RosetteAPI-App' => 'ruby-app' } + + response = RosetteAPI.new('0123456789').get_language(params) + expect(response).instance_of? Hash + end + + it 'sends custom header with X-BabelStreetAPI- prefix' do + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/language') + .with( + body: @json, + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent, + 'X-BabelStreetAPI-Key' => '0123456789', + 'X-Rosetteapi-Binding' => 'ruby', + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-App' => 'ruby-app' + } + ) + .to_return(status: 200, body: '{"test": "language"}', headers: {}) + + params = DocumentParameters.new + params.content = @content + params.custom_headers = { 'X-BabelStreetAPI-App' => 'ruby-app' } + + response = RosetteAPI.new('0123456789').get_language(params) + expect(response).instance_of? Hash + end + + it 'sends custom headers with both prefixes together' do + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/language') + .with( + body: @json, + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent, + 'X-BabelStreetAPI-Key' => '0123456789', + 'X-Rosetteapi-Binding' => 'ruby', + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0', + 'X-RosetteAPI-App' => 'ruby-app', + 'X-BabelStreetAPI-App' => 'ruby-app' + } + ) + .to_return(status: 200, body: '{"test": "language"}', headers: {}) + + params = DocumentParameters.new + params.content = @content + params.custom_headers = { + 'X-RosetteAPI-App' => 'ruby-app', + 'X-BabelStreetAPI-App' => 'ruby-app' + } + + response = RosetteAPI.new('0123456789').get_language(params) + expect(response).instance_of? Hash + end + it 'test custom_headers is invalid' do params = DocumentParameters.new - params.content = 'Por favor Senorita, says the man.?' + params.content = @content params.custom_headers = { 'test' => 'ruby-app' } expect { RosetteAPI.new('0123456789').get_language(params) } .to raise_error(RosetteAPIError) @@ -671,13 +924,13 @@ describe '.error_409_incompatible_client_version' do before do - stub_request(:get, 'https://api.rosette.com/rest/v1/info') + stub_request(:get, 'https://analytics.babelstreet.com/rest/v1/info') .with( headers: { 'Accept' => '*/*', 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789' + 'X-BabelStreetAPI-Key' => '0123456789' } ) .to_return(status: 409, @@ -692,7 +945,7 @@ describe '.get_similar_terms' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/semantics/similar') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/semantics/similar') .with( body: @json, headers: { @@ -700,9 +953,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "language"}', headers: {}) @@ -719,7 +974,7 @@ describe '.get_semantic_vectors' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/semantics/vector') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/semantics/vector') .with( body: @json, headers: { @@ -727,9 +982,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "language"}', headers: {}) @@ -744,7 +1001,7 @@ describe '.get_syntax_dependencies' do before do - stub_request(:post, 'https://api.rosette.com/rest/v1/syntax/dependencies') + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/syntax/dependencies') .with( body: @json, headers: { @@ -752,9 +1009,11 @@ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type' => 'application/json', 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', + 'X-BabelStreetAPI-Key' => '0123456789', 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' } ) .to_return(status: 200, body: '{"test": "language"}', headers: {}) @@ -769,35 +1028,67 @@ describe '.address_similarity' do before do - address_similarity_json = { - address1: { - houseNumber: '1600', - road: 'Pennsylvania Ave NW', - city: 'Washington', - state: 'DC' - }, - address2: { - houseNumber: '1600', - road: 'Pennsilvana Avenue', - city: 'Washington', - state: 'D.C.' - } - }.to_json - stub_request(:post, 'https://api.rosette.com/rest/v1/address-similarity') - .with(body: address_similarity_json, - headers: { - 'Accept' => 'application/json', - 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', - 'Content-Type' => 'application/json', - 'User-Agent' => @user_agent, - 'X-Rosetteapi-Key' => '0123456789', - 'X-Rosetteapi-Binding' => 'ruby', - 'X-Rosetteapi-Binding-Version' => '1.27.1' - }) + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/address-similarity') + .with( + body: hash_including( + address1: { + houseNumber: '1600', + road: 'Pennsylvania Ave NW', + city: 'Washington', + state: 'DC' + }, + address2: { + houseNumber: '1600', + road: 'Pennsilvana Avenue', + city: 'Washington', + state: 'D.C.' + } + ), + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent, + 'X-BabelStreetAPI-Key' => '0123456789', + 'X-Rosetteapi-Binding' => 'ruby', + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' + } + ) .to_return(status: 200, body: '{"test": "address-similarity"}', headers: {}) end + + it 'sends parameters in the request body when provided' do + address1 = AddressParameter.new( + house_number: '1600', + road: 'Pennsylvania Ave NW', + city: 'Washington', + state: 'DC' + ) + address2 = AddressParameter.new( + house_number: '1600', + road: 'Pennsilvana Avenue', + city: 'Washington', + state: 'D.C.' + ) + + params = AddressSimilarityParameters.new( + address1, + address2, + { someOption: true } + ) + + RosetteAPI.new('0123456789').get_address_similarity(params) + + expect( + a_request(:post, 'https://analytics.babelstreet.com/rest/v1/address-similarity') + .with(body: hash_including(parameters: { someOption: true })) + ).to have_been_made.once + end + it 'test address similarity' do address1 = AddressParameter.new( house_number: '1600', @@ -849,4 +1140,132 @@ .to raise_error(BadRequestError) end end + + describe 'NameParameter gender' do + it 'serializes gender when valid' do + name = NameParameter.new('Alex Smith', gender: 'nonbinary') + expect(name.load_param).to include('gender' => 'nonbinary') + end + + it 'raises when gender is invalid' do + expect { NameParameter.new('Alex Smith', gender: 'unknown') } + .to raise_error(ArgumentError) + end + end + + describe '.get_record_similarity' do + before do + body = { + fields: { 'primaryName' => { type: 'rni_name', weight: 0.5 } }, + records: { left: [{ 'primaryName' => { text: 'Ethan R' } }], right: [{ 'primaryName' => { text: 'Seth R' } }] }, + properties: { threshold: 0.7 } + }.to_json + + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/record-similarity') + .with( + body: body, + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent, + 'X-BabelStreetAPI-Key' => '0123456789', + 'X-Rosetteapi-Binding' => 'ruby', + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' + } + ) + .to_return(status: 200, body: '{"test": "record-similarity"}', headers: {}) + end + + it 'test record similarity (minimal request with properties)' do + fields = { 'primaryName' => { type: 'rni_name', weight: 0.5 } } + records = { + left: [{ 'primaryName' => { text: 'Ethan R' } }], + right: [{ 'primaryName' => { text: 'Seth R' } }] + } + properties = { threshold: 0.7 } + + params = RecordSimilarityParameters.new(fields, records, properties) + response = RosetteAPI.new('0123456789').get_record_similarity(params) + expect(response).instance_of? Hash + end + + it 'test record similarity without properties' do + body = { + fields: { 'primaryName' => { type: 'rni_name', weight: 0.5 } }, + records: { left: [{ 'primaryName' => { text: 'Ethan R' } }], right: [{ 'primaryName' => { text: 'Seth R' } }] } + }.to_json + + stub_request(:post, 'https://analytics.babelstreet.com/rest/v1/record-similarity') + .with( + body: body, + headers: { + 'Accept' => 'application/json', + 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', + 'Content-Type' => 'application/json', + 'User-Agent' => @user_agent, + 'X-BabelStreetAPI-Key' => '0123456789', + 'X-Rosetteapi-Binding' => 'ruby', + 'X-BabelStreetAPI-Binding' => 'ruby', + 'X-Rosetteapi-Binding-Version' => '1.37.0', + 'X-BabelStreetAPI-Binding-Version' => '1.37.0' + } + ) + .to_return(status: 200, body: '{"test": "record-similarity"}', headers: {}) + + fields = { 'primaryName' => { type: 'rni_name', weight: 0.5 } } + records = { + left: [{ 'primaryName' => { text: 'Ethan R' } }], + right: [{ 'primaryName' => { text: 'Seth R' } }] + } + + params = RecordSimilarityParameters.new(fields, records) + response = RosetteAPI.new('0123456789').get_record_similarity(params) + expect(response).instance_of? Hash + end + + it 'badRequest: fields is required' do + params = RecordSimilarityParameters.new(nil, { left: [{}], right: [{}] }, { threshold: 0.7 }) + expect { RosetteAPI.new('0123456789').get_record_similarity(params) } + .to raise_error(BadRequestError) + end + + it 'badRequest: fields must be a Hash' do + params = RecordSimilarityParameters.new(['not-a-hash'], { left: [{}], right: [{}] }, { threshold: 0.7 }) + expect { RosetteAPI.new('0123456789').get_record_similarity(params) } + .to raise_error(BadRequestError) + end + + it 'badRequest: fields must not be empty' do + params = RecordSimilarityParameters.new({}, { left: [{}], right: [{}] }, { threshold: 0.7 }) + expect { RosetteAPI.new('0123456789').get_record_similarity(params) } + .to raise_error(BadRequestError) + end + + it 'badRequest: records is required' do + params = RecordSimilarityParameters.new({ 'primaryName' => {} }, nil, { threshold: 0.7 }) + expect { RosetteAPI.new('0123456789').get_record_similarity(params) } + .to raise_error(BadRequestError) + end + + it 'badRequest: records must be a Hash' do + params = RecordSimilarityParameters.new({ 'primaryName' => {} }, ['not-a-hash'], { threshold: 0.7 }) + expect { RosetteAPI.new('0123456789').get_record_similarity(params) } + .to raise_error(BadRequestError) + end + + it 'badRequest: records must not be empty' do + params = RecordSimilarityParameters.new({ 'primaryName' => {} }, {}, { threshold: 0.7 }) + expect { RosetteAPI.new('0123456789').get_record_similarity(params) } + .to raise_error(BadRequestError) + end + + it 'badRequest: properties must be a Hash when provided' do + params = RecordSimilarityParameters.new({ 'primaryName' => {} }, { left: [{}], right: [{}] }, 'nope') + expect { RosetteAPI.new('0123456789').get_record_similarity(params) } + .to raise_error(BadRequestError) + end + end end