ealdent-sax-machine 0.0.7 → 0.0.12

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.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: