class RIXML

rubocop:disable Metrics/ClassLength

Public Class Methods

new(data) click to toggle source
# File lib/rixml.rb, line 17
def initialize(data)
  @data = data
  @document = Nokogiri::XML(data)
  @attrs = Hash.from_xml(@document.root.to_s)
  @document.remove_namespaces!
end
parse_from_file(filename) click to toggle source
# File lib/rixml.rb, line 12
def parse_from_file(filename)
  RIXML.new(File.read(filename))
end

Public Instance Methods

asset_classes() click to toggle source
# File lib/rixml.rb, line 79
def asset_classes
  assets = @attrs.dig('Research', 'Product', 'Source', 'Organization', 'Expertise', 'AssetClasses', 'AssetClass')
  assets = [assets] unless assets.is_a?(Array)

  assets.collect do |asset|
    asset&.dig('assetClass')
  end.compact
end
authors() click to toggle source
# File lib/rixml.rb, line 56
def authors
  org = @attrs.dig('Research', 'Product', 'Source', 'Organization') || {}
  if org.is_a?(Array)
    org = org.find { |v| v['primaryIndicator'] == 'Yes' } || org.first
  end
  authors = org.dig('PersonGroup', 'PersonGroupMember') || []
  authors = [authors] unless authors.is_a?(Array)

  authors.map { |author| parse_info_from_author(author) }
end
context() click to toggle source
# File lib/rixml.rb, line 88
def context
  context = @attrs.dig('Research', 'Product', 'Context') || {}
  {
    companies: parse_companies_from_context(context),
    sectors: parse_sectors_from_context(context),
    countries: parse_countries_from_context(context),
    category: parse_product_category_from_context(context),
    publication_date: parse_publication_date_from_context(context),
  }
end
product_id() click to toggle source
# File lib/rixml.rb, line 28
def product_id
  @attrs.dig('Research', 'Product', 'productID')
end
publication_date() click to toggle source

@deprecated Please use {#status_info} instead

# File lib/rixml.rb, line 51
def publication_date
  time_str = current_status_info&.dig('statusDateTime') || DateTime.now.to_s
  Time.parse(time_str).to_datetime.to_s
end
report_info() click to toggle source
# File lib/rixml.rb, line 67
def report_info
  content = @attrs.dig('Research', 'Product', 'Content')
  {
    title: content['Title'],
    subtitle: content['SubTitle'],
    abstract: content['Abstract'],
    synopsis: content['Synopsis'],
    file_name: content['Resource']&.dig('Name'),
    pages: resource_length(content['Resource']),
  }
end
research() click to toggle source
# File lib/rixml.rb, line 24
def research
  @rixml_document ||= RixmlDocument.parse(@data)
end
research_id() click to toggle source
# File lib/rixml.rb, line 32
def research_id
  @attrs.dig('Research', 'researchID')
end
status() click to toggle source

@deprecated Please use {#status_info} instead

# File lib/rixml.rb, line 37
def status
  current_status_info&.dig('statusType')&.downcase&.to_sym || :published
end
status_info() click to toggle source
# File lib/rixml.rb, line 41
def status_info
  time_str = current_status_info&.dig('statusDateTime') || DateTime.now.to_s
  status = current_status_info&.dig('statusType')&.downcase&.to_sym || :published
  {
    status_type: status,
    status_date_time: Time.parse(time_str).to_datetime.to_s,
  }
end
xpath(path) click to toggle source
# File lib/rixml.rb, line 99
def xpath(path)
  @document.xpath(path)
end

Private Instance Methods

current_status_info() click to toggle source
# File lib/rixml.rb, line 105
def current_status_info
  info = @attrs.dig('Research', 'Product', 'StatusInfo')
  info = [info] unless info.is_a?(Array)
  info.find { |status| status&.dig('currentStatusIndicator')&.downcase == 'yes' } || info.first
end
parse_author_contact_phone(phone) click to toggle source
# File lib/rixml.rb, line 145
def parse_author_contact_phone(phone)
  [phone['CountryCode'], phone['Number']].join(' ') if phone
end
parse_author_contacts(contacts) click to toggle source
# File lib/rixml.rb, line 134
def parse_author_contacts(contacts)
  contacts = [contacts] unless contacts.is_a?(Array)

  contacts.map do |contact|
    {
      email: contact&.dig('Email')&.downcase,
      phone: parse_author_contact_phone(contact&.dig('Phone')),
    }
  end
end
parse_companies_from_context(context) click to toggle source
# File lib/rixml.rb, line 164
def parse_companies_from_context(context)
  companies = []
  [context['IssuerDetails']].flatten.compact.each do |issuer|
    [issuer['Issuer']].flatten.compact.select { |c| c['issuerType'] == 'Corporate' }.each do |company|
      companies << parse_company_info(company)
    end
  end
  companies.flatten
end
parse_company_info(company) click to toggle source
# File lib/rixml.rb, line 184
def parse_company_info(company)
  securities = company.dig('SecurityDetails', 'Security')
  securities = [securities].compact unless securities.is_a?(Array)
  securities.map do |security|
    info = { name: (company.dig('IssuerName') || {})['NameValue'], primary: company['primaryIndicator'] == 'Yes' }
    info = info.merge(parse_security_info(security))
    info.merge(securities: parse_securities(security)) # Keep retrocompatibility adding a new key 'securities'
  end
end
parse_countries_from_context(context) click to toggle source
# File lib/rixml.rb, line 158
def parse_countries_from_context(context)
  [context['ProductClassifications']&.dig('Country')].flatten.compact.map do |country|
    { code: country['code'].upcase }
  end
end
parse_info_from_author(author) click to toggle source
# File lib/rixml.rb, line 116
def parse_info_from_author(author)
  person = author&.dig('Person')
  {
    primary: primary?(author.dig('primaryIndicator')),
    name: person['DisplayName'],
    first_name: person['GivenName'],
    middle_name: person['MiddleName'],
    last_name: person['FamilyName'],
    job_title: person['JobTitle'],
    email: person['ContactInfo']&.dig('Email')&.downcase, # TODO: Remove: Use email from contacts
    contacts: parse_author_contacts(person['ContactInfo']),
  }
end
parse_product_category_from_context(context) click to toggle source
# File lib/rixml.rb, line 174
def parse_product_category_from_context(context)
  product_category = context.dig('ProductDetails', 'ProductCategory')
  return product_category['productCategory'] if product_category.is_a?(Hash)
  product_category
end
parse_publication_date_from_context(context) click to toggle source
# File lib/rixml.rb, line 180
def parse_publication_date_from_context(context)
  context.dig('ProductDetails', 'publicationDateTime')
end
parse_sectors_from_context(context) click to toggle source
# File lib/rixml.rb, line 149
def parse_sectors_from_context(context)
  list = context['ProductClassifications'].try(:[], 'SectorIndustry')
  return [] if list.nil?
  list = [list] unless list.is_a?(Array)
  list.select { |s| s['classificationType'] == 'GICS' }.map do |v|
    { code: v['code'].to_i, focus: v['focusLevel'].try(:downcase) == 'yes' }
  end
end
parse_securities(security) click to toggle source
# File lib/rixml.rb, line 202
def parse_securities(security)
  security_ids = security.dig('SecurityID')
  security_ids = [security_ids].compact unless security_ids.is_a?(Array)
  security_ids&.map do |security_id|
    {
      primary: primary?(security.dig('primaryIndicator')),
      security_id['idType'].underscore.to_sym => security_id['idValue'],
    }
  end
end
parse_security_info(security) click to toggle source
# File lib/rixml.rb, line 194
def parse_security_info(security)
  security_ids = security.dig('SecurityID')
  security_ids = [security_ids].compact unless security_ids.is_a?(Array)
  security_ids&.map do |security_id|
    { security_id['idType'].underscore.to_sym => security_id['idValue'] }
  end&.reduce({}, :merge) || []
end
primary?(primary_indicator) click to toggle source
# File lib/rixml.rb, line 130
def primary?(primary_indicator)
  primary_indicator == 'Yes'
end
resource_length(resource) click to toggle source
# File lib/rixml.rb, line 111
def resource_length(resource)
  length = resource&.dig('Length')
  return length.to_i if length.respond_to?(:to_i)
end