audrey2 0.2.1 → 0.3.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.
data/README.rdoc CHANGED
@@ -7,6 +7,20 @@ Audrey 2.0 is a gem for feed processing and aggregation.
7
7
  The initial codebase is an adaptation of several other prototypes. It suffers from
8
8
  severe shortages of documentation and testing. Both are coming soon.
9
9
 
10
+ == Release notes
11
+
12
+ The 0.3.0 version of Audrey 2.0 makes three changes which could break compatibility with
13
+ existing installations. They are all very easy to deal with:
14
+
15
+ 1) The default location of the configuration file has moved from /etc/audrey2/audrey2.conf
16
+ to /etc/audrey2.conf
17
+
18
+ 2) In a theme's entry.haml when you reference data in the entry hash you now need to index
19
+ the hash using symbols rather than strings: entry[:title] replaces entry['title'].
20
+
21
+ 3) If email notification of errors is configured via SMTP you now need to identify the
22
+ SMTP server with the key 'address' instead of 'server' in Audrey 2.0's configuration file.
23
+
10
24
  == Installation
11
25
 
12
26
  gem install audrey2
data/Rakefile CHANGED
@@ -5,13 +5,15 @@ begin
5
5
  require 'jeweler'
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "audrey2"
8
- gem.summary = "Gem for feed processing and aggregation"
9
- gem.description = "Gem for feed processing and aggregation"
8
+ gem.summary = "Feed processing and aggregation"
9
+ gem.description = "Audrey 2.0 is a command-line utility for customizable feed processing, aggregation, and output."
10
10
  gem.email = "sven.aas@gmail.com"
11
11
  gem.homepage = "http://github.com/svenaas/audrey2"
12
12
  gem.authors = ["Sven Aas"]
13
13
  gem.add_dependency "feed-normalizer", "~>1.5.2"
14
14
  gem.add_dependency "haml", "~>3.0.13"
15
+ gem.add_development_dependency "shoulda", ">= 2.11.1"
16
+ gem.add_development_dependency "mocha", ">= 0.9.8"
15
17
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
18
  end
17
19
  Jeweler::GemcutterTasks.new
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.3.0
data/audrey2.conf.sample CHANGED
@@ -31,7 +31,7 @@ themes_folder: ./themes
31
31
  # from: Audrey 2.0 <noreply@test.com>
32
32
  # via: smtp
33
33
  # smtp:
34
- # server: smtp.test.com
34
+ # address: smtp.test.com
35
35
  # port: 25
36
36
  # user_name: test
37
37
  # password: password
data/audrey2.gemspec CHANGED
@@ -5,13 +5,13 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{audrey2}
8
- s.version = "0.2.1"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sven Aas"]
12
- s.date = %q{2010-07-30}
12
+ s.date = %q{2010-08-17}
13
13
  s.default_executable = %q{feedme}
14
- s.description = %q{Gem for feed processing and aggregation}
14
+ s.description = %q{Audrey 2.0 is a command-line utility for customizable feed processing, aggregation, and output.}
15
15
  s.email = %q{sven.aas@gmail.com}
16
16
  s.executables = ["feedme"]
17
17
  s.extra_rdoc_files = [
@@ -28,13 +28,33 @@ Gem::Specification.new do |s|
28
28
  "audrey2.conf.sample",
29
29
  "audrey2.gemspec",
30
30
  "bin/feedme",
31
- "lib/audrey2.rb"
31
+ "lib/audrey2.rb",
32
+ "test/helper.rb",
33
+ "test/test_config.rb",
34
+ "test/test_email.rb",
35
+ "test/test_misc.rb",
36
+ "test/test_options.rb",
37
+ "test/test_parse.rb",
38
+ "test/test_recipes.rb",
39
+ "test/test_sort.rb",
40
+ "test/test_themes.rb"
32
41
  ]
33
42
  s.homepage = %q{http://github.com/svenaas/audrey2}
34
43
  s.rdoc_options = ["--charset=UTF-8"]
35
44
  s.require_paths = ["lib"]
36
45
  s.rubygems_version = %q{1.3.7}
37
- s.summary = %q{Gem for feed processing and aggregation}
46
+ s.summary = %q{Feed processing and aggregation}
47
+ s.test_files = [
48
+ "test/helper.rb",
49
+ "test/test_config.rb",
50
+ "test/test_email.rb",
51
+ "test/test_misc.rb",
52
+ "test/test_options.rb",
53
+ "test/test_parse.rb",
54
+ "test/test_recipes.rb",
55
+ "test/test_sort.rb",
56
+ "test/test_themes.rb"
57
+ ]
38
58
 
39
59
  if s.respond_to? :specification_version then
40
60
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
@@ -43,13 +63,19 @@ Gem::Specification.new do |s|
43
63
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
44
64
  s.add_runtime_dependency(%q<feed-normalizer>, ["~> 1.5.2"])
45
65
  s.add_runtime_dependency(%q<haml>, ["~> 3.0.13"])
66
+ s.add_development_dependency(%q<shoulda>, [">= 2.11.1"])
67
+ s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
46
68
  else
47
69
  s.add_dependency(%q<feed-normalizer>, ["~> 1.5.2"])
48
70
  s.add_dependency(%q<haml>, ["~> 3.0.13"])
71
+ s.add_dependency(%q<shoulda>, [">= 2.11.1"])
72
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
49
73
  end
50
74
  else
51
75
  s.add_dependency(%q<feed-normalizer>, ["~> 1.5.2"])
52
76
  s.add_dependency(%q<haml>, ["~> 3.0.13"])
77
+ s.add_dependency(%q<shoulda>, [">= 2.11.1"])
78
+ s.add_dependency(%q<mocha>, [">= 0.9.8"])
53
79
  end
54
80
  end
55
81
 
data/bin/feedme CHANGED
@@ -1,45 +1,14 @@
1
1
  #!/usr/bin/ruby
2
-
3
2
  require 'rubygems'
4
3
  require 'audrey2'
5
- require 'optparse'
6
-
7
- options = {}
8
-
9
- opts = OptionParser.new do |opts|
10
- opts.banner = "Usage: feedme [OPTIONS] recipes"
11
-
12
- options[:config] = '/etc/audrey2/audrey2.conf'
13
- opts.on( '--config CONFIGFILE', "Location of config file", "(default: /etc/audrey2/audrey2.conf)" ) do |f|
14
- options[:config] = f
15
- end
16
-
17
- opts.on_tail( '-h', '--help', 'Display this screen' ) do
18
- puts opts
19
- exit
20
- end
21
- end
22
-
23
- begin
24
- opts.parse! ARGV
25
- options
26
- rescue OptionParser::InvalidOption => e
27
- $stderr.puts e
28
- $stderr.puts opts
29
- exit 1
30
- rescue OptionParser::MissingArgument => e
31
- $stderr.puts e
32
- $stderr.puts opts
33
- exit 1
34
- end
35
4
 
5
+ options = Audrey2::Options.parse(ARGV)
6
+
36
7
  recipes = ARGV
37
- if recipes.length == 0
38
- $stderr.puts "You must specify at least one recipe to feed me"
39
- $stderr.puts opts
40
- exit 1
41
- end
42
8
 
43
- audrey2 = Audrey2::Aggregator.new(options[:config])
44
-
45
- recipes.each { |recipe| audrey2.feed_me(recipe) }
9
+ if recipes.empty?
10
+ abort "You must specify at least one recipe to feed me"
11
+ else
12
+ audrey2 = Audrey2::Aggregator.new(options[:config])
13
+ recipes.each { |recipe| audrey2.feed_me(recipe) }
14
+ end
data/lib/audrey2.rb CHANGED
@@ -3,8 +3,59 @@ require 'yaml'
3
3
  require 'feed-normalizer'
4
4
  require 'open-uri'
5
5
  require 'haml'
6
+ require 'optparse'
7
+
8
+ module HashExtensions # Adapted from http://gist.github.com/151324 by Avdi Grimm and Paul Berry
9
+ def recursively_symbolize_keys
10
+ inject({}) do |acc, (k,v)|
11
+ key = String === k ? k.to_sym : k
12
+ value = case v
13
+ when Hash
14
+ v.recursively_symbolize_keys
15
+ when Array
16
+ v.collect { |e| Hash === e ? e.recursively_symbolize_keys : e }
17
+ else
18
+ v
19
+ end
20
+ acc[key] = value
21
+ acc
22
+ end
23
+ end
24
+ end
25
+ Hash.send(:include, HashExtensions)
6
26
 
7
27
  module Audrey2
28
+ class Options
29
+ def self.parse(args)
30
+ options = {}
31
+
32
+ opts = OptionParser.new do |opts|
33
+ opts.banner = "Usage: feedme [OPTIONS] recipes"
34
+
35
+ options[:config] = '/etc/audrey2.conf'
36
+ opts.on( '--config CONFIGFILE', "Location of config file", "(default: /etc/audrey2.conf)" ) do |f|
37
+ options[:config] = f
38
+ end
39
+
40
+ opts.on_tail( '-h', '--help', 'Display this screen' ) do
41
+ puts opts
42
+ exit
43
+ end
44
+
45
+ begin
46
+ opts.parse! args
47
+ options
48
+ rescue OptionParser::ParseError => e
49
+ warn e.message
50
+ $stderr.puts opts
51
+ exit 1
52
+ end
53
+ end
54
+
55
+ options
56
+ end
57
+ end
58
+
8
59
 
9
60
  class Aggregator
10
61
  def initialize(configfile)
@@ -15,19 +66,21 @@ module Audrey2
15
66
  begin
16
67
  # Load recipe and theme and make sure everything is in order
17
68
  recipe = load_recipe(recipe_name)
18
- init_theme(recipe['theme'])
19
- output_file = recipe['output_file']
69
+ output_file = recipe[:output_file]
20
70
  verify_output_file(output_file)
21
- max_entries = recipe['max_entries'] || 1000
71
+ max_entries = recipe[:max_entries] || 1000
72
+
73
+ # Load theme
74
+ init_theme(recipe[:theme])
22
75
 
23
76
  # Download and parse the feeds
24
77
  entry_sources = {}
25
- feeds = recipe['feeds'].collect { |feed| parse_feed(feed, entry_sources) }
78
+ feeds = recipe[:feeds].collect { |feed| parse_feed(feed, entry_sources) }
26
79
 
27
80
  # Aggregate and sort the entries
28
81
  entries = []
29
82
  feeds.each { |feed| entries += feed.entries }
30
- sort!(entries)
83
+ entries.sort! &entry_sort_comparator
31
84
 
32
85
  # Prepare template evaluation scope including any helper code defined in the theme
33
86
  scope = Object.new
@@ -42,8 +95,9 @@ module Audrey2
42
95
  end
43
96
 
44
97
  File.open(output_file, 'w') { |f| f << output }
45
-
46
98
  rescue Exception => e
99
+ # NOTE: This also catches SystemExit as can be raise by Kernel#exit when recipes
100
+ # and themes are loaded and verified. Is it good to handle those events here? Perhaps ...
47
101
  if @email
48
102
  email(<<-EOF
49
103
  An exception occurred while running recipe #{recipe_name}
@@ -67,24 +121,25 @@ EOF
67
121
  return unless @email
68
122
 
69
123
  mail = Mail.new
70
- mail[:from] = @email['from']
71
- mail[:to] = @email['to']
124
+ mail[:from] = @email[:from]
125
+ mail[:to] = @email[:to]
72
126
  mail[:subject] = "[AUDREY 2.0] Exception Notification"
73
127
  mail[:body] = e
74
-
75
- case @email['via']
76
- when 'sendmail'
128
+
129
+ @email[:via] ||= 'sendmail' # Do this somewhere else?
130
+ case @email[:via].to_sym # Do this somewhere else too?
131
+ when :sendmail
77
132
  mail.delivery_method :sendmail
78
- when 'smtp'
79
- raise "Missing SMTP configuration" unless @email['smtp']
133
+ when :smtp
134
+ raise "Missing SMTP configuration" unless @email[:smtp]
80
135
  smtp = {
81
- :address => @email['smtp']['server'] || 'localhost',
82
- :port => @email['smtp']['port'] || 25
136
+ :address => @email[:smtp][:address] || 'localhost',
137
+ :port => @email[:smtp][:port] || 25
83
138
  }
84
- smtp[:domain] = @email['smtp']['domain'] if @email['smtp']['domain']
85
- smtp[:user_name] = @email['smtp']['user_name'] if @email['smtp']['user_name']
86
- smtp[:password] = @email['smtp']['password'] if @email['smtp']['password']
87
- smtp[:authentication] = @email['smtp']['authentication'] if @email['smtp']['authentication']
139
+ smtp[:domain] = @email[:smtp][:domain] if @email[:smtp][:domain]
140
+ smtp[:user_name] = @email[:smtp][:user_name] if @email[:smtp][:user_name]
141
+ smtp[:password] = @email[:smtp][:password] if @email[:smtp][:password]
142
+ smtp[:authentication] = @email[:smtp][:authentication] if @email[:smtp][:authentication]
88
143
  mail.delivery_method :smtp, smtp
89
144
  end
90
145
 
@@ -129,38 +184,47 @@ EOF
129
184
  @helper_code = nil
130
185
  if File.exist? helper_file
131
186
  if ! File.readable? helper_file
132
- $stderr.puts "ERROR: Helper file #{helper_file} is not readable"
187
+ $stderr.puts "ERROR: Helpers file #{helper_file} is not readable"
133
188
  exit(1)
134
189
  end
135
190
  @helper_code = File.open(helper_file) { |f| f.read }
136
191
  end
137
192
  end
138
193
 
139
- # Uses the sort order specified in configuration
140
- def sort!(entries)
141
- case @sort
142
- when 'reverse-chronological'
143
- entries.sort! {|a, b| b.date_published <=> a.date_published } # Reverse chronological
194
+ # Implements sort orders which may be specified in configuration
195
+ def entry_sort_comparator(sort = @sort) # Defaults to the sort order specified in configuration
196
+ case sort
197
+ when :reverse_chronological
198
+ Proc.new {|a, b| b.date_published <=> a.date_published }
199
+ when :chronological
200
+ Proc.new {|a, b| a.date_published <=> b.date_published }
144
201
  end
145
202
  end
146
203
 
147
204
  def parse_feed(feed, entry_sources)
148
205
  remote_feed = nil
149
206
  begin
150
- remote_feed = open(feed['url'], "User-Agent" => @user_agent)
207
+ remote_feed = open(feed[:url], "User-Agent" => @user_agent)
151
208
  rescue Exception => e
152
- raise "Exception occurred when opening feed #{feed['name']} at #{feed['url']}:\n\n" + e.to_s
209
+ raise "Exception occurred when opening feed #{feed[:name]} at #{feed[:url]}:\n\n" + e.to_s
153
210
  end
154
211
 
155
212
  parsed_feed = nil
156
- begin
213
+ begin :test
157
214
  parsed_feed = FeedNormalizer::FeedNormalizer.parse remote_feed
158
215
  rescue Exception => e
159
- raise "Exception occurred when parsing feed #{feed['name']} which was downloaded from #{feed['url']}:\n\n" + e.to_s
216
+ raise "Exception occurred when parsing feed #{feed[:name]} which was downloaded from #{feed[:url]}:\n\n" + e.to_s
160
217
  end
161
218
 
162
- raise "Feed #{feed['name']} at #{feed['url']} does not appear to be a parsable feed" unless parsed_feed
219
+ raise "Feed #{feed[:name]} at #{feed[:url]} does not appear to be a parsable feed" unless parsed_feed
163
220
 
221
+ # Sort and truncate the entries if max_entries argument is present
222
+ if feed[:max_entries]
223
+ parsed_feed.entries.sort!(&entry_sort_comparator)
224
+ parsed_feed.entries.slice!(feed[:max_entries], parsed_feed.entries.size - feed[:max_entries])
225
+ end
226
+
227
+ # Store the entry sources. TODO: Store this information in the entries themselves
164
228
  parsed_feed.entries.each { |entry| entry_sources[entry] = feed }
165
229
 
166
230
  parsed_feed
@@ -169,13 +233,24 @@ EOF
169
233
  def load_recipe(recipe)
170
234
  recipefile = File.join(@recipes_folder, recipe)
171
235
  if ! File.exist? recipefile
172
- $stderr.puts "ERROR: Recipe #{recipefile} does not exist"
236
+ $stderr.puts "ERROR: Recipe file #{recipefile} does not exist"
173
237
  exit(1)
174
238
  elsif ! File.readable? recipefile
175
239
  $stderr.puts "ERROR: Recipe file #{recipefile} is not readable"
176
240
  exit(1)
177
241
  end
178
- YAML::load_file(recipefile)
242
+
243
+ recipe = {}
244
+
245
+ begin
246
+ recipe = YAML::load_file(recipefile).recursively_symbolize_keys
247
+ rescue Exception => e
248
+ $stderr.puts "ERROR: Problem parsing recipe file #{recipefile}"
249
+ $stderr.puts e
250
+ exit(1)
251
+ end
252
+
253
+ recipe
179
254
  end
180
255
 
181
256
  def init_config(configfile)
@@ -187,9 +262,17 @@ EOF
187
262
  exit(1)
188
263
  end
189
264
 
190
- config = YAML::load_file(configfile)
265
+ config = {}
266
+
267
+ begin
268
+ config = YAML::load_file(configfile).recursively_symbolize_keys
269
+ rescue Exception => e
270
+ $stderr.puts "ERROR: Problem parsing configuration file #{configfile}"
271
+ $stderr.puts e
272
+ exit(1)
273
+ end
191
274
 
192
- @recipes_folder = config['recipes_folder']
275
+ @recipes_folder = config[:recipes_folder]
193
276
  if ! File.exist? @recipes_folder
194
277
  $stderr.puts "ERROR: Recipes folder #{@recipes_folder} does not exist"
195
278
  exit(1)
@@ -198,7 +281,7 @@ EOF
198
281
  exit(1)
199
282
  end
200
283
 
201
- @themes_folder = config['themes_folder']
284
+ @themes_folder = config[:themes_folder]
202
285
  if ! File.exist? @themes_folder
203
286
  $stderr.puts "ERROR: Themes folder #{@themes_folder} does not exist"
204
287
  exit(1)
@@ -207,10 +290,10 @@ EOF
207
290
  exit(1)
208
291
  end
209
292
 
210
- @user_agent = config['user_agent'] || 'Audrey 2.0 Feed Aggregator'
211
- @sort = config['sort'] || 'reverse-chronological'
293
+ @user_agent = config[:user_agent] || 'Audrey 2.0 Feed Aggregator'
294
+ @sort = (config[:sort] || 'reverse_chronological').to_sym
212
295
 
213
- if @email = config['email']
296
+ if @email = config[:email]
214
297
  gem 'mail', '~> 2.2.5'
215
298
  require 'mail'
216
299
  # TODO: Check for required/consistent email config
data/test/helper.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ gem 'test-unit'
3
+ require 'test/unit'
4
+ require 'shoulda'
5
+ require 'mocha'
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'bin'))
9
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
10
+ require 'audrey2'
11
+
12
+ # The following trick is via http://thinkingdigitally.com/archive/capturing-output-from-puts-in-ruby/
13
+ require 'stringio'
14
+ module Kernel
15
+ def capture_stderr
16
+ err = StringIO.new
17
+ $stderr = err
18
+ yield
19
+ return err
20
+ ensure
21
+ $stderr = STDERR
22
+ end
23
+
24
+ def capture_stdout
25
+ out = StringIO.new
26
+ $stdout = out
27
+ yield
28
+ return out
29
+ ensure
30
+ $stdout = STDOUT
31
+ end
32
+ end
33
+
34
+ class Test::Unit::TestCase
35
+ end
@@ -0,0 +1,148 @@
1
+ require 'helper'
2
+
3
+ class TestConfig < Test::Unit::TestCase
4
+ context "Initializing an Aggregator" do
5
+
6
+ context "without a configfile" do
7
+ should 'report error and exit' do
8
+ File.stubs(:exist?).with('configfile').returns(false)
9
+ err = capture_stderr { assert_raise(SystemExit) { Audrey2::Aggregator.new('configfile') } }
10
+ assert_match /ERROR: Configuration file configfile does not exist/, err.string
11
+ end
12
+ end
13
+
14
+ context "with an unreadable configfile" do
15
+ should 'report error and exit' do
16
+ File.stubs(:exist?).with('configfile').returns(true)
17
+ File.expects(:readable?).with('configfile').returns(false)
18
+ err = capture_stderr { assert_raise(SystemExit) { Audrey2::Aggregator.new('configfile') } }
19
+ assert_match /ERROR: Configuration file configfile is not readable/, err.string
20
+ end
21
+ end
22
+
23
+ context "with an unparsable configfile" do
24
+ should 'report error and exit' do
25
+ File.stubs(:exist?).with('configfile').returns(true)
26
+ File.stubs(:readable?).with('configfile').returns(true)
27
+ YAML.expects(:load_file).with('configfile').raises(Exception)
28
+ err = capture_stderr { assert_raise(SystemExit) { Audrey2::Aggregator.new('configfile') } }
29
+ assert_match /ERROR: Problem parsing configuration file configfile/, err.string
30
+ end
31
+ end
32
+
33
+ context "with a valid configfile" do
34
+ setup do
35
+ @config
36
+ File.stubs(:exist?).with('configfile').returns(true)
37
+ File.stubs(:readable?).with('configfile').returns(true)
38
+ YAML.stubs(:load_file).with('configfile').returns({
39
+ 'recipes_folder' => 'recipes_folder',
40
+ 'themes_folder' => 'themes_folder'
41
+ })
42
+ end
43
+
44
+ context "without a recipes folder" do
45
+ should 'report error and exit' do
46
+ File.expects(:exist?).with('recipes_folder').returns(false)
47
+ err = capture_stderr { assert_raise(SystemExit) { Audrey2::Aggregator.new('configfile') } }
48
+ assert err.string =~ /ERROR: Recipes folder recipes_folder does not exist/
49
+ end
50
+ end
51
+
52
+ context "with an unreadable recipes folder" do
53
+ should 'report error and exit' do
54
+ File.stubs(:exist?).with('recipes_folder').returns(true)
55
+ File.expects(:readable?).with('recipes_folder').returns(false)
56
+ err = capture_stderr { assert_raise(SystemExit) { Audrey2::Aggregator.new('configfile') } }
57
+ assert err.string =~ /ERROR: Recipes folder recipes_folder is not readable/
58
+ end
59
+ end
60
+
61
+ context "and recipes folder" do
62
+ setup do
63
+ File.stubs(:exist?).with('recipes_folder').returns(true)
64
+ File.stubs(:readable?).with('recipes_folder').returns(true)
65
+ end
66
+
67
+ context "without a themes folder" do
68
+ should 'report error and exit' do
69
+ File.expects(:exist?).with('themes_folder').returns(false)
70
+ err = capture_stderr { assert_raise(SystemExit) { Audrey2::Aggregator.new('configfile') } }
71
+ assert err.string =~ /ERROR: Themes folder themes_folder does not exist/
72
+ end
73
+ end
74
+
75
+ context "with an unreadable themes folder" do
76
+ should 'report error and exit' do
77
+ File.stubs(:exist?).with('themes_folder').returns(true)
78
+ File.expects(:readable?).with('themes_folder').returns(false)
79
+ err = capture_stderr { assert_raise(SystemExit) { Audrey2::Aggregator.new('configfile') } }
80
+ assert err.string =~ /ERROR: Themes folder themes_folder is not readable/
81
+ end
82
+ end
83
+
84
+ context "and themes folder" do
85
+ setup do
86
+ File.stubs(:exist?).with('themes_folder').returns(true)
87
+ File.stubs(:readable?).with('themes_folder').returns(true)
88
+ @aggregator = Audrey2::Aggregator.new('configfile')
89
+ end
90
+
91
+ should "return a valid aggregator" do
92
+ assert_not_nil @aggregator
93
+ end
94
+
95
+ should "use the default user agent" do
96
+ assert_equal 'Audrey 2.0 Feed Aggregator', @aggregator.instance_variable_get('@user_agent')
97
+ end
98
+
99
+ should "use the default sort" do
100
+ assert_equal :reverse_chronological, @aggregator.instance_variable_get('@sort')
101
+ end
102
+
103
+ should "not setup email" do
104
+ assert_nil @aggregator.instance_variable_get('@email')
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ context "with a complete config" do
111
+ setup do
112
+ @config
113
+ File.stubs(:exist?).with('configfile').returns(true)
114
+ File.stubs(:readable?).with('configfile').returns(true)
115
+ YAML.stubs(:load_file).with('configfile').returns({
116
+ 'recipes_folder' => 'recipes_folder',
117
+ 'themes_folder' => 'themes_folder',
118
+ 'user_agent' => 'user_agent',
119
+ 'sort' => 'sort',
120
+ 'email' => 'email'
121
+ })
122
+ File.stubs(:exist?).with('recipes_folder').returns(true)
123
+ File.stubs(:readable?).with('recipes_folder').returns(true)
124
+ File.stubs(:exist?).with('themes_folder').returns(true)
125
+ File.stubs(:readable?).with('themes_folder').returns(true)
126
+ @aggregator = Audrey2::Aggregator.new('configfile')
127
+ end
128
+
129
+ should "return a valid aggregator" do
130
+ assert_not_nil @aggregator
131
+ end
132
+
133
+ should "use the specified user agent" do
134
+ assert_equal 'user_agent', @aggregator.instance_variable_get('@user_agent')
135
+ end
136
+
137
+ should "use the specified sort" do
138
+ assert_equal :sort, @aggregator.instance_variable_get('@sort')
139
+ end
140
+
141
+ # TODO: Fix this one later once email config consistency checking (and testing) are implemented
142
+ should "setup email" do
143
+ assert_equal 'email', @aggregator.instance_variable_get('@email')
144
+ end
145
+
146
+ end
147
+ end
148
+ end