feed_me 0.0.5 → 0.6.0

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