hexp 0.3.3 → 0.4.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +8 -3
- data/Changelog.md +32 -1
- data/Gemfile +0 -5
- data/Rakefile +21 -15
- data/hexp.gemspec +6 -4
- data/lib/hexp.rb +5 -14
- data/lib/hexp/core_ext/nil.rb +9 -0
- data/lib/hexp/css_selector.rb +2 -1
- data/lib/hexp/h.rb +9 -1
- data/lib/hexp/list.rb +6 -1
- data/lib/hexp/node.rb +9 -2
- data/lib/hexp/node/attributes.rb +1 -1
- data/lib/hexp/node/children.rb +4 -2
- data/lib/hexp/node/normalize.rb +24 -28
- data/lib/hexp/nokogiri/reader.rb +1 -1
- data/lib/hexp/text_node.rb +6 -0
- data/lib/hexp/unparser.rb +73 -0
- data/lib/hexp/version.rb +1 -1
- data/spec/integration/literal_syntax_spec.rb +2 -2
- data/spec/shared_helper.rb +1 -1
- data/spec/unit/hexp/builder_spec.rb +2 -2
- data/spec/unit/hexp/css_selector/attribute_spec.rb +24 -24
- data/spec/unit/hexp/css_selector/class_spec.rb +3 -3
- data/spec/unit/hexp/css_selector/comma_sequence_spec.rb +1 -1
- data/spec/unit/hexp/css_selector/element_spec.rb +2 -2
- data/spec/unit/hexp/css_selector/simple_sequence_spec.rb +8 -8
- data/spec/unit/hexp/css_selector/universal_spec.rb +1 -1
- data/spec/unit/hexp/dsl_spec.rb +3 -3
- data/spec/unit/hexp/h_spec.rb +2 -2
- data/spec/unit/hexp/node/attributes_spec.rb +4 -4
- data/spec/unit/hexp/node/class_spec.rb +7 -7
- data/spec/unit/hexp/node/normalize_spec.rb +14 -6
- data/spec/unit/hexp/node/rewrite_spec.rb +1 -1
- data/spec/unit/hexp/node/text_spec.rb +1 -1
- data/spec/unit/hexp/node/to_dom_spec.rb +1 -1
- data/spec/unit/hexp/node/to_html_spec.rb +17 -1
- data/spec/unit/hexp/nokogiri/equality_spec.rb +6 -6
- data/spec/unit/hexp/text_node_spec.rb +2 -2
- metadata +62 -34
- data/Gemfile.devtools +0 -55
- data/Gemfile.lock +0 -186
data/lib/hexp/version.rb
CHANGED
@@ -2,11 +2,11 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe 'Constructing literal hexps' do
|
4
4
|
it do
|
5
|
-
H[:p].
|
5
|
+
expect(H[:p]).to eql Hexp::Node.new(:p, {}, [])
|
6
6
|
end
|
7
7
|
|
8
8
|
it do
|
9
|
-
H[:p, "foo"].
|
9
|
+
expect(H[:p, "foo"]).to eql Hexp::Node.new(:p, {}, ["foo"])
|
10
10
|
end
|
11
11
|
|
12
12
|
end
|
data/spec/shared_helper.rb
CHANGED
@@ -19,7 +19,7 @@ describe Hexp::Builder do
|
|
19
19
|
context 'with a block parameter' do
|
20
20
|
it 'should pass the builder to the block' do
|
21
21
|
Hexp::Builder.new do |builder|
|
22
|
-
expect(Hexp::Builder === builder).to
|
22
|
+
expect(Hexp::Builder === builder).to be true
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -44,7 +44,7 @@ describe Hexp::Builder do
|
|
44
44
|
it 'should evaluate in the context of the builder' do
|
45
45
|
this = self
|
46
46
|
Hexp::Builder.new do
|
47
|
-
this.expect(::Hexp::Builder === self).to this.
|
47
|
+
this.expect(::Hexp::Builder === self).to this.be true
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -12,15 +12,15 @@ describe Hexp::CssSelector::Attribute do
|
|
12
12
|
let(:name) { 'href' }
|
13
13
|
|
14
14
|
it 'should match elements with the attribute present' do
|
15
|
-
expect(selector.matches? H[:a, href: 'http://foo']).to
|
15
|
+
expect(selector.matches? H[:a, href: 'http://foo']).to be true
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'should match elements with an empty attribute present' do
|
19
|
-
expect(selector.matches? H[:a, href: '']).to
|
19
|
+
expect(selector.matches? H[:a, href: '']).to be true
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'should not match elements without the attribute present' do
|
23
|
-
expect(selector.matches? H[:a]).to
|
23
|
+
expect(selector.matches? H[:a]).to be false
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -30,15 +30,15 @@ describe Hexp::CssSelector::Attribute do
|
|
30
30
|
let(:value) { 'foo' }
|
31
31
|
|
32
32
|
it "should match if the attribute's value is exactly equal to the given value" do
|
33
|
-
expect(selector.matches? H[:a, class: 'foo']).to
|
33
|
+
expect(selector.matches? H[:a, class: 'foo']).to be true
|
34
34
|
end
|
35
35
|
|
36
36
|
it "should not match if the attribute's value contains more than the given value" do
|
37
|
-
expect(selector.matches? H[:a, class: 'foofoo']).to
|
37
|
+
expect(selector.matches? H[:a, class: 'foofoo']).to be false
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should not match if the attribute's value does not contain the given value" do
|
41
|
-
expect(selector.matches? H[:a, class: 'fo']).to
|
41
|
+
expect(selector.matches? H[:a, class: 'fo']).to be false
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -48,15 +48,15 @@ describe Hexp::CssSelector::Attribute do
|
|
48
48
|
let(:value) { 'foo' }
|
49
49
|
|
50
50
|
it 'should match an entry in a space separated list' do
|
51
|
-
expect(selector.matches? H[:a, class: 'foo bla baz']).to
|
51
|
+
expect(selector.matches? H[:a, class: 'foo bla baz']).to be true
|
52
52
|
end
|
53
53
|
|
54
54
|
it 'should return false if there is no entry that matches' do
|
55
|
-
expect(selector.matches? H[:a, class: 'bla baz']).to
|
55
|
+
expect(selector.matches? H[:a, class: 'bla baz']).to be false
|
56
56
|
end
|
57
57
|
|
58
58
|
it 'should return false if there is no such attribute' do
|
59
|
-
expect(selector.matches? H[:a]).to
|
59
|
+
expect(selector.matches? H[:a]).to be false
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -66,15 +66,15 @@ describe Hexp::CssSelector::Attribute do
|
|
66
66
|
let(:value) { 'foo' }
|
67
67
|
|
68
68
|
it 'should match if the attribute starts with the value, followed by a dash' do
|
69
|
-
expect(selector.matches? H[:a, id: 'foo-1']).to
|
69
|
+
expect(selector.matches? H[:a, id: 'foo-1']).to be_truthy
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'should not match if the value is not at the start' do
|
73
|
-
expect(selector.matches? H[:a, id: 'myfoo-1']).to
|
73
|
+
expect(selector.matches? H[:a, id: 'myfoo-1']).to be_falsey
|
74
74
|
end
|
75
75
|
|
76
76
|
it 'should not match if the value is not followed by a dash' do
|
77
|
-
expect(selector.matches? H[:a, id: 'foo1']).to
|
77
|
+
expect(selector.matches? H[:a, id: 'foo1']).to be_falsey
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
@@ -84,15 +84,15 @@ describe Hexp::CssSelector::Attribute do
|
|
84
84
|
let(:value) { 'foo' }
|
85
85
|
|
86
86
|
it 'should match if the attribute is just the value' do
|
87
|
-
expect(selector.matches? H[:a, id: 'foo']).to
|
87
|
+
expect(selector.matches? H[:a, id: 'foo']).to be true
|
88
88
|
end
|
89
89
|
|
90
90
|
it 'should match if the attribute starts with the value' do
|
91
|
-
expect(selector.matches? H[:a, id: 'foohi']).to
|
91
|
+
expect(selector.matches? H[:a, id: 'foohi']).to be true
|
92
92
|
end
|
93
93
|
|
94
94
|
it 'should not match if the value is not at the start' do
|
95
|
-
expect(selector.matches? H[:a, id: 'myfoo-1']).to
|
95
|
+
expect(selector.matches? H[:a, id: 'myfoo-1']).to be false
|
96
96
|
end
|
97
97
|
end
|
98
98
|
|
@@ -102,15 +102,15 @@ describe Hexp::CssSelector::Attribute do
|
|
102
102
|
let(:value) { 'foo' }
|
103
103
|
|
104
104
|
it 'should match if the attribute is just the value' do
|
105
|
-
expect(selector.matches? H[:a, id: 'foo']).to
|
105
|
+
expect(selector.matches? H[:a, id: 'foo']).to be_truthy
|
106
106
|
end
|
107
107
|
|
108
108
|
it 'should match if the attribute ends starts with the value' do
|
109
|
-
expect(selector.matches? H[:a, id: 'hifoo']).to
|
109
|
+
expect(selector.matches? H[:a, id: 'hifoo']).to be_truthy
|
110
110
|
end
|
111
111
|
|
112
112
|
it 'should not match if the value is not at the end' do
|
113
|
-
expect(selector.matches? H[:a, id: 'foo-1']).to
|
113
|
+
expect(selector.matches? H[:a, id: 'foo-1']).to be_falsey
|
114
114
|
end
|
115
115
|
end
|
116
116
|
|
@@ -120,19 +120,19 @@ describe Hexp::CssSelector::Attribute do
|
|
120
120
|
let(:value) { 'foo' }
|
121
121
|
|
122
122
|
it 'should match if the attribute is just the value' do
|
123
|
-
expect(selector.matches? H[:a, id: 'foo']).to
|
123
|
+
expect(selector.matches? H[:a, id: 'foo']).to be true
|
124
124
|
end
|
125
125
|
|
126
126
|
it 'should match if the attribute starts starts with the value' do
|
127
|
-
expect(selector.matches? H[:a, id: 'foohi']).to
|
127
|
+
expect(selector.matches? H[:a, id: 'foohi']).to be true
|
128
128
|
end
|
129
129
|
|
130
130
|
it 'should match if the attribute ends starts with the value' do
|
131
|
-
expect(selector.matches? H[:a, id: 'hifoo']).to
|
131
|
+
expect(selector.matches? H[:a, id: 'hifoo']).to be true
|
132
132
|
end
|
133
133
|
|
134
134
|
it 'should not match if the value is not in the attribute' do
|
135
|
-
expect(selector.matches? H[:a, id: 'yomofohoho']).to
|
135
|
+
expect(selector.matches? H[:a, id: 'yomofohoho']).to be false
|
136
136
|
end
|
137
137
|
end
|
138
138
|
|
@@ -140,11 +140,11 @@ describe Hexp::CssSelector::Attribute do
|
|
140
140
|
subject(:selector) { Hexp::CssSelector::Parser.new('[src$="foo/bar.js"]').parse }
|
141
141
|
|
142
142
|
it 'should match correctly' do
|
143
|
-
expect(selector.matches? H[:script, src: "/tmp/foo/bar.js"]).to
|
143
|
+
expect(selector.matches? H[:script, src: "/tmp/foo/bar.js"]).to be true
|
144
144
|
end
|
145
145
|
|
146
146
|
it 'should only match at the end' do
|
147
|
-
expect(selector.matches? H[:script, src: "/tmp/foo/bar.jsx"]).to
|
147
|
+
expect(selector.matches? H[:script, src: "/tmp/foo/bar.jsx"]).to be false
|
148
148
|
end
|
149
149
|
end
|
150
150
|
end
|
@@ -2,14 +2,14 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Hexp::CssSelector::Class do
|
4
4
|
it 'should match elements having the giving class' do
|
5
|
-
expect(described_class.new('big').matches?(H[:div, class: 'big'])).to
|
5
|
+
expect(described_class.new('big').matches?(H[:div, class: 'big'])).to be true
|
6
6
|
end
|
7
7
|
|
8
8
|
it 'should not match elements not having the given class' do
|
9
|
-
expect(described_class.new('big').matches?(H[:div, class: 'small'])).to
|
9
|
+
expect(described_class.new('big').matches?(H[:div, class: 'small'])).to be false
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'should work with elements with multiple classes' do
|
13
|
-
expect(described_class.new('foo').matches?(H[:div, class: 'foo bar'])).to
|
13
|
+
expect(described_class.new('foo').matches?(H[:div, class: 'foo bar'])).to be true
|
14
14
|
end
|
15
15
|
end
|
@@ -2,10 +2,10 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Hexp::CssSelector::Element do
|
4
4
|
it 'should match elements with the same name' do
|
5
|
-
expect(described_class.new('tag').matches?(H[:tag])).to
|
5
|
+
expect(described_class.new('tag').matches?(H[:tag])).to be true
|
6
6
|
end
|
7
7
|
|
8
8
|
it 'should not match elements with a different name' do
|
9
|
-
expect(described_class.new('spane').matches?(H[:div])).to
|
9
|
+
expect(described_class.new('spane').matches?(H[:div])).to be false
|
10
10
|
end
|
11
11
|
end
|
@@ -5,11 +5,11 @@ describe Hexp::CssSelector::SimpleSequence do
|
|
5
5
|
let(:sequence) { described_class[Hexp::CssSelector::Element.new('div')] }
|
6
6
|
|
7
7
|
it 'should match when the element has the same tag name' do
|
8
|
-
expect(sequence.matches?(H[:div])).to
|
8
|
+
expect(sequence.matches?(H[:div])).to be true
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'should not match when the tag name differs' do
|
12
|
-
expect(sequence.matches?(H[:span])).to
|
12
|
+
expect(sequence.matches?(H[:span])).to be false
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
@@ -17,15 +17,15 @@ describe Hexp::CssSelector::SimpleSequence do
|
|
17
17
|
let(:sequence) { described_class[Hexp::CssSelector::Class.new('mega')] }
|
18
18
|
|
19
19
|
it 'should match when the element has a class by that name' do
|
20
|
-
expect(sequence.matches?(H[:div, class: 'mega'])).to
|
20
|
+
expect(sequence.matches?(H[:div, class: 'mega'])).to be true
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'should not match when the element has no classes' do
|
24
|
-
expect(sequence.matches?(H[:span])).to
|
24
|
+
expect(sequence.matches?(H[:span])).to be false
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'should not match when the element has no classes by that name' do
|
28
|
-
expect(sequence.matches?(H[:span, class: 'megalopolis'])).to
|
28
|
+
expect(sequence.matches?(H[:span, class: 'megalopolis'])).to be false
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -37,12 +37,12 @@ describe Hexp::CssSelector::SimpleSequence do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'should match if all parts are satisfied' do
|
40
|
-
expect(sequence.matches?(H[:div, class: 'mega'])).to
|
40
|
+
expect(sequence.matches?(H[:div, class: 'mega'])).to be true
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'should not match if one parts is not satisfied' do
|
44
|
-
expect(sequence.matches?(H[:div, class: 'foo'])).to
|
45
|
-
expect(sequence.matches?(H[:span, class: 'mega'])).to
|
44
|
+
expect(sequence.matches?(H[:div, class: 'foo'])).to be false
|
45
|
+
expect(sequence.matches?(H[:span, class: 'mega'])).to be false
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
data/spec/unit/hexp/dsl_spec.rb
CHANGED
@@ -28,7 +28,7 @@ describe Hexp::DSL do
|
|
28
28
|
|
29
29
|
it "should delegate `to_html' to to_hexp" do
|
30
30
|
expect(hexpable.to_html).to match \
|
31
|
-
%r{<div class=
|
31
|
+
%r{<div class='prinses'>Liefste, Hart en woorden houden voor jou stil</div>}
|
32
32
|
end
|
33
33
|
|
34
34
|
it "should delegate `attr' to to_hexp" do
|
@@ -43,8 +43,8 @@ describe Hexp::DSL do
|
|
43
43
|
end
|
44
44
|
|
45
45
|
it "should delegate `class?' to to_hexp" do
|
46
|
-
expect(hexpable.class?(:prinses)).to
|
47
|
-
expect(hexpable.class?(:prins)).to
|
46
|
+
expect(hexpable.class?(:prinses)).to be true
|
47
|
+
expect(hexpable.class?(:prins)).to be false
|
48
48
|
end
|
49
49
|
|
50
50
|
it "should delegate `rewrite' to to_hexp" do
|
data/spec/unit/hexp/h_spec.rb
CHANGED
@@ -3,19 +3,19 @@ require 'spec_helper'
|
|
3
3
|
describe Hexp::Node::Attributes do
|
4
4
|
describe 'attr?' do
|
5
5
|
it 'should return true if the attribute is present' do
|
6
|
-
expect(H[:a, href: '/foo'].has_attr?(:href)).to
|
6
|
+
expect(H[:a, href: '/foo'].has_attr?(:href)).to be true
|
7
7
|
end
|
8
8
|
|
9
9
|
it 'should return true if the attribute is present and empty' do
|
10
|
-
expect(H[:a, href: ''].has_attr?(:href)).to
|
10
|
+
expect(H[:a, href: ''].has_attr?(:href)).to be true
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'should return false if the attribute is not present' do
|
14
|
-
expect(H[:a].has_attr?(:href)).to
|
14
|
+
expect(H[:a].has_attr?(:href)).to be false
|
15
15
|
end
|
16
16
|
|
17
17
|
it 'should work with a string argument' do
|
18
|
-
expect(H[:a, href: '/foo'].has_attr?('href')).to
|
18
|
+
expect(H[:a, href: '/foo'].has_attr?('href')).to be true
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -3,35 +3,35 @@ require 'spec_helper'
|
|
3
3
|
describe Hexp::Node, 'class?' do
|
4
4
|
context 'with no class attribute set' do
|
5
5
|
it 'should return false' do
|
6
|
-
expect(H[:p].class?('strong')).to
|
6
|
+
expect(H[:p].class?('strong')).to be_falsey
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
10
|
context 'with a single class set' do
|
11
11
|
it 'should return true if the class name is the same' do
|
12
|
-
expect(H[:p, class: 'strong'].class?('strong')).to
|
12
|
+
expect(H[:p, class: 'strong'].class?('strong')).to be true
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'should return false if the class name is not same' do
|
16
|
-
expect(H[:p, class: 'strong'].class?('foo')).to
|
16
|
+
expect(H[:p, class: 'strong'].class?('foo')).to be false
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'should return false if the class name is a partial match' do
|
20
|
-
expect(H[:p, class: 'strong'].class?('stron')).to
|
20
|
+
expect(H[:p, class: 'strong'].class?('stron')).to be false
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
24
|
context 'with multiple classes set' do
|
25
25
|
it 'should return true if the class name is part of the class list' do
|
26
|
-
expect(H[:p, class: 'banner strong'].class?('strong')).to
|
26
|
+
expect(H[:p, class: 'banner strong'].class?('strong')).to be true
|
27
27
|
end
|
28
28
|
|
29
29
|
it 'should return false if the class name is not in the class list' do
|
30
|
-
expect(H[:p, class: 'banner strong'].class?('foo')).to
|
30
|
+
expect(H[:p, class: 'banner strong'].class?('foo')).to be false
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'should return false if the class name is a partial match' do
|
34
|
-
expect(H[:p, class: 'banner strong'].class?('er str')).to
|
34
|
+
expect(H[:p, class: 'banner strong'].class?('er str')).to be false
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -21,13 +21,13 @@ describe Hexp::Node::Normalize, '#call' do
|
|
21
21
|
let(:node) { [:div, {class: 'foo'}] }
|
22
22
|
|
23
23
|
it 'should treat the first as the tag' do
|
24
|
-
subject.tag.
|
24
|
+
expect(subject.tag).to be :div
|
25
25
|
end
|
26
26
|
it 'should treat the second as the attribute list, if it is a Hash' do
|
27
|
-
subject.attributes.
|
27
|
+
expect(subject.attributes).to eql('class' => 'foo')
|
28
28
|
end
|
29
29
|
it 'should treat the second as a list of children, if it is an Array' do
|
30
|
-
subject.children.
|
30
|
+
expect(subject.children).to eql Hexp::List[]
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -35,7 +35,7 @@ describe Hexp::Node::Normalize, '#call' do
|
|
35
35
|
let(:node) { [:div, "this is text in the div"] }
|
36
36
|
|
37
37
|
it 'should set is as the single child' do
|
38
|
-
subject.children.
|
38
|
+
expect(subject.children).to eql Hexp::List["this is text in the div"]
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -50,7 +50,7 @@ describe Hexp::Node::Normalize, '#call' do
|
|
50
50
|
}
|
51
51
|
|
52
52
|
it 'must normalize them recursively' do
|
53
|
-
subject.children.
|
53
|
+
expect(subject.children).to eql Hexp::List[
|
54
54
|
Hexp::Node[:h1, {}, Hexp::List["Big Title"] ],
|
55
55
|
Hexp::Node[:p, {class: 'greeting'}, Hexp::List["hello world"] ],
|
56
56
|
"Some loose text"
|
@@ -71,7 +71,7 @@ describe Hexp::Node::Normalize, '#call' do
|
|
71
71
|
}
|
72
72
|
|
73
73
|
it 'must expand that object' do
|
74
|
-
subject.children.
|
74
|
+
expect(subject.children).to eql Hexp::List[
|
75
75
|
Hexp::Node[:em, {}, Hexp::List["I am in your hexpz"] ]
|
76
76
|
]
|
77
77
|
end
|
@@ -84,4 +84,12 @@ describe Hexp::Node::Normalize, '#call' do
|
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
+
context 'with multiple children not wrapped in an error' do
|
88
|
+
let(:node) { [:div, {foo: 'bar'}, "hello", [:p], [:span, "foo"]] }
|
89
|
+
|
90
|
+
it 'should work fine' do
|
91
|
+
expect(normalized).to eql Hexp::Node[:div, {"foo"=>"bar"}, Hexp::List["hello", Hexp::Node[:p], Hexp::Node[:span, Hexp::List["foo"]]]]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
87
95
|
end
|