myredditnews 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +50 -0
- data/Rakefile +11 -0
- data/lib/myredditnews.rb +251 -0
- data/lib/myredditnews/version.rb +3 -0
- data/myredditnews.gemspec +31 -0
- data/test/lib/myredditnews/app_test.rb +39 -0
- data/test/lib/myredditnews/entry_test.rb +56 -0
- data/test/lib/myredditnews/formatter_test.rb +38 -0
- data/test/lib/myredditnews/history_test.rb +39 -0
- data/test/lib/myredditnews/source_test.rb +18 -0
- data/test/lib/myredditnews/version_test.rb +8 -0
- data/test/test_helper.rb +5 -0
- metadata +193 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 60567deb5739350f3193263d102447ea5451ddeb
|
4
|
+
data.tar.gz: 9fa9b5e8c56cfc0948653d36f83a09c65b1a6d49
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2b89b52a72391b48ee1bbb645e42d91add14e1d43586df76fc0f1114316a93b071c0acd2053dc6f6218961b17424659805e67cc48255ea1e4256e1c299632990
|
7
|
+
data.tar.gz: 5b9534c59fdd68653ad289b6a1732904e9132da3e10ac9fd99f71bbd0075752dd5d64bcdd05c2b50b2be809af223b99f362090f3a7bc835385055523093b7748
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Rudi Grinberg
|
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,50 @@
|
|
1
|
+
# Myredditnews
|
2
|
+
|
3
|
+
Want to get your reddit and rss feeds at the same place? Mirror your rss
|
4
|
+
feeds into a personal subreddit with this script.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'myredditnews'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install myredditnews
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
First configure which feeds you'd like to follow and which subreddit
|
23
|
+
you'd like them to be sent.
|
24
|
+
|
25
|
+
```
|
26
|
+
require 'myredditnews'
|
27
|
+
|
28
|
+
mrn = Myreddinews::App.new
|
29
|
+
username 'foobar'
|
30
|
+
password 'hunter2'
|
31
|
+
history '~/.mrn'
|
32
|
+
source 'http://feeds.bbci.co.uk/news/world/rss.xml'
|
33
|
+
source 'http://feeds.bbci.co.uk/news/rss.xml' do
|
34
|
+
name 'breaking news'
|
35
|
+
end
|
36
|
+
target_subreddit 'my_personal_news' # r/my_personal_news
|
37
|
+
end
|
38
|
+
|
39
|
+
mrn.sync
|
40
|
+
```
|
41
|
+
|
42
|
+
Then run the script above as with a cron job.
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
|
46
|
+
1. Fork it
|
47
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
48
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
49
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
50
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/myredditnews.rb
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'myredditnews/version'
|
2
|
+
require 'snoo'
|
3
|
+
require 'set'
|
4
|
+
require 'json'
|
5
|
+
require 'doodle'
|
6
|
+
require 'logger'
|
7
|
+
require 'feedzirra'
|
8
|
+
require 'nokogiri'
|
9
|
+
require 'pstore'
|
10
|
+
|
11
|
+
$logger = Logger.new(STDOUT)
|
12
|
+
# TODO get rid of the global variables
|
13
|
+
$delay = 4.5
|
14
|
+
$dry = false
|
15
|
+
|
16
|
+
module Myredditnews
|
17
|
+
|
18
|
+
def self.delay; $delay; end
|
19
|
+
def self.delay=d; $delay=d; end
|
20
|
+
def self.dry; $dry; end
|
21
|
+
def self.dry=d; $dry=d; end
|
22
|
+
|
23
|
+
# TODO : remove the boiler plate below
|
24
|
+
def self.with_dry(set_to)
|
25
|
+
old = self.dry
|
26
|
+
self.dry = set_to
|
27
|
+
yield
|
28
|
+
self.dry = old
|
29
|
+
end
|
30
|
+
def self.with_delay(set_to)
|
31
|
+
old = self.delay
|
32
|
+
self.delay = set_to
|
33
|
+
yield
|
34
|
+
self.delay = old
|
35
|
+
end
|
36
|
+
class RedditError < StandardError; end
|
37
|
+
class Entry < Doodle
|
38
|
+
has :author , kind: String
|
39
|
+
has :content , kind: String
|
40
|
+
has :url , kind: String
|
41
|
+
has :title , kind: String
|
42
|
+
has :date , kind: String
|
43
|
+
has :summary , default: ''
|
44
|
+
has :self_post , default: true
|
45
|
+
def submit(reddit, subreddit)
|
46
|
+
opts = {}
|
47
|
+
if self_post?
|
48
|
+
opts[:kind] = 'self'
|
49
|
+
opts[:text] = @content
|
50
|
+
else
|
51
|
+
opts[:kind] = 'link'
|
52
|
+
opts[:url] = @url
|
53
|
+
end
|
54
|
+
$logger.info("Submitting #{opts[:kind]}: #{self}")
|
55
|
+
puts "Dryness: #{Myredditnews.dry}"
|
56
|
+
unless Myredditnews.dry
|
57
|
+
response = reddit.submit(@title, subreddit, opts)
|
58
|
+
$logger.info(response)
|
59
|
+
throw_if_error response
|
60
|
+
# TODO rate limiting should be smarter than this
|
61
|
+
puts "Sleeping for #{Myredditnews.delay}"
|
62
|
+
sleep Myredditnews.delay
|
63
|
+
end
|
64
|
+
end
|
65
|
+
def to_s
|
66
|
+
return "[#{truncate(@author, 10)}, #{truncate(@url, 20)}]"
|
67
|
+
end
|
68
|
+
def self_post?
|
69
|
+
self_post
|
70
|
+
end
|
71
|
+
def to_json(*a)
|
72
|
+
{
|
73
|
+
"author" => @author,
|
74
|
+
"content" => @content,
|
75
|
+
"url" => @url,
|
76
|
+
"date" => @date,
|
77
|
+
"summary" => @summary,
|
78
|
+
"title" => @title, }.to_json(*a)
|
79
|
+
end
|
80
|
+
private
|
81
|
+
def truncate str, width
|
82
|
+
str.size > width ? (str[0..width-1] + "...") : str
|
83
|
+
end
|
84
|
+
def throw_if_error response
|
85
|
+
unless response['json']['errors'].empty?
|
86
|
+
raise RedditError, response['json']['errors']
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class Formatter < Doodle
|
92
|
+
# @format is the "format" of the title only
|
93
|
+
has :format, kind: String
|
94
|
+
def fmt(entry)
|
95
|
+
new_title = @format.gsub(/\{\{(.+?)\}\}/) { |match| entry.send($1) }
|
96
|
+
new_entry = entry.clone
|
97
|
+
new_entry.title = new_title
|
98
|
+
new_entry.content = format_content(new_entry)
|
99
|
+
if new_entry.content.empty?
|
100
|
+
new_entry.self_post = false
|
101
|
+
else
|
102
|
+
new_entry.content += "\n\n" + md_link('source', new_entry.url)
|
103
|
+
end
|
104
|
+
return new_entry
|
105
|
+
end
|
106
|
+
def self.default
|
107
|
+
self.new '{{title}} - {{author}}'
|
108
|
+
end
|
109
|
+
private
|
110
|
+
def md_link(text, url)
|
111
|
+
"[#{text}](#{url})"
|
112
|
+
end
|
113
|
+
def format_content entry
|
114
|
+
# maybe translate to markdown?
|
115
|
+
return filter_html(entry.content) if !entry.content.empty?
|
116
|
+
return filter_html(entry.summary) if !entry.summary.empty?
|
117
|
+
return ''
|
118
|
+
end
|
119
|
+
def filter_html html
|
120
|
+
Nokogiri::HTML(html).xpath("//text()").remove.to_s
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class FeedFetchingError < StandardError
|
125
|
+
attr_reader :parent
|
126
|
+
def initialize parent
|
127
|
+
@parent = parent
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
class Source < Doodle
|
132
|
+
has :source, kind: String
|
133
|
+
has :name, default: nil
|
134
|
+
has :formatter, kind: Formatter, default: Formatter.default
|
135
|
+
def safe_get field
|
136
|
+
# not using sanitize because of some encoding bug.
|
137
|
+
# field.nil? ? "" : field.sanitize
|
138
|
+
field.nil? ? "" : field
|
139
|
+
end
|
140
|
+
def fetch
|
141
|
+
feed = Feedzirra::Feed.fetch_and_parse(@source)
|
142
|
+
s = self
|
143
|
+
feed.entries.map do |feed_entry|
|
144
|
+
Myredditnews::Entry.new do
|
145
|
+
author s.safe_get(feed_entry.author)
|
146
|
+
content s.safe_get(feed_entry.content)
|
147
|
+
title s.safe_get(feed_entry.title)
|
148
|
+
summary s.safe_get(feed_entry.summary)
|
149
|
+
url feed_entry.url
|
150
|
+
date feed_entry.published.to_s
|
151
|
+
end
|
152
|
+
end
|
153
|
+
rescue => e
|
154
|
+
raise FeedFetchingError, e
|
155
|
+
end
|
156
|
+
def format entry
|
157
|
+
formatter.fmt(entry)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class History
|
162
|
+
def initialize path
|
163
|
+
@path = path
|
164
|
+
@posted_queue = []
|
165
|
+
@db = PStore.new(File.expand_path @path)
|
166
|
+
end
|
167
|
+
def filter entries
|
168
|
+
@db.transaction do
|
169
|
+
entries.reject { |e| @db.root? e }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
# TODO : the only reason this method was not removed is because it's
|
173
|
+
# used in some tests
|
174
|
+
def posted? entry
|
175
|
+
return true if @posted_queue.include? entry
|
176
|
+
@db.transaction do
|
177
|
+
@db.root? entry
|
178
|
+
end
|
179
|
+
end
|
180
|
+
def posted! entry
|
181
|
+
@posted_queue << entry
|
182
|
+
end
|
183
|
+
def append_entries!
|
184
|
+
return if Myredditnews.dry
|
185
|
+
@db.transaction do
|
186
|
+
@posted_queue.each do |e|
|
187
|
+
@db[e] = 0
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
def delete_all!
|
192
|
+
@db = nil
|
193
|
+
File.delete @path if File.exists? @path
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
class App < Doodle
|
198
|
+
has :username , kind: String
|
199
|
+
has :password , kind: String
|
200
|
+
has :useragent , default: "Myredditnews v#{Myredditnews::VERSION}"
|
201
|
+
has :history , kind: History do
|
202
|
+
from String do |path|
|
203
|
+
History.new(path)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
has :target_subreddit , kind: String
|
207
|
+
has :sources, collect: Source
|
208
|
+
def sync
|
209
|
+
$logger.info("Mode: dry = #{Myredditnews.dry}")
|
210
|
+
reddit = Snoo::Client.new(useragent: useragent)
|
211
|
+
$logger.info("Logging in with #{@username}")
|
212
|
+
reddit.log_in @username, @password
|
213
|
+
total = 0
|
214
|
+
fetch_sources().each do |source, submissions|
|
215
|
+
only_new(submissions).each do |submission|
|
216
|
+
begin
|
217
|
+
source.format(submission).submit(reddit, @target_subreddit)
|
218
|
+
@history.posted! submission
|
219
|
+
total += 1
|
220
|
+
rescue RedditError => e
|
221
|
+
puts "Error submitting #{submission}"
|
222
|
+
puts "Reason: #{e.message}"
|
223
|
+
rescue => e
|
224
|
+
puts "Failed submitting #{submission}"
|
225
|
+
puts "Message: #{e.message}"
|
226
|
+
puts e.backtrace
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
$logger.info("Sent #{total} entries to r/#{@target_subreddit}")
|
231
|
+
reddit.log_out
|
232
|
+
history.append_entries!
|
233
|
+
end
|
234
|
+
def only_new submissions
|
235
|
+
@history.filter(submissions)
|
236
|
+
end
|
237
|
+
def fetch_sources
|
238
|
+
sources = {}
|
239
|
+
@sources.each do |source|
|
240
|
+
begin
|
241
|
+
sources[source] = source.fetch
|
242
|
+
rescue FeedFetchingError => e
|
243
|
+
$logger.info("Could not fetch feed #{source.source}. Reason:")
|
244
|
+
$logger.info("Exception: #{e.message}. Backtrace:")
|
245
|
+
$logger.info(e.parent.backtrace.drop(1).map {|s| "\t#{s}"}.join("\n"))
|
246
|
+
end
|
247
|
+
end
|
248
|
+
sources
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'myredditnews/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "myredditnews"
|
8
|
+
spec.version = Myredditnews::VERSION
|
9
|
+
spec.authors = ["Rudi Grinberg"]
|
10
|
+
spec.email = ["rudi.grinberg@gmail.com"]
|
11
|
+
spec.description = %q{Mirror your rss feeds into a subreddit}
|
12
|
+
spec.summary = %q{This gem is a standalone program designed to mirror
|
13
|
+
your RSS feeds into your subreddits of choice. Runs in the background }
|
14
|
+
spec.homepage = ""
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "pry"
|
25
|
+
spec.add_development_dependency "minitest"
|
26
|
+
spec.add_dependency "snoo"
|
27
|
+
spec.add_dependency "json"
|
28
|
+
spec.add_dependency "doodle"
|
29
|
+
spec.add_dependency "feedzirra"
|
30
|
+
spec.add_dependency "nokogiri"
|
31
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
describe Myredditnews::App do
|
4
|
+
|
5
|
+
it 'be configured' do
|
6
|
+
sample_format = '#{date} >> #{title} - #{author}'
|
7
|
+
user, pass = 'user', 'pass'
|
8
|
+
s1name = 'my special blog source'
|
9
|
+
s2url = 'http://another.com/one/two.rss'
|
10
|
+
|
11
|
+
mrn = Myredditnews::App.new do
|
12
|
+
username 'user'
|
13
|
+
password 'pass'
|
14
|
+
history '~/.mrn'
|
15
|
+
# Complex source
|
16
|
+
source 'http://hey.com/path/to.rss' do
|
17
|
+
formatter sample_format
|
18
|
+
name s1name
|
19
|
+
end
|
20
|
+
source s2url # simple source
|
21
|
+
target_subreddit 'testing'
|
22
|
+
end
|
23
|
+
|
24
|
+
mrn.username.must_equal user
|
25
|
+
mrn.password.must_equal pass
|
26
|
+
mrn.history.wont_be_nil
|
27
|
+
mrn.target_subreddit.wont_be_nil
|
28
|
+
|
29
|
+
refute_nil mrn.useragent
|
30
|
+
|
31
|
+
s1 = mrn.sources.first
|
32
|
+
s1.formatter.format.must_equal sample_format
|
33
|
+
|
34
|
+
s2 = mrn.sources.last
|
35
|
+
s2.source.must_equal s2url
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
describe Myredditnews::Entry do
|
4
|
+
before do
|
5
|
+
@entry = Myredditnews::Entry.new do
|
6
|
+
author "david"
|
7
|
+
content "lorem ipsum"
|
8
|
+
url "google.com"
|
9
|
+
date "tomorrow"
|
10
|
+
title "my title"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'can be serialized to json' do
|
15
|
+
js = JSON.parse(@entry.to_json)
|
16
|
+
js["author"].must_equal "david"
|
17
|
+
js["content"].must_equal "lorem ipsum"
|
18
|
+
js["date"].must_equal "tomorrow"
|
19
|
+
js["title"].must_equal "my title"
|
20
|
+
js["url"].must_equal "google.com"
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'can be parsed from json' do
|
24
|
+
json = <<END
|
25
|
+
{
|
26
|
+
"author" : "rudi",
|
27
|
+
"content" : "boring",
|
28
|
+
"date" : "yesterday",
|
29
|
+
"title" : "testing123",
|
30
|
+
"url" : "testing.com"
|
31
|
+
}
|
32
|
+
END
|
33
|
+
entry = Myredditnews::Entry(JSON.parse(json))
|
34
|
+
entry.author.must_equal "rudi"
|
35
|
+
entry.content.must_equal "boring"
|
36
|
+
entry.date.must_equal "yesterday"
|
37
|
+
entry.title.must_equal "testing123"
|
38
|
+
entry.url.must_equal "testing.com"
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'respects delay when submitting' do
|
42
|
+
reddit_mock = MiniTest::Mock.new
|
43
|
+
reddit_mock.expect(:submit,
|
44
|
+
{'json' => {'errors' => []}}, [String, String, Hash])
|
45
|
+
@new_delay = 0.05
|
46
|
+
@now = Time.now.to_f
|
47
|
+
Myredditnews.with_dry false do
|
48
|
+
Myredditnews.with_delay 0.05 do
|
49
|
+
@entry.submit(reddit_mock, 'my_subreddit')
|
50
|
+
refute_in_delta @now, Time.now.to_f, @new_delay
|
51
|
+
end
|
52
|
+
end
|
53
|
+
reddit_mock.verify
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
describe Myredditnews::Formatter do
|
4
|
+
before do
|
5
|
+
@sample_entry = Myredditnews::Entry.new do
|
6
|
+
author 'rudi'
|
7
|
+
content '<b>something</b>'
|
8
|
+
title 'testing'
|
9
|
+
url 'http://test.me/ok.rss'
|
10
|
+
title 'a title'
|
11
|
+
date 'never'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
it 'must have a default formatting' do
|
15
|
+
formatter = Myredditnews::Formatter.default
|
16
|
+
refute_nil formatter.format
|
17
|
+
end
|
18
|
+
it 'default formatter must format title' do
|
19
|
+
formatted_entry = Myredditnews::Formatter.default.fmt(@sample_entry)
|
20
|
+
assert_includes formatted_entry.title, 'a title'
|
21
|
+
end
|
22
|
+
it 'custom formatting of title must work' do
|
23
|
+
formatter = Myredditnews::Formatter.new do
|
24
|
+
format '{{author}} {{author}}'
|
25
|
+
end
|
26
|
+
formatter.fmt(@sample_entry).title.must_equal 'rudi rudi'
|
27
|
+
end
|
28
|
+
it 'formatted posts must include links' do
|
29
|
+
f = Myredditnews::Formatter.default
|
30
|
+
assert_includes f.fmt(@sample_entry).content, "(#{@sample_entry.url})"
|
31
|
+
end
|
32
|
+
it 'formatted text must remove html' do
|
33
|
+
f = Myredditnews::Formatter.default
|
34
|
+
refute_includes f.fmt(@sample_entry).content, "<b>"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
describe Myredditnews::History do
|
4
|
+
before do
|
5
|
+
Myredditnews.dry = false
|
6
|
+
@entry = Myredditnews::Entry.new do
|
7
|
+
author "rudi"
|
8
|
+
content "someone"
|
9
|
+
title "foo"
|
10
|
+
date "bar"
|
11
|
+
url "gopnik"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
it 'can have entries' do
|
15
|
+
history = Myredditnews::History.new('testin.db')
|
16
|
+
history.posted?("testing").must_equal false
|
17
|
+
history.delete_all!
|
18
|
+
end
|
19
|
+
it 'can add entries' do
|
20
|
+
history = Myredditnews::History.new('testing.db')
|
21
|
+
history.posted! @entry
|
22
|
+
history.posted?(@entry).must_equal true
|
23
|
+
history.delete_all!
|
24
|
+
end
|
25
|
+
it 'can write posted' do
|
26
|
+
path = './scrub.txt'
|
27
|
+
File.exists?(path).must_equal false
|
28
|
+
history = Myredditnews::History.new(path)
|
29
|
+
history.posted! @entry
|
30
|
+
history.posted?(@entry).must_equal true
|
31
|
+
history.append_entries!
|
32
|
+
File.exists?(path).must_equal true
|
33
|
+
history.delete_all!
|
34
|
+
end
|
35
|
+
after do
|
36
|
+
Myredditnews.dry = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative '../../test_helper'
|
2
|
+
|
3
|
+
rss_url = "http://rss.cbc.ca/lineup/topstories.xml"
|
4
|
+
|
5
|
+
describe Myredditnews::Source do
|
6
|
+
it 'can be created' do
|
7
|
+
source = Myredditnews::Source.new do
|
8
|
+
source rss_url
|
9
|
+
name 'cbc'
|
10
|
+
end
|
11
|
+
source.source.must_equal rss_url
|
12
|
+
source.name.must_equal "cbc"
|
13
|
+
end
|
14
|
+
it 'can fetch entries' do
|
15
|
+
entries = Myredditnews::Source.new(source: rss_url).fetch
|
16
|
+
(entries.size > 0).must_equal true
|
17
|
+
end
|
18
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: myredditnews
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rudi Grinberg
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-05-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: pry
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: snoo
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: json
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: doodle
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: feedzirra
|
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: nokogiri
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: Mirror your rss feeds into a subreddit
|
140
|
+
email:
|
141
|
+
- rudi.grinberg@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- .gitignore
|
147
|
+
- Gemfile
|
148
|
+
- LICENSE.txt
|
149
|
+
- README.md
|
150
|
+
- Rakefile
|
151
|
+
- lib/myredditnews.rb
|
152
|
+
- lib/myredditnews/version.rb
|
153
|
+
- myredditnews.gemspec
|
154
|
+
- test/lib/myredditnews/app_test.rb
|
155
|
+
- test/lib/myredditnews/entry_test.rb
|
156
|
+
- test/lib/myredditnews/formatter_test.rb
|
157
|
+
- test/lib/myredditnews/history_test.rb
|
158
|
+
- test/lib/myredditnews/source_test.rb
|
159
|
+
- test/lib/myredditnews/version_test.rb
|
160
|
+
- test/test_helper.rb
|
161
|
+
homepage: ''
|
162
|
+
licenses:
|
163
|
+
- MIT
|
164
|
+
metadata: {}
|
165
|
+
post_install_message:
|
166
|
+
rdoc_options: []
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - '>='
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
requirements: []
|
180
|
+
rubyforge_project:
|
181
|
+
rubygems_version: 2.0.3
|
182
|
+
signing_key:
|
183
|
+
specification_version: 4
|
184
|
+
summary: This gem is a standalone program designed to mirror your RSS feeds into your
|
185
|
+
subreddits of choice. Runs in the background
|
186
|
+
test_files:
|
187
|
+
- test/lib/myredditnews/app_test.rb
|
188
|
+
- test/lib/myredditnews/entry_test.rb
|
189
|
+
- test/lib/myredditnews/formatter_test.rb
|
190
|
+
- test/lib/myredditnews/history_test.rb
|
191
|
+
- test/lib/myredditnews/source_test.rb
|
192
|
+
- test/lib/myredditnews/version_test.rb
|
193
|
+
- test/test_helper.rb
|