rssly 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3e7668f11f0cec7ba5f1da6674e516a46df57bef
4
+ data.tar.gz: 4969418e2ef5a9d8e55433988a02b8342bc1ee41
5
+ SHA512:
6
+ metadata.gz: 788e43bd09c3f51e61a7693efaf292ffe434979444b543828ded0141390fde2273ba61d4396033c38b8785c7ccb41837c349649609c4d5d06c2375ce2e460f21
7
+ data.tar.gz: ae3af50267214d349159fb09a9412779ef81f2b05a5d5fbbb6b1a265dc0473c10d44032eee981a9c8ab5c5a3be068b99b930c113d1868119a37da15c664a1654
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1.1
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rssly.gemspec
4
+ gemspec
5
+
6
+ gem 'activesupport'
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Nathan Kot
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # Rssly
2
+
3
+ A tool for serializing multiple RSS feeds into different formats.
4
+
5
+ Design-wise, this gem is responsible for:
6
+
7
+ - Encapsulating RSS Feed URL's
8
+ - Creating a collection of articles from either Feed URL's or persisted data
9
+ - Filtering that collection of articles
10
+ - Sorting that collection of articles
11
+ - Transforming the collection of articles into different formats
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ gem 'rssly'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install rssly
26
+
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/rssly ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ # vim: set ft=ruby:
3
+ require 'rssly/cli'
4
+ Rssly::CLI.start
@@ -0,0 +1,79 @@
1
+ require 'addressable/uri'
2
+ require 'readability'
3
+ require 'open-uri'
4
+ require 'sanitize'
5
+ require 'ots'
6
+
7
+ module Rssly
8
+ # Represents a single rss article
9
+ class Article
10
+ class << self
11
+ def create_from_feedjira_entry(entry)
12
+ new(title: entry.title, url: entry.url, published: entry.published)
13
+ end
14
+ end
15
+
16
+ SUMMARY_RATIO = 35
17
+
18
+ attr_accessor :title
19
+ attr_accessor :url
20
+ attr_accessor :summary
21
+ attr_accessor :topics
22
+ attr_accessor :published
23
+
24
+ def initialize(
25
+ title: nil,
26
+ url: nil,
27
+ published: nil,
28
+ summary: nil,
29
+ topics: nil
30
+ )
31
+ self.title = title
32
+ self.url = url
33
+ self.published = published
34
+ self.summary = summary
35
+ self.topics = topics
36
+ end
37
+
38
+ def title
39
+ @title ||= extracted.title
40
+ end
41
+
42
+ def summary
43
+ @summary ||= summarized.summarize(
44
+ percent: SUMMARY_RATIO
45
+ ).reduce('') do |text, o|
46
+ text << o[:sentence].strip + ' '
47
+ end.strip
48
+ end
49
+
50
+ def topics
51
+ @topics ||= summarized.topics
52
+ end
53
+
54
+ def url=(url)
55
+ normalized = Addressable::URI.parse(url).normalize
56
+ @url = normalized.scheme + '://' + normalized.host + normalized.path
57
+ end
58
+
59
+ def published
60
+ @published ||= Time.now
61
+ end
62
+
63
+ private
64
+
65
+ def summarized
66
+ @summarized ||= begin
67
+ text = Sanitize.clean(extracted.content)
68
+ OTS.parse(text)
69
+ end
70
+ end
71
+
72
+ def extracted
73
+ @extracted ||= begin
74
+ source = open(url).read
75
+ Readability::Document.new(source)
76
+ end
77
+ end
78
+ end
79
+ end
data/lib/rssly/cli.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'thor'
2
+ require 'rssly'
3
+
4
+ module Rssly
5
+ # The rssly CLI
6
+ class CLI < Thor
7
+ desc 'fetch URL1 URL2', 'Fetch feeds and output them in a given format.'
8
+
9
+ option :format, default: 'text', desc: <<-EOT
10
+ Choose from one of the following serializers:
11
+
12
+ `text` : Output articles in a simple text layout.
13
+ `html` : Output articles in an html format.
14
+ EOT
15
+
16
+ def fetch(*feed_urls)
17
+ feeds = feed_urls.map do |url|
18
+ Rssly::Feed.new url: url
19
+ end
20
+
21
+ collection = Rssly::Collection.create_from_feeds(*feeds)
22
+
23
+ serializer = case options[:format]
24
+ when 'text' then Rssly::Serializers::Text
25
+ when 'html' then Rssly::Serializers::HTML
26
+ else fail "Serializer #{options[:format]} not found."
27
+ end
28
+
29
+ puts serializer.new(collection).perform
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module Rssly
2
+ class Collection
3
+ # Filters articles out by age
4
+ module AgeFilter
5
+ def self.parse(articles, min: nil, max: nil)
6
+ articles.select do |article|
7
+ if min && article.published < min then false
8
+ elsif max && article.published > max then false
9
+ else true
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ require 'bloomfilter-rb'
2
+
3
+ module Rssly
4
+ class Collection
5
+ # Filters out any articles that have the same url in the set.
6
+ module UniqueFilter
7
+ def self.parse(articles, **args)
8
+ bf = BloomFilter::Redis.new(
9
+ size: 10000
10
+ )
11
+
12
+ articles.select do |article|
13
+ unless bf.include?(article.url)
14
+ bf.insert article.url
15
+ true
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ module Rssly
2
+ # Represents a collection of articles
3
+ class Collection
4
+ class << self
5
+ def create_from_feeds(*feeds)
6
+ instance = new(
7
+ feeds.map { |f| f.articles }.flatten
8
+ )
9
+
10
+ instance.filter(UniqueFilter)
11
+ instance
12
+ end
13
+ end
14
+
15
+ attr_accessor :articles
16
+
17
+ def initialize(items)
18
+ self.articles = items
19
+ end
20
+
21
+ def each(&block)
22
+ articles.each(&block)
23
+ end
24
+
25
+ def length
26
+ articles.length
27
+ end
28
+
29
+ def articles
30
+ @articles ||= []
31
+ end
32
+
33
+ def filter(filter, **opts)
34
+ self.articles = filter.parse(articles, **opts)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ module Rssly
2
+ module Deserializers
3
+
4
+ end
5
+ end
data/lib/rssly/feed.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'feedjira'
2
+
3
+ module Rssly
4
+ # Represents a single rss feed and it's metadata
5
+ class Feed
6
+ class << self
7
+ end
8
+
9
+ attr_accessor :url
10
+ attr_accessor :title
11
+ attr_accessor :articles
12
+
13
+ def initialize(title: nil, url: nil)
14
+ self.url = url
15
+ self.title = title
16
+ end
17
+
18
+ def articles
19
+ @articles ||= fetch_articles
20
+ end
21
+
22
+ private
23
+
24
+ def fetch_articles
25
+ result = Feedjira::Feed.fetch_and_parse @url
26
+ self.title = result.title
27
+ result.entries.map do |obj|
28
+ Article.create_from_feedjira_entry(obj)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,56 @@
1
+ module Rssly
2
+ module Serializers
3
+ # The base serializer class
4
+ class Serializer
5
+ def initialize(collection)
6
+ @collection = collection
7
+ end
8
+
9
+ def perform
10
+ fail 'Serializer#perform must be implemented'
11
+ end
12
+ end
13
+
14
+ # Transforms a collection into a text representation
15
+ class Text < Serializer
16
+ ARTICLE_TEMPLATE = <<-EOT
17
+ ====== %{title} ======
18
+ Seen @ %{published}
19
+
20
+ %{summary}
21
+
22
+ Read on: %{url}
23
+
24
+ --
25
+
26
+ EOT
27
+
28
+ def perform
29
+ @collection.articles.reduce('') do |response, article|
30
+ response + ARTICLE_TEMPLATE % {
31
+ title: article.title,
32
+ summary: article.summary,
33
+ published: article.published,
34
+ url: article.url
35
+ }
36
+ end
37
+ end
38
+ end
39
+
40
+ # Transforms a collection into a html representation
41
+ class HTML < Text
42
+ ARTICLE_TEMPLATE = <<-EOT
43
+ <article>
44
+ <h1 class="title">%{title}</h1>
45
+ <date>%{published}</date>
46
+
47
+ <p>%{summary}</p>
48
+
49
+ <a class="read more" href="%{url}">
50
+ Read on.
51
+ </a>
52
+ </article>
53
+ EOT
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module Rssly
2
+ VERSION = "0.0.1"
3
+ end
data/lib/rssly.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'active_support'
2
+ require "rssly/version"
3
+ require "rssly/article"
4
+ require "rssly/feed"
5
+ require "rssly/deserializers"
6
+ require "rssly/serializers"
7
+ require "rssly/collection"
8
+ require "rssly/collection/unique_filter"
9
+ require "rssly/collection/age_filter"
10
+
11
+ module Rssly
12
+ end
data/rssly.gemspec ADDED
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rssly/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rssly"
8
+ spec.version = Rssly::VERSION
9
+ spec.authors = ["Nathan Kot"]
10
+ spec.email = ["me@nathankot.com"]
11
+ spec.homepage = ""
12
+ spec.license = "MIT"
13
+ spec.description = "Collect and serialize rss feeds."
14
+ spec.summary = <<-EOT
15
+ Rssly is a tool to gather rssly feeds, filter and serialize them into
16
+ various outputs.
17
+ EOT
18
+
19
+ spec.files = `git ls-files`.split($/)
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "feedbag", "~> 0.9"
25
+ spec.add_dependency "feedjira", "~> 1.1"
26
+ spec.add_dependency "ruby-readability", "~> 0.6"
27
+ spec.add_dependency "sanitize", "~> 2.1"
28
+ spec.add_dependency "ots", "~> 0.5"
29
+ spec.add_dependency "addressable", "~> 2.3"
30
+ spec.add_dependency "bloomfilter-rb", "~> 2.1"
31
+ spec.add_dependency "thor"
32
+
33
+ spec.add_development_dependency "bundler", "~> 1.3"
34
+ spec.add_development_dependency "rake"
35
+ spec.add_development_dependency "rspec"
36
+
37
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+ require 'rssly'
3
+ require 'feedjira'
4
+ require 'addressable/uri'
5
+
6
+ describe 'Rssly::Article' do
7
+
8
+ ARTICLE_TEST_FEED_URL = 'news.ycombinator.com/rss'
9
+ ARTICLE_TEST_URL = \
10
+ 'http://blog.ycombinator.com/meet-the-people-taking-over-hacker-news'
11
+
12
+ describe 'class' do
13
+ describe '#create_from_feedjira_entry' do
14
+ before do
15
+ @entry = Feedjira::Feed.fetch_and_parse(ARTICLE_TEST_FEED_URL).entries.first
16
+ allow(@entry).to receive(:published).and_return(Time.now)
17
+ @article = Rssly::Article.create_from_feedjira_entry @entry
18
+ end
19
+
20
+ it 'should set the title' do
21
+ expect(@article.title).to eq(@entry.title)
22
+ end
23
+
24
+ it 'should set the url' do
25
+ expect(@article.url).to eq(@entry.url)
26
+ end
27
+
28
+ it 'should set the publish date' do
29
+ expect(@article.published).to eq(@entry.published)
30
+ end
31
+ end
32
+ end
33
+
34
+ describe 'instance' do
35
+ before do
36
+ @article = Rssly::Article.new(url: ARTICLE_TEST_URL)
37
+ end
38
+
39
+ it 'should standardize the url' do
40
+ article = Rssly::Article.new url: 'http://notstandard.com/123123/?test=hello/'
41
+ expect(article.url).to eq('http://notstandard.com/123123/')
42
+ end
43
+
44
+ it 'should standardize a file url' do
45
+ article = Rssly::Article.new url: 'http://notstandard.com/123123.html?hello'
46
+ expect(article.url).to eq('http://notstandard.com/123123.html')
47
+ end
48
+
49
+ it 'should fetch the title if not given' do
50
+ expect(@article.title).not_to eq(nil)
51
+ end
52
+
53
+ it 'should fetch the summary if not given' do
54
+ expect(@article.summary).not_to eq(nil)
55
+ end
56
+
57
+ it 'should always have a published date' do
58
+ expect(@article.published).not_to eq(nil)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+ require 'rssly'
3
+ require 'active_support/core_ext'
4
+
5
+ describe 'Rssly::Collection' do
6
+
7
+ COLLECTION_TEST_URL = 'news.ycombinator.com/rss'
8
+ COLLECTION_ARTICLE_TEST_URL = \
9
+ 'http://blog.ycombinator.com/meet-the-people-taking-over-hacker-news'
10
+
11
+ before do
12
+ @feed = Rssly::Feed.new(url: COLLECTION_TEST_URL)
13
+ @feed2 = Rssly::Feed.new(url: COLLECTION_TEST_URL)
14
+ end
15
+
16
+ describe 'class' do
17
+ describe '#create_from_feeds' do
18
+ before do
19
+ @feed_count = @feed.articles.length
20
+ @collection = Rssly::Collection.create_from_feeds(
21
+ @feed, @feed2
22
+ )
23
+ end
24
+
25
+ it 'filters out duplicate articles' do
26
+ expect(@collection.length).to eq(@feed_count)
27
+ end
28
+ end
29
+ end
30
+
31
+ describe 'instance' do
32
+ before do
33
+ @articles = []
34
+ 3.times do
35
+ @articles << Rssly::Article.new(url: COLLECTION_ARTICLE_TEST_URL)
36
+ end
37
+
38
+ @collection = Rssly::Collection.new(@articles)
39
+ end
40
+
41
+ it 'should respond to #each' do
42
+ expect(@collection.respond_to?(:each)).to eq(true)
43
+ end
44
+
45
+ it 'should respond to #length' do
46
+ expect(@collection.length).to eq(3)
47
+ end
48
+
49
+ describe 'filtering' do
50
+ it 'can filter by age' do
51
+ @collection.filter(
52
+ Rssly::Collection::AgeFilter, min: 1.hour.from_now
53
+ )
54
+
55
+ expect(@collection.length).to eq(0)
56
+
57
+ @collection.filter(
58
+ Rssly::Collection::AgeFilter, max: 1.hour.ago
59
+ )
60
+
61
+ expect(@collection.length).to eq(0)
62
+ end
63
+ end
64
+ end
65
+ end
data/spec/feed_spec.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ require 'rssly'
3
+
4
+ describe 'Rssly::Feed' do
5
+
6
+ FEED_TEST_URL = 'news.ycombinator.com/rss'
7
+
8
+ before do
9
+ @feed = Rssly::Feed.new(url: FEED_TEST_URL)
10
+ end
11
+
12
+ it 'should set the @url' do
13
+ expect(@feed.url).to eq(FEED_TEST_URL)
14
+ end
15
+
16
+ describe '#articles' do
17
+ before do
18
+ allow(Rssly::Article).to receive(:create_from_feedjira_entry) do |entry|
19
+ entry
20
+ end
21
+ end
22
+
23
+ it 'should call Article#create_from_feedjira_entry' do
24
+ expect(Rssly::Article).to receive(:create_from_feedjira_entry)
25
+ @feed.articles
26
+ end
27
+
28
+ it 'articles should have titles' do
29
+ expect(@feed.articles.first.title).to_not eq(nil)
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,17 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ RSpec.configure do |config|
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.run_all_when_everything_filtered = true
10
+ config.filter_run :focus
11
+
12
+ # Run specs in random order to surface order dependencies. If you find an
13
+ # order dependency and want to debug it, you can fix the order by providing
14
+ # the seed, which is printed after each run.
15
+ # --seed 1234
16
+ config.order = 'random'
17
+ end
metadata ADDED
@@ -0,0 +1,227 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rssly
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Nathan Kot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: feedbag
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '0.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: feedjira
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: ruby-readability
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '0.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sanitize
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '2.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '2.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: ots
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0.5'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0.5'
83
+ - !ruby/object:Gem::Dependency
84
+ name: addressable
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '2.3'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '2.3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bloomfilter-rb
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '2.1'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '2.1'
111
+ - !ruby/object:Gem::Dependency
112
+ name: thor
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: bundler
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ~>
130
+ - !ruby/object:Gem::Version
131
+ version: '1.3'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ~>
137
+ - !ruby/object:Gem::Version
138
+ version: '1.3'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rake
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rspec
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: Collect and serialize rss feeds.
168
+ email:
169
+ - me@nathankot.com
170
+ executables:
171
+ - rssly
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - .gitignore
176
+ - .rspec
177
+ - .ruby-version
178
+ - Gemfile
179
+ - LICENSE.txt
180
+ - README.md
181
+ - Rakefile
182
+ - bin/rssly
183
+ - lib/rssly.rb
184
+ - lib/rssly/article.rb
185
+ - lib/rssly/cli.rb
186
+ - lib/rssly/collection.rb
187
+ - lib/rssly/collection/age_filter.rb
188
+ - lib/rssly/collection/unique_filter.rb
189
+ - lib/rssly/deserializers.rb
190
+ - lib/rssly/feed.rb
191
+ - lib/rssly/serializers.rb
192
+ - lib/rssly/version.rb
193
+ - rssly.gemspec
194
+ - spec/article_spec.rb
195
+ - spec/collection_spec.rb
196
+ - spec/feed_spec.rb
197
+ - spec/spec_helper.rb
198
+ homepage: ''
199
+ licenses:
200
+ - MIT
201
+ metadata: {}
202
+ post_install_message:
203
+ rdoc_options: []
204
+ require_paths:
205
+ - lib
206
+ required_ruby_version: !ruby/object:Gem::Requirement
207
+ requirements:
208
+ - - '>='
209
+ - !ruby/object:Gem::Version
210
+ version: '0'
211
+ required_rubygems_version: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - '>='
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ requirements: []
217
+ rubyforge_project:
218
+ rubygems_version: 2.0.3
219
+ signing_key:
220
+ specification_version: 4
221
+ summary: Rssly is a tool to gather rssly feeds, filter and serialize them into various
222
+ outputs.
223
+ test_files:
224
+ - spec/article_spec.rb
225
+ - spec/collection_spec.rb
226
+ - spec/feed_spec.rb
227
+ - spec/spec_helper.rb