ealdent-sax-machine 0.0.7 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -48,6 +48,15 @@ feed.entries.first.title # => title of the first entry
48
48
  feed.entries.first.author # => the author of the first entry
49
49
  feed.entries.first.url # => the permalink on the blog for this entry
50
50
  # etc ...
51
+
52
+ # you can also use the elements method without specifying a class like so
53
+ class SomeServiceResponse
54
+ elements :message, :as => :messages
55
+ end
56
+
57
+ response = SomeServiceResponse.parse("<response><message>hi</message><message>world</message></response>")
58
+ response.messages.first # => "hi"
59
+ response.messages.last # => "world"
51
60
  </pre>
52
61
 
53
62
  h2. LICENSE
data/lib/sax-machine.rb CHANGED
@@ -7,5 +7,5 @@ require "sax-machine/sax_handler"
7
7
  require "sax-machine/sax_config"
8
8
 
9
9
  module SAXMachine
10
- VERSION = "0.0.7"
10
+ VERSION = "0.0.12"
11
11
  end
@@ -21,10 +21,11 @@ module SAXMachine
21
21
  end
22
22
 
23
23
  def element_config_for_attribute(name, attrs)
24
- @top_level_elements.detect do |element_config|
24
+ element_configs = @top_level_elements.select do |element_config|
25
25
  element_config.name == name &&
26
26
  element_config.has_value_and_attrs_match?(attrs)
27
27
  end
28
+ element_configs.empty? ? nil : element_configs
28
29
  end
29
30
 
30
31
  def element_config_for_tag(name, attrs)
@@ -23,19 +23,25 @@ module SAXMachine
23
23
  options[:as] ||= name
24
24
  sax_config.add_top_level_element(name, options)
25
25
 
26
- # we only want to insert the setter if they haven't defined it from elsewhere.
26
+ # we only want to insert the getter and setter if they haven't defined it from elsewhere.
27
27
  # this is how we allow custom parsing behavior. So you could define the setter
28
28
  # and have it parse the string into a date or whatever.
29
- if instance_methods.include?("#{options[:as]}=")
30
- attr_reader options[:as]
31
- else
32
- attr_accessor options[:as]
33
- end
29
+ attr_reader options[:as] unless instance_methods.include?(options[:as].to_s)
30
+ attr_writer options[:as] unless instance_methods.include?("#{options[:as]}=")
34
31
  end
35
32
 
36
33
  def elements(name, options = {})
37
34
  options[:as] ||= name
38
- sax_config.add_collection_element(name, options)
35
+ if options[:class]
36
+ sax_config.add_collection_element(name, options)
37
+ else
38
+ class_eval <<-SRC
39
+ def add_#{options[:as]}(value)
40
+ #{options[:as]} << value
41
+ end
42
+ SRC
43
+ sax_config.add_top_level_element(name, options.merge(:collection => true))
44
+ end
39
45
 
40
46
  class_eval <<-SRC
41
47
  def #{options[:as]}
@@ -2,7 +2,7 @@ module SAXMachine
2
2
  class SAXConfig
3
3
 
4
4
  class ElementConfig
5
- attr_reader :name
5
+ attr_reader :name, :setter
6
6
 
7
7
  def initialize(name, options)
8
8
  @name = name.to_s
@@ -21,16 +21,19 @@ module SAXMachine
21
21
  end
22
22
 
23
23
  @as = options[:as]
24
+ @collection = options[:collection]
25
+
26
+ if @collection
27
+ @setter = "add_#{options[:as]}"
28
+ else
29
+ @setter = "#{@as}="
30
+ end
24
31
  end
25
32
 
26
33
  def value_from_attrs(attrs)
27
34
  attrs[attrs.index(@value) + 1]
28
35
  end
29
36
 
30
- def setter
31
- "#{@as}="
32
- end
33
-
34
37
  def attrs_match?(attrs)
35
38
  if @with
36
39
  @with == (@with & attrs)
@@ -42,6 +45,10 @@ module SAXMachine
42
45
  def has_value_and_attrs_match?(attrs)
43
46
  !@value.nil? && attrs_match?(attrs)
44
47
  end
48
+
49
+ def collection?
50
+ @collection
51
+ end
45
52
  end
46
53
 
47
54
  end
@@ -30,6 +30,7 @@ module SAXMachine
30
30
 
31
31
  elsif @collection_config = sax_config.collection_config(@name)
32
32
  @collection_handler = @collection_config.handler
33
+ @collection_handler.start_element(@name, @attrs)
33
34
 
34
35
  elsif @element_config = sax_config.element_config_for_attribute(@name, @attrs)
35
36
  parse_element_attribute
@@ -67,14 +68,18 @@ module SAXMachine
67
68
  def parse_element_attribute
68
69
  unless parsed_config?
69
70
  mark_as_parsed
70
- @object.send(@element_config.setter, @element_config.value_from_attrs(@attrs))
71
+ @element_config.each do |config|
72
+ @object.send(config.setter, config.value_from_attrs(@attrs))
73
+ end
71
74
  end
72
75
 
73
76
  @element_config = nil
74
77
  end
75
78
 
76
79
  def mark_as_parsed
77
- @parsed_configs[@element_config] = true
80
+ # TODO: make this code not suck like this
81
+ @parsed_configs[@element_config] = true unless (@element_config.respond_to?(:collection?) && @element_config.collection?) ||
82
+ (@element_config.class == Array && @element_config.first.collection?)
78
83
  end
79
84
 
80
85
  def parsed_config?
@@ -209,37 +209,55 @@ describe "SAXMachine" do
209
209
  document = @klass.parse("<link foo='test'/>")
210
210
  document.link.should == 'test'
211
211
  end
212
+
213
+ it "should save two different attribute values on a single tag" do
214
+ @klass = Class.new do
215
+ include SAXMachine
216
+ element :link, :value => :foo, :as => :first
217
+ element :link, :value => :bar, :as => :second
218
+ end
219
+ document = @klass.parse("<link foo='foo value' bar='bar value'></link>")
220
+ document.first.should == "foo value"
221
+ document.second.should == "bar value"
222
+ end
212
223
  end
213
224
  end
214
225
  end
215
226
 
216
227
  describe "elements" do
217
- # I took this stuff out because I'm not sure yet if this is something I want to bother supporting.
218
-
219
- # describe "when parsing multiple elements" do
220
- # before :each do
221
- # @klass = Class.new do
222
- # include SAXMachine
223
- # elements :entry, :as => :entries
224
- # end
225
- # end
226
- #
227
- # it "should provide a collection accessor" do
228
- # document = @klass.new
229
- # document.entries << :foo
230
- # document.entries.should == [:foo]
231
- # end
232
- #
233
- # it "should parse a single element" do
234
- # document = @klass.parse("<entry>hello</entry>")
235
- # document.entries.should == ["hello"]
236
- # end
237
- #
238
- # it "should parse multiple elements" do
239
- # document = @klass.parse("<xml><entry>hello</entry><entry>world</entry></xml>")
240
- # document.entries.should == ["hello", "world"]
241
- # end
242
- # end
228
+ describe "when parsing multiple elements" do
229
+ before :each do
230
+ @klass = Class.new do
231
+ include SAXMachine
232
+ elements :entry, :as => :entries
233
+ end
234
+ end
235
+
236
+ it "should provide a collection accessor" do
237
+ document = @klass.new
238
+ document.entries << :foo
239
+ document.entries.should == [:foo]
240
+ end
241
+
242
+ it "should parse a single element" do
243
+ document = @klass.parse("<entry>hello</entry>")
244
+ document.entries.should == ["hello"]
245
+ end
246
+
247
+ it "should parse multiple elements" do
248
+ document = @klass.parse("<xml><entry>hello</entry><entry>world</entry></xml>")
249
+ document.entries.should == ["hello", "world"]
250
+ end
251
+
252
+ it "should parse multiple elements when taking an attribute value" do
253
+ attribute_klass = Class.new do
254
+ include SAXMachine
255
+ elements :entry, :as => :entries, :value => :foo
256
+ end
257
+ doc = attribute_klass.parse("<xml><entry foo='asdf' /><entry foo='jkl' /></xml>")
258
+ doc.entries.should == ["asdf", "jkl"]
259
+ end
260
+ end
243
261
 
244
262
  describe "when using the class option" do
245
263
  before :each do
@@ -271,6 +289,16 @@ describe "SAXMachine" do
271
289
  document.entries.size.should == 1
272
290
  document.entries.first.title.should == "correct title"
273
291
  end
292
+
293
+ it "should parse out an attribute value from the tag that starts the collection" do
294
+ class Foo
295
+ element :entry, :value => :href, :as => :url
296
+ end
297
+ document = @klass.parse("<xml><entry href='http://pauldix.net'><title>paul</title></entry></xml>")
298
+ document.entries.size.should == 1
299
+ document.entries.first.title.should == "paul"
300
+ document.entries.first.url.should == "http://pauldix.net"
301
+ end
274
302
  end
275
303
  end
276
304
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ealdent-sax-machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Dix
@@ -14,6 +14,7 @@ default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: nokogiri
17
+ type: :runtime
17
18
  version_requirement:
18
19
  version_requirements: !ruby/object:Gem::Requirement
19
20
  requirements: