saxxy 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|