saxxy 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.travis.yml +5 -0
- data/Gemfile +13 -0
- data/LICENSE +22 -0
- data/README.md +117 -0
- data/Rakefile +12 -0
- data/lib/saxxy.rb +2 -0
- data/lib/saxxy/activatable.rb +160 -0
- data/lib/saxxy/callbacks/libxml.rb +26 -0
- data/lib/saxxy/callbacks/nokogiri.rb +30 -0
- data/lib/saxxy/callbacks/ox.rb +66 -0
- data/lib/saxxy/callbacks/sax.rb +86 -0
- data/lib/saxxy/context.rb +88 -0
- data/lib/saxxy/context_tree.rb +85 -0
- data/lib/saxxy/event.rb +83 -0
- data/lib/saxxy/event_registry.rb +122 -0
- data/lib/saxxy/node_action.rb +59 -0
- data/lib/saxxy/node_rule.rb +90 -0
- data/lib/saxxy/parsers/base.rb +28 -0
- data/lib/saxxy/parsers/libxml.rb +52 -0
- data/lib/saxxy/parsers/nokogiri.rb +28 -0
- data/lib/saxxy/parsers/ox.rb +30 -0
- data/lib/saxxy/service.rb +47 -0
- data/lib/saxxy/utils/agent.rb +66 -0
- data/lib/saxxy/utils/callback_array.rb +27 -0
- data/lib/saxxy/utils/helpers.rb +13 -0
- data/lib/saxxy/version.rb +3 -0
- data/saxxy.gemspec +21 -0
- data/spec/saxxy/activatable_spec.rb +344 -0
- data/spec/saxxy/callbacks/sax_spec.rb +456 -0
- data/spec/saxxy/context_spec.rb +51 -0
- data/spec/saxxy/context_tree_spec.rb +68 -0
- data/spec/saxxy/event_registry_spec.rb +137 -0
- data/spec/saxxy/event_spec.rb +49 -0
- data/spec/saxxy/node_action_spec.rb +46 -0
- data/spec/saxxy/node_rule_spec.rb +99 -0
- data/spec/saxxy/parsers/libxml_spec.rb +104 -0
- data/spec/saxxy/parsers/nokogiri_spec.rb +200 -0
- data/spec/saxxy/parsers/ox_spec.rb +175 -0
- data/spec/saxxy/utils/agent_spec.rb +63 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/agent_macros.rb +24 -0
- metadata +155 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "saxxy/node_rule"
|
3
|
+
require "saxxy/node_action"
|
4
|
+
require "saxxy/context"
|
5
|
+
|
6
|
+
|
7
|
+
describe Saxxy::Context do
|
8
|
+
let(:rule) { Saxxy::NodeRule.new("div") }
|
9
|
+
|
10
|
+
it "should include activatable" do
|
11
|
+
Saxxy::Context.ancestors.should include(Saxxy::Activatable)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#initialize" do
|
15
|
+
it "should start with empty child_contexts and actions" do
|
16
|
+
subject.actions.should be_empty
|
17
|
+
subject.child_contexts.should be_empty
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should start with an activation rule if one is given" do
|
21
|
+
subject.activation_rule.should be_nil
|
22
|
+
Saxxy::Context.new(rule).activation_rule.should == rule
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# #register action is used to register either an action or a child context
|
27
|
+
describe "#register" do
|
28
|
+
it "should add an action in the actions array if argument is a NodeAction" do
|
29
|
+
action = Saxxy::NodeAction.new(rule)
|
30
|
+
expect { subject.register("foo") }.to_not change { subject.actions }
|
31
|
+
expect { subject.register(action) }.to change { subject.actions }.by([action])
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should add a child context and change its parent to self if argument is a Context" do
|
35
|
+
ctx = Saxxy::Context.new(rule)
|
36
|
+
ctx.parent_context.should be_nil
|
37
|
+
subject.register(ctx).child_contexts.should == [ctx]
|
38
|
+
ctx.parent_context.should == subject
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "#has_parent?" do
|
43
|
+
it "returns false if the context has no parent" do
|
44
|
+
ctx = Saxxy::Context.new(rule)
|
45
|
+
ctx.has_parent?.should be_false
|
46
|
+
subject.register(ctx)
|
47
|
+
ctx.has_parent?.should be_true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "saxxy/node_rule"
|
3
|
+
require "saxxy/node_action"
|
4
|
+
require "saxxy/context_tree"
|
5
|
+
|
6
|
+
|
7
|
+
describe Saxxy::ContextTree do
|
8
|
+
let(:subject) { Saxxy::ContextTree.new {} }
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
it "sets root to a new context without a rule" do
|
12
|
+
subject.root.should be_a(Saxxy::Context)
|
13
|
+
subject.root.activation_rule.should be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should call the eval_subtree! with the provided block" do
|
17
|
+
block = ->(){}
|
18
|
+
Saxxy::ContextTree.any_instance.should_receive(:eval_subtree!).with(&block)
|
19
|
+
Saxxy::ContextTree.new(&block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Maybe we should make the #on action idempotent on the sense that it will merge
|
24
|
+
# the actions (the blocks) if it is called with the same arguments more than once.
|
25
|
+
describe "#on" do
|
26
|
+
it "should not change the root context" do
|
27
|
+
expect { subject.on("div", { class: /foo/ }) }.to_not change { subject.root }
|
28
|
+
end
|
29
|
+
|
30
|
+
it "creates an action and registers it on the root context" do
|
31
|
+
expect { subject.on("div", { class: /foo/ }) }.to change { subject.root.actions.size }.by(1)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "creates a rule for the action with the specified arguments" do
|
35
|
+
subject.on("div", { class: /foo/ })
|
36
|
+
subject.root.actions[0].activation_rule.element.should == "div"
|
37
|
+
subject.root.actions[0].activation_rule.attributes.should == { "class" => /foo/ }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#under" do
|
42
|
+
it "should add a child context to the root" do
|
43
|
+
expect { subject.under("div", { class: /foo/ }) }.to change { subject.root.child_contexts.length }.by(1)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should create a tree of contexts if it has nested #under calls" do
|
47
|
+
subject.under("div") do
|
48
|
+
under("span") { under("ul") }
|
49
|
+
under("div", class: "bar") { under("ul") { under("li", class: /foo/); under("span") } }
|
50
|
+
end
|
51
|
+
subject.root.should have(1).child_contexts
|
52
|
+
subject.root.child_contexts[0].should have(2).child_contexts
|
53
|
+
subject.root.child_contexts[0].child_contexts[0].should have(1).child_contexts
|
54
|
+
subject.root.child_contexts[0].child_contexts[0].child_contexts[0].should have(0).child_contexts
|
55
|
+
subject.root.child_contexts[0].child_contexts[1].should have(1).child_contexts
|
56
|
+
subject.root.child_contexts[0].child_contexts[1].child_contexts[0].should have(2).child_contexts
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should build an activation rule for the child context from arguments" do
|
60
|
+
args = ["div", { class: /foo/ }]
|
61
|
+
subject.under(*args)
|
62
|
+
ctx = subject.root.child_contexts[0]
|
63
|
+
ctx.activation_rule.element.should == "div"
|
64
|
+
ctx.activation_rule.attributes.should == { "class" => /foo/ }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "saxxy/node_rule"
|
3
|
+
require "saxxy/node_action"
|
4
|
+
require "saxxy/event_registry"
|
5
|
+
|
6
|
+
|
7
|
+
describe Saxxy::EventRegistry do
|
8
|
+
|
9
|
+
def actions(reg = subject)
|
10
|
+
reg.instance_variable_get("@actions")
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
describe "#initialize" do
|
15
|
+
it "sets the actions to an empty hash" do
|
16
|
+
actions(Saxxy::EventRegistry.new).should == {}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
describe "#register_event_from_action" do
|
22
|
+
let(:rule) { Saxxy::NodeRule.new("div", { title: "foo" }) }
|
23
|
+
let(:action) { Saxxy::NodeAction.new(rule) }
|
24
|
+
|
25
|
+
it "should create the action entry with events as the value if it does not exist yet" do
|
26
|
+
actions().should == {}
|
27
|
+
event = subject.register_event_from_action(action)
|
28
|
+
actions().should == { action => [event] }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should append the event to the action entry" do
|
32
|
+
ev1 = subject.register_event_from_action(action)
|
33
|
+
ev2 = subject.register_event_from_action(action)
|
34
|
+
actions()[action].should == [ev1, ev2]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
describe "#events" do
|
40
|
+
let(:rule1) { Saxxy::NodeRule.new("div", { class: /foo/ }) }
|
41
|
+
let(:rule2) { Saxxy::NodeRule.new("div", { title: "foo" }) }
|
42
|
+
let(:action1) { Saxxy::NodeAction.new(rule1) }
|
43
|
+
let(:action2) { Saxxy::NodeAction.new(rule2) }
|
44
|
+
|
45
|
+
it "should return an array consisting of the last event of each action" do
|
46
|
+
5.times { subject.register_event_from_action(action1) }
|
47
|
+
last_ev1 = subject.register_event_from_action(action1)
|
48
|
+
5.times { subject.register_event_from_action(action2) }
|
49
|
+
last_ev2 = subject.register_event_from_action(action2)
|
50
|
+
subject.events.should == [last_ev1, last_ev2]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
describe "#push_text" do
|
56
|
+
let(:rule1) { Saxxy::NodeRule.new("div", { class: /foo/ }) }
|
57
|
+
let(:rule2) { Saxxy::NodeRule.new("div", { title: "foo" }) }
|
58
|
+
let(:action1) { Saxxy::NodeAction.new(rule1) }
|
59
|
+
let(:action2) { Saxxy::NodeAction.new(rule2) }
|
60
|
+
|
61
|
+
it "should add the text to the events (last events)" do
|
62
|
+
5.times { subject.register_event_from_action(action1) }
|
63
|
+
last_ev1 = subject.register_event_from_action(action1)
|
64
|
+
5.times { subject.register_event_from_action(action2) }
|
65
|
+
last_ev2 = subject.register_event_from_action(action2)
|
66
|
+
expect { subject.push_text("foo") }.to change {
|
67
|
+
[last_ev1, last_ev2].map(&:text)
|
68
|
+
}.from(["", ""]).to(["foo", "foo"])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
describe "#deactivate_events_on" do
|
74
|
+
let(:rule1) { Saxxy::NodeRule.new("div", { class: /foo/ }) }
|
75
|
+
let(:rule2) { Saxxy::NodeRule.new("span", { title: "foo" }) }
|
76
|
+
|
77
|
+
it "should call deactivate_events_on on every event with the element name as argument" do
|
78
|
+
last_ev1 = subject.register_event_from_action(a1 = Saxxy::NodeAction.new(rule1))
|
79
|
+
last_ev2 = subject.register_event_from_action(a2 = Saxxy::NodeAction.new(rule2))
|
80
|
+
last_ev1.should_receive(:deactivate_on).with("div")
|
81
|
+
last_ev2.should_receive(:deactivate_on).with("div")
|
82
|
+
subject.deactivate_events_on("div")
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should not remove inactive events" do
|
86
|
+
last_ev1 = subject.register_event_from_action(a1 = Saxxy::NodeAction.new(rule1))
|
87
|
+
last_ev2 = subject.register_event_from_action(a2 = Saxxy::NodeAction.new(rule2))
|
88
|
+
expect { subject.deactivate_events_on("div") }.to_not change { actions()[a1] }
|
89
|
+
expect { subject.deactivate_events_on("div") }.to_not change { actions()[a2] }
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should remove active events that match the element name" do
|
93
|
+
last_ev11 = subject.register_event_from_action(a1 = Saxxy::NodeAction.new(rule1)).tap do |e|
|
94
|
+
e.activate_on("div", "class" => "foo")
|
95
|
+
end
|
96
|
+
last_ev12 = subject.register_event_from_action(a1).tap { |e| e.activate_on("div", "class" => "foo") }
|
97
|
+
last_ev21 = subject.register_event_from_action(a2 = Saxxy::NodeAction.new(rule2))
|
98
|
+
expect {
|
99
|
+
subject.deactivate_events_on("div")
|
100
|
+
}.to change { actions()[a1] }.from([last_ev11, last_ev12]).to([last_ev11])
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should delete the action if the last event gets removed" do
|
104
|
+
last_ev1 = subject.register_event_from_action(a1 = Saxxy::NodeAction.new(rule1)).tap do |e|
|
105
|
+
e.activate_on("div", "class" => "foo")
|
106
|
+
end
|
107
|
+
last_ev2 = subject.register_event_from_action(a2 = Saxxy::NodeAction.new(rule2))
|
108
|
+
expect {
|
109
|
+
subject.deactivate_events_on("div")
|
110
|
+
}.to change { actions()[a1] }.from([last_ev1]).to(nil)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should not remove already activated events that don't match the element name" do
|
114
|
+
last_ev1 = subject.register_event_from_action(a1 = Saxxy::NodeAction.new(rule1)).tap do |e|
|
115
|
+
e.activate_on("div", "class" => "foo")
|
116
|
+
end
|
117
|
+
last_ev2 = subject.register_event_from_action(a2 = Saxxy::NodeAction.new(rule2))
|
118
|
+
expect { subject.deactivate_events_on("span") }.to_not change { actions()[a1] }
|
119
|
+
expect { subject.deactivate_events_on("span") }.to_not change { actions()[a2] }
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should append the text of the removed event to the next one in the queue" do
|
123
|
+
last_ev11 = subject.register_event_from_action(a1 = Saxxy::NodeAction.new(rule1)).tap do |e|
|
124
|
+
e.append_text("foo")
|
125
|
+
e.activate_on("div", "class" => "foo")
|
126
|
+
end
|
127
|
+
last_ev12 = subject.register_event_from_action(a1).tap do |e|
|
128
|
+
e.append_text(" bar")
|
129
|
+
e.activate_on("div", "class" => "foo")
|
130
|
+
end
|
131
|
+
last_ev21 = subject.register_event_from_action(a2 = Saxxy::NodeAction.new(rule2))
|
132
|
+
expect {
|
133
|
+
subject.deactivate_events_on("div")
|
134
|
+
}.to change { last_ev11.text }.from("foo").to("foo bar")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "saxxy/node_action"
|
3
|
+
require "saxxy/node_rule"
|
4
|
+
require "saxxy/event"
|
5
|
+
|
6
|
+
|
7
|
+
describe Saxxy::Event do
|
8
|
+
|
9
|
+
def event(action = Saxxy::NodeAction.new(Saxxy::NodeRule.new("div")))
|
10
|
+
Saxxy::Event.new(action)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should include activatable" do
|
14
|
+
Saxxy::Event.ancestors.should include(Saxxy::Activatable)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#initialize" do
|
18
|
+
it "should set the action to the argument" do
|
19
|
+
action = Saxxy::NodeAction.new(Saxxy::NodeRule.new("div"))
|
20
|
+
event(action).action.should == action
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should call initialize_activatable with the activation rule that action has" do
|
24
|
+
rule = Saxxy::NodeRule.new("div")
|
25
|
+
Saxxy::Event.any_instance.should_receive(:initialize_activatable).with(rule)
|
26
|
+
event(Saxxy::NodeAction.new(rule))
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set the text instance variable to an empty string" do
|
30
|
+
event().text.should == ""
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#append_text" do
|
35
|
+
it "appends the text provided as an argument to the @text instance variable" do
|
36
|
+
e = event()
|
37
|
+
expect { e.append_text("foo") }.to change { e.text }.from("").to("foo")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#fire" do
|
42
|
+
it "should delegate the call to the action with the text as the argument" do
|
43
|
+
e = event()
|
44
|
+
e.action.should_receive(:call).with(e.text, nil, {})
|
45
|
+
e.fire
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "saxxy/node_rule"
|
3
|
+
require "saxxy/node_action"
|
4
|
+
|
5
|
+
|
6
|
+
describe Saxxy::NodeAction do
|
7
|
+
let(:rule) { Saxxy::NodeRule.new("div") }
|
8
|
+
|
9
|
+
describe "#initialize" do
|
10
|
+
it "initializes with an activation rule and with a block" do
|
11
|
+
block = ->() { "this is a test block" }
|
12
|
+
action = Saxxy::NodeAction.new(rule, &block)
|
13
|
+
action.action.should == block
|
14
|
+
action.activation_rule.should == rule
|
15
|
+
end
|
16
|
+
|
17
|
+
it "initializes with the id block if none is given" do
|
18
|
+
Saxxy::NodeAction.new(rule).action.call("foo").should == "foo"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#matches" do
|
23
|
+
it "should delegate the call to activation_rule" do
|
24
|
+
action = Saxxy::NodeAction.new(rule)
|
25
|
+
args = ["div", { class: /foo/ }]
|
26
|
+
action.activation_rule.should_receive(:matches).with(*args)
|
27
|
+
action.matches(*args)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#call" do
|
32
|
+
it "should delegate the call to an instance exec on the binding i.e. context if a context is given" do
|
33
|
+
a_context = Object.new
|
34
|
+
action = Saxxy::NodeAction.new(rule, a_context)
|
35
|
+
a_context.should_receive(:instance_exec).with(["foo"], &action.action)
|
36
|
+
action.call("foo")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should delegate the call to an instance exec on itself if no context is given" do
|
40
|
+
action = Saxxy::NodeAction.new(rule)
|
41
|
+
action.should_receive(:instance_exec).with(["foo"], &action.action)
|
42
|
+
action.call("foo")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "saxxy/node_rule"
|
3
|
+
|
4
|
+
|
5
|
+
describe Saxxy::NodeRule do
|
6
|
+
|
7
|
+
describe "#matches" do
|
8
|
+
it "should return false if @element does not match first argument as string" do
|
9
|
+
nr = Saxxy::NodeRule.new("div")
|
10
|
+
nr.element.should eql("div")
|
11
|
+
nr.matches("span").should be_false
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return false if @element does not match first argument as regexp" do
|
15
|
+
nr = Saxxy::NodeRule.new(/div/)
|
16
|
+
nr.element.should be_a(Regexp)
|
17
|
+
nr.matches("span").should be_false
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return true if @element matches first argument as string and empty @attributes" do
|
21
|
+
nr = Saxxy::NodeRule.new("div")
|
22
|
+
nr.attributes.should be_empty
|
23
|
+
nr.matches("div").should be_true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return true if @element matches first argument as regexp and empty @attributes" do
|
27
|
+
nr = Saxxy::NodeRule.new(/^d[iv]+?/)
|
28
|
+
nr.attributes.should be_empty
|
29
|
+
nr.matches("div").should be_true
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return false if @element matches first argument as string
|
33
|
+
and non-empty @attributes with keys not in second argument's keys" do
|
34
|
+
nr = Saxxy::NodeRule.new("div", { class: /fooo?/ })
|
35
|
+
nr.attributes.should_not be_empty
|
36
|
+
nr.matches("div", { foo: "bar" }).should be_false
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return false if @element matches first argument as regexp
|
40
|
+
and non-empty @attributes with keys not in second argument's keys" do
|
41
|
+
nr = Saxxy::NodeRule.new(/div/, { class: /fooo?/ })
|
42
|
+
nr.attributes.should_not be_empty
|
43
|
+
nr.matches("div", { foo: "bar" }).should be_false
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
it "should return true if @element matches first argument as string
|
48
|
+
and non-empty @attributes with keys in second argument's keys and
|
49
|
+
at the same time same values should match" do
|
50
|
+
nr = Saxxy::NodeRule.new("div", { class: /fooo?/ })
|
51
|
+
nr.attributes.should_not be_empty
|
52
|
+
nr.matches("div", { foo: "bar", class: "foo" }).should be_true
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return true if @element matches first argument as regexp
|
56
|
+
and non-empty @attributes with keys in second argument's keys and
|
57
|
+
at the same time same values should match" do
|
58
|
+
nr = Saxxy::NodeRule.new(/div/, { class: "foo" })
|
59
|
+
nr.attributes.should_not be_empty
|
60
|
+
nr.matches("div", { foo: "bar", class: "foo" }).should be_true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
describe "#match_attributes" do
|
66
|
+
it "should return true on any attrs hash if the attributes are empty" do
|
67
|
+
nr = Saxxy::NodeRule.new(/div/)
|
68
|
+
nr.match_attributes({class: "some class", title: "bar"}).should be_true
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should return true if an attribute exists and is nil
|
72
|
+
and the matching does not contain this attribute" do
|
73
|
+
nr = Saxxy::NodeRule.new(/div/, class: nil)
|
74
|
+
nr.match_attributes({}).should be_true
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should return true if an attribute exists and is nil
|
78
|
+
and the matching does contain this attribute and is nil" do
|
79
|
+
nr = Saxxy::NodeRule.new(/div/, class: nil)
|
80
|
+
nr.match_attributes({ class: nil }).should be_true
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should return false if an attribute exists and is nil
|
84
|
+
and the matching does contain this attribute and is not nil" do
|
85
|
+
nr = Saxxy::NodeRule.new(/div/, class: nil)
|
86
|
+
nr.match_attributes({ class: "foo" }).should be_false
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return true if it has a subset of the matching attributes" do
|
90
|
+
nr = Saxxy::NodeRule.new(/div/, title: "foo", class: "bar")
|
91
|
+
nr.match_attributes({ title: "foo", class: "bar", rel: "baz" }).should be_true
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should return false if it has a superset of the matching attributes" do
|
95
|
+
nr = Saxxy::NodeRule.new(/div/, title: "foo", class: "bar", rel: "baz")
|
96
|
+
nr.match_attributes({ title: "foo", class: "bar" }).should be_false
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|