sax-machine 0.0.15 → 0.0.20

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/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'nokogiri', '>= 1.4.4'
4
+ gem 'rspec', '>= 2.6.0'
data/README.textile CHANGED
@@ -23,6 +23,7 @@ class AtomEntry
23
23
  element :summary
24
24
  element :content
25
25
  element :published
26
+ parent :parent
26
27
  end
27
28
 
28
29
  # Class for parsing Atom feeds
@@ -43,10 +44,11 @@ feed = Atom.parse(xml_text)
43
44
  feed.title # => whatever the title of the blog is
44
45
  feed.url # => the main url of the blog
45
46
  feed.feed_url # => goes to the feedburner feed
46
-
47
+
47
48
  feed.entries.first.title # => title of the first entry
48
49
  feed.entries.first.author # => the author of the first entry
49
50
  feed.entries.first.url # => the permalink on the blog for this entry
51
+ feed.entries.first.parent # => the Atom parent
50
52
  # etc ...
51
53
 
52
54
  # you can also use the elements method without specifying a class like so
@@ -62,11 +64,11 @@ response.messages.last # => "world"
62
64
  h2. LICENSE
63
65
 
64
66
  (The MIT License)
65
-
66
- Copyright (c) 2009:
67
-
67
+
68
+ Copyright (c) 2009 - 2011:
69
+
68
70
  "Paul Dix":http://pauldix.net
69
-
71
+
70
72
  Permission is hereby granted, free of charge, to any person obtaining
71
73
  a copy of this software and associated documentation files (the
72
74
  'Software'), to deal in the Software without restriction, including
@@ -74,10 +76,10 @@ without limitation the rights to use, copy, modify, merge, publish,
74
76
  distribute, sublicense, and/or sell copies of the Software, and to
75
77
  permit persons to whom the Software is furnished to do so, subject to
76
78
  the following conditions:
77
-
79
+
78
80
  The above copyright notice and this permission notice shall be
79
81
  included in all copies or substantial portions of the Software.
80
-
82
+
81
83
  THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
82
84
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
83
85
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
data/Rakefile CHANGED
@@ -1,14 +1,21 @@
1
- require "spec"
2
- require "spec/rake/spectask"
3
- require 'lib/sax-machine.rb'
1
+ require "rspec/core/rake_task"
4
2
 
5
- Spec::Rake::SpecTask.new do |t|
6
- t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
7
- t.spec_files = FileList['spec/**/*_spec.rb']
3
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
4
+ require 'sax-machine'
5
+
6
+ desc "Run all specs"
7
+ RSpec::Core::RakeTask.new do |t|
8
+ t.rspec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
9
+ end
10
+
11
+ task :default => [:spec]
12
+
13
+ task :test do
14
+ sh 'rspec spec'
8
15
  end
9
16
 
10
17
  task :install do
11
18
  rm_rf "*.gem"
12
19
  puts `gem build sax-machine.gemspec`
13
20
  puts `sudo gem install sax-machine-#{SAXMachine::VERSION}.gem`
14
- end
21
+ end
@@ -0,0 +1,40 @@
1
+ module SAXMachine
2
+ class SAXConfig
3
+
4
+ class AttributeConfig
5
+ attr_reader :name, :setter
6
+
7
+ def initialize(name, options)
8
+ @name = name.to_s
9
+ @as = options[:as]
10
+ @setter = "#{@as}="
11
+ @required = options[:required]
12
+ end
13
+
14
+ def column
15
+ @as || @name.to_sym
16
+ end
17
+
18
+ def required?
19
+ @required
20
+ end
21
+
22
+ def value_from_attrs(attrs)
23
+ attrs.index(@name) ? attrs[attrs.index(@name) + 1] : nil
24
+ end
25
+
26
+ def attrs_match?(attrs)
27
+ attrs.index(@name) ? true : false
28
+ end
29
+
30
+ def has_value_and_attrs_match?(attrs)
31
+ attrs_match?(attrs)
32
+ end
33
+
34
+ def collection?
35
+ false
36
+ end
37
+ end
38
+
39
+ end
40
+ end
@@ -1,47 +1,74 @@
1
+ require "sax-machine/sax_attribute_config"
2
+ require "sax-machine/sax_element_value_config"
1
3
  require "sax-machine/sax_element_config"
2
4
  require "sax-machine/sax_collection_config"
5
+ require "sax-machine/sax_parent_config"
3
6
 
4
7
  module SAXMachine
5
8
  class SAXConfig
6
- attr_accessor :top_level_elements, :collection_elements
7
-
9
+
10
+ attr_accessor :top_level_elements, :top_level_attributes, :top_level_element_value, :collection_elements, :parents
11
+
8
12
  def initialize
9
- @top_level_elements = {}
10
- @collection_elements = {}
13
+ # Default value is an empty array
14
+ @top_level_elements = Hash.new { |hash, key| hash[key] = [] }
15
+ @top_level_attributes = []
16
+ @top_level_element_value = []
17
+ @collection_elements = Hash.new { |hash, key| hash[key] = [] }
18
+ @parents = []
11
19
  end
12
-
20
+
13
21
  def columns
14
22
  @top_level_elements.map {|name, ecs| ecs }.flatten
15
23
  end
16
-
24
+
17
25
  def initialize_copy(sax_config)
26
+ super
18
27
  @top_level_elements = sax_config.top_level_elements.clone
28
+ @top_level_attributes = sax_config.top_level_attributes.clone
29
+ @top_level_element_value = sax_config.top_level_element_value.clone
19
30
  @collection_elements = sax_config.collection_elements.clone
31
+ @parents = sax_config.parents.clone
20
32
  end
21
33
 
22
34
  def add_top_level_element(name, options)
23
- @top_level_elements[name.to_s] = [] unless @top_level_elements[name.to_s]
24
35
  @top_level_elements[name.to_s] << ElementConfig.new(name, options)
25
36
  end
26
37
 
38
+ def add_top_level_attribute(name, options)
39
+ @top_level_attributes << AttributeConfig.new(options.delete(:name), options)
40
+ end
41
+
42
+ def add_top_level_element_value(name, options)
43
+ @top_level_element_value << ElementValueConfig.new(options.delete(:name), options)
44
+ end
45
+
27
46
  def add_collection_element(name, options)
28
- @collection_elements[name.to_s] = [] unless @collection_elements[name.to_s]
29
47
  @collection_elements[name.to_s] << CollectionConfig.new(name, options)
30
48
  end
31
49
 
50
+ def add_parent(name, options)
51
+ @parents << ParentConfig.new(name, options)
52
+ end
53
+
32
54
  def collection_config(name, attrs)
33
- ces = @collection_elements[name.to_s]
34
- ces && ces.detect { |cc| cc.attrs_match?(attrs) }
55
+ @collection_elements[name.to_s].detect { |cc| cc.attrs_match?(attrs) }
56
+ end
57
+
58
+ def attribute_configs_for_element(attrs)
59
+ @top_level_attributes.select { |aa| aa.attrs_match?(attrs) }
60
+ end
61
+
62
+ def element_values_for_element
63
+ @top_level_element_value
35
64
  end
36
65
 
37
66
  def element_configs_for_attribute(name, attrs)
38
- tes = @top_level_elements[name.to_s]
39
- tes && tes.select { |ec| ec.has_value_and_attrs_match?(attrs) } || []
67
+ @top_level_elements[name.to_s].select { |ec| ec.has_value_and_attrs_match?(attrs) }
40
68
  end
41
69
 
42
70
  def element_config_for_tag(name, attrs)
43
- tes = @top_level_elements[name.to_s]
44
- tes && tes.detect { |ec| ec.attrs_match?(attrs) }
71
+ @top_level_elements[name.to_s].detect { |ec| ec.attrs_match?(attrs) }
45
72
  end
46
73
  end
47
74
  end
@@ -1,33 +1,50 @@
1
1
  require "nokogiri"
2
2
 
3
3
  module SAXMachine
4
-
4
+
5
5
  def self.included(base)
6
6
  base.extend ClassMethods
7
7
  end
8
-
9
- def parse(xml_text)
10
- sax_handler = SAXHandler.new(self)
8
+
9
+ def parse(xml_text, on_error = nil, on_warning = nil)
10
+ sax_handler = SAXHandler.new(self, on_error, on_warning)
11
11
  parser = Nokogiri::XML::SAX::Parser.new(sax_handler)
12
12
  parser.parse(xml_text)
13
13
  self
14
14
  end
15
-
15
+
16
16
  module ClassMethods
17
17
 
18
- def parse(xml_text)
19
- new.parse(xml_text)
18
+ def inherited(subclass)
19
+ subclass.sax_config.send(:initialize_copy, self.sax_config)
20
20
  end
21
-
21
+
22
+ def parse(xml_text, on_error = nil, on_warning = nil)
23
+ new.parse(xml_text, on_error, on_warning)
24
+ end
25
+
22
26
  def element(name, options = {})
23
- options[:as] ||= name
27
+ real_name = (options[:as] ||= name).to_s
24
28
  sax_config.add_top_level_element(name, options)
25
-
26
- # we only want to insert the getter and setter if they haven't defined it from elsewhere.
27
- # this is how we allow custom parsing behavior. So you could define the setter
28
- # and have it parse the string into a date or whatever.
29
- attr_reader options[:as] unless instance_methods.include?(options[:as].to_s)
30
- attr_writer options[:as] unless instance_methods.include?("#{options[:as]}=")
29
+ create_attr real_name
30
+ end
31
+
32
+ def attribute(name, options = {})
33
+ real_name = (options[:as] ||= name).to_s
34
+ sax_config.add_top_level_attribute(self.class.to_s, options.merge(:name => name))
35
+ create_attr real_name
36
+ end
37
+
38
+ def value(name, options = {})
39
+ real_name = (options[:as] ||= name).to_s
40
+ sax_config.add_top_level_element_value(self.class.to_s, options.merge(:name => name))
41
+ create_attr real_name
42
+ end
43
+
44
+ def parent(name, options = {})
45
+ real_name = (options[:as] ||= name).to_s
46
+ sax_config.add_parent(name, options)
47
+ create_attr(real_name)
31
48
  end
32
49
 
33
50
  def columns
@@ -35,7 +52,7 @@ module SAXMachine
35
52
  end
36
53
 
37
54
  def column(sym)
38
- columns.select{|c| c.column == sym}[0]
55
+ columns.select { |c| c.column == sym }[0]
39
56
  end
40
57
 
41
58
  def data_class(sym)
@@ -47,9 +64,9 @@ module SAXMachine
47
64
  end
48
65
 
49
66
  def column_names
50
- columns.map{|e| e.column}
67
+ columns.map { |e| e.column }
51
68
  end
52
-
69
+
53
70
  def elements(name, options = {})
54
71
  options[:as] ||= name
55
72
  if options[:class]
@@ -62,21 +79,29 @@ module SAXMachine
62
79
  SRC
63
80
  sax_config.add_top_level_element(name, options.merge(:collection => true))
64
81
  end
65
-
66
- if !instance_methods.include?(options[:as].to_s)
67
- class_eval <<-SRC
82
+
83
+ if !method_defined?(options[:as].to_s)
84
+ class_eval <<-SRC
68
85
  def #{options[:as]}
69
86
  @#{options[:as]} ||= []
70
87
  end
71
88
  SRC
72
89
  end
73
-
74
- attr_writer options[:as] unless instance_methods.include?("#{options[:as]}=")
90
+
91
+ attr_writer options[:as] unless method_defined?("#{options[:as]}=")
75
92
  end
76
-
93
+
77
94
  def sax_config
78
95
  @sax_config ||= SAXConfig.new
79
96
  end
97
+
98
+ # we only want to insert the getter and setter if they haven't defined it from elsewhere.
99
+ # this is how we allow custom parsing behavior. So you could define the setter
100
+ # and have it parse the string into a date or whatever.
101
+ def create_attr real_name
102
+ attr_reader real_name unless method_defined?(real_name)
103
+ attr_writer real_name unless method_defined?("#{real_name}=")
104
+ end
80
105
  end
81
-
82
- end
106
+
107
+ end
@@ -31,6 +31,14 @@ module SAXMachine
31
31
  @data_class = options[:class]
32
32
  @required = options[:required]
33
33
  end
34
+
35
+ def value_configured?
36
+ !@value.nil?
37
+ end
38
+
39
+ def to_s
40
+ "name: #{@name} dataclass: #{@data_class} setter: #{@setter} required: #{@required} value: #{@value} as:#{@as} collection: #{@collection} with: #{@with}"
41
+ end
34
42
 
35
43
  def column
36
44
  @as || @name.to_sym
@@ -62,4 +70,4 @@ module SAXMachine
62
70
  end
63
71
 
64
72
  end
65
- end
73
+ end
@@ -0,0 +1,24 @@
1
+ module SAXMachine
2
+ class SAXConfig
3
+
4
+ class ElementValueConfig
5
+ attr_reader :name, :setter
6
+
7
+ def initialize(name, options)
8
+ @name = name.to_s
9
+ @as = options[:as]
10
+ @setter = "#{@as}="
11
+ @required = options[:required]
12
+ end
13
+
14
+ def column
15
+ @as || @name.to_sym
16
+ end
17
+
18
+ def required?
19
+ @required
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -4,9 +4,11 @@ module SAXMachine
4
4
  class SAXHandler < Nokogiri::XML::SAX::Document
5
5
  attr_reader :stack
6
6
 
7
- def initialize(object)
8
- @stack = [[object, nil, ""]]
7
+ def initialize(object, on_error = nil, on_warning = nil)
8
+ @stack = [[object, nil, String.new]]
9
9
  @parsed_configs = {}
10
+ @on_error = on_error
11
+ @on_warning = on_warning
10
12
  end
11
13
 
12
14
  def characters(string)
@@ -19,13 +21,18 @@ module SAXMachine
19
21
  end
20
22
 
21
23
  def start_element(name, attrs = [])
24
+ attrs.flatten!
22
25
  object, config, value = stack.last
23
26
  sax_config = object.class.respond_to?(:sax_config) ? object.class.sax_config : nil
24
27
 
25
28
  if sax_config
26
29
  if collection_config = sax_config.collection_config(name, attrs)
27
- stack.push [object = collection_config.data_class.new, collection_config, ""]
30
+ stack.push [object = collection_config.data_class.new, collection_config, String.new]
28
31
  object, sax_config, is_collection = object, object.class.sax_config, true
32
+
33
+ if (attribute_config = object.class.respond_to?(:sax_config) && object.class.sax_config.attribute_configs_for_element(attrs))
34
+ attribute_config.each { |ac| object.send(ac.setter, ac.value_from_attrs(attrs)) }
35
+ end
29
36
  end
30
37
  sax_config.element_configs_for_attribute(name, attrs).each do |ec|
31
38
  unless parsed_config?(object, ec)
@@ -34,7 +41,12 @@ module SAXMachine
34
41
  end
35
42
  end
36
43
  if !collection_config && element_config = sax_config.element_config_for_tag(name, attrs)
37
- stack.push [element_config.data_class ? element_config.data_class.new : object, element_config, ""]
44
+ new_object = element_config.data_class ? element_config.data_class.new : object
45
+ stack.push [new_object, element_config, String.new]
46
+
47
+ if (attribute_config = new_object.class.respond_to?(:sax_config) && new_object.class.sax_config.attribute_configs_for_element(attrs))
48
+ attribute_config.each { |ac| new_object.send(ac.setter, ac.value_from_attrs(attrs)) }
49
+ end
38
50
  end
39
51
  end
40
52
  end
@@ -44,13 +56,29 @@ module SAXMachine
44
56
  return unless stack.size > 1 && config && config.name.to_s == name.to_s
45
57
 
46
58
  unless parsed_config?(object, config)
59
+ if (element_value_config = config.data_class.respond_to?(:sax_config) && config.data_class.sax_config.element_values_for_element)
60
+ element_value_config.each { |evc| element.send(evc.setter, value) }
61
+ end
62
+
47
63
  if config.respond_to?(:accessor)
64
+ subconfig = element.class.sax_config if element.class.respond_to?(:sax_config)
65
+ if econf = subconfig.element_config_for_tag(name, [])
66
+ element.send(econf.setter, value) unless econf.value_configured?
67
+ end
48
68
  object.send(config.accessor) << element
49
69
  else
50
70
  value = config.data_class ? element : value
51
71
  object.send(config.setter, value) unless value == ""
52
72
  mark_as_parsed(object, config)
53
73
  end
74
+
75
+ # try to set the parent
76
+ sax_config = element.class.respond_to?(:sax_config) ? element.class.sax_config : nil
77
+ if sax_config
78
+ sax_config.parents.each do |parent|
79
+ element.send(parent.setter, object)
80
+ end
81
+ end
54
82
  end
55
83
  stack.pop
56
84
  end
@@ -62,5 +90,18 @@ module SAXMachine
62
90
  def parsed_config?(object, element_config)
63
91
  @parsed_configs[[object.object_id, element_config.object_id]]
64
92
  end
93
+
94
+ def warning string
95
+ if @on_warning
96
+ @on_warning.call(string)
97
+ end
98
+ end
99
+
100
+ def error string
101
+ if @on_error
102
+ @on_error.call(string)
103
+ end
104
+ end
105
+
65
106
  end
66
- end
107
+ end
@@ -0,0 +1,21 @@
1
+ module SAXMachine
2
+ class SAXConfig
3
+
4
+ class ParentConfig
5
+ attr_reader :name, :setter
6
+
7
+ def initialize(name, options)
8
+ @name = name.to_s
9
+
10
+ @as = options[:as]
11
+ @setter = "#{@as}="
12
+ end
13
+
14
+ def column
15
+ @as || @name.to_sym
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
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.15"
10
+ VERSION = "0.0.16"
11
11
  end
@@ -20,11 +20,26 @@ describe "SAXMachine" do
20
20
  @klass.column_names.should =~ [:title]
21
21
  end
22
22
 
23
+ it "should not overwrite the getter is there is already one present" do
24
+ @klass = Class.new do
25
+ def title
26
+ "#{@title} ***"
27
+ end
28
+
29
+ include SAXMachine
30
+ element :title
31
+ end
32
+ document = @klass.new
33
+ document.title = "Title"
34
+ document.title.should == "Title ***"
35
+ end
36
+
23
37
  it "should not overwrite the setter if there is already one present" do
24
38
  @klass = Class.new do
25
39
  def title=(val)
26
40
  @title = "#{val} **"
27
41
  end
42
+
28
43
  include SAXMachine
29
44
  element :title
30
45
  end
@@ -105,6 +120,36 @@ describe "SAXMachine" do
105
120
  document.name.should == "Paul"
106
121
  document.title.should == "My Title"
107
122
  end
123
+
124
+
125
+ it "should not overwrite the getter is there is already one present" do
126
+ @klass = Class.new do
127
+ def items
128
+ []
129
+ end
130
+
131
+ include SAXMachine
132
+ elements :items
133
+ end
134
+ document = @klass.new
135
+ document.items = [1, 2, 3, 4]
136
+ document.items.should == []
137
+ end
138
+
139
+ it "should not overwrite the setter if there is already one present" do
140
+ @klass = Class.new do
141
+ def items=(val)
142
+ @items = [1, *val]
143
+ end
144
+
145
+ include SAXMachine
146
+ elements :items
147
+ end
148
+ document = @klass.new
149
+ document.items = [2, 3]
150
+ document.items.should == [1, 2, 3]
151
+ end
152
+
108
153
  end
109
154
 
110
155
  describe "when using options for parsing elements" do
@@ -382,6 +427,23 @@ describe "SAXMachine" do
382
427
  document.entries.first.title.should == "correct title"
383
428
  end
384
429
 
430
+ it "should parse elements, and make attributes and inner text available" do
431
+ class Related
432
+ include SAXMachine
433
+ element 'related', :as=>:item
434
+ element 'related', :as=>:attr, :value=>'attr'
435
+ end
436
+ class Foo
437
+ elements 'related', :as=>'items', :class=>Related
438
+ end
439
+
440
+ doc = Foo.parse(%{<xml><collection><related attr='baz'>something</related><related>somethingelse</related></collection></xml>})
441
+ doc.items.first.should_not be_nil
442
+ doc.items.size.should == 2
443
+ doc.items.first.item.should == 'something'
444
+ doc.items.last.item.should == 'somethingelse'
445
+ end
446
+
385
447
  it "should parse out an attribute value from the tag that starts the collection" do
386
448
  class Foo
387
449
  element :entry, :value => :href, :as => :url
@@ -392,7 +454,6 @@ describe "SAXMachine" do
392
454
  document.entries.first.url.should == "http://pauldix.net"
393
455
  end
394
456
  end
395
-
396
457
  end
397
458
 
398
459
  describe "full example" do
@@ -437,13 +498,15 @@ describe "SAXMachine" do
437
498
  </category>
438
499
  </categories>
439
500
  ]
440
- class CategoryCollection; end
501
+ class CategoryCollection;
502
+ end
441
503
  class Category
442
504
  include SAXMachine
443
505
  attr_accessor :id
444
506
  element :category, :value => :id, :as => :id
445
507
  element :title
446
508
  element :categories, :as => :collection, :class => CategoryCollection
509
+ parent :parent
447
510
  end
448
511
  class CategoryCollection
449
512
  include SAXMachine
@@ -455,6 +518,7 @@ describe "SAXMachine" do
455
518
  it "should parse the first category" do
456
519
  @collection.categories.first.id.should == "1"
457
520
  @collection.categories.first.title.should == "First"
521
+ @collection.categories.first.parent.should == @collection
458
522
  end
459
523
 
460
524
  it "should parse the nested category" do
@@ -524,4 +588,151 @@ describe "SAXMachine" do
524
588
  @item.title.should == "Hello"
525
589
  end
526
590
  end
591
+
592
+ describe "with config to pull multiple attributes" do
593
+ before do
594
+ @xml = %[
595
+ <item id="1">
596
+ <author name="John Doe" role="writer" />
597
+ </item>
598
+ ]
599
+ class AuthorElement
600
+ include SAXMachine
601
+ attribute :name
602
+ attribute :role
603
+ end
604
+ class ItemElement
605
+ include SAXMachine
606
+ element :author, :class => AuthorElement
607
+ end
608
+ @item = ItemElement.parse(@xml)
609
+ end
610
+
611
+ it 'should have the child element' do
612
+ @item.author.should_not be_nil
613
+ end
614
+
615
+ it 'should have the author name' do
616
+ @item.author.name.should == 'John Doe'
617
+ end
618
+
619
+ it 'should have the author role' do
620
+ @item.author.role.should == 'writer'
621
+ end
622
+ end
623
+
624
+ describe "with multiple elements and multiple attributes" do
625
+ before do
626
+ @xml = %[
627
+ <item id="1">
628
+ <author name="John Doe" role="writer" />
629
+ <author name="Jane Doe" role="artist" />
630
+ </item>
631
+ ]
632
+ class AuthorElement2
633
+ include SAXMachine
634
+ attribute :name
635
+ attribute :role
636
+ end
637
+ class ItemElement2
638
+ include SAXMachine
639
+ elements :author, :as => :authors, :class => AuthorElement2
640
+ end
641
+ @item = ItemElement2.parse(@xml)
642
+ end
643
+
644
+ it 'should have the child elements' do
645
+ @item.authors.should_not be_nil
646
+ @item.authors.count.should == 2
647
+ end
648
+
649
+ it 'should have the author names' do
650
+ @item.authors.first.name.should == 'John Doe'
651
+ @item.authors.last.name.should == 'Jane Doe'
652
+ end
653
+
654
+ it 'should have the author roles' do
655
+ @item.authors.first.role.should == 'writer'
656
+ @item.authors.last.role.should == 'artist'
657
+ end
658
+ end
659
+
660
+ describe "with mixed attributes and element values" do
661
+ before do
662
+ @xml = %[
663
+ <item id="1">
664
+ <author role="writer">John Doe</author>
665
+ </item>
666
+ ]
667
+ class AuthorElement3
668
+ include SAXMachine
669
+ value :name
670
+ attribute :role
671
+ end
672
+ class ItemElement3
673
+ include SAXMachine
674
+ element :author, :class => AuthorElement3
675
+ end
676
+ @item = ItemElement3.parse(@xml)
677
+ end
678
+
679
+ it 'should have the child elements' do
680
+ @item.author.should_not be_nil
681
+ end
682
+
683
+ it 'should have the author names' do
684
+ @item.author.name.should == 'John Doe'
685
+ end
686
+
687
+ it 'should have the author roles' do
688
+ @item.author.role.should == 'writer'
689
+ end
690
+ end
691
+
692
+ describe "with multiple mixed attributes and element values" do
693
+ before do
694
+ @xml = %[
695
+ <item id="1">
696
+ <title>sweet</title>
697
+ <author role="writer">John Doe</author>
698
+ <author role="artist">Jane Doe</author>
699
+ </item>
700
+ ]
701
+ class AuthorElement4
702
+ include SAXMachine
703
+ value :name
704
+ attribute :role
705
+ end
706
+ class ItemElement4
707
+ include SAXMachine
708
+ element :title
709
+ elements :author, :as => :authors, :class => AuthorElement4
710
+
711
+ def title=(blah)
712
+ #raise 'woo'
713
+ @title = blah
714
+ end
715
+ end
716
+ @item = ItemElement4.parse(@xml)
717
+ end
718
+
719
+ it 'should have the title' do
720
+ @item.title.should == 'sweet'
721
+ end
722
+
723
+ it 'should have the child elements' do
724
+ @item.authors.should_not be_nil
725
+ @item.authors.count.should == 2
726
+ end
727
+
728
+ it 'should have the author names' do
729
+ @item.authors.first.name.should == 'John Doe'
730
+ @item.authors.last.name.should == 'Jane Doe'
731
+ end
732
+
733
+ it 'should have the author roles' do
734
+ @item.authors.first.role.should == 'writer'
735
+ @item.authors.last.role.should == 'artist'
736
+ end
737
+ end
527
738
  end
data/spec/spec_helper.rb CHANGED
@@ -1,13 +1,11 @@
1
- require "rubygems"
2
- require "spec"
1
+ require 'date'
3
2
 
4
3
  # gem install redgreen for colored test output
5
- begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end
4
+ begin require "redgreen" unless ENV['TM_CURRENT_LINE']
5
+ rescue LoadError
6
+ end
6
7
 
7
8
  path = File.expand_path(File.dirname(__FILE__) + "/../lib/")
8
9
  $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
9
10
 
10
- require "lib/sax-machine"
11
-
12
- # Spec::Runner.configure do |config|
13
- # end
11
+ require "sax-machine"
metadata CHANGED
@@ -1,27 +1,39 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sax-machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ hash: 55
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 20
10
+ version: 0.0.20
5
11
  platform: ruby
6
12
  authors:
7
13
  - Paul Dix
14
+ - Julien Kirch
8
15
  autorequire:
9
16
  bindir: bin
10
17
  cert_chain: []
11
18
 
12
- date: 2009-01-13 00:00:00 -05:00
13
- default_executable:
19
+ date: 2011-07-20 00:00:00 Z
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: nokogiri
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">"
22
28
  - !ruby/object:Gem::Version
29
+ hash: 31
30
+ segments:
31
+ - 0
32
+ - 0
33
+ - 0
23
34
  version: 0.0.0
24
- version:
35
+ type: :runtime
36
+ version_requirements: *id001
25
37
  description:
26
38
  email: paul@pauldix.net
27
39
  executables: []
@@ -32,17 +44,19 @@ extra_rdoc_files: []
32
44
 
33
45
  files:
34
46
  - lib/sax-machine.rb
47
+ - lib/sax-machine/sax_attribute_config.rb
35
48
  - lib/sax-machine/sax_config.rb
49
+ - lib/sax-machine/sax_document.rb
36
50
  - lib/sax-machine/sax_collection_config.rb
37
51
  - lib/sax-machine/sax_element_config.rb
38
- - lib/sax-machine/sax_document.rb
52
+ - lib/sax-machine/sax_element_value_config.rb
39
53
  - lib/sax-machine/sax_handler.rb
54
+ - lib/sax-machine/sax_parent_config.rb
40
55
  - README.textile
41
56
  - Rakefile
42
- - spec/spec.opts
57
+ - Gemfile
43
58
  - spec/spec_helper.rb
44
59
  - spec/sax-machine/sax_document_spec.rb
45
- has_rdoc: true
46
60
  homepage: http://github.com/pauldix/sax-machine
47
61
  licenses: []
48
62
 
@@ -52,21 +66,27 @@ rdoc_options: []
52
66
  require_paths:
53
67
  - lib
54
68
  required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
55
70
  requirements:
56
71
  - - ">="
57
72
  - !ruby/object:Gem::Version
73
+ hash: 3
74
+ segments:
75
+ - 0
58
76
  version: "0"
59
- version:
60
77
  required_rubygems_version: !ruby/object:Gem::Requirement
78
+ none: false
61
79
  requirements:
62
80
  - - ">="
63
81
  - !ruby/object:Gem::Version
82
+ hash: 3
83
+ segments:
84
+ - 0
64
85
  version: "0"
65
- version:
66
86
  requirements: []
67
87
 
68
88
  rubyforge_project:
69
- rubygems_version: 1.3.5
89
+ rubygems_version: 1.8.5
70
90
  signing_key:
71
91
  specification_version: 2
72
92
  summary: Declarative SAX Parsing with Nokogiri
data/spec/spec.opts DELETED
@@ -1,2 +0,0 @@
1
- --diff
2
- --color