feedbook 0.9.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/README.md +4 -6
- data/bin/feedbook +25 -11
- data/feedbook.gemspec +1 -1
- data/lib/feedbook/configuration.rb +7 -25
- data/lib/feedbook/errors.rb +0 -1
- data/lib/feedbook/factories/notifiers_factory.rb +9 -1
- data/lib/feedbook/liquid_extensions.rb +1 -0
- data/lib/feedbook/liquid_extensions/filters/googl_shortener_filter.rb +22 -0
- data/lib/feedbook/listener.rb +122 -47
- data/lib/feedbook/notification.rb +1 -0
- data/lib/feedbook/notifiers/facebook_notifier.rb +5 -6
- data/lib/feedbook/notifiers/null_notifier.rb +1 -1
- data/lib/feedbook/notifiers/twitter_notifier.rb +8 -9
- data/lib/feedbook/plugins_manager.rb +20 -0
- data/lib/feedbook/version.rb +1 -1
- data/spec/unit/lib/configuration_spec.rb +5 -5
- data/spec/unit/lib/factories/notifiers_factory_spec.rb +41 -0
- data/spec/unit/lib/liquid_extensions/filters/googl_shortener_filter_spec.rb +18 -0
- data/spec/unit/lib/listener_spec.rb +117 -1
- data/spec/unit/lib/notifiers/facebook_notifier_spec.rb +13 -1
- data/spec/unit/lib/plugins_manager_spec.rb +31 -0
- metadata +23 -17
- data/lib/feedbook/errors/notifier_notify_error.rb +0 -12
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NWM2NzUzZWNhOTIwZTE2MDhkZTQ5NTU3NGNhNTYwZmQ4ZDNiOThjOA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZmIzOTgxMmU5MWNmNzJiMjFjN2RlNzFlOGQ4MjY4NTg3Y2EzYzQ1Mw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MmM1NDJlYTY4MDUxYjM5YmFiY2RjNzNlZjhmNjRiN2Q5MTNiZTAxODEyOTUy
|
10
|
+
NDY5MjI4ZTVkMmZkZWY5Y2RlNjJjM2Y3Yjg3MmFhOTUyYzk5YzFiYThmMjNi
|
11
|
+
NWVlNGRmNzZlYTljMTM4YzhjNjIwNmNmMTcxMGI4Nzk0YjliOTU=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MWI2YjRlODRkNTJmNzFmMDE4ZTBiYjdlYTdkZjBlZjE0MGVhMDcwODlmZmE1
|
14
|
+
MjUxYTFmMWJjMzYyMWVjZjc5ZTYyZmRkOGU5ZGZmNjNiOTQ0OGU4N2VjZjhi
|
15
|
+
NGU4ODNkMzU1ZTg3MjBlODc4YjdhYzRlMmVkNWFkZjNkMWZmMzM=
|
data/README.md
CHANGED
@@ -112,13 +112,11 @@ Feedbook uses Liquid for generating output. If you know Mustache it will not be
|
|
112
112
|
Because Feedbook is still in development there is many to do:
|
113
113
|
|
114
114
|
* add Google+ Notifier
|
115
|
-
|
116
|
-
* add links shortener (bit.ly or goo.gl) as a Liquid tag/filter
|
117
|
-
Twitter limits Tweet length to 140 characters, why not to shorten links and rescue too long message.
|
118
|
-
* add ability to add own Notifier without forking Feedbook project
|
119
|
-
I would like to give ability to users to create own Notifier plugins without any special development to Feedbook.
|
115
|
+
* Unfortunately Google+ does not provides API with ability to push messages to streams. Because of that I need to find a tool that will provide that feature without use of Google+.
|
120
116
|
* add more tests
|
121
|
-
|
117
|
+
* I would like to add integration tests to make sure that all features work.
|
118
|
+
* add offline mode
|
119
|
+
* I would like to add ability to run Feedbook with cron (start Feedbook, look for changes, save list of already notified posts and turn off)
|
122
120
|
|
123
121
|
## Contributing
|
124
122
|
|
data/bin/feedbook
CHANGED
@@ -10,28 +10,42 @@ include GLI::App
|
|
10
10
|
|
11
11
|
program_desc 'Feedbook is a simple gem and application that notifies about new posts and Atom/RSS updates on your social media sites (like Facebook and Twitter), e-mail or IRC.'
|
12
12
|
|
13
|
-
flag [:c,:config], default_value: 'feedbook.yml', desc: 'Feedbook configuration file location'
|
14
|
-
|
15
13
|
desc 'Parses feedbook.yml file for feeds and configuration and listen for changes in RSS/Atom feeds to notify about updates on social media sites'
|
16
14
|
command :start do |c|
|
17
15
|
|
18
|
-
c.
|
19
|
-
|
16
|
+
c.flag [:c, :config], default_value: 'feedbook.yml', desc: 'Feedbook configuration file location'
|
17
|
+
c.flag [:p, :plugins], default_value: './plugins', desc: 'Plugins directory'
|
18
|
+
c.flag [:a, :archive], default_value: 'feedbook_offline.yml', desc: 'Feedbook archive file'
|
19
|
+
|
20
|
+
c.default_desc 'Parses feedbook.yml file for feeds and configuration and listen for changes in RSS/Atom feeds to notify about updates on social media sites'
|
21
|
+
c.action do |_, options, _|
|
22
|
+
Feedbook::Listener.start(options[:config], options[:plugins])
|
23
|
+
end
|
24
|
+
|
25
|
+
c.desc 'Parses feedbook.yml file for feeds and configuration and listen for changes in RSS/Atom feeds to notify about updates on social media sites'
|
26
|
+
c.command :offline do |cc|
|
27
|
+
|
28
|
+
cc.action do |_, options, _|
|
29
|
+
Feedbook::Listener.start_offline(options[:config], options[:archive], options[:plugins])
|
30
|
+
end
|
20
31
|
end
|
21
32
|
end
|
22
33
|
|
23
34
|
desc 'Creates basic feedbook config file'
|
24
35
|
command :init do |c|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
36
|
+
|
37
|
+
c.flag [:c,:config], default_value: 'feedbook.yml', desc: 'Feedbook configuration file location'
|
38
|
+
|
39
|
+
c.action do |_, options, _|
|
40
|
+
abort 'There is already a feedbook configuration file' if File.exist?(options[:config])
|
41
|
+
File.open(options[:config], 'w') { |f| f.write(Box::FILES['feedbook']) }
|
42
|
+
puts "=> Created default feedbook configuration file: #{options[:config]}"
|
29
43
|
end
|
30
44
|
end
|
31
45
|
|
32
46
|
desc 'Outputs feedbook gem version'
|
33
47
|
command :version do |c|
|
34
|
-
c.action do |
|
48
|
+
c.action do |_, _, _|
|
35
49
|
puts "feedbook version: #{Feedbook::VERSION}"
|
36
50
|
end
|
37
51
|
end
|
@@ -67,7 +81,7 @@ configuration:
|
|
67
81
|
facebook:
|
68
82
|
token: SECRET_FACEBOOK_TOKEN
|
69
83
|
twitter:
|
70
|
-
|
71
|
-
|
84
|
+
api_key: SECRET_API_KEY
|
85
|
+
api_secret: SECRET_API_SECRET
|
72
86
|
access_token: SECRET_TWITTER_ACCESS_TOKEN
|
73
87
|
access_token_secret: SECRET_TWITTER_ACCESS_TOKEN_SECRET
|
data/feedbook.gemspec
CHANGED
@@ -26,11 +26,11 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_runtime_dependency 'box', '~> 0.1'
|
27
27
|
spec.add_runtime_dependency 'twitter', '~> 5.1'
|
28
28
|
spec.add_runtime_dependency 'mail', '~> 2.6'
|
29
|
+
spec.add_runtime_dependency 'googl', '~> 0.6'
|
29
30
|
spec.add_runtime_dependency 'irc-notify'
|
30
31
|
|
31
32
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
32
33
|
spec.add_development_dependency 'rake', '~> 10.3'
|
33
34
|
spec.add_development_dependency 'rspec'
|
34
35
|
spec.add_development_dependency 'coveralls'
|
35
|
-
spec.add_development_dependency 'pry-debugger'
|
36
36
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'feedbook/
|
1
|
+
require 'feedbook/factories/notifiers_factory'
|
2
2
|
require 'feedbook/helpers/time_interval_parser'
|
3
3
|
|
4
4
|
module Feedbook
|
5
5
|
class Configuration
|
6
|
-
attr_reader :interval
|
6
|
+
attr_reader :interval, :options
|
7
7
|
|
8
8
|
INTERVAL_FORMAT = /\A(\d+)(s|m|h|d)\z/
|
9
9
|
|
@@ -12,36 +12,18 @@ module Feedbook
|
|
12
12
|
#
|
13
13
|
# @return [NilClass] nil
|
14
14
|
def initialize(opts = {})
|
15
|
-
@interval = Helpers::TimeIntervalParser.parse
|
16
|
-
@
|
17
|
-
@facebook = opts.fetch(:facebook, nil)
|
18
|
-
@irc = opts.fetch(:irc, nil)
|
19
|
-
@mail = opts.fetch(:mail, nil)
|
15
|
+
@interval = Helpers::TimeIntervalParser.parse opts.delete('interval')
|
16
|
+
@options = opts
|
20
17
|
end
|
21
18
|
|
22
19
|
# Load notifiers configuration
|
23
20
|
#
|
24
21
|
# @return [NilClass] nil
|
25
22
|
def load_notifiers
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
unless facebook.nil?
|
31
|
-
Notifiers::FacebookNotifier.instance.load_configuration(facebook)
|
32
|
-
end
|
33
|
-
|
34
|
-
unless irc.nil?
|
35
|
-
Notifiers::IRCNotifier.instance.load_configuration(irc)
|
36
|
-
end
|
37
|
-
|
38
|
-
unless mail.nil?
|
39
|
-
Notifiers::MailNotifier.instance.load_configuration(mail)
|
23
|
+
options.each do |name, config|
|
24
|
+
notifier = Factories::NotifiersFactory.create(name)
|
25
|
+
notifier.load_configuration(config) unless notifier.nil?
|
40
26
|
end
|
41
27
|
end
|
42
|
-
|
43
|
-
private
|
44
|
-
attr_reader :twitter, :facebook, :irc, :mail
|
45
|
-
|
46
28
|
end
|
47
29
|
end
|
data/lib/feedbook/errors.rb
CHANGED
@@ -19,8 +19,16 @@ module Feedbook
|
|
19
19
|
Notifiers::FacebookNotifier.instance
|
20
20
|
when :irc, 'irc'
|
21
21
|
Notifiers::IRCNotifier.instance
|
22
|
+
when :mail, 'mail'
|
23
|
+
Notifiers::MailNotifier.instance
|
22
24
|
else
|
23
|
-
|
25
|
+
if Notifiers.const_defined?("#{type.capitalize}Notifier")
|
26
|
+
Notifiers.const_get("#{type.capitalize}Notifier").instance
|
27
|
+
elsif Notifiers.const_defined?("#{type.upcase}Notifier")
|
28
|
+
Notifiers.const_get("#{type.upcase}Notifier").instance
|
29
|
+
else
|
30
|
+
puts "notifier #{type} is not supported by Feedbook."
|
31
|
+
end
|
24
32
|
end
|
25
33
|
end
|
26
34
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'feedbook/liquid_extensions/filters/googl_shortener_filter'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'googl'
|
2
|
+
require 'liquid'
|
3
|
+
|
4
|
+
module Feedbook
|
5
|
+
module LiquidExtensions
|
6
|
+
module Filters
|
7
|
+
module GooglShortenerFilter
|
8
|
+
|
9
|
+
# Shorten links with goo.gl
|
10
|
+
# @param input [String] url
|
11
|
+
#
|
12
|
+
# @return [String] url in shorten form
|
13
|
+
def googl(input)
|
14
|
+
url = Googl.shorten(input)
|
15
|
+
url.short_url
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Liquid::Template.register_filter(Feedbook::LiquidExtensions::Filters::GooglShortenerFilter)
|
data/lib/feedbook/listener.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'timeloop'
|
3
3
|
require 'feedbook/feed'
|
4
|
+
require 'feedbook/plugins_manager'
|
4
5
|
require 'feedbook/errors'
|
5
6
|
require 'feedbook/configuration'
|
6
7
|
require 'feedbook/comparers/posts_comparer'
|
@@ -10,23 +11,16 @@ module Feedbook
|
|
10
11
|
|
11
12
|
# Starts listening on feeds and notifies if there is new post.
|
12
13
|
# @param path [String] configuration file path
|
13
|
-
|
14
|
+
# @param plugins_path [String] plugins directory path
|
15
|
+
def self.start(path, plugins_path)
|
14
16
|
handle_exceptions do
|
15
|
-
|
16
|
-
feeds, configuration = load_configuration(path)
|
17
|
-
feeds.each { |feed| feed.valid? }
|
18
|
-
puts 'completed.'
|
19
|
-
|
20
|
-
puts 'Loading notifiers... '
|
21
|
-
configuration.load_notifiers
|
22
|
-
puts 'completed.'
|
17
|
+
feeds, configuration = initialize_listener(path, plugins_path)
|
23
18
|
|
24
19
|
print 'Fetching feeds for the first use... '
|
25
20
|
observed_feeds = feeds.map do |feed|
|
26
21
|
{
|
27
|
-
feed:
|
28
|
-
|
29
|
-
new_posts: []
|
22
|
+
feed: feed,
|
23
|
+
posts: feed.fetch
|
30
24
|
}
|
31
25
|
end
|
32
26
|
puts 'completed.'
|
@@ -36,34 +30,104 @@ module Feedbook
|
|
36
30
|
|
37
31
|
puts 'Fetching feeds...'
|
38
32
|
observed_feeds.each do |feed|
|
39
|
-
|
40
|
-
|
41
|
-
difference = Comparers::PostsComparer.get_new_posts(feed[:old_posts], new_posts)
|
42
|
-
|
43
|
-
if difference.empty?
|
44
|
-
puts 'No new posts found.'
|
45
|
-
else
|
46
|
-
puts "#{difference.size} new posts found."
|
47
|
-
print 'Started sending notifications... '
|
48
|
-
end
|
49
|
-
|
50
|
-
difference.each do |post|
|
51
|
-
feed[:feed].notifications.each do |notification|
|
52
|
-
notification.notify(post)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
unless difference.empty?
|
57
|
-
puts 'completed.'
|
58
|
-
end
|
59
|
-
|
60
|
-
feed[:old_posts] = new_posts
|
61
|
-
feed[:new_posts] = []
|
33
|
+
observe_and_notify(feed)
|
62
34
|
end
|
63
35
|
end
|
64
36
|
end
|
65
37
|
end
|
66
38
|
|
39
|
+
# Starts listening on feeds and notifies if there is new post (offline mode).
|
40
|
+
# @param path [String] configuration file path
|
41
|
+
# @param plugins_path [String] plugins directory path
|
42
|
+
def self.start_offline(path, archive_path, plugins_path)
|
43
|
+
handle_exceptions do
|
44
|
+
feeds, configuration = initialize_listener(path, plugins_path)
|
45
|
+
|
46
|
+
observed_feeds = load_feeds_archive(archive_path)
|
47
|
+
|
48
|
+
if observed_feeds.blank?
|
49
|
+
print 'Fetching feeds for the first use... '
|
50
|
+
observed_feeds = feeds.map do |feed|
|
51
|
+
{
|
52
|
+
feed: feed,
|
53
|
+
posts: feed.fetch
|
54
|
+
}
|
55
|
+
end
|
56
|
+
puts 'completed.'
|
57
|
+
end
|
58
|
+
|
59
|
+
puts 'Fetching feeds...'
|
60
|
+
observed_feeds.each do |feed|
|
61
|
+
observe_and_notify(feed)
|
62
|
+
end
|
63
|
+
|
64
|
+
save_feeds_archive(archive_path, observed_feeds)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Load feeds from serialized YAML file.
|
69
|
+
# @param [String] path to YAML file with serialized objects
|
70
|
+
#
|
71
|
+
# @return [Array] Array of feeds with archived posts
|
72
|
+
def self.load_feeds_archive(path)
|
73
|
+
print 'Reading feeds from file... '
|
74
|
+
|
75
|
+
if File.exist? path
|
76
|
+
puts 'completed.'
|
77
|
+
YAML::load(File.read(path))
|
78
|
+
else
|
79
|
+
puts 'canceled. File does not exist.'
|
80
|
+
[]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Saves feeds into serialized YAML file
|
85
|
+
# @param path [String] path to file
|
86
|
+
# @param feeds [Array] Array with feeds to be saved
|
87
|
+
#
|
88
|
+
# @return [NilClass] nil
|
89
|
+
def self.save_feeds_archive(path, feeds)
|
90
|
+
print 'Saving feeds to file... '
|
91
|
+
|
92
|
+
File.open(path, 'w') do |f|
|
93
|
+
f.write YAML::dump(feeds)
|
94
|
+
end
|
95
|
+
|
96
|
+
puts 'completed.'
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# Single run of loop for listening for changes in RSS feeds and notifies about updates
|
101
|
+
# @param feed [Feedbook::Feed] requested feed to be observed (hash with feed and posts)
|
102
|
+
#
|
103
|
+
# @return [NilClass] nil
|
104
|
+
def self.observe_and_notify(feed)
|
105
|
+
new_posts = feed[:feed].fetch
|
106
|
+
|
107
|
+
difference = Comparers::PostsComparer.get_new_posts(feed[:posts], new_posts)
|
108
|
+
|
109
|
+
if difference.empty?
|
110
|
+
puts 'No new posts found.'
|
111
|
+
else
|
112
|
+
puts "#{difference.size} new posts found."
|
113
|
+
print 'Started sending notifications... '
|
114
|
+
end
|
115
|
+
|
116
|
+
difference.each do |post|
|
117
|
+
feed[:feed].notifications.each do |notification|
|
118
|
+
notification.notify(post)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
unless difference.empty?
|
123
|
+
puts 'completed.'
|
124
|
+
end
|
125
|
+
|
126
|
+
feed[:posts] = new_posts
|
127
|
+
|
128
|
+
feed
|
129
|
+
end
|
130
|
+
|
67
131
|
private
|
68
132
|
|
69
133
|
# Handle exceptions rescued from given block
|
@@ -72,23 +136,39 @@ module Feedbook
|
|
72
136
|
rescue Errors::InvalidFeedUrlError
|
73
137
|
abort 'feed url collection is not valid (contains empty or invalid urls)'
|
74
138
|
rescue Errors::InvalidIntervalFormatError
|
75
|
-
abort 'interval value in configuration is not
|
139
|
+
abort 'interval value in configuration is not valid (should be in format: "(Number)(TimeType)" where TimeType is s, m, h or d)'
|
76
140
|
rescue Errors::InvalidVariablesFormatError
|
77
141
|
abort 'invalid variables format in configuration (should be a key-value pairs)'
|
78
142
|
rescue Errors::NoConfigurationFileError => e
|
79
143
|
abort "configuration file could not be loaded: #{e.message}"
|
80
144
|
rescue Errors::NotifierConfigurationError => e
|
81
145
|
abort "notifier #{e.notifier} has invalid configuration (#{e.message})."
|
82
|
-
rescue Errors::NotifierNotifyError => e
|
83
|
-
p "notifier #{e.notifier} did not notify because of client error (#{e.message})."
|
84
146
|
rescue Errors::ParseFeedError => e
|
85
147
|
p "feed on #{e.url} could not be parsed because of fetching/parsing error."
|
86
|
-
rescue Errors::UnsupportedNotifierError => e
|
87
|
-
abort "notifier #{e.notifier} is not supported by Feedbook."
|
88
148
|
rescue Errors::TemplateSyntaxError
|
89
149
|
abort "one of your templates in configuration file is not valid."
|
90
150
|
end
|
91
151
|
|
152
|
+
# Initializes listener configuration, loads plugins and notifiers.
|
153
|
+
# @param path [String] config file path
|
154
|
+
# @param plugins_path [String] plugins directory path
|
155
|
+
#
|
156
|
+
# @return [[Array, Feedbook::Configuration]] feeds and Configuration instance
|
157
|
+
def self.initialize_listener(path, plugins_path)
|
158
|
+
print "Loading configuration from file #{path}... "
|
159
|
+
feeds, configuration = load_configuration(path)
|
160
|
+
feeds.each { |feed| feed.valid? }
|
161
|
+
puts 'completed.'
|
162
|
+
|
163
|
+
Feedbook::PluginsManager.load_plugins(plugins_path)
|
164
|
+
|
165
|
+
puts 'Loading notifiers... '
|
166
|
+
configuration.load_notifiers
|
167
|
+
puts 'completed.'
|
168
|
+
|
169
|
+
[feeds, configuration]
|
170
|
+
end
|
171
|
+
|
92
172
|
# Load configuration from given path
|
93
173
|
# @param path [String] configuration file path
|
94
174
|
#
|
@@ -107,16 +187,11 @@ module Feedbook
|
|
107
187
|
|
108
188
|
configuration_hash = config.fetch('configuration', {})
|
109
189
|
|
110
|
-
configuration = Configuration.new(
|
111
|
-
twitter: configuration_hash['twitter'],
|
112
|
-
facebook: configuration_hash['facebook'],
|
113
|
-
interval: configuration_hash['interval'],
|
114
|
-
)
|
190
|
+
configuration = Configuration.new(configuration_hash)
|
115
191
|
|
116
192
|
[feeds, configuration]
|
117
193
|
rescue Errno::ENOENT => e
|
118
194
|
raise Errors::NoConfigurationFileError.new(e)
|
119
195
|
end
|
120
|
-
|
121
196
|
end
|
122
|
-
end
|
197
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'singleton'
|
2
2
|
require 'koala'
|
3
3
|
require 'feedbook/errors/notifier_configuration_error'
|
4
|
-
require 'feedbook/errors/notifier_notify_error'
|
5
4
|
|
6
5
|
module Feedbook
|
7
6
|
module Notifiers
|
@@ -21,17 +20,17 @@ module Feedbook
|
|
21
20
|
puts "New message has been notified on Facebook: #{message}"
|
22
21
|
end
|
23
22
|
rescue Koala::KoalaError => e
|
24
|
-
|
23
|
+
p "FacebookNotifier did not notify because of client error (#{e.message})."
|
25
24
|
end
|
26
25
|
|
27
26
|
# Load configuration for FacebookNotifier
|
28
|
-
# @param configuration = {} [Hash] Configuration hash (required: token)
|
29
|
-
#
|
27
|
+
# @param configuration = {} [Hash] Configuration hash (required: token, optional: app_secret)
|
28
|
+
#
|
30
29
|
# @return [NilClass] nil
|
31
30
|
# @raise [Feedbook::Errors::NotifierConfigurationError] if notifier configuration fails
|
32
31
|
def load_configuration(configuration = {})
|
33
|
-
@client = Koala::Facebook::API.new(configuration.fetch('token'))
|
34
|
-
|
32
|
+
@client = Koala::Facebook::API.new(configuration.fetch('token'), configuration.fetch('app_secret', nil))
|
33
|
+
|
35
34
|
puts 'Configuration loaded for FacebookNotifier'
|
36
35
|
rescue Koala::KoalaError => e
|
37
36
|
raise Errors::NotifierConfigurationError.new(:facebook, e.message)
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'singleton'
|
2
2
|
require 'twitter'
|
3
3
|
require 'feedbook/errors/notifier_configuration_error'
|
4
|
-
require 'feedbook/errors/notifier_notify_error'
|
5
4
|
|
6
5
|
module Feedbook
|
7
6
|
module Notifiers
|
@@ -10,9 +9,9 @@ module Feedbook
|
|
10
9
|
|
11
10
|
# Sends notification to Twitter
|
12
11
|
# @param message [String] message to be send to Twitter
|
13
|
-
#
|
12
|
+
#
|
14
13
|
# @return [NilClass] nil
|
15
|
-
# @raise [Feedbook::Errors::NotifierNotifyError] if notify method fails
|
14
|
+
# @raise [Feedbook::Errors::NotifierNotifyError] if notify method fails
|
16
15
|
def notify(message)
|
17
16
|
if client.nil?
|
18
17
|
puts "Message has not been notified on Twitter: #{message} because of invalid client configuration"
|
@@ -21,18 +20,18 @@ module Feedbook
|
|
21
20
|
puts "New message has been notified on Twitter: #{message}"
|
22
21
|
end
|
23
22
|
rescue Twitter::Error => e
|
24
|
-
|
23
|
+
p "TwitterNotifier did not notify because of client error (#{e.message})."
|
25
24
|
end
|
26
25
|
|
27
26
|
# Load configuration for TwitterNotifier
|
28
27
|
# @param configuration = {} [Hash] Configuration hash (required: consumer_key, consumer_secret, access_token, access_token_secret)
|
29
|
-
#
|
28
|
+
#
|
30
29
|
# @return [NilClass] nil
|
31
|
-
# @raise [Feedbook::Errors::NotifierConfigurationError] if notifier configuration fails
|
30
|
+
# @raise [Feedbook::Errors::NotifierConfigurationError] if notifier configuration fails
|
32
31
|
def load_configuration(configuration = {})
|
33
32
|
@client = Twitter::REST::Client.new do |config|
|
34
|
-
config.consumer_key = configuration.fetch('
|
35
|
-
config.consumer_secret = configuration.fetch('
|
33
|
+
config.consumer_key = configuration.fetch('api_key')
|
34
|
+
config.consumer_secret = configuration.fetch('api_secret')
|
36
35
|
config.access_token = configuration.fetch('access_token')
|
37
36
|
config.access_token_secret = configuration.fetch('access_token_secret')
|
38
37
|
end
|
@@ -46,4 +45,4 @@ module Feedbook
|
|
46
45
|
attr_reader :client
|
47
46
|
end
|
48
47
|
end
|
49
|
-
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Feedbook
|
2
|
+
class PluginsManager
|
3
|
+
|
4
|
+
# Loads plugins and extensions from given path.
|
5
|
+
# @param path [String] plugins directory path
|
6
|
+
#
|
7
|
+
# @return [NilClass] nil
|
8
|
+
def self.load_plugins(path)
|
9
|
+
print "Loading plugins from #{path}... "
|
10
|
+
if File.directory? path
|
11
|
+
Dir[File.join(path, '**', '*.rb')].sort.each do |f|
|
12
|
+
require f
|
13
|
+
end
|
14
|
+
puts 'completed.'
|
15
|
+
else
|
16
|
+
puts "Plugins directory could not be found in #{path}."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/feedbook/version.rb
CHANGED
@@ -4,16 +4,16 @@ describe Feedbook::Configuration do
|
|
4
4
|
|
5
5
|
let(:hash) do
|
6
6
|
{
|
7
|
-
twitter
|
8
|
-
facebook
|
9
|
-
irc
|
10
|
-
interval
|
7
|
+
'twitter' => {},
|
8
|
+
'facebook' => {},
|
9
|
+
'irc' => {},
|
10
|
+
'interval' => '5m'
|
11
11
|
}
|
12
12
|
end
|
13
13
|
|
14
14
|
before :each do
|
15
15
|
allow(Feedbook::Helpers::TimeIntervalParser).to receive(:parse).with('5m').and_return(300)
|
16
|
-
allow(Feedbook::Helpers::TimeIntervalParser).to receive(:parse).with(
|
16
|
+
allow(Feedbook::Helpers::TimeIntervalParser).to receive(:parse).with(nil).and_raise(Feedbook::Errors::InvalidIntervalFormatError.new)
|
17
17
|
end
|
18
18
|
|
19
19
|
subject { Feedbook::Configuration.new(hash) }
|
@@ -14,6 +14,11 @@ describe Feedbook::Factories::NotifiersFactory do
|
|
14
14
|
it { expect(Feedbook::Factories::NotifiersFactory.create(:irc)).to be(Feedbook::Notifiers::IRCNotifier.instance) }
|
15
15
|
end
|
16
16
|
|
17
|
+
context 'MailNotifier' do
|
18
|
+
it { expect(Feedbook::Factories::NotifiersFactory.create('mail')).to be(Feedbook::Notifiers::MailNotifier.instance) }
|
19
|
+
it { expect(Feedbook::Factories::NotifiersFactory.create(:mail)).to be(Feedbook::Notifiers::MailNotifier.instance) }
|
20
|
+
end
|
21
|
+
|
17
22
|
context 'NullNotifier' do
|
18
23
|
it { expect(Feedbook::Factories::NotifiersFactory.create('null')).to be(Feedbook::Notifiers::NullNotifier.instance) }
|
19
24
|
it { expect(Feedbook::Factories::NotifiersFactory.create(:null)).to be(Feedbook::Notifiers::NullNotifier.instance) }
|
@@ -24,5 +29,41 @@ describe Feedbook::Factories::NotifiersFactory do
|
|
24
29
|
it { expect(Feedbook::Factories::NotifiersFactory.create(:twitter)).to be(Feedbook::Notifiers::TwitterNotifier.instance) }
|
25
30
|
end
|
26
31
|
|
32
|
+
context 'Notifier is not defined in Factory' do
|
33
|
+
context 'and Notifier exists as TestNotifier' do
|
34
|
+
before :each do
|
35
|
+
expect(Feedbook::Notifiers).to receive(:const_defined?).with('TestNotifier').and_return(true)
|
36
|
+
expect(Feedbook::Notifiers).to receive(:const_get).with('TestNotifier').and_return(Feedbook::Notifiers::NullNotifier)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'returns instance of given Notifier' do
|
40
|
+
expect(Feedbook::Factories::NotifiersFactory.create('test')).to be(Feedbook::Notifiers::NullNotifier.instance)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'and Notifier exists as TESTNotifier' do
|
45
|
+
before :each do
|
46
|
+
expect(Feedbook::Notifiers).to receive(:const_defined?).with('TestNotifier').and_return(false)
|
47
|
+
expect(Feedbook::Notifiers).to receive(:const_defined?).with('TESTNotifier').and_return(true)
|
48
|
+
expect(Feedbook::Notifiers).to receive(:const_get).with('TESTNotifier').and_return(Feedbook::Notifiers::NullNotifier)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns instance of given Notifier' do
|
52
|
+
expect(Feedbook::Factories::NotifiersFactory.create('test')).to be(Feedbook::Notifiers::NullNotifier.instance)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'and Notifier does not exist' do
|
57
|
+
before :each do
|
58
|
+
expect(Feedbook::Notifiers).to receive(:const_defined?).with('TestNotifier').and_return(false)
|
59
|
+
expect(Feedbook::Notifiers).to receive(:const_defined?).with('TESTNotifier').and_return(false)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'does nothing' do
|
63
|
+
expect(Feedbook::Factories::NotifiersFactory.create('test')).to be(nil)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
27
68
|
end
|
28
69
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Feedbook::LiquidExtensions::Filters::GooglShortenerFilter do
|
4
|
+
|
5
|
+
describe '#googl' do
|
6
|
+
before :each do
|
7
|
+
allow(Googl).to receive(:shorten).with('https://github.com/pinoss').and_return(OpenStruct.new(short_url: 'http://goo.gl/jExQ6W'))
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'converts given link into shorten form by Googl API service' do
|
11
|
+
class TestClass
|
12
|
+
include Feedbook::LiquidExtensions::Filters::GooglShortenerFilter
|
13
|
+
end
|
14
|
+
|
15
|
+
expect(TestClass.new.googl('https://github.com/pinoss')).to eq('http://goo.gl/jExQ6W')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -15,7 +15,10 @@ describe Feedbook::Listener do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'parses hash and creates Feed instance' do
|
18
|
+
expect(Feedbook::PluginsManager).to receive(:load_plugins).with('./plugins')
|
19
|
+
|
18
20
|
allow(configuration).to receive(:load_notifiers)
|
21
|
+
|
19
22
|
feeds.each do |feed|
|
20
23
|
expect(feed).to receive(:fetch)
|
21
24
|
expect(feed).to receive(:valid?)
|
@@ -23,7 +26,120 @@ describe Feedbook::Listener do
|
|
23
26
|
|
24
27
|
expect(Object).to receive(:every).with(300).and_return(300)
|
25
28
|
|
26
|
-
subject.start('feedbook.yml')
|
29
|
+
subject.start('feedbook.yml', './plugins')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#start_offline' do
|
34
|
+
|
35
|
+
context 'there is no file with archived feeds' do
|
36
|
+
let(:configuration) { double }
|
37
|
+
let(:feeds) { [double, double, double] }
|
38
|
+
let(:feeds_with_posts) do
|
39
|
+
feeds.map do |feed|
|
40
|
+
{
|
41
|
+
feed: feed,
|
42
|
+
posts: nil
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
before :each do
|
48
|
+
allow(subject).to receive(:load_configuration).with('feedbook.yml').and_return([feeds, configuration])
|
49
|
+
allow(subject).to receive(:load_feeds_archive).with('feedbook_offline.yml').and_return([])
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'parses hash and creates Feed instance' do
|
53
|
+
expect(Feedbook::PluginsManager).to receive(:load_plugins).with('./plugins')
|
54
|
+
|
55
|
+
allow(configuration).to receive(:load_notifiers)
|
56
|
+
|
57
|
+
feeds.each do |feed|
|
58
|
+
expect(feed).to receive(:fetch)
|
59
|
+
expect(feed).to receive(:valid?)
|
60
|
+
expect(subject).to receive(:observe_and_notify).with({
|
61
|
+
feed: feed,
|
62
|
+
posts: nil
|
63
|
+
})
|
64
|
+
end
|
65
|
+
|
66
|
+
expect(subject).to receive(:save_feeds_archive).with('feedbook_offline.yml', feeds_with_posts)
|
67
|
+
|
68
|
+
subject.start_offline('feedbook.yml', 'feedbook_offline.yml', './plugins')
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'there is file with archived feeds' do
|
73
|
+
let(:configuration) { double }
|
74
|
+
let(:feeds) { [double, double, double] }
|
75
|
+
|
76
|
+
before :each do
|
77
|
+
allow(subject).to receive(:load_configuration).with('feedbook.yml').and_return([feeds, configuration])
|
78
|
+
allow(subject).to receive(:load_feeds_archive).with('feedbook_offline.yml').and_return(feeds)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'parses hash and creates Feed instance' do
|
82
|
+
expect(Feedbook::PluginsManager).to receive(:load_plugins).with('./plugins')
|
83
|
+
|
84
|
+
allow(configuration).to receive(:load_notifiers)
|
85
|
+
|
86
|
+
feeds.each do |feed|
|
87
|
+
expect(feed).to receive(:valid?)
|
88
|
+
expect(subject).to receive(:observe_and_notify).with(feed)
|
89
|
+
end
|
90
|
+
|
91
|
+
expect(subject).to receive(:save_feeds_archive).with('feedbook_offline.yml', feeds)
|
92
|
+
|
93
|
+
subject.start_offline('feedbook.yml', 'feedbook_offline.yml', './plugins')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe '#observe_and_notify' do
|
99
|
+
|
100
|
+
context 'there are new posts' do
|
101
|
+
let(:feed) do
|
102
|
+
{
|
103
|
+
posts: [OpenStruct.new(url: '1'), OpenStruct.new(url: '2')],
|
104
|
+
feed: double
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
let(:notifications) { [double, double] }
|
109
|
+
|
110
|
+
before :each do
|
111
|
+
expect(feed[:feed]).to receive(:fetch).and_return([OpenStruct.new(url: '1'), OpenStruct.new(url: '2'), OpenStruct.new(url: '3'), OpenStruct.new(url: '4')])
|
112
|
+
expect(feed[:feed]).to receive(:notifications).twice.and_return(notifications)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'parses hash and creates Feed instance' do
|
116
|
+
expect(Feedbook::Comparers::PostsComparer).to receive(:get_new_posts).with([OpenStruct.new(url: '1'), OpenStruct.new(url: '2')], [OpenStruct.new(url: '1'), OpenStruct.new(url: '2'), OpenStruct.new(url: '3'), OpenStruct.new(url: '4')]).and_return([OpenStruct.new(url: '3'), OpenStruct.new(url: '4')])
|
117
|
+
notifications.each do |notification|
|
118
|
+
expect(notification).to receive(:notify).with(OpenStruct.new(url: '3')).and_return(nil)
|
119
|
+
expect(notification).to receive(:notify).with(OpenStruct.new(url: '4')).and_return(nil)
|
120
|
+
end
|
121
|
+
|
122
|
+
expect(subject.observe_and_notify(feed)[:posts]).to eq([OpenStruct.new(url: '1'), OpenStruct.new(url: '2'), OpenStruct.new(url: '3'), OpenStruct.new(url: '4')])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'there are no new posts' do
|
127
|
+
let(:feed) do
|
128
|
+
{
|
129
|
+
posts: [OpenStruct.new(url: '1'), OpenStruct.new(url: '2')],
|
130
|
+
feed: double
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
134
|
+
before :each do
|
135
|
+
expect(feed[:feed]).to receive(:fetch).and_return([OpenStruct.new(url: '1'), OpenStruct.new(url: '2')])
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'parses hash and creates Feed instance' do
|
139
|
+
expect(Feedbook::Comparers::PostsComparer).to receive(:get_new_posts).with([OpenStruct.new(url: '1'), OpenStruct.new(url: '2')], [OpenStruct.new(url: '1'), OpenStruct.new(url: '2')]).and_return([])
|
140
|
+
|
141
|
+
expect(subject.observe_and_notify(feed)[:posts]).to eq([OpenStruct.new(url: '1'), OpenStruct.new(url: '2')])
|
142
|
+
end
|
27
143
|
end
|
28
144
|
end
|
29
145
|
end
|
@@ -8,13 +8,25 @@ describe Feedbook::Notifiers::FacebookNotifier do
|
|
8
8
|
}
|
9
9
|
end
|
10
10
|
|
11
|
+
let(:hash_with_app_token) do
|
12
|
+
{
|
13
|
+
'token' => 'token123',
|
14
|
+
'app_secret' => 'app_token_123'
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
11
18
|
subject { Feedbook::Notifiers::FacebookNotifier.instance }
|
12
19
|
|
13
20
|
describe '#load_configuration' do
|
14
21
|
it 'parses configuration hash and creates client instance' do
|
15
|
-
expect(Koala::Facebook::API).to receive(:new).with('token123')
|
22
|
+
expect(Koala::Facebook::API).to receive(:new).with('token123', nil)
|
16
23
|
subject.load_configuration(hash)
|
17
24
|
end
|
25
|
+
|
26
|
+
it 'parses configuration hash and creates client instance with app secret' do
|
27
|
+
expect(Koala::Facebook::API).to receive(:new).with('token123', 'app_token_123')
|
28
|
+
subject.load_configuration(hash_with_app_token)
|
29
|
+
end
|
18
30
|
end
|
19
31
|
|
20
32
|
describe '#notify' do
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Feedbook::PluginsManager do
|
4
|
+
|
5
|
+
describe '#load_plugins' do
|
6
|
+
|
7
|
+
context 'when plugins directory exists' do
|
8
|
+
before :each do
|
9
|
+
expect(File).to receive(:directory?).with('./plugins').and_return(true)
|
10
|
+
expect(File).to receive(:join).with('./plugins', '**', '*.rb').and_return('./plugins/**/.fb')
|
11
|
+
expect(Dir).to receive(:[]).with('./plugins/**/.fb').and_return(['time'])
|
12
|
+
expect(Object).to receive(:require).with('time')
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'requires all file inside plugins directory' do
|
16
|
+
Feedbook::PluginsManager.load_plugins('./plugins')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when plugins directory do not exists' do
|
21
|
+
before :each do
|
22
|
+
expect(File).to receive(:directory?).with('./plugins').and_return(false)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'does nothing' do
|
26
|
+
Feedbook::PluginsManager.load_plugins('./plugins')
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: feedbook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maciej Paruszewski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: feedjira
|
@@ -122,6 +122,20 @@ dependencies:
|
|
122
122
|
- - ~>
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '2.6'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: googl
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ~>
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0.6'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.6'
|
125
139
|
- !ruby/object:Gem::Dependency
|
126
140
|
name: irc-notify
|
127
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,20 +206,6 @@ dependencies:
|
|
192
206
|
- - ! '>='
|
193
207
|
- !ruby/object:Gem::Version
|
194
208
|
version: '0'
|
195
|
-
- !ruby/object:Gem::Dependency
|
196
|
-
name: pry-debugger
|
197
|
-
requirement: !ruby/object:Gem::Requirement
|
198
|
-
requirements:
|
199
|
-
- - ! '>='
|
200
|
-
- !ruby/object:Gem::Version
|
201
|
-
version: '0'
|
202
|
-
type: :development
|
203
|
-
prerelease: false
|
204
|
-
version_requirements: !ruby/object:Gem::Requirement
|
205
|
-
requirements:
|
206
|
-
- - ! '>='
|
207
|
-
- !ruby/object:Gem::Version
|
208
|
-
version: '0'
|
209
209
|
description: Feedbook is a simple console application that allows to notify on IRC,
|
210
210
|
mail and social media (like Twitter and Facebook) about RSS/Atom updates.
|
211
211
|
email:
|
@@ -233,13 +233,14 @@ files:
|
|
233
233
|
- lib/feedbook/errors/invalid_variables_format_error.rb
|
234
234
|
- lib/feedbook/errors/no_configuration_file_error.rb
|
235
235
|
- lib/feedbook/errors/notifier_configuration_error.rb
|
236
|
-
- lib/feedbook/errors/notifier_notify_error.rb
|
237
236
|
- lib/feedbook/errors/parse_feed_error.rb
|
238
237
|
- lib/feedbook/errors/template_syntax_error.rb
|
239
238
|
- lib/feedbook/errors/unsupported_notifier_error.rb
|
240
239
|
- lib/feedbook/factories/notifiers_factory.rb
|
241
240
|
- lib/feedbook/feed.rb
|
242
241
|
- lib/feedbook/helpers/time_interval_parser.rb
|
242
|
+
- lib/feedbook/liquid_extensions.rb
|
243
|
+
- lib/feedbook/liquid_extensions/filters/googl_shortener_filter.rb
|
243
244
|
- lib/feedbook/listener.rb
|
244
245
|
- lib/feedbook/notification.rb
|
245
246
|
- lib/feedbook/notifiers.rb
|
@@ -248,6 +249,7 @@ files:
|
|
248
249
|
- lib/feedbook/notifiers/mail_notifier.rb
|
249
250
|
- lib/feedbook/notifiers/null_notifier.rb
|
250
251
|
- lib/feedbook/notifiers/twitter_notifier.rb
|
252
|
+
- lib/feedbook/plugins_manager.rb
|
251
253
|
- lib/feedbook/post.rb
|
252
254
|
- lib/feedbook/version.rb
|
253
255
|
- spec/spec_helper.rb
|
@@ -256,6 +258,7 @@ files:
|
|
256
258
|
- spec/unit/lib/factories/notifiers_factory_spec.rb
|
257
259
|
- spec/unit/lib/feed_spec.rb
|
258
260
|
- spec/unit/lib/helpers/time_interval_parser_spec.rb
|
261
|
+
- spec/unit/lib/liquid_extensions/filters/googl_shortener_filter_spec.rb
|
259
262
|
- spec/unit/lib/listener_spec.rb
|
260
263
|
- spec/unit/lib/notification_spec.rb
|
261
264
|
- spec/unit/lib/notifiers/facebook_notifier_spec.rb
|
@@ -263,6 +266,7 @@ files:
|
|
263
266
|
- spec/unit/lib/notifiers/mail_notifier_spec.rb
|
264
267
|
- spec/unit/lib/notifiers/null_notifier_spec.rb
|
265
268
|
- spec/unit/lib/notifiers/twitter_notifier_spec.rb
|
269
|
+
- spec/unit/lib/plugins_manager_spec.rb
|
266
270
|
- spec/unit/lib/post_spec.rb
|
267
271
|
homepage: https://github.com/pinoss/feedbook
|
268
272
|
licenses:
|
@@ -296,6 +300,7 @@ test_files:
|
|
296
300
|
- spec/unit/lib/factories/notifiers_factory_spec.rb
|
297
301
|
- spec/unit/lib/feed_spec.rb
|
298
302
|
- spec/unit/lib/helpers/time_interval_parser_spec.rb
|
303
|
+
- spec/unit/lib/liquid_extensions/filters/googl_shortener_filter_spec.rb
|
299
304
|
- spec/unit/lib/listener_spec.rb
|
300
305
|
- spec/unit/lib/notification_spec.rb
|
301
306
|
- spec/unit/lib/notifiers/facebook_notifier_spec.rb
|
@@ -303,4 +308,5 @@ test_files:
|
|
303
308
|
- spec/unit/lib/notifiers/mail_notifier_spec.rb
|
304
309
|
- spec/unit/lib/notifiers/null_notifier_spec.rb
|
305
310
|
- spec/unit/lib/notifiers/twitter_notifier_spec.rb
|
311
|
+
- spec/unit/lib/plugins_manager_spec.rb
|
306
312
|
- spec/unit/lib/post_spec.rb
|