feed_me 0.0.5 → 0.6.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 CHANGED
@@ -3,7 +3,7 @@ Feed Me
3
3
 
4
4
  Feed Me is a simple parser for RSS2 and Atom feed, adding other feed formats should be trivial. Feed Me is pretty minimal and basically only does translation/cleanup from different feed formats to a consistent API. It is designed to be minimal.
5
5
 
6
- Feed Me is built on the excellent Hpricot parser written by _why the lucky stiff.
6
+ Feed Me is built on the excellent Nokogiri parser.
7
7
 
8
8
  Use it like this:
9
9
 
@@ -20,4 +20,4 @@ Use it like this:
20
20
 
21
21
  Check out the specs or lib/feed_me/consts.rb for the complete API.
22
22
 
23
- DISCLAIMER: This is very much alpha software, use at your own risk!
23
+ DISCLAIMER: This is very much alpha software, use at your own risk!
data/Rakefile CHANGED
@@ -23,8 +23,13 @@ namespace :spec do
23
23
 
24
24
  end
25
25
 
26
+ desc "Run all examples"
27
+ Spec::Rake::SpecTask.new('spec') do |t|
28
+ t.spec_files = file_list
29
+ end
30
+
26
31
  desc 'Default: run specs.'
27
- task :default => 'spec:rcov'
32
+ task :default => 'spec'
28
33
 
29
34
  PLUGIN = "feed_me"
30
35
  NAME = "feed_me"
@@ -53,7 +58,6 @@ begin
53
58
  s.add_dependency('hpricot')
54
59
  s.files = %w(LICENSE README Rakefile TODO) + Dir.glob("{lib,specs}/**/*")
55
60
  end
56
- Jeweler::GemcutterTasks.new
57
61
  rescue
58
62
  puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install namelessjon-jeweler -s http://gems.github.com"
59
63
  end
@@ -1,23 +1,6 @@
1
- # make sure we're running inside Merb
2
- if defined?(Merb::Plugins)
3
- dependency 'hpricot'
4
- else
5
- require 'rubygems'
6
- require 'hpricot'
7
- end
1
+ require 'nokogiri'
8
2
  require 'time'
9
3
 
10
- unless nil.respond_to? :try
11
- # the ultimate duck
12
- class Object
13
- def try(method, *args)
14
- self.send(method, *args)
15
- rescue NoMethodError
16
- nil
17
- end
18
- end
19
- end
20
-
21
4
  module FeedMe
22
5
  class InvalidFeedFormat < StandardError ; end
23
6
 
@@ -30,7 +13,7 @@ module FeedMe
30
13
  end
31
14
  end
32
15
 
33
- ['consts', 'abstract_parser', 'feed_struct', 'simple_struct',
34
- 'feed_parser', 'item_parser'].each do |f|
35
- require File.join(File.dirname(__FILE__), 'feed_me', f)
36
- end
16
+ require 'feed_me/abstract_parser'
17
+ require 'feed_me/feed_parser'
18
+ require 'feed_me/item_parser'
19
+ require 'feed_me/person_parser'
@@ -2,118 +2,121 @@ class FeedMe::AbstractParser
2
2
 
3
3
  class << self
4
4
 
5
- attr_accessor :properties, :root_nodes
5
+ def properties
6
+ @properties ||= {}
7
+ end
6
8
 
7
- def build(xml, format, *args)
8
- # in a world with activesupport this would have been written as
9
- # format_parser = (format.to_s.camelize + self.to_s).constantize
10
- camelized_format = format.to_s.split('_').map{ |w| w.capitalize }.join('')
11
- bare_class = self.to_s.split('::').last
9
+ def property(name, options={})
10
+ options[:path] ||= name
11
+ properties[name.to_sym] = options
12
12
 
13
- begin
14
- format_parser = FeedMe.const_get(camelized_format + bare_class)
15
- rescue NameError
16
- end
13
+ class_eval <<-RUBY, __FILE__, __LINE__+1
14
+ def #{name}
15
+ get_property(:#{name})
16
+ end
17
+ RUBY
18
+ end
17
19
 
18
- if format_parser.is_a?(Class) and format_parser.ancestors.include?(self)
19
- return format_parser.new(xml, format, *args)
20
- else
21
- return self.new(xml, format, *args)
22
- end
20
+ def has_many(name, options={})
21
+ raise ArgumentError, "must specify :use option" unless options[:use]
22
+ options[:path] ||= name
23
+ options[:association] = :has_many
24
+ properties[name.to_sym] = options
23
25
 
26
+ class_eval <<-RUBY, __FILE__, __LINE__+1
27
+ def #{name}
28
+ get_has_many_association(:#{name})
29
+ end
30
+ RUBY
24
31
  end
25
32
 
26
- end
33
+ def has_one(name, options={})
34
+ raise ArgumentError, "must specify :use option" unless options[:use]
35
+ options[:path] ||= name
36
+ options[:association] = :has_one
37
+ properties[name.to_sym] = options
38
+
39
+ class_eval <<-RUBY, __FILE__, __LINE__+1
40
+ def #{name}
41
+ get_has_one_association(:#{name})
42
+ end
43
+ RUBY
44
+ end
27
45
 
28
- def initialize(xml, format)
29
- self.xml = xml
30
- self.format = format
31
- self.properties = self.class.properties[self.format]
46
+ end
32
47
 
33
- append_methods
48
+ def initialize(feed, xml)
49
+ @xml = xml
50
+ @feed = feed
34
51
  end
35
52
 
36
53
  def to_hash
37
54
  hash = {}
38
- self.properties.each do |method, p|
55
+ self.class.properties.each do |method, p|
39
56
  hash[method] = self.send(method)
40
57
  end
41
58
  return hash
42
59
  end
43
60
 
44
- attr_accessor :xml, :format, :properties
61
+ attr_reader :xml, :feed
45
62
 
46
63
  alias_method :root_node, :xml
47
64
 
48
- protected
49
-
50
- def fetch_rss_person(selector)
51
- item = fetch(selector)
52
- if(item)
53
- email, name = item.split(/\s+/, 2)
54
- name = name.match( /\((.*?)\)/ ).to_a[1] if name # strip parentheses
55
- else
56
- name, email = nil
65
+ private
66
+
67
+ def get_has_many_association(name)
68
+ return nil unless xml
69
+ association = self.class.properties[name]
70
+
71
+ nodes = xml.xpath("./#{association[:path]}")
72
+ parser = FeedMe.const_get(association[:use].to_s)
73
+
74
+ nodes.map do |node|
75
+ parser.new(self, node)
57
76
  end
58
- FeedMe::SimpleStruct.new(:email => email, :name => name, :uri => nil)
59
77
  end
60
78
 
61
- def append_methods
62
- self.properties.each do |method, p|
63
- unless respond_to?(method)
64
- block = get_proc_for_property(method, p)
65
- # meta programming magic
66
- (class << self; self; end).module_eval do
67
- define_method method, &block
68
- end
69
- end
70
- end
79
+ def get_has_one_association(name)
80
+ return nil unless xml
81
+ association = self.class.properties[name]
82
+
83
+ node = xml.xpath("./#{association[:path]}").first
84
+ parser = FeedMe.const_get(association[:use].to_s)
85
+
86
+ parser.new(self, node)
71
87
  end
72
88
 
73
- def get_proc_for_property(method, p)
74
- if p.class == Array
75
- return caching_proc(method, &proc { fetch("/#{p[0]}", root_node, p[1].to_sym) })
76
- elsif p.class == Hash
77
- return caching_proc(method, &proc { FeedMe::FeedStruct.new(root_node, p) })
78
- elsif p != :undefined
79
- return caching_proc(method, &proc { fetch("/#{p}", root_node) })
89
+ def get_property(name)
90
+ return nil unless xml
91
+ property = self.class.properties[name]
92
+
93
+ values = xml.xpath("./#{property[:path]}").map do |node|
94
+ result = extract_result(node, property[:from])
95
+ cast_result(result, property[:as])
96
+ end
97
+
98
+ case property[:cardinality]
99
+ when :many
100
+ return values
80
101
  else
81
- return proc { nil }
102
+ return values.first
82
103
  end
83
104
  end
84
105
 
85
- def caching_proc(name, &block)
86
- proc do
87
- ivar = instance_variable_get("@#{name}")
88
- unless ivar
89
- result = yield
90
- instance_variable_set("@#{name}", result)
91
- return result
92
- end
93
- ivar
106
+ def extract_result(node, from)
107
+ if from
108
+ node[from]
109
+ else
110
+ node.inner_html
94
111
  end
95
112
  end
96
113
 
97
- def fetch(selector, search_in = xml, method = :inner_html)
98
- item = search_in.search(selector)
99
-
100
- unless method == :array
101
- self.try("extract_" + method.to_s, item.first) unless item.empty?
114
+ def cast_result(result, as)
115
+ if as == :time
116
+ Time.parse(result)
102
117
  else
103
- item.map { |i| self.try("extract_inner_html", i) }
118
+ result
104
119
  end
105
120
  end
106
121
 
107
- def extract_inner_html(item)
108
- item.inner_html
109
- end
110
-
111
- def extract_href(item)
112
- item[:href]
113
- end
114
-
115
- def extract_time(item)
116
- Time.parse(item.inner_html).utc
117
- end
118
-
119
122
  end
@@ -2,10 +2,22 @@ module FeedMe
2
2
 
3
3
  class FeedParser < AbstractParser
4
4
 
5
- self.properties = FEED_PROPERTIES
6
-
7
5
  class << self
8
6
 
7
+ def root_node(node=nil)
8
+ @root_node = node if node
9
+ @root_node
10
+ end
11
+
12
+ def parsers
13
+ @parsers ||= []
14
+ end
15
+
16
+ def inherited(subclass)
17
+ super
18
+ parsers << subclass
19
+ end
20
+
9
21
  def open(file)
10
22
  self.parse(Kernel.open(file).read)
11
23
  end
@@ -13,47 +25,60 @@ module FeedMe
13
25
  # parses the passed feed and identifeis what kind of feed it is
14
26
  # then returns a parser object
15
27
  def parse(feed)
16
- xml = Hpricot.XML(feed)
17
-
18
- root_node, format = self.identify(xml)
19
- raise InvalidFeedFormat if format.nil?
20
-
21
- self.build(root_node, format)
22
- end
23
-
24
- protected
25
-
26
- def identify(xml)
27
- FeedMe::ROOT_NODES.each do |f, s|
28
- item = xml.at(s)
29
- return item, f if item
28
+ document = Nokogiri::XML(feed)
29
+ if root = document.root
30
+ root.add_namespace_definition('atom', 'http://www.w3.org/2005/Atom')
31
+ parsers.each do |parser|
32
+ node = root.xpath(parser.root_node).first
33
+ if node
34
+ return parser.new(node, document.encoding)
35
+ end
36
+ end
30
37
  end
38
+ # if we cannot find a parser, raise an error.
39
+ raise InvalidFeedFormat
31
40
  end
32
41
 
42
+ end # class << self
43
+
44
+ def initialize(xml, encoding)
45
+ @xml = xml
46
+ @encoding = encoding
33
47
  end
48
+
49
+ attr_reader :encoding
50
+
34
51
  end
35
52
 
36
53
  class AtomFeedParser < FeedParser
37
- self.properties = FEED_PROPERTIES
54
+ root_node "//atom:feed"
38
55
 
39
- def entries
40
- xml.search('entry').map do |el|
41
- ItemParser.build(el, self.format, self)
42
- end
43
- end
56
+ property :title, :path => 'atom:title'
57
+ property :feed_id, :path => 'atom:id'
58
+ property :description, :path => 'atom:subtitle'
59
+ property :generator, :path => 'atom:generator'
60
+ property :updated_at, :path => 'atom:updated', :as => :time
61
+ property :url, :path => "atom:link[@rel='alternate']", :from => :href
62
+ property :href, :path => "atom:link[@rel='self']", :from => :href
63
+
64
+ has_many :entries, :path => 'atom:entry', :use => :AtomItemParser
65
+
66
+ has_one :author, :path => 'atom:author', :use => :AtomPersonParser
44
67
  end
45
68
 
46
69
  class Rss2FeedParser < FeedParser
47
- self.properties = FEED_PROPERTIES
70
+ root_node "//rss[@version='2.0']/channel"
48
71
 
49
- def entries
50
- xml.search('item').map do |el|
51
- ItemParser.build(el, self.format, self)
52
- end
53
- end
72
+ property :title
73
+ property :updated_at, :path => :lastBuildDate, :as => :time
74
+ property :feed_id, :path => :undefined
75
+ property :url, :path => :link
76
+ property :href, :path => :undefined
77
+ property :description
78
+ property :generator
54
79
 
55
- def author
56
- fetch_rss_person("managingEditor")
57
- end
80
+ has_many :entries, :path => 'item', :use => :Rss2ItemParser
81
+
82
+ has_one :author, :path => 'managingEditor', :use => :Rss2PersonParser
58
83
  end
59
84
  end
@@ -1,25 +1,25 @@
1
1
  module FeedMe
2
2
 
3
- class ItemParser < AbstractParser
3
+ class ItemParser < AbstractParser; end
4
4
 
5
- self.properties = ITEM_PROPERTIES
6
-
7
- attr_accessor :feed
8
-
9
- def initialize(xml, format, feed)
10
- super(xml, format)
11
- self.feed = feed
12
- end
5
+ class AtomItemParser < ItemParser
6
+ property :title, :path => 'atom:title'
7
+ property :updated_at, :path => "atom:updated", :as => :time
8
+ property :item_id, :path => "atom:id"
9
+ property :url, :path => "atom:link[@rel='alternate']", :from => :href
10
+ property :content, :path => 'atom:content'
13
11
 
12
+ has_one :author, :path => 'atom:author', :use => :AtomPersonParser
14
13
  end
15
14
 
16
15
  class Rss2ItemParser < ItemParser
17
-
18
- self.properties = ITEM_PROPERTIES
19
-
20
- def author
21
- fetch_rss_person("author")
22
- end
23
-
16
+ property :title
17
+ property :updated_at, :path => :pubDate, :as => :time
18
+ property :item_id, :path => :guid
19
+ property :url, :path => :link
20
+ property :content, :path => :description
21
+ property :categories, :path => :category, :cardinality => :many
22
+
23
+ has_one :author, :use => :Rss2PersonParser
24
24
  end
25
- end
25
+ end
@@ -0,0 +1,23 @@
1
+ module FeedMe
2
+
3
+ class PersonParser < AbstractParser; end
4
+
5
+ class AtomPersonParser < PersonParser
6
+ property :email, :path => 'atom:email'
7
+ property :name, :path => 'atom:name'
8
+ property :uri, :path => 'atom:uri'
9
+ end
10
+
11
+ class Rss2PersonParser < PersonParser
12
+ attr_reader :uri
13
+
14
+ def email
15
+ xml.inner_html.split(/\s+/, 2)[0] if xml
16
+ end
17
+
18
+ def name
19
+ xml.inner_html.split(/\s+/, 2)[1].to_s[/\((.*?)\)/, 1] if xml
20
+ end
21
+ end
22
+
23
+ end
@@ -5,24 +5,32 @@ require 'feed_me'
5
5
  describe "all parsing methods", :shared => true do
6
6
  it "should identify an atom feed" do
7
7
  @atom.should be_an_instance_of(FeedMe::AtomFeedParser)
8
- @atom.format.should == :atom
9
8
  @atom.root_node.xpath == "//feed[@xmlns='http://www.w3.org/2005/Atom']"
10
9
  end
11
10
 
12
11
  it "should identify an rss2 feed" do
13
12
  @rss2.should be_an_instance_of(FeedMe::Rss2FeedParser)
14
- @rss2.format.should == :rss2
15
13
  @rss2.root_node.xpath == "//rss[@version=2.0]/channel"
16
14
  end
15
+
16
+ describe "with bad input" do
17
+ it "should raise on an empty body" do
18
+ lambda { FeedMe::FeedParser.parse("") }.should raise_error(FeedMe::InvalidFeedFormat)
19
+ end
20
+
21
+ it "should raise on a body with non-recognised xml" do
22
+ lambda {
23
+ FeedMe::FeedParser.parse(%Q|<?xml version="1.0" encoding="UTF-8"?>"<foo>bar</foo>|)
24
+ }.should raise_error(FeedMe::InvalidFeedFormat)
25
+ end
26
+ end
17
27
  end
18
28
 
19
29
  describe FeedMe::FeedParser do
20
30
 
21
31
  before :each do
22
- @atom_feed = hpricot_fixture('welformed.atom') / "//feed[@xmlns='http://www.w3.org/2005/Atom']"
23
- @atom = FeedMe::FeedParser.build(@atom_feed, :atom)
24
- @rss2_feed = hpricot_fixture('welformed.rss2') / "//rss[@version=2.0]/channel"
25
- @rss2 = FeedMe::FeedParser.build(@rss2_feed, :rss2)
32
+ @atom = FeedMe::FeedParser.parse(open(fixture('welformed.atom')).read)
33
+ @rss2 = FeedMe::FeedParser.parse(open(fixture('welformed.rss2')).read)
26
34
  end
27
35
 
28
36
  it "should be an atom parser for an atom feed" do
@@ -36,19 +44,6 @@ describe FeedMe::FeedParser do
36
44
  end
37
45
 
38
46
  it_should_behave_like "all parsing methods"
39
-
40
- describe "with bad input" do
41
- it "should raise on an empty body" do
42
- lambda { FeedMe::FeedParser.parse("") }.should raise_error(FeedMe::InvalidFeedFormat)
43
- end
44
-
45
- it "should raise on a body with non-recognised xml" do
46
- lambda {
47
- FeedMe::FeedParser.parse(%Q|<?xml version="1.0" encoding="UTF-8"?>"<foo>bar</foo>|)
48
- }.should raise_error(FeedMe::InvalidFeedFormat)
49
- end
50
- end
51
-
52
47
  end
53
48
 
54
49
  describe ".open" do
@@ -60,6 +55,16 @@ describe FeedMe::FeedParser do
60
55
  it_should_behave_like "all parsing methods"
61
56
  end
62
57
 
58
+ describe '#encoding' do
59
+ it "should return the encoding for an atom feed" do
60
+ @atom.encoding.should == 'UTF-8'
61
+ end
62
+
63
+ it "should return the encoding for an atom feed" do
64
+ @rss2.encoding.should == 'iso-8859-1'
65
+ end
66
+ end
67
+
63
68
  describe '#title' do
64
69
  it "should be valid for an atom feed" do
65
70
  @atom.title.should == "Test feed"
@@ -130,16 +135,6 @@ describe FeedMe::FeedParser do
130
135
  end
131
136
  end
132
137
 
133
- describe '#format' do
134
- it "should be :atom for an atom feed" do
135
- @atom.format.should == :atom
136
- end
137
-
138
- it "should be :rss2 for an rss2 feed" do
139
- @rss2.format.should == :rss2
140
- end
141
- end
142
-
143
138
  describe '#author.name' do
144
139
  it "should be valid for an atom feed" do
145
140
  @atom.author.name.should == "Frank"
@@ -6,9 +6,9 @@ describe FeedMe::ItemParser do
6
6
 
7
7
  before :each do
8
8
  @atom_feed = FeedMe::FeedParser.open(fixture('welformed.atom'))
9
- @atom = FeedMe::ItemParser.build(@atom_feed.root_node.search('/entry').first, :atom, @atom_feed)
9
+ @atom = @atom_feed.entries.first
10
10
  @rss2_feed = FeedMe::FeedParser.open(fixture('welformed.rss2'))
11
- @rss2 = FeedMe::ItemParser.build(@rss2_feed.root_node.search('/item').first, :rss2, @rss2_feed)
11
+ @rss2 = @rss2_feed.entries.first
12
12
  end
13
13
 
14
14
  describe '#to_hash' do
@@ -67,16 +67,6 @@ describe FeedMe::ItemParser do
67
67
  end
68
68
  end
69
69
 
70
- describe '#format' do
71
- it "should be :atom for an atom feed" do
72
- @atom.format.should == :atom
73
- end
74
-
75
- it "should be :rss2 for an rss2 feed" do
76
- @rss2.format.should == :rss2
77
- end
78
- end
79
-
80
70
  describe '#categories' do
81
71
  it "should be correct for an rss2 feed" do
82
72
  @rss2.categories.should == ['news', 'chuck']
@@ -170,9 +160,9 @@ describe "Without an author", FeedMe::ItemParser do
170
160
 
171
161
  before :each do
172
162
  @atom_feed = FeedMe::FeedParser.open(fixture('welformed.atom'))
173
- @atom = FeedMe::ItemParser.build(@atom_feed.root_node.search('/entry')[1], :atom, @atom_feed)
163
+ @atom = @atom_feed.entries[1]
174
164
  @rss2_feed = FeedMe::FeedParser.open(fixture('welformed.rss2'))
175
- @rss2 = FeedMe::ItemParser.build(@rss2_feed.root_node.search('/item')[1], :rss2, @rss2_feed)
165
+ @rss2 = @rss2_feed.entries[1]
176
166
  end
177
167
 
178
168
  describe '#author.name' do
@@ -2,7 +2,9 @@ $TESTING=true
2
2
  $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
3
 
4
4
  require 'rubygems'
5
- # require 'ruby-debug'
5
+ require 'ruby-debug'
6
+ require 'spec'
7
+ require 'spec/autorun'
6
8
 
7
9
  module Fixtures
8
10
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: feed_me
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Nicklas
@@ -10,7 +10,7 @@ autorequire: feed_me
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-11-06 00:00:00 +00:00
13
+ date: 2010-01-18 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -40,12 +40,9 @@ files:
40
40
  - TODO
41
41
  - lib/feed_me.rb
42
42
  - lib/feed_me/abstract_parser.rb
43
- - lib/feed_me/consts.rb
44
43
  - lib/feed_me/feed_parser.rb
45
- - lib/feed_me/feed_struct.rb
46
44
  - lib/feed_me/item_parser.rb
47
- - lib/feed_me/merbtasks.rb
48
- - lib/feed_me/simple_struct.rb
45
+ - lib/feed_me/person_parser.rb
49
46
  has_rdoc: true
50
47
  homepage: http://github.com/jnicklas/feed_me
51
48
  licenses: []
@@ -77,5 +74,4 @@ summary: Nice and simple RSS and atom feed parsing built on hpricot
77
74
  test_files:
78
75
  - spec/feed_parser_spec.rb
79
76
  - spec/item_parser_spec.rb
80
- - spec/simple_struct_spec.rb
81
77
  - spec/spec_helper.rb
@@ -1,69 +0,0 @@
1
- module FeedMe
2
-
3
- ROOT_NODES = {
4
- :atom => "//feed[@xmlns='http://www.w3.org/2005/Atom']",
5
- :rss2 => "//rss[@version=2.0]/channel"
6
- }
7
-
8
- FEED_PROPERTIES = {
9
- :atom => {
10
- :title => :title,
11
- :updated_at => [:updated, :time],
12
- :feed_id => :id,
13
- :url => ["link[@rel=alternate]", :href],
14
- :href => ["link[@rel=self]", :href],
15
- :description => :subtitle,
16
- :generator => :generator,
17
- :author => {
18
- :email => 'author/email',
19
- :name => 'author/name',
20
- :uri => 'author/uri'
21
- },
22
- :entries => :special
23
- },
24
- :rss2 => {
25
- :title => :title,
26
- :updated_at => [:lastBuildDate, :time],
27
- :feed_id => :undefined,
28
- :url => :link,
29
- :href => :undefined,
30
- :description => :description,
31
- :generator => :generator,
32
- :author => :special,
33
- :entries => :special
34
- }
35
- }
36
-
37
- ITEM_PROPERTIES = {
38
- :atom => {
39
- :title => :title,
40
- :updated_at => [:updated, :time],
41
- :item_id => :id,
42
- :url => ["link[@rel=alternate]", :href],
43
- :content => :content,
44
- :author => {
45
- :email => 'author/email',
46
- :name => 'author/name',
47
- :uri => 'author/uri'
48
- }
49
- },
50
- :rss2 => {
51
- :title => :title,
52
- :updated_at => [:pubDate, :time],
53
- :item_id => :guid,
54
- :url => :link,
55
- :content => :description,
56
- :author => :special,
57
- :categories => [:category, :array]
58
- }
59
- }
60
-
61
- AUTHOR_PROPERTIES = {
62
- :atom => {
63
- :name => :name,
64
- :uri => :uri,
65
- :email => :email
66
- }
67
- }
68
-
69
- end
@@ -1,13 +0,0 @@
1
- module FeedMe
2
-
3
- class FeedStruct < AbstractParser
4
-
5
- def initialize(xml, properties)
6
- self.xml = xml
7
- self.properties = properties
8
- append_methods
9
- end
10
-
11
- end
12
-
13
- end
@@ -1,6 +0,0 @@
1
- namespace :feed_me do
2
- desc "Do something for feed_me"
3
- task :default do
4
- puts "feed_me doesn't do anything"
5
- end
6
- end
@@ -1,15 +0,0 @@
1
- module FeedMe
2
-
3
- class SimpleStruct
4
-
5
- def initialize(hash = {})
6
- (class << self; self; end).module_eval do
7
- hash.each do |method, result|
8
- define_method( method ) { result }
9
- end
10
- end
11
- end
12
-
13
- end
14
-
15
- end
@@ -1,14 +0,0 @@
1
- require File.join( File.dirname(__FILE__), "spec_helper" )
2
-
3
- require 'feed_me'
4
-
5
- describe FeedMe::SimpleStruct do
6
-
7
- it "should append methods" do
8
- struct = FeedMe::SimpleStruct.new(:foo => "blah", :bar => 23)
9
-
10
- struct.foo.should == "blah"
11
- struct.bar.should == 23
12
- end
13
-
14
- end