sax-machine 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.travis.yml +14 -4
  4. data/Gemfile +5 -1
  5. data/Guardfile +2 -2
  6. data/HISTORY.md +23 -6
  7. data/README.md +111 -40
  8. data/Rakefile +4 -3
  9. data/lib/sax-machine.rb +11 -2
  10. data/lib/sax-machine/{sax_ancestor_config.rb → config/sax_ancestor.rb} +3 -7
  11. data/lib/sax-machine/{sax_attribute_config.rb → config/sax_attribute.rb} +4 -6
  12. data/lib/sax-machine/{sax_collection_config.rb → config/sax_collection.rb} +6 -10
  13. data/lib/sax-machine/{sax_element_config.rb → config/sax_element.rb} +16 -17
  14. data/lib/sax-machine/{sax_element_value_config.rb → config/sax_element_value.rb} +5 -7
  15. data/lib/sax-machine/{sax_handler.rb → handlers/sax_abstract_handler.rb} +28 -32
  16. data/lib/sax-machine/handlers/sax_nokogiri_handler.rb +16 -0
  17. data/lib/sax-machine/handlers/sax_ox_handler.rb +41 -0
  18. data/lib/sax-machine/sax_config.rb +9 -9
  19. data/lib/sax-machine/sax_configure.rb +1 -6
  20. data/lib/sax-machine/sax_document.rb +28 -17
  21. data/lib/sax-machine/version.rb +2 -2
  22. data/sax-machine.gemspec +8 -11
  23. data/spec/fixtures/atom-content.html +15 -0
  24. data/spec/{sax-machine → fixtures}/atom.xml +0 -0
  25. data/spec/sax-machine/sax_activerecord_spec.rb +23 -0
  26. data/spec/sax-machine/sax_configure_spec.rb +48 -0
  27. data/spec/sax-machine/sax_document_spec.rb +333 -280
  28. data/spec/sax-machine/sax_include_spec.rb +43 -0
  29. data/spec/spec_helper.rb +11 -2
  30. metadata +36 -41
  31. data/spec/benchmarks/amazon.xml +0 -40
  32. data/spec/benchmarks/benchmark.rb +0 -158
  33. data/spec/benchmarks/public_timeline.xml +0 -411
  34. data/spec/sax-machine/configure_sax_machine_spec.rb +0 -53
  35. data/spec/sax-machine/include_sax_machine_spec.rb +0 -42
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: eced69c84dfa4d14f4e55e8f8f57af2c90f69281
4
+ data.tar.gz: a00ec939b3a116885109a44283c68d0d301ebb63
5
+ SHA512:
6
+ metadata.gz: e728531fb1931246e61c4ecc5182f51f30ec2d7b4131976c282313f2db08c324a679c6f58f01fd02c2816fae380e4c711324764ca8cc192c04f4d8702218640f
7
+ data.tar.gz: 3014692c51809a0dd4cd0f0656fdc63d6d669ad9d3ba863fec64ac5aa0238a7b0dda83658b693ff4de800d8073ddf55d0bb6f32f7b3ac4370bbb24da9428606b
data/.gitignore CHANGED
@@ -6,3 +6,5 @@ Gemfile.lock
6
6
  .DS_STORE
7
7
  pkg/
8
8
  coverage/
9
+ .ruby-version
10
+ .ruby-gemset
@@ -1,12 +1,22 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.2
4
3
  - 1.9.3
5
- - 2.0.0
4
+ - 2.0
5
+ - 2.1
6
+ - jruby-1.7
7
+ - rbx-2
6
8
  - ruby-head
7
- - jruby-19mode
8
9
  - jruby-head
9
- - rbx-19mode
10
10
  matrix:
11
11
  allow_failures:
12
+ - rvm: rbx-2
12
13
  - rvm: ruby-head
14
+ - rvm: jruby-head
15
+ - env: HANDLER="ox"
16
+ rvm: jruby-1.7
17
+ - env: HANDLER="ox"
18
+ rvm: jruby-head
19
+ env:
20
+ matrix:
21
+ - HANDLER="nokogiri"
22
+ - HANDLER="ox"
data/Gemfile CHANGED
@@ -5,5 +5,9 @@ gemspec
5
5
  group :development, :test do
6
6
  gem 'rake'
7
7
  gem 'guard-rspec'
8
- gem 'simplecov', :require => false, :platforms => :mri_19
8
+ gem 'simplecov', require: false, platforms: [:mri]
9
+ gem 'coveralls', require: false, platforms: [:mri]
10
+
11
+ gem 'activerecord', '~> 4.1'
12
+ gem 'ox', '>= 2.1.2', platforms: [:mri, :rbx]
9
13
  end
data/Guardfile CHANGED
@@ -1,5 +1,5 @@
1
- guard 'rspec', :version => 2 do
1
+ guard "rspec", version: 2 do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
3
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
- watch('spec/spec_helper.rb') { "spec" }
4
+ watch("spec/spec_helper.rb") { "spec" }
5
5
  end
data/HISTORY.md CHANGED
@@ -1,13 +1,30 @@
1
+ # HEAD
2
+
3
+
4
+ # 0.3.0
5
+
6
+ * Option to use Ox as a SAX handler instead of Nokogiri [[#49](https://github.com/pauldix/sax-machine/pull/49)]
7
+ * Bump RSpec to 3.0, convert existing specs
8
+
9
+ # 0.2.1
10
+
11
+ * Turn on replace_entities on Nokogiri parser [[#40](https://github.com/pauldix/sax-machine/pull/40)]
12
+ * Provide mass assignment through initialize method [[#38](https://github.com/pauldix/sax-machine/pull/38)]
13
+ * Bump nokogiri (~> 1.6) and rspec, drop growl dependency
14
+ * Update 'with' option to allow pattern matching in addition to string matching
15
+
1
16
  # 0.2.0.rc1
2
- * Tried to reduce the number of instances of respond_to? in the code by
17
+
18
+ * Try to reduce the number of instances of respond_to? in the code by
3
19
  pulling common uses of it out to methods. [[#32](https://github.com/pauldix/sax-machine/pull/32)]
4
20
  * The parse stack is now composed of simple objects instead of it being
5
21
  an array of arrays. [[#32](https://github.com/pauldix/sax-machine/pull/32)]
6
22
  * Now using an identifier for an empty buffer instead of empty string. [[#32](https://github.com/pauldix/sax-machine/pull/32)]
7
- * Cleaned up several variables that were not being used. [[#32](https://github.com/pauldix/sax-machine/pull/32)]
8
- * Encapsulated stack so it's not being exposed as part of the API. [[#32](https://github.com/pauldix/sax-machine/pull/32)]
9
- * #cdata_block is now an alias instead of delegating to characters. [[#32](https://github.com/pauldix/sax-machine/pull/32)]
23
+ * Clean up several variables that were not being used. [[#32](https://github.com/pauldix/sax-machine/pull/32)]
24
+ * Encapsulate stack so it's not being exposed as part of the API. [[#32](https://github.com/pauldix/sax-machine/pull/32)]
25
+ * `cdata_block` is now an alias instead of delegating to characters. [[#32](https://github.com/pauldix/sax-machine/pull/32)]
10
26
 
11
27
  # 0.1.0
12
- * rename parent to ancestor
13
- * added SAXMachine.configure
28
+
29
+ * Rename parent to ancestor
30
+ * Add SAXMachine.configure
data/README.md CHANGED
@@ -1,91 +1,162 @@
1
- # SAX Machine [![Build Status](https://secure.travis-ci.org/pauldix/sax-machine.png?branch=master)](http://travis-ci.org/pauldix/sax-machine)
1
+ # SAX Machine
2
2
 
3
- [Wiki](https://github.com/pauldix/sax-machine/wiki)
3
+ ## Status
4
+
5
+ [![Gem Version](https://badge.fury.io/rb/sax-machine.svg)](http://badge.fury.io/rb/sax-machine)
6
+ [![Build Status](https://secure.travis-ci.org/pauldix/sax-machine.svg?branch=master)](http://travis-ci.org/pauldix/sax-machine?branch=master)
7
+ [![Coverage Status](https://img.shields.io/coveralls/pauldix/sax-machine.svg)](https://coveralls.io/r/pauldix/sax-machine?branch=master)
8
+ [![Code Climate](https://img.shields.io/codeclimate/github/pauldix/sax-machine.svg)](https://codeclimate.com/github/pauldix/sax-machine)
9
+ [![Dependencies](https://gemnasium.com/pauldix/sax-machine.svg)](https://gemnasium.com/pauldix/sax-machine)
4
10
 
5
11
  ## Description
6
12
 
7
- A declarative SAX parsing library backed by Nokogiri
13
+ A declarative SAX parsing library backed by Nokogiri or Ox.
14
+
15
+ ## Installation
16
+
17
+ Add this line to your application's Gemfile:
18
+
19
+ ```ruby
20
+ gem 'sax-machine'
21
+ ```
22
+
23
+ And then execute:
24
+
25
+ ```bash
26
+ $ bundle
27
+ ```
8
28
 
9
29
  ## Usage
30
+
31
+ To use **Nokogiri** as a SAX handler:
32
+
10
33
  ```ruby
11
34
  require 'sax-machine'
35
+ ```
36
+
37
+ To use **Ox** as a SAX handler:
38
+
39
+ Add this line to your application's Gemfile:
40
+
41
+ ```ruby
42
+ gem 'ox', '>= 2.1.2'
43
+ ```
44
+
45
+ Tell SAXMachine to use Ox:
12
46
 
13
- # Class for information associated with content parts in a feed.
14
- # Ex: <content type="text">sample</content>
15
- # instance.type will be "text", instance.text will be "sample"
47
+ ```ruby
48
+ require 'sax-machine'
49
+ SAXMachine.handler = :ox
50
+ ```
51
+
52
+ Please note that this operation is not thread-safe, so it's better to define
53
+ handler at initialization stage and do not change it during runtime.
54
+
55
+ ## Examples
56
+
57
+ Include `SAXMachine` in any class and define properties to parse:
58
+
59
+ ```ruby
16
60
  class AtomContent
17
61
  include SAXMachine
18
62
  attribute :type
19
63
  value :text
20
64
  end
21
65
 
22
- # Class for parsing an atom entry out of a feedburner atom feed
23
66
  class AtomEntry
24
67
  include SAXMachine
25
68
  element :title
26
- # the :as argument makes this available through atom_entry.author instead of .name
27
- element :name, :as => :author
28
- element "feedburner:origLink", :as => :url
69
+ # The :as argument makes this available through entry.author instead of .name
70
+ element :name, as: :author
71
+ element "feedburner:origLink", as: :url
29
72
  element :summary
30
- element :content, :class => AtomContent
73
+ element :content, class: AtomContent
31
74
  element :published
32
75
  ancestor :ancestor
33
76
  end
34
77
 
35
- # Class for parsing Atom feeds
36
78
  class Atom
37
79
  include SAXMachine
38
80
  element :title
39
- # the :with argument means that you only match a link tag that has an attribute of :type => "text/html"
40
- # the :value argument means that instead of setting the value to the text between the tag,
41
- # it sets it to the attribute value of :href
42
- element :link, :value => :href, :as => :url, :with => {:type => "text/html"}
43
- element :link, :value => :href, :as => :feed_url, :with => {:type => "application/atom+xml"}
44
- elements :entry, :as => :entries, :class => AtomEntry
81
+ # The :with argument means that you only match a link tag
82
+ # that has an attribute of type: "text/html"
83
+ element :link, value: :href, as: :url, with: {
84
+ type: "text/html"
85
+ }
86
+ # The :value argument means that instead of setting the value
87
+ # to the text between the tag, it sets it to the attribute value of :href
88
+ element :link, value: :href, as: :feed_url, with: {
89
+ type: "application/atom+xml"
90
+ }
91
+ elements :entry, as: :entries, class: AtomEntry
45
92
  end
93
+ ```
94
+
95
+ Then parse any XML with your class:
46
96
 
47
- # you can then parse like this
97
+ ```ruby
48
98
  feed = Atom.parse(xml_text)
49
- # then you're ready to rock
50
- feed.title # => whatever the title of the blog is
51
- feed.url # => the main url of the blog
52
- feed.feed_url # => goes to the feedburner feed
53
-
54
- feed.entries.first.title # => title of the first entry
55
- feed.entries.first.author # => the author of the first entry
56
- feed.entries.first.url # => the permalink on the blog for this entry
57
- feed.entries.first.ancestor # => the Atom ancestor
58
- # etc ...
59
-
60
- # you can also use the elements method without specifying a class like so
61
- class SomeServiceResponse
99
+
100
+ feed.title # Whatever the title of the blog is
101
+ feed.url # The main URL of the blog
102
+ feed.feed_url # The URL of the blog feed
103
+
104
+ feed.entries.first.title # Title of the first entry
105
+ feed.entries.first.author # The author of the first entry
106
+ feed.entries.first.url # Permalink on the blog for this entry
107
+ feed.entries.first.ancestor # The Atom ancestor
108
+ feed.entries.first.content # Instance of AtomContent
109
+ feed.entries.first.content.text # Entry content text
110
+ ```
111
+
112
+ You can also use the elements method without specifying a class:
113
+
114
+ ```ruby
115
+ class ServiceResponse
62
116
  include SAXMachine
63
- elements :message, :as => :messages
117
+ elements :message, as: :messages
64
118
  end
65
119
 
66
- response = SomeServiceResponse.parse("<response><message>hi</message><message>world</message></response>")
67
- response.messages.first # => "hi"
68
- response.messages.last # => "world"
120
+ response = ServiceResponse.parse("
121
+ <response>
122
+ <message>hi</message>
123
+ <message>world</message>
124
+ </response>
125
+ ")
126
+ response.messages.first # hi
127
+ response.messages.last # world
128
+ ```
69
129
 
70
- # To limit conflicts in the class used for mappping, you can use the alternate SAXMachine.configure syntax
130
+ To limit conflicts in the class used for mappping, you can use the alternate
131
+ `SAXMachine.configure` syntax:
71
132
 
133
+ ```ruby
72
134
  class X < ActiveRecord::Base
73
- # this way no element, elements or ancestor method will be added to X
135
+ # This way no element, elements or ancestor method will be added to X
74
136
  SAXMachine.configure(X) do |c|
75
137
  c.element :title
76
138
  end
77
139
  end
78
140
  ```
79
141
 
142
+ ## Contributing
143
+
144
+ 1. Fork it
145
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
146
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
147
+ 4. Push to the branch (`git push origin my-new-feature`)
148
+ 5. Create new Pull Request
149
+
80
150
  ## LICENSE
81
151
 
82
152
  The MIT License
83
153
 
84
- Copyright (c) 2009-2012:
154
+ Copyright (c) 2009-2014:
85
155
 
86
156
  * [Paul Dix](http://www.pauldix.net)
87
157
  * [Julien Kirch](http://www.archiloque.net)
88
158
  * [Ezekiel Templin](http://zeke.templ.in)
159
+ * [Dmitry Krasnoukhov](http://krasnoukhov.com)
89
160
 
90
161
  Permission is hereby granted, free of charge, to any person obtaining
91
162
  a copy of this software and associated documentation files (the
@@ -104,4 +175,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
104
175
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
105
176
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
106
177
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
107
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
178
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
2
+ require 'bundler/gem_tasks'
3
3
  require 'rspec/core/rake_task'
4
+
4
5
  RSpec::Core::RakeTask.new(:spec)
5
- task :test => :spec
6
- task :default => :test
6
+ task test: :spec
7
+ task default: :test
@@ -1,8 +1,17 @@
1
1
  require "sax-machine/version"
2
2
  require "sax-machine/sax_document"
3
3
  require "sax-machine/sax_configure"
4
- require "sax-machine/sax_handler"
5
4
  require "sax-machine/sax_config"
6
5
 
7
6
  module SAXMachine
8
- end
7
+ def self.handler
8
+ @@handler
9
+ end
10
+
11
+ def self.handler=(handler)
12
+ require "sax-machine/handlers/sax_#{handler}_handler"
13
+ @@handler = handler
14
+ end
15
+ end
16
+
17
+ SAXMachine.handler = :nokogiri
@@ -1,21 +1,17 @@
1
1
  module SAXMachine
2
2
  class SAXConfig
3
-
4
3
  class AncestorConfig
5
4
  attr_reader :name, :setter
6
5
 
7
6
  def initialize(name, options)
8
- @name = name.to_s
9
-
10
- @as = options[:as]
7
+ @name = name.to_s
8
+ @as = options[:as]
11
9
  @setter = "#{@as}="
12
10
  end
13
11
 
14
12
  def column
15
13
  @as || @name.to_sym
16
14
  end
17
-
18
15
  end
19
-
20
16
  end
21
- end
17
+ end
@@ -1,13 +1,12 @@
1
1
  module SAXMachine
2
2
  class SAXConfig
3
-
4
3
  class AttributeConfig
5
4
  attr_reader :name, :setter
6
5
 
7
6
  def initialize(name, options)
8
- @name = name.to_s
9
- @as = options[:as]
10
- @setter = "#{@as}="
7
+ @name = name.to_s
8
+ @as = options[:as]
9
+ @setter = "#{@as}="
11
10
  @required = options[:required]
12
11
  end
13
12
 
@@ -16,7 +15,7 @@ module SAXMachine
16
15
  end
17
16
 
18
17
  def required?
19
- @required
18
+ !!@required
20
19
  end
21
20
 
22
21
  def value_from_attrs(attrs)
@@ -35,6 +34,5 @@ module SAXMachine
35
34
  false
36
35
  end
37
36
  end
38
-
39
37
  end
40
38
  end
@@ -1,20 +1,19 @@
1
1
  module SAXMachine
2
2
  class SAXConfig
3
-
4
3
  class CollectionConfig
5
4
  attr_reader :name
6
-
5
+
7
6
  def initialize(name, options)
8
7
  @name = name.to_s
9
8
  @class = options[:class]
10
9
  @as = options[:as].to_s
11
10
  @with = options.fetch(:with, {})
12
11
  end
13
-
12
+
14
13
  def accessor
15
14
  as
16
15
  end
17
-
16
+
18
17
  def attrs_match?(attrs)
19
18
  @with.all? do |key, value|
20
19
  value === attrs[key.to_s]
@@ -23,15 +22,12 @@ module SAXMachine
23
22
 
24
23
  def data_class
25
24
  @class || @name
26
- end
27
-
28
- protected
29
-
25
+ end
26
+
27
+ protected
30
28
  def as
31
29
  @as
32
30
  end
33
-
34
31
  end
35
-
36
32
  end
37
33
  end
@@ -1,31 +1,31 @@
1
1
  module SAXMachine
2
2
  class SAXConfig
3
-
4
3
  class ElementConfig
5
4
  attr_reader :name, :setter, :data_class, :collection
6
-
5
+
7
6
  def initialize(name, options)
8
7
  @name = name.to_s
9
8
  @with = options.fetch(:with, {})
10
9
 
11
- if options.has_key?(:value)
12
- @value = options[:value].to_s
10
+ @value = if options.has_key?(:value)
11
+ options[:value].to_s
13
12
  else
14
- @value = nil
13
+ nil
15
14
  end
16
-
15
+
17
16
  @as = options[:as]
18
17
  @collection = options[:collection]
19
-
20
- if @collection
21
- @setter = "add_#{options[:as]}"
18
+
19
+ @setter = if @collection
20
+ "add_#{options[:as]}"
22
21
  else
23
- @setter = "#{@as}="
22
+ "#{@as}="
24
23
  end
24
+
25
25
  @data_class = options[:class]
26
26
  @required = options[:required]
27
27
  end
28
-
28
+
29
29
  def value_configured?
30
30
  !@value.nil?
31
31
  end
@@ -39,27 +39,26 @@ module SAXMachine
39
39
  end
40
40
 
41
41
  def required?
42
- @required
42
+ !!@required
43
43
  end
44
44
 
45
45
  def value_from_attrs(attrs)
46
46
  attrs.fetch(@value, nil)
47
47
  end
48
-
48
+
49
49
  def attrs_match?(attrs)
50
50
  @with.all? do |key, value|
51
51
  value === attrs[key.to_s]
52
52
  end
53
53
  end
54
-
54
+
55
55
  def has_value_and_attrs_match?(attrs)
56
56
  !@value.nil? && attrs_match?(attrs)
57
57
  end
58
-
58
+
59
59
  def collection?
60
- @collection
60
+ !!@collection
61
61
  end
62
62
  end
63
-
64
63
  end
65
64
  end