sax-machine 0.1.0 → 1.3.2

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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +32 -0
  5. data/Gemfile +13 -2
  6. data/Guardfile +5 -0
  7. data/HISTORY.md +77 -0
  8. data/README.md +207 -0
  9. data/Rakefile +6 -20
  10. data/lib/sax-machine/{sax_ancestor_config.rb → config/sax_ancestor.rb} +3 -7
  11. data/lib/sax-machine/config/sax_attribute.rb +18 -0
  12. data/lib/sax-machine/config/sax_collection.rb +33 -0
  13. data/lib/sax-machine/{sax_element_config.rb → config/sax_element.rb} +23 -31
  14. data/lib/sax-machine/{sax_element_value_config.rb → config/sax_element_value.rb} +7 -8
  15. data/lib/sax-machine/handlers/sax_abstract_handler.rb +199 -0
  16. data/lib/sax-machine/handlers/sax_nokogiri_handler.rb +23 -0
  17. data/lib/sax-machine/handlers/sax_oga_handler.rb +39 -0
  18. data/lib/sax-machine/handlers/sax_ox_handler.rb +56 -0
  19. data/lib/sax-machine/sax_config.rb +13 -9
  20. data/lib/sax-machine/sax_configure.rb +3 -8
  21. data/lib/sax-machine/sax_document.rb +79 -49
  22. data/lib/sax-machine/version.rb +3 -0
  23. data/lib/sax-machine.rb +26 -7
  24. data/sax-machine.gemspec +20 -0
  25. data/spec/fixtures/atom-content.html +15 -0
  26. data/spec/fixtures/atom.xml +165 -0
  27. data/spec/sax-machine/sax_activerecord_spec.rb +21 -0
  28. data/spec/sax-machine/sax_configure_spec.rb +51 -0
  29. data/spec/sax-machine/sax_document_spec.rb +709 -239
  30. data/spec/sax-machine/sax_include_spec.rb +49 -0
  31. data/spec/spec_helper.rb +18 -7
  32. metadata +71 -70
  33. data/README.textile +0 -110
  34. data/lib/sax-machine/sax_attribute_config.rb +0 -40
  35. data/lib/sax-machine/sax_collection_config.rb +0 -45
  36. data/lib/sax-machine/sax_handler.rb +0 -107
  37. data/spec/sax-machine/configure_sax_machine_spec.rb +0 -53
  38. data/spec/sax-machine/include_sax_machine_spec.rb +0 -42
@@ -0,0 +1,49 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "SAXMachine inheritance" do
4
+ before do
5
+ class A
6
+ include SAXMachine
7
+ element :title
8
+ end
9
+
10
+ class B < A
11
+ element :b
12
+ end
13
+
14
+ class C < B
15
+ element :c
16
+ end
17
+
18
+ xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
19
+ @a = A.new
20
+ @a.parse xml
21
+ @b = B.new
22
+ @b.parse xml
23
+ @c = C.new
24
+ @c.parse xml
25
+ end
26
+
27
+ after do
28
+ Object.send(:remove_const, :A)
29
+ Object.send(:remove_const, :B)
30
+ Object.send(:remove_const, :C)
31
+ end
32
+
33
+ it { expect(@a).to be_a(A) }
34
+ it { expect(@a).not_to be_a(B) }
35
+ it { expect(@a).to be_a(SAXMachine) }
36
+ it { expect(@a.title).to eq("Test") }
37
+ it { expect(@b).to be_a(A) }
38
+ it { expect(@b).to be_a(B) }
39
+ it { expect(@b).to be_a(SAXMachine) }
40
+ it { expect(@b.title).to eq("Test") }
41
+ it { expect(@b.b).to eq("Matched!") }
42
+ it { expect(@c).to be_a(A) }
43
+ it { expect(@c).to be_a(B) }
44
+ it { expect(@c).to be_a(C) }
45
+ it { expect(@c).to be_a(SAXMachine) }
46
+ it { expect(@c.title).to eq("Test") }
47
+ it { expect(@c.b).to eq("Matched!") }
48
+ it { expect(@c.c).to eq("And Again") }
49
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,11 +1,22 @@
1
- require 'date'
1
+ begin
2
+ require 'simplecov'
3
+ require 'coveralls'
2
4
 
3
- # gem install redgreen for colored test output
4
- begin require "redgreen" unless ENV['TM_CURRENT_LINE']
5
- rescue LoadError
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ SimpleCov::Formatter::HTMLFormatter,
7
+ Coveralls::SimpleCov::Formatter
8
+ ]
9
+
10
+ SimpleCov.start do
11
+ add_filter '/spec/'
12
+ end
13
+ rescue LoadError
6
14
  end
7
15
 
8
- path = File.expand_path(File.dirname(__FILE__) + "/../lib/")
9
- $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
16
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/sax-machine')
17
+ SAXMachine.handler = ENV['HANDLER'].to_sym if ENV['HANDLER']
10
18
 
11
- require "sax-machine"
19
+ RSpec.configure do |config|
20
+ config.run_all_when_everything_filtered = true
21
+ config.filter_run :focus
22
+ end
metadata CHANGED
@@ -1,97 +1,98 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: sax-machine
3
- version: !ruby/object:Gem::Version
4
- hash: 27
5
- prerelease:
6
- segments:
7
- - 0
8
- - 1
9
- - 0
10
- version: 0.1.0
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.2
11
5
  platform: ruby
12
- authors:
6
+ authors:
13
7
  - Paul Dix
14
8
  - Julien Kirch
9
+ - Ezekiel Templin
10
+ - Dmitry Krasnoukhov
15
11
  autorequire:
16
12
  bindir: bin
17
13
  cert_chain: []
18
-
19
- date: 2011-09-30 00:00:00 Z
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
22
- name: nokogiri
14
+ date: 2015-04-19 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '3.0'
23
+ type: :development
23
24
  prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ">"
28
- - !ruby/object:Gem::Version
29
- hash: 31
30
- segments:
31
- - 0
32
- - 0
33
- - 0
34
- version: 0.0.0
35
- type: :runtime
36
- version_requirements: *id001
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
37
30
  description:
38
31
  email: paul@pauldix.net
39
32
  executables: []
40
-
41
33
  extensions: []
42
-
43
34
  extra_rdoc_files: []
44
-
45
- files:
35
+ files:
36
+ - ".gitignore"
37
+ - ".rspec"
38
+ - ".travis.yml"
39
+ - Gemfile
40
+ - Guardfile
41
+ - HISTORY.md
42
+ - README.md
43
+ - Rakefile
46
44
  - lib/sax-machine.rb
47
- - lib/sax-machine/sax_ancestor_config.rb
48
- - lib/sax-machine/sax_attribute_config.rb
45
+ - lib/sax-machine/config/sax_ancestor.rb
46
+ - lib/sax-machine/config/sax_attribute.rb
47
+ - lib/sax-machine/config/sax_collection.rb
48
+ - lib/sax-machine/config/sax_element.rb
49
+ - lib/sax-machine/config/sax_element_value.rb
50
+ - lib/sax-machine/handlers/sax_abstract_handler.rb
51
+ - lib/sax-machine/handlers/sax_nokogiri_handler.rb
52
+ - lib/sax-machine/handlers/sax_oga_handler.rb
53
+ - lib/sax-machine/handlers/sax_ox_handler.rb
49
54
  - lib/sax-machine/sax_config.rb
50
55
  - lib/sax-machine/sax_configure.rb
51
56
  - lib/sax-machine/sax_document.rb
52
- - lib/sax-machine/sax_collection_config.rb
53
- - lib/sax-machine/sax_element_config.rb
54
- - lib/sax-machine/sax_element_value_config.rb
55
- - lib/sax-machine/sax_handler.rb
56
- - README.textile
57
- - Rakefile
58
- - Gemfile
59
- - spec/spec_helper.rb
60
- - spec/sax-machine/configure_sax_machine_spec.rb
61
- - spec/sax-machine/include_sax_machine_spec.rb
57
+ - lib/sax-machine/version.rb
58
+ - sax-machine.gemspec
59
+ - spec/fixtures/atom-content.html
60
+ - spec/fixtures/atom.xml
61
+ - spec/sax-machine/sax_activerecord_spec.rb
62
+ - spec/sax-machine/sax_configure_spec.rb
62
63
  - spec/sax-machine/sax_document_spec.rb
64
+ - spec/sax-machine/sax_include_spec.rb
65
+ - spec/spec_helper.rb
63
66
  homepage: http://github.com/pauldix/sax-machine
64
- licenses: []
65
-
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
66
70
  post_install_message:
67
71
  rdoc_options: []
68
-
69
- require_paths:
72
+ require_paths:
70
73
  - lib
71
- required_ruby_version: !ruby/object:Gem::Requirement
72
- none: false
73
- requirements:
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
74
76
  - - ">="
75
- - !ruby/object:Gem::Version
76
- hash: 3
77
- segments:
78
- - 0
79
- version: "0"
80
- required_rubygems_version: !ruby/object:Gem::Requirement
81
- none: false
82
- requirements:
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
83
81
  - - ">="
84
- - !ruby/object:Gem::Version
85
- hash: 3
86
- segments:
87
- - 0
88
- version: "0"
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
89
84
  requirements: []
90
-
91
85
  rubyforge_project:
92
- rubygems_version: 1.8.5
86
+ rubygems_version: 2.2.2
93
87
  signing_key:
94
- specification_version: 2
95
- summary: Declarative SAX Parsing with Nokogiri
96
- test_files: []
97
-
88
+ specification_version: 4
89
+ summary: Declarative SAX Parsing with Nokogiri, Ox or Oga
90
+ test_files:
91
+ - spec/fixtures/atom-content.html
92
+ - spec/fixtures/atom.xml
93
+ - spec/sax-machine/sax_activerecord_spec.rb
94
+ - spec/sax-machine/sax_configure_spec.rb
95
+ - spec/sax-machine/sax_document_spec.rb
96
+ - spec/sax-machine/sax_include_spec.rb
97
+ - spec/spec_helper.rb
98
+ has_rdoc:
data/README.textile DELETED
@@ -1,110 +0,0 @@
1
- h1. SAX Machine
2
-
3
- "http://github.com/pauldix/sax-machine/wikis":http://github.com/pauldix/sax-machine/wikis
4
-
5
- "http://github.com/pauldix/sax-machine/tree/master":http://github.com/pauldix/sax-machine/tree/master
6
-
7
- h2. Description
8
-
9
- A declarative SAX parsing library backed by Nokogiri
10
-
11
- h2. Usage
12
-
13
- <pre>
14
- require 'sax-machine'
15
-
16
- # Class for information associated with content parts in a feed.
17
- # Ex: <content type="text">sample</content>
18
- # instance.type will be "text", instance.text will be "sample"
19
- class AtomContent
20
- include SAXMachine
21
- attribute :type
22
- value :text
23
- end
24
-
25
- # Class for parsing an atom entry out of a feedburner atom feed
26
- class AtomEntry
27
- include SAXMachine
28
- element :title
29
- # the :as argument makes this available through atom_entry.author instead of .name
30
- element :name, :as => :author
31
- element "feedburner:origLink", :as => :url
32
- element :summary
33
- element :content, :class => AtomContent
34
- element :published
35
- ancestor :ancestor
36
- end
37
-
38
- # Class for parsing Atom feeds
39
- class Atom
40
- include SAXMachine
41
- element :title
42
- # the :with argument means that you only match a link tag that has an attribute of :type => "text/html"
43
- # the :value argument means that instead of setting the value to the text between the tag,
44
- # it sets it to the attribute value of :href
45
- element :link, :value => :href, :as => :url, :with => {:type => "text/html"}
46
- element :link, :value => :href, :as => :feed_url, :with => {:type => "application/atom+xml"}
47
- elements :entry, :as => :entries, :class => AtomEntry
48
- end
49
-
50
- # you can then parse like this
51
- feed = Atom.parse(xml_text)
52
- # then you're ready to rock
53
- feed.title # => whatever the title of the blog is
54
- feed.url # => the main url of the blog
55
- feed.feed_url # => goes to the feedburner feed
56
-
57
- feed.entries.first.title # => title of the first entry
58
- feed.entries.first.author # => the author of the first entry
59
- feed.entries.first.url # => the permalink on the blog for this entry
60
- feed.entries.first.ancestor # => the Atom ancestor
61
- # etc ...
62
-
63
- # you can also use the elements method without specifying a class like so
64
- class SomeServiceResponse
65
- include SAXMachine
66
- elements :message, :as => :messages
67
- end
68
-
69
- response = SomeServiceResponse.parse("<response><message>hi</message><message>world</message></response>")
70
- response.messages.first # => "hi"
71
- response.messages.last # => "world"
72
- </pre>
73
-
74
- # To limit conflicts in the class used for mappping, you can use the alternate SAXMachine.configure syntax
75
-
76
- class X < ActiveRecord::Base
77
-
78
- # this way no element, elements or ancestor method will be added to X
79
- SAXMachine.configure(X) do |c|
80
- c.element :title
81
- end
82
-
83
- end
84
-
85
- h2. LICENSE
86
-
87
- (The MIT License)
88
-
89
- Copyright (c) 2009 - 2011:
90
-
91
- "Paul Dix":http://pauldix.net
92
-
93
- Permission is hereby granted, free of charge, to any person obtaining
94
- a copy of this software and associated documentation files (the
95
- 'Software'), to deal in the Software without restriction, including
96
- without limitation the rights to use, copy, modify, merge, publish,
97
- distribute, sublicense, and/or sell copies of the Software, and to
98
- permit persons to whom the Software is furnished to do so, subject to
99
- the following conditions:
100
-
101
- The above copyright notice and this permission notice shall be
102
- included in all copies or substantial portions of the Software.
103
-
104
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
105
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
106
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
107
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
108
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
109
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
110
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,40 +0,0 @@
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,45 +0,0 @@
1
- module SAXMachine
2
- class SAXConfig
3
-
4
- class CollectionConfig
5
- attr_reader :name
6
-
7
- def initialize(name, options)
8
- @name = name.to_s
9
- @class = options[:class]
10
- @as = options[:as].to_s
11
-
12
- if options.has_key?(:with)
13
- # for faster comparisons later
14
- @with = options[:with].to_a.flatten.collect {|o| o.to_s}
15
- else
16
- @with = nil
17
- end
18
- end
19
-
20
- def accessor
21
- as
22
- end
23
-
24
- def attrs_match?(attrs)
25
- if @with
26
- @with == (@with & attrs)
27
- else
28
- true
29
- end
30
- end
31
-
32
- def data_class
33
- @class || @name
34
- end
35
-
36
- protected
37
-
38
- def as
39
- @as
40
- end
41
-
42
- end
43
-
44
- end
45
- end
@@ -1,107 +0,0 @@
1
- require "nokogiri"
2
-
3
- module SAXMachine
4
- class SAXHandler < Nokogiri::XML::SAX::Document
5
- attr_reader :stack
6
-
7
- def initialize(object, on_error = nil, on_warning = nil)
8
- @stack = [[object, nil, String.new]]
9
- @parsed_configs = {}
10
- @on_error = on_error
11
- @on_warning = on_warning
12
- end
13
-
14
- def characters(string)
15
- object, config, value = stack.last
16
- value << string
17
- end
18
-
19
- def cdata_block(string)
20
- characters(string)
21
- end
22
-
23
- def start_element(name, attrs = [])
24
- attrs.flatten!
25
- object, config, value = stack.last
26
- sax_config = object.class.respond_to?(:sax_config) ? object.class.sax_config : nil
27
-
28
- if sax_config
29
- if collection_config = sax_config.collection_config(name, attrs)
30
- stack.push [object = collection_config.data_class.new, collection_config, String.new]
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
36
- end
37
- sax_config.element_configs_for_attribute(name, attrs).each do |ec|
38
- unless parsed_config?(object, ec)
39
- object.send(ec.setter, ec.value_from_attrs(attrs))
40
- mark_as_parsed(object, ec)
41
- end
42
- end
43
- if !collection_config && element_config = sax_config.element_config_for_tag(name, attrs)
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
50
- end
51
- end
52
- end
53
-
54
- def end_element(name)
55
- (object, tag_config, _), (element, config, value) = stack[-2..-1]
56
- return unless stack.size > 1 && config && config.name.to_s == name.to_s
57
-
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
-
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
68
- object.send(config.accessor) << element
69
- else
70
- value = config.data_class ? element : value
71
- object.send(config.setter, value) unless value == ""
72
- mark_as_parsed(object, config)
73
- end
74
-
75
- # try to set the ancestor
76
- sax_config = element.class.respond_to?(:sax_config) ? element.class.sax_config : nil
77
- if sax_config
78
- sax_config.ancestors.each do |ancestor|
79
- element.send(ancestor.setter, object)
80
- end
81
- end
82
- end
83
- stack.pop
84
- end
85
-
86
- def mark_as_parsed(object, element_config)
87
- @parsed_configs[[object.object_id, element_config.object_id]] = true unless element_config.collection?
88
- end
89
-
90
- def parsed_config?(object, element_config)
91
- @parsed_configs[[object.object_id, element_config.object_id]]
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
-
106
- end
107
- end
@@ -1,53 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class A
4
-
5
- SAXMachine.configure(A) do |c|
6
- c.element :title
7
- end
8
-
9
- end
10
-
11
- class B < A
12
-
13
- SAXMachine.configure(B) do |c|
14
- c.element :b
15
- end
16
-
17
- end
18
-
19
- class C < B
20
-
21
- SAXMachine.configure(C) do |c|
22
- c.element :c
23
- end
24
-
25
- end
26
-
27
- describe "SAXMachine configure" do
28
- before do
29
- xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
30
- @a = A.new
31
- @a.parse xml
32
- @b = B.new
33
- @b.parse xml
34
- @c = C.new
35
- @c.parse xml
36
- end
37
- it { @a.should be_a(A) }
38
- it { @a.should_not be_a(B) }
39
- it { @a.should be_a(SAXMachine) }
40
- it { @a.title.should == "Test" }
41
- it { @b.should be_a(A) }
42
- it { @b.should be_a(B) }
43
- it { @b.should be_a(SAXMachine) }
44
- it { @b.title.should == "Test" }
45
- it { @b.b.should == "Matched!" }
46
- it { @c.should be_a(A) }
47
- it { @c.should be_a(B) }
48
- it { @c.should be_a(C) }
49
- it { @c.should be_a(SAXMachine) }
50
- it { @c.title.should == "Test" }
51
- it { @c.b.should == "Matched!" }
52
- it { @c.c.should == "And Again" }
53
- end
@@ -1,42 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class A
4
- include SAXMachine
5
- element :title
6
- end
7
-
8
- class B < A
9
- element :b
10
- end
11
-
12
- class C < B
13
- element :c
14
- end
15
-
16
- describe "SAXMachine inheritance" do
17
- before do
18
- xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
19
- @a = A.new
20
- @a.parse xml
21
- @b = B.new
22
- @b.parse xml
23
- @c = C.new
24
- @c.parse xml
25
- end
26
- it { @a.should be_a(A) }
27
- it { @a.should_not be_a(B) }
28
- it { @a.should be_a(SAXMachine) }
29
- it { @a.title.should == "Test" }
30
- it { @b.should be_a(A) }
31
- it { @b.should be_a(B) }
32
- it { @b.should be_a(SAXMachine) }
33
- it { @b.title.should == "Test" }
34
- it { @b.b.should == "Matched!" }
35
- it { @c.should be_a(A) }
36
- it { @c.should be_a(B) }
37
- it { @c.should be_a(C) }
38
- it { @c.should be_a(SAXMachine) }
39
- it { @c.title.should == "Test" }
40
- it { @c.b.should == "Matched!" }
41
- it { @c.c.should == "And Again" }
42
- end