sax-machine 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eced69c84dfa4d14f4e55e8f8f57af2c90f69281
4
- data.tar.gz: a00ec939b3a116885109a44283c68d0d301ebb63
3
+ metadata.gz: d0fb49e4c86a5d258cd1266f3b39f0279ff6ecc4
4
+ data.tar.gz: 9221aa8a9a9a552f1ac9ce7e5b962db2e5987515
5
5
  SHA512:
6
- metadata.gz: e728531fb1931246e61c4ecc5182f51f30ec2d7b4131976c282313f2db08c324a679c6f58f01fd02c2816fae380e4c711324764ca8cc192c04f4d8702218640f
7
- data.tar.gz: 3014692c51809a0dd4cd0f0656fdc63d6d669ad9d3ba863fec64ac5aa0238a7b0dda83658b693ff4de800d8073ddf55d0bb6f32f7b3ac4370bbb24da9428606b
6
+ metadata.gz: 6da8e076f9d871aebfee80887b007712768c60643d5690b514cd886758583e132971417533afb560de2a4c8aee988131a46a62da28b32be9ed2837c7f4cf9e86
7
+ data.tar.gz: 8f28dd9652e24a9d853ded552df3ca25e80cba2eead23bb1ead8d331bc50768778938d7709ab3ebaa7cc11c3ebb411c74de119b8c64897f3d1ae7a41c3457911
data/Gemfile CHANGED
@@ -9,5 +9,6 @@ group :development, :test do
9
9
  gem 'coveralls', require: false, platforms: [:mri]
10
10
 
11
11
  gem 'activerecord', '~> 4.1'
12
+ gem 'nokogiri', '~> 1.6'
12
13
  gem 'ox', '>= 2.1.2', platforms: [:mri, :rbx]
13
14
  end
data/HISTORY.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # HEAD
2
2
 
3
+ # 1.0.0
4
+
5
+ * Make `nokogiri` dependency optional
6
+ * Add :default argument for elements [[#51](https://github.com/pauldix/sax-machine/pull/51)]
3
7
 
4
8
  # 0.3.0
5
9
 
data/README.md CHANGED
@@ -28,30 +28,26 @@ $ bundle
28
28
 
29
29
  ## Usage
30
30
 
31
- To use **Nokogiri** as a SAX handler:
31
+ SAX Machine can use either `nokogiri` or `ox` as XML SAX handler.
32
+
33
+ To use **Nokogiri** add this line to your Gemfile:
32
34
 
33
35
  ```ruby
34
- require 'sax-machine'
36
+ gem 'nokogiri', '~> 1.6'
35
37
  ```
36
38
 
37
- To use **Ox** as a SAX handler:
38
-
39
- Add this line to your application's Gemfile:
39
+ To use **Ox** add this line to your Gemfile:
40
40
 
41
41
  ```ruby
42
42
  gem 'ox', '>= 2.1.2'
43
43
  ```
44
44
 
45
- Tell SAXMachine to use Ox:
45
+ You can also specify which handler to use manually, like this:
46
46
 
47
47
  ```ruby
48
- require 'sax-machine'
49
- SAXMachine.handler = :ox
48
+ SAXMachine.handler = :nokogiri
50
49
  ```
51
50
 
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
51
  ## Examples
56
52
 
57
53
  Include `SAXMachine` in any class and define properties to parse:
@@ -69,7 +65,8 @@ class AtomEntry
69
65
  # The :as argument makes this available through entry.author instead of .name
70
66
  element :name, as: :author
71
67
  element "feedburner:origLink", as: :url
72
- element :summary
68
+ # The :default argument specifies default value for element when it's missing
69
+ element :summary, class: String, default: "No summary available"
73
70
  element :content, class: AtomContent
74
71
  element :published
75
72
  ancestor :ancestor
@@ -104,6 +101,7 @@ feed.feed_url # The URL of the blog feed
104
101
  feed.entries.first.title # Title of the first entry
105
102
  feed.entries.first.author # The author of the first entry
106
103
  feed.entries.first.url # Permalink on the blog for this entry
104
+ feed.entries.first.summary # Returns "No summary available" if summary is missing
107
105
  feed.entries.first.ancestor # The Atom ancestor
108
106
  feed.entries.first.content # Instance of AtomContent
109
107
  feed.entries.first.content.text # Entry content text
@@ -14,4 +14,8 @@ module SAXMachine
14
14
  end
15
15
  end
16
16
 
17
- SAXMachine.handler = :nokogiri
17
+ begin
18
+ SAXMachine.handler = :ox
19
+ rescue LoadError
20
+ SAXMachine.handler = :nokogiri
21
+ end
@@ -25,10 +25,7 @@ module SAXMachine
25
25
  def attrs_match?(attrs)
26
26
  attrs.key?(@name) || attrs.value?(@name)
27
27
  end
28
-
29
- def has_value_and_attrs_match?(attrs)
30
- attrs_match?(attrs)
31
- end
28
+ alias_method :has_value_and_attrs_match?, :attrs_match?
32
29
 
33
30
  def collection?
34
31
  false
@@ -1,7 +1,7 @@
1
1
  module SAXMachine
2
2
  class SAXConfig
3
3
  class ElementConfig
4
- attr_reader :name, :setter, :data_class, :collection
4
+ attr_reader :name, :as, :setter, :data_class, :collection, :default
5
5
 
6
6
  def initialize(name, options)
7
7
  @name = name.to_s
@@ -15,6 +15,7 @@ module SAXMachine
15
15
 
16
16
  @as = options[:as]
17
17
  @collection = options[:collection]
18
+ @default = options[:default]
18
19
 
19
20
  @setter = if @collection
20
21
  "add_#{options[:as]}"
@@ -104,19 +104,18 @@ module SAXMachine
104
104
  else
105
105
  value =
106
106
  case config.data_class.to_s
107
- when "String" then value.to_s
108
- when "Integer" then value.to_i
109
- when "Float" then value.to_f
107
+ when "String" then value != NO_BUFFER ? value.to_s : value
108
+ when "Integer" then value != NO_BUFFER ? value.to_i : value
109
+ when "Float" then value != NO_BUFFER ? value.to_f : value
110
110
  # Assumes that time elements will be string-based and are not
111
111
  # something else, e.g. seconds since epoch
112
- when "Time" then Time.parse(value.to_s)
112
+ when "Time" then value != NO_BUFFER ? Time.parse(value.to_s) : value
113
113
  when "" then value
114
114
  else
115
115
  element
116
116
  end
117
117
 
118
118
  object.send(config.setter, value) unless value == NO_BUFFER
119
-
120
119
  mark_as_parsed(object, config)
121
120
  end
122
121
 
@@ -18,7 +18,7 @@ module SAXMachine
18
18
  end
19
19
 
20
20
  def columns
21
- @top_level_elements.map { |name, ecs| ecs }.flatten
21
+ @top_level_elements.map { |_, ecs| ecs }.flatten
22
22
  end
23
23
 
24
24
  def initialize_copy(sax_config)
@@ -33,6 +33,15 @@ module SAXMachine
33
33
  attributes.each do |name, value|
34
34
  send("#{name}=", value)
35
35
  end
36
+
37
+ self.class.sax_config.top_level_elements.each do |_, configs|
38
+ configs.each do |config|
39
+ next unless config.default
40
+ next unless send(config.as).nil?
41
+
42
+ send(config.setter, config.default)
43
+ end
44
+ end
36
45
  end
37
46
  end
38
47
 
@@ -48,19 +57,19 @@ module SAXMachine
48
57
  def element(name, options = {})
49
58
  real_name = (options[:as] ||= name).to_s
50
59
  sax_config.add_top_level_element(name, options)
51
- create_attr real_name
60
+ create_attr(real_name)
52
61
  end
53
62
 
54
63
  def attribute(name, options = {})
55
64
  real_name = (options[:as] ||= name).to_s
56
65
  sax_config.add_top_level_attribute(self.class.to_s, options.merge(name: name))
57
- create_attr real_name
66
+ create_attr(real_name)
58
67
  end
59
68
 
60
69
  def value(name, options = {})
61
70
  real_name = (options[:as] ||= name).to_s
62
71
  sax_config.add_top_level_element_value(self.class.to_s, options.merge(name: name))
63
- create_attr real_name
72
+ create_attr(real_name)
64
73
  end
65
74
 
66
75
  def ancestor(name, options = {})
@@ -1,3 +1,3 @@
1
1
  module SAXMachine
2
- VERSION = "0.3.0"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -16,6 +16,5 @@ Gem::Specification.new do |s|
16
16
  s.require_paths = ["lib"]
17
17
  s.platform = Gem::Platform::RUBY
18
18
 
19
- s.add_dependency "nokogiri", "~> 1.6.0"
20
19
  s.add_development_dependency "rspec", "~> 3.0"
21
20
  end
@@ -1,23 +1,21 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
  require 'active_record'
3
3
 
4
- describe "ActiveRecord" do
5
- describe "integration" do
6
- before :each do
7
- class MySaxModel < ActiveRecord::Base
8
- SAXMachine.configure(MySaxModel) do |c|
9
- c.element :title
10
- end
4
+ describe "SAXMachine ActiveRecord integration" do
5
+ before do
6
+ class MySaxModel < ActiveRecord::Base
7
+ SAXMachine.configure(MySaxModel) do |c|
8
+ c.element :title
11
9
  end
12
10
  end
11
+ end
13
12
 
14
- after :each do
15
- Object.send(:remove_const, :MySaxModel)
16
- end
13
+ after do
14
+ Object.send(:remove_const, :MySaxModel)
15
+ end
17
16
 
18
- it "parses document" do
19
- document = MySaxModel.parse("<xml><title>My Title</title></xml>")
20
- expect(document.title).to eq("My Title")
21
- end
17
+ it "parses document" do
18
+ document = MySaxModel.parse("<xml><title>My Title</title></xml>")
19
+ expect(document.title).to eq("My Title")
22
20
  end
23
21
  end
@@ -1,32 +1,35 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
- class A
4
- SAXMachine.configure(A) do |c|
5
- c.element :title
6
- end
7
- end
3
+ describe "SAXMachine configure" do
4
+ before do
5
+ class A
6
+ SAXMachine.configure(A) do |c|
7
+ c.element :title
8
+ end
9
+ end
8
10
 
9
- class B < A
10
- SAXMachine.configure(B) do |c|
11
- c.element :b
12
- end
13
- end
11
+ class B < A
12
+ SAXMachine.configure(B) do |c|
13
+ c.element :b
14
+ end
15
+ end
14
16
 
15
- class C < B
16
- SAXMachine.configure(C) do |c|
17
- c.element :c
18
- end
19
- end
17
+ class C < B
18
+ SAXMachine.configure(C) do |c|
19
+ c.element :c
20
+ end
21
+ end
20
22
 
21
- describe "SAXMachine configure" do
22
- before do
23
23
  xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
24
- @a = A.new
25
- @a.parse xml
26
- @b = B.new
27
- @b.parse xml
28
- @c = C.new
29
- @c.parse xml
24
+ @a = A.parse xml
25
+ @b = B.parse xml
26
+ @c = C.parse xml
27
+ end
28
+
29
+ after do
30
+ Object.send(:remove_const, :A)
31
+ Object.send(:remove_const, :B)
32
+ Object.send(:remove_const, :C)
30
33
  end
31
34
 
32
35
  it { expect(@a).to be_a(A) }
@@ -3,10 +3,13 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
3
  describe "SAXMachine" do
4
4
  describe "element" do
5
5
  describe "when parsing a single element" do
6
- before :each do
6
+ before do
7
7
  @klass = Class.new do
8
8
  include SAXMachine
9
9
  element :title
10
+ ancestor :body
11
+ value :something, required: false
12
+ attribute :anything, required: true
10
13
  end
11
14
  end
12
15
 
@@ -21,10 +24,6 @@ describe "SAXMachine" do
21
24
  expect(document.title).to eq("Title")
22
25
  end
23
26
 
24
- it "allows introspection of the elements" do
25
- expect(@klass.column_names).to match_array([:title])
26
- end
27
-
28
27
  it "does not overwrites the getter is there is already one present" do
29
28
  @klass = Class.new do
30
29
  def title
@@ -97,6 +96,38 @@ describe "SAXMachine" do
97
96
  expect(document.title).to eq("My Title")
98
97
  end
99
98
 
99
+ describe "the introspection" do
100
+ it "allows to get column names" do
101
+ expect(@klass.column_names).to match_array([:title])
102
+ end
103
+
104
+ it "allows to get elements" do
105
+ expect(@klass.sax_config.top_level_elements.values.flatten.map(&:to_s)).to \
106
+ match_array(["name: title dataclass: setter: title= required: value: as:title collection: with: {}"])
107
+ end
108
+
109
+ it "allows to get ancestors" do
110
+ expect(@klass.sax_config.ancestors.map(&:column)).to \
111
+ match_array([:body])
112
+ end
113
+
114
+ it "allows to get values" do
115
+ expect(@klass.sax_config.top_level_element_value.map(&:column)).to \
116
+ match_array([:something])
117
+ expect(@klass.sax_config.top_level_element_value.map(&:required?)).to \
118
+ match_array([false])
119
+ end
120
+
121
+ it "allows to get attributes" do
122
+ expect(@klass.sax_config.top_level_attributes.map(&:column)).to \
123
+ match_array([:anything])
124
+ expect(@klass.sax_config.top_level_attributes.map(&:required?)).to \
125
+ match_array([true])
126
+ expect(@klass.sax_config.top_level_attributes.map(&:collection?)).to \
127
+ match_array([false])
128
+ end
129
+ end
130
+
100
131
  describe "the class attribute" do
101
132
  before(:each) do
102
133
  @klass = Class.new do
@@ -153,6 +184,21 @@ describe "SAXMachine" do
153
184
  end
154
185
  end
155
186
 
187
+ describe "the default attribute" do
188
+ it "is available" do
189
+ @klass = Class.new do
190
+ include SAXMachine
191
+ element :number, class: Integer, default: 0
192
+ end
193
+
194
+ document = @klass.parse("<no>number</no>")
195
+ expect(document.number).to eq(0)
196
+
197
+ document = @klass.parse("<number></number>")
198
+ expect(document.number).to eq(0)
199
+ end
200
+ end
201
+
156
202
  describe "the required attribute" do
157
203
  it "is available" do
158
204
  @klass = Class.new do
@@ -165,7 +211,7 @@ describe "SAXMachine" do
165
211
  end
166
212
 
167
213
  describe "when parsing multiple elements" do
168
- before :each do
214
+ before do
169
215
  @klass = Class.new do
170
216
  include SAXMachine
171
217
  element :title
@@ -212,7 +258,7 @@ describe "SAXMachine" do
212
258
 
213
259
  describe "when using options for parsing elements" do
214
260
  describe "using the 'as' option" do
215
- before :each do
261
+ before do
216
262
  @klass = Class.new do
217
263
  include SAXMachine
218
264
  element :description, as: :summary
@@ -233,7 +279,7 @@ describe "SAXMachine" do
233
279
 
234
280
  describe "using the :with option" do
235
281
  describe "and the :value option" do
236
- before :each do
282
+ before do
237
283
  @klass = Class.new do
238
284
  include SAXMachine
239
285
  element :link, value: :href, with: { foo: "bar" }
@@ -251,7 +297,7 @@ describe "SAXMachine" do
251
297
  end
252
298
 
253
299
  describe "and the :as option" do
254
- before :each do
300
+ before do
255
301
  @klass = Class.new do
256
302
  include SAXMachine
257
303
  element :link, value: :href, as: :url, with: { foo: "bar" }
@@ -268,7 +314,7 @@ describe "SAXMachine" do
268
314
  end
269
315
 
270
316
  describe "with only one element" do
271
- before :each do
317
+ before do
272
318
  @klass = Class.new do
273
319
  include SAXMachine
274
320
  element :link, with: { foo: "bar" }
@@ -297,7 +343,7 @@ describe "SAXMachine" do
297
343
  end
298
344
 
299
345
  describe "with multiple elements of same tag" do
300
- before :each do
346
+ before do
301
347
  @klass = Class.new do
302
348
  include SAXMachine
303
349
  element :link, as: :first, with: { foo: "bar" }
@@ -317,7 +363,7 @@ describe "SAXMachine" do
317
363
  end
318
364
 
319
365
  describe "with only one element as a regular expression" do
320
- before :each do
366
+ before do
321
367
  @klass = Class.new do
322
368
  include SAXMachine
323
369
  element :link, with: { foo: /ar$/ }
@@ -347,7 +393,7 @@ describe "SAXMachine" do
347
393
  end
348
394
 
349
395
  describe "using the 'value' option" do
350
- before :each do
396
+ before do
351
397
  @klass = Class.new do
352
398
  include SAXMachine
353
399
  element :link, value: :foo
@@ -395,7 +441,7 @@ describe "SAXMachine" do
395
441
  end
396
442
 
397
443
  describe "when desiring both the content and attributes of an element" do
398
- before :each do
444
+ before do
399
445
  @klass = Class.new do
400
446
  include SAXMachine
401
447
  element :link
@@ -416,7 +462,7 @@ describe "SAXMachine" do
416
462
 
417
463
  describe "elements" do
418
464
  describe "when parsing multiple elements" do
419
- before :each do
465
+ before do
420
466
  @klass = Class.new do
421
467
  include SAXMachine
422
468
  elements :entry, as: :entries
@@ -451,7 +497,7 @@ describe "SAXMachine" do
451
497
  end
452
498
 
453
499
  describe "when using the with and class options" do
454
- before :each do
500
+ before do
455
501
  class Bar
456
502
  include SAXMachine
457
503
  element :title
@@ -484,7 +530,7 @@ describe "SAXMachine" do
484
530
  end
485
531
 
486
532
  describe "when using the class option" do
487
- before :each do
533
+ before do
488
534
  class Foo
489
535
  include SAXMachine
490
536
  element :title
@@ -559,7 +605,7 @@ describe "SAXMachine" do
559
605
  end
560
606
 
561
607
  describe "full example" do
562
- before :each do
608
+ before do
563
609
  @xml = File.read("spec/fixtures/atom.xml")
564
610
 
565
611
  class AtomEntry
@@ -881,11 +927,20 @@ describe "SAXMachine" do
881
927
  end
882
928
 
883
929
  @errors = []
884
- @item = ItemElement5.parse(@xml, ->(x) { @errors << x })
930
+ @warnings = []
931
+ @item = ItemElement5.parse(
932
+ @xml,
933
+ ->(x) { @errors << x },
934
+ ->(x) { @warnings << x },
935
+ )
885
936
  end
886
937
 
887
938
  it "has error" do
888
939
  expect(@errors.uniq.size).to eq(1)
889
940
  end
941
+
942
+ it "has no warning" do
943
+ expect(@warnings.uniq.size).to eq(0)
944
+ end
890
945
  end
891
946
  end
@@ -1,20 +1,20 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
- class A
4
- include SAXMachine
5
- element :title
6
- end
3
+ describe "SAXMachine inheritance" do
4
+ before do
5
+ class A
6
+ include SAXMachine
7
+ element :title
8
+ end
7
9
 
8
- class B < A
9
- element :b
10
- end
10
+ class B < A
11
+ element :b
12
+ end
11
13
 
12
- class C < B
13
- element :c
14
- end
14
+ class C < B
15
+ element :c
16
+ end
15
17
 
16
- describe "SAXMachine inheritance" do
17
- before do
18
18
  xml = "<top><title>Test</title><b>Matched!</b><c>And Again</c></top>"
19
19
  @a = A.new
20
20
  @a.parse xml
@@ -24,6 +24,12 @@ describe "SAXMachine inheritance" do
24
24
  @c.parse xml
25
25
  end
26
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
+
27
33
  it { expect(@a).to be_a(A) }
28
34
  it { expect(@a).not_to be_a(B) }
29
35
  it { expect(@a).to be_a(SAXMachine) }
@@ -14,9 +14,7 @@ rescue LoadError
14
14
  end
15
15
 
16
16
  require File.expand_path(File.dirname(__FILE__) + '/../lib/sax-machine')
17
- if ENV['HANDLER'] == 'ox'
18
- SAXMachine.handler = :ox
19
- end
17
+ SAXMachine.handler = ENV['HANDLER'].to_sym
20
18
 
21
19
  RSpec.configure do |config|
22
20
  config.run_all_when_everything_filtered = true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sax-machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Dix
@@ -11,22 +11,8 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2014-07-22 00:00:00.000000000 Z
14
+ date: 2014-08-05 00:00:00.000000000 Z
15
15
  dependencies:
16
- - !ruby/object:Gem::Dependency
17
- name: nokogiri
18
- requirement: !ruby/object:Gem::Requirement
19
- requirements:
20
- - - "~>"
21
- - !ruby/object:Gem::Version
22
- version: 1.6.0
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - "~>"
28
- - !ruby/object:Gem::Version
29
- version: 1.6.0
30
16
  - !ruby/object:Gem::Dependency
31
17
  name: rspec
32
18
  requirement: !ruby/object:Gem::Requirement