hexp 0.3.3 → 0.4.0.beta1
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 +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
|