synchroniser 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/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ desc 'Default: run specs.'
5
+ task :default => :spec
6
+
7
+ desc 'Run the specs'
8
+ Spec::Rake::SpecTask.new(:spec) do |t|
9
+ t.spec_opts = ['--colour --format progress --loadby mtime --reverse']
10
+ t.spec_files = FileList['spec/**/*_spec.rb']
11
+ end
data/Readme.rdoc ADDED
@@ -0,0 +1,26 @@
1
+ = Synchroniser
2
+
3
+ Synchroniser is a simple class to class synchronisation plugin.
4
+
5
+ === Sync your data
6
+
7
+ ==== Requirements
8
+
9
+ * Rails
10
+ * MySQL DB (currently)
11
+
12
+ ==== Instructions
13
+
14
+ * <tt>ruby script/plugin install git://github.com/robsharp/synchroniser.git</tt>
15
+
16
+
17
+ === Running Tests
18
+
19
+ To run the test suite, follow these steps to create a testbed app:
20
+
21
+ rails -d mysql synchroniser_tests
22
+ cd synchroniser_tests
23
+ ruby script/plugin install git://github.com/robsharp/synchroniser.git
24
+ script/generate synchroniser
25
+ rake db:setup RAILS_ENV=test
26
+ rake test:plugins
@@ -0,0 +1,5 @@
1
+ $:.push(File.join(File.dirname(__FILE__), %w[.. .. rspec]))
2
+
3
+ Autotest.add_discovery do
4
+ "rspec"
5
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generate a migration for the synchroniser data table
3
+
4
+ Example:
5
+ ./script/generate synchroniser
6
+
7
+ This will create:
8
+ db/migrations/xxx_create_sync_items.rb
@@ -0,0 +1,21 @@
1
+ require 'rbconfig'
2
+
3
+ class SynchroniserGenerator < Rails::Generator::Base
4
+ attr_reader :file_name, :klass_name
5
+
6
+ def manifest
7
+ recorded_session = record do |m|
8
+ m.directory 'db/migrate'
9
+ m.template 'create_sync_items.rb', "db/migrate/#{Time.now.utc.strftime("%Y%m%d%H%M%S")}_create_sync_items.rb"
10
+ end
11
+
12
+ recorded_session
13
+ end
14
+
15
+ def after_generate
16
+ puts <<-OUTRO
17
+ Now run rake db:migrate to update your database to support the synchroniser
18
+ OUTRO
19
+ end
20
+
21
+ end
@@ -0,0 +1,17 @@
1
+ class CreateSyncItems < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :sync_items, :options => "ENGINE=MyISAM" do |t|
4
+ t.string :item
5
+ t.string :group
6
+ t.string :class_name
7
+ t.string :class_id
8
+ t.string :status
9
+
10
+ t.timestamps
11
+ end
12
+ end
13
+
14
+ def self.down
15
+ drop_table :sync_items
16
+ end
17
+ end
@@ -0,0 +1,27 @@
1
+ class DummyIngestor
2
+ include Synchroniser::Ingestor::Uri
3
+
4
+ attr_accessor :data
5
+
6
+ def initialize
7
+ @data = [
8
+ { :url => "abc123", :title => "123abc" },
9
+ { :url => "def456", :title => "def456" }
10
+ ]
11
+ end
12
+
13
+ def ingest(container)
14
+ @data.map {|item|
15
+ itemise(item, container.clone)
16
+ }
17
+ end
18
+
19
+ def itemise(item, container)
20
+ container.instance_eval{
21
+ self.url = item[:url]
22
+ self.title = item[:title]
23
+ self
24
+ }
25
+ end
26
+
27
+ end
data/lib/post.rb ADDED
@@ -0,0 +1,11 @@
1
+ class Post < ActiveRecord::Base
2
+ include Synchroniser::Model
3
+
4
+ attr_accessor :test_default
5
+
6
+ def item
7
+ url
8
+ end
9
+
10
+ end
11
+
@@ -0,0 +1,22 @@
1
+ class RssIngestor
2
+ include Synchroniser::Ingestor::Uri
3
+
4
+ require 'hpricot'
5
+
6
+ def ingest(container)
7
+ Hpricot(@data).search("rss/channel/item").collect {|item|
8
+ itemise(item, container.clone)
9
+ }.reject { |item|
10
+ item.nil?
11
+ }
12
+ end
13
+
14
+ def itemise(item, container)
15
+ container.instance_eval{
16
+ self.url = ((item/"guid").inner_html)
17
+ self.title = ((item/"title").inner_html)
18
+ self
19
+ }
20
+ end
21
+
22
+ end
data/lib/sync_item.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'active_record'
2
+
3
+ class SyncItem < ActiveRecord::Base
4
+ end
@@ -0,0 +1,60 @@
1
+ module Synchroniser::Config
2
+
3
+ class Params
4
+
5
+ attr_accessor :config
6
+
7
+ def initialize(file_name, ingestor_name)
8
+ file_path = RAILS_ROOT
9
+ config = YAML::load(File.open("#{file_path}#{file_name}"))
10
+
11
+ environment = RAILS_ENV
12
+ if config[RAILS_ENV].nil?
13
+ environment = "test"
14
+ end
15
+
16
+ begin
17
+ @config = config[environment]
18
+ rescue
19
+ @config = nil
20
+ raise ArgumentError, "Unable to find the #{environment} stanza for #{ingestor_name}' in the configuration file supplied"
21
+ end
22
+
23
+ if @config.nil?
24
+ raise ArgumentError, "Unable to find the stanza '#{ingestor_name}' in the configuration file supplied"
25
+ end
26
+ end
27
+
28
+ def get_sync
29
+ container = build_container(@config['params']['container'])
30
+ ingestors = build_ingestors(container)
31
+ Synchroniser.new(container, ingestors)
32
+ end
33
+
34
+ def build_ingestors(container)
35
+ require @config['ingestor'] + "_ingestor.rb"
36
+ @ingestor = eval("#{@config['ingestor'].camelize}Ingestor.new")
37
+
38
+ strategies = []
39
+ @config['params']['url'].each { |url|
40
+ @ingestor.load(url)
41
+ strategies << @ingestor.clone
42
+ puts url
43
+
44
+ # not sure if this will actually work
45
+ @ingestor.pagination.each do |url|
46
+ @ingestor.load(url)
47
+ strategies << @ingestor.clone
48
+ puts url
49
+ end
50
+ }
51
+ strategies
52
+ end
53
+
54
+ def build_container(container)
55
+ eval "#{container['object']}.new(container['defaults'])"
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,14 @@
1
+ module Synchroniser::Ingestor::Uri
2
+ include Synchroniser::Ingestor
3
+
4
+ require 'open-uri'
5
+
6
+ def load(uri)
7
+ @data = open(uri).read
8
+ end
9
+
10
+ def pagination
11
+ # pagination is not enabled by default
12
+ []
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ module Synchroniser::Ingestor::Yql
2
+ include Synchroniser::Ingestor
3
+
4
+ require 'uri'
5
+ require 'open-uri'
6
+ require 'yajl/http_stream'
7
+ require 'yajl/json_gem'
8
+ require 'digest/md5'
9
+
10
+ def load(uri)
11
+ resource = Yajl::HttpStream.get(build_url(url))
12
+ @data = resource['query']['results']['products']['product']
13
+ end
14
+
15
+ private
16
+
17
+ def build_url(url)
18
+ yql = "use \"#{url}\" as shop; select * from shop;"
19
+
20
+ base = "http://query.yahooapis.com/v1/public/yql?format=json&q="
21
+ URI.parse(base + URI.escape(yql))
22
+ end
23
+
24
+ end
@@ -0,0 +1,19 @@
1
+ module Synchroniser::Ingestor
2
+
3
+ attr_accessor :container
4
+
5
+ def sync
6
+ @container.find_all_flags.each {|flag|
7
+ flag.status = 0
8
+ flag.save
9
+ }
10
+
11
+ SyncItem.logger.info("Reset status for the set '#{@container.group}'")
12
+
13
+ ingest.each {|item|
14
+ item.save
15
+ }
16
+
17
+ @container.delete_expired_items
18
+ end
19
+ end
@@ -0,0 +1,55 @@
1
+ module Synchroniser::Model
2
+ require File.join(File.dirname(__FILE__), '..', 'sync_item.rb')
3
+
4
+ def find_all_flags
5
+ SyncItem.find_all_by_group(group)
6
+ end
7
+
8
+ def delete_expired_items
9
+ params = {:status => false,
10
+ :group => group}
11
+ SyncItem.find(:all, :conditions => params).each {|sync_item|
12
+ begin
13
+ eval "#{sync_item.class_name}.find(#{sync_item.id}).delete"
14
+ rescue Exception
15
+ SyncItem.logger.warn("Unable to remove #{sync_item.class_name}.find(#{sync_item.id})")
16
+ end
17
+ sync_item.delete
18
+ }
19
+ SyncItem.logger.info("Expired Items Deleted")
20
+ end
21
+
22
+ def before_validation
23
+ if (sync_item = SyncItem.find_by_group_and_item(group, self.item)).nil? === false
24
+ # we've already sync'd this object
25
+ sync_item.status = 2
26
+ sync_item.save
27
+ SyncItem.logger.info("#{sync_item.class_name} with id #{sync_item.class_id} doesn't require an update")
28
+ #stop further saving
29
+ #TODO on innodb tables this will cause the transaction to rollback
30
+ return false
31
+ end
32
+ return true
33
+ end
34
+
35
+ def after_save
36
+ # we must have a new object
37
+ sync_item = SyncItem.new({
38
+ :group => group,
39
+ :item => self.item,
40
+ :class_name => self.class.to_s,
41
+ :class_id => self.id,
42
+ :status => "1" })
43
+ sync_item.save
44
+ SyncItem.logger.info("Created new #{sync_item.class_name}")
45
+ end
46
+
47
+ def group=(value)
48
+ @@group = value
49
+ end
50
+
51
+ def group
52
+ @@group
53
+ end
54
+
55
+ end
@@ -0,0 +1,14 @@
1
+ require 'yaml'
2
+
3
+ namespace :synchroniser do
4
+
5
+ desc "Ingest a provider"
6
+ task :provider => :environment do |t, args|
7
+ if args.name.nil?
8
+ raise ArgumentError, "name argument must be supplied to the rake task"
9
+ end
10
+
11
+ synchroniser = Synchroniser::Config::Params.new("/config/ingestors/#{args.name}.yml", args.name).get_sync
12
+ synchroniser.sync
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ module Synchroniser
2
+ module VERSION
3
+ MAJOR = 0
4
+ MINOR = 3
5
+ TINY = 0
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ class Synchroniser
2
+
3
+ attr_accessor :container
4
+ attr_accessor :ingestors
5
+
6
+ def initialize(container, ingestors)
7
+ @container = container
8
+ @ingestors = ingestors
9
+ end
10
+
11
+ def ingest
12
+ @ingestors.map {|ingestor|
13
+ ingestor.ingest(@container)
14
+ }.flatten
15
+ end
16
+
17
+ def sync
18
+ stats = {}
19
+
20
+ if @container.group.nil?
21
+ raise ArgumentError, "Group not set on container '#{@container.class}'"
22
+ end
23
+
24
+ stats[:seed] = 0
25
+ @container.find_all_flags.each {|flag|
26
+ flag.status = 0
27
+ flag.save
28
+ stats[:seed] += 1
29
+ }
30
+
31
+ SyncItem.logger.info("Reset status for the set '#{@container.group}'")
32
+
33
+ stats[:ingestable] = 0
34
+ ingest.each {|item|
35
+ if item.item.nil?
36
+ raise NotImplementedError, "Method call '#{@container.class}.item' is returning null. Please ensure it returns a unique value per instance."
37
+ end
38
+ item.save
39
+ item.url
40
+ stats[:ingestable] += 1
41
+ }
42
+
43
+ @container.delete_expired_items
44
+
45
+ puts "Initial seeding of #{stats[:seed]}"
46
+ puts "Ingestor found #{stats[:ingestable]} items"
47
+ end
48
+ end
49
+
50
+ require File.join(File.dirname(__FILE__), 'synchroniser', 'config.rb')
51
+ require File.join(File.dirname(__FILE__), 'synchroniser', 'model.rb')
52
+ require File.join(File.dirname(__FILE__), 'synchroniser', 'ingestor.rb')
53
+ require File.join(File.dirname(__FILE__), 'synchroniser', 'ingestor', 'uri.rb')
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ # Include hook code here
@@ -0,0 +1,3 @@
1
+ sqlite3:
2
+ :adapter: sqlite3
3
+ :database: vendor/plugins/synchroniser/spec/db/synchroniser.sqlite3.db
data/spec/db/schema.rb ADDED
@@ -0,0 +1,19 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :sync_items, :force => true do |t|
3
+ t.string :item
4
+ t.string :group
5
+ t.string :class_name
6
+ t.string :class_id
7
+ t.string :status
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ create_table :posts, :force => true do |t|
13
+ t.string :title
14
+ t.string :url
15
+
16
+ t.timestamps
17
+ end
18
+
19
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,17 @@
1
+ begin
2
+ require File.dirname(__FILE__) + '/../../../../spec/spec_helper'
3
+ rescue LoadError
4
+ puts "You need to install rspec in your base app"
5
+ exit
6
+ end
7
+
8
+ plugin_spec_dir = File.dirname(__FILE__)
9
+ ActiveRecord::Base.logger = Logger.new(plugin_spec_dir + "/debug.log")
10
+
11
+ databases = YAML::load(IO.read(plugin_spec_dir + "/db/database.yml"))
12
+ ActiveRecord::Base.establish_connection(databases[ENV["DB"] || "sqlite3"])
13
+ load(File.join(plugin_spec_dir, "db", "schema.rb"))
14
+
15
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'synchroniser.rb')
16
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'post.rb')
17
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'dummy_ingestor.rb')
@@ -0,0 +1,65 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ item = "abc123"
4
+ group = "def456"
5
+
6
+ describe Synchroniser do
7
+ it "should always create a new post with new data" do
8
+ container = Post.new({:url => item, :group => group})
9
+ ingestors = [ DummyIngestor.new ]
10
+ sync = Synchroniser.new(container, ingestors)
11
+ sync_data = sync.ingest
12
+ sync_data.first.before_validation.should == true
13
+ end
14
+
15
+ it "should never create a new post with an existing object" do
16
+ #TODO should use a fixture instead
17
+ a = SyncItem.new
18
+ a.item = item
19
+ a.group = group
20
+ a.save
21
+
22
+ container = Post.new({:url => item, :group => group})
23
+ ingestors = [ DummyIngestor.new ]
24
+ sync = Synchroniser.new(container, ingestors)
25
+ sync_data = sync.ingest
26
+ sync_data.first.before_validation.should == false
27
+ end
28
+
29
+ it "should set the correct container group from a config" do
30
+ config = Synchroniser::Config::Params.new("/vendor/plugins/synchroniser/test/docs/ingestors.yml", "rss")
31
+ synchroniser = config.get_sync
32
+ synchroniser.container.group.should == "rss_test_feed"
33
+ end
34
+
35
+ it "should set the correct model group from a config" do
36
+ config = Synchroniser::Config::Params.new("/vendor/plugins/synchroniser/test/docs/ingestors.yml", "rss")
37
+ synchroniser = config.get_sync
38
+ synchroniser.ingest[0].group.should == "rss_test_feed"
39
+ end
40
+
41
+ it "should set the correct url from a config" do
42
+ synchroniser = Synchroniser::Config::Params.new("/vendor/plugins/synchroniser/test/docs/ingestors.yml", "rss").get_sync
43
+ synchroniser.ingest[0].url.should == "http://news.bbc.co.uk/sport1/hi/football/teams/n/newcastle_united/8329055.stm"
44
+ end
45
+
46
+ it "should correctly set the title upon ingestion" do
47
+ synchroniser = Synchroniser::Config::Params.new("/vendor/plugins/synchroniser/test/docs/ingestors.yml", "rss").get_sync
48
+ synchroniser.ingest[0].title.should == "Ashley takes Newcastle off market"
49
+ end
50
+
51
+ it "should set container defaults corrently" do
52
+ synchroniser = Synchroniser::Config::Params.new("/vendor/plugins/synchroniser/test/docs/ingestors.yml", "rss").get_sync
53
+ synchroniser.container.test_default.should == "random_default_name"
54
+ end
55
+
56
+ it "should sync without error" do
57
+ synchroniser = Synchroniser::Config::Params.new("/vendor/plugins/synchroniser/test/docs/ingestors.yml", "rss").get_sync
58
+ synchroniser.sync
59
+ SyncItem.find(:all)[0].item.should == "http://news.bbc.co.uk/sport1/hi/football/teams/n/newcastle_united/8329055.stm"
60
+ SyncItem.find(:all)[0].group.should == "rss_test_feed"
61
+ end
62
+
63
+
64
+
65
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :synchroniser do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,10 @@
1
+ test:
2
+ rss:
3
+ ingestor: rss
4
+ params:
5
+ url: /home/robsharp/Dropbox/workspace/synchroniser_tests/vendor/plugins/synchroniser/test/docs/rss.xml
6
+ container:
7
+ object: Post
8
+ defaults:
9
+ group: rss_test_feed
10
+ test_default: random_default_name
data/test/docs/rss.xml ADDED
@@ -0,0 +1,154 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <?xml-stylesheet title="XSL_formatting" type="text/xsl" href="/shared/bsp/xsl/rss/nolsol.xsl"?>
3
+ <rss xmlns:media="http://search.yahoo.com/mrss" version="2.0">
4
+ <channel>
5
+ <title>BBC Sport | Football | UK Edition</title>
6
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/default.stm</link>
7
+ <description>The latest BBC Football news plus live scores, fixtures, results, tables, video, audio, blogs and analysis for all major UK and international leagues.</description>
8
+ <language>en-gb</language>
9
+ <lastBuildDate>Wed, 28 Oct 2009 09:26:52 GMT</lastBuildDate>
10
+ <copyright>Copyright: (C) British Broadcasting Corporation, see http://news.bbc.co.uk/sport1/hi/help/rss/4517815.stm for terms and conditions of reuse</copyright>
11
+ <docs>http://www.bbc.co.uk/syndication/</docs>
12
+ <ttl>15</ttl>
13
+ <image>
14
+ <title>BBC Sport</title>
15
+ <url>http://news.bbc.co.uk/sol/shared/img/sport_120x60.gif</url>
16
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/default.stm</link>
17
+ </image>
18
+ <item>
19
+ <title>Ashley takes Newcastle off market</title>
20
+ <description>Newcastle owner Mike Ashley ends his attempt to sell the club and aims to sell the naming rights to St James' Park to increase revenues.</description>
21
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/teams/n/newcastle_united/8329055.stm</link>
22
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/teams/n/newcastle_united/8329055.stm</guid>
23
+ <pubDate>Tue, 27 Oct 2009 22:38:41 GMT</pubDate>
24
+ <category>Newcastle</category>
25
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/45880000/jpg/_45880872_ashley.jpg"/>
26
+ </item>
27
+ <item>
28
+ <title>Stoke players in plane emergency</title>
29
+ <description>A plane carrying Stoke City players back from their 4-0 defeat at Portsmouth on Tuesday is forced to make an emergency midnight landing.</description>
30
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/teams/s/stoke_city/8329270.stm</link>
31
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/teams/s/stoke_city/8329270.stm</guid>
32
+ <pubDate>Wed, 28 Oct 2009 08:41:28 GMT</pubDate>
33
+ <category>Stoke</category>
34
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/44936000/gif/_44936207_stoke_66x49.gif"/>
35
+ </item>
36
+ <item>
37
+ <title>Barnsley 0-2 Man Utd</title>
38
+ <description>Danny Welbeck and Michael Owen seal a 2-0 win for Man Utd at Barnsley in the Carling Cup fourth round, although the visitors have Gary Neville sent off.</description>
39
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/league_cup/8323041.stm</link>
40
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/league_cup/8323041.stm</guid>
41
+ <pubDate>Tue, 27 Oct 2009 21:43:25 GMT</pubDate>
42
+ <category>League Cup</category>
43
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46621000/jpg/_46621742_owen336.jpg"/>
44
+ </item>
45
+ <item>
46
+ <title>Tottenham 2-0 Everton</title>
47
+ <description>Tottenham shrug off Everton to book their place in the quarter-finals of the Carling Cup.</description>
48
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/league_cup/8323083.stm</link>
49
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/league_cup/8323083.stm</guid>
50
+ <pubDate>Tue, 27 Oct 2009 21:51:39 GMT</pubDate>
51
+ <category>League Cup</category>
52
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46621000/jpg/_46621816_keane66x49.jpg"/>
53
+ </item>
54
+ <item>
55
+ <title>Blackburn 5-2 Peterborough</title>
56
+ <description>Blackburn shrug off an outbreak of swine flu to beat valiant Peterborough at Ewood Park.</description>
57
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/league_cup/8323055.stm</link>
58
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/league_cup/8323055.stm</guid>
59
+ <pubDate>Tue, 27 Oct 2009 22:01:51 GMT</pubDate>
60
+ <category>League Cup</category>
61
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46621000/jpg/_46621844_008185130-1.jpg"/>
62
+ </item>
63
+ <item>
64
+ <title>Sunderland 0-0 Villa (1-3 pens)</title>
65
+ <description>Aston Villa keeper Brad Guzan saves three spot-kicks in a penalty shoot-out to seal a Carling Cup fourth round win for his side at Sunderland.</description>
66
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/league_cup/8323069.stm</link>
67
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/league_cup/8323069.stm</guid>
68
+ <pubDate>Tue, 27 Oct 2009 22:23:53 GMT</pubDate>
69
+ <category>League Cup</category>
70
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46621000/jpg/_46621989_guzan226x170.jpg"/>
71
+ </item>
72
+ <item>
73
+ <title>Portsmouth 4-0 Stoke</title>
74
+ <description>Portsmouth stroll into the quarter-finals of the Carling Cup after comfortably beating Stoke. </description>
75
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/league_cup/8323058.stm</link>
76
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/league_cup/8323058.stm</guid>
77
+ <pubDate>Tue, 27 Oct 2009 21:41:35 GMT</pubDate>
78
+ <category>League Cup</category>
79
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46621000/jpg/_46621719_008184644-1.jpg"/>
80
+ </item>
81
+ <item>
82
+ <title>Dundee 1-3 Rangers</title>
83
+ <description>Rangers progress to the semi-finals of the Co-operative Insurance Cup after a tough game at Dens Park.</description>
84
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/scot_cups/8325938.stm</link>
85
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/scot_cups/8325938.stm</guid>
86
+ <pubDate>Tue, 27 Oct 2009 21:37:57 GMT</pubDate>
87
+ <category>Scottish Cups</category>
88
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46621000/jpg/_46621715_whittaker66.jpg"/>
89
+ </item>
90
+ <item>
91
+ <title>Bristol Rovers 0-4 Leeds United</title>
92
+ <description>Jermaine Beckford scores two as League One leaders Leeds condemn Bristol Rovers to a fourth consecutive defeat.</description>
93
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/eng_div_2/8316580.stm</link>
94
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/eng_div_2/8316580.stm</guid>
95
+ <pubDate>Tue, 27 Oct 2009 21:50:19 GMT</pubDate>
96
+ <category>League One</category>
97
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46621000/jpg/_46621982_beckford_celeb_index203.jpg"/>
98
+ </item>
99
+ <item>
100
+ <title>St Mirren 3-0 Motherwell</title>
101
+ <description>St Mirren score three past Motherwell for the second time in a week as they progressed to the Co-operative Insurance Cup semi-finals.</description>
102
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/scot_cups/8325956.stm</link>
103
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/scot_cups/8325956.stm</guid>
104
+ <pubDate>Tue, 27 Oct 2009 21:38:56 GMT</pubDate>
105
+ <category>Scottish Cups</category>
106
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46621000/jpg/_46621865_ross66.jpg"/>
107
+ </item>
108
+ <item>
109
+ <title>St Johnstone 2-1 Dundee United</title>
110
+ <description>Steven Anderson helps put his former team to the sword as St Johnstone squeeze through to the Co-operative Insurance Cup semi-finals.</description>
111
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/scot_cups/8325947.stm</link>
112
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/scot_cups/8325947.stm</guid>
113
+ <pubDate>Tue, 27 Oct 2009 21:41:58 GMT</pubDate>
114
+ <category>Scottish Cups</category>
115
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46621000/jpg/_46621884_anderson66.jpg"/>
116
+ </item>
117
+ <item>
118
+ <title>Spitting on pitch 'is flu risk'</title>
119
+ <description>Footballers are warned about spitting on the pitch during games as more swine flu cases are confirmed in the Premier League.</description>
120
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/8327576.stm</link>
121
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/8327576.stm</guid>
122
+ <pubDate>Tue, 27 Oct 2009 16:04:31 GMT</pubDate>
123
+ <category>Football</category>
124
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46616000/jpg/_46616158_flu_66.jpg"/>
125
+ </item>
126
+ <item>
127
+ <title>Aquilani close to Liverpool debut</title>
128
+ <description>Preview followed by live coverage of Wednesday's game between Arsenal and Liverpool in the Carling Cup.</description>
129
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/league_cup/8323097.stm</link>
130
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/league_cup/8323097.stm</guid>
131
+ <pubDate>Mon, 26 Oct 2009 15:33:17 GMT</pubDate>
132
+ <category>League Cup</category>
133
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46158000/jpg/_46158717_carling_cup_live_66x49.jpg"/>
134
+ </item>
135
+ <item>
136
+ <title>Celtic prepare for Brown absence</title>
137
+ <description>Scott Brown could miss several games for Celtic and Scotland as his club look to resolve his ankle problems.</description>
138
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/teams/c/celtic/8328502.stm</link>
139
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/teams/c/celtic/8328502.stm</guid>
140
+ <pubDate>Tue, 27 Oct 2009 16:15:56 GMT</pubDate>
141
+ <category>Celtic</category>
142
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46619000/jpg/_46619552_scott_brown226i.jpg"/>
143
+ </item>
144
+ <item>
145
+ <title>Clarity required for Rangers sale</title>
146
+ <description>Sir David Murray will have to go public with details of the sale of any of his majority shareholding in Rangers.</description>
147
+ <link>http://news.bbc.co.uk/go/rss/-/sport1/hi/football/teams/r/rangers/8324603.stm</link>
148
+ <guid isPermaLink="false">http://news.bbc.co.uk/sport1/hi/football/teams/r/rangers/8324603.stm</guid>
149
+ <pubDate>Tue, 27 Oct 2009 16:11:48 GMT</pubDate>
150
+ <category>Rangers</category>
151
+ <media:thumbnail width="66" height="49" url="http://newsimg.bbc.co.uk/media/images/46605000/jpg/_46605624_waltersmith_getty282.jpg"/>
152
+ </item>
153
+ </channel>
154
+ </rss>
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: synchroniser
3
+ version: !ruby/object:Gem::Version
4
+ hash: 19
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
+ platform: ruby
12
+ authors:
13
+ - Rob Sharp
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-05 00:00:00 +10:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: " Synchroniser is a simple class to class synchronisation plugin.\n"
23
+ email: rob@sharp.id.au
24
+ executables: []
25
+
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - Readme.rdoc
32
+ - Rakefile
33
+ - MIT-LICENSE
34
+ - autotest/discover.rb
35
+ - generators/synchroniser/USAGE
36
+ - generators/synchroniser/synchroniser_generator.rb
37
+ - generators/synchroniser/templates/create_sync_items.rb
38
+ - lib/rss_ingestor.rb
39
+ - lib/synchroniser.rb
40
+ - lib/sync_item.rb
41
+ - lib/dummy_ingestor.rb
42
+ - lib/synchroniser/ingestor/yql.rb
43
+ - lib/synchroniser/ingestor/uri.rb
44
+ - lib/synchroniser/model.rb
45
+ - lib/synchroniser/tasks/synchroniser.rake
46
+ - lib/synchroniser/version.rb
47
+ - lib/synchroniser/config.rb
48
+ - lib/synchroniser/ingestor.rb
49
+ - lib/post.rb
50
+ - rails/init.rb
51
+ - spec/spec.opts
52
+ - spec/db/database.yml
53
+ - spec/db/schema.rb
54
+ - spec/synchroniser_spec.rb
55
+ - spec/spec_helper.rb
56
+ - test/docs/ingestors.yml
57
+ - test/docs/rss.xml
58
+ - tasks/synchroniser_tasks.rake
59
+ has_rdoc: true
60
+ homepage: http://github.com/iondrive/synchroniser
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
76
+ version: "0"
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ hash: 3
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project:
89
+ rubygems_version: 1.3.7
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: A basic synchronisation plugin for rails
93
+ test_files: []
94
+