audrey2 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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