Class: SimpleRSS
- Inherits:
-
Object
- Object
- SimpleRSS
- Includes:
- Enumerable
- Defined in:
- lib/simple-rss.rb,
lib/simple-rss/request_errors.rb
Overview
rbs_inline: enabled
Defined Under Namespace
Classes: Discovery, DiscoveryDependencyError, DiscoveryError, EntryNormalizer, HTTPClient, HTTPError, JsonEntryNormalizer, JsonFeed, NormalizedEntry, PolicyError, RedirectError, RequestError, RequestPolicy, RequestTimeout, ResponseTooLarge, XmlElement
Constant Summary collapse
- VERSION =
@rbs! include Enumerable[Hash[Symbol, untyped]]
"2.3.0".freeze
- DATE_TAGS =
%i[pubDate lastBuildDate published updated expirationDate modified dc:date].freeze
- STRIP_HTML_TAGS =
%i[author contributor skipHours skipDays].freeze
- ATOM_NAMESPACE =
"http://www.w3.org/2005/Atom".freeze
- RSS_NAMESPACES =
[nil, "", "http://purl.org/rss/1.0/", "http://my.netscape.com/rdf/simple/0.9/"].freeze
- XML_TAG_PATTERN =
%r{<!--.*?-->|<!\[CDATA\[.*?\]\]>|<\?.*?\?>|<(/?)([\w:.-]+)((?:[^<>"']|"[^"]*"|'[^']*')*)>}m%i[ id title subtitle link description author webMaster managingEditor contributor pubDate lastBuildDate updated dc:date generator language docs cloud ttl skipHours skipDays image logo icon rating rights copyright textInput feedburner:browserFriendly itunes:author itunes:category ]
%i[ id title link link+alternate link+self link+edit link+replies author contributor description summary content content:encoded comments pubDate published updated expirationDate modified dc:date category guid trackback:ping trackback:about dc:creator dc:title dc:subject dc:rights dc:publisher feedburner:origLink media:content#url media:content#type media:content#height media:content#width media:content#duration media:title media:thumbnail#url media:thumbnail#height media:thumbnail#width media:credit media:credit#role media:category media:category#scheme media:description enclosure#url enclosure#type enclosure#length itunes:duration itunes:image#href ]
Instance Attribute Summary collapse
-
#authors ⇒ Object
readonly
: untyped.
-
#etag ⇒ Object
readonly
: String?.
-
#expired ⇒ Object
readonly
: bool?.
-
#favicon ⇒ Object
readonly
: String?.
-
#feed_url ⇒ Object
readonly
: String?.
-
#home_page_url ⇒ Object
readonly
: String?.
-
#hubs ⇒ Object
readonly
: untyped.
-
#items ⇒ Object
(also: #entries)
readonly
Returns the value of attribute items.
-
#last_modified ⇒ Object
readonly
: String?.
-
#next_url ⇒ Object
readonly
: String?.
-
#raw_json ⇒ Object
readonly
: Hash[String, untyped]?.
-
#source ⇒ Object
readonly
: String.
-
#source_url ⇒ Object
readonly
: String?.
-
#user_comment ⇒ Object
readonly
: String?.
Class Method Summary collapse
- .discover(url, options = {}) ⇒ Object
- .feed_tags ⇒ Object
- .feed_tags=(ft) ⇒ Object
-
.fetch(url, options = {}) ⇒ Object
Fetch and parse a feed from a URL Returns nil if conditional GET returns 304 Not Modified.
- .item_tags ⇒ Object
- .item_tags=(it) ⇒ Object
- .merge(*feeds) ⇒ Object
-
.parse(source, options = {}) ⇒ Object
The strict attribute is for compatibility with Ruby's standard RSS parser.
- .valid?(source, options = {}) ⇒ Boolean
Instance Method Summary collapse
-
#[](index) ⇒ Object
Access an item by index.
- #as_json(_options = {}) ⇒ Object (also: #to_hash)
- #channel ⇒ Object (also: #feed)
- #dedupe ⇒ Object
- #diff(other) ⇒ Object
-
#each(&block) ⇒ Object
Iterate over all items in the feed.
- #enclosures ⇒ Object
- #feed_type ⇒ Object
- #images ⇒ Object
-
#initialize(source, options = {}) ⇒ SimpleRSS
constructor
A new instance of SimpleRSS.
- #items_by_category(name) ⇒ Object
- #items_since(time) ⇒ Object
-
#latest(count = 10) ⇒ Object
Get the n most recent items, sorted by date.
- #merge(*feeds) ⇒ Object
- #normalized_entries(source_url: nil, mappings: {}) ⇒ Object
- #search(query) ⇒ Object
- #to_json ⇒ Object
- #to_xml(format: :rss2) ⇒ Object
- #valid? ⇒ Boolean
Constructor Details
#initialize(source, options = {}) ⇒ SimpleRSS
Returns a new instance of SimpleRSS.
68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/simple-rss.rb', line 68 def initialize(source, = {}) @source = source.respond_to?(:read) ? source.read.to_s : source.to_s @items = [] #: Array[Hash[Symbol, untyped]] @options = {} #: Hash[Symbol, untyped] @options.update() @source_url = [:source_url] @json_feed = nil @raw_json = nil @entry_contexts = {} #: Hash[Hash[Symbol, untyped], Hash[Symbol, untyped]] @entry_contexts.compare_by_identity parse end |
Instance Attribute Details
#authors ⇒ Object (readonly)
: untyped
30 31 32 |
# File 'lib/simple-rss.rb', line 30 def @authors end |
#etag ⇒ Object (readonly)
: String?
25 26 27 |
# File 'lib/simple-rss.rb', line 25 def etag @etag end |
#expired ⇒ Object (readonly)
: bool?
31 32 33 |
# File 'lib/simple-rss.rb', line 31 def expired @expired end |
#favicon ⇒ Object (readonly)
: String?
29 30 31 |
# File 'lib/simple-rss.rb', line 29 def favicon @favicon end |
#feed_url ⇒ Object (readonly)
: String?
29 30 31 |
# File 'lib/simple-rss.rb', line 29 def feed_url @feed_url end |
#home_page_url ⇒ Object (readonly)
: String?
29 30 31 |
# File 'lib/simple-rss.rb', line 29 def home_page_url @home_page_url end |
#hubs ⇒ Object (readonly)
: untyped
30 31 32 |
# File 'lib/simple-rss.rb', line 30 def hubs @hubs end |
#items ⇒ Object (readonly) Also known as: entries
Returns the value of attribute items.
23 24 25 |
# File 'lib/simple-rss.rb', line 23 def items @items end |
#last_modified ⇒ Object (readonly)
: String?
26 27 28 |
# File 'lib/simple-rss.rb', line 26 def last_modified @last_modified end |
#next_url ⇒ Object (readonly)
: String?
29 30 31 |
# File 'lib/simple-rss.rb', line 29 def next_url @next_url end |
#raw_json ⇒ Object (readonly)
: Hash[String, untyped]?
28 29 30 |
# File 'lib/simple-rss.rb', line 28 def raw_json @raw_json end |
#source ⇒ Object (readonly)
: String
24 25 26 |
# File 'lib/simple-rss.rb', line 24 def source @source end |
#source_url ⇒ Object (readonly)
: String?
27 28 29 |
# File 'lib/simple-rss.rb', line 27 def source_url @source_url end |
#user_comment ⇒ Object (readonly)
: String?
29 30 31 |
# File 'lib/simple-rss.rb', line 29 def user_comment @user_comment end |
Class Method Details
.discover(url, options = {}) ⇒ Object
332 333 334 335 |
# File 'lib/simple-rss.rb', line 332 def discover(url, = {}) require_relative "simple-rss/discovery" Discovery.new().discover(url) end |
.feed_tags ⇒ Object
267 268 269 |
# File 'lib/simple-rss.rb', line 267 def @@feed_tags end |
.feed_tags=(ft) ⇒ Object
272 273 274 |
# File 'lib/simple-rss.rb', line 272 def (ft) @@feed_tags = ft end |
.fetch(url, options = {}) ⇒ Object
Fetch and parse a feed from a URL Returns nil if conditional GET returns 304 Not Modified
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
# File 'lib/simple-rss.rb', line 313 def fetch(url, = {}) require "net/http" require "uri" require_relative "simple-rss/http_client" response, final_uri = HTTPClient.new().get(url) return nil if response.is_a?(Net::HTTPNotModified) raise SimpleRSSError, "HTTP #{response.code}: #{response.}" unless response.is_a?(Net::HTTPSuccess) body = (response.body || "").force_encoding(Encoding::UTF_8) feed = parse(body, .merge(source_url: final_uri.to_s)) feed.instance_variable_set(:@etag, response["ETag"]) feed.instance_variable_set(:@last_modified, response["Last-Modified"]) feed end |
.item_tags ⇒ Object
277 278 279 |
# File 'lib/simple-rss.rb', line 277 def @@item_tags end |
.item_tags=(it) ⇒ Object
282 283 284 |
# File 'lib/simple-rss.rb', line 282 def (it) @@item_tags = it end |
.merge(*feeds) ⇒ Object
302 303 304 305 306 307 |
# File 'lib/simple-rss.rb', line 302 def merge(*feeds) first_feed = feeds.first return [] if first_feed.nil? first_feed.merge(*feeds.drop(1)) end |
.parse(source, options = {}) ⇒ Object
The strict attribute is for compatibility with Ruby's standard RSS parser
289 290 291 |
# File 'lib/simple-rss.rb', line 289 def parse(source, = {}) new source, end |
.valid?(source, options = {}) ⇒ Boolean
294 295 296 297 298 299 |
# File 'lib/simple-rss.rb', line 294 def valid?(source, = {}) parse(source, ) true rescue StandardError false end |
Instance Method Details
#[](index) ⇒ Object
Access an item by index
118 119 120 |
# File 'lib/simple-rss.rb', line 118 def [](index) items[index] end |
#as_json(_options = {}) ⇒ Object Also known as: to_hash
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 |
# File 'lib/simple-rss.rb', line 229 def as_json( = {}) raw_json = @raw_json hash = raw_json ? raw_json.transform_keys(&:to_sym) : {} #: Hash[Symbol, untyped] @@feed_tags.each do |tag| tag_cleaned = clean_tag(tag) value = instance_variable_get("@#{tag_cleaned}") hash[tag_cleaned] = serialize_value(value) if value end hash[:items] = items.map do |item| item.transform_values { |v| serialize_value(v) } end hash end |
#channel ⇒ Object Also known as: feed
83 84 85 |
# File 'lib/simple-rss.rb', line 83 def channel self end |
#dedupe ⇒ Object
203 204 205 206 |
# File 'lib/simple-rss.rb', line 203 def dedupe @items = dedupe_items(items) self end |
#diff(other) ⇒ Object
192 193 194 195 196 197 198 199 200 |
# File 'lib/simple-rss.rb', line 192 def diff(other) other_keys = keyed_item_set(other.items) current_keys = keyed_item_set(items) { added: select_new_keyed_items(other.items, current_keys), removed: select_new_keyed_items(items, other_keys) } end |
#each(&block) ⇒ Object
Iterate over all items in the feed
108 109 110 111 112 113 |
# File 'lib/simple-rss.rb', line 108 def each(&block) return enum_for(:each) unless block items.each(&block) self end |
#enclosures ⇒ Object
209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/simple-rss.rb', line 209 def enclosures items.filter_map do |item| enclosure_url = item[:enclosure_url] next if blank_value?(enclosure_url) { url: enclosure_url, type: item[:enclosure_type], length: item[:enclosure_length], item: item } end end |
#feed_type ⇒ Object
130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/simple-rss.rb', line 130 def feed_type return :json_feed if @json_feed atom_namespaced_feed = source.match?(/<(atom:)?feed\b[^>]*xmlns(:\w+)?=['"][^'"]*atom/i) return :atom if atom_namespaced_feed return :rss2 if source.match?(/<rss[^>]*version=['"]2/i) return :rss1 if source.match?(/<rdf:RDF/i) return :rss09 if source.match?(/<rss[^>]*version=['"]0\.9/i) :unknown end |
#images ⇒ Object
224 225 226 |
# File 'lib/simple-rss.rb', line 224 def images items.flat_map { |item| item_image_urls(item) }.uniq end |
#items_by_category(name) ⇒ Object
164 165 166 167 168 169 170 171 172 173 |
# File 'lib/simple-rss.rb', line 164 def items_by_category(name) query = name.to_s.downcase items.select do |item| category = item[:category] next false if category.nil? category_matches_query?(category, query) end end |
#items_since(time) ⇒ Object
156 157 158 159 160 161 |
# File 'lib/simple-rss.rb', line 156 def items_since(time) items.select do |item| date = item_date(item) date && date > time end end |
#latest(count = 10) ⇒ Object
Get the n most recent items, sorted by date
125 126 127 |
# File 'lib/simple-rss.rb', line 125 def latest(count = 10) sorted_items_by_date(items).first(count) end |
#merge(*feeds) ⇒ Object
185 186 187 188 189 |
# File 'lib/simple-rss.rb', line 185 def merge(*feeds) all_items = [items, *feeds.map(&:items)].flatten keyed_items, unkeyed_items = all_items.partition { |item| !item_key(item).nil? } dedupe_items(sorted_items_by_date(keyed_items) + unkeyed_items) end |
#normalized_entries(source_url: nil, mappings: {}) ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/simple-rss.rb', line 89 def normalized_entries(source_url: nil, mappings: {}) json_feed = @json_feed raise ArgumentError, "XML mappings are not supported for JSON Feed" if json_feed && !mappings.empty? return items.map { |item| json_feed.normalized_entry(item, source_url: source_url || @source_url) } if json_feed EntryNormalizer.validate_mappings(mappings) = items.map do |item| context = @entry_contexts[item] || raise(SimpleRSSError, "Cannot normalize an item without its original XML source") element = XmlElement.new(context[:name], context[:attributes], context[:content], context[:parent]) EntryNormalizer.new(element, item, source_url: source_url || @source_url, mappings: mappings, raw_xml: context[:xml], feed_authors: ).entry end end |
#search(query) ⇒ Object
176 177 178 179 180 181 182 |
# File 'lib/simple-rss.rb', line 176 def search(query) pattern = Regexp.new(Regexp.escape(query.to_s), Regexp::IGNORECASE) items.select do |item| searchable_fields(item).any? { |field| field.to_s.match?(pattern) } end end |
#to_json ⇒ Object
247 248 249 250 |
# File 'lib/simple-rss.rb', line 247 def to_json(*) require "json" JSON.generate(as_json) end |
#to_xml(format: :rss2) ⇒ Object
255 256 257 258 259 260 261 262 263 |
# File 'lib/simple-rss.rb', line 255 def to_xml(format: :rss2) raise SimpleRSSError, "JSON Feed to XML conversion is not supported" if @json_feed case format when :rss2 then to_rss2_xml when :atom then to_atom_xml else raise ArgumentError, "Unknown format: #{format}. Supported: :rss2, :atom" end end |
#valid? ⇒ Boolean
143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/simple-rss.rb', line 143 def valid? return true if @json_feed return false if items.empty? title_value = instance_variable_get(:@title) link_value = instance_variable_get(:@link) return true if title_value || link_value false end |