lib/html2rss/item_extractors.rb in html2rss-0.9.0 vs lib/html2rss/item_extractors.rb in html2rss-0.10.0
- old
+ new
@@ -1,23 +1,88 @@
+# frozen_string_literal: true
+
module Html2rss
##
# Provides a namespace for item extractors.
module ItemExtractors
- DEFAULT = 'text'.freeze
- private_constant :DEFAULT
+ ##
+ # The Error class to be thrown when an unknown extractor name is requested.
+ class UnknownExtractorName < StandardError; end
- def self.get_extractor(name)
- @get_extractor ||= Hash.new do |extractors, key|
- extractors[key] = Utils.get_class_from_name(key || DEFAULT, 'ItemExtractors')
- end
+ ##
+ # Maps the extractor name to the class implementing the extractor.
+ #
+ # The key is the name to use in the feed config.
+ NAME_TO_CLASS = {
+ attribute: Attribute,
+ href: Href,
+ html: Html,
+ static: Static,
+ text: Text
+ }.freeze
- @get_extractor[name]
+ ##
+ # Maps the extractor class to its corresponding options class.
+ ITEM_OPTION_CLASSES = Hash.new do |hash, klass|
+ hash[klass] = klass.const_get(:Options)
end
+ DEFAULT_EXTRACTOR = :text
+
##
- # @return [Nokogiri::XML::Element]
- def self.element(xml, options)
- selector = options[:selector]
+ # Retrieves an element from Nokogiri XML based on the selector.
+ #
+ # @param xml [Nokogiri::XML::Document]
+ # @param selector [String, nil]
+ # @return [Nokogiri::XML::ElementSet] selected XML elements
+ def self.element(xml, selector)
selector ? xml.css(selector) : xml
+ end
+
+ ##
+ # Creates an instance of the requested item extractor.
+ #
+ # @param attribute_options [Hash<Symbol, Object>]
+ # Should contain at least `:extractor` (the name) and required options for that extractor.
+ # @param xml [Nokogiri::XML::Document]
+ # @return [Object] instance of the specified item extractor class
+ def self.item_extractor_factory(attribute_options, xml)
+ extractor_name = attribute_options[:extractor]&.to_sym || DEFAULT_EXTRACTOR
+ extractor_class = find_extractor_class(extractor_name)
+ options_instance = build_options_instance(extractor_class, attribute_options)
+ create_extractor_instance(extractor_class, xml, options_instance)
+ end
+
+ ##
+ # Finds the extractor class based on the name.
+ #
+ # @param extractor_name [Symbol] the name of the extractor
+ # @return [Class] the class implementing the extractor
+ # @raise [UnknownExtractorName] if the extractor class is not found
+ def self.find_extractor_class(extractor_name)
+ NAME_TO_CLASS[extractor_name] || raise(UnknownExtractorName,
+ "Unknown extractor name '#{extractor_name}' requested in NAME_TO_CLASS")
+ end
+
+ ##
+ # Builds the options instance for the extractor class.
+ #
+ # @param extractor_class [Class] the class implementing the extractor
+ # @param attribute_options [Hash<Symbol, Object>] the attribute options
+ # @return [Object] an instance of the options class for the extractor
+ def self.build_options_instance(extractor_class, attribute_options)
+ options = attribute_options.slice(*extractor_class::Options.members)
+ ITEM_OPTION_CLASSES[extractor_class].new(options)
+ end
+
+ ##
+ # Creates an instance of the extractor class.
+ #
+ # @param extractor_class [Class] the class implementing the extractor
+ # @param xml [Nokogiri::XML::Document] the XML document
+ # @param options_instance [Object] the options instance
+ # @return [Object] an instance of the extractor class
+ def self.create_extractor_instance(extractor_class, xml, options_instance)
+ extractor_class.new(xml, options_instance)
end
end
end